From 26b222002c21502c9daf8f55fe78099217553647 Mon Sep 17 00:00:00 2001 From: Thomas Jung <12159356+jung-thomas@users.noreply.github.com> Date: Fri, 12 Jun 2026 12:22:04 -0400 Subject: [PATCH] ci(ospo): add three PR controls + admin emergency bypass OSPO compliance request (deadline 16 June 2026) flagged three missing controls on the main-protection ruleset. Add them now under our own ruleset so the posture is explicit before central enforcement: - dismiss_stale_reviews_on_push: false -> true - require_last_push_approval: false -> true - required_review_thread_resolution: false -> true Per project-owner request, also re-add a narrow bypass actor: - bypass_actors: [] -> RepositoryRole/5 (admin), bypass_mode pull_request This regresses OSPO Control 5 (PR #22 had removed the admin bypass entirely) and is documented in CLAUDE.md as an explicit owner decision. The bypass is pull_request mode only: admins still cannot force-push or delete main, only merge a PR without satisfying the new review/resolution checks during an emergency. Using RepositoryRole/5 (well-known id for the 'admin' role) instead of enumerating Users avoids drift as the admin roster changes (see docs/ospo-admin-demotion-draft.md, an active demotion effort) and avoids the Integration actor type that the SAP-samples org rejected with HTTP 422 in PR #23. Apply order matches PR #22/#23: this PR commits the JSON spec; the gh api PUT to import it server-side runs after merge. If the org rejects RepositoryRole/5 with HTTP 422, the fallback is to ship the three required controls with bypass_actors:[] (the 16 June deadline is binding; bypass is owner preference). Refs: docs/ospo-admin-demotion-draft.md, .github/rulesets/main-protection.json --- .github/rulesets/main-protection.json | 10 ++++++---- CLAUDE.md | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/rulesets/main-protection.json b/.github/rulesets/main-protection.json index d3a00a2..ebb2de4 100644 --- a/.github/rulesets/main-protection.json +++ b/.github/rulesets/main-protection.json @@ -15,10 +15,10 @@ "type": "pull_request", "parameters": { "required_approving_review_count": 1, - "dismiss_stale_reviews_on_push": false, + "dismiss_stale_reviews_on_push": true, "require_code_owner_review": false, - "require_last_push_approval": false, - "required_review_thread_resolution": false + "require_last_push_approval": true, + "required_review_thread_resolution": true } }, { @@ -31,5 +31,7 @@ } } ], - "bypass_actors": [] + "bypass_actors": [ + {"actor_id": 5, "actor_type": "RepositoryRole", "bypass_mode": "pull_request"} + ] } diff --git a/CLAUDE.md b/CLAUDE.md index e57a820..2989f09 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -230,7 +230,7 @@ gh release edit vX.Y.Z --draft=false --latest --notes "release notes here" 3. `sign-windows.yml` (workflow_run on Tray success, env: `signing`) → **pauses for required-reviewer approval** (OSPO gate), then Authenticode-signs Windows `.exe` binaries via SignPath.io and publishes the release (best-effort) 4. Manual: `gh release edit --draft=false` only needed if signing is skipped — otherwise the signing job publishes automatically after approval -**OSPO compliance:** `main` is protected by ruleset (`main-protection`: requires PR + CI `test` check, blocks force-push and deletion). **No actor — including admins and `github-actions[bot]` — can bypass.** Every change to `main` goes through a PR with one approving review and a passing `test` check. Automated PRs (notably `news-sync`) open the PR and arm `gh pr merge --auto`; a maintainer must approve them, and the merge then fires automatically. (The SAP-samples org doesn't allow Integration `github-actions[bot]` as a bypass actor at the repo level, so the bot cannot self-merge — that's why a human approval is in the loop.) Workflows that touch secrets or publish artifacts run in named environments: `release`, `signing` (required reviewer = repo admin), `news-sync`. SignPath secrets and `YOUTUBE_API_KEY` should be scoped to their respective environments rather than the org/repo level. Ruleset spec: [.github/rulesets/main-protection.json](.github/rulesets/main-protection.json). +**OSPO compliance:** `main` is protected by ruleset (`main-protection`: requires PR + 1 approval + CI `test` check, blocks force-push and deletion, dismisses stale approvals on new commits, requires approval of the most recent reviewable push, and requires conversation resolution before merging — added June 2026 ahead of central enforcement on 16 June 2026). **Repo admins retain a `pull_request`-mode bypass for emergency merges; this regresses OSPO Control 5 and is documented as an explicit owner decision (June 2026).** No other actor — including `github-actions[bot]` — can bypass. Every change to `main` goes through a PR with one approving review and a passing `test` check. Automated PRs (notably `news-sync`) open the PR and arm `gh pr merge --auto`; a maintainer must approve them, and the merge then fires automatically. (The SAP-samples org doesn't allow Integration `github-actions[bot]` as a bypass actor at the repo level, so the bot cannot self-merge — that's why a human approval is in the loop.) Workflows that touch secrets or publish artifacts run in named environments: `release`, `signing` (required reviewer = repo admin), `news-sync`. SignPath secrets and `YOUTUBE_API_KEY` should be scoped to their respective environments rather than the org/repo level. Ruleset spec: [.github/rulesets/main-protection.json](.github/rulesets/main-protection.json). **Artifacts per release:** CLI binaries (linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64) + tray binaries (linux/amd64, darwin/arm64, windows/amd64) + checksums + tray-checksums + Scoop manifest + Homebrew cask.