@intentius/chant-lexicon-terraform 0.59.0 → 0.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/describe-resources.d.ts +59 -0
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/hcl/edges.d.ts +124 -0
- package/dist/hcl/edges.d.ts.map +1 -0
- package/dist/hcl/parse.d.ts +42 -0
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/roots.d.ts +6 -0
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/terraform.d.ts +44 -8
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/adoption.d.ts +110 -35
- package/dist/op/adoption.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/__fixtures__/ACCEPTANCE.md +92 -58
- package/src/__fixtures__/graph-roots/README.md +21 -0
- package/src/__fixtures__/graph-roots/app/main.tf +41 -0
- package/src/__fixtures__/graph-roots/app/modules/cdn/main.tf +7 -0
- package/src/__fixtures__/graph-roots/network/main.tf +16 -0
- package/src/__fixtures__/live-estate/README.md +65 -19
- package/src/__fixtures__/live-estate/adoptable.tf +13 -0
- package/src/__fixtures__/live-ls.json +5 -5
- package/src/__fixtures__/live-plan.json +67 -35
- package/src/composites/terraform-adopt-op.acceptance.test.ts +36 -50
- package/src/composites/terraform-apply-op.acceptance.test.ts +4 -2
- package/src/describe-resources.live.test.ts +76 -4
- package/src/describe-resources.test.ts +35 -0
- package/src/describe-resources.ts +110 -3
- package/src/hcl/edges.test.ts +207 -0
- package/src/hcl/edges.ts +316 -0
- package/src/hcl/parse.ts +53 -0
- package/src/hcl/roots.ts +14 -0
- package/src/index.ts +1 -0
- package/src/op/activities/choudoufu.test.ts +3 -3
- package/src/op/activities/terraform.ts +70 -21
- package/src/op/adoption.test.ts +129 -11
- package/src/op/adoption.ts +181 -49
package/dist/op/adoption.d.ts
CHANGED
|
@@ -1,14 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The adoption ledger: which live resources this estate's markers can claim,
|
|
3
|
-
* read off `live-plan -json`'s document and rendered as text (#2105).
|
|
3
|
+
* read off `live-plan -json`'s document and rendered as text (#2105, #2241).
|
|
4
4
|
*
|
|
5
5
|
* Pure. No filesystem, no child process, no HCL parse — everything here is a
|
|
6
|
-
* projection of
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* projection of two sections of choudoufu's document, which between them state
|
|
7
|
+
* both halves of the answer: the live resource an adoption would claim, and
|
|
8
|
+
* the `tofu-estate`/`tofu-address` pair that claims it. Two tags is the whole
|
|
9
|
+
* ownership contract (choudoufu's `live/MARKERS.md`), so those two values are
|
|
10
|
+
* the whole of what an adoption needs to know.
|
|
11
|
+
*
|
|
12
|
+
* ## The two sections, and why there are two
|
|
13
|
+
*
|
|
14
|
+
* `unowned[]` (choudoufu issue #788) is a live resource read at an identity
|
|
15
|
+
* the configuration itself declares: a log group's name is in the block, so an
|
|
16
|
+
* unmarked live one with that name is found by reading it.
|
|
17
|
+
*
|
|
18
|
+
* `adoptable[]` (choudoufu issue #962, shipped in v0.15.0) is a live resource
|
|
19
|
+
* the estate-wide sweep matched to a declared instance by content, for a
|
|
20
|
+
* declaration that carries no identity at all: EC2 assigns a VPC's id, so a
|
|
21
|
+
* declared `aws_vpc` lands in `omissions[]` as `NEEDS_DISCOVERY` and the live
|
|
22
|
+
* VPC standing at its `cidr_block` is found by comparing arguments. Each row
|
|
23
|
+
* carries `matched[]`, the arguments that agreed, and `adopt_command`, the
|
|
24
|
+
* paste-ready tagging command, so nothing on this path parses the human
|
|
25
|
+
* render any more. Before v0.15.0 the document had no row for that match at
|
|
26
|
+
* all and chant read the two regexes {@link parseAdoptionCommands} still
|
|
27
|
+
* holds, which is what chant #2168 measured and filed.
|
|
28
|
+
*
|
|
29
|
+
* The two sections are disjoint by construction, so this reads both and keys
|
|
30
|
+
* the union by declared address.
|
|
31
|
+
*
|
|
32
|
+
* ## What the empty ledger means
|
|
33
|
+
*
|
|
34
|
+
* `adoptable[]` and `swept[]` are populated only on a run that asked the
|
|
35
|
+
* estate-wide sweep the account-bounded question (`-adoption-only`, or
|
|
36
|
+
* `TOFU_LIVE_COLLECT_UNCLAIMED=1` on a `-json` run). {@link AdoptionLedger}
|
|
37
|
+
* carries `swept` for exactly that reason: an empty `adoptions` under an empty
|
|
38
|
+
* `swept` is "this run did not look", not "there is nothing to adopt", and
|
|
39
|
+
* {@link renderAdoptionLedger} says which.
|
|
12
40
|
*
|
|
13
41
|
* ## Why chant renders a ledger at all
|
|
14
42
|
*
|
|
@@ -18,42 +46,62 @@
|
|
|
18
46
|
* says why each unadoptable instance is unadoptable. But `-adoption-only` and
|
|
19
47
|
* `-json` are refused together (`internal/command/live_plan.go`: "this run
|
|
20
48
|
* cannot produce both reports at once"), and an Op that reports adoptables
|
|
21
|
-
* needs the machine-readable document anyway
|
|
22
|
-
* outcome attributes
|
|
49
|
+
* needs the machine-readable document anyway, for the counts it publishes as
|
|
50
|
+
* outcome attributes and for the addresses an adoption step acts on. So the
|
|
23
51
|
* ledger below is rendered from the document that run already has, in the row
|
|
24
52
|
* form `-adoption-only` prints, rather than paying for a third live read.
|
|
25
53
|
*
|
|
26
54
|
* ## Ambiguity
|
|
27
55
|
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* two entries carrying the same `addr`. That is the ambiguous
|
|
31
|
-
* tag write claims the address, and picking one of the two is
|
|
32
|
-
* the estate rather than something a tool infers.
|
|
33
|
-
* separates those into `contested` and never lets
|
|
34
|
-
* `TerraformAdoptOp` passes the contested list to
|
|
35
|
-
* result names what it refused as well as what it
|
|
56
|
+
* Both sections are one entry per live resource, keyed by the declared
|
|
57
|
+
* instance the resource was matched to, so two live resources at one
|
|
58
|
+
* declaration are two entries carrying the same `addr`. That is the ambiguous
|
|
59
|
+
* case: no single tag write claims the address, and picking one of the two is
|
|
60
|
+
* a decision about the estate rather than something a tool infers.
|
|
61
|
+
* {@link readAdoptionLedger} separates those into `contested` and never lets
|
|
62
|
+
* them into `adoptions`, and `TerraformAdoptOp` passes the contested list to
|
|
63
|
+
* its Adopt step so the Op's result names what it refused as well as what it
|
|
64
|
+
* wrote.
|
|
36
65
|
*/
|
|
66
|
+
/** One argument a content match rested on, as choudoufu's `adoptable[].matched[]`. */
|
|
67
|
+
export interface AdoptionMatch {
|
|
68
|
+
/** The argument's name in the declared block, `cidr_block` and the like. */
|
|
69
|
+
attribute: string;
|
|
70
|
+
/** The value both the declaration and the live resource carried. */
|
|
71
|
+
value: string;
|
|
72
|
+
}
|
|
37
73
|
/** One live resource a marker write would bind to a declared instance. */
|
|
38
74
|
export interface AdoptionCandidate {
|
|
39
|
-
/** The declared instance address
|
|
75
|
+
/** The declared instance address the live resource was matched to. */
|
|
40
76
|
addr: string;
|
|
41
|
-
/** The live resource's type, as choudoufu's `
|
|
77
|
+
/** The live resource's type, as choudoufu's `type`. */
|
|
42
78
|
type: string;
|
|
43
|
-
/** The identity the live resource was read with
|
|
79
|
+
/** The identity the live resource was read with: the handle a human, or a tagging call, needs. */
|
|
44
80
|
identity: string;
|
|
45
81
|
/** The `tofu-estate` value that adopts it. */
|
|
46
82
|
markerEstate: string;
|
|
47
83
|
/** The `tofu-address` value that adopts it, escaped as choudoufu stores it. */
|
|
48
84
|
markerAddress: string;
|
|
49
85
|
/**
|
|
50
|
-
* The paste-ready tagging command choudoufu printed for this address
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
86
|
+
* The paste-ready tagging command choudoufu printed for this address, when
|
|
87
|
+
* it printed one. Absent for a type whose service has its own tagging call
|
|
88
|
+
* this fork does not spell out (IAM, Route53, S3 and friends): the two
|
|
89
|
+
* marker values above are still the whole contract, but the caller has to
|
|
90
|
+
* write them itself.
|
|
91
|
+
*
|
|
92
|
+
* An `adoptable[]` row carries its own (`adopt_command`, choudoufu #962). An
|
|
93
|
+
* `unowned[]` row does not, so a command for one of those comes from the
|
|
94
|
+
* `commands` map {@link parseAdoptionCommands} builds off the human render.
|
|
55
95
|
*/
|
|
56
96
|
command?: string;
|
|
97
|
+
/**
|
|
98
|
+
* The arguments the declaration and the live resource agreed on exactly, in
|
|
99
|
+
* the order choudoufu's matcher compared them. Present on a content match
|
|
100
|
+
* (`adoptable[]`) and absent on a row found by reading a declared identity
|
|
101
|
+
* (`unowned[]`), which matched on the identity itself and has nothing else
|
|
102
|
+
* to name.
|
|
103
|
+
*/
|
|
104
|
+
matched?: AdoptionMatch[];
|
|
57
105
|
}
|
|
58
106
|
/** What {@link readAdoptionLedger} found in one `live-plan -json` document. */
|
|
59
107
|
export interface AdoptionLedger {
|
|
@@ -68,20 +116,29 @@ export interface AdoptionLedger {
|
|
|
68
116
|
contested: AdoptionCandidate[];
|
|
69
117
|
/** How many distinct declared addresses are contested. */
|
|
70
118
|
ambiguous: number;
|
|
119
|
+
/**
|
|
120
|
+
* `swept[]`: every resource type the estate-wide sweep listed in full on the
|
|
121
|
+
* run that produced the document. Empty means the run never asked the
|
|
122
|
+
* account-bounded question, so an empty `adoptions` beside it is silence
|
|
123
|
+
* rather than a finding.
|
|
124
|
+
*/
|
|
125
|
+
swept: string[];
|
|
71
126
|
}
|
|
72
127
|
/**
|
|
73
|
-
* Project a `live-plan -json` document's `unowned`
|
|
74
|
-
* and the contested sets.
|
|
128
|
+
* Project a `live-plan -json` document's `unowned` and `adoptable` sections
|
|
129
|
+
* into the adoptable and the contested sets.
|
|
75
130
|
*
|
|
76
131
|
* An entry counts as a candidate only when choudoufu offered both marker
|
|
77
|
-
* values. Both empty means adoption was not this run's to offer
|
|
132
|
+
* values. Both empty means adoption was not this run's to offer: the resource
|
|
78
133
|
* belongs to another estate (`tofu_estate` names it), or the run had no estate
|
|
79
|
-
* name of its own
|
|
134
|
+
* name of its own, and such an entry is neither adoptable nor contested here,
|
|
80
135
|
* because there is no tag write to refuse.
|
|
81
136
|
*
|
|
82
137
|
* `commands` maps a declared address to the paste-ready tagging command
|
|
83
|
-
* choudoufu printed for it, from {@link parseAdoptionCommands}
|
|
84
|
-
*
|
|
138
|
+
* choudoufu printed for it, from {@link parseAdoptionCommands}. An
|
|
139
|
+
* `adoptable[]` row carries its own command in the document and never needs
|
|
140
|
+
* the map; omit the map entirely when the run had no `-adoption-only` render
|
|
141
|
+
* to read one out of.
|
|
85
142
|
*/
|
|
86
143
|
export declare function readAdoptionLedger(document: unknown, commands?: ReadonlyMap<string, string>): AdoptionLedger;
|
|
87
144
|
/**
|
|
@@ -100,6 +157,17 @@ export declare function readAdoptionLedger(document: unknown, commands?: Readonl
|
|
|
100
157
|
* choudoufu already wrote.
|
|
101
158
|
*
|
|
102
159
|
* An address the render offered no command for is simply absent from the map.
|
|
160
|
+
*
|
|
161
|
+
* ## Which caller still needs this (#2241)
|
|
162
|
+
*
|
|
163
|
+
* One: the `unowned[]` half of {@link readAdoptionLedger}. choudoufu's
|
|
164
|
+
* `views.StatelessUnowned` has no command field, so a live resource found at
|
|
165
|
+
* an identity the configuration declares still gets its paste-ready command
|
|
166
|
+
* from the human render and from nowhere else. The `adoptable[]` half no
|
|
167
|
+
* longer reads a line of text: those rows carry `adopt_command` in the
|
|
168
|
+
* document itself since v0.15.0 (choudoufu #962), which is what made the
|
|
169
|
+
* adopt path stop resting on two regexes over a render nobody promised to
|
|
170
|
+
* keep stable.
|
|
103
171
|
*/
|
|
104
172
|
export declare function parseAdoptionCommands(ledgerText: string): Map<string, string>;
|
|
105
173
|
/**
|
|
@@ -109,10 +177,17 @@ export declare function parseAdoptionCommands(ledgerText: string): Map<string, s
|
|
|
109
177
|
* One line per adoptable match, naming the declared address, the live resource
|
|
110
178
|
* it binds, and the two tag values that adopt it, in the token forms
|
|
111
179
|
* `-adoption-only` prints them in (`<addr> <- <type> <identity>`,
|
|
112
|
-
* `tofu-estate=`, `tofu-address=`).
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
180
|
+
* `tofu-estate=`, `tofu-address=`). A content match adds the arguments it
|
|
181
|
+
* rested on under its row, in the same `matched on:` form the human render
|
|
182
|
+
* uses, because "these two agreed on this cidr" is the whole evidence for a
|
|
183
|
+
* match nobody read an identity for. Contested addresses follow, listed and
|
|
184
|
+
* not offered.
|
|
185
|
+
*
|
|
186
|
+
* An empty ledger still renders a line: "nothing adoptable" is a result a
|
|
187
|
+
* reader wants, and a section that vanishes reads as one that was never
|
|
188
|
+
* computed. Which of the two empties it is comes from `swept`: a run that
|
|
189
|
+
* asked no estate-wide sweep found nothing because it did not look, and
|
|
190
|
+
* saying so is the difference between a report and a silence.
|
|
116
191
|
*/
|
|
117
192
|
export declare function renderAdoptionLedger(ledger: AdoptionLedger, estate?: string): string;
|
|
118
193
|
//# sourceMappingURL=adoption.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adoption.d.ts","sourceRoot":"","sources":["../../src/op/adoption.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adoption.d.ts","sourceRoot":"","sources":["../../src/op/adoption.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AAEH,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;CACf;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,kGAAkG;IAClG,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;IACrB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,CAAC;IACtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B;;;;;OAKG;IACH,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,0DAA0D;IAC1D,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAsCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,cAAc,CA2D5G;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAoB7E;AAID;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CA0DpF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-terraform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.61.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
},
|
|
57
57
|
"peerDependencies": {
|
|
58
58
|
"zod": "^4.3.6",
|
|
59
|
-
"@intentius/chant": "^0.
|
|
59
|
+
"@intentius/chant": "^0.61.0",
|
|
60
60
|
"typescript": "^5.9.3"
|
|
61
61
|
},
|
|
62
62
|
"description": "terraform lexicon for chant, existing Terraform root modules as declarable entities",
|
|
@@ -16,12 +16,14 @@ and stays where it is.
|
|
|
16
16
|
|
|
17
17
|
## The binary and the emulator these rows name
|
|
18
18
|
|
|
19
|
-
`choudoufu v0.
|
|
20
|
-
build: `gh release download v0.
|
|
21
|
-
'choudoufu_v0.
|
|
22
|
-
`SHA256SUMS` (`
|
|
23
|
-
extracted and put first on PATH. `choudoufu version` prints `choudoufu v0.
|
|
24
|
-
(based on OpenTofu v1.13.0-dev)`.
|
|
19
|
+
`choudoufu v0.15.0` below means the published release binary, not a source
|
|
20
|
+
build: `gh release download v0.15.0 -R INTENTIUS/choudoufu -p
|
|
21
|
+
'choudoufu_v0.15.0_darwin_arm64.tar.gz' -p SHA256SUMS`, verified against
|
|
22
|
+
`SHA256SUMS` (`db29573cb7d8dfa7205eeaecc0e4bcf154e941b8bb8179fb93ad53ac5c959409`),
|
|
23
|
+
extracted and put first on PATH. `choudoufu version` prints `choudoufu v0.15.0
|
|
24
|
+
(based on OpenTofu v1.13.0-dev)`. A row that still names `v0.14.0` means the
|
|
25
|
+
same recipe one tag back
|
|
26
|
+
(`41c705d9b5fec47100c4f2fb9ab0694f0160b31a4e0661e877b4d9821bc464e3`).
|
|
25
27
|
|
|
26
28
|
`the pinned floci emulator` means choudoufu's own smoke stack image,
|
|
27
29
|
`ghcr.io/lex00/floci@sha256:a39185cc3971d0188663d61043cb038dff1260d8a975b1aa72c4e2bb1feac3cb`
|
|
@@ -47,10 +49,11 @@ resolvable).
|
|
|
47
49
|
npx vitest run lexicons/terraform/src/composites/terraform-apply-op.acceptance.test.ts
|
|
48
50
|
```
|
|
49
51
|
|
|
50
|
-
Last passed: 2026-09-
|
|
52
|
+
Last passed: 2026-09-08, `Terraform v1.15.8` on `darwin_arm64`, with
|
|
51
53
|
`hashicorp/null` resolved from the public registry for the fixture's `~> 3.2`
|
|
52
|
-
constraint. No emulator is involved. Re-run by chant #
|
|
53
|
-
|
|
54
|
+
constraint. No emulator is involved. Re-run by chant #2241 alongside every
|
|
55
|
+
other block in this file, so all four rows come from one run; #2168 had run it
|
|
56
|
+
on 2026-09-07 the same way.
|
|
54
57
|
|
|
55
58
|
### 2. `TerraformApplyOp applies a live root against choudoufu's emulator`
|
|
56
59
|
|
|
@@ -63,21 +66,22 @@ carrying choudoufu's own message rather than as thrown errors, then applies
|
|
|
63
66
|
the same file once the world is restored.
|
|
64
67
|
|
|
65
68
|
Gated on a `choudoufu` on PATH, on it reporting a release version at or above
|
|
66
|
-
`MIN_CHOUDOUFU_VERSION` (0.
|
|
67
|
-
gated on choudoufu #894 and never was: the
|
|
68
|
-
-out` path and reads no JSON document.
|
|
69
|
+
`MIN_CHOUDOUFU_VERSION` (0.15.0 since chant #2241), and on
|
|
70
|
+
`CHOUDOUFU_EMULATOR_ENDPOINT`. Not gated on choudoufu #894 and never was: the
|
|
71
|
+
plan half here is the stock `plan -out` path and reads no JSON document.
|
|
69
72
|
|
|
70
73
|
```
|
|
71
74
|
npx vitest run lexicons/terraform/src/composites/terraform-apply-op.acceptance.test.ts
|
|
72
75
|
```
|
|
73
76
|
|
|
74
|
-
Last passed: 2026-09-
|
|
75
|
-
recorded by chant #
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
Last passed: 2026-09-08, choudoufu v0.15.0 with the pinned floci emulator up,
|
|
78
|
+
recorded by chant #2241; before that 2026-09-07 on v0.14.0, recorded by chant
|
|
79
|
+
#2168. Both runs are reproducible from this file: the binary is a release
|
|
80
|
+
asset and the emulator is a pinned digest. Before them, the only record was PR
|
|
81
|
+
#2157's prose ("the acceptance suite 3 passed against v0.13.0 with the
|
|
82
|
+
emulator up", merged at `81200b5d97c15920619de4b109c4393ec3223720`), which
|
|
83
|
+
#2220 could not reproduce because no binary existed on the machine that wrote
|
|
84
|
+
this file.
|
|
81
85
|
|
|
82
86
|
### 3. `choudoufu live-check and live-plan against the fixture`
|
|
83
87
|
|
|
@@ -94,12 +98,12 @@ PATH is gone.
|
|
|
94
98
|
npx vitest run lexicons/terraform/src/op/activities/choudoufu.acceptance.test.ts
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
Last passed: 2026-09-
|
|
98
|
-
recorded by chant #
|
|
99
|
-
|
|
100
|
-
gated shut on choudoufu #894
|
|
101
|
-
before that gate, PR #2135's body
|
|
102
|
-
`live-check` half only.
|
|
101
|
+
Last passed: 2026-09-08, choudoufu v0.15.0 with the pinned floci emulator up,
|
|
102
|
+
recorded by chant #2241; before that 2026-09-07 on v0.14.0, recorded by chant
|
|
103
|
+
#2168, which was the first pass this block ever had as a suite and the first
|
|
104
|
+
the `live-plan` test ever had at all. It had been gated shut on choudoufu #894
|
|
105
|
+
since commit `65821d76` (2026-09-06 12:45Z); before that gate, PR #2135's body
|
|
106
|
+
records a hand verification of the `live-check` half only.
|
|
103
107
|
|
|
104
108
|
Two chant-side changes in #2168 were what the pass needed, both consequences
|
|
105
109
|
of what choudoufu PR 915 shipped. `-estate` is still refused beside a declared
|
|
@@ -112,51 +116,59 @@ first real run of this block found.
|
|
|
112
116
|
### 4. `TerraformAdoptOp adopts an unmarked live resource`
|
|
113
117
|
|
|
114
118
|
`composites/terraform-adopt-op.acceptance.test.ts`. One test: create an
|
|
115
|
-
unmarked VPC directly against the emulator
|
|
116
|
-
|
|
117
|
-
Ledger step and expect exactly one
|
|
118
|
-
values, run the Adopt step and let it
|
|
119
|
-
estate to own the same VPC with
|
|
119
|
+
unmarked VPC directly against the emulator at the cidr the `live-adopt/` root
|
|
120
|
+
declares, so it is a live resource this estate does not own and the sweep can
|
|
121
|
+
match to a declaration by content, run the Ledger step and expect exactly one
|
|
122
|
+
adoptable match carrying the two marker values, run the Adopt step and let it
|
|
123
|
+
write them, then re-plan and expect the estate to own the same VPC with
|
|
124
|
+
nothing left adoptable.
|
|
120
125
|
|
|
121
126
|
Gated on a `choudoufu` on PATH, on an `aws` CLI on PATH (the unmarked
|
|
122
|
-
resource is created and adopted through it), on
|
|
123
|
-
`CHOUDOUFU_EMULATOR_ENDPOINT
|
|
124
|
-
`CHOUDOUFU_ADOPTABLE_NOT_IN_DOCUMENT
|
|
125
|
-
|
|
127
|
+
resource is created and adopted through it), and on
|
|
128
|
+
`CHOUDOUFU_EMULATOR_ENDPOINT`. Those three and nothing else since chant
|
|
129
|
+
#2241: the `CHOUDOUFU_ADOPTABLE_NOT_IN_DOCUMENT` constant that named choudoufu
|
|
130
|
+
#962, and the #894 gate before it, are both gone.
|
|
126
131
|
|
|
127
132
|
```
|
|
128
133
|
npx vitest run lexicons/terraform/src/composites/terraform-adopt-op.acceptance.test.ts
|
|
129
134
|
```
|
|
130
135
|
|
|
131
|
-
Last passed:
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
136
|
+
Last passed: 2026-09-08, choudoufu v0.15.0 with the pinned floci emulator up,
|
|
137
|
+
recorded by chant #2241. **That is the first time this block has ever passed,
|
|
138
|
+
on any binary.**
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
✓ TerraformAdoptOp adopts an unmarked live resource > ledgers one adoptable
|
|
142
|
+
VPC, writes its two markers, and re-plans with it owned 18614ms
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
What it needed was choudoufu PR 963, released in v0.15.0. `live-plan -json`'s
|
|
146
|
+
document now carries the estate-wide sweep's content matches as an
|
|
147
|
+
`adoptable[]` section, with `swept[]` beside it, and each row carries the two
|
|
148
|
+
marker values, the arguments the match rested on, and the tagging command that
|
|
149
|
+
writes them. Before that the match existed only in the human `-adoption-only`
|
|
150
|
+
render, which choudoufu refuses alongside `-json`, so an `aws_vpc` (EC2
|
|
151
|
+
assigns the id, so no argument in the block determines it) reached
|
|
152
|
+
`omissions[].reason = "NEEDS_DISCOVERY"` and never `unowned[]`, and
|
|
153
|
+
`ledger.adoptions` came back empty:
|
|
135
154
|
|
|
136
155
|
```
|
|
137
156
|
AssertionError: expected [] to have a length of 1 but got +0
|
|
138
157
|
❯ terraform-adopt-op.acceptance.test.ts:116:34
|
|
139
158
|
```
|
|
140
159
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
human render's "Adoptable" section, for which `views.LivePlanDocument` has no
|
|
150
|
-
field. `-adoption-only` is refused alongside `-json`, and
|
|
151
|
-
`TOFU_LIVE_COLLECT_UNCLAIMED=1` on the `-json` run leaves `"unowned": []`
|
|
152
|
-
while the text run beside it prints `Adoptable: 1 live resource matches a
|
|
153
|
-
declared resource`. Filed upstream as choudoufu #962
|
|
154
|
-
(https://github.com/INTENTIUS/choudoufu/issues/962), which carries the full
|
|
155
|
-
measurement; chant #2168 has the same.
|
|
160
|
+
That was chant #2168's measurement on 2026-09-07 against v0.14.0, filed
|
|
161
|
+
upstream as choudoufu #962
|
|
162
|
+
(https://github.com/INTENTIUS/choudoufu/issues/962), which carries the whole
|
|
163
|
+
of it. Two chant-side changes in #2241 were what the pass needed on top of the
|
|
164
|
+
release: `choudoufuLivePlan` puts `TOFU_LIVE_COLLECT_UNCLAIMED=1` on the
|
|
165
|
+
`-json` run under `adoptionOnly`, because a `-json` run asks no estate-wide
|
|
166
|
+
sweep of its own and the section is empty without one; and
|
|
167
|
+
`readAdoptionLedger` reads both `unowned[]` and `adoptable[]` into one ledger.
|
|
156
168
|
|
|
157
169
|
The fixture was deliberately left as an `aws_vpc`. A log group would make the
|
|
158
|
-
block pass and would stop it proving the content-matcher
|
|
159
|
-
only thing it exists to prove.
|
|
170
|
+
block pass off `unowned[]` alone and would stop it proving the content-matcher
|
|
171
|
+
path, which is the only thing it exists to prove.
|
|
160
172
|
|
|
161
173
|
## Running everything that can run on a machine with no choudoufu
|
|
162
174
|
|
|
@@ -169,9 +181,31 @@ npx vitest run \
|
|
|
169
181
|
|
|
170
182
|
With `terraform` on PATH and the registry reachable, that is 1 passed and 5
|
|
171
183
|
skipped, and each skip names its own reason in the block title. With
|
|
172
|
-
choudoufu v0.
|
|
173
|
-
and
|
|
174
|
-
printed.
|
|
184
|
+
choudoufu v0.15.0, the `aws` CLI and the emulator all present, it is 6 passed
|
|
185
|
+
and 0 skipped: no block in this file skips any more. On 2026-09-08 that is
|
|
186
|
+
exactly what it printed.
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
Test Files 3 passed (3)
|
|
190
|
+
Tests 6 passed (6)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Bring the emulator up on a fixed port from choudoufu's own compose file rather
|
|
194
|
+
than through `just smoke`, which runs one scenario and tears the stack down
|
|
195
|
+
again:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
cd <choudoufu checkout>
|
|
199
|
+
FLOCI_IMAGE="$(cat live/floci-image)" FLOCI_PORT=4660 \
|
|
200
|
+
OPENTOFU_IMAGE=unused SMOKE_WORK=/tmp \
|
|
201
|
+
docker compose -p chant-acceptance -f live/smoke/docker-compose.yml up -d floci
|
|
202
|
+
export CHOUDOUFU_EMULATOR_ENDPOINT=http://localhost:4660
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Each run wants a fresh emulator: the adopt block creates an unmarked VPC at a
|
|
206
|
+
fixed cidr, and a second one left over from an earlier run is a contested
|
|
207
|
+
address rather than an adoptable match, which is a real refusal and not a
|
|
208
|
+
flake. `docker compose -p chant-acceptance ... down -v` between runs.
|
|
175
209
|
|
|
176
210
|
## Keeping this file honest
|
|
177
211
|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# graph-roots
|
|
2
|
+
|
|
3
|
+
Two root modules with real references between their blocks, for the graph-IR
|
|
4
|
+
edge and grouping tests (chant #2265, #2266).
|
|
5
|
+
|
|
6
|
+
Everything the two issues asked to have pinned by a test rather than by prose
|
|
7
|
+
is here exactly once:
|
|
8
|
+
|
|
9
|
+
- every reference form that becomes an edge: `resource`, `data`, `module`,
|
|
10
|
+
`var` and `local`
|
|
11
|
+
- a `depends_on`, which is an edge with no attribute
|
|
12
|
+
- a `count` block, which stays ONE node and one edge per target
|
|
13
|
+
- a local child module, so a reference resolves inside the child's own scope
|
|
14
|
+
and never against the root's
|
|
15
|
+
- a `provider = aws.replica` meta-argument, which is deliberately NOT an edge
|
|
16
|
+
- two roots that share nothing, which is what a cross-root edge would have to
|
|
17
|
+
invent
|
|
18
|
+
|
|
19
|
+
`app` reads a policy by NAME through a data source rather than by reference,
|
|
20
|
+
which is how the estate these issues were filed against composes its roots.
|
|
21
|
+
No edge should appear between the two roots because of it.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
variable "region" {
|
|
2
|
+
type = string
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
variable "subnets" {
|
|
6
|
+
type = list(string)
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
provider "aws" {
|
|
10
|
+
alias = "replica"
|
|
11
|
+
region = var.region
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
data "aws_iam_policy" "boundary" {
|
|
15
|
+
name = "waterpark-boundary"
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
resource "aws_s3_bucket" "assets" {
|
|
19
|
+
provider = aws.replica
|
|
20
|
+
bucket = "app-assets"
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
module "cdn" {
|
|
24
|
+
source = "./modules/cdn"
|
|
25
|
+
|
|
26
|
+
bucket = aws_s3_bucket.assets.id
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
resource "aws_instance" "web" {
|
|
30
|
+
count = length(var.subnets)
|
|
31
|
+
subnet_id = var.subnets[count.index]
|
|
32
|
+
depends_on = [aws_s3_bucket.assets, module.cdn]
|
|
33
|
+
|
|
34
|
+
tags = {
|
|
35
|
+
boundary = data.aws_iam_policy.boundary.arn
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
output "cdn_url" {
|
|
40
|
+
value = module.cdn.url
|
|
41
|
+
}
|