@intentius/chant-lexicon-terraform 0.105.1 → 0.106.1
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/integrity.json +3 -3
- package/dist/manifest.json +1 -1
- package/dist/rules/tf022.ts +1 -1
- package/package.json +2 -2
- package/src/change-set-combined-run.test.ts +2 -1
- package/src/changed-roots.test.ts +26 -0
- package/src/lint/post-synth/single-block.test.ts +4 -2
- package/src/lint/post-synth/tf022.ts +1 -1
- package/src/plan-summary.test.ts +18 -0
package/dist/integrity.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"algorithm": "sha256",
|
|
3
3
|
"artifacts": {
|
|
4
|
-
"manifest.json": "
|
|
4
|
+
"manifest.json": "88dd9c9a9374f8880f3ec2028254efa12d37a931f7ab2dd40313a08687844670",
|
|
5
5
|
"meta.json": "ca3d163bab055381827226140568f3bef7eaac187cebd76878e0b63e9e442356",
|
|
6
6
|
"types/index.d.ts": "022927e6a7b351cc4cf52d5f973f60ccd140e5810e17b32fb8868965aa1db161",
|
|
7
7
|
"rules/plan-before-apply.ts": "31b1b3176799fd365b2583fe3947edd187c2a863e3dc0094ed9e91ece2464c99",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"rules/tf019.ts": "ae1841a358e5b7a3f42c484f0b5cf1c1f5aa845a50516969a46d65b13e282951",
|
|
32
32
|
"rules/tf020.ts": "2210815c355e37459c34de0fe622f0b87b78010ee7c444135cf5abf7e048adf7",
|
|
33
33
|
"rules/tf021.ts": "ad3cd813a289437d33da866927697077e7a5b20f3c05341325193d286b57bbd5",
|
|
34
|
-
"rules/tf022.ts": "
|
|
34
|
+
"rules/tf022.ts": "5466797cd88fd5489f6c5abd1e796d7c5d3d0e977d0e9e043d253f6ecf369cdc",
|
|
35
35
|
"rules/tf024.ts": "c0c101f913bd3d0fdb5403ee57888e80d8fc612e363f0eb43d7ae759ac1d5651",
|
|
36
36
|
"rules/tf025.ts": "0c31be3885e940e2b3e9ac8e023067d8d6e2b42c04f628890405c9fc6db7d1ce",
|
|
37
37
|
"rules/tf026.ts": "8cf1e61bc9563aa2d3c149f243ffa02ad4f183eebb672f861cd6c4e6fba1d310",
|
|
@@ -56,5 +56,5 @@
|
|
|
56
56
|
"rules/tf045.ts": "760b1f4f385fbe7a86897efe3078fdeac11bcc9bfb806285d63db50488174b7b",
|
|
57
57
|
"skills/chant-terraform.md": "d9ca7b7c28aed0038ce775a3491150298492eed2858fd3651ed9bfca0e577ae8"
|
|
58
58
|
},
|
|
59
|
-
"composite": "
|
|
59
|
+
"composite": "88c99f7360817f2de33f2eef527c4778e223db4679dd3cebde3649dd53652631"
|
|
60
60
|
}
|
package/dist/manifest.json
CHANGED
package/dist/rules/tf022.ts
CHANGED
|
@@ -50,7 +50,7 @@ export const tf022: PostSynthCheck = {
|
|
|
50
50
|
"characters, redacted here). The value is in git history, in state, and in plan output. " +
|
|
51
51
|
"Replace it with a reference: a `sensitive` variable, or a data source that reads the " +
|
|
52
52
|
"value from a secret manager at apply time.",
|
|
53
|
-
entity:
|
|
53
|
+
entity: block.key,
|
|
54
54
|
lexicon: "terraform",
|
|
55
55
|
});
|
|
56
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@intentius/chant-lexicon-terraform",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.106.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"src/",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"access": "public"
|
|
68
68
|
},
|
|
69
69
|
"peerDependencies": {
|
|
70
|
-
"@intentius/chant": "^0.
|
|
70
|
+
"@intentius/chant": "^0.106.1",
|
|
71
71
|
"typescript": "^5.9.3",
|
|
72
72
|
"zod": "^4.3.6"
|
|
73
73
|
},
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
*
|
|
9
9
|
* The plans are the real fixtures the adapter tests pin: chant's `lifecycle
|
|
10
10
|
* plan --json` against floci (`packages/core/src/__fixtures__/change-set`),
|
|
11
|
-
* choudoufu 0.16.0's `show -json` and the warden's
|
|
11
|
+
* choudoufu 0.16.0's `show -json` and the change sets github-warden's
|
|
12
|
+
* `reconcile --plan-json` wrote (`warden.plan.json`, github-warden#66). The
|
|
12
13
|
* two planner activities that need a cloud are stand-ins returning what the
|
|
13
14
|
* real ones return for those plans. `composeChangeSet` and
|
|
14
15
|
* `readChangeSetPart` are the real activities. The scenario is #2300's on a
|
|
@@ -56,3 +56,29 @@ describe("changedRoots", () => {
|
|
|
56
56
|
expect(changedRoots(project, ROOTS, ["README.md", "roots/netsplit/main.tf"])).toEqual([]);
|
|
57
57
|
});
|
|
58
58
|
});
|
|
59
|
+
|
|
60
|
+
describe("changedRoots in a workspace member (#3465)", () => {
|
|
61
|
+
// The project is a member at infra/network. Its root calls a module that
|
|
62
|
+
// lives outside the member, and the changed files come relative to the
|
|
63
|
+
// member, so a file outside it reads `../...`.
|
|
64
|
+
const repo = mkdtempSync(join(tmpdir(), "chant-changed-roots-member-"));
|
|
65
|
+
afterAll(() => rmSync(repo, { recursive: true, force: true }));
|
|
66
|
+
const put = (path: string, text: string): void => {
|
|
67
|
+
mkdirSync(dirname(join(repo, path)), { recursive: true });
|
|
68
|
+
writeFileSync(join(repo, path), text);
|
|
69
|
+
};
|
|
70
|
+
put("infra/network/roots/vpc/main.tf", 'module "base" {\n source = "../../../../shared/modules/base"\n}\n');
|
|
71
|
+
put("shared/modules/base/main.tf", "");
|
|
72
|
+
put("apps/web/main.tf", "");
|
|
73
|
+
const member = join(repo, "infra/network");
|
|
74
|
+
const roots = { vpc: { dir: "roots/vpc" } };
|
|
75
|
+
|
|
76
|
+
test("a module outside the member is watched by a path that leaves it", () => {
|
|
77
|
+
expect(rootWatchPaths(member, roots.vpc)).toEqual(["../../shared/modules/base", "roots/vpc"]);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("a change to that module touches the root; a change in another member touches nothing", () => {
|
|
81
|
+
expect(changedRoots(member, roots, ["../../shared/modules/base/main.tf"])).toEqual(["vpc"]);
|
|
82
|
+
expect(changedRoots(member, roots, ["../../apps/web/main.tf"])).toEqual([]);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -243,9 +243,10 @@ describe("TF022: credential-named resource attribute holding a literal", () => {
|
|
|
243
243
|
test("flags the plaintext password", async () => {
|
|
244
244
|
const diags = tf022.check(await loadFixture("TF022", "positive"));
|
|
245
245
|
expect(diags).toHaveLength(1);
|
|
246
|
-
expect(diags[0].entity).toBe("TF022/aws_db_instance.app
|
|
246
|
+
expect(diags[0].entity).toBe("TF022/aws_db_instance.app");
|
|
247
247
|
expect(diags[0].message).not.toContain("Pr0dDbP4ssw0rd");
|
|
248
248
|
expect(diags[0].message).toContain("reference");
|
|
249
|
+
expect(diags[0].message).toContain("`password`");
|
|
249
250
|
});
|
|
250
251
|
|
|
251
252
|
test("passes a password read from a data source", async () => {
|
|
@@ -254,7 +255,8 @@ describe("TF022: credential-named resource attribute holding a literal", () => {
|
|
|
254
255
|
|
|
255
256
|
test("descends into a nested block", async () => {
|
|
256
257
|
const diags = tf022.check(await loadFixture("TF022", "positive-nested"));
|
|
257
|
-
expect(diags.map((d) => d.entity)).toEqual(["TF022/aws_instance.web
|
|
258
|
+
expect(diags.map((d) => d.entity)).toEqual(["TF022/aws_instance.web"]);
|
|
259
|
+
expect(diags[0].message).toContain("`connection.password`");
|
|
258
260
|
});
|
|
259
261
|
|
|
260
262
|
test("a locator attribute is the remediation, not the finding", async () => {
|
|
@@ -50,7 +50,7 @@ export const tf022: PostSynthCheck = {
|
|
|
50
50
|
"characters, redacted here). The value is in git history, in state, and in plan output. " +
|
|
51
51
|
"Replace it with a reference: a `sensitive` variable, or a data source that reads the " +
|
|
52
52
|
"value from a secret manager at apply time.",
|
|
53
|
-
entity:
|
|
53
|
+
entity: block.key,
|
|
54
54
|
lexicon: "terraform",
|
|
55
55
|
});
|
|
56
56
|
}
|
package/src/plan-summary.test.ts
CHANGED
|
@@ -102,6 +102,24 @@ describe("the shared normalization vectors", () => {
|
|
|
102
102
|
expect(grouped).toEqual([]);
|
|
103
103
|
});
|
|
104
104
|
|
|
105
|
+
test("red first: keeping a sensitive value or a read's result splits the sensitive and read must-group rows", () => {
|
|
106
|
+
const keepValues = (root: Json): Json => {
|
|
107
|
+
const r = clone(root);
|
|
108
|
+
for (const rc of r.plan.resource_changes) {
|
|
109
|
+
delete rc.change.before_sensitive;
|
|
110
|
+
delete rc.change.after_sensitive;
|
|
111
|
+
if (rc.change.actions.length === 1 && rc.change.actions[0] === "read") rc.change.actions = ["create"];
|
|
112
|
+
}
|
|
113
|
+
return r;
|
|
114
|
+
};
|
|
115
|
+
const rows = vectors.rootPairs.filter((r) => r.group && ["sensitive attribute with different values", "read entries whose results differ"].includes(r.name));
|
|
116
|
+
expect(rows.map((r) => r.name).sort()).toEqual(["read entries whose results differ", "sensitive attribute with different values"]);
|
|
117
|
+
for (const row of rows) {
|
|
118
|
+
expect(rootsGroup(row.a, row.b)).toBe(true);
|
|
119
|
+
expect(rootsGroup(keepValues(row.a), keepValues(row.b))).toBe(false);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
105
123
|
test("red first: blanking every string falsely groups exactly the named must-not pairs", () => {
|
|
106
124
|
const falselyGrouped = vectors.rootPairs.filter((r) => !r.group && rootsGroup(blankStrings(r.a), blankStrings(r.b))).map((r) => r.name);
|
|
107
125
|
expect(falselyGrouped.sort()).toEqual([...vectors.overEagerFalselyGroups].sort());
|