microsoft / microsoft/hve-core

Run a full Poutine scan of main and address findings

Open
#2,527 0 comments 1 reaction 1 assignee View on GitHub

@WilliamBerryiii is already working on this.

Since Jul 28, 2026.

security tech-debt workflows
Dominant language
Python
Stars
1.5k
Forks
301
Avg merge
3d 3h
Merged PRs (30d)
92

Description

## 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](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.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.