Skip to content

ci: replace secrets inherit with explicit secrets in release pipeline - #1196

Open
ital0 wants to merge 3 commits into
mainfrom
cursor/sec-release-explicit-secrets
Open

ci: replace secrets inherit with explicit secrets in release pipeline#1196
ital0 wants to merge 3 commits into
mainfrom
cursor/sec-release-explicit-secrets

Conversation

@ital0

@ital0 ital0 commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Fixes code-scanning alerts #82, #83, #84, #85 (yaml.github-actions.security.secrets-inherit).

Changes

release.yml passed all repository secrets to its four called workflows via secrets: inherit. Each reusable workflow now declares exactly the secrets it references in on.workflow_call.secrets, and release.yml passes exactly those:

Workflow Secrets
version-bump.yml RELEASE_APP_CLIENT_ID, RELEASE_APP_PRIVATE_KEY
desktop-release.yml Apple signing/notarization (6), CRABNEBULA_CLOUD_API_KEY, Tauri updater key pair (2), APPLE_TEAM_ID
ios-release.yml Apple cert/profile (3), App Store Connect API (3), APPLE_TEAM_ID
android-release.yml Upload keystore (3), GOOGLE_PLAY_SERVICE_ACCOUNT_JSON

The cli job already passed no secrets and is untouched. GITHUB_TOKEN is automatic and is neither declared nor passed.

Behavior preservation

All declarations use required: false, which reproduces the inherit semantics exactly: a secret that doesn't exist in the repo resolves to an empty string instead of failing the workflow. The nightly release should behave identically — the only change is that a compromised called workflow can no longer read unrelated repository secrets.

Checked: release.yml is the only caller of these four workflows, and none of them calls another reusable workflow with secrets: inherit.

Validation

actionlint on all five files: zero new findings vs main (39 pre-existing shellcheck info-level findings, unchanged). Secret cross-check: referenced secrets == declared secrets == passed secrets, per workflow.

ital0 added 2 commits August 5, 2026 16:38
Limit reusable workflows to the release secrets they need. Keep declarations
optional to preserve existing behavior when repository secrets are missing.
- make each least-privilege release secret contract self-describing
- keep every reusable workflow declaration aligned with its exact needs
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Semgrep Security Scan

No security issues found.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Preview environment deployed 🚀

Service URL
Marketing / blog / docs https://thunderbolt-pr-1196.preview.thunderbolt.io
App https://app-pr-1196.preview.thunderbolt.io
API https://api-pr-1196.preview.thunderbolt.io
Keycloak https://auth-pr-1196.preview.thunderbolt.io
PowerSync https://powersync-pr-1196.preview.thunderbolt.io

Stack: preview-pr-1196 · Commit: 84c40cb2924d29a7f01e1aab6af5a9e71f710907

Auto-destroys on PR close/merge. Login via the bundled Keycloak realm — demo@thunderbolt.io / demo by default.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

PR Metrics

Metric Value
Lines changed (prod code) +100 / -4
JS bundle size (gzipped) 🟢 589.2 KB → 591.3 KB (+2.1 KB, +0.4%)
Test coverage 🟢 81.28% → 81.40% (+0.1%)
Performance (preview) Preview not ready — Render deploy may have timed out
Accessibility
Best Practices
SEO

Updated Fri, 07 Aug 2026 00:37:55 GMT · run #2621

@ital0
ital0 marked this pull request as ready for review August 5, 2026 21:51
@ital0 ital0 self-assigned this Aug 5, 2026

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔭 thunder-deep-review (advisory)

Complements the other bots — surfaces only what they did not flag. Never approves, never requests changes, never gates merge.
head: f03dc595a132 · mode: single · deferred 0 item(s) already reported by other bots (best-effort dedup)

uses: ./.github/workflows/desktop-release.yml
secrets: inherit
secrets:
APPLE_DEVELOPER_CERTIFICATE: ${{ secrets.APPLE_DEVELOPER_CERTIFICATE }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 Blocking — Dropping secrets: inherit could break environment-scoped release secrets

Heads up — I want to flag a subtle behavior change here before it bites a release. Every job that actually consumes these signing secrets declares environment: thunderbolt_release (desktop build, ios build_and_deploy_ios, android build_and_deploy_android, and version-bump). A job that calls a reusable workflow can't declare an environment, so when release.yml resolves ${{ secrets.APPLE_DEVELOPER_CERTIFICATE }} (and the RELEASE_APP_, ANDROID_, TAURI_* keys) it evaluates them in the caller's context, which sees only repository/organization secrets — not the thunderbolt_release environment. With the old secrets: inherit, the reusable workflow resolved those secrets inside its own environment-gated jobs, so environment secrets worked. If any of these are stored as environment secrets, they'll now be forwarded as empty strings and the if [ -z "$..." ] guards will abort every platform build. Interestingly, CRABNEBULA_CLOUD_API_KEY is used in desktop's non-environment draft/publish jobs, which tells me it's repo-level — but that doesn't guarantee the signing keys are. Could we confirm where the Apple/Android/Tauri/RELEASE_APP secrets actually live? If they're environment-scoped, the safest move is to keep secrets: inherit (it's still fully compatible with the new documented workflow_call.secrets declarations) rather than switching to explicit passing.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔭 thunder-deep-review (advisory)

Complements the other bots — surfaces only what they did not flag. Never approves, never requests changes, never gates merge.
head: 84c40cb2924d · mode: single · deferred 0 item(s) already reported by other bots (best-effort dedup)

uses: ./.github/workflows/version-bump.yml
secrets: inherit
secrets:
RELEASE_APP_CLIENT_ID: ${{ secrets.RELEASE_APP_CLIENT_ID }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚫 Blocking — Explicit ${{ secrets.* }} in release.yml can't read the thunderbolt_release environment secrets

Heads up — I think this switch from secrets: inherit to explicit passing may silently break the release. The CHANGELOG notes these credentials were moved to environment secrets (#752: "Use environment secrets and rename RELEASE_APP_ID to RELEASE_APP_CLIENT_ID"), and every job in the called workflows declares environment: thunderbolt_release. But the jobs here in release.yml (version_bump, desktop, ios, android) do NOT declare that environment, and ${{ secrets.X }} only resolves environment secrets inside a job that targets that environment. So these expressions likely evaluate to empty strings and get passed down as empty.

Under the old secrets: inherit, this worked because each reusable job pulled the environment secrets itself via its own environment: thunderbolt_release declaration. With explicit passing, version_bump feeds empty RELEASE_APP_CLIENT_ID/RELEASE_APP_PRIVATE_KEY into actions/create-github-app-token (which has no [ -z ] guard and will error), failing the very first job — and since every other job is gated on needs.version_bump.result == 'success', the whole release becomes a no-op. The platform jobs would hit the same wall via their if [ -z "$APPLE_..." ]; exit 1 guards.

Could we either add environment: thunderbolt_release to these caller jobs so ${{ secrets.* }} can see the env secrets, or confirm with a nightly dry-run that the values still arrive non-empty before merging? Direct workflow_dispatch of the reusable workflows would still work (they target the environment themselves), which can mask this during testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant