Repository navigation
SonarCloud S7637 conflicts with org first-party reusable-ref exemption — need an org-level SonarCloud exemption #498
Description
Summary
SonarCloud's GitHub Actions rule githubactions:S7637 ("pin actions to a full-length commit SHA") fires on first-party petry-projects/.github reusable-workflow refs that the org standard intentionally pins by moving tag/channel (@<name>/stable, @v1/@v2) rather than SHA. The org already exempts these internal refs from SHA-pinning in our compliance audit (check_action_pinning, see #239) — but SonarCloud is an external gate and doesn't know about that exemption, so it flags them as high-severity vulnerabilities and can fail the quality gate. We need an org-level SonarCloud exemption for first-party reusable refs so the two policies agree.
Evidence / how it surfaced
During the #482 channel migration, the channel-repin PR on google-app-scripts (#399) failed SonarCloud with 4 high-severity githubactions:S7637 alerts ("C Security Rating on New Code" → Quality Gate failed), all on the migrated stub uses: lines:
| File | Line | Ref |
|---|---|---|
.github/workflows/agent-shield.yml |
33 | …@agent-shield/stable |
.github/workflows/pr-review-mention.yml |
40 | …@pr-review-mention/stable |
.github/workflows/auto-rebase.yml |
53 | …@auto-rebase/stable |
.github/workflows/dependabot-rebase.yml |
53 | …@dependabot-rebase/stable |
These were resolved one-off as "won't fix / safe" in the SonarCloud UI to unblock #399, but that recurs on every future workflow-stub change. (Note: only google-app-scripts' SonarCloud project gates on this rule today; markets/ContentTwin/broodly/bmad-bgreat-suite/TalkTerm passed with the same tags — so configuration is inconsistent across repos too.)
The conflict (two policies, mutually exclusive on one pin)
- Org action-pinning policy /
check_action_pinning(Compliance: unpinned-actions-dependabot-automerge.yml #239): first-partypetry-projects/.github(-private)reusable refs are exempt from SHA-pinning — they use moving channel/tag refs by design (standards/ci-standards.md#action-pinning-policy, and the channel model in Reconcile workflow-stub pin drift: templates vs compliance-audit vs fleet are three-way inconsistent #482). - SonarCloud
githubactions:S7637: wants everyuses:SHA-pinned, including those first-party refs.
A stub can satisfy one or the other, not both. Third-party actions should still be SHA-pinned — so a blanket rule-disable or path-exclusion on .github/workflows/** is too broad (it would drop SHA-pin enforcement for third-party actions too).
Recommendation
Reconcile org-wide so SonarCloud accepts first-party reusable refs without dropping third-party protection. Options, roughly in order of preference:
- Org-level SonarCloud rule scope/exclusion targeted at first-party refs — e.g. a custom quality profile or an
sonar.issue.ignorekeyed so onlypetry-projects/.github*/.github/workflows/*-reusable.yml@…refs are exempt from S7637, applied to all org SonarCloud projects (consistent config). - If SonarCloud can't scope by ref content, suppress S7637 only on the thin caller-stub files (which contain only a first-party reusable ref and no third-party actions), leaving full S7637 enforcement on
ci.ymland other workflows that call third-party actions. - Standardize SonarCloud project config across the org so the gate behaves identically everywhere (today it's inconsistent).
Acceptance
- First-party reusable-ref stubs (
@<name>/stable,@v1/@v2) no longer trip SonarCloudS7637/ fail the gate, org-wide. - Third-party actions are still required to be SHA-pinned (no blanket workflow-path exclusion).
- SonarCloud quality-gate config is consistent across org repos.
References
- Surfaced from the Reconcile workflow-stub pin drift: templates vs compliance-audit vs fleet are three-way inconsistent #482 reusable-channel migration; incident PR
petry-projects/google-app-scripts#399. - Org exemption precedent: Compliance: unpinned-actions-dependabot-automerge.yml #239 (
check_action_pinningexempts internal reusable refs);standards/ci-standards.md#action-pinning-policy. - Prior SHA-pin driver: fix(standards): pin auto-rebase stub to SHA to satisfy SonarCloud security gate #166.
Activity
don-petry commentedon Jun 20, 2026
Resolution approach — code, not a manual SonarCloud chore
This can be fixed in version-controlled config, no per-issue UI clicking and no SonarCloud admin required.
Key insight: the thin caller stubs (
agent-shield.yml,auto-rebase.yml,dependency-audit.yml,dependabot-automerge.yml,dependabot-rebase.yml,pr-review-mention.yml,dev-lead.yml,add-to-project.yml) contain only a first-partypetry-projects/.github(-private)reusableuses:line — no third-party actions. So a path-scoped ignore ofgithubactions:S7637on exactly those stub files is, in effect, a first-party-only exemption — whileci.yml,sonarcloud.yml, etc. (which call third-party actions) keep full S7637 / SHA-pin enforcement.The config (committed in each gating repo's
sonar-project.properties)(If a repo already has a
sonar.issue.ignore.multicriterialist, append a new criterion id rather than overwriting.)Why not the alternatives
.github/workflows/**: too broad — drops third-party SHA enforcement. ✗Rollout
google-app-scripts; others passed with channel tags — config is inconsistent, see below).scripts/deploy-standard-workflows.sh) — the same mechanism used for the Reconcile workflow-stub pin drift: templates vs compliance-audit vs fleet are three-way inconsistent #482 channel migration — ideally by making thesonar.issue.ignore.multicriteriablock part of a standardsonar-project.propertiessnippet so drift is auditable.Acceptance
sonar.issue.ignore.multicriteriafor thegithubactionsanalyzer (open a stub-touching PR, confirm S7637 no longer fires on the stub files, and confirm it still fires on a third-party unpinned action elsewhere).Implementation note: the actual
sonar-project.propertiesedits live in the consumer repos, not here — so the.githubtask is to define the canonical snippet + drive the rollout (a deploy run), not a single in-repo edit.don-petry commentedon Jun 20, 2026
Dev-Lead Implementation Plan
Issue: #498 — SonarCloud S7637 conflicts with org first-party reusable-ref exemption — need an org-level SonarCloud exemption
Scope
Reconcile SonarCloud
githubactions:S7637with the org action-pinning exemption by adding a canonical, narrow SonarCloud issue-ignore (S7637 suppressed only on first-party reusable-ref caller-stub workflow files), documenting it as an org standard, and enforcing org-wide consistency via a new compliance-audit check. Recommendation option 2 is used because SonarCloud'ssonar.issue.ignorefilters by file path + rule, not byuses:ref content (option 1 is not expressible insonar-project.properties).Implementation Checklist
scripts/compliance-audit.sh: add pure helperclassify_sonar_s7637_exemption(→present/missing/too-broad) andcheck_sonar_s7637_exemptionfinding emitter; wire into the per-repo audit loop.sonar-project.properties: add the canonical narrow S7637 exemption block targeting only the thin caller-stub workflow files (reference implementation).standards/ci-standards.md: document the "SonarCloud Exemption: First-Party Reusable-Ref S7637" standard and cross-link the Action Pinning Policy exemption + SonarCloud section.Tests to Write
test/scripts/compliance-audit/sonar-s7637-exemption.bats: classifier returnspresentfor a narrow caller-stub exemption,missingwhen no S7637 criterion,too-broadfor a blanketworkflows/*.yml/**/*.ymlresourceKey (guards acceptance criterion 2: third-party actions stay SHA-pinned).Test Command
bats --print-output-on-failure test/scripts/compliance-audit/(plusshellcheck --severity=warning -x scripts/compliance-audit.shandbash .dev-lead/scripts/dev-lead-lint.sh)don-petry commentedon Jun 20, 2026
Dev-Lead: Implementation Complete
Plan Execution
classify_sonar_s7637_exemption(pure verdict helper) +check_sonar_s7637_exemption(finding emitter) toscripts/compliance-audit.sh, wired into the per-repo audit loop aftercheck_sonarcloud.sonar-project.properties(onesonar.issue.ignore.multicriteriapair per first-party caller-stub file) as the org reference implementation.standards/ci-standards.md("SonarCloud Exemption: First-Party Reusable-Ref S7637") and cross-linked the Action Pinning Policy exemption.test/scripts/compliance-audit/sonar-s7637-exemption.bats(TDD: written red, then green).Design note (why option 2, not option 1)
SonarCloud's
sonar.issue.ignorefilters by file path + rule, not byuses:ref content — so scoping by ref string (recommendation option 1) is not expressible insonar-project.properties. The implementation uses option 2: suppressgithubactions:S7637only on the thin caller-stub files, each via its own per-fileresourceKey. A blanketworkflows/*.yml/**/*.ymlresourceKeyis explicitly rejected by the audit (sonar-s7637-exemption-too-broad, error) so third-party actions inci.yml/sonarcloud.ymlkeep full SHA-pin enforcement.Acceptance criteria
check_sonar_s7637_exemptionflags any SonarCloud-gated repo missing (warning) or over-broadening (error) the exemption.Test Results
Files Changed
scripts/compliance-audit.sh: newclassify_sonar_s7637_exemption+check_sonar_s7637_exemptionchecks, wired into the audit loop.sonar-project.properties: canonical per-stub S7637 exemption block (reference impl).standards/ci-standards.md: new SonarCloud S7637 exemption standard + cross-link from Action Pinning Policy.test/scripts/compliance-audit/sonar-s7637-exemption.bats: classifier unit tests (new).Notes
sonarcloud.yml; a missingsonar-project.propertiesis still reported by the existingcheck_sonarcloud.feat: implement issue #498 — SonarCloud S7637 conflicts with org firs…