Skip to content

bootstrap: the promotion bucket grant is refused unwritten, so a prod promote fails on storage.objects.get #1530

Open

Description

@DefeatMan

npm run bootstrap -- --stage <destination> --confirm reports the bucket half of
its promotion grants as refused on every run, and nothing reaches Cloud Storage.

grantPromotionReads makes two grants in the source project. The registry one
carries --condition=None; the bucket one does not. A source stage that stages its
runner binary rather than installing a release holds a condition on the very bucket
a promotion reads from — the deploy attaches runner-artifacts-only to it
(apps/infra/mdeploy/stack/providers/gcp/runners.ts:237, gated on
transport === 'gcs') — and gcloud … add-iam-policy-binding, which reads the
policy before editing it, refuses to edit in a binding carrying no condition when
the policy it read holds one:

ERROR: (gcloud.storage.buckets.add-iam-policy-binding) Adding a binding without
specifying a condition to a policy containing conditions is prohibited in
non-interactive mode. Run the command again with `--condition=None`

The refusal is non-fatal by design, so the bootstrap still exits 0 and the line is
easy to miss. Because no policy is written, the source project's admin-activity log
holds nothing either — the grant looks like it was never made rather than refused.

The failure surfaces later, in mdeploy-all's promote runner job:

listing what is staged under runner/<sha>/ failed: ERROR: (gcloud.storage.ls)
HTTPError 403: bl-app-prod-deploy@<destination>.iam.gserviceaccount.com does not
have storage.objects.get access to the Google Cloud Storage object.

The command printed for an operator to run by hand also omits the flag, so it only
works where a prompt can be answered.

allowImpersonation (apps/infra/bootstrap/gcp.ts) has the same omission. Service
account policies carry no conditions today, so that site is latent rather than
broken.

Activity

  1. ZxlDragonDoctor commented on Sep 18, 2026

    @ZxlDragonDoctor
    Contributor

    I'd like to take this issue.

    Scope

    • In: make the promotion bucket IAM grant pass an explicit condition that is compatible when the source policy already carries conditions (so gcloud ... add-iam-policy-binding no longer refuses the unconditioned binding), matching the issue's root cause.
    • Out: changing runner artifact transport policy, redesigning bootstrap grants beyond the promotion bucket read path.
    • Testing: whatever local/bootstrap unit coverage exists for grant construction; otherwise a focused test of the gcloud args for the bucket grant.

    I'll keep the change limited to the promotion read grant path.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions