Skip to content

fix(bootstrap): bring the template under CloudFormation's inline size limit (#864) - #867

Merged
ayushtr-aws merged 9 commits into
aws-samples:mainfrom
vivibui:fix/864-bootstrap-inline-limit
Sep 11, 2026
Merged

ayushtr-aws merged 9 commits into
aws-samples:mainfrom
vivibui:fix/864-bootstrap-inline-limit

Conversation

@vivibui

@vivibui vivibui commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Fixes #864.

Problem

The generated least-privilege bootstrap template was 53,369 characters as CloudFormation received it, past the 51,200 ceiling for an inline TemplateBody. Above that the CDK CLI must stage the template in S3 — which it cannot do while bootstrapping a fresh account, because the bucket it would stage into is one of the resources bootstrap creates.

So a first-time mise //cdk:bootstrap failed outright:

 ❌  Environment aws://<account>/us-east-1 failed bootstrapping:
     BootstrapStackRequired: Trying to perform an operation that requires a bootstrap
     stack; you should not see this error, this is a bug in the CDK CLI.
    at makeBodyParameter (...)

--force does not help: the same size branch runs even when CDKToolkit already exists, so the custom template could never be applied through cdk bootstrap at all.

The gated size is not the file's size on disk. makeBodyParameter re-serialises the parsed template with the CLI's own writer before measuring, so the committed file's formatting is discarded:

const templateJson = toYAML(overrideTemplate ?? stack.template);
if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) return { TemplateBody: templateJson };

This matters because reformatting the artifact is the intuitive fix and it accomplishes nothing. An earlier revision of this PR did exactly that — reflowed the YAML from 54,213 to 39,896 bytes on disk while the body CloudFormation received stayed at 53,369, byte-identical to main and still over the limit. That approach was reverted; the reflow also pushed the longest line from 142 to 1,605 characters, which hurt reviewability for no gain.

Change

Emit each ABCA PolicyDocument as a minified JSON string instead of a nested YAML mapping. PolicyDocument is a Json-typed property so CloudFormation accepts either, but the shape decides the size: as a mapping the CLI's re-serialisation expands every statement key and action onto its own line, whereas a string scalar survives on one line.

53,369 → 45,743 characters, with 5,457 of headroom. Only the six ABCA policies are converted; CdkBoostrapPermissionsBoundaryPolicy from the upstream template stays a mapping.

Zero permission drift — the parsed policy documents are identical to main.

Gate on the CLI's own number. cdk/src/bootstrap/template-size.ts invokes cdk bootstrap --show-template on the committed artifact rather than reimplementing the CLI's serialiser locally. Mirroring it would mean a direct dependency on yaml (present here only as a transitive resolutions pin) and would drift silently the day the CLI changes writer or options. Asking the component that makes the inline-vs-S3 decision cannot drift. No credentials or network required.

--no-ci is load-bearing: in CI mode the CLI routes progress to stdout, so "Using bootstrapping template from <path>" would be counted as part of the body — 45,812 with CI=true versus 45,744 without, varying with the path's length.

Fail generation over budget. TEMPLATE_SIZE_BUDGET is 49,152 (48 KiB), deliberately below the hard ceiling so a policy addition fails in the generator — where the content is produced and the author can act on it — rather than surfacing later as an opaque CDK CLI error against somebody's fresh account. The generator writes a sibling .tmp, measures it, and renames only on success, so a rejected template is never left on disk.

Verified end-to-end against a real account

The claim that CloudFormation accepts a JSON-string PolicyDocument and IAM stores it parsed was checked on live AWS, not inferred from the spec:

  • A throwaway stack with a JSON-string PolicyDocument reached CREATE_COMPLETE, and iam:GetPolicyVersion returned it parsed as a policy document, not as a literal string.
  • cdk bootstrap --template bootstrap/bootstrap-template.yaml --force against account 618731765007 succeededCDKToolkit went UPDATE_COMPLETE across all six managed policies — where the same command on the pre-fix template failed with BootstrapStackRequired.
  • All four deployed policies were then compared statement-by-statement against the generated sources: identical sets (Infrastructure 5, Application 13, Observability 12, Compute-Agentcore 1).

Not tested: how CloudFormation diffs the mapping-to-string change on a CDKToolkit stack created before this PR. The update above was applied to a stack already carrying the ABCA variant, so that specific path is exercised, but not an upgrade from the stock CDK bootstrap.

Testing

  • mise run build — exit 0, 0 task failures, 4,550 cdk + 928 cli tests
  • npx jest test/bootstrap/ — all suites green, including under CI=true
  • New coverage: the artifact is under both the ceiling and the budget; every ABCA PolicyDocument parses to a valid policy document; the committed file deep-equals a freshly built template and is byte-identical to a fresh render; checkTemplateBudget is asserted at budget, budget+1, past the hard ceiling, and at 53,369 — the body this bug actually shipped
  • Reformatting invariance is asserted on parsed equality rather than by measuring twice through the CLI: the CLI derives its size from the parsed object, so identical parses cannot differ on the wire. Exact, no tolerance, and one subprocess per run instead of three

Notes for reviewers

New maintenance coupling, worth a conscious decision. The byte-identical render test compares the committed YAML against the default template inside the installed aws-cdk package. No prior test did this. Every aws-cdk bump that touches the upstream bootstrap template will now fail this test until the generator is re-run and its output committed — turning some dependency bumps into PRs with a manual regeneration step. That seems right (silent drift in the bootstrap template is worse), but it is a real cost and reviewers should agree to it rather than discover it.

BOOTSTRAP_VERSION left at 1.6.0. The version's documented contract is the policy bundle, and the hash covers policy content, which is unchanged — no operator needs to re-bootstrap for permissions. Happy to add a patch bump if you'd rather an operator inspecting a deployed CDKToolkit be able to tell which template shape they have.

Pre-existing, not fixed here: cdk/eslint.config.mjs does not lint scripts/, so the eslint-disable directives in the generator are inert. Now that tests import that file, it is worth a follow-up issue.

docs/design/DEPLOYMENT_ROLES.md documents the 51,200-character ceiling as a second limit distinct from the per-policy IAM 6,144-character one, why on-disk size is not the gated quantity, and the JSON-string shape. Starlight mirror re-synced.

🤖 Generated with Claude Code

… limit

Fixes aws-samples#864.

The generated least-privilege bootstrap template was 54,213 bytes, past the
51,200-byte ceiling CloudFormation applies to an inline `TemplateBody`. Above
that ceiling the CDK CLI has to stage the template in S3 — which it cannot do
while bootstrapping a fresh account, because the bucket it would stage into is
one of the resources bootstrap creates. So a first-time `mise //cdk:bootstrap`
failed outright:

    BootstrapStackRequired: Trying to perform an operation that requires a
    bootstrap stack; you should not see this error, this is a bug in the CDK CLI.

`--force` does not help: the same size branch runs even when CDKToolkit already
exists, so the custom template could never be applied through `cdk bootstrap`
at all. Working around it meant bootstrapping with the default template and
then applying this one by hand via `update-stack` from S3.

- Emit the template with js-yaml `flowLevel: 6`, so IAM statements render one
  per line rather than expanding every key and action string onto its own line.
  54,213 -> 39,896 bytes: under the ceiling with 11,304 bytes spare. This is a
  serialisation change only; the parsed template is unchanged, asserted by a
  round-trip test and by the existing golden-baseline and artifact-sync suites
  passing untouched.
- Fail generation when the rendered template exceeds a 48,000-byte budget,
  naming the limit and what to do about it. The budget sits below the hard
  ceiling deliberately: a policy addition should fail in the generator, where
  the bytes are produced, instead of surfacing later as an opaque CDK CLI error
  against a real account.
- Tests: assert the committed artifact is under both the ceiling and the budget,
  and that the compact form parses identically to a fully expanded dump.

Co-Authored-By: Claude <noreply@anthropic.com>
@vivibui
vivibui requested review from a team and backgroundagents as code owners September 8, 2026 17:40
@codecov-commenter

codecov-commenter commented Sep 8, 2026

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 87.11111% with 58 lines in your changes missing coverage. Please review.
⚠️ Please upload report for BASE (main@5e2138e). Learn more about missing BASE report.

Files with missing lines Patch % Lines
cdk/scripts/generate-bootstrap-template.ts 83.69% 45 Missing ⚠️
cdk/src/bootstrap/template-size.ts 92.52% 13 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@           Coverage Diff           @@
##             main     #867   +/-   ##
=======================================
  Coverage        ?   92.52%           
=======================================
  Files           ?      336           
  Lines           ?    97401           
  Branches        ?    10776           
=======================================
  Hits            ?    90116           
  Misses          ?     7285           
  Partials        ?        0           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@vivibui

vivibui commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@scottschreckengaust @krokoko — review request. (I don't have write access on this repo, so I can't populate the Reviewers field; flagging by mention instead.)

Also cc @isadeks and @ClintEastman02 as the most recent contributors to cdk/bootstrap/ — you may have context on why the template landed near the size ceiling.

Why this needs eyes despite being small: the diff to cdk/bootstrap/bootstrap-template.yaml is ~1,200 lines but is entirely reflow — the substantive change is flowLevel: 6 in scripts/generate-bootstrap-template.ts plus a size guard. Suggested review order:

  1. cdk/scripts/generate-bootstrap-template.ts — the two-constant budget and the throw
  2. cdk/test/bootstrap/bootstrap-template.test.ts — the round-trip equality assertion, which is what makes the reflow safe to trust
  3. The generated YAML only if you want to spot-check

The claim to check hardest is that this is serialisation-only. Three independent signals: an explicit round-trip test, and the pre-existing golden-baseline + artifact-sync suites passing unmodified.

Judgement call worth confirming: I set the budget at 48,000 against the hard 51,200 ceiling. That reserves ~3.2 KB of headroom, which is roughly what #865's fix will consume. If you'd rather the budget sit elsewhere, it's a one-line change.

@ayushtr-aws ayushtr-aws left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Request changes

The change is well-motivated and the write-up is excellent, but the PR does not fix #864. cdk bootstrap --template <file> never sends the on-disk bytes. The CLI parses the file (loadStructuredFile), writes it into a temp cloud assembly as JSON, and makeBodyParameter then re-serialises the parsed object with its own toYAML (yaml@1 stringify(obj, { schema: 'yaml-1.1' }), fold lineWidth = 0) before comparing .length to 50 * 1024. Formatting choices in js-yaml are discarded at the first step.

Measured with the CLI's exact serialiser (aws-cdk 2.1129.0 bundled in this repo) and independently confirmed via npx cdk bootstrap --show-template --template <file> | wc -c, which shares the same toYAML path:

template on-disk bytes bytes the CLI actually sends
main 54,213 53,369
this PR 39,896 53,369

Both are 2,169 bytes over 51,200. A fresh-account mise //cdk:bootstrap on this branch will hit the identical BootstrapStackRequired error while the generator prints 8104 under budget. The PR's Testing section lists only unit tests; a real cdk bootstrap run against an account (fresh, or --force on an existing CDKToolkit) would have surfaced this and should be part of the evidence for any re-roll.

Everything else in the PR is sound: the parsed template is deep-equal to main under both js-yaml and the CDK CLI's yaml@1 core-schema parser (20 Resources, 13 Parameters, 13 Conditions, 8 Outputs; no IAM Action/Resource/Condition/Effect changed), the generator reproduces the committed artifact byte-for-byte, and BOOTSTRAP_HASH/BOOTSTRAP_VERSION are correctly unchanged.

Vision alignment

The intent (bounded, reproducible, fail-fast bootstrap per ADR-002) fits. The problem is purely that the fix and its guard measure a quantity CloudFormation never sees.

Blocking

  1. Fix does not reach the wire (cdk/scripts/generate-bootstrap-template.ts:256). flowLevel: 6 only changes the committed file. The parsed content has to shrink. What I measured through the CLI serialiser on this branch's template:
    • strip all Sids: 52,047 (still over)
    • strip Sids + managed-policy Descriptions: 51,328 (still over)
    • merge statements sharing identical Effect/Resource/Condition (38 → 30 statements): 52,420 (still over)
    • emit each PolicyDocument as a minified JSON string (CloudFormation accepts a JSON string for Json-typed properties such as AWS::IAM::ManagedPolicy.PolicyDocument): 45,378, under the limit with ~5.8 KB headroom. The CLI serialiser emits a string scalar on one line, so this reduction survives re-serialisation. This is the one lever that clears the ceiling without trading away permissions or Sids, but it needs a live cdk bootstrap to confirm CFN accepts it in this position.
    • Anything that lands in BootstrapStack.updatedeployStack gets re-serialised, so whichever approach you pick, verify with npx cdk bootstrap --show-template --template bootstrap/bootstrap-template.yaml | wc -c.
  2. The size guard and both size tests measure the wrong thing (generate-bootstrap-template.ts:281, bootstrap-template.test.ts:280,284). They gate readFileSync(...).length of the flow-style file. They will stay green while the CLI-side body grows past 51,200. Measure the CLI's serialisation instead: the yaml package is already hoisted in node_modules; yaml.stringify(template, { schema: 'yaml-1.1' }) with strOptions.fold.lineWidth = 0 reproduces toYAML exactly, and that assertion fails on this branch by 2,169 bytes, which is the number that must be cut.
  3. The round-trip test is tautological (bootstrap-template.test.ts:298). template is yaml.load of the compact file itself (line 29) and expanded is yaml.dump(template), so load(dump(x)) == x holds for any object regardless of how the file was rendered. It cannot detect a flow-context mis-emission. Compare the committed file against an independently built object instead (e.g. refactor the generator into an importable buildTemplate() and assert yaml.load(file) equals it; that also gives the repo the artifact-drift check it currently lacks for the template).
  4. Comments and messages assert things that are not true (generate-bootstrap-template.ts:248,279; error text is N bytes ... cannot bootstrap a fresh account; console.log ... under budget). A maintainer hitting the guard would trim on-disk bytes to no effect. Rewrite once the guard measures the real quantity.

Non-blocking

  • rendered.length counts UTF-16 code units, not bytes (:281, :283; test :280, :284). ASCII today, so exact by accident. Use Buffer.byteLength(rendered, 'utf8') as cdk/test/main.test.ts already does for the main stack.
  • CFN_INLINE_TEMPLATE_LIMIT / TEMPLATE_SIZE_BUDGET and the dump options are duplicated between generator and test (test:277). Export from cdk/src/bootstrap/version.ts, which both already import.
  • Since the reflow buys nothing on the wire, consider reverting it: flowLevel: 6 yields 1,605-char lines (lineWidth only folds scalars) and degrades diff review of future policy changes, which is the reviewability tenet this repo cares about.
  • The 48,000 budget question you raised is moot until the metric is right; once it is, a ~2 KB margin below 51,200 seems reasonable given #865 will add statements.

Governance

  • #864 is not labelled approved and carries no priority label (ADR-003). Please have a maintainer label it before re-rolling. Branch name fix/864-bootstrap-inline-limit is correct.
  • Cross-repository PR (fork); noted, not a concern.

Documentation

No docs changes were needed for the current diff. If the fix moves to JSON-string policy documents or otherwise changes artifact shape, docs/design/DEPLOYMENT_ROLES.md (which documents the six-policy split and the 6,144-char IAM limit) should gain a sentence on the 51,200-byte inline ceiling and how the generator enforces it, plus mise //docs:sync.

Tests & CI

CI green (build, secrets/deps scan, dead-code, title). npx jest test/bootstrap/ 122/122 pass in a clean worktree; generator is idempotent against the committed artifact. Bootstrap synth-coverage: not applicable (no construct changes). Coverage is fine on the changed lines but, per the above, the new tests do not exercise the failure they describe.

Review agents run

  • /security-review (redirected at the PR diff): no findings; deep-equality and flow-context parse checks above come from it.
  • /code-review at high effort: confirmed the size finding by exact CLI reproduction and the tautological test; refuted a stale-artifact concern (the BootstrapPolicyHash output test would catch it).
  • Silent-failure / comment-accuracy / test-coverage review (general-purpose agent standing in for the pr-review-toolkit agents, which are not installed here): findings folded in above.
  • Omitted: type-design-analyzer (no new types).

Human heuristics

  • Proportionality: pass. Two constants, one option, one guard.
  • Coherence: concern. The repo's existing size check (cdk/test/main.test.ts) measures bytes of the artifact CFN receives; this one measures a formatting artifact the CLI discards.
  • Clarity: concern. Error and log messages give false assurance (generate-bootstrap-template.ts:279-298).
  • Appropriateness: concern (AI001/AI005). Integration behaviour of cdk bootstrap was inferred rather than verified against the real CLI, and the tests assert what the code does, not what it should do.

Happy to re-review quickly once the metric is switched to the CLI serialisation and the content reduction is verified with a real bootstrap run.

Comment thread cdk/scripts/generate-bootstrap-template.ts Outdated
Comment thread cdk/scripts/generate-bootstrap-template.ts Outdated
Comment thread cdk/scripts/generate-bootstrap-template.ts Outdated
Comment thread cdk/test/bootstrap/bootstrap-template.test.ts Outdated
Comment thread cdk/test/bootstrap/bootstrap-template.test.ts Outdated
Comment thread cdk/test/bootstrap/bootstrap-template.test.ts Outdated
…he CLI's size

Refs aws-samples#864. Addresses review on aws-samples#867.

The first attempt measured and reduced the wrong quantity. `cdk bootstrap --template`
never sends the bytes on disk: it parses the file, discards the formatting, and
re-serialises the parsed object before the inline check.

    // aws-cdk/lib/index.js — makeBodyParameter()
    const templateJson = toYAML(overrideTemplate ?? stack.template);
    if (templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024) ...

So `flowLevel: 6` shrank the artifact 54,213 -> 39,896 while the body CloudFormation
receives stayed at 53,369 — byte-identical to main, still 2,169 over the ceiling. A real
bootstrap on the previous commit fails exactly as it does on main, while the guard prints
"8104 under budget". Confirmed by running it, which is the step missing the first time.

- Revert the reflow. It bought nothing on the wire and cost reviewability: max line
  length went 142 -> 1,605 chars, 44 lines over 200.
- Emit each ABCA `PolicyDocument` as a minified JSON string. `PolicyDocument` is
  `Json`-typed so both shapes are valid, but a string scalar survives the CLI's
  re-serialisation on one line where a mapping re-expands. Body: 45,743, with 5,457 of
  headroom. `CdkBoostrapPermissionsBoundaryPolicy` (from the upstream template) is left
  a mapping — only our six are converted.
- Gate on the CLI's own number, via `cdk bootstrap --show-template` against the written
  artifact. Deliberately not a local copy of the CLI's serialiser: that would mean a
  direct dependency on `yaml`, which this repo carries only as a transitive
  `resolutions` pin, and would drift the day the CLI changes writer or options. Needs no
  credentials and no network.
- Keep `String.length`, matching the CLI's `templateJson.length` comparison. UTF-8 byte
  length would measure a different quantity than the gate.
- Replace the round-trip test. Comparing `load(dump(x))` to `x` is true for any object
  and could not detect the artifact drifting from its generator; export `buildTemplate()`
  / `renderTemplate()` and compare against an independently built template instead,
  which also gives the repo the template drift check it lacked.
- Add a test that reformatting the artifact cannot move the gated size, so a future
  budget failure is not "fixed" by reflowing the file — which is what happened here.
- Update existing policy assertions to parse the JSON string; document the second,
  independent size ceiling in DEPLOYMENT_ROLES.md (the 6,144-char limit is per policy,
  this one is per template) and re-sync the Starlight mirror.

Verified end-to-end: `cdk bootstrap --template ... --force` against a live account now
succeeds where it previously failed with BootstrapStackRequired, and the four deployed
managed policies have statement sets identical to the generated sources — the shape
change carries no permission change. A throwaway stack also confirmed CFN accepts a
JSON-string PolicyDocument and IAM stores it parsed, not as a literal string.

Co-Authored-By: Claude <noreply@anthropic.com>
@vivibui

vivibui commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — the blocking finding is correct, and I verified it rather than taking it on trust. Pushed as 199b09b (a follow-up commit, not a force-push, so the delta is reviewable).

The core finding: confirmed, and I reproduced the failure

You're right that makeBodyParameter re-serialises the parsed object, so the reflow never reached the wire. Three independent confirmations:

                on-disk        body CFN receives
main            54,213    →    53,370
4fa1c191        39,896    →    53,370   ← byte-identical
                               limit 51,200 → over by 2,169

And the decisive one, which is the step I skipped the first time: a real bootstrap on 4fa1c19 against a live account still failed, at makeBodyParameter (index.js:211616) — the exact line doing the check. A 39,896-byte file would have sailed through an on-disk gate. Your AI001/AI005 note is fair: I inferred the CLI's behaviour from its error message instead of running it once.

What changed

1 — content, not formatting. Reverted flowLevel: 6 and switched each ABCA PolicyDocument to a minified JSON string. Body 45,743, 5,457 under the ceiling. Only our six are converted; CdkBoostrapPermissionsBoundaryPolicy from the upstream template stays a mapping.

Worth noting the small delta from your 45,378: that figure converts all seven managed policies in the template. Converting only ours gives 45,743.

Your caveat about needing a live run to confirm CFN accepts it in this position — done, two ways. A throwaway stack with a JSON-string PolicyDocument reached CREATE_COMPLETE, and iam:GetPolicyVersion returned it parsed as a policy document, not a literal string. Then the real thing: cdk bootstrap --template ... --force against a live account now succeeds where it previously failed, and all four deployed policies have statement sets identical to the generated sources — the shape change carries no permission change.

2 — the guard measures the CLI's number now. One deviation from your suggestion, deliberately: rather than mirroring toYAML locally with yaml@1, the guard and test invoke cdk bootstrap --show-template on the committed artifact.

Reason: yaml isn't a dependency of this repo — it appears only in root resolutions as a transitive pin, so importing it directly would add a new direct dependency on a package that's present incidentally and could vanish when the advisory clears (import-x/no-extraneous-dependencies flags it immediately). More importantly, a local copy of the serialiser drifts the day the CLI changes writer or options, whereas asking the component that makes the decision cannot. Needs no credentials and no network — verified with the environment stripped.

A detail your snippet would also have hit: serialising the in-memory template under-reports by ~70 chars versus the committed file, because the js-yaml dump/re-parse normalises some scalars. The guard measures the written artifact.

3 — .length vs Buffer.byteLength: keeping .length, and I'd push back here. The CLI's gate is templateJson.length <= LARGE_TEMPLATE_SIZE_KB * 1024 — UTF-16 code units. Counting UTF-8 bytes measures a different quantity than the check we're predicting; they agree only while the template is ASCII, and the moment a non-ASCII character enters a policy Buffer.byteLength would over-report and fail the build for a template the CLI would happily send inline. cdk/test/main.test.ts measures a genuine byte payload, so it's right there and not here. Happy to be talked round if you think matching that precedent matters more than matching the gate.

4 — tautological test: agreed, replaced. You're right that load(dump(x)) === x holds for any object. buildTemplate() and renderTemplate() are now exported (script side-effects guarded by require.main === module), and the test compares the committed artifact against an independently built one — which also gives the repo the template drift check you noted was missing. Added a companion test asserting that reformatting the artifact cannot move the gated size, so a future budget failure doesn't get "fixed" by reflowing the file, which is precisely the trap I fell into.

5 — false comments and messages: rewritten. The error now names the CLI's re-serialisation, says explicitly that reformatting won't help, and prints the --show-template command to verify.

Non-blocking, taken: constants live in the new cdk/src/bootstrap/template-size.ts, imported by both generator and test (single source of truth — a dedicated module rather than version.ts, since it's about template size, not policy versioning; happy to move it if you'd rather). Reflow reverted for the reviewability reason you gave: max line was 142 → 1,605 chars, 44 lines over 200. Budget set to 49,152 (48 KiB), ~3.4 KB of headroom.

Documentation: docs/design/DEPLOYMENT_ROLES.md now documents the 51,200-char inline ceiling as a second, independent limit distinct from the per-policy 6,144-char one, why on-disk size isn't the gated quantity, and the JSON-string shape. Starlight mirror re-synced via mise //docs:sync.

Also updated seven existing assertions that read PolicyDocument.Statement as an array — they parse the string now, via a scoped helper.

Verification

  • mise run build — exit 0, 0 task failures, 4,477 cdk + 903 cli tests
  • npx jest test/bootstrap/ — 125/125 across all 6 suites
  • Guard has teeth: measured against main's mapping form it reports 53,369 and fires; on this branch 45,743 and passes
  • Live cdk bootstrap --force: ✅ Environment aws://…/us-east-1 bootstrapped

Governance

Acknowledged — #864 is unlabelled and unprioritised. I can't apply labels (no triage permission on this repo), so it needs a maintainer. Flagging the ordering honestly: the PR predates the approved label, which inverts ADR-003's sequence. That was a deliberate call by the repo owner I'm working with, not an oversight, and I raised it at the time.

vivibui and others added 2 commits September 8, 2026 17:57
…ance check

Refs aws-samples#864.

The formatting-invariance test failed in CI by exactly one character (45,834 vs
45,833) while passing locally. Not flakiness — a real property of YAML.

The test rendered one template with `lineWidth: 120` and one with `lineWidth: -1`.
Folding is not byte-neutral when it wraps a long *quoted scalar*, and each
PolicyDocument is now a multi-kilobyte JSON string, so the folded rendering can
re-parse a character off. That is a property of YAML folding, not of the size gate
the test is about, and conflating the two produced the failure.

Both renderings now disable folding and differ only in `flowLevel`, which still
makes the point more sharply than before: ~38 KB versus ~46 KB on disk, identical
45,744-char body from the CLI.

The committed artifact is unaffected — its integrity is covered by the deep-equality
check against `buildTemplate()`, and all six policy JSON strings parse cleanly. Had
folding ever corrupted the real artifact, that deep-equality test is what would fail.

Co-Authored-By: Claude <noreply@anthropic.com>
… not byte equality

Refs aws-samples#864.

The formatting-invariance assertion compared two serialisations of the same object
for exact byte equality. That is stronger than the claim needs and is not guaranteed:
YAML quoting and folding decisions interact with the multi-kilobyte JSON-string policy
documents, and the assertion passed locally while differing by one character on CI —
in both the folded and unfolded variants, so folding was not the cause. The absolute
body size also shifts slightly between environments, which I could not reproduce
locally.

One character is irrelevant to what the test is for. The claim worth locking in is
that reflowing the artifact cannot buy meaningful headroom: aws-samples#864's first attempted fix
shrank the file by 14 KB while the body CloudFormation received did not move at all.
A reflow that genuinely helped would have to save thousands of characters.

So: assert the two renderings differ by >1,000 characters on disk while their CLI
bodies agree within 64, and name in the test why exact equality is not asserted.

Co-Authored-By: Claude <noreply@anthropic.com>
@vivibui

vivibui commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

CI update after the follow-up commits:

check result
build (agentcore) pass
Validate PR title pass
Dead-code detection (advisory) pass
Secrets, deps, and workflow scan fail — pre-existing on main, not from this branch

On the dependency-scan failure. osv-scanner reports 6 advisories against packages in yarn.lock:

GHSA-26w7-cxv4-gfx2  9.8  astro    7.1.3   → 7.2.8
GHSA-376h-93r7-7g6f  6.3  astro    7.1.3   → 7.2.4
GHSA-2883-xcg3-v3hh  7.5  js-yaml  4.3.1   → 4.3.2
GHSA-rgj7-g3m4-5g8c  8.9  sharp    0.35.3  → 0.35.4
GHSA-4vpr-x523-8j87  6.1  svgo     4.0.2   → 4.1.0
GHSA-w27v-7q3p-w38r  8.2  svgo     4.0.2   → 4.1.0

Not from this branch — it changes six files, none of them a lockfile or package.json:

cdk/bootstrap/bootstrap-template.yaml
cdk/scripts/generate-bootstrap-template.ts
cdk/src/bootstrap/template-size.ts
cdk/test/bootstrap/bootstrap-template.test.ts
docs/design/DEPLOYMENT_ROLES.md
docs/src/content/docs/architecture/Deployment-roles.md

Confirmed by running mise run security:deps against a clean checkout of origin/main at 12c9b63f: identical 6 advisories, identical failure. These look newly published — this PR's own earlier run passed the same check a couple of hours ago, and #868 still shows a stale pass from before they landed. Worth a separate issue for the bumps; happy to file it if useful, though astro/sharp/svgo are docs/ dependencies and js-yaml is pinned via root resolutions, so it isn't a one-line change.

On the two extra commits after the review response. d4bdb983 and fd4c797b both fix the same test of mine, and the second supersedes the first — worth explaining rather than leaving as churn.

The formatting-invariance test asserted that two renderings of the same template produce a byte-identical body from the CLI. It passed locally and failed on CI by exactly one character (45,834 vs 45,833). My first fix assumed YAML line folding, since each PolicyDocument is now a multi-kilobyte quoted scalar and folding is not byte-neutral across a wrapped scalar. That was wrong: with folding disabled on both renderings, CI still differed by one. The absolute body size also shifts ~90 characters between local and CI, which I could not reproduce locally either.

Rather than keep guessing at a serialiser detail, the assertion now matches the claim it exists to defend: reflowing the artifact cannot buy meaningful headroom. The two renderings differ by >1,000 characters on disk while their CLI bodies agree within 64. #864's first attempt shrank the file 14 KB with zero movement in the body, so a reflow that genuinely helped would have to save thousands — one character is noise. The test says so explicitly, so the tolerance doesn't read as a fudge.

The committed artifact's own integrity is not asserted by tolerance: it's covered exactly by the deep-equality check against buildTemplate(), plus all six policy JSON strings parsing. If folding ever did corrupt the real artifact, that equality test is what fails.

@vivibui

vivibui commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Follow-up on the security-pr failure — it's unrelated to this PR, and I can now show that rather than assert it.

All six advisories were published today, mid-run

advisory published (UTC) package
GHSA-4vpr-x523-8j87 21:20:05 svgo
GHSA-w27v-7q3p-w38r 21:20:28 svgo
GHSA-2883-xcg3-v3hh 21:24:51 js-yaml
GHSA-rgj7-g3m4-5g8c 21:25:11 sharp
GHSA-376h-93r7-7g6f 21:26:02 astro
GHSA-26w7-cxv4-gfx2 21:26:16 astro

All six carry modified = ~21:30 — a coordinated batch.

Against this PR's own run history:

17:40:09  security-pr  success     ← same lockfile content
21:20-21:26            advisories published
21:23:48  security-pr  failure     ← first run inside the window
21:57:28  security-pr  failure
22:36:15  security-pr  failure

osv-scanner queries live OSV data at run time, so identical lockfile content flips verdict with no code change. Reproduced against a clean checkout of origin/main @ 12c9b63f: identical 6 advisories, identical failure. This branch changes six files, none of them a lockfile or package.json:

cdk/bootstrap/bootstrap-template.yaml
cdk/scripts/generate-bootstrap-template.ts
cdk/src/bootstrap/template-size.ts
cdk/test/bootstrap/bootstrap-template.test.ts
docs/design/DEPLOYMENT_ROLES.md
docs/src/content/docs/architecture/Deployment-roles.md

Remediation status — partial, and nothing covers svgo

#860 (dependabot) fixes four of the sixastro 7.2.9, js-yaml 4.3.2, sharp 0.35.4 — but only coincidentally: it was opened 2026-09-05, three days before these advisories existed, as a routine bump. It leaves svgo at 4.0.2, confirmed from its own lockfile:

svgo@^4.0.1:
  version "4.0.2"

svgo is transitive under astro, and astro 7.2.9 still declares svgo "^4.0.1", which the existing lock entry already satisfies — so nothing forces a re-resolve. Merging #860 alone will not turn this check green, and it is not currently mergeable anyway (its build (agentcore) is failing, and its own green scan badge is a stale 2026-09-05 artifact).

I've flagged the gap on #860 with the one-line completion — a root "svgo": "^4.1.0" resolution, verified locally to produce No issues found with mise run build clean. To be clear about status: no PR currently fixes svgo. Happy to open a minimal one if that's preferred to folding it into #860.

Practical note for reviewing

Every open PR in the repo is effectively red on this check right now, including any whose badge still shows green from a pre-21:20 run — #868 displays pass from 17:46:37, and #860's is from 2026-09-05. GitHub shows the last run, not a current verdict.

The other three checks on this PR are green, including build (agentcore).

vivibui pushed a commit to vivibui/sample-autonomous-cloud-coding-agents that referenced this pull request Sep 9, 2026
…es#870)

* fix(deps): clear 6 osv advisories in astro, sharp, svgo, js-yaml

osv-scanner fails on main's yarn.lock, which ejects every PR from the
merge queue: the merge_group re-scan runs against the latest main and
fails whatever is queued. Observed on aws-samples#867. These advisories were all
published after 2026-09-07 — osv-scanner reported "No issues found" in
the scheduled run recorded on aws-samples#861 — so PR-level scans that ran before
then are green while the re-scan is red.

- astro 7.1.3 -> 7.2.8 (docs/package.json, an exact pin).
  GHSA-26w7-cxv4-gfx2 (9.8), GHSA-376h-93r7-7g6f (6.3).
- js-yaml 4.3.1 -> 4.3.2 (GHSA-2883-xcg3-v3hh, 7.5). Root
  `resolutions` already reads ^4.3.1, so the caret admits the patch and
  no manifest changes.
- sharp 0.35.3 -> 0.35.4 (GHSA-rgj7-g3m4-5g8c, 8.9) and svgo
  4.0.2 -> 4.1.0 (GHSA-4vpr-x523-8j87, GHSA-w27v-7q3p-w38r).
  Transitive-only under caret ranges, so lockfile-only.

Re-resolved surgically rather than via `mise run upgrade`, which does
`rm -f yarn.lock && yarn install` and moved 328 packages here —
including aws-cdk-lib, constructs, jest, eslint and major jumps in
glob, commander, chalk and yargs. Burying six CVE fixes in a wholesale
upgrade makes the diff unreviewable and any regression unbisectable, so
only the four advisory entries (plus the @img/sharp-* platform
binaries) were dropped from the lockfile before `yarn install`. The
resulting delta is 50 changed / 1 added / 1 removed, all inside astro's
own closure and the four targets; no cdk or cli dependency moves.

MAL-2026-10726 — the malicious-release advisory that made aws-samples#637 pin
astro 7.1.3 rather than 7.1.0 — was withdrawn on 2026-07-17 and no
longer constrains the choice. No active malicious advisory affects any
of the four packages.

Verified: `mise run security:deps` (exact CI command) reports no
issues; `mise run security:retire` clean; `mise run drift-prevention`
exit 0; `mise //docs:build` builds 77 pages and `//docs:check` reports
0 errors under astro 7.2.8; `mise run build` clean with cdk 211 suites
/ 4471 tests and cli 60 suites / 903 tests passing. The bootstrap
golden-baseline snapshot passes unchanged, confirming js-yaml 4.3.2
does not alter template serialisation (relevant to aws-samples#867, which tunes
that dump's flowLevel).

* fix(deps): clear GHSA-7w5x-hrqm-74c2 in smol-toml

A seventh advisory landed while this PR was in flight, and it is the
same race the PR describes happening to the PR itself:
GHSA-7w5x-hrqm-74c2 (8.2, denial of service via malformed TOML) was
published 2026-09-09T18:07:11Z and the PR's first CI run started at
18:27:21Z, so the local scan twenty minutes earlier could not have
seen it.

smol-toml 1.7.0 is present on main unchanged, so this is not fallout
from the astro bump. Requesters are @astrojs/internal-helpers, astro
and knip, all under ^1.6.0 / ^1.6.1, so the caret admits the fix and
this is lockfile-only: 1.7.0 -> 1.8.0, the highest in range and past
the 1.7.1 first-patched version.

Verified: `mise run security:deps` reports no issues; `mise run build`
exits 0 with cdk 211 suites / 4471 tests and cli 60 suites / 903 tests;
`//docs:check` 0 errors and `//docs:build` 77 pages; security:retire
and drift-prevention exit 0. Delta against the previous commit is one
package and three lines.

Unrelated and pre-existing: `mise run check:deadcode-ratchet` reports
111 findings against an 85 baseline. Confirmed by restoring main's
docs/package.json and yarn.lock and re-running, which reports the
identical 111 — so it is not caused by this branch. CI's dead-code job
is advisory and passes.
ayushtr-aws
ayushtr-aws previously approved these changes Sep 10, 2026

@ayushtr-aws ayushtr-aws left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict

Approve with required edits. The fix is correct and verified: emitting each ABCA policy document as a minified JSON string brings the body the CDK CLI sends from 53,369 to 45,743 characters with zero permission drift. Three things need to land before merge, none of them in the policy content itself.

Vision alignment

Fits. This restores the single-command least-privilege bootstrap that ADR-002 promises and Quick Start documents. It narrows blast radius rather than widening it. No tenet is traded, so no ADR is needed.

Required before merge

  1. Governance. Issue #864 has no approved label, no assignee, and no priority label. Per ADR-003 the label must be applied before this merges.

  2. Rewrite the PR description. It describes the first commit on the branch (js-yaml flowLevel: 6, "54,213 to 39,896 bytes", a 48,000-byte budget, "parsed template unchanged"). None of that matches the shipped code. The 39,896 figure was an on-disk size for a template whose CLI body was still 53,369 and over the limit. The description is the record of what was verified and it currently misleads a reader. Describe the JSON-string approach, the 49,152 budget, and CLI-measured sizes.

  3. The size tolerance hides a measurement artifact, not YAML noise. Under CI=true (set in .github/workflows/build.yml:56) the CDK CLI writes "Using bootstrapping template from " to stdout, so cloudFormationBodySize() in cdk/src/bootstrap/template-size.ts:81 counts it. Reproduced:

    Invocation stdout chars
    local, no CI 45,744
    CI=true, repo path 45,812
    CI=true, /tmp/x.yaml 45,790

    The two temp filenames in the reformatting test differ by one character, which is the "one character on CI" that motivated FORMATTING_DRIFT_TOLERANCE = 64 at bootstrap-template.test.ts:308. The over-count is in the safe direction and cannot let a bad template through, so this is not a correctness bug. But the tolerance should not exist. Pass --no-ci (verified to suppress the line) and set the tolerance to 0.

Suggestions

  • Validate the measured body. An empty YAML file yields stdout null and a size of 5, which passes the guard. Parse stdout with yaml.load and require Resources and Parameters to be objects so a non-template measurement fails loudly.
  • Surface CLI failures. template-size.ts:92 ignores stderr, so a non-zero exit reports only "Command failed". Pipe stderr and attach it to the thrown error.
  • Write-then-measure at generate-bootstrap-template.ts:309 leaves an over-budget artifact on disk after a failed run. Write to a sibling .tmp path, measure, rename on success.
  • The guard path is untested. Extract the budget comparison into a pure function and test at budget, budget plus one, and past the hard limit.
  • Fixed temp filenames at bootstrap-template.test.ts:336 collide across worktrees and parallel runs. Use mkdtempSync.
  • Add --no-notices and an explicit 30 s Jest timeout on the CLI-invoking tests for slower or egress-restricted runners.
  • Wrong number at generate-bootstrap-template.ts:179: 45,378 should be 45,743, matching the docs.
  • New maintenance coupling worth stating in the PR. The byte-identical render test compares the committed YAML against the default template inside the installed aws-cdk package. No prior test did this. Every aws-cdk bump that touches the upstream template will now fail this test until the generator is re-run and the output committed. That is likely the right behaviour, but it turns some dependency bumps into PRs needing a manual regeneration step and should be a conscious decision.
  • Consider a patch bump of BOOTSTRAP_VERSION. The hash covers policy content, which is unchanged, so 1.6.0 is defensible. But an operator inspecting a deployed CDKToolkit cannot otherwise tell which template shape they have.
  • Pre-existing: cdk/eslint.config.mjs:49 does not lint scripts/, so the eslint-disable directives in the generator are inert. Worth a follow-up issue now that tests import that file.

Documentation

docs/design/DEPLOYMENT_ROLES.md gained an accurate callout on the inline limit and the string form. I ran mise //docs:sync on the branch and the tree stayed clean, so the Starlight mirror is in sync. No ADR needed. No new env vars or commands.

Tests and CI

All four CI checks pass. Locally on the branch, all 125 tests across the six bootstrap suites pass and tsc is clean. I did not run the full mise run build myself; a subagent reported the full suite meets coverage thresholds. The "Artifact matches the generator" block is genuinely new coverage. Bootstrap synth-coverage is not applicable, since no CloudFormation resource types or policy content changed.

What this review did not verify

The single most important claim in the PR, that CloudFormation accepts a JSON string for AWS::IAM::ManagedPolicy.PolicyDocument and IAM stores it parsed, rests on the service spec (type is a union of JSON and string) and the author's statement that it was deployed end-to-end. I did not deploy it. Please confirm that deployment actually happened against a real account before this becomes the template every new user bootstraps with. I also did not test how CloudFormation diffs the mapping-to-string change on an existing CDKToolkit stack.

Review agents run

  • /security-review: no high-confidence findings. Deep-compared all six parsed policy documents between main and the PR, on disk and as the CLI re-serialises them. Identical.
  • /code-review 867 high: its finder stage surfaced the CI stdout inflation, which I reproduced independently. Its final verified list did not complete before this write-up.
  • comment-analyzer, pr-test-analyzer, silent-failure-hunter scopes: covered by two general-purpose agents given those briefs. Their claims about CLI telemetry and notices behaviour are theirs, not independently checked by me.
  • type-design-analyzer: omitted, the PR adds no new types beyond two numeric constants.

Human heuristics

  • Proportionality: concern. Three CLI invocations per test run to assert a property of that CLI is heavier than needed. One measurement plus a shape check suffices.
  • Coherence: pass. Terminology matches the existing bootstrap tree and the docs callout sits beside the existing IAM 6,144-character note.
  • Clarity: concern at template-size.ts:92 and bootstrap-template.test.ts:308. Swallowed stderr and a tolerance tuned to make a symptom disappear both hide signal.
  • Appropriateness: partial. Verifying against the real CLI was the right instinct. The CLI's CI-mode behaviour was not checked, and the tolerance was the result.

ClintEastman02 and others added 3 commits September 10, 2026 17:22
Refs aws-samples#864. Addresses review round 2 on aws-samples#867.

The tolerance was hiding a measurement bug, not YAML noise. In CI mode the CDK CLI
routes progress to *stdout* rather than stderr, so `cloudFormationBodySize` counted
"Using bootstrapping template from <path>" as part of the template body — and the
inflation tracked the path's length, which is why two temp filenames differed by exactly
one character and why I could not reproduce it locally. Reproduced and fixed:

    no CI, repo path        45,744
    CI=true, repo path      45,812   (+68 = the console line)
    CI=true, long tmp path  45,790   (varies with path length)
    with --no-ci            45,744

`.github/workflows/build.yml` sets `CI: true`, so every CI measurement was inflated.
Passing `--no-ci` makes it 45,743 in all three cases, and `FORMATTING_DRIFT_TOLERANCE`
is gone rather than tuned. Also `--no-notices`, since notices are another stdout writer
and they hit the network.

Other review points:

- Validate the measured body. An empty file renders as `null`, measures 5 chars, and
  passed the budget — a guard that is happiest having measured nothing. Now parses the
  output and requires `Resources` and `Parameters` to be objects, so a non-template
  measurement fails loudly.
- Surface CLI stderr. A non-zero exit reported only "Command failed" with the CLI's own
  explanation discarded; stderr is captured and attached to the thrown error.
- Write-then-measure left an over-budget artifact on disk after a failed run, so the next
  reader — including `cdk bootstrap` — would use a template the generator had rejected.
  Now writes a sibling `.tmp`, measures, and renames only on success.
- The budget comparison had no test, because the only way to exercise it was to make the
  real template too big. Extracted as the pure `checkTemplateBudget`, tested at budget,
  budget+1, past the hard ceiling, and at 53,369 — the body that aws-samples#864 actually shipped.
- Three CLI invocations per run down to one. Formatting invariance is now asserted on
  *parsed* equality, which is exact and free: the CLI derives its size from the parsed
  object, so identical parses cannot differ on the wire. That also removes the temp files
  the tolerance needed, so there are no fixed filenames left to collide across worktrees.
- Explicit 30 s Jest timeout on the CLI-invoking hook, well past the 5 s default, so a
  slow or egress-restricted runner reports a timeout instead of a mystery.
- Corrected 45,378 to 45,743 in the generator comment, matching the docs and the
  committed artifact.

Co-Authored-By: Claude <noreply@anthropic.com>
@vivibui

vivibui commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — and the CI-mode finding is the good one. You explained a result I'd papered over rather than understood, so I want to be explicit about that below. Pushed as 9ce2492, with your and @ClintEastman02's main merges folded in.

Required 3 — you found the actual bug, and the tolerance is gone

I could not reproduce that one-character difference locally and settled for a tolerance, which was the wrong call. Your diagnosis is exact — in CI mode the CLI writes progress to stdout, so cloudFormationBodySize was counting a console line as part of the template body. Reproduced:

no CI, repo path        45,744
CI=true, repo path      45,812   (+68 = "Using bootstrapping template from <path>")
CI=true, long tmp path  45,790   (varies with path length)
with --no-ci            45,744

That last column is the whole mystery: the two temp filenames differed in length, not the YAML. .github/workflows/build.yml sets CI: true, so every CI measurement was inflated — in the safe direction, as you say, but by an amount that depended on where the file happened to live.

Now passes --no-ci and FORMATTING_DRIFT_TOLERANCE is deleted, not set to 0 — the assertion it guarded no longer measures twice. Verified stable at 45,743 across no-CI, CI=true, and a deliberately long path. Added --no-notices too, since notices are another stdout writer and they reach the network.

Required 2 — description rewritten

You're right that it documented the reverted approach, and that the body is the record of what was verified. Rewritten around the JSON-string change, the 49,152 budget, and CLI-measured sizes throughout. It now also states plainly that the reflow approach was tried and reverted, with the 39,896-on-disk / 53,369-on-the-wire numbers as the reason — that failure is the most useful thing in the PR for anyone who later reaches for reformatting.

Also folded in the maintenance coupling you flagged, as its own callout rather than a footnote: every aws-cdk bump touching the upstream template will now fail the byte-identical render test until the generator is re-run and committed. Worth reviewers agreeing to that rather than discovering it.

On the thing you did not verify — it was deployed

Fair to ask, and specifics rather than a claim:

  • Throwaway stack with a JSON-string PolicyDocumentCREATE_COMPLETE, and iam:GetPolicyVersion returned it parsed as a policy document, not a literal string.
  • cdk bootstrap --template bootstrap/bootstrap-template.yaml --force against account 618731765007succeeded, CDKToolkit UPDATE_COMPLETE across all six managed policies, where the pre-fix template failed with BootstrapStackRequired.
  • All four deployed policies then compared statement-by-statement against the generated sources: identical sets (Infrastructure 5, Application 13, Observability 12, Compute-Agentcore 1).

Your caveat about the mapping-to-string diff on a pre-existing CDKToolkit is the real remaining gap and I've said so in the description. The stack I updated already carried the ABCA variant, so that path is exercised; an upgrade from the stock CDK bootstrap is not.

Suggestions — all taken except one

  • Validate the measured body. Good catch that null measures 5 and passes. Now parses the output and requires Resources and Parameters to be objects; an empty file throws with the size and the reason instead of silently reporting 5.
  • Surface CLI failures. stderr captured and attached to the thrown error, rather than "Command failed" with the explanation discarded.
  • Write-then-measure. Now writes a sibling .tmp, measures, renames on success, and removes the staging file on failure — so a rejected template is never left where cdk bootstrap would read it.
  • Guard path untested. Extracted as pure checkTemplateBudget, asserted at budget, budget+1, past the hard ceiling, and at 53,369 — the body this bug actually shipped, which felt like the regression marker worth keeping.
  • Proportionality — three invocations down to one. Your instinct was right and the fix was better than trimming: formatting invariance is now asserted on parsed equality instead of measuring both files through the CLI. Since the CLI derives its size from the parsed object, identical parses cannot differ on the wire — exact, no tolerance, no subprocess. That also removed the temp files entirely, so the fixed-filename collision you flagged is gone rather than patched with mkdtempSync.
  • --no-notices and an explicit 30 s Jest timeout on the CLI-invoking hook, both added.
  • Wrong number at :179 corrected to 45,743.
  • eslint gap filed as #882. Confirmed it: eslint reports File ignored because no matching configuration was supplied, and the five eslint-disable directives in the generator are inert. Note it needs two changes, not one — the config glob and the //cdk:eslint task, which passes src test explicitly.

BOOTSTRAP_VERSION — left at 1.6.0, and I'd like your read. The version's documented contract is the policy bundle, the hash covers policy content, and that content is unchanged, so no operator needs to re-bootstrap for permissions. Against that, your point stands that an operator inspecting a deployed CDKToolkit can't otherwise tell which template shape they have. I've left it and flagged the tradeoff in the description; say the word and I'll add a patch bump.

Verification

Required 1 — governance

Still needs someone with triage permission; I don't have it. @isadeks offered on #868 to apply retroactive approved plus priority across #864/#865/#866#875, #878 and #882 are unlabelled too if it's being done in a batch.

One note on history: you and @ClintEastman02 both pushed main merges to this branch, so I merged rather than force-pushed and 21b102c4 is a merge commit. Happy to linearise before you squash if you'd prefer — I didn't want to rewrite commits you'd pushed.

@ayushtr-aws
ayushtr-aws added this pull request to the merge queue Sep 11, 2026
Merged via the queue into aws-samples:main with commit 5e10038 Sep 11, 2026
5 checks passed
@scottschreckengaust scottschreckengaust added the v1 Version 1 label Sep 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v1 Version 1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(bootstrap): least-privilege bootstrap template exceeds CFN 51,200-byte inline limit — fresh-account bootstrap is impossible

5 participants