diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 66d46c9..7bd42d9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -95,6 +95,10 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} + # Write deploy keys on simtabi/homebrew-tap and simtabi/scoop-bucket. When set, GoReleaser + # pushes with them and the token is not used for those two. + HOMEBREW_TAP_DEPLOY_KEY: ${{ secrets.HOMEBREW_TAP_DEPLOY_KEY }} + SCOOP_BUCKET_DEPLOY_KEY: ${{ secrets.SCOOP_BUCKET_DEPLOY_KEY }} # Scoop/Winget publishing is skipped until the bucket/fork exist. Set # repo variable SKIP_WINDOWS_PKGS to "false" to enable it. SKIP_WINDOWS_PKGS: ${{ vars.SKIP_WINDOWS_PKGS || 'true' }} diff --git a/docs/release.md b/docs/release.md index a85b1b8..e130fb9 100644 --- a/docs/release.md +++ b/docs/release.md @@ -59,8 +59,10 @@ matching native one per OS. The binary version comes from the tag via ldflags ## Channels still to wire (need external setup) Homebrew cask, Scoop manifest, and Linux packages (deb/rpm/apk) are not yet in -`release.yml`. They need the `simtabi/homebrew-tap` and `simtabi/scoop-bucket` -repos plus a `TAP_GITHUB_TOKEN` secret; add them once those exist. +`release.yml`. GoReleaser publishes the cask and the Scoop manifest with the +write deploy keys `HOMEBREW_TAP_DEPLOY_KEY` (on `simtabi/homebrew-tap`) and `SCOOP_BUCKET_DEPLOY_KEY` (on `simtabi/scoop-bucket`), each a repository secret that reaches its one repository and nothing else. The tap requires a pull request on `main`, with deploy keys +as its one bypass actor. `TAP_GITHUB_TOKEN` is only the fallback when a key is +missing, and the Winget pull request's token. ## GitHub Actions hygiene diff --git a/src/.goreleaser.yaml b/src/.goreleaser.yaml index bfc3158..d60ae52 100644 --- a/src/.goreleaser.yaml +++ b/src/.goreleaser.yaml @@ -124,17 +124,22 @@ sboms: homebrew_casks: - name: sshmgr ids: [archive] - # envOrDefault, not .Env.X: .Env only holds variables that are actually set, - # so referencing a missing one is a template error that fails the whole - # release. It survives in CI only because `env:` assigns the secret - # unconditionally, making it present-but-empty - which means `make dist` was - # broken for anyone whose shell had never exported it, and the release - # config depended on a property of the workflow rather than of itself. - skip_upload: '{{ if envOrDefault "TAP_GITHUB_TOKEN" "" }}false{{ else }}true{{ end }}' + # Skipped unless a token or the deploy key is present, so `make dist` works in a + # shell that exported neither. envOrDefault is right here, but NOT in `token:` + # below: GoReleaser 2.18.3 does not define it in that field ("function + # envOrDefault not defined", measured), so the token stays .Env, which a skipped + # cask never evaluates and a git push with the key never needs. + skip_upload: '{{ if or (envOrDefault "TAP_GITHUB_TOKEN" "") (envOrDefault "HOMEBREW_TAP_DEPLOY_KEY" "") }}false{{ else }}true{{ end }}' repository: owner: simtabi name: homebrew-tap - token: "{{ envOrDefault \"TAP_GITHUB_TOKEN\" \"\" }}" + token: "{{ .Env.TAP_GITHUB_TOKEN }}" + # Write deploy key on simtabi/homebrew-tap (secret HOMEBREW_TAP_DEPLOY_KEY): reaches that + # one repository only. Set, git pushes with it; unset, the URL is empty and the token + # path above runs. Measured with GoReleaser 2.18.3. + git: + url: '{{ if envOrDefault "HOMEBREW_TAP_DEPLOY_KEY" "" }}git@github.com:simtabi/homebrew-tap.git{{ end }}' + private_key: '{{ envOrDefault "HOMEBREW_TAP_DEPLOY_KEY" "" }}' directory: Casks homepage: "https://opensource.simtabi.com/products/simtabi/ssh-manager" description: "Profile-based SSH key and config lifecycle manager." @@ -153,7 +158,13 @@ scoops: repository: owner: simtabi name: scoop-bucket - token: "{{ envOrDefault \"TAP_GITHUB_TOKEN\" \"\" }}" + token: "{{ .Env.TAP_GITHUB_TOKEN }}" + # Write deploy key on simtabi/scoop-bucket (secret SCOOP_BUCKET_DEPLOY_KEY): reaches that + # one repository only. Set, git pushes with it; unset, the URL is empty and the token + # path above runs. Measured with GoReleaser 2.18.3. + git: + url: '{{ if envOrDefault "SCOOP_BUCKET_DEPLOY_KEY" "" }}git@github.com:simtabi/scoop-bucket.git{{ end }}' + private_key: '{{ envOrDefault "SCOOP_BUCKET_DEPLOY_KEY" "" }}' directory: bucket homepage: "https://opensource.simtabi.com/products/simtabi/ssh-manager" description: "Profile-based SSH key and config lifecycle manager." @@ -177,7 +188,7 @@ winget: owner: simtabi name: winget-pkgs branch: "sshmgr-{{ .Version }}" - token: "{{ envOrDefault \"TAP_GITHUB_TOKEN\" \"\" }}" + token: "{{ .Env.TAP_GITHUB_TOKEN }}" pull_request: enabled: true draft: false