From 1c3d1fd4a40ade857c25f15c449bf08f2feb5ef3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 03:19:21 +0000 Subject: [PATCH 1/2] ci: eliminate, then harden, every secret-bearing job RE001 reports Applies the safety triangle to the nine jobs that RE001 (standards ADR-009) reports on main: first remove a credential, and harden what remains. Eliminate: - security-policy secret-gitleaks: drop GITLEAKS_LICENSE. gitleaks-action needs one only for an organization owner, and logs "[hyperpolymath] is an individual user. No license key is required." The secret was never set (empty in the step env of run 40442141312). - inbox-steward analyze-patterns: the checkout is read-only, so it no longer takes FARM_PAT and persists no credential. - inbox-steward dispatch-to-farm: drop a checkout the job never read. Control: each remaining job installs step-security/harden-runner with egress-policy block and an allow-list of the hosts it talks to: - GitHub and its API for the inbox-steward jobs, both sweeps and roadmap-sync; - plus the artifact service for hypatia-remediation-sweep's upload; - for push-email-notify, the action's release download plus the SMTP host taken from the existing secret, so the host stays masked. actions.lock is regenerated by the tool in a following commit. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01J4QvDfStHgMdZGTeqaBgM1 --- .github/workflows/ci-health-sweep.yml | 9 +++++ .../workflows/hypatia-remediation-sweep.yml | 11 +++++ .github/workflows/inbox-steward-intake.yml | 40 +++++++++++++++++-- .github/workflows/push-email-notify.yml | 13 ++++++ .github/workflows/roadmap-sync.yml | 8 ++++ .github/workflows/security-policy.yml | 5 ++- 6 files changed, 82 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-health-sweep.yml b/.github/workflows/ci-health-sweep.yml index c26d8ecc..2a350152 100644 --- a/.github/workflows/ci-health-sweep.yml +++ b/.github/workflows/ci-health-sweep.yml @@ -45,6 +45,15 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # The checkout, and gh against the GitHub API (scripts/ci-health/). + allowed-endpoints: > + github.com:443 + api.github.com:443 + - uses: actions/checkout@v7.0.1 - name: Run CI-health sweep env: diff --git a/.github/workflows/hypatia-remediation-sweep.yml b/.github/workflows/hypatia-remediation-sweep.yml index b15c694f..f2a3e97c 100644 --- a/.github/workflows/hypatia-remediation-sweep.yml +++ b/.github/workflows/hypatia-remediation-sweep.yml @@ -62,6 +62,17 @@ jobs: timeout-minutes: 30 steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # gh against the GitHub API, plus the artifact service and its blob + # storage for the target-list upload. + allowed-endpoints: > + api.github.com:443 + results-receiver.actions.githubusercontent.com:443 + *.blob.core.windows.net:443 + - name: Resolve inputs id: cfg run: | diff --git a/.github/workflows/inbox-steward-intake.yml b/.github/workflows/inbox-steward-intake.yml index 938119c0..de6bd3a1 100644 --- a/.github/workflows/inbox-steward-intake.yml +++ b/.github/workflows/inbox-steward-intake.yml @@ -52,6 +52,15 @@ jobs: merged_count: ${{ steps.record.outputs.merged_count }} steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # git and gh against GitHub only. + allowed-endpoints: > + github.com:443 + api.github.com:443 + - name: Checkout hypatia uses: actions/checkout@v7.0.1 with: @@ -126,11 +135,22 @@ jobs: rule_updates: ${{ steps.analyze.outputs.rule_updates }} steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # git and gh against GitHub only. + allowed-endpoints: > + github.com:443 + api.github.com:443 + + # Read-only: nothing is pushed from this job, so the checkout needs no + # PAT and keeps none in .git/config. - name: Checkout hypatia uses: actions/checkout@v7.0.1 with: fetch-depth: 0 - token: ${{ secrets.FARM_PAT }} + persist-credentials: false - name: Analyze merged PR patterns id: analyze @@ -226,6 +246,15 @@ jobs: if: needs.analyze-patterns.result == 'success' && inputs.dry_run != 'true' steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # git and gh against GitHub only. + allowed-endpoints: > + github.com:443 + api.github.com:443 + - name: Checkout hypatia uses: actions/checkout@v7.0.1 with: @@ -279,8 +308,13 @@ jobs: if: always() && needs.record-report.result == 'success' steps: - - name: Checkout hypatia - uses: actions/checkout@v7.0.1 + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # One gh api call: the dispatch to .git-private-farm. + allowed-endpoints: > + api.github.com:443 - name: Send dispatch to .git-private-farm env: diff --git a/.github/workflows/push-email-notify.yml b/.github/workflows/push-email-notify.yml index 3cd69a56..2172e9b8 100644 --- a/.github/workflows/push-email-notify.yml +++ b/.github/workflows/push-email-notify.yml @@ -40,6 +40,19 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # The action downloads its pinned binary from its GitHub release, then + # speaks SMTP to the org mail host. The host is itself a secret, so it + # is allowed from the secret, and stays masked in the log. + allowed-endpoints: > + github.com:443 + release-assets.githubusercontent.com:443 + objects.githubusercontent.com:443 + ${{ secrets.SMTP_HOST }}:${{ secrets.SMTP_PORT || '465' }} + - name: Send push notification email uses: hyperpolymath/smtp-notify-action@v0.5.0 with: diff --git a/.github/workflows/roadmap-sync.yml b/.github/workflows/roadmap-sync.yml index eae7a233..6b4b6a63 100644 --- a/.github/workflows/roadmap-sync.yml +++ b/.github/workflows/roadmap-sync.yml @@ -46,6 +46,14 @@ jobs: EXCLUDE: 'idaptik burble rattlescript vcl-ut' WINDOW_MIN: ${{ inputs.window_min || '45' }} # look-back window (> cron interval for overlap) steps: + - name: Harden the runner + uses: step-security/harden-runner@v2.22.2 + with: + egress-policy: block + # The App token mint and every gh call go to the GitHub API. + allowed-endpoints: > + api.github.com:443 + - name: Mint App installation token id: app uses: actions/create-github-app-token@v3.3.0 diff --git a/.github/workflows/security-policy.yml b/.github/workflows/security-policy.yml index bfab5075..04817a25 100644 --- a/.github/workflows/security-policy.yml +++ b/.github/workflows/security-policy.yml @@ -302,7 +302,10 @@ jobs: uses: gitleaks/gitleaks-action@v3.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - GITLEAKS_LICENSE: ${{ secrets.GITLEAKS_LICENSE }} + # No GITLEAKS_LICENSE: gitleaks-action requires one only for an + # organization owner, and logs "[hyperpolymath] is an individual + # user. No license key is required." The secret was never set (the + # step's env showed it empty). Restore it if the repo moves to an org. secret-trufflehog: name: Secret Detection (TruffleHog) From 4c60f84ce740abd8c4cd93866b59624efed55c07 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 27 Oct 2026 03:21:33 +0000 Subject: [PATCH 2/2] ci: regenerate actions.lock for the harden-runner steps These are the exact bytes that `gh actions-lock` v0.2.0 and the standards 333b06a repair chain produced in run 40443523409. That run also passed check-lock-sync.sh and the governance gate's check-actions-lock-gate.sh (GATE_RC=0). sha256 74ebf8bebae57cbdf370f7014b1d58bfcafdabe09a4f1147d032434c09dbc995. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01J4QvDfStHgMdZGTeqaBgM1 --- .github/workflows/actions.lock | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/actions.lock b/.github/workflows/actions.lock index 8519497d..10b1b064 100644 --- a/.github/workflows/actions.lock +++ b/.github/workflows/actions.lock @@ -17,6 +17,7 @@ workflows: - 'taiki-e/install-action@v2.87.29' '.github/workflows/ci-health-sweep.yml': - 'actions/checkout@v7.0.1' + - 'step-security/harden-runner@v2.22.2' '.github/workflows/ci.yml': - 'actions/cache@v6.1.0' - 'actions/checkout@v7.0.1' @@ -50,10 +51,12 @@ workflows: - 'metadatastician/standards@333b06a01db1874ffedb2de1bfabb195640927c7' '.github/workflows/hypatia-remediation-sweep.yml': - 'actions/upload-artifact@v7.0.2' + - 'step-security/harden-runner@v2.22.2' '.github/workflows/hypatia-scan.yml': - 'metadatastician/standards@333b06a01db1874ffedb2de1bfabb195640927c7' '.github/workflows/inbox-steward-intake.yml': - 'actions/checkout@v7.0.1' + - 'step-security/harden-runner@v2.22.2' '.github/workflows/label-triage.yml': [] '.github/workflows/labels.yml': [] '.github/workflows/language-blockers.yml': @@ -71,6 +74,7 @@ workflows: - 'actions/upload-pages-artifact@v5.0.0' '.github/workflows/push-email-notify.yml': - 'hyperpolymath/smtp-notify-action@v0.5.0' + - 'step-security/harden-runner@v2.22.2' '.github/workflows/quality.yml': - 'actions/checkout@v7.0.1' - 'actions/deploy-pages@v5.0.1' @@ -94,6 +98,7 @@ workflows: - 'swatinem/rust-cache@v2.9.3' '.github/workflows/roadmap-sync.yml': - 'actions/create-github-app-token@v3.3.0' + - 'step-security/harden-runner@v2.22.2' '.github/workflows/rsr-oracle.yml': - 'actions/checkout@v7.0.1' - 'erlef/setup-beam@v1.24.1'