Conversation
There was a problem hiding this comment.
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.
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.
Summary
vX.Y.Z; aPublishworkflow builds that commit'sDockerfileforlinux/amd64and pushesus-docker.pkg.dev/e2b-artifacts/dashboard/dashboard:vX.Y.Zthrough workloadidentity.
only identity this repository has today. The
E2B Embed package
pins the dashboard image the way it pins the others.
A tag pushed with the default
GITHUB_TOKENdoes not triggeron: push, so amissing App must fail loudly rather than produce a release that never
publishes.
Publishholdsid-token: writebut runs only on av*tag push and manual dispatch, andtags are immutable. Attestations are off because Artifact Registry rejects
buildx's default manifest lists.
bump-minor-pre-major, so the first release isv0.2.0. No release PR opens until the first
featorfixafter thebootstrap commit.
Verification
(
include-component-in-tag: falseand the workflow's^v[0-9]+\.[0-9]+\.[0-9]+$), the registry path and platform, the identityvariables, and the absence of
pull_request,pull_request_targetandworkflow_run.actionlintclean on both workflows; no existing workflow fires on tagpushes, so a release starts exactly one run.
Dockerfilewith--loadinstead of--push: a 111 MBlinux/amd64image with the expectedlabels.
and whether the App grants
contents: write.Merge order / notes
Dockerfile, andthe runtime-config PR before the first tag, or the image bakes
NEXT_PUBLIC_E2B_DOMAIN=unset.invalid. All three PRs editREADME.mdandpackage.jsonin disjoint regions.GCP_WORKLOAD_IDENTITY_PROVIDERandGCP_SERVICE_ACCOUNTas repositoryvariables before the first tag; until then the first step fails with a FIX
line naming both.
Publishnow does — adjust it in whichever of the two merges second.