feat(init): §1.5.1 secret-ingress hardening for jtk + cfl init (#390)… #110
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release jtk | |
| on: | |
| push: | |
| tags: | |
| - 'jtk-v*' | |
| permissions: | |
| contents: write | |
| jobs: | |
| goreleaser: | |
| # INT-450: darwin must build with cgo (Keychain backend). cgo+darwin | |
| # cannot cross-compile from Linux, so this job runs on macOS. Pinned | |
| # image (not the moving macos-latest label) for a reproducible release. | |
| runs-on: macos-15 | |
| outputs: | |
| version: ${{ steps.get_version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Get version from tag | |
| id: get_version | |
| run: | | |
| VERSION=${GITHUB_REF#refs/tags/jtk-v} | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| - uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.26' | |
| cache-dependency-path: tools/jtk/go.sum | |
| - name: Install GoReleaser | |
| uses: goreleaser/goreleaser-action@v6 | |
| with: | |
| version: "~> v2" | |
| install-only: true | |
| - name: GoReleaser check | |
| run: goreleaser check -f .goreleaser-jtk.yml | |
| - name: Create temporary semver tag for GoReleaser | |
| run: | | |
| git tag v${{ steps.get_version.outputs.version }} | |
| - name: Build (snapshot, no publish) | |
| env: | |
| GORELEASER_CURRENT_TAG: v${{ steps.get_version.outputs.version }} | |
| run: goreleaser release --snapshot --clean -f .goreleaser-jtk.yml | |
| # INT-450 pre-publish gate: prove the darwin binaries actually carry | |
| # the Keychain backend BEFORE anything is published. A CGO_ENABLED=0 | |
| # darwin build links no Security.framework and fails closed at | |
| # runtime; this gate makes that impossible to ship silently. | |
| - name: Pre-publish gate — darwin Keychain backend present | |
| run: | | |
| set -euo pipefail | |
| art=dist/artifacts.json | |
| arm_bin=$(jq -r '.[]|select(.type=="Binary" and .goos=="darwin" and .goarch=="arm64")|.path' "$art") | |
| amd_bin=$(jq -r '.[]|select(.type=="Binary" and .goos=="darwin" and .goarch=="amd64")|.path' "$art") | |
| [ -n "$arm_bin" ] && [ -n "$amd_bin" ] || { echo "missing a darwin binary in artifacts.json"; exit 1; } | |
| # darwin archives: exactly one per arch, no duplicate names | |
| tot=$(jq '[.[]|select(.type=="Archive" and .goos=="darwin")|.name]|length' "$art") | |
| uniq=$(jq '[.[]|select(.type=="Archive" and .goos=="darwin")|.name]|unique|length' "$art") | |
| [ "$tot" = "$uniq" ] || { echo "duplicate darwin archive names"; exit 1; } | |
| [ "$(jq '[.[]|select(.type=="Archive" and .goos=="darwin" and .goarch=="arm64")]|length' "$art")" = 1 ] || { echo "expected exactly one darwin/arm64 archive"; exit 1; } | |
| [ "$(jq '[.[]|select(.type=="Archive" and .goos=="darwin" and .goarch=="amd64")]|length' "$art")" = 1 ] || { echo "expected exactly one darwin/amd64 archive"; exit 1; } | |
| # Mach-O arch sanity (both slices) | |
| file "$arm_bin" | grep -q 'arm64' || { echo "arm64 binary is not arm64 Mach-O"; exit 1; } | |
| file "$amd_bin" | grep -q 'x86_64' || { echo "amd64 binary is not x86_64 Mach-O"; exit 1; } | |
| lipo -archs "$arm_bin" | grep -qw arm64 || { echo "lipo: arm64 slice missing"; exit 1; } | |
| lipo -archs "$amd_bin" | grep -qw x86_64 || { echo "lipo: x86_64 slice missing"; exit 1; } | |
| # amd64 cannot run on the arm64 runner: assert Security.framework | |
| # is linked. CGO_ENABLED=0 omits it entirely, so its presence is a | |
| # sound *necessary* cgo signal for the slice we can't execute. | |
| otool -L "$amd_bin" | grep -q '/System/Library/Frameworks/Security.framework' \ | |
| || { echo "amd64 binary not linked against Security.framework (cgo missing)"; exit 1; } | |
| # arm64 authoritative functional check: with no backend override | |
| # and isolated HOME/XDG, credstore must auto-select the Keychain. | |
| # jtk config show emits a pipe-delimited table; we grep for the | |
| # keyring_backend row containing "keychain (auto)". | |
| tmp=$(mktemp -d) | |
| mkdir -p "$tmp/Library/Application Support/atlassian-cli" | |
| out=$(env -u ATLASSIAN_CLI_KEYRING_BACKEND \ | |
| -u JIRA_API_TOKEN -u ATLASSIAN_API_TOKEN \ | |
| HOME="$tmp" XDG_CONFIG_HOME="$tmp/xdg" \ | |
| "$arm_bin" config show 2>/dev/null) | |
| echo "$out" | |
| echo "$out" | grep -q 'keychain (auto)' \ | |
| || { echo "GATE FAIL: keychain (auto) not found in jtk config show output"; exit 1; } | |
| echo "GATE OK: darwin/arm64 reports keychain backend auto-selected; darwin/amd64 Security.framework linked" | |
| - name: Release notes | |
| run: | | |
| set -euo pipefail | |
| cat > "$RUNNER_TEMP/release-notes.md" <<'EOF' | |
| ### macOS Keychain storage restored | |
| Builds since the credential-store migration were compiled without | |
| cgo and failed closed on macOS (no Keychain backend). This release | |
| builds the darwin binaries with cgo enabled, restoring native | |
| macOS Keychain storage. Upgrade and re-run your normal commands; | |
| no other action is required. | |
| EOF | |
| - name: Release (publish) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAP_GITHUB_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} | |
| GORELEASER_CURRENT_TAG: v${{ steps.get_version.outputs.version }} | |
| run: goreleaser release --clean -f .goreleaser-jtk.yml --release-notes="$RUNNER_TEMP/release-notes.md" | |
| - name: Fix release tag | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version }} | |
| gh release edit "v${VERSION}" --tag "jtk-v${VERSION}" --title "jtk v${VERSION}" | |
| git push origin :refs/tags/v${VERSION} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Verify release notes published | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| VERSION=${{ steps.get_version.outputs.version }} | |
| body=$(gh release view "jtk-v${VERSION}" --repo "$GITHUB_REPOSITORY" --json body -q .body) | |
| if ! printf '%s' "$body" | grep -q 'macOS Keychain'; then | |
| gh release edit "jtk-v${VERSION}" --repo "$GITHUB_REPOSITORY" --notes-file "$RUNNER_TEMP/release-notes.md" | |
| fi | |
| - name: Update jira-ticket-cli alias cask | |
| run: | | |
| VERSION=${{ steps.get_version.outputs.version }} | |
| git clone https://x-access-token:${TAP_TOKEN}@github.com/open-cli-collective/homebrew-tap.git tap | |
| cd tap | |
| sed -e 's/cask "jtk"/cask "jira-ticket-cli"/' \ | |
| -e 's/name "jtk"/name "jira-ticket-cli"/' \ | |
| Casks/jtk.rb > Casks/jira-ticket-cli.rb | |
| git add Casks/jira-ticket-cli.rb | |
| git diff --cached --quiet && exit 0 | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git commit -m "Update jira-ticket-cli alias cask for v${VERSION}" | |
| git push | |
| env: | |
| TAP_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }} | |
| # chocolatey-publish-jtk.yml and winget-publish-jtk.yml are dispatched | |
| # automatically by the trigger-publish job below. They remain in separate | |
| # workflow files (workflow_dispatch only) so Microsoft-hosted service | |
| # flakiness in wingetcreate fork-sync or choco push does not gate the | |
| # binary/Homebrew artifacts. | |
| trigger-publish: | |
| needs: goreleaser | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| permissions: | |
| actions: write | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ needs.goreleaser.outputs.version }} | |
| steps: | |
| - name: Trigger Chocolatey publish | |
| continue-on-error: true | |
| run: gh workflow run chocolatey-publish-jtk.yml -f version="$VERSION" --ref main --repo "$GITHUB_REPOSITORY" | |
| - name: Trigger Winget publish | |
| continue-on-error: true | |
| run: gh workflow run winget-publish-jtk.yml -f version="$VERSION" --ref main --repo "$GITHUB_REPOSITORY" | |
| linux-packages: | |
| needs: goreleaser | |
| runs-on: ubuntu-latest | |
| continue-on-error: true | |
| steps: | |
| - name: Trigger linux-packages repo update | |
| uses: peter-evans/repository-dispatch@v3 | |
| with: | |
| token: ${{ secrets.LINUX_PACKAGES_DISPATCH_TOKEN }} | |
| repository: open-cli-collective/linux-packages | |
| event-type: package-release | |
| client-payload: |- | |
| { | |
| "package": "jtk", | |
| "version": "${{ github.ref_name }}", | |
| "repo": "open-cli-collective/atlassian-cli" | |
| } |