ballerina/scan Ballerina library

1.0.0

Overview

This package provides the @scan:Suppress annotation, which accepts a finding of the bal scan static code analysis tool at the construct that contains it, along with the reason it is accepted.

Copy
import ballerina/scan;

public function main() {
    @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "The literal always parses"}
    int port = checkpanic int:fromString("9090");
}

A suppressed finding is not dropped. It stays in the scan reports with its reason, so every accepted finding remains reviewable.

Suppress findings

Suppress one rule:

Copy
@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "The literal always parses"}
int port = checkpanic int:fromString("9090");

Suppress several rules for the same reason:

Copy
@scan:Suppress {rules: [scan:CHECKPANIC_USAGE, scan:UNUSED_FUNCTION_PARAMETER], reason: "Kept until the parser is replaced"}
function parsePort(string input, string locale) returns int {
    return checkpanic int:fromString(input);
}

Give each rule its own reason by repeating the annotation:

Copy
@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "The input is validated by the caller"}
@scan:Suppress {rules: [scan:UNUSED_FUNCTION_PARAMETER], reason: "locale is part of the public API, SEC-1042"}
function parsePort(string input, string locale) returns int {
    return checkpanic int:fromString(input);
}

Share a rule list through a constant:

Copy
const LEGACY_PARSER_RULES = [scan:CHECKPANIC_USAGE, scan:UNUSED_FUNCTION_PARAMETER];

@scan:Suppress {rules: LEGACY_PARSER_RULES, reason: "Kept until the parser is replaced"}
function parsePort(string input, string locale) returns int {
    return checkpanic int:fromString(input);
}

Suppress every rule by leaving out rules. This also accepts rules added to bal scan later, so prefer naming the rules:

Copy
@scan:Suppress {reason: "Generated code"}
function generatedMapping(json payload) returns Order|error => payload.cloneWithType();

Both fields are optional, so @scan:Suppress and @scan:Suppress {rules: [scan:CHECKPANIC_USAGE]} are valid too. A project can require them, as described in Project policy.

Rules

Each core rule of bal scan (ballerina:<number>) has a constant in this package, named after the finding it suppresses:

ConstantRule ID
scan:CHECKPANIC_USAGEballerina:1
scan:UNUSED_FUNCTION_PARAMETERballerina:2
scan:NON_ISOLATED_PUBLIC_FUNCTIONballerina:3
scan:NON_ISOLATED_PUBLIC_METHODballerina:4
scan:NON_ISOLATED_PUBLIC_CLASSballerina:5
scan:NON_ISOLATED_PUBLIC_OBJECTballerina:6
scan:ALWAYS_TRUE_OPERATIONballerina:7
scan:ALWAYS_FALSE_OPERATIONballerina:8
scan:REDUNDANT_OPERATIONballerina:9
scan:SELF_ASSIGNMENTballerina:10
scan:UNUSED_PRIVATE_CLASS_FIELDballerina:11
scan:EMPTY_RANGE_EXPRESSIONballerina:12
scan:HARD_CODED_SECRETballerina:13
scan:NON_CONFIGURABLE_SECRETballerina:14

Any rule can also be named by its ID, which bal scan prints with each finding, and bal scan --list-rules lists the rules available to a package. Rules contributed by a package's analyzer have no constant in this package and are named by ID:

FormExampleRule of
ballerina:<number>ballerina:1bal scan itself
<org>/<package>:<number>ballerina/http:1The analyzer of a package

Where to place it

The annotation covers the findings within the construct it is attached to. The rules below only illustrate the syntax:

Copy
@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Startup configuration is always valid"}
final int port = checkpanic int:fromString("9090");

@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Generated type"}
type Order record {|
    @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Legacy field name"}
    string order_id;
|};

@scan:Suppress {rules: ["ballerina/http:1"], reason: "Internal network only"}
listener http:Listener ordersListener = new (port);

service /orders on ordersListener {
    @scan:Suppress {rules: ["ballerina/http:2"], reason: "Read-only endpoint behind the gateway"}
    resource function get [string id]() returns Order => {order_id: id};
}

@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Pure function"}
function parse(@scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Trusted input"} string value)
        returns @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Always an int"} int {
    @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Validated above"}
    int result = checkpanic int:fromString(value);

    @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Worker input is trusted"}
    worker w {
    }
    return result;
}

function nativeHash(string value) returns string = @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "Native code"} external;

It can also be attached to a constant, a class, an object field or method, a service, an included record parameter (*Opts opts), the return type of an anonymous function and a member of a tuple type definition.

  • A suppression on a service, class or object type does not reach the findings inside its members. Annotate the member instead.

  • A declaration that destructures its value, such as [int, int] [x, y] = pair;, and a function or tuple type written outside a type definition cannot carry a suppression. The annotation is reported as unsupported there, and bal scan ignores it.

  • A finding in a statement that is not a declaration can be suppressed by turning the statement into one:

    Copy
    @scan:Suppress {rules: [scan:CHECKPANIC_USAGE], reason: "The literal always parses"}
    var _ = checkpanic int:fromString("1");

Validation

Rule IDs and reasons are checked as the compiler evaluates them, so constants, string templates and escapes are resolved first.

ProblemExampleReported byResult
Malformed rule IDrules: ["http:1"]bal buildError
Empty rule listrules: []bal buildError
Rule listed twicerules: [scan:CHECKPANIC_USAGE, "ballerina:1"]bal buildWarning
Rule already suppressed by another annotation on the constructTwo annotations naming ballerina:1bal build, bal scanWarning
Second annotation without rules on the constructTwo @scan:Suppress {reason: "..."}bal build, bal scanWarning
Blank reasonreason: ""bal buildWarning
Unsupported placement@scan:Suppress on [int, int] [x, y] = pair;bal buildWarning
Unknown rulerules: ["ballerina:999"]bal scanScan fails
Rule of an analyzer the scan does not runrules: ["acme/lint:1"]bal scanWarning
Suppression that matched no findingThe finding was fixedbal scanWarning
Missing reason or rules, when the project requires them@scan:Suppress {rules: [scan:CHECKPANIC_USAGE]}bal scanScan fails

When the scan fails on a suppression, it reports nothing: no findings are printed, saved or sent to a platform.

Code actions

The editor offers these fixes:

ProblemCode actionResult
No reasonAdd suppression reasonAdds reason: "" to fill in
Blank reasonRemove blank suppression reasonRemoves reason
Rule listed twiceRemove duplicate ruleRemoves the later occurrence
Empty rule listSuppress all rules on this constructRemoves rules
Empty rule list, and no reasonRemove suppressionRemoves the annotation

Project policy

A project can require every suppression to give a reason or name its rules, or disregard suppressions altogether, in Scan.toml:

Copy
[suppression]
enabled = true
requireReason = true
requireRuleId = true
SettingCommand-line optionEffect
enabled = false--ignore-suppressionsReports every finding, as though nothing were suppressed
requireReason = true--require-suppression-reasonFails the scan when a suppression gives no reason
requireRuleId = true--require-suppression-rule-idFails the scan when a suppression names no rule

Review suppressed findings

  • The console prints active findings only, with a summary such as 1 issue(s), 2 suppressed.
  • The JSON and SARIF reports keep suppressed findings, each with a suppressions entry carrying the reason.
  • The HTML report (bal scan --scan-report) lists them under the Suppressed filter.
  • bal scan --ignore-suppressions shows every finding, to audit what is suppressed.

Import

import ballerina/scan;Copy

Other versions

1.0.0

Metadata

Released date: about 5 hours ago

Version: 1.0.0

License: Apache-2.0


Security

No known vulnerabilities in libraries

Checked on 2026-11-05 via OSV.dev


Compatibility

Platform: java21

Ballerina version: 2201.12.0

GraalVM compatible: Yes


Pull count

Total: 0

Current verison: 0


Weekly downloads


Source repository


Keywords

scan

static code analysis

suppression

Type/Library

Name/Scan


Contributors