Skip to content

ci(release): version with release-please and publish a container image - #529

Open
svalleru wants to merge 3 commits into
mainfrom
feat/release-pipeline
Open

svalleru wants to merge 3 commits into
mainfrom
feat/release-pipeline

Conversation

@svalleru

Copy link
Copy Markdown

Summary

  • What. release-please (node type) keeps a release PR open and tags
    vX.Y.Z; a Publish workflow builds that commit's Dockerfile for
    linux/amd64 and pushes
    us-docker.pkg.dev/e2b-artifacts/dashboard/dashboard:vX.Y.Z through workload
    identity.
  • Why. Self-hosted installs need a version to pin, and a commit SHA is the
    only identity this repository has today. The
    E2B Embed package
    pins the dashboard image the way it pins the others.
  • The release job uses the same GitHub App token the spec sync uses, ungated.
    A tag pushed with the default GITHUB_TOKEN does not trigger on: push, so a
    missing App must fail loudly rather than produce a release that never
    publishes.
  • The publisher is unreachable from a pull request. Publish holds
    id-token: write but runs only on a v* tag push and manual dispatch, and
    tags are immutable. Attestations are off because Artifact Registry rejects
    buildx's default manifest lists.
  • Seeded at 0.1.0 with bump-minor-pre-major, so the first release is
    v0.2.0.
    No release PR opens until the first feat or fix after the
    bootstrap commit.

Verification

  • 254 unit tests pass. New ones pin both sides of the tag contract
    (include-component-in-tag: false and the workflow's
    ^v[0-9]+\.[0-9]+\.[0-9]+$), the registry path and platform, the identity
    variables, and the absence of pull_request, pull_request_target and
    workflow_run.
  • actionlint clean on both workflows; no existing workflow fires on tag
    pushes, so a release starts exactly one run.
  • The build was rehearsed locally against the container PR's Dockerfile with
    --load instead of --push: a 111 MB linux/amd64 image with the expected
    labels.
  • Untestable before a real release: the identity exchange, the registry push,
    and whether the App grants contents: write.

Merge order / notes

  • Merge the container PR first, since this workflow builds its Dockerfile, and
    the runtime-config PR before the first tag, or the image bakes
    NEXT_PUBLIC_E2B_DOMAIN=unset.invalid. All three PRs edit README.md and
    package.json in disjoint regions.
  • Set GCP_WORKLOAD_IDENTITY_PROVIDER and GCP_SERVICE_ACCOUNT as repository
    variables before the first tag; until then the first step fails with a FIX
    line naming both.
  • The container PR's workflow header says nothing else in CI builds the image.
    Publish now does — adjust it in whichever of the two merges second.

@cla-bot cla-bot Bot added the cla-signed label Sep 12, 2026
@svalleru
svalleru marked this pull request as ready for review September 12, 2026 01:58

@claude claude 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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Beyond the inline findings, I checked whether workflow_dispatch's ref and tag inputs could be used to publish a tag that doesn't actually match the ref being built — they are independent free-text fields with no cross-check against real git tags, but triggering it already requires repo write/dispatch access, so this is an operational footgun rather than a new attack surface and doesn't change the outcome here.

Extended reasoning...

I reproduced the ruled-out candidate by reading .github/workflows/publish.yml: in the "Resolve the tag and the commit" step, tag comes from inputs.tag on workflow_dispatch while the checkout step uses inputs.ref || github.ref — these are two separate free-text inputs with no validation that a git tag named tag exists or points at the commit resolved from ref. This confirms the previously ruled-out item is real but bounded: workflow_dispatch on this workflow can only be triggered by someone with write access to the repository (GitHub restricts manual dispatch to collaborators with write permission), so it does not introduce a fork-reachable or privilege-escalation path beyond what a trusted maintainer could already do by hand — it's a usability/footgun issue (a maintainer typo could publish v1.2.3 built from an unrelated ref) rather than a security hole, consistent with why it was ruled out rather than confirmed. Since two other findings (the tag-existence guard treating any gcloud failure as "free", and mutable @ v3 action tags for the GCP auth chain) are already confirmed and will be posted inline, and this additional item is genuinely something I verified beyond those, the narrow exception for a brief defer note applies.

Comment thread .github/workflows/publish.yml
Comment thread .github/workflows/publish.yml Outdated
An unreadable tag listing was treated as "the tag is free", so a registry the
publish identity cannot read would have published straight over an existing
tag. NOT_FOUND still means free, since that is where the first release starts,
but every other gcloud failure now fails the step with the error it returned
and a line saying what to check.

A dispatched run takes the ref and the tag as separate inputs, so it could
publish an image as v1.2.3 built from a commit that v1.2.3 does not name. It
now fetches the tag and refuses unless the tag names the commit that was
checked out. A push run cannot disagree with itself, because the ref it builds
is the tag, so it skips the check, and so does a dry run, which publishes
nothing and may rehearse with any tag.

Third-party actions in these two workflows are pinned to commit SHAs. They
differ from the rest of CI because they are the two that hold credentials:
this one holds id-token: write for the workload identity that writes to the
registry, and release-please.yml holds an App installation token that pushes
tags and opens PRs. A moved major tag on an action in either would run
someone else's code against those. The other workflows keep their major tags.
Pinning trades a moved-tag risk for a staleness one, so this repository should
enable Dependabot for the github-actions ecosystem to keep the pins bumped.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants