Skip to content

SonarCloud S7637 conflicts with org first-party reusable-ref exemption — need an org-level SonarCloud exemption #498

Closed

Description

@don-petry

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)

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:

  1. Org-level SonarCloud rule scope/exclusion targeted at first-party refs — e.g. a custom quality profile or an sonar.issue.ignore keyed so only petry-projects/.github*/.github/workflows/*-reusable.yml@… refs are exempt from S7637, applied to all org SonarCloud projects (consistent config).
  2. 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.yml and other workflows that call third-party actions.
  3. 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 SonarCloud S7637 / 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

Activity

  1. don-petry commented on Jun 20, 2026

    @don-petry
    ContributorAuthor

    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-party petry-projects/.github(-private) reusable uses: line — no third-party actions. So a path-scoped ignore of githubactions:S7637 on exactly those stub files is, in effect, a first-party-only exemption — while ci.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)

    sonar.issue.ignore.multicriteria=firstpartyrefs
    sonar.issue.ignore.multicriteria.firstpartyrefs.ruleKey=githubactions:S7637
    sonar.issue.ignore.multicriteria.firstpartyrefs.resourceKey=.github/workflows/{agent-shield,auto-rebase,dependency-audit,dependabot-automerge,dependabot-rebase,pr-review-mention,dev-lead,add-to-project}.yml

    (If a repo already has a sonar.issue.ignore.multicriteria list, append a new criterion id rather than overwriting.)

    Why not the alternatives

    • Per-issue "won't fix" in the UI (what unblocked Org Status — 2026-06-06 #399): manual, recurs on every stub change. ✗
    • Org-level SonarCloud "Ignore Issues" / custom quality profile: one-time but UI-only, not version-controlled, needs SonarCloud admin. Acceptable fallback, not preferred. ✗
    • Blanket path-ignore on .github/workflows/**: too broad — drops third-party SHA enforcement. ✗

    Rollout

    • Only repos whose SonarCloud project gates on S7637 need it (today: google-app-scripts; others passed with channel tags — config is inconsistent, see below).
    • Roll out via the standards-sync deploy tooling (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 the sonar.issue.ignore.multicriteria block part of a standard sonar-project.properties snippet so drift is auditable.

    Acceptance

    • Validate on one repo first that SonarCloud honors sonar.issue.ignore.multicriteria for the githubactions analyzer (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).
    • Canonical snippet added to the org standard; rolled out to gating repos via the deploy tooling.
    • SonarCloud project config made consistent across org repos (so the gate behaves identically everywhere).

    Implementation note: the actual sonar-project.properties edits live in the consumer repos, not here — so the .github task is to define the canonical snippet + drive the rollout (a deploy run), not a single in-repo edit.

  2. don-petry commented on Jun 20, 2026

    @don-petry
    ContributorAuthor

    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:S7637 with 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's sonar.issue.ignore filters by file path + rule, not by uses: ref content (option 1 is not expressible in sonar-project.properties).

    Implementation Checklist

    • scripts/compliance-audit.sh: add pure helper classify_sonar_s7637_exemption (→ present/missing/too-broad) and check_sonar_s7637_exemption finding 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 returns present for a narrow caller-stub exemption, missing when no S7637 criterion, too-broad for a blanket workflows/*.yml/**/*.yml resourceKey (guards acceptance criterion 2: third-party actions stay SHA-pinned).

    Test Command

    bats --print-output-on-failure test/scripts/compliance-audit/ (plus shellcheck --severity=warning -x scripts/compliance-audit.sh and bash .dev-lead/scripts/dev-lead-lint.sh)

  3. don-petry commented on Jun 20, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead: Implementation Complete

    Plan Execution

    • Added classify_sonar_s7637_exemption (pure verdict helper) + check_sonar_s7637_exemption (finding emitter) to scripts/compliance-audit.sh, wired into the per-repo audit loop after check_sonarcloud.
    • Added the canonical narrow S7637 exemption block to sonar-project.properties (one sonar.issue.ignore.multicriteria pair per first-party caller-stub file) as the org reference implementation.
    • Documented the standard in standards/ci-standards.md ("SonarCloud Exemption: First-Party Reusable-Ref S7637") and cross-linked the Action Pinning Policy exemption.
    • Added 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.ignore filters by file path + rule, not by uses: ref content — so scoping by ref string (recommendation option 1) is not expressible in sonar-project.properties. The implementation uses option 2: suppress githubactions:S7637 only on the thin caller-stub files, each via its own per-file resourceKey. A blanket workflows/*.yml/**/*.yml resourceKey is explicitly rejected by the audit (sonar-s7637-exemption-too-broad, error) so third-party actions in ci.yml/sonarcloud.yml keep full SHA-pin enforcement.

    Acceptance criteria

    • First-party reusable-ref stubs no longer trip S7637 — per-stub exemption + documented canonical block to copy org-wide.
    • Third-party actions still require SHA-pinning — blanket workflow-path exclusions are forbidden and audited as an error.
    • Config consistency enforced org-wide — check_sonar_s7637_exemption flags any SonarCloud-gated repo missing (warning) or over-broadening (error) the exemption.

    Test Results

    === shellcheck --severity=warning -x scripts/compliance-audit.sh ===
    OK
    === bats test/scripts/compliance-audit/ (59 tests) ===
    ok 50 no issue-ignore config at all is missing
    ok 51 an issue-ignore for an unrelated rule is missing (S7637 not covered)
    ok 52 a narrow single-file S7637 exemption is present
    ok 53 multiple narrow per-stub S7637 criteria are present
    ok 54 a blanket workflows/*.yml resourceKey is too-broad
    ok 55 a bare ** resourceKey is too-broad
    ok 56 a bare *.yml resourceKey is too-broad
    ok 57 one narrow + one blanket S7637 criterion is too-broad (blanket wins)
    ok 58 whitespace around the ruleKey assignment is tolerated
    ok 59 the repo's own canonical sonar-project.properties classifies as present
    === .dev-lead/scripts/dev-lead-lint.sh ===
    [lint] all checks passed
    

    Files Changed

    • scripts/compliance-audit.sh: new classify_sonar_s7637_exemption + check_sonar_s7637_exemption checks, 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

    • The audit check runs only for repos that have sonarcloud.yml; a missing sonar-project.properties is still reported by the existing check_sonarcloud.
    • Each adopting repo copies the canonical block and omits criteria for stubs it doesn't have (every required-workflow caller stub is covered). SonarCloud UI quality-profile changes are out of scope for an in-repo change — the properties-file approach is version-controlled and audited, which is what delivers org-wide consistency.
  4. added a commit that references this issue on Jun 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    ciCI/CD pipeline issuesdev-leadFor dev-lead agent pickupenhancementFeature requests

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions