Skip to content

Run a full Poutine scan of main and address findings #2527

Description

@WilliamBerryiii

Context

Poutine runs today only via pr-validation.yml, which triggers on pull_request and workflow_dispatch — never on push to main. It therefore only ever analyzes PR merge refs, and its findings live and die with the PR.

Consequence: we have no standing Poutine coverage of main. Anything already merged has never been scanned. At time of writing, main has 3 open code scanning alerts, all from Scorecard, and zero from Poutine — not because main is clean, but because Poutine has never looked at it.

This was discovered while triaging code scanning alert #348 (default_permissions_on_risky_events on .github/workflows/pr-review.lock.yml), which was dismissed as a false positive: that file declares workflow-level permissions: {} (zero scopes) inherited by every job, but Poutine's utils.empty() helper cannot distinguish an empty permissions map from an absent one.

Scope

  1. Run a full Poutine scan against main (poutine analyze_local . or a one-off workflow_dispatch run) and capture the complete finding set.
  2. Triage each finding: genuine issue, false positive, or accepted risk.
  3. Address genuine findings in a follow-up PR.
  4. Record false positives as scoped skip entries in .poutine.yml with written justification, or dismiss with a documented reason.
  5. Decide whether Poutine should gain standing coverage of main — e.g. a scheduled run in weekly-security-maintenance.yml — so findings on merged code surface without waiting for an unrelated PR to touch them.

Notes

  • Poutine is advisory by design here: poutine-soft-fail: true is set in pr-validation.yml, so it cannot block a merge. The homegrown template-injection gate remains the only hard gate. See docs/security/dangerous-workflow-detection.md.
  • The action is SHA-pinned (boostsecurityio/poutine-action@e240ebd3eff8b2db5a8e5f6b28f58739d7db2247, v1.1.4), so the rule set only changes when that pin is bumped.
  • skip entries in .poutine.yml match on fields the rule actually emits. default_permissions_on_risky_events emits only path and event_triggers — not job — so suppression for that rule cannot be scoped narrower than an entire file. Prefer fixing or dismissing over broad skips.

Related follow-up

scripts/security/Test-WorkflowPermissions.ps1 currently only greps for a top-level ^permissions: block, so it scores 100% while individual jobs carry no declaration. Teaching it to walk jobs — and to distinguish workflow-level {} (provably zero) from an absent block (inherits repo/org defaults) — would enforce the job-level convention in .github/instructions/workflows.instructions.md as a hard gate. Worth pairing with this work or splitting into its own issue.

Metadata

Metadata

Labels

securitySecurity-related changes or concernstech-debtworkflowsGitHub Actions workflows

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions