@intentius/chant-lexicon-terraform 0.124.44 → 0.124.46
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/__fixtures__/capabilities/chant.config.d.ts +26 -0
- package/dist/__fixtures__/capabilities/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/capabilities/chant.config.js +13 -0
- package/dist/__fixtures__/effective-topology/chant.config.d.ts +13 -0
- package/dist/__fixtures__/effective-topology/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/effective-topology/chant.config.js +9 -0
- package/dist/__fixtures__/kind-type/chant.config.d.ts +13 -0
- package/dist/__fixtures__/kind-type/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/kind-type/chant.config.js +9 -0
- package/dist/__fixtures__/search-roots/chant.config.d.ts +13 -0
- package/dist/__fixtures__/search-roots/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/search-roots/chant.config.js +9 -0
- package/dist/__fixtures__/sensitive-default/chant.config.d.ts +13 -0
- package/dist/__fixtures__/sensitive-default/chant.config.d.ts.map +1 -0
- package/dist/__fixtures__/sensitive-default/chant.config.js +9 -0
- package/dist/capabilities/adapter.d.ts +9 -0
- package/dist/capabilities/adapter.d.ts.map +1 -0
- package/dist/capabilities/adapter.js +25 -0
- package/dist/capabilities/mapping.json +166 -0
- package/dist/config.d.ts +52 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -0
- package/dist/describe-resources.d.ts +101 -8
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +395 -56
- package/dist/hcl/parse.d.ts +10 -0
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +20 -2
- package/dist/hcl/redact.d.ts +26 -0
- package/dist/hcl/redact.d.ts.map +1 -0
- package/dist/hcl/redact.js +228 -0
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/terraform.d.ts +109 -4
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +148 -7
- package/dist/plan-observation.d.ts +153 -0
- package/dist/plan-observation.d.ts.map +1 -0
- package/dist/plan-observation.js +354 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/package.json +2 -2
- package/src/__fixtures__/ACCEPTANCE.md +53 -1
- package/src/__fixtures__/capabilities/catalog/main.tf +105 -0
- package/src/__fixtures__/capabilities/chant.config.ts +15 -0
- package/src/__fixtures__/capabilities/findings/main.tf +225 -0
- package/src/__fixtures__/capabilities/ledger/main.tf +265 -0
- package/src/__fixtures__/capabilities/package.json +1 -0
- package/src/__fixtures__/effective-topology/chant.config.ts +11 -0
- package/src/__fixtures__/effective-topology/net/main.tf +176 -0
- package/src/__fixtures__/effective-topology/package.json +6 -0
- package/src/__fixtures__/kind-type/app/main.tf +35 -0
- package/src/__fixtures__/kind-type/chant.config.ts +11 -0
- package/src/__fixtures__/kind-type/package.json +6 -0
- package/src/__fixtures__/live-plan-depth/README.md +59 -0
- package/src/__fixtures__/live-plan-depth/live-plan.json +110 -0
- package/src/__fixtures__/live-plan-depth/show-plan-sensitive.json +1 -0
- package/src/__fixtures__/live-plan-depth/show-plan.json +1 -0
- package/src/__fixtures__/plan-read/main.tf +46 -0
- package/src/__fixtures__/plan-read/next.tfvars +1 -0
- package/src/__fixtures__/plan-read-drift/README.md +33 -0
- package/src/__fixtures__/plan-read-drift/main.tf +63 -0
- package/src/__fixtures__/plan-read-drift/next.tfvars +1 -0
- package/src/__fixtures__/search-roots/chant.config.ts +11 -0
- package/src/__fixtures__/search-roots/net/main.tf +73 -0
- package/src/__fixtures__/search-roots/package.json +6 -0
- package/src/__fixtures__/sensitive-default/chant.config.ts +11 -0
- package/src/__fixtures__/sensitive-default/net/main.tf +38 -0
- package/src/__fixtures__/sensitive-default/package.json +6 -0
- package/src/__fixtures__/show-plan.json +663 -0
- package/src/capabilities/adapter.ts +32 -0
- package/src/capabilities/mapping.json +166 -0
- package/src/capabilities-workspace.e2e.test.ts +251 -0
- package/src/capabilities.test.ts +264 -0
- package/src/config.ts +26 -0
- package/src/describe-resources.live-plan.test.ts +302 -0
- package/src/describe-resources.live-root-unchanged.test.ts +126 -0
- package/src/describe-resources.plan.test.ts +437 -0
- package/src/describe-resources.ts +445 -52
- package/src/effective-topology.test.ts +134 -0
- package/src/hcl/parse.ts +30 -2
- package/src/hcl/redact.ts +181 -0
- package/src/live-plan-depth.acceptance.e2e.test.ts +193 -0
- package/src/op/activities/terraform.test.ts +118 -1
- package/src/op/activities/terraform.ts +213 -9
- package/src/plan-observation.ts +428 -0
- package/src/plan-read.acceptance.test.ts +184 -0
- package/src/plugin.ts +2 -0
- package/src/redact-ir.e2e.test.ts +79 -0
- package/src/redact.test.ts +111 -0
- package/src/search-build-roots.test.ts +125 -0
- package/src/search-count.test.ts +144 -0
- package/src/search-kind-type.test.ts +136 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import "@intentius/chant-lexicon-terraform";
|
|
2
|
+
declare const _default: {
|
|
3
|
+
lexicons: string[];
|
|
4
|
+
lint: {
|
|
5
|
+
rules: {
|
|
6
|
+
TF022: "off";
|
|
7
|
+
TF030: "off";
|
|
8
|
+
TF033: "off";
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
terraform: {
|
|
12
|
+
roots: {
|
|
13
|
+
ledger: {
|
|
14
|
+
dir: string;
|
|
15
|
+
};
|
|
16
|
+
catalog: {
|
|
17
|
+
dir: string;
|
|
18
|
+
};
|
|
19
|
+
findings: {
|
|
20
|
+
dir: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
export default _default;
|
|
26
|
+
//# sourceMappingURL=chant.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chant.config.d.ts","sourceRoot":"","sources":["../../../src/__fixtures__/capabilities/chant.config.ts"],"names":[],"mappings":"AACA,OAAO,oCAAoC,CAAC;;;;;;;;;;;QAOxC,KAAK;YACH,MAAM;gBAAI,GAAG;;YACb,OAAO;gBAAI,GAAG;;YACd,QAAQ;gBAAI,GAAG"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "@intentius/chant-lexicon-terraform";
|
|
2
|
+
export default {
|
|
3
|
+
lexicons: ["terraform"],
|
|
4
|
+
// The estates hold the findings these rules report on purpose.
|
|
5
|
+
lint: { rules: { TF022: "off", TF030: "off", TF033: "off" } },
|
|
6
|
+
terraform: {
|
|
7
|
+
roots: {
|
|
8
|
+
ledger: { dir: "./ledger" },
|
|
9
|
+
catalog: { dir: "./catalog" },
|
|
10
|
+
findings: { dir: "./findings" },
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chant.config.d.ts","sourceRoot":"","sources":["../../../src/__fixtures__/effective-topology/chant.config.ts"],"names":[],"mappings":"AACA,OAAO,oCAAoC,CAAC;;;;QAKxC,KAAK;YACH,GAAG;gBAAI,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chant.config.d.ts","sourceRoot":"","sources":["../../../src/__fixtures__/kind-type/chant.config.ts"],"names":[],"mappings":"AACA,OAAO,oCAAoC,CAAC;;;;QAKxC,KAAK;YACH,GAAG;gBAAI,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chant.config.d.ts","sourceRoot":"","sources":["../../../src/__fixtures__/search-roots/chant.config.ts"],"names":[],"mappings":"AACA,OAAO,oCAAoC,CAAC;;;;QAKxC,KAAK;YACH,GAAG;gBAAI,GAAG"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chant.config.d.ts","sourceRoot":"","sources":["../../../src/__fixtures__/sensitive-default/chant.config.ts"],"names":[],"mappings":"AACA,OAAO,oCAAoC,CAAC;;;;QAKxC,KAAK;YACH,GAAG;gBAAI,GAAG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The terraform lexicon's capability pack (#4375): its mapping onto the
|
|
3
|
+
* lexicon-neutral view, as data, and the one thing the mapping can't say as
|
|
4
|
+
* data, how to read a policy written as `jsonencode({...})`.
|
|
5
|
+
*/
|
|
6
|
+
import type { CapabilityAdapter, CapabilityPack } from "@intentius/chant/capabilities/view";
|
|
7
|
+
export declare const terraformCapabilityAdapter: CapabilityAdapter;
|
|
8
|
+
export declare const terraformCapabilityPack: CapabilityPack;
|
|
9
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/capabilities/adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAqB,cAAc,EAAE,MAAM,oCAAoC,CAAC;AAc/G,eAAO,MAAM,0BAA0B,EAAE,iBAOxC,CAAC;AAEF,eAAO,MAAM,uBAAuB,EAAE,cAGrC,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import mapping from "./mapping.json" with { type: "json" };
|
|
2
|
+
import { isUnknown, readJsonencode } from "../hcl/jsonencode.js";
|
|
3
|
+
/** Turn each value position `readJsonencode` couldn't read into its expression, as `${...}` text. */
|
|
4
|
+
function withExpressions(v) {
|
|
5
|
+
if (isUnknown(v))
|
|
6
|
+
return v.source !== undefined ? `\${${v.source}}` : undefined;
|
|
7
|
+
if (Array.isArray(v))
|
|
8
|
+
return v.map(withExpressions);
|
|
9
|
+
if (v && typeof v === "object") {
|
|
10
|
+
return Object.fromEntries(Object.entries(v).map(([k, x]) => [k, withExpressions(x)]));
|
|
11
|
+
}
|
|
12
|
+
return v;
|
|
13
|
+
}
|
|
14
|
+
export const terraformCapabilityAdapter = {
|
|
15
|
+
readDocument(value) {
|
|
16
|
+
// An inline_policy block carries the document in its `policy` argument.
|
|
17
|
+
const raw = value && typeof value === "object" && !Array.isArray(value) ? value.policy : value;
|
|
18
|
+
const read = readJsonencode(raw, { unknownLeaves: true });
|
|
19
|
+
return read.kind === "literal" ? withExpressions(read.value) : undefined;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
export const terraformCapabilityPack = {
|
|
23
|
+
mapping: mapping,
|
|
24
|
+
adapter: terraformCapabilityAdapter,
|
|
25
|
+
};
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lexicon": "terraform",
|
|
3
|
+
"types": "terraform",
|
|
4
|
+
"body": "body",
|
|
5
|
+
"refs": "terraform",
|
|
6
|
+
"labels": {
|
|
7
|
+
"aws_vpc": "Vpc",
|
|
8
|
+
"aws_default_vpc": {
|
|
9
|
+
"label": "Vpc",
|
|
10
|
+
"set": {
|
|
11
|
+
"isDefault": true
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"aws_default_security_group": "SecurityGroup",
|
|
15
|
+
"aws_network_interface": "NetworkInterface",
|
|
16
|
+
"aws_ebs_volume": "Volume",
|
|
17
|
+
"aws_lambda_function": "Function",
|
|
18
|
+
"aws_lambda_function_url": "FunctionUrl",
|
|
19
|
+
"aws_iam_instance_profile": "InstanceProfile",
|
|
20
|
+
"aws_iam_role": "Role",
|
|
21
|
+
"aws_iam_policy": "Policy",
|
|
22
|
+
"aws_iam_role_policy": "Policy",
|
|
23
|
+
"aws_iam_role_policy_attachment": "PolicyAttachment",
|
|
24
|
+
"aws_s3_bucket_policy": "ResourcePolicy",
|
|
25
|
+
"aws_sqs_queue_policy": "ResourcePolicy",
|
|
26
|
+
"aws_s3_bucket": "Bucket",
|
|
27
|
+
"aws_s3_bucket_public_access_block": "PublicAccessBlock",
|
|
28
|
+
"aws_dynamodb_table": "Table",
|
|
29
|
+
"aws_db_instance": "Database",
|
|
30
|
+
"aws_rds_cluster": "Database",
|
|
31
|
+
"aws_secretsmanager_secret": "Secret",
|
|
32
|
+
"aws_sqs_queue": "Queue",
|
|
33
|
+
"aws_efs_file_system": "FileSystem",
|
|
34
|
+
"aws_ssm_parameter": "Parameter",
|
|
35
|
+
"aws_ecs_service": "Service",
|
|
36
|
+
"aws_ecs_task_definition": "TaskDefinition",
|
|
37
|
+
"aws_db_subnet_group": "SubnetGroup",
|
|
38
|
+
"aws_nat_gateway": "NatGateway",
|
|
39
|
+
"aws_lb": "LoadBalancer",
|
|
40
|
+
"aws_alb": "LoadBalancer"
|
|
41
|
+
},
|
|
42
|
+
"edges": {
|
|
43
|
+
"Instance": {
|
|
44
|
+
"iam_instance_profile": "profile"
|
|
45
|
+
},
|
|
46
|
+
"LaunchTemplate": {
|
|
47
|
+
"iam_instance_profile": "profile"
|
|
48
|
+
},
|
|
49
|
+
"Subnet": {
|
|
50
|
+
"vpc_id": "vpc"
|
|
51
|
+
},
|
|
52
|
+
"SecurityGroup": {
|
|
53
|
+
"vpc_id": "vpc"
|
|
54
|
+
},
|
|
55
|
+
"NetworkInterface": {
|
|
56
|
+
"subnet_id": "subnet",
|
|
57
|
+
"security_groups": "sg"
|
|
58
|
+
},
|
|
59
|
+
"Database": {
|
|
60
|
+
"vpc_security_group_ids": "sg",
|
|
61
|
+
"db_subnet_group_name": "subnetGroup"
|
|
62
|
+
},
|
|
63
|
+
"Function": {
|
|
64
|
+
"role": "role",
|
|
65
|
+
"vpc_config": {
|
|
66
|
+
"SecurityGroup": "sg",
|
|
67
|
+
"Subnet": "subnet"
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"FunctionUrl": {
|
|
71
|
+
"function_name": "function"
|
|
72
|
+
},
|
|
73
|
+
"InstanceProfile": {
|
|
74
|
+
"role": "role"
|
|
75
|
+
},
|
|
76
|
+
"Policy": {
|
|
77
|
+
"role": "attachedTo"
|
|
78
|
+
},
|
|
79
|
+
"PolicyAttachment": {
|
|
80
|
+
"role": "role",
|
|
81
|
+
"policy_arn": "policy"
|
|
82
|
+
},
|
|
83
|
+
"ResourcePolicy": {
|
|
84
|
+
"bucket": "policyOf",
|
|
85
|
+
"queue_url": "policyOf"
|
|
86
|
+
},
|
|
87
|
+
"PublicAccessBlock": {
|
|
88
|
+
"bucket": "blocks"
|
|
89
|
+
},
|
|
90
|
+
"Service": {
|
|
91
|
+
"task_definition": "task",
|
|
92
|
+
"network_configuration": {
|
|
93
|
+
"SecurityGroup": "sg",
|
|
94
|
+
"Subnet": "subnet"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"TaskDefinition": {
|
|
98
|
+
"task_role_arn": "role"
|
|
99
|
+
},
|
|
100
|
+
"SubnetGroup": {
|
|
101
|
+
"subnet_ids": "subnet"
|
|
102
|
+
},
|
|
103
|
+
"NatGateway": {
|
|
104
|
+
"subnet_id": "subnet"
|
|
105
|
+
},
|
|
106
|
+
"LoadBalancer": {
|
|
107
|
+
"subnets": "subnet",
|
|
108
|
+
"security_groups": "sg"
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"links": {
|
|
112
|
+
"PolicyAttachment": {
|
|
113
|
+
"from": "policy",
|
|
114
|
+
"to": "role",
|
|
115
|
+
"edge": "attachedTo"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"attrs": {
|
|
119
|
+
"FunctionUrl": {
|
|
120
|
+
"authType": "authorization_type"
|
|
121
|
+
},
|
|
122
|
+
"Role": {
|
|
123
|
+
"name": "name"
|
|
124
|
+
},
|
|
125
|
+
"Bucket": {
|
|
126
|
+
"name": "bucket",
|
|
127
|
+
"acl": "acl"
|
|
128
|
+
},
|
|
129
|
+
"PublicAccessBlock": {
|
|
130
|
+
"blockPublicPolicy": "block_public_policy"
|
|
131
|
+
},
|
|
132
|
+
"Table": {
|
|
133
|
+
"name": "name"
|
|
134
|
+
},
|
|
135
|
+
"Database": {
|
|
136
|
+
"encrypted": "storage_encrypted"
|
|
137
|
+
},
|
|
138
|
+
"FileSystem": {
|
|
139
|
+
"encrypted": "encrypted"
|
|
140
|
+
},
|
|
141
|
+
"Volume": {
|
|
142
|
+
"encrypted": "encrypted"
|
|
143
|
+
},
|
|
144
|
+
"Parameter": {
|
|
145
|
+
"paramType": "type"
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
"documents": {
|
|
149
|
+
"Role": {
|
|
150
|
+
"assume_role_policy": "trust",
|
|
151
|
+
"inline_policy[].policy": "permission"
|
|
152
|
+
},
|
|
153
|
+
"Policy": {
|
|
154
|
+
"policy": "permission"
|
|
155
|
+
},
|
|
156
|
+
"ResourcePolicy": {
|
|
157
|
+
"policy": "resource"
|
|
158
|
+
}
|
|
159
|
+
},
|
|
160
|
+
"tags": [
|
|
161
|
+
"tags"
|
|
162
|
+
],
|
|
163
|
+
"classificationTags": [
|
|
164
|
+
"data-classification"
|
|
165
|
+
]
|
|
166
|
+
}
|
package/dist/config.d.ts
CHANGED
|
@@ -49,6 +49,15 @@ export type TerraformDeleteMode = z.infer<typeof terraformDeleteModeSchema>;
|
|
|
49
49
|
* strict, and a root entry is exactly where a typo (`varfiles`) would
|
|
50
50
|
* otherwise land silently.
|
|
51
51
|
*/
|
|
52
|
+
/**
|
|
53
|
+
* How deep a root is observed (#4358): `"state"` reads state, `"plan"`
|
|
54
|
+
* reads a saved plan. See {@link TerraformRootConfig.observe}.
|
|
55
|
+
*/
|
|
56
|
+
export declare const terraformObserveDepthSchema: z.ZodEnum<{
|
|
57
|
+
plan: "plan";
|
|
58
|
+
state: "state";
|
|
59
|
+
}>;
|
|
60
|
+
export type TerraformObserveDepth = z.infer<typeof terraformObserveDepthSchema>;
|
|
52
61
|
export declare const terraformRootSchema: z.ZodObject<{
|
|
53
62
|
/** Root module directory, relative to the project root (where `chant.config.*` lives). */
|
|
54
63
|
dir: z.ZodString;
|
|
@@ -90,6 +99,25 @@ export declare const terraformRootSchema: z.ZodObject<{
|
|
|
90
99
|
never: "never";
|
|
91
100
|
"owned-only": "owned-only";
|
|
92
101
|
}>>;
|
|
102
|
+
/**
|
|
103
|
+
* How deep `describeResources` reads this root (#4358). `"state"`, the
|
|
104
|
+
* default, is `terraform show -json` over state: what the last apply
|
|
105
|
+
* recorded. `"plan"` is a saved plan, `plan -lock=false -out=<tmp>` then
|
|
106
|
+
* `show -json`: what the next apply would do, with replace reasons,
|
|
107
|
+
* values unknown until apply and drift. It needs provider credentials and
|
|
108
|
+
* an initialised root, and falls back to the state read, then to declared
|
|
109
|
+
* only, saying which read answered. A live choudoufu root keeps its
|
|
110
|
+
* `live-plan -json` read for ownership at either depth; at `"plan"` the
|
|
111
|
+
* plan read runs beside it and its attributes go on the blocks `live-plan`
|
|
112
|
+
* bound (#4371).
|
|
113
|
+
*
|
|
114
|
+
* The `CHANT_TERRAFORM_OBSERVE` environment variable overrides it for
|
|
115
|
+
* every root, for one run.
|
|
116
|
+
*/
|
|
117
|
+
observe: z.ZodOptional<z.ZodEnum<{
|
|
118
|
+
plan: "plan";
|
|
119
|
+
state: "state";
|
|
120
|
+
}>>;
|
|
93
121
|
}, z.core.$strict>;
|
|
94
122
|
export declare const terraformConfigSchema: z.ZodObject<{
|
|
95
123
|
/**
|
|
@@ -131,6 +159,11 @@ export declare const terraformConfigSchema: z.ZodObject<{
|
|
|
131
159
|
* project does not own.
|
|
132
160
|
*/
|
|
133
161
|
moduleRoot: z.ZodOptional<z.ZodString>;
|
|
162
|
+
/** The default {@link TerraformRootConfig.observe} for every root that sets none (#4358). */
|
|
163
|
+
observe: z.ZodOptional<z.ZodEnum<{
|
|
164
|
+
plan: "plan";
|
|
165
|
+
state: "state";
|
|
166
|
+
}>>;
|
|
134
167
|
/** Named root modules. The name is the entity-key prefix, so keep it stable. */
|
|
135
168
|
roots: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
136
169
|
/** Root module directory, relative to the project root (where `chant.config.*` lives). */
|
|
@@ -173,6 +206,25 @@ export declare const terraformConfigSchema: z.ZodObject<{
|
|
|
173
206
|
never: "never";
|
|
174
207
|
"owned-only": "owned-only";
|
|
175
208
|
}>>;
|
|
209
|
+
/**
|
|
210
|
+
* How deep `describeResources` reads this root (#4358). `"state"`, the
|
|
211
|
+
* default, is `terraform show -json` over state: what the last apply
|
|
212
|
+
* recorded. `"plan"` is a saved plan, `plan -lock=false -out=<tmp>` then
|
|
213
|
+
* `show -json`: what the next apply would do, with replace reasons,
|
|
214
|
+
* values unknown until apply and drift. It needs provider credentials and
|
|
215
|
+
* an initialised root, and falls back to the state read, then to declared
|
|
216
|
+
* only, saying which read answered. A live choudoufu root keeps its
|
|
217
|
+
* `live-plan -json` read for ownership at either depth; at `"plan"` the
|
|
218
|
+
* plan read runs beside it and its attributes go on the blocks `live-plan`
|
|
219
|
+
* bound (#4371).
|
|
220
|
+
*
|
|
221
|
+
* The `CHANT_TERRAFORM_OBSERVE` environment variable overrides it for
|
|
222
|
+
* every root, for one run.
|
|
223
|
+
*/
|
|
224
|
+
observe: z.ZodOptional<z.ZodEnum<{
|
|
225
|
+
plan: "plan";
|
|
226
|
+
state: "state";
|
|
227
|
+
}>>;
|
|
176
228
|
}, z.core.$strict>>;
|
|
177
229
|
}, z.core.$strict>;
|
|
178
230
|
export type TerraformRootConfig = z.infer<typeof terraformRootSchema>;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB;;;;EAA2C,CAAC;AAClF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB;IAC9B,0FAA0F;;IAE1F,4EAA4E;;IAE5E,0DAA0D;;IAE1D,0DAA0D;;IAE1D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;;IAEH,+EAA+E;;;;;;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAE3D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB;;;;EAA2C,CAAC;AAClF,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAE5E;;;;;;;;GAQG;AACH;;;GAGG;AACH,eAAO,MAAM,2BAA2B;;;EAA4B,CAAC;AAErE,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF,eAAO,MAAM,mBAAmB;IAC9B,0FAA0F;;IAE1F,4EAA4E;;IAE5E,0DAA0D;;IAE1D,0DAA0D;;IAE1D;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;;IAEH,+EAA+E;;;;;;IAE/E;;;;;;;;;;;;;;OAcG;;;;;kBAEH,CAAC;AAEH,eAAO,MAAM,qBAAqB;IAChC;;;;;;;OAOG;;;;;;IAEH;;;;;;;OAOG;;;;;;IAEH;;;;;;;;;;;OAWG;;IAEH,6FAA6F;;;;;IAE7F,gFAAgF;;QAxFhF,0FAA0F;;QAE1F,4EAA4E;;QAE5E,0DAA0D;;QAE1D,0DAA0D;;QAE1D;;;;;;;;;;;;;;;;;;;;;;;;WAwBG;;QAEH,+EAA+E;;;;;;QAE/E;;;;;;;;;;;;;;WAcG;;;;;;kBAwCH,CAAC;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AACtE,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE,OAAO,QAAQ,yBAAyB,CAAC;IACvC,UAAU,WAAW;QACnB,SAAS,CAAC,EAAE,eAAe,CAAC;KAC7B;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,wBAAwB,GAAG,WAAW,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -43,6 +43,11 @@ export const terraformDeleteModeSchema = z.enum(["never", "owned-only", "gated"]
|
|
|
43
43
|
* strict, and a root entry is exactly where a typo (`varfiles`) would
|
|
44
44
|
* otherwise land silently.
|
|
45
45
|
*/
|
|
46
|
+
/**
|
|
47
|
+
* How deep a root is observed (#4358): `"state"` reads state, `"plan"`
|
|
48
|
+
* reads a saved plan. See {@link TerraformRootConfig.observe}.
|
|
49
|
+
*/
|
|
50
|
+
export const terraformObserveDepthSchema = z.enum(["state", "plan"]);
|
|
46
51
|
export const terraformRootSchema = z.strictObject({
|
|
47
52
|
/** Root module directory, relative to the project root (where `chant.config.*` lives). */
|
|
48
53
|
dir: z.string(),
|
|
@@ -80,6 +85,22 @@ export const terraformRootSchema = z.strictObject({
|
|
|
80
85
|
estate: z.string().optional(),
|
|
81
86
|
/** This root's declared delete mode. See {@link terraformDeleteModeSchema}. */
|
|
82
87
|
delete: terraformDeleteModeSchema.optional(),
|
|
88
|
+
/**
|
|
89
|
+
* How deep `describeResources` reads this root (#4358). `"state"`, the
|
|
90
|
+
* default, is `terraform show -json` over state: what the last apply
|
|
91
|
+
* recorded. `"plan"` is a saved plan, `plan -lock=false -out=<tmp>` then
|
|
92
|
+
* `show -json`: what the next apply would do, with replace reasons,
|
|
93
|
+
* values unknown until apply and drift. It needs provider credentials and
|
|
94
|
+
* an initialised root, and falls back to the state read, then to declared
|
|
95
|
+
* only, saying which read answered. A live choudoufu root keeps its
|
|
96
|
+
* `live-plan -json` read for ownership at either depth; at `"plan"` the
|
|
97
|
+
* plan read runs beside it and its attributes go on the blocks `live-plan`
|
|
98
|
+
* bound (#4371).
|
|
99
|
+
*
|
|
100
|
+
* The `CHANT_TERRAFORM_OBSERVE` environment variable overrides it for
|
|
101
|
+
* every root, for one run.
|
|
102
|
+
*/
|
|
103
|
+
observe: terraformObserveDepthSchema.optional(),
|
|
83
104
|
});
|
|
84
105
|
export const terraformConfigSchema = z.strictObject({
|
|
85
106
|
/**
|
|
@@ -113,6 +134,8 @@ export const terraformConfigSchema = z.strictObject({
|
|
|
113
134
|
* project does not own.
|
|
114
135
|
*/
|
|
115
136
|
moduleRoot: z.string().optional(),
|
|
137
|
+
/** The default {@link TerraformRootConfig.observe} for every root that sets none (#4358). */
|
|
138
|
+
observe: terraformObserveDepthSchema.optional(),
|
|
116
139
|
/** Named root modules. The name is the entity-key prefix, so keep it stable. */
|
|
117
140
|
roots: z.record(z.string(), terraformRootSchema),
|
|
118
141
|
});
|
|
@@ -24,18 +24,26 @@
|
|
|
24
24
|
* is a different one.
|
|
25
25
|
*
|
|
26
26
|
* So the returned `ObservationResult` carries `sources`, keyed by chant entity
|
|
27
|
-
* name, with one of exactly
|
|
27
|
+
* name, with one of exactly four values:
|
|
28
28
|
*
|
|
29
|
-
* - `"state"
|
|
30
|
-
* - `"live"
|
|
29
|
+
* - `"state"`: this entity's root was read with `terraform show -json`.
|
|
30
|
+
* - `"live"`: this entity's root was read with `choudoufu live-plan -json`.
|
|
31
|
+
* - `"plan"`: this entity's root was read at the plan depth (#4358), a saved
|
|
32
|
+
* plan's `show -json`, which says what the next apply would do. See the
|
|
33
|
+
* plan depth section below.
|
|
34
|
+
* - `"live+plan"`: a live root at the plan depth (#4371), where both reads
|
|
35
|
+
* answered: `live-plan -json` for presence and ownership, the plan read for
|
|
36
|
+
* the attributes. A live root whose plan read failed says `"live"`.
|
|
31
37
|
*
|
|
32
38
|
* Three guarantees a consumer may rely on. Every entity `describeResources`
|
|
33
39
|
* was asked about that belongs to a root has an entry, whatever verdict it
|
|
34
40
|
* came back with: present, absent and not-observed alike, because which read
|
|
35
|
-
* was attempted is a fact independent of what it found.
|
|
36
|
-
* declared entity's own `props.mode`
|
|
37
|
-
* decides both, so `props.mode` is also a
|
|
38
|
-
* holding the declared graph and no
|
|
41
|
+
* was attempted is a fact independent of what it found. On a root read at the
|
|
42
|
+
* default depth the value equals the declared entity's own `props.mode`
|
|
43
|
+
* (`./hcl/parse.ts`), since one fact decides both, so `props.mode` is also a
|
|
44
|
+
* valid join key for a consumer holding the declared graph and no
|
|
45
|
+
* observation; the plan depth is chosen at read time, so only `sources` says
|
|
46
|
+
* it was used. And a project mixing stock
|
|
39
47
|
* and live roots gets both values in one document, which is why this is a map
|
|
40
48
|
* and not a field on the result as a whole.
|
|
41
49
|
*
|
|
@@ -144,6 +152,49 @@
|
|
|
144
152
|
* (`live-ls`'s own help text) and a listing taken right after an apply can
|
|
145
153
|
* otherwise show a resource under both its old and new estate, or neither.
|
|
146
154
|
*
|
|
155
|
+
* ## The plan depth (#4358)
|
|
156
|
+
*
|
|
157
|
+
* A stock root can be read one depth further: `terraform.observe` (or a
|
|
158
|
+
* root's own `observe`) set to `"plan"`, or `CHANT_TERRAFORM_OBSERVE=plan`,
|
|
159
|
+
* or `depth: "plan"` from a caller. The read is `terraformPlanRead`:
|
|
160
|
+
* `plan -input=false -lock=false -out=<tmp>/plan.tfplan`, then `show -json`,
|
|
161
|
+
* with `<tmp>` under the OS temp directory and removed afterwards, and no
|
|
162
|
+
* `init`. Presence and ownership come from the plan's `prior_state` by the
|
|
163
|
+
* state read's own rule; `./plan-observation.ts` adds the plan's attributes
|
|
164
|
+
* (`planAction`, `planReplacePaths`, `planAfterUnknown`, `planDrift`, ...)
|
|
165
|
+
* to each present block, with sensitive values redacted.
|
|
166
|
+
*
|
|
167
|
+
* It falls back by depth (`planAdapter`): no provider credentials -> the
|
|
168
|
+
* state read; no backend, or a root that needs `init` -> declared only. Each
|
|
169
|
+
* root gets a note saying which read answered. A planned create has no row in
|
|
170
|
+
* `prior_state` and reads absent, as on the state read, so its plan
|
|
171
|
+
* attributes have nowhere to ride.
|
|
172
|
+
*
|
|
173
|
+
* ### On a live root (#4371)
|
|
174
|
+
*
|
|
175
|
+
* `live-plan -json` carries ownership and no attribute values (behold#404),
|
|
176
|
+
* and `choudoufu plan -out` writes a stock plan file (choudoufu #878). So a
|
|
177
|
+
* live root at the plan depth runs both (`livePlanDepthAdapter`):
|
|
178
|
+
* `live-plan -json` first, unchanged, for presence and ownership, then the
|
|
179
|
+
* same `terraformPlanRead` a stock root gets, whose attributes are added to
|
|
180
|
+
* each block `live-plan` bound. A foreign or adoptable block gets none: the
|
|
181
|
+
* plan proposes a create there, which is choudoufu's answer for an instance
|
|
182
|
+
* it does not own, not a fact about the live resource. `sources` reads
|
|
183
|
+
* `"live+plan"`.
|
|
184
|
+
*
|
|
185
|
+
* choudoufu rebuilds prior state from the account on every run, so on a live
|
|
186
|
+
* root out-of-band drift is not in `resource_drift`. It is the planned
|
|
187
|
+
* `update` itself: `planChanges` has the live value as `before` and the
|
|
188
|
+
* declared one as `after`, and `planDrift` stays empty. That is where #2472's
|
|
189
|
+
* property-level drift for a live root comes from.
|
|
190
|
+
*
|
|
191
|
+
* Falling back is one step: if the plan read fails, `live-plan` alone
|
|
192
|
+
* answered, the note says why, and `sources` reads `"live"`. If `live-plan`
|
|
193
|
+
* fails the root is not observed, as at the default depth, and the plan read
|
|
194
|
+
* is not tried, since its attributes would have no present block to ride.
|
|
195
|
+
* The cost is two refreshes of the estate per read, run one after the other
|
|
196
|
+
* so they never share the root's cache file.
|
|
197
|
+
*
|
|
147
198
|
* ## Nothing from `values` is surfaced
|
|
148
199
|
*
|
|
149
200
|
* A state row's `values` are the resource's full attribute set, secrets
|
|
@@ -155,7 +206,8 @@
|
|
|
155
206
|
import type { DescribeResourcesResult, ResourceMetadata, TeardownEnumeration } from "@intentius/chant/lexicon";
|
|
156
207
|
import { type DeclaredEntity, type UnobservedReason } from "@intentius/chant/observation";
|
|
157
208
|
import type { OwnershipMarker } from "@intentius/chant/ownership";
|
|
158
|
-
import { choudoufuLiveLs, choudoufuLivePlanDocument, terraformInit, terraformShow } from "./op/activities/terraform.js";
|
|
209
|
+
import { choudoufuLiveLs, choudoufuLivePlanDocument, terraformInit, terraformPlanRead, terraformShow } from "./op/activities/terraform.js";
|
|
210
|
+
import type { TerraformObserveDepth } from "./config.js";
|
|
159
211
|
export { TERRAFORM_STATE_OWNERSHIP_KEYS } from "./state-ownership.js";
|
|
160
212
|
export { TERRAFORM_LIVE_MARKER_KEYS } from "./live-ownership.js";
|
|
161
213
|
/** One row out of `values.root_module.resources[]`, at any module depth. */
|
|
@@ -315,6 +367,26 @@ export type InstanceVerdict = {
|
|
|
315
367
|
* (choudoufu #962, chant #2241).
|
|
316
368
|
*/
|
|
317
369
|
export declare function classifyLiveInstance(address: string, index: LivePlanIndex): InstanceVerdict;
|
|
370
|
+
/**
|
|
371
|
+
* The environment variable that asks for each live root's `live-plan -json`
|
|
372
|
+
* document as a file, in a directory the caller owns (behold#924).
|
|
373
|
+
*
|
|
374
|
+
* The overlay keeps chant's verdict per block and drops the rows behind it:
|
|
375
|
+
* each instance's omission reason and detail, `identity_values`, the adoptable
|
|
376
|
+
* row's own fields. A caller that paints ownership from those rows and wants
|
|
377
|
+
* the plan's attributes from the plan depth would otherwise run its own
|
|
378
|
+
* `live-plan` beside this one, two refreshes of the estate that can disagree
|
|
379
|
+
* (choudoufu #1014). With this set to an absolute directory, the document this
|
|
380
|
+
* read used is written there as `<root>.live-plan.json`, so the caller reads
|
|
381
|
+
* the same `live-plan` the verdicts came from.
|
|
382
|
+
*
|
|
383
|
+
* Opt-in, and never inside the root: a relative path is ignored, so nothing
|
|
384
|
+
* lands in the root by accident (#4379). A write that fails is ignored too;
|
|
385
|
+
* the read answers either way, and the caller sees no file.
|
|
386
|
+
*/
|
|
387
|
+
export declare const TERRAFORM_LIVE_PLAN_DIR_ENV = "CHANT_TERRAFORM_LIVE_PLAN_DIR";
|
|
388
|
+
/** The file {@link TERRAFORM_LIVE_PLAN_DIR_ENV} names for a root: the root's name, made safe for a file name. */
|
|
389
|
+
export declare function livePlanDocumentFile(root: string): string;
|
|
318
390
|
/** One `items[]` entry of a `live-ls -json` listing. */
|
|
319
391
|
export interface LiveLsItem {
|
|
320
392
|
/** ARN or other stable identity. */
|
|
@@ -421,6 +493,11 @@ export interface TerraformReadDeps {
|
|
|
421
493
|
/** The document alone (chant #2498): this reader indexes it and never reads the human render. */
|
|
422
494
|
livePlan: typeof choudoufuLivePlanDocument;
|
|
423
495
|
liveLs: typeof choudoufuLiveLs;
|
|
496
|
+
/**
|
|
497
|
+
* The plan depth's read (#4358). Optional so a test that never asks for the
|
|
498
|
+
* plan depth need not stub it; omitted, the real activity runs.
|
|
499
|
+
*/
|
|
500
|
+
planRead?: typeof terraformPlanRead;
|
|
424
501
|
}
|
|
425
502
|
/** A declared entity, plus the root, address and mode `buildRoots()` recorded on it. */
|
|
426
503
|
export interface TerraformDeclared extends DeclaredEntity {
|
|
@@ -448,6 +525,14 @@ export declare function declaredOf(name: string, entity: {
|
|
|
448
525
|
entityType: string;
|
|
449
526
|
props: Record<string, unknown>;
|
|
450
527
|
} | undefined): TerraformDeclared;
|
|
528
|
+
/** Which read answered a plan-depth root. */
|
|
529
|
+
export type PlanDepthAnswer = "plan" | "state" | "declared";
|
|
530
|
+
/** Does this text name a credentials or authorization failure? Exported for the fallback tests. */
|
|
531
|
+
export declare function planFailureIsCredentials(text: string): boolean;
|
|
532
|
+
/** Which reads answered a live root at the plan depth (#4371). */
|
|
533
|
+
export type LivePlanDepthAnswer = "live+plan" | "live";
|
|
534
|
+
/** The environment variable that overrides every root's observation depth for one run (#4358). */
|
|
535
|
+
export declare const TERRAFORM_OBSERVE_ENV = "CHANT_TERRAFORM_OBSERVE";
|
|
451
536
|
export interface DescribeResourcesOptions {
|
|
452
537
|
environment: string;
|
|
453
538
|
buildOutput: string;
|
|
@@ -467,6 +552,14 @@ export interface DescribeResourcesOptions {
|
|
|
467
552
|
* the running process's cwd. Same meaning as `TerraformWatchOpConfig.cwd`.
|
|
468
553
|
*/
|
|
469
554
|
cwd?: string;
|
|
555
|
+
/**
|
|
556
|
+
* Read every stock root at this depth (#4358), over the config's
|
|
557
|
+
* `terraform.observe` and `terraform.roots.<name>.observe` and the
|
|
558
|
+
* `CHANT_TERRAFORM_OBSERVE` variable. Not a core option: a caller holding
|
|
559
|
+
* this lexicon directly (behold) passes it, and the CLI reaches it through
|
|
560
|
+
* the config or the variable.
|
|
561
|
+
*/
|
|
562
|
+
depth?: TerraformObserveDepth;
|
|
470
563
|
}
|
|
471
564
|
/**
|
|
472
565
|
* Observe every declared terraform entity, one `init` + `show` per configured
|