Skip to content

docs: sign in to Shorebird from GitHub Actions with OIDC - #725

Merged
eseidel merged 6 commits into
mainfrom
docs/github-actions-oidc
Oct 16, 2026
Merged

eseidel merged 6 commits into
mainfrom
docs/github-actions-oidc

Conversation

@eseidel

@eseidel eseidel commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

CI jobs on GitHub Actions can sign in to Shorebird with the OIDC token GitHub issues to each job, instead of a long-lived SHOREBIRD_TOKEN stored as a repository secret. This adds a section to the GitHub Actions guide covering it. The console's "Workflow trusted" dialog links to this page.

What the section covers

  • Adding a trust rule to a service account in the console: owner, repository, workflow file, environment (recommended) and ref pattern. The Service accounts settings tab stays hidden, so the page is reached by its URL, https://console.shorebird.dev/orgs//settings/service-accounts. Managing service accounts takes Admin or Owner. The page recommends the Developer role (the default, enough to release and patch) and notes that the key the console creates with an account isn't needed for OIDC. The same steps with shorebird api follow.
  • The workflow changes: permissions: id-token: write, the environment the rule names, and SHOREBIRD_PROJECT_ID.
  • That SHOREBIRD_TOKEN takes precedence over OIDC in the CLI, so it has to be removed when moving a workflow over.
  • Plans: trust rules on Business and Enterprise. After a downgrade, existing rules keep working and can be deleted, and new ones can't be added.
  • What a refused sign-in looks like.

The job acts with the service account's role. Trust rules have no scope of their own.

Status

Everything this page describes is live: server and auth support (https://github.com/shorebirdtech/_shorebird/pull/3529, https://github.com/shorebirdtech/_shorebird/pull/3530, https://github.com/shorebirdtech/_shorebird/pull/3531, private), the console trust rules UI (https://github.com/shorebirdtech/_shorebird/pull/3532, private) on prod, and the CLI side (shorebirdtech/shorebird#4084) in Shorebird 1.6.129. The page says OIDC needs 1.6.129 or newer.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Verdict: changes requested. The plan gating, matching rules, console flow and CLI precedence are all accurate against source. Five findings are below: a misquoted error string, no CLI version requirement, agent entry points not updated, a missing key-revocation step, and a link that redirects.

Reviewed at c63d063.

Checked

  • Dependency state: _shorebird#3529, #3530, #3531 and #3532 and shorebird#4084 are all merged. CLI version.dart on shorebird main is still 1.6.128, so OIDC sign-in is not in a released CLI yet. The Service accounts settings tab still has no nav link in web/apps/console/app/routes/orgs.$id.settings.tsx. The description declares this, so it is not a finding.
  • Plan gating:
    • oidcFederation is in _businessFeatures, which _enterpriseFeatures inherits (packages/code_push_server/lib/src/capabilities/plan_feature.dart).
    • Adding a rule returns 403 shorebird_plan_insufficient_tier without that feature. Listing, deleting and exchanging do not check the plan (routes/.../trust-rules/index.dart; header of web/apps/auth/app/services/federated-exchange.server.ts, "a rule that exists keeps working after a downgrade").
    • The console shows the Add button only when the plan has the feature, and keeps existing rules listed and deletable (web/apps/console/app/components/service-accounts/trust-rules.tsx).
    • The note on lines 99-101 is accurate. This is a pricing fact, not internal gating.
  • Console UI (trust-rules.tsx):
    • The GitHub Actions heading and the Add workflow button exist.
    • The fields are Owner, Repository, Workflow file, "Environment (recommended)" and "Ref pattern (optional)". The ref hint reads "e.g. refs/heads/main or refs/tags/*. Empty accepts any ref."
    • The "Workflow trusted" view shows SHOREBIRD_PROJECT_ID: {projectId}, permissions: id-token: write, the environment line, and "No SHOREBIRD_TOKEN". It links to https://docs.shorebird.dev/code-push/ci/github/.
    • "Create service account" exists (service-accounts.tsx).
  • Matching (083_add_oidc_trust_rule_table_migration.dart, match_github_oidc_trust_rules):
    • A null environment or ref pattern matches anything.
    • A ref pattern is either an exact ref or a prefix ending in *, so refs/heads/main and refs/tags/* are valid examples.
    • The environment is compared without regard to case.
  • Role and scope: the issued token carries no scope and acts with the service account's role (federated-exchange.server.ts).
  • CLI (shorebird origin/main):
    • SHOREBIRD_TOKEN takes priority, and OIDC is not built when an API key is set (auth.dart, about lines 628-641).
    • OIDC needs ACTIONS_ID_TOKEN_REQUEST_URL/_TOKEN (set by id-token: write) and SHOREBIRD_PROJECT_ID matching ^[0-9]+$ after trimming, so the example's '123' is valid (github_actions_oidc.dart, oidc_credential_source.dart).
    • When the server refuses, the CLI prints "The Shorebird auth service refused to sign in with GitHub Actions OIDC (invalid_grant: )."
  • Repo checks: no em-dashes in added lines. Prettier, cspell and vale all pass on src/content/docs/code-push/ci/github.mdx. actions/checkout@v7 and setup-shorebird@v1 match the rest of the page.

Findings

  1. src/content/docs/code-push/ci/github.mdx:163-164: the refusal reason is misquoted.

    • Problem: the page shows no trust rule matches as the text the CLI prints. That string does not exist.
    • Evidence: the auth service returns oauthError('invalid_grant', 'No trust rule matches this workflow') (web/apps/auth/app/services/federated-exchange.server.ts). The CLI prints it as ... OIDC (invalid_grant: No trust rule matches this workflow). (oidc_credential_source.dart, _exchangeIdToken). A reader searching their log for the quoted text will not find it.
    • Fix: replace the sentence with:

      If the sign-in is refused, the CLI prints the reason, such as No trust rule matches this workflow. Check that the repository, workflow file, environment and ref of the job match the trust rule.

  2. src/content/docs/code-push/ci/github.mdx:90-97: no CLI version requirement.

    • Problem: OIDC sign-in comes from shorebird#4084, which is not in v1.6.128, the latest release. On an older CLI the section does nothing and the job fails as unauthenticated. Other pages state the minimum CLI version for new features (for example code-push/tracks.mdx:134, code-push/initialize.mdx:94).
    • Fix: add after the first paragraph of the section:

      Signing in with OIDC is available in Shorebird CLI releases after 1.6.128. On an older CLI, use an API key in SHOREBIRD_TOKEN instead.

  3. public/.well-known/agent-instructions.txt:26, astro.config.mjs:227 and src/content/docs/code-push/ci/scripting.mdx:43-44: agent entry points not updated for the new CI sign-in workflow.

    • Problem: all three still say unattended runs authenticate only with an API key in SHOREBIRD_TOKEN. The PR adds a second CI sign-in method with a new variable, SHOREBIRD_PROJECT_ID. scripting.md is the "Full reference" the agent instructions and the cli-scripting skill point to.
    • Fix for agent-instructions.txt:26:
      • Authenticate with an API key in the SHOREBIRD_TOKEN environment variable. shorebird login needs a browser. In GitHub Actions, a job can instead sign in with OIDC through a trust rule on a service account: grant permissions: id-token: write, set SHOREBIRD_PROJECT_ID, and leave SHOREBIRD_TOKEN unset (https://docs.shorebird.dev/code-push/ci/github.md).
    • Fix for astro.config.mjs:227: change "authenticate with an API key in SHOREBIRD_TOKEN" to "authenticate with an API key in SHOREBIRD_TOKEN, or in GitHub Actions with OIDC (https://docs.shorebird.dev/code-push/ci/github.md)".
    • Fix for scripting.mdx: after "since shorebird login needs a browser.", add:

      In GitHub Actions, a job can sign in with OIDC instead.

    • If notes 1 and 2 above go in, include the same version marker in each.
  4. src/content/docs/code-push/ci/github.mdx:159-161: the migration step does not revoke the old key.

    • Problem: deleting the repository secret does not stop the key working. It stays valid until it expires, which undercuts the section's point that nothing is stored or needs rotating. The console also tells users to revoke keys once a trust rule is in use ("Revoke this account's keys that nothing uses anymore.", trust-rules.tsx).

    • Fix:

      If you are moving a workflow from an API key to OIDC, remove the SHOREBIRD_TOKEN line and the repository secret, then revoke the API key.

      The anchor comes from the ## Revoking an API key heading in account/api-keys.mdx.

  5. src/content/docs/code-push/ci/github.mdx:115: the GitHub environments link redirects.

    • Problem: https://docs.github.com/en/actions/managing-workflow-runs-and-deployments/managing-deployments/managing-environments-for-deployment returns a redirect, not the page itself.
    • Evidence: curl -IL ends at https://docs.github.com/en/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments (200).
    • Fix: link to https://docs.github.com/en/actions/how-tos/deploy/configure-and-manage-deployments/manage-environments directly.

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed at dfa8dc3.

Verdict: one finding left, about reusable workflows. All five findings from the previous round are fixed correctly, and everything else checks out against source.

Checked

  • Previous findings: the refusal text matches oauthError('invalid_grant', 'No trust rule matches this workflow') in web/apps/auth/app/services/federated-exchange.server.ts. The "after 1.6.128" marker is present (CLI version.dart on main is still 1.6.128). The agent entry points are updated, the migration step revokes the old key (#revoking-an-api-key resolves), and the GitHub environments link returns 200 with no redirect.
  • Dependencies: _shorebird#3529, #3530, #3531 and #3532 and shorebird#4084 are all merged.
  • CLI: SHOREBIRD_TOKEN takes priority over OIDC (auth.dart). OIDC needs ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, which permissions: id-token: write provides (github_actions_oidc.dart). SHOREBIRD_PROJECT_ID must be numeric, so '123' is valid (oidc_credential_source.dart).
  • Console (trust-rules.tsx, service-accounts.tsx, routes/orgs.$id.settings.service-accounts.tsx): the labels match the page (Service accounts, GitHub Actions, Add workflow, Owner, Repository, Workflow file, "Environment (recommended)", "Ref pattern (optional)"), and the project ID appears in the "Workflow trusted" view.
  • Server validation (service_account_trust_rules.dart): the workflow path must be under .github/workflows/ and end in .yml or .yaml. The ref pattern accepts refs/heads/main and refs/tags/*, and an empty environment or ref accepts anything.
  • Plan gating: oidcFederation is a Business feature that Enterprise inherits. Only adding a rule checks the plan, so the downgrade note is accurate.
  • Repo checks: no em-dashes. Prettier, cspell and vale are clean on the changed text, and the new anchor resolves.

Findings

  1. src/content/docs/code-push/ci/github.mdx:115-116: the Workflow file field is wrong for reusable workflows.
    • Problem: the page says to enter "the path of the workflow". The auth service matches the file that defines the job, not the workflow that was triggered. If the release job lives in a reusable workflow, a rule naming the caller never matches, and the CLI only prints No trust rule matches this workflow. A reusable workflow from another repository is refused outright.
    • Evidence: web/apps/auth/app/services/oidc-providers.server.ts reads the path from the job_workflow_ref claim ("For a job that calls a reusable workflow, that is the called workflow") and refuses a workflow from another repository ("trust rules match only workflows in the repository that runs them").
    • Fix: "the path of the workflow file that defines the job, such as .github/workflows/release.yaml. If the job is in a reusable workflow, enter that file, not the workflow that calls it. A reusable workflow from another repository cannot sign in."

@AbhishekDoshi26 AbhishekDoshi26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Reviewed at 0265db7.

Verdict: clean, no findings. The fixes from both earlier rounds are in place, and every claim checks out against source. Content is ready; the merge still follows the conditions in the description (console Service accounts tab visible and a CLI release with shorebird#4084).

Checked

  • Scope. The exchanged token carries no scope of its own and acts with the service account's role (federated-exchange.server.ts). Nothing is stored: the job trades GitHub's per-job OIDC token for a short-lived access token.
  • Plan note. oidcFederation is a Business feature that Enterprise inherits (plan_feature.dart). The exchange never reads the plan, and the console shows Add workflow only when the plan has the feature while keeping existing rules listed and deletable (trust-rules.tsx).
  • Console flow. Service accounts under org settings, Create service account, the GitHub Actions heading, Add workflow, and the fields Owner, Repository, Workflow file, "Environment (recommended)" and "Ref pattern (optional)" all match. The "Workflow trusted" dialog shows SHOREBIRD_PROJECT_ID.
  • Workflow file. The server accepts ^\.github/workflows/[A-Za-z0-9._-]+\.ya?ml$. oidc-providers.server.ts matches on job_workflow_ref (the called file for a reusable workflow) and refuses a workflow from another repository, as the page now says.
  • Ref pattern. ^refs/(?:[^*\s]+\*?|\*)$ accepts both examples, and an empty pattern accepts any ref.
  • CLI. An API key in SHOREBIRD_TOKEN takes priority (auth.dart). OIDC needs the ACTIONS_ID_TOKEN_REQUEST_* variables that permissions: id-token: write provides. SHOREBIRD_PROJECT_ID must be numeric. version.dart is still 1.6.128, so the markers are right.
  • Refusal text matches oauthError('invalid_grant', 'No trust rule matches this workflow').
  • Agent entry points. agent-instructions.txt, the astro.config.mjs details and scripting.mdx mention OIDC with the version marker.
  • Links and lint. Both new anchors resolve, the GitHub environments link returns 200, there are no em-dashes, and Prettier, vale and cspell are clean on the changed text.

Findings

None.

@eseidel
eseidel marked this pull request as ready for review October 16, 2026 16:38
@eseidel
eseidel enabled auto-merge (squash) October 16, 2026 16:38
@eseidel
eseidel merged commit 18a29fc into main Oct 16, 2026
4 checks passed
@eseidel
eseidel deleted the docs/github-actions-oidc branch October 16, 2026 16:41
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.

2 participants