chore(security): masking rule precision — annotate correct fail-closed sites + fix nosemgrep placement (#790) - #862
Open
ClintEastman02 wants to merge 2 commits into
Conversation
…d sites + fix nosemgrep placement (aws-samples#790) Category 0 of the aws-samples#756 silent-success-masking gate. Investigation showed the issue's proposed rule change (a `pattern-not` for a catch/except containing a throw/raise) cannot be delivered: linear-oauth's correct classify-then-rethrow is structurally indistinguishable from the conditional-rethrow masking the rule deliberately catches (the `maskedConditionalRethrow`/`masked_conditional_reraise` fixtures from the original rule PR aws-samples#311). Any pattern-not broad enough to clear the false positive also silences a real detection. So instead of weakening the rule, this annotates the three mis-flagged sites and fixes a suppression that never bound: - cli/src/linear-oauth.ts (readExistingWebhookSecret): justified nosemgrep on the classified `return undefined` — "no such secret" IS the empty success; every other error rethrows (the aws-samples#611 fail-closed contract). Mirrors the already- annotated twin readExistingOauthTokens. - cdk/src/handlers/registry-publish.ts (parseBody): justified nosemgrep — malformed JSON is an expected client-input class; null IS the failure encoding and the caller returns 400 VALIDATION_ERROR. - agent/src/observability.py: the existing nosemgrep did not bind (multi-line comment whose continuation line abutted the return, token two lines up). Restructured so the `# nosemgrep:` token sits directly above `return None`. - .semgrep/silent-success-masking.yaml: documented the placement footgun in the rule header (focus-metavariable:$RET anchors on the return; the token must be on the return line or the line immediately above). Verification: `semgrep test .semgrep/` passes; the three sites drop out of the full masking scan with no new findings; the ratcheted PR gate reports zero new findings; ruff, eslint, tsc, and the agent observability tests are green.
ClintEastman02
requested review from
a team and
backgroundagents
as code owners
September 8, 2026 14:30
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #862 +/- ##
=======================================
Coverage ? 92.48%
=======================================
Files ? 328
Lines ? 95035
Branches ? 10504
=======================================
Hits ? 87891
Misses ? 7144
Partials ? 0 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…ion, malformed-JSON test - observability.py: move nosemgrep token directly above return None (rule placement footgun), tighten justification - linear-oauth.ts: fix suppression attribution to the aws-samples#612-B1 fail-closed contract (was mis-citing aws-samples#611) - registry-handlers.test.ts: add 400 VALIDATION_ERROR malformed-JSON test proving the parseBody fail-closed path the suppression claims
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #790 (Category 0 of the #756 silent-success-masking gate).
What changed vs. what the issue proposed
The issue proposed tightening the rule with a
pattern-notfor a catch/except that contains athrow/raise. Investigation showed that can't be delivered as a clean precision win, so this PR takes a different route. Full reasoning below.Why not the
pattern-notcli/src/linear-oauth.ts's correct classify-then-rethrow —— is structurally indistinguishable from the conditional-rethrow masking the rule was built to catch, encoded in the
maskedConditionalRethrow/masked_conditional_reraisefixtures shipped in the original rule PR #311:Both "catch, contain a throw, and return an empty default." Semgrep's
...ellipsis matching is too loose to anchor on the throw being the terminal / fallthrough statement, so anypattern-notbroad enough to clear the linear-oauth false positive also silences the #311 detection — a real, deliberately-flagged masking pattern. Weakening a security rule to remove two annotations is the wrong trade, so we annotate instead.Changes
cli/src/linear-oauth.ts(readExistingWebhookSecret) — justifiednosemgrepon the classifiedreturn undefined: "no such secret" is the empty success (a first install has no bundle); every other error rethrows below (the fix(cli): linear setup clobbers a second workspace's webhook signing secret with the stack-wide one → 401 Invalid signature #611 fail-closed contract). Mirrors the already-annotated twinreadExistingOauthTokens.cdk/src/handlers/registry-publish.ts(parseBody) — justifiednosemgrep: malformed JSON is an expected client-input class, andnullis the failure encoding — the caller turns it into a400 VALIDATION_ERROR. This site is structurally identical to a real mask, so no rule change could clear it.agent/src/observability.py— the existingnosemgrepnever bound: it was a multi-line comment whose continuation line abutted thereturn None, leaving the token two lines above the finding. Restructured so the# nosemgrep:token sits directly above the return..semgrep/silent-success-masking.yaml— documented the placement footgun in the rule header (focus-metavariable: $RETanchors the finding on thereturn; thenosemgreptoken must be on the return line or the line immediately above).Verification
semgrep test .semgrep/passes (fixtures unchanged; feat(security): custom semgrep rules for silent-success masking (AI004) #311 detection preserved).security:sast:masking:rangevsmain) reports zero new findings.ruff,eslint(cli + cdk),tsc(cli + cdk), and the agentobservabilitytests (9/9) are green.