giantswarm/giantswarm-aws-account-prerequisites, the crossplane/ module (pinned tag v8.2.2, commit f1a7d8d51086824a97749b1a8a13327c6f081f72)
Source: https://github.com/giantswarm/giantswarm-aws-account-prerequisites.git at v8.2.2.
Set: core. Lane: opentofu-native.
Why it is in the core set: a real project built for OpenTofu specifically, so OpenTofu-only surface is exercised
Clear. Every headline stage passes.
| Stage | Verdict | Duration | Detail |
|---|---|---|---|
| Cold deploy | pass | 5s | 6 resource instances added, 0 already tofu-estate-marked before migration |
| Migrate | pass | 23s | 2 of 6 stamped (role, managed policy), 4 untaggable skipped, module’s own tags survived the stamp |
| Replan from nothing | pass | 3s | live-plan empty, role/policy tofu-address unchanged, both *_exclusive resources re-derived by value |
| No-op apply | pass | 2s | no-op apply (0 added, 0 changed, 0 destroyed); object count unchanged at 2, both exclusive sets unchanged |
| Drift and reconverge | pass | 5s | role’s installation tag tampered, exactly the IAM role proposed and reconciled, apply changed 1, tag reads back as configured |
| Rename | pass | 10s | moved block: module.crossplane renamed to .crossplane_renamed with zero churn (0 add, 2 change, 0 destroy - role and policy), markers rewritten in place; live-mv: .crossplane_renamed renamed to .crossplane_final with zero churn, both markers rewritten in place (one live-mv call per taggable object); stock oracle over the same chained module rename on cold_deploy’s own state also shows zero churn (0 add, 0 change, 0 destroy); both live ids unchanged, read via the AWS CLI |
| Remove a block | pass | 5s | choudoufu: deleting module.crossplane_final’s block proposed 6 resource action(s), address-for-address and action-for-action identical to stock’s oracle on cold_deploy’s own state; applied cleanly; the role is genuinely gone from the live account (get-role now returns NoSuchEntity, read via the AWS CLI, not choudoufu’s own report); classifyOrphans did not withhold any destroy because no other module.crossplane* block is declared anywhere in this config; the next plan is empty |
| Change count | pass | 40s | choudoufu: scaling aws_iam_role.count_test from 2 to 1 proposed exactly “count_test[1] will be destroyed” (0 add, 0 change, 1 destroy) and applied it, leaving count_test[0]’s server-minted RoleId (AROAF6UOOK7U9HWAWCUB), its CreateDate and its tofu-address=aws_iam_role.count_test:0 marker all unchanged, and tombstoning count_test[1]’s local record (has tombstone, no identity - the #398-guard shape); scaling back from 1 to 2 proposed exactly “count_test[1] will be created” (1 add, 0 change, 0 destroy) and brought it back under the SAME deterministic name (giantswarm-crossplane-count-test-1) with a NEW RoleId (AROAKT3QF6VPPUKQNPE0 -> AROA9Z1KIB868XAAA8W4) and a new CreateDate, re-marked aws_iam_role.count_test:1 and re-identified in the record store, while count_test[0] stayed untouched throughout; the next plan is empty. Every identity here is read back through the AWS CLI and the local record store, never through choudoufu’s own report, and the destroy witness is the RoleId rather than the name or the ARN because both of those are deterministic from configuration and come back identical - confirmed against floci directly, no tofu in the loop, before the assertions were written. Stock oracle (G-ORACLE): real tofu standing the IDENTICAL count block up in the idle greenfield-oracle account showed the identical shape - destroy the higher index only, create the higher index back under the same name with a new RoleId (AROAUPVLO1EN4EMFJMYY -> AROARYYO2DDILTQTPK6Y), the lower index’s RoleId and CreateDate unchanged both times - and the two sides’ normalised action sets are compared literally, not just described. Synthetic block, per live/GAUNTLET.md #8’s sanctioned fallback: the pinned crossplane module declares no count at all and its only two for_each knobs (aws_iam_role_policy.additional_policies over var.additional_policies, aws_iam_role_policy_attachment.additional_policy_attachments over toset(var.additional_policies_arns)) are both UNTAGGABLE types that carry no marker to keep an identity in, the second provably resolving to zero instances, and the first’s inline-policy set is additionally policed by aws_iam_role_policies_exclusive in the same module; aws_iam_role.count_test reuses a type this estate already exercises and lives in its own day2_count.tofu beside the estate’s root wiring ($ESTATE), so the vendored module stays byte-identical. BREAK_COUNT=1 asserts the WRONG instance (count_test[0]) was destroyed and reports fail, proving the which-instance assertion is load-bearing. G1S (#969/#976), the two kinds of count instance side by side in one apply: the whole tag key set is read back off each live role through the AWS CLI, and count_test[0]/count_test[1] - whose names the configuration itself builds from count.index, so identity resolution answers CONCRETE per instance - carry exactly [purpose tofu-address tofu-estate], with tofu-estate=giantswarm-crossplane-crossing and tofu-address=aws_iam_role.count_test:0/:1 asserted by value and tofu-slot ABSENT (the query returns None), while two roles of the SAME type differing in exactly one property - name_prefix instead of name, so NEEDS_DISCOVERY - carry [tofu-address tofu-estate tofu-slot] and read back the pairs aws_iam_role.slot_control:0=0 aws_iam_role.slot_control:1=1 through the identical call, which is what makes the absence evidence rather than a broken query; the plan with all four instances live proposes nothing, so the slotless set binds by tofu-address and the fungible one by its slots. BREAK_SLOT=1 stamps a tofu-slot onto count_test[0] out of band through the AWS CLI and the identical assertions catch it, proving the absence check is load-bearing (an absence needs a wrongly-PRESENT tag as its break, not a missing one). |
| Replace with create_before_destroy | pass | 7s | choudoufu: changing module.crossplane_final’s ForceNew installation_name argument proposed a 6 add / 0 change / 6 destroy cascade with the role and the managed policy each explicitly named ‘must be replaced’ at their same declared addresses, applied cleanly; the old role (giantswarm-gsprereqs-crossplane) is confirmed gone and the new role (giantswarm-gsprereqs-v2-crossplane) carries the marker, both via the AWS CLI; the local record store’s record at the role’s address now names the new role, not the destroyed one (giantswarm-gsprereqs-crossplane -> giantswarm-gsprereqs-v2-crossplane); the next plan proposes no resource action; stock oracle on cold_deploy’s own state (F-ORACLE) also proposes an equal add/destroy cascade (>=2) with role and policy both replaced at the same addresses (plan only, not applied - it shares floci’s account with $ESTATE); BREAK=replace confirms a manufactured marker collision is reported loudly (a named ‘Live resource displaced from the address it is marked for’ warning, the scalar-resource shape) rather than silently proposed as nothing. Scope note: this exercises OpenTofu’s default destroy-then-create ordering, not the create_before_destroy variant the stage’s Title names - see this section’s own header comment and corpus-sqs-basic’s matching one. |
| Crash between create and destroy | not run | ||
| Teardown | not run | ||
| Plan, review, apply | pass | 11s | one argument edited (additional_policies[“extra-tagging”] widened to allow ec2:DeleteTags as well), “plan -out=approved.tfplan” wrote a 10340-byte stock-format plan file whose whole change set is one update on module.crossplane.aws_iam_role_policy.additional_inline_policies[“extra-tagging”]; the world then moved out of band (giantswarm-gsprereqs-crossplane’s installation tag, through the AWS CLI, never through choudoufu) and “apply approved.tfplan” refused with “The approved plan no longer matches the live system” at exit 3, classifying the drift under “This apply would do, and the approved plan does not include:” and naming both module.crossplane.aws_iam_role.giantswarm_crossplane_role and the live giantswarm-gsprereqs-crossplane it was computed against, with “Exit status 3” spelled out for a pipeline; nothing was applied - the inline policy read back through the AWS CLI still allowed only ec2:CreateTags, which is stronger evidence than the absence of an “Apply complete!” line. Inverted control on the same run (the shape live/smoke/scenarios/apply-what-was-approved.sh reasons out): with the tag put back and nothing else changed, the IDENTICAL file applied - 0 added, 1 changed, 0 destroyed - and the inline policy read back allowing ec2:DeleteTags, so the refusal is earned by the drift and not handed out to every plan file. BREAK_APPROVAL=1 asserts stage 12’s own recorded Break line (apply the planfile after a mutation and expect success) and correctly fails |
| Greenfield apply | pass | 12s | 6 resources from nothing (role, managed policy, 4 untaggable), role marker verified via the AWS CLI, 6 records in the local record store (#364 A2, one per managed instance), replan empty, stock oracle in its own namespace matches structurally on the role and the managed policy |
| Strict profile (not a headline stage) | not run |
Last run at commit 933618dec4 on 2026-09-08T22:17:50Z, exit code 0, against emulator image ghcr.io/lex00/floci@sha256:a39185cc3971d0188663d61043cb038dff1260d8a975b1aa72c4e2bb1feac3cb. Stale: the current pin is ghcr.io/lex00/floci@sha256:d9207de14c919f4bfa50e956376cc441970f3679aabfdd43f3dbf4b779b20805. Total run time 2m3.7s.
Oracle: stock terraform 1.16.1, stock tofu 1.12.6 (matches the current pin).
Landed 2026-08-19 (crossing 0bd3ac80b7, merge 9fa0141294), the seventh OpenTofu-native estate and the first from a commercial vendor’s production repository rather than a module registry, personal monorepo, or single-maintainer accelerator - Giant Swarm GmbH’s own customer-facing account-prep for their managed Kubernetes offering. OpenTofu-native evidence, three independent kinds: README’s opening sentence and directory index both say OpenTofu with no compatibility hedge; the CI workflow is named ‘OpenTofu checks’, installs via opentofu/setup-opentofu, and never mentions terraform; the crossed crossplane/ directory is genuinely .tofu-suffixed throughout (providers.tofu, role.tofu, variables.tofu), the file-level standard only the hongbomiao slices had met before (overture-tiles and xancloud-iac are both plain .tf). Scoped to crossplane/ specifically: self-contained (no remote state, no live EKS/OIDC dependency, its only data source is aws_partition which makes no API call), the other five directories in the repo excluded with stated reasons (three plain-.tf same-shape, one an account-singleton quota table, one a wrapper that only calls the others). Real run, rc=0, 548s. cold_deploy: PASS, plain tofu apply, 6 resources added, 0 pre-existing tofu-estate tags, the toset()-keyed for_each on additional_policy_attachments confirmed resolving to zero instances. migrate: PASS - 2 of 6 eligible (UNTAGGABLE 2, UNADMITTED_TYPE 2, DRIFTED 2), -approve 2 newly stamped 0 failed, both markers re-verified directly through the AWS CLI including that the module’s own installation tag survived the stamp. test_plan: BLOCKED for real at exactly 2 sites, the plan’s entire diagnostic surface - both Rule: unadmitted-type, on aws_iam_role_policy_attachments_exclusive and aws_iam_role_policies_exclusive, no other rule firing anywhere in the estate. A control stage (3b, not counted toward stage 4/5) cut exactly those two resource blocks and drove the rest of the pipeline for real: control test plan EMPTY, control test apply a genuine no-op (2 objects before and after), control drift-and-reconverge fixed exactly one mutated object - proving the estate’s only real block is those two types, not routing around anything. Both negative controls (BREAK=1 at the stage-2 identity assertion, BREAK_STAGE3=1 expecting 3 refusal sites where the real count is 2) verified failing in real full runs. Filed as INTENTIUS/choudoufu#334: both unadmitted types have the identical import-grammar shape (single-argument, no-separator) to aws_vpc_security_group_rules_exclusive, which #307 already admitted via row-gen’s tryGrammarComposite at 64cac28120, and carry the same no-CFN-counterpart mapping-gen overlay as that admitted twin - a worked ADMIT-class precedent, not attempted here; the one recorded difference (force_new on the admitted twin’s security_group_id, absent on either new type’s role_name) is flagged as not obviously the gate since tryGrammarComposite’s single-argument branch reads no force_new field, and why row-gen’s own proposal for these two is currently absent from ratified.json is the fix’s first open question. No Go code touched. justfile gained demo-corpus-giantswarm-crossplane; live/corpus-manifest.json gained the pin; HANDOFF.md section 3 updated. Follow-up pass 2026-08-19/20 (#334 fixed and merged, 37957d873c/a6627543c4/20cc1774d6): the issue’s own open question resolved the OPPOSITE way from what it suspected - row-gen was never declining to propose these two rows; it proposes both, byte-identical in shape to the admitted aws_vpc_security_group_rules_exclusive twin, and nobody had ever ratified the proposal. Fix is a ratified.json entry, no code change - reach is exactly these two types, stated plainly rather than dressed up as a generalization. The real finding: 316 types row-gen proposes sit unratified, 166 under this exact rule (including every other *_exclusive family member) - a ratification backlog, not a generator defect, and clearing it is a maintainer-scale call since every ratified row is a claim that touches live infrastructure. FIVE OF FIVE, run for real on the rebased tree, rc=0, 250s: stage 3 now an empty plan (identities asserted by value - the two exclusive resources carry no marker, being untaggable, so the assertion is the live content each enforces, e.g. attached policy ARN and inline-policy name); stage 4 a genuine no-op (2 tagged objects before and after, both exclusive sets independently re-read afterward so a wrongly-reconciled enforcer would be caught); stage 5 one out-of-band mutation, exactly one object proposed and fixed. Three real negative controls (BREAK=1, BREAK_STAGE3=1, BREAK_STAGE5=1) each confirmed failing at the right point. Script rewritten: stage 3 now asserts a pass instead of hard-failing by design, the 3b control retired with the block it existed to control for. Separately found, not yet fixed: every crossing script that runs more than one terraform init pays a real ~320s tax per extra init, because the shared plugin cache records no checksums and a directory with no .terraform.lock.hcl re-downloads the whole provider to compute them - seeding the lock file from stage 1’s own init cuts this to ~1s and this estate’s full run from several failed 10-minute-cap attempts to 250s total. Worth a sweep across every multi-init script here.
Reproduce it#
go run ./tools/gauntlet run corpus-giantswarm-crossplaneNeeds Docker (the emulator is pulled at the pinned digest), the AWS CLI, and a
stock terraform or tofu binary on PATH for the cold deploy. The script is
live/e2e/corpus-giantswarm-crossplane/run.sh; BREAK=1 corrupts its assertions to show they are load-bearing.