Skip to content

ci(workflows): pin third-party actions to commit SHAs and add dependabot config - #2730

Open
polylane[bot] wants to merge 1 commit into
mainfrom
polylane/autofix/2xkhjjxxnrkn
Open

polylane[bot] wants to merge 1 commit into
mainfrom
polylane/autofix/2xkhjjxxnrkn

Conversation

@polylane

@polylane polylane Bot commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Fixes: Repo security/supply-chain guards disabled on a public, trivially-pushable main: vulnerability alerts & dependabot off, push protection off, unpinned flyctl@master on prod deploy

The production deploy workflows in this repository resolved the Fly CLI installer and the SBOM scanner from moving upstream refs, so a change to those actions would silently reach the public API, workflows, checker and private-location fleets on the next main push, with no review gate on main. Merging pins every third-party action reference to an immutable commit and adds a Dependabot config, so future action and dependency updates arrive as reviewed pull requests instead of drifting refs.

What caused this

Affected: int_01b0344f3001ufkixqp40d4t · severity medium

What changed

  • .github/workflows/deploy.yml, deploy-checker.yml, deploy-workflows.yml, deploy-private-location.yml, restart-workflows.yml: pinned superfly/flyctl-actions/setup-flyctl from @master to @ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1 (the commit master resolves to today).
  • .github/workflows/api-preview.yml, workflow-preview.yml: pinned both setup-flyctl references per file to the same commit.
  • .github/workflows/docker-publish.yml: pinned anchore/sbom-action from @v0 to @e22c389904149dbc22b58101806040fa8d37a610 (the commit v0 resolves to today).
  • .github/dependabot.yml: new weekly version-updates config for the pnpm monorepo (root npm ecosystem) and GitHub Actions, each grouped with an open-PR limit of 10, so dependency and action updates arrive as reviewed pull requests.

Why it's safe

  • The pinned SHAs are exactly what the floating refs resolve to today, verified this turn via the GitHub API (master = ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1, v0 = e22c389904149dbc22b58101806040fa8d37a610), so behavior is identical until upstream moves; previously a move changed the next run silently.
  • Only uses: ref strings changed; no step order, permissions, environment, or deploy command was touched in any of the eight workflows.
  • The docker-publish.yml edit touches only the uses: line of the SBOM step; PR ci(publish): stop the SBOM step from failing the job after a successful push #2728's edits (id/continue-on-error on the step and an if-condition on the upload step) are on adjacent, distinct lines, so the two changes merge cleanly.
  • The new github-actions Dependabot entry is the safety valve: pins update through reviewed pull requests instead of silently aging, which is what a bare SHA pin without an update channel would risk.

Validation

  • ruby -e 'require "yaml"; ...' over all 21 .github/workflows/*.yml plus .github/dependabot.yml: all parse OK.
  • actionlint 1.7.12 on the 8 touched workflows: clean, except pre-existing depot-ubuntu-24.04-4 runner-label warnings in deploy.yml and api-preview.yml (Depot's custom runner label, unrelated to this diff and present before it).
  • grep -rn "uses: ...@master" .github/workflows/: no unpinned action refs remain; the only @latest left is go install ...@latest in proto-check.yml, an install-time tool pin outside this change's scope.
  • not run: pnpm verify (repo CI gate for code changes; this change touches only workflow and Dependabot YAML, no source, dependency or lockfile).
Root cause and scoping notes

Root cause

Signal: the confirmed issue "Repo security/supply-chain guards disabled on a public, trivially-pushable main" names unpinned superfly/flyctl-actions/setup-flyctl@master on the production deploy path as one of its verified findings.

Chain: .github/workflows/deploy.yml (and its siblings) run on every main push touching apps/server/** or packages/**, resolving setup-flyctl@master to whatever upstream's master branch points at on that run, then execute flyctl deploy with FLY_API_TOKEN. The main branch requires zero reviews, enforce_admins=false, has no status-check requirement and no rulesets, so a merged PR or direct push reaches this path unreviewed. /actions/permissions reports allowed_actions: all. An upstream commit to the action's master branch therefore ships arbitrary code to the public API, the workflows app, the checker fleet and private-location on the next relevant main push.

Scope found in this run: a full sweep of .github/workflows found the float is wider than the issue brief named: nine setup-flyctl@master references across seven files (the three other production deploy paths deploy-workflows.yml, deploy-private-location.yml, restart-workflows.yml included) plus anchore/sbom-action@v0 in docker-publish.yml, for ten unpinned refs in total.

{"type":"bar","title":"Unpinned third-party action refs per workflow","xLabel":"Workflow","yLabel":"Refs floating on a mutable ref","series":[{"name":"setup-flyctl@master","data":[{"x":"deploy.yml","y":1},{"x":"deploy-checker.yml","y":1},{"x":"deploy-workflows.yml","y":1},{"x":"deploy-private-location.yml","y":1},{"x":"restart-workflows.yml","y":1},{"x":"api-preview.yml","y":2},{"x":"workflow-preview.yml","y":2}]},{"name":"sbom-action@v0","data":[{"x":"docker-publish.yml","y":1}]}]}

Why this fixes the cause: each reference is repointed at the immutable commit it resolves to today (verified via the GitHub API this turn), so a future upstream move changes nothing at run time. The new Dependabot github-actions entry is the update channel: action upgrades now arrive as pull requests with visible diffs instead of silently drifting, which is what makes a SHA pin safe to keep. The disabled repo settings (vulnerability alerts, push protection) and the unresolved Slack-webhook alert are admin-side actions no pull request can perform and are recorded on the issue timeline for a maintainer.

Out of scope / follow-ups

  • Repo admin settings (vulnerability alerts, dependabot security updates, push protection, actions permissions, branch protection): not changeable via pull request; recorded on the issue timeline for a maintainer.
  • Rotating the exposed Slack webhook and resolving secret-scanning alert feat: coming soon #1: requires Slack workspace access; recorded on the issue timeline.
  • go install ...@latest in proto-check.yml: install-time pinning of a dev tool, not an action ref on the deploy path; left for the Dependabot/renovate conversation rather than changed blind.
  • SBOM step failure handling in docker-publish.yml: already covered by the open PR ci(publish): stop the SBOM step from failing the job after a successful push #2728.
Causal chain
  • Signal (alert): Repo security/supply-chain guards disabled on a public, trivially-pushable main: vulnerability alerts & dependabot off, push protection off, unpinned flyctl@master on prod deploy
  • Surfacing site: Github integration (int_01b0344f3001ufkixqp40d4t) at GitHub REST API: security_and_analysis, actions/permissions, branches/main/protection, secret-scanning/alerts, workflow files
  • Mechanism: The repository's security_and_analysis block reports dependabot_security_updates, secret_scanning_push_protection, secret_scanning_validity_checks and secret_scanning_non_provider_patterns all disabled; /vulnerability-alerts returns 404 and /dependabot/alerts 500 (both disabled); /actions/permissions returns allowed_actions=all with sha_pinning_required=false; branches/main/protection requires 0 approving reviews, enforce_admins=false, no status checks, rulesets=[]; and the workflow files resolve superfly/flyctl-actions/setup-flyctl@master (9 refs across 7 files) and anchore/sbom-action@v0 (1 ref) from mutable upstream refs on the production deploy path.
  • Producer: openstatusHQ/openstatus repository, instance main branch, production deploy path, at .github/workflows/deploy.yml, deploy-checker.yml, deploy-workflows.yml, deploy-private-location.yml, restart-workflows.yml, api-preview.yml, workflow-preview.yml, docker-publish.yml
  • Trigger: Standing configuration, not a deploy event: the floating action refs and disabled security settings predate the 2024-09-07 webhook commit and persist on main; every relevant main push re-resolves the floating refs at run time.
  • What happens to the failed unit today: Each workflow run resolves the floating ref to upstream's current head at execution time, then flyctl deploy runs with FLY_API_TOKEN; there is no pin, no update mechanism (no .github/dependabot.yml) and no review gate on main (0 required reviews, enforce_admins=false). After this change the same step resolves a pinned commit, and the github-actions Dependabot entry proposes updates as reviewed pull requests.
  • Cadence check: Standing configuration, continuous exposure: every relevant main push re-resolves the @master/@v0 refs at run time, so an upstream commit ships on the next push with no review gate; the disabled-settings state reproduces on every REST check.
  • Blast radius: 8 other resource(s), 0 other tenant(s); data at risk: Arbitrary code execution on the CI/deploy path holding FLY_API_TOKEN (deploys openstatus-api, openstatus-workflows, the checker fleet and private-location); Slack channel injection via the exposed webhook; undetected CVEs in the monorepo dependency tree
  • Producer evidence:
    • Brief REST checks 2026-09-15: vulnerability-alerts 404, dependabot/alerts 500, security_and_analysis all disabled, actions/permissions {allowed_actions:all, sha_pinning_required:false}, branches/main/protection 0 reviews, rulesets=[]; secret-scanning alert feat: coming soon #1 open since 2024-09-07 (Slack webhook, team id matches org Slack)
    • Sandbox grep of .github/workflows: 9 setup-flyctl@master refs (deploy.yml:36, deploy-checker.yml:15, deploy-workflows.yml:22, deploy-private-location.yml:18, restart-workflows.yml:20, api-preview.yml:38+71, workflow-preview.yml:38+69) and anchore/sbom-action@v0 (docker-publish.yml:151)
    • GitHub API this turn: superfly/flyctl-actions master = ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1; anchore/sbom-action v0 = e22c389904149dbc22b58101806040fa8d37a610

Detection outcome

The condition the issue names, unpinned third-party action refs on the production deploy path, stops existing once this merges: a re-scan of .github/workflows finds every superfly/flyctl-actions/setup-flyctl reference pinned to the commit SHA ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1 and anchore/sbom-action pinned to e22c389904149dbc22b58101806040fa8d37a610, with no @master or major-tag float left. Workflow runs no longer resolve a mutable upstream ref at execution time, and the new github-actions Dependabot entry replaces silent drift with reviewed update pull requests, so the refs stay current without ever floating again.

Fix chosen

Chosen: cause (removes the mechanism that produces the failure): Pin all ten floating third-party action references (setup-flyctl@master x9, sbom-action@v0 x1) to the immutable commit SHAs they currently resolve to, and add a Dependabot config so future action and dependency updates arrive as reviewed pull requests.

Considered and not chosen:

  • disable (turns a feature, guard, check, test, or telemetry off): Disable the deploy and publish workflows that call the unpinned actions. Not chosen: Turning off the affected workflows stops the production Fly deploys themselves; the refs would stay unpinned for the next time they are re-enabled.
  • loosen (raises a limit, threshold, or timeout, or widens a retry): Pin to a semver tag of the flyctl action instead of a full SHA. Not chosen: Semver-major-tag pins still move: a v1 tag can be retargeted or a later commit pushed to the same tag, so this does not remove the mutable-ref mechanism.
  • suppress (silences, downgrades, or reroutes the signal without changing what produces it): Mark the unpinned refs as known and stop reporting them. Not chosen: Silencing the finding without changing the refs leaves the auto-ship path live; it would also misrepresent a confirmed security gap as resolved.
  • capacity (shrinks or reshapes the thing that exceeds a limit so the feature keeps working): Bound the number of workflow runs that can execute the deploy path. Not chosen: No limit is exceeded here; the gap is the absence of an immutable ref and an update channel, which a capacity change does not address.

Outcome after fix

Replay with the change applied. A main push touching apps/server/** triggers the Fly Deploy workflow: checkout runs, then setup-flyctl@ed8efb33836e8b2096c7fd3ba1c8afe303ebbff1 downloads the same action commit that master points at today, and flyctl deploy proceeds exactly as before. Upstream later pushes a new commit to superfly/flyctl-actions's master branch: the next run still executes ed8efb3, so the new commit reaches neither CI nor production until a maintainer merges the Dependabot pull request that proposes it, with a visible diff. The same holds for the SBOM step's action. The floating-ref auto-ship mechanism the issue names is gone; the repo-settings facets (vulnerability alerts, push protection, the unresolved webhook alert) remain open and are recorded on the issue timeline for a maintainer, since no pull request can change them.

9 files changed (+31/-10)
  • .github/dependabot.yml: added, +21/-0
  • .github/workflows/api-preview.yml: modified, +2/-2
  • .github/workflows/deploy-checker.yml: modified, +1/-1
  • .github/workflows/deploy-private-location.yml: modified, +1/-1
  • .github/workflows/deploy-workflows.yml: modified, +1/-1
  • .github/workflows/deploy.yml: modified, +1/-1
  • .github/workflows/docker-publish.yml: modified, +1/-1
  • .github/workflows/restart-workflows.yml: modified, +1/-1
  • .github/workflows/workflow-preview.yml: modified, +2/-2

Repository conventions present in the repository: AGENTS.md, CLAUDE.md, apps/checker/AGENTS.md, apps/dashboard/AGENTS.md, apps/server/AGENTS.md, apps/status-page/AGENTS.md, apps/web/AGENTS.md, apps/workflows/AGENTS.md, packages/services/AGENTS.md, packages/ui/AGENTS.md.

Repository lint: pnpm run lint (declared in package.json) could not run in the sandbox because its tool is not installed there; run it before merging.

View autofix View thread


Generated by Polylane.

Review in cubic

…bot config

Co-authored-by: polylane[bot] <277585245+polylane[bot]@users.noreply.github.com>
@polylane polylane Bot added the polylane label Sep 16, 2026
@vercel

vercel Bot commented Sep 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
openstatus-dashboard Ready Ready Preview Sep 16, 2026 1:27am UTC
openstatus-status-page Ready Ready Preview Sep 16, 2026 1:27am UTC
openstatus-web Error Error Sep 16, 2026 1:27am UTC

Request Review

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

Labels

polylane severity:medium Polylane autofix severity: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant