From a6ded7b33e8851e8d276c6b0eec386b9f4d48ff4 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 9 Oct 2026 00:02:19 +0100 Subject: [PATCH] ci: refresh standards pins to 900c42c; fix mirror startup failure governance-reusable@5a93d9d predates the Hypatia scanner-cache fix (standards#441, e9c8888) and Governance on main fails its own staleness gate on exactly that pin. Bump all three standards pins with scripts/propagate-workflow-pins.sh --to 900c42c70b96 (standards main). - governance.yml: grant actions: read, which the callee now requests. - scorecard.yml: the job-level map replaces read-all, so add actions: read (new in the callee) and drop secrets: inherit (callee reads none). - mirror.yml: secrets.* in a step `if:` is a workflow-file error, so every push to main died at startup with zero jobs. Call mirror-reusable instead, with an explicit secrets map; the per-forge vars._MIRROR_ENABLED gates now live in the callee. - The four edited workflows are KYAML (kyaml-format.sh), since the new pin is past 13b872c1 and gates read workflows with yq. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01GpUzjdhWFi26k6s7AWxYcf --- .github/workflows/governance.yml | 48 ++++--- .github/workflows/mirror.yml | 192 +++++---------------------- .github/workflows/scorecard.yml | 43 +++--- .github/workflows/secret-scanner.yml | 40 +++--- 4 files changed, 117 insertions(+), 206 deletions(-) diff --git a/.github/workflows/governance.yml b/.github/workflows/governance.yml index 8161ec2..72d41c0 100644 --- a/.github/workflows/governance.yml +++ b/.github/workflows/governance.yml @@ -1,16 +1,32 @@ -# SPDX-License-Identifier: PMPL-1.0-or-later -name: Governance - -on: - push: - branches: [main, master] - pull_request: - branches: [main, master] - workflow_dispatch: - -permissions: - contents: read - -jobs: - governance: - uses: hyperpolymath/standards/.github/workflows/governance-reusable.yml@5a93d9d57cc04de4002d6d0ecd336fc7a8698910 +# SPDX-License-Identifier: MPL-2.0 +{ + name: "Governance", + on: { + push: { + branches: [ + "main", + "master", + ], + }, + pull_request: { + branches: [ + "main", + "master", + ], + }, + workflow_dispatch: null, + }, + concurrency: { + group: "${{ github.workflow }}-${{ github.ref }}", + cancel-in-progress: true, + }, + permissions: { + actions: "read", # required by the reusable workflow (staleness check reads workflow runs) + contents: "read", + }, + jobs: { + governance: { + uses: "hyperpolymath/standards/.github/workflows/governance-reusable.yml@900c42c70b968e11a2bca04bf0ce050be5c286dc", + }, + }, +} diff --git a/.github/workflows/mirror.yml b/.github/workflows/mirror.yml index 0fb3b8c..eebb714 100644 --- a/.github/workflows/mirror.yml +++ b/.github/workflows/mirror.yml @@ -1,158 +1,38 @@ # SPDX-License-Identifier: MPL-2.0 # SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell -name: Mirror to Git Forges - -on: - push: - branches: [main] - workflow_dispatch: - -permissions: - contents: read - -jobs: - mirror-gitlab: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.GITLAB_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.GITLAB_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.GITLAB_SSH_KEY }} - - - name: Mirror to GitLab - run: | - ssh-keyscan -t ed25519 gitlab.com >> ~/.ssh/known_hosts - git remote add gitlab git@gitlab.com:${{ vars.GITLAB_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }}.git || true - git push --force gitlab main - - mirror-bitbucket: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.BITBUCKET_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.BITBUCKET_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.BITBUCKET_SSH_KEY }} - - - name: Mirror to Bitbucket - run: | - ssh-keyscan -t ed25519 bitbucket.org >> ~/.ssh/known_hosts - git remote add bitbucket git@bitbucket.org:${{ vars.BITBUCKET_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }}.git || true - git push --force bitbucket main - - mirror-codeberg: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.CODEBERG_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.CODEBERG_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.CODEBERG_SSH_KEY }} - - - name: Mirror to Codeberg - run: | - ssh-keyscan -t ed25519 codeberg.org >> ~/.ssh/known_hosts - git remote add codeberg git@codeberg.org:${{ vars.CODEBERG_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }}.git || true - git push --force codeberg main - - mirror-sourcehut: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.SOURCEHUT_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.SOURCEHUT_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.SOURCEHUT_SSH_KEY }} - - - name: Mirror to SourceHut - run: | - ssh-keyscan -t ed25519 git.sr.ht >> ~/.ssh/known_hosts - git remote add sourcehut git@git.sr.ht:~${{ vars.SOURCEHUT_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }} || true - git push --force sourcehut main - - mirror-disroot: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.DISROOT_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.DISROOT_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.DISROOT_SSH_KEY }} - - - name: Mirror to Disroot - run: | - ssh-keyscan -t ed25519 git.disroot.org >> ~/.ssh/known_hosts - git remote add disroot git@git.disroot.org:${{ vars.DISROOT_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }}.git || true - git push --force disroot main - - mirror-gitea: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.GITEA_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.GITEA_SSH_KEY != '' }} - with: - ssh-private-key: ${{ secrets.GITEA_SSH_KEY }} - - - name: Mirror to Gitea - run: | - ssh-keyscan -t ed25519 ${{ vars.GITEA_HOST }} >> ~/.ssh/known_hosts - git remote add gitea git@${{ vars.GITEA_HOST }}:${{ vars.GITEA_ORG || vars.MIRROR_ORG || github.repository_owner }}/${{ github.event.repository.name }}.git || true - git push --force gitea main - - mirror-radicle: - runs-on: ubuntu-latest - timeout-minutes: 15 - if: vars.RADICLE_MIRROR_ENABLED == 'true' - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - - - name: Setup Rust - uses: dtolnay/rust-toolchain@7e38f4b43b4db5c8dd498af069a4f6196df1d067 # stable - with: - toolchain: stable - - - name: Install Radicle - run: | - # Install via cargo (safer than curl|sh) - cargo install radicle-cli --locked - echo "$HOME/.cargo/bin" >> $GITHUB_PATH - - - name: Mirror to Radicle - run: | - echo "${{ secrets.RADICLE_KEY }}" > ~/.radicle/keys/radicle - chmod 600 ~/.radicle/keys/radicle - rad sync --announce || echo "Radicle sync attempted" +{ + name: "Mirror to Git Forges", + on: { + push: { + branches: [ + "main", + ], + }, + workflow_dispatch: null, + }, + concurrency: { + group: "${{ github.workflow }}-${{ github.ref }}", + cancel-in-progress: false, + }, + permissions: { + actions: "read", # required by the reusable workflow + contents: "read", + }, + jobs: { + mirror: { + uses: "hyperpolymath/standards/.github/workflows/mirror-reusable.yml@900c42c70b968e11a2bca04bf0ce050be5c286dc", + # Each forge job is still gated on vars._MIRROR_ENABLED, inside the + # callee. Explicit secrets map, no secrets: inherit; these seven are the + # callee's complete optional contract at 900c42c70b968e11a2bca04bf0ce050be5c286dc. + secrets: { + GITLAB_SSH_KEY: "${{ secrets.GITLAB_SSH_KEY }}", + BITBUCKET_SSH_KEY: "${{ secrets.BITBUCKET_SSH_KEY }}", + CODEBERG_SSH_KEY: "${{ secrets.CODEBERG_SSH_KEY }}", + SOURCEHUT_SSH_KEY: "${{ secrets.SOURCEHUT_SSH_KEY }}", + DISROOT_SSH_KEY: "${{ secrets.DISROOT_SSH_KEY }}", + GITEA_SSH_KEY: "${{ secrets.GITEA_SSH_KEY }}", + RADICLE_KEY: "${{ secrets.RADICLE_KEY }}", + }, + }, + }, +} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index d358265..ae8ad02 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -1,18 +1,27 @@ # SPDX-License-Identifier: MPL-2.0 -name: Scorecards supply-chain security - -on: - branch_protection_rule: - schedule: - - cron: '23 4 * * 1' - -permissions: read-all - -jobs: - analysis: - uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@81dbf2dd854b1444fd6236fa2352474383b2c2b9 - permissions: - contents: read - security-events: write - id-token: write - secrets: inherit +{ + name: "Scorecards supply-chain security", + on: { + branch_protection_rule: null, + schedule: [ + { + cron: "23 4 * * 1", + }, + ], + }, + permissions: "read-all", + jobs: { + analysis: { + uses: "hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@900c42c70b968e11a2bca04bf0ce050be5c286dc", + # A job-level map replaces the workflow-level one, so every scope the + # callee's jobs request must be listed here. actions: read is new in the + # callee since 81dbf2dd. No secrets: the callee declares and reads none. + permissions: { + actions: "read", + contents: "read", + security-events: "write", + id-token: "write", + }, + }, + }, +} diff --git a/.github/workflows/secret-scanner.yml b/.github/workflows/secret-scanner.yml index fa6eb1f..1f3a824 100644 --- a/.github/workflows/secret-scanner.yml +++ b/.github/workflows/secret-scanner.yml @@ -8,20 +8,26 @@ # No `secrets:` line, deliberately: the reusable references no secrets # (gitleaks runs as a checksum-verified binary, not gitleaks-action), so # `secrets: inherit` would only hand it every repo and org secret (CWE-250). -name: Secret Scanner - -on: - pull_request: - push: - branches: [main] - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -permissions: - contents: read - -jobs: - scan: - uses: hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@74d2f66f575246cf6e313ae7775f44df6e097ff2 +{ + name: "Secret Scanner", + on: { + pull_request: null, + push: { + branches: [ + "main", + ], + }, + }, + concurrency: { + group: "${{ github.workflow }}-${{ github.ref }}", + cancel-in-progress: true, + }, + permissions: { + contents: "read", + }, + jobs: { + scan: { + uses: "hyperpolymath/standards/.github/workflows/secret-scanner-reusable.yml@900c42c70b968e11a2bca04bf0ce050be5c286dc", + }, + }, +}