Skip to main content

Suppressing Static Analysis Findings

Suppressing a finding records that your team has accepted it — the scanner was wrong, the risk is understood, or the code belongs to a third-party library. The finding stays stored exactly as the scan produced it, and every place mtdt.io shows or gates on static analysis reports the effective number: raw findings minus the accepted ones. Suppressed findings stay visible behind an N suppressed chip, so a report never quietly loses a number.

Suppression and excluded rules​

Two mechanisms shape what a report shows, and they live in different places.

Where it livesWhen it actsWhat it means
Excluded rulesScan profileWhile the scan runsThe rule does not run at all, so no findings are produced
SuppressionsSuppressions panel and the Findings tabWhile results are readThe findings exist and your team accepted them

An excluded rule cannot be reviewed after the fact, because its findings were never collected. A suppressed finding comes back with one click, and every screen recalculates.

Product defaults exclude three rules that dominate an unconfigured org — ApexDoc, IfStmtsMustUseBraces, and DebugsShouldUseLoggingLevel. On a codebase that was never scanned before, those three alone account for 17–53% of raw findings. Excluding them keeps that volume out of the scan instead of asking someone to accept it finding by finding.

Choosing a match level​

A suppression matches findings at one of these levels:

  • This exact finding — one finding, identified by its fingerprint (engine, rule, file path, line text, occurrence index).
  • This rule in this file — every finding of that rule inside that file. This survives line edits and Flow version changes, which makes it the practical choice for noisy rules and for Flows.
  • A path pattern — a glob over the file path, optionally combined with a rule. src/classes/fflib_* is the third-party-library case: on a real org that single pattern covers about 13,000 findings across 58 files.
  • This rule across the scope — every finding of that rule, the broadest level.

Pattern rules worth knowing:

  • The only wildcard is *.
  • A pattern needs at least four literal characters. A very short pattern would silence most of an org from one click, so mtdt.io rejects it.
  • Underscores are treated literally, so src/classes/fflib_* matches only the fflib_ prefix.

When several suppressions could match the same finding, the most specific one wins: exact finding, then rule in file, then path pattern, then rule in scope.

Scope. A suppression applies to one org, one repository, or the whole team, with no inheritance. Accepting a finding in one org leaves the other orgs untouched.

Choosing a category and writing a reason​

Every suppression needs a category and a non-empty reason. The category feeds the breakdown in the monthly org report, so "the scanner was wrong" and "we accept this risk" stay separate numbers.

CategoryUse it when
False positiveThe rule fired on code that does not have the problem it describes
Accepted riskThe finding is real and your team decided to live with it
Won't fixThe finding is real and the code is not going to change
Third-party codeThe file comes from a library your team does not maintain

Security findings always expire​

A security finding can only be suppressed together with an expiry date, capped at 180 days; the form pre-fills 90 days. When the date passes, the finding returns on its own.

The server decides whether a finding counts as security by looking at the findings the suppression would cover, so the browser cannot claim otherwise. A broad rule-level or path-pattern suppression created over non-security findings also cannot grow to cover a security finding later. "Security accepted forever" has no way to be expressed.

Where suppressions appear​

  • Findings tab in the scan-results dialog — a table you can filter by text, severity, rule, and security-only, with Suppress and Un-suppress on each row and a Show N suppressed toggle. Suppressed rows are dimmed, and the reason and expiry show in the tooltip.
  • The suppression dialog — match level, category, reason, and expiry date. When a rule fires more than once in the same file, the dialog points that out so you can pick the rule-in-file level instead of repeating yourself.
  • Suppressed findings panel on the Static Analysis page, beside Scan profiles — the registry of every decision, with a state filter, a revoke action, and a warning for suppressions that are about to expire.
  • Code tab in the same dialog — suppressed findings are hidden in the Monaco tree and reachable through a [SUPPRESSED] chip in the Problems panel. File badges count only what is still open.
  • Org Analyses list — the severity chips carry an N suppressed chip whenever a scan has accepted findings.
  • Deploy Modal → Static analysis and the Impact analysis tab — effective counts and rule breakdown, including the clipboard export.
  • Monthly org report — effective counts, suppressed volume shaded to read as a decision, and "accepted during the period" counted in suppressions rather than findings, because one suppression can close thousands of findings.
  • Health Check — the static-analysis block is a stored snapshot, so suppressions created after the run do not rewrite it.

Effective counts everywhere​

One database filter feeds every consumer, so a suppression cannot be honoured on one screen and ignored on another. That filter drives the results dialog, the Org Analyses list, the pre-deploy code-quality gate, pull-request check annotations, the scan delta, and the monthly report.

Two consequences to plan for:

  • Gates read effective counts. A suppressed finding does not block a deploy, and the gate's reason says so — for example … (1 finding suppressed). The pull-request check also filters the findings themselves, so an accepted finding stops coming back as an inline annotation on every PR.
  • Scan delta reads effective counts too. New, fixed, and persisting are computed after suppression, so accepting a finding does not leave it stuck in "new" forever.

Because the filter runs at read time, suppressing a finding changes historical scan numbers as well. The stored findings are never modified, which is what makes un-suppressing free.

Permissions and audit​

Suppressing and revoking sit behind their own team permission, separate from the permission that manages static analysis — configuring scan profiles and accepting a security risk are different authorities. The Suppress and Un-suppress actions appear only for members who hold it.

Every suppression and every revoke writes a team audit-log entry with the author, the reason, and the number of findings matched. Suppressing a security finding is logged at warning level.

Nothing is deleted. A revoked suppression stays in the registry under the Revoked state as the record that someone once accepted it, and an expired suppression stops applying on its own with no job to run.

Counting units​

Apex and Lightning Web Component findings are counted per finding. Flow findings are counted per violation, meaning one rule-and-file pair: the scan stores a row for every flow element the rule touched, and a flow violation stays counted until every one of its elements is suppressed. The scan delta for Flows works at the individual finding level, because a finding is the unit you suppress.