From 1ac9e2addac5c15c8307a4ef543c9ee1336060c8 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:09:14 +0100 Subject: [PATCH] fix(ci): hoist secrets to job env in mirror-reusable; refresh example SHAs mirror-reusable.yml (two real bugs): - Remove duplicate `if:` key on the "Mirror to GitLab" step. - The `secrets` context is not valid in step-level `if:` (it is an "Unrecognized named-value: 'secrets'" startup failure). Hoist each forge secret to a job-level `env:` block and gate every step `if:` on `env._KEY` instead of `secrets._SSH_KEY`, matching the already-correct `mirror-radicle` pattern. Applies to all six forge jobs (gitlab, bitbucket, codeberg, sourcehut, disroot, gitea). Behaviour identical; only the reference site moves. actionlint clean. {elixir,deno,rust,changelog}-*-reusable.yml: - Refresh the stale copy-paste example SHA in the header comments (861b5e9 -> 4762ba6, current main HEAD) so new adopters copy a current pin. Comment-only. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/changelog-reusable.yml | 2 +- .github/workflows/deno-ci-reusable.yml | 2 +- .github/workflows/elixir-ci-reusable.yml | 6 +-- .github/workflows/mirror-reusable.yml | 63 +++++++++++++++++------- .github/workflows/rust-ci-reusable.yml | 8 +-- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/.github/workflows/changelog-reusable.yml b/.github/workflows/changelog-reusable.yml index 2e4c81b9..2a94a6c4 100644 --- a/.github/workflows/changelog-reusable.yml +++ b/.github/workflows/changelog-reusable.yml @@ -10,7 +10,7 @@ # Caller example (auto-update CHANGELOG.md on every push to main): # jobs: # changelog: -# uses: hyperpolymath/standards/.github/workflows/changelog-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/changelog-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # permissions: # contents: write # pull-requests: write diff --git a/.github/workflows/deno-ci-reusable.yml b/.github/workflows/deno-ci-reusable.yml index 9924526a..e0a0f5d3 100644 --- a/.github/workflows/deno-ci-reusable.yml +++ b/.github/workflows/deno-ci-reusable.yml @@ -23,7 +23,7 @@ # # jobs: # deno-ci: -# uses: hyperpolymath/standards/.github/workflows/deno-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/deno-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a name: Deno CI (reusable) diff --git a/.github/workflows/elixir-ci-reusable.yml b/.github/workflows/elixir-ci-reusable.yml index 3af1968a..81bfd658 100644 --- a/.github/workflows/elixir-ci-reusable.yml +++ b/.github/workflows/elixir-ci-reusable.yml @@ -33,13 +33,13 @@ # # jobs: # elixir-ci: -# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # # With dialyzer + customised versions: # # jobs: # elixir-ci: -# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # with: # elixir-version: "1.18" # enable_dialyzer: true @@ -49,7 +49,7 @@ # # jobs: # elixir-ci: -# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/elixir-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # with: # working_directory: server diff --git a/.github/workflows/mirror-reusable.yml b/.github/workflows/mirror-reusable.yml index bad602f9..2ecaf4f8 100644 --- a/.github/workflows/mirror-reusable.yml +++ b/.github/workflows/mirror-reusable.yml @@ -51,29 +51,34 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.GITLAB_MIRROR_ENABLED == 'true' + # Map the secret to env so step `if:`s can gate on its presence: the + # `secrets` context is NOT available in `if:` (using it is an + # "Unrecognized named-value: 'secrets'" startup failure). `env` IS + # available in step `if:`, and secrets are valid in job-level `env`. + env: + GITLAB_KEY: ${{ secrets.GITLAB_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.GITLAB_SSH_KEY != '' }} + if: ${{ env.GITLAB_KEY != '' }} with: ssh-private-key: ${{ secrets.GITLAB_SSH_KEY }} - name: Mirror to GitLab - if: ${{ secrets.GITLAB_SSH_KEY != '' }} # continue-on-error: GitLab branch protection on the mirror repo may block # force-push even for a deploy key. Owner action required: in GitLab go to # Settings → Repository → Protected branches → main and either allow force-push # for Maintainers/Developers or remove the protection on the mirror repo. # Until then this step is advisory-only; failures do not red main. continue-on-error: true - if: ${{ secrets.GITLAB_SSH_KEY != '' }} + if: ${{ env.GITLAB_KEY != '' }} run: | ssh-keyscan -t ed25519 gitlab.com >> ~/.ssh/known_hosts git remote add gitlab git@gitlab.com:hyperpolymath/${{ github.event.repository.name }}.git || true git push --force gitlab main - name: Skipped (GITLAB_SSH_KEY not configured) - if: ${{ secrets.GITLAB_SSH_KEY == '' }} + if: ${{ env.GITLAB_KEY == '' }} run: | echo "::notice::GITLAB_MIRROR_ENABLED=true but secrets.GITLAB_SSH_KEY is empty. Skipping GitLab mirror. Configure the GITLAB_SSH_KEY org/repo secret to enable." @@ -81,22 +86,26 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.BITBUCKET_MIRROR_ENABLED == 'true' + # See mirror-gitlab: the `secrets` context is not valid in step `if:`; + # hoist to job-level `env` and gate steps on `env.BITBUCKET_KEY`. + env: + BITBUCKET_KEY: ${{ secrets.BITBUCKET_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.BITBUCKET_SSH_KEY != '' }} + if: ${{ env.BITBUCKET_KEY != '' }} with: ssh-private-key: ${{ secrets.BITBUCKET_SSH_KEY }} - name: Mirror to Bitbucket - if: ${{ secrets.BITBUCKET_SSH_KEY != '' }} + if: ${{ env.BITBUCKET_KEY != '' }} run: | ssh-keyscan -t ed25519 bitbucket.org >> ~/.ssh/known_hosts git remote add bitbucket git@bitbucket.org:hyperpolymath/${{ github.event.repository.name }}.git || true git push --force bitbucket main - name: Skipped (BITBUCKET_SSH_KEY not configured) - if: ${{ secrets.BITBUCKET_SSH_KEY == '' }} + if: ${{ env.BITBUCKET_KEY == '' }} run: | echo "::notice::BITBUCKET_MIRROR_ENABLED=true but secrets.BITBUCKET_SSH_KEY is empty. Skipping Bitbucket mirror. Configure the BITBUCKET_SSH_KEY org/repo secret to enable." @@ -104,22 +113,26 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.CODEBERG_MIRROR_ENABLED == 'true' + # See mirror-gitlab: the `secrets` context is not valid in step `if:`; + # hoist to job-level `env` and gate steps on `env.CODEBERG_KEY`. + env: + CODEBERG_KEY: ${{ secrets.CODEBERG_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.CODEBERG_SSH_KEY != '' }} + if: ${{ env.CODEBERG_KEY != '' }} with: ssh-private-key: ${{ secrets.CODEBERG_SSH_KEY }} - name: Mirror to Codeberg - if: ${{ secrets.CODEBERG_SSH_KEY != '' }} + if: ${{ env.CODEBERG_KEY != '' }} run: | ssh-keyscan -t ed25519 codeberg.org >> ~/.ssh/known_hosts git remote add codeberg git@codeberg.org:hyperpolymath/${{ github.event.repository.name }}.git || true git push --force codeberg main - name: Skipped (CODEBERG_SSH_KEY not configured) - if: ${{ secrets.CODEBERG_SSH_KEY == '' }} + if: ${{ env.CODEBERG_KEY == '' }} run: | echo "::notice::CODEBERG_MIRROR_ENABLED=true but secrets.CODEBERG_SSH_KEY is empty. Skipping Codeberg mirror. Configure the CODEBERG_SSH_KEY org/repo secret to enable." @@ -127,22 +140,26 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.SOURCEHUT_MIRROR_ENABLED == 'true' + # See mirror-gitlab: the `secrets` context is not valid in step `if:`; + # hoist to job-level `env` and gate steps on `env.SOURCEHUT_KEY`. + env: + SOURCEHUT_KEY: ${{ secrets.SOURCEHUT_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.SOURCEHUT_SSH_KEY != '' }} + if: ${{ env.SOURCEHUT_KEY != '' }} with: ssh-private-key: ${{ secrets.SOURCEHUT_SSH_KEY }} - name: Mirror to SourceHut - if: ${{ secrets.SOURCEHUT_SSH_KEY != '' }} + if: ${{ env.SOURCEHUT_KEY != '' }} run: | ssh-keyscan -t ed25519 git.sr.ht >> ~/.ssh/known_hosts git remote add sourcehut git@git.sr.ht:~hyperpolymath/${{ github.event.repository.name }} || true git push --force sourcehut main - name: Skipped (SOURCEHUT_SSH_KEY not configured) - if: ${{ secrets.SOURCEHUT_SSH_KEY == '' }} + if: ${{ env.SOURCEHUT_KEY == '' }} run: | echo "::notice::SOURCEHUT_MIRROR_ENABLED=true but secrets.SOURCEHUT_SSH_KEY is empty. Skipping SourceHut mirror. Configure the SOURCEHUT_SSH_KEY org/repo secret to enable." @@ -150,22 +167,26 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.DISROOT_MIRROR_ENABLED == 'true' + # See mirror-gitlab: the `secrets` context is not valid in step `if:`; + # hoist to job-level `env` and gate steps on `env.DISROOT_KEY`. + env: + DISROOT_KEY: ${{ secrets.DISROOT_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.DISROOT_SSH_KEY != '' }} + if: ${{ env.DISROOT_KEY != '' }} with: ssh-private-key: ${{ secrets.DISROOT_SSH_KEY }} - name: Mirror to Disroot - if: ${{ secrets.DISROOT_SSH_KEY != '' }} + if: ${{ env.DISROOT_KEY != '' }} run: | ssh-keyscan -t ed25519 git.disroot.org >> ~/.ssh/known_hosts git remote add disroot git@git.disroot.org:hyperpolymath/${{ github.event.repository.name }}.git || true git push --force disroot main - name: Skipped (DISROOT_SSH_KEY not configured) - if: ${{ secrets.DISROOT_SSH_KEY == '' }} + if: ${{ env.DISROOT_KEY == '' }} run: | echo "::notice::DISROOT_MIRROR_ENABLED=true but secrets.DISROOT_SSH_KEY is empty. Skipping Disroot mirror. Configure the DISROOT_SSH_KEY org/repo secret to enable." @@ -173,22 +194,26 @@ jobs: timeout-minutes: 20 runs-on: ${{ inputs.runs-on }} if: vars.GITEA_MIRROR_ENABLED == 'true' + # See mirror-gitlab: the `secrets` context is not valid in step `if:`; + # hoist to job-level `env` and gate steps on `env.GITEA_KEY`. + env: + GITEA_KEY: ${{ secrets.GITEA_SSH_KEY }} steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: 0 - uses: webfactory/ssh-agent@e83874834305fe9a4a2997156cb26c5de65a8555 # v0.10.0 - if: ${{ secrets.GITEA_SSH_KEY != '' }} + if: ${{ env.GITEA_KEY != '' }} with: ssh-private-key: ${{ secrets.GITEA_SSH_KEY }} - name: Mirror to Gitea - if: ${{ secrets.GITEA_SSH_KEY != '' }} + if: ${{ env.GITEA_KEY != '' }} run: | ssh-keyscan -t ed25519 ${{ vars.GITEA_HOST }} >> ~/.ssh/known_hosts git remote add gitea git@${{ vars.GITEA_HOST }}:hyperpolymath/${{ github.event.repository.name }}.git || true git push --force gitea main - name: Skipped (GITEA_SSH_KEY not configured) - if: ${{ secrets.GITEA_SSH_KEY == '' }} + if: ${{ env.GITEA_KEY == '' }} run: | echo "::notice::GITEA_MIRROR_ENABLED=true but secrets.GITEA_SSH_KEY is empty. Skipping Gitea mirror. Configure the GITEA_SSH_KEY org/repo secret to enable." diff --git a/.github/workflows/rust-ci-reusable.yml b/.github/workflows/rust-ci-reusable.yml index 939c36af..c36e3202 100644 --- a/.github/workflows/rust-ci-reusable.yml +++ b/.github/workflows/rust-ci-reusable.yml @@ -19,13 +19,13 @@ # # jobs: # rust-ci: -# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # # With audit + coverage enabled: # # jobs: # rust-ci: -# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # with: # enable_audit: true # enable_coverage: true @@ -34,11 +34,11 @@ # # jobs: # rust-ci-cli: -# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # with: # working_directory: crates/cli # rust-ci-server: -# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@861b5e911d9e5dcfb3c0ab3dd2a9a3c8fd0a1613 +# uses: hyperpolymath/standards/.github/workflows/rust-ci-reusable.yml@4762ba66441de05bccb36e074ba3d2202219126a # with: # working_directory: crates/server #