Skip to content

fix(privacy): skip comments when scanning for tracking SDKs and ATT - #35

Open
Maher-Reven wants to merge 2 commits into
RevylAI:mainfrom
Maher-Reven:tracking-scan-skip-comments
Open

Maher-Reven wants to merge 2 commits into
RevylAI:mainfrom
Maher-Reven:tracking-scan-skip-comments

Conversation

@Maher-Reven

@Maher-Reven Maher-Reven commented Sep 19, 2026

Copy link
Copy Markdown

Independent of #33 and #34 — this touches the scan loop rather than the pattern table, so it can be reviewed and merged in any order.

Problem

The tracking SDK and ATT checks ran against the whole file:

fullContent := strings.Join(lines, "\n")

if regexp.MustCompile(`(?i)(ATTrackingManager|requestTrackingAuthorization|...)`).MatchString(fullContent) {
    hasATT = true
}

for _, sdk := range trackingSDKPatterns {
    if sdk.Pattern.MatchString(fullContent) {
        trackingSDKsFound[sdk.Name] = true
    }
}

So commented-out code counts as live. The Required Reason scan in the same walk, about ten lines below, already skips comment lines — these two did not.

It is wrong in both directions, and the second one is the dangerous one.

False positive. A file that only mentions these SDKs to say it does not use them:

// We deliberately do not use mixpanel here.
/* AppsFlyer was removed in v2.0 */
func body() { render() }
  Tracking SDKs found: Mixpanel, AppsFlyer
  [CRITICAL] §5.1.2 Tracking SDKs detected without ATT implementation

False negative. A commented-out ATT call suppresses the CRITICAL for an app that really does track:

import AppsFlyerLib
// TODO: call ATTrackingManager.requestTrackingAuthorization before this ships
func start() { AppsFlyerLib.shared().start() }

hasATT becomes true, and the §5.1.2 finding never fires. This is the failure mode worth fixing — greenlight silently greenlights an app that will be rejected.

Fix

Match line by line, skipping comments with the same rule the Required Reason scan uses, extracted into isCommentLine. This is equivalent to the old whole-file match for these patterns, because Go's . does not cross newlines, so none of them could ever span lines anyway.

isCommentLine only skips lines that begin with a comment marker, so import AppsFlyerLib // analytics is still scanned. There is a test for that, because the obvious over-correction here is to strip anything after // and start missing real integrations.

The same file, after:

  ✓ PrivacyInfo.xcprivacy found
  No privacy issues found!
  GREENLIT — privacy compliance looks good

Also here

The finding now cites a location. §5.1.2 was the only CRITICAL that carried no file or line, which is exactly what makes a false positive hard to check against the source — the issue on #30 raises this directly. Finding already had File and Line; they were simply never populated.

  [CRITICAL] §5.1.2 Tracking SDKs detected without ATT implementation
             Found: AppsFlyer. ... First seen at Analytics.swift:2.

The ATT regexp is hoisted to a package-level var. It was being recompiled for every file in the project.

Testing

Four tests in internal/privacy/scanner_test.go:

test guards
TestTrackingScanIgnoresComments commented-out SDK references produce no finding
TestCommentedOutATTDoesNotSuppressFinding a commented-out ATT call no longer hides a real CRITICAL
TestTrackingScanStillReadsCodeWithTrailingComment over-correction guard — a trailing comment does not hide real code
TestTrackingFindingCitesFileAndLine the finding reports Analytics.swift:2

Three of the four fail against the unmodified scanner, which I verified by checking out main's scanner.go and rerunning; the first reports [AppsFlyer Mixpanel AppLovin] from a file that is nothing but comments. The trailing-comment test passes either way by design — it exists to stop a future fix from going too far.

go build ./... and go test ./... are clean.

One behaviour change worth calling out

Apps whose only ATT reference is inside a comment will now correctly get the CRITICAL they were always owed. That is the point of the change, but it does mean a small number of projects that pass --exit-code today will start failing — and they would have been rejected at review anyway.


Note

Low Risk
Scoped to privacy static-analysis heuristics and report output; improves accuracy with no auth or runtime behavior changes, though some projects may newly fail if they only had ATT in comments.

Overview
Tracking SDK and ATT detection no longer treat commented-out code as live integrations. The scan matches line-by-line and skips lines that start with comment markers via shared isCommentLine (same rule as Required Reason API scanning), so mention-only comments stop triggering §5.1.2 false positives and commented ATT TODOs no longer suppress real CRITICALs when tracking code is present.

§5.1.2 findings are easier to verify and stable across runs. The CRITICAL now sets File/Line from the earliest SDK hit (earliestHit), appends a “First seen at …” detail, and sorts TrackingSDKs for deterministic reports. The ATT regexp is compiled once at package scope.

Tests cover comment-only SDK refs, commented ATT not suppressing findings, trailing comments still scanning code, location on findings, and repeated-scan determinism.

Reviewed by Cursor Bugbot for commit 2db79cb. Bugbot is set up for automated code reviews on this repo. Configure here.

The tracking SDK and ATT checks matched against the whole file with
MatchString(fullContent), so commented-out code counted as live. The
Required Reason scan in the same walk already skipped comment lines.

Both directions were wrong. A file containing only `// we do not use
mixpanel` reported Mixpanel as a tracking SDK and produced a CRITICAL
§5.1.2 for an app that does not track. More seriously, a commented-out
`ATTrackingManager.requestTrackingAuthorization` set hasATT and hid the
CRITICAL from an app that really does track.

Match line by line instead, reusing the same comment rule, which is
equivalent for these patterns because Go's `.` does not cross newlines.
Only lines that begin with a comment marker are skipped, so a trailing
comment does not hide the code in front of it.

Also record where each SDK was first seen. §5.1.2 was the only CRITICAL
that cited no location, which is what makes a false positive hard to
check against the source; Finding already had File and Line. The ATT
regexp is hoisted out of the walk rather than recompiled per file.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit f04b441. Configure here.

Comment thread internal/privacy/scanner.go
Review catch: `result.TrackingSDKs` is filled by ranging over a map, and
Go randomises map iteration, so indexing `[0]` picked an arbitrary SDK.
The cited file and line therefore changed between runs on any project
using more than one tracking SDK — 3 distinct outputs over 40 scans of
the same three-SDK fixture.

Sort the SDK list, which also settles the `Found:` ordering that was
already unstable before this branch, and cite the genuinely earliest hit
by file then line so "first seen" means what it says.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant