fix(setup): harden setup-aws/setup-gcp exits, confirmation, and output#115
Draft
tcerqueira wants to merge 3 commits into
Draft
fix(setup): harden setup-aws/setup-gcp exits, confirmation, and output#115tcerqueira wants to merge 3 commits into
tcerqueira wants to merge 3 commits into
Conversation
Addresses three coupled rough edges in the cloud-connection wizards (setup rough edges from #112): D — bare `Deno.exit(1)` bypassed the error envelope. Every direct exit (missing aws/gcloud CLI, CLI command failure, JSON parse failure, no active GCP account / project, cancelled prompt) now routes through util.ts `error()`, so agents get a structured `{error:{code,...}}` envelope on stderr and a stable ExitCode (USAGE for missing prerequisites/cancellation, GENERIC for CLI failures). E — non-interactive runs auto-applied infra with no confirmation. Added an explicit `--apply` opt-in: in non-interactive mode the wizards now refuse to create/modify IAM roles, service accounts, or workload identity unless `--apply` is passed (USAGE/CONFIRMATION_REQUIRED otherwise); interactive mode still prompts. The GCP API-enable step is gated the same way behind its existing `--enable-apis` flag instead of silently enabling APIs in CI. The decision lives in a pure, unit-tested `applyGate()` helper. B — the wizards printed human text to stdout and emitted no JSON. All progress/status/plan chrome now goes to stderr; under `--json` the decorative output is suppressed and a single JSON result object (provider, role/service-account, ARNs, policies/roles, enabled APIs) is written to stdout via `writeJsonResult`. Also fixes a latent bug where the GCP role-grant and the plan preview stringified the `{label,value}` option object instead of its value.
Unit-test `applyGate()` — the safety contract that the wizards must never auto-apply cloud infra in non-interactive mode without an explicit opt-in flag. Pure, so it runs without aws/gcloud or a backend token.
… mutation setup-gcp enabled missing APIs (a real cloud mutation) as soon as `--enable-apis` was passed, then the later master apply gate would refuse when `--apply` was absent in non-interactive mode — leaving APIs enabled but nothing else created (a surprise partial mutation despite the gate "refusing"). Make `--apply` the master gate for all cloud mutations: the new pure `gcpApiEnableDecision()` evaluates `--apply` *before* the API-specific `--enable-apis`, so a non-interactive run without `--apply` exits via `error()` (USAGE/CONFIRMATION_REQUIRED) before any API is enabled. Net contract: non-interactive API enablement now requires BOTH `--enable-apis` (authorizes the action) AND `--apply` (authorizes mutating the account); without `--apply` nothing mutates. The interactive prompt path is preserved, and the AWS path's already-correct gating is unchanged. Updates the `--apply`/`--enable-apis` help text and adds unit assertions covering the "no mutation before refuse" ordering.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Hardens the
setup-aws/setup-gcpcloud-connection wizards, fixing three coupled rough edges from the setup work in #112.D — bare
Deno.exit(1)bypassed the error envelope. Every direct exit (missingaws/gcloudCLI, CLI command failure, JSON parse failure, no active GCP account/project, cancelled prompt) now routes throughutil.tserror(). Agents get a structured{ error: { code, message, hint, traceId } }envelope on stderr and a stableExitCode.runAwsCommand/runGcloudCommandnow take theGlobalContextso they can emit the envelope.E — non-interactive runs auto-applied infra with no confirmation. Previously
confirmApply()returnedtruewhenever non-interactive, so CI silently created IAM roles / service accounts / workload identity. Now there is an explicit--applyopt-in.B — wizards printed human text to stdout and emitted no JSON. All progress/status/plan chrome moved to stderr; under
--jsonthe decorative output is suppressed and a single JSON result object is written to stdout viawriteJsonResult(provider,org,app,contexts, role/service-account name, ARNs, policies/roles, enabled APIs).Confirmation contract (chosen)
In non-interactive mode (
--non-interactive/-yor no TTY), the wizards refuse to create or modify cloud infrastructure unless the caller passes the explicit--applyflag — otherwise they exit withUSAGE/CONFIRMATION_REQUIREDexplaining how to opt in. In interactive mode the existing confirmation prompt is shown (and--applyskips it). The GCP API-enable step keeps its dedicated--enable-apisopt-in: missing APIs in non-interactive mode without--enable-apisnow error (USAGE/APIS_NOT_ENABLED) instead of being silently enabled. The decision lives in a pure, unit-testedapplyGate()helper, reused by both the apply gate and the API-enable gate.Why this approach
--policies/--roles/--enable-apis"pre-supply the input" pattern.--json --non-interactive --policies ... --apply(AWS) or--json --non-interactive --roles ... --enable-apis --apply(GCP).Rejected alternatives
-y/--non-interactiveas the apply confirmation — conflates "don't prompt me" with "yes, mutate my cloud account"; too easy to trigger destructive changes by habit. Kept them orthogonal.Tests
deploy/setup-cloud.test.tsunit-testsapplyGate()(apply / refuse / prompt) — pure, runs without aws/gcloud or a backend token.deno fmt,deno lint,deno checkall pass.setup-aws --json --non-interactive ...against an unreachable endpoint emits nothing on stdout and a single structured envelope on stderr (exit 3).e2e gap / follow-up
The wizards query the backend, then shell out to real
aws/gcloudbefore reaching the apply gate, so the create-IAM-role / missing-CLI / API-enable paths can only be exercised end-to-end with live credentials and the CLIs installed. Those weren't runnable in this environment; the control-flow fixes are code-level and the core guard is unit-tested. Worth a manual e2e pass with real AWS/GCP creds before release.Review follow-up: GCP API-enablement ordering
Fixed a partial-mutation ordering bug:
setup-gcppreviously enabled missing APIs (a real cloud mutation) as soon as--enable-apiswas passed, then the master apply gate would refuse later when--applywas absent in non-interactive mode — leaving APIs enabled but nothing else created.--applyis now the master gate for all cloud mutations. The new puregcpApiEnableDecision()evaluates--applybefore the API-specific--enable-apis, so a non-interactive run without--applyexits viaerror()(USAGE/CONFIRMATION_REQUIRED) before any API is enabled. Net contract: non-interactive API enablement requires both--enable-apis(authorizes the action) and--apply(authorizes mutating the account); without--apply, nothing mutates. The interactive prompt path and the AWS gating are unchanged. Added unit assertions covering the "no mutation before refuse" ordering (pure logic, no gcloud).