@intentius/chant-lexicon-aws 0.0.6 → 0.0.9

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.
Files changed (128) hide show
  1. package/dist/integrity.json +25 -10
  2. package/dist/manifest.json +1 -1
  3. package/dist/meta.json +9444 -4597
  4. package/dist/rules/cf-refs.ts +99 -0
  5. package/dist/rules/ext001.ts +32 -25
  6. package/dist/rules/hardcoded-region.ts +1 -0
  7. package/dist/rules/iam-wildcard.ts +1 -0
  8. package/dist/rules/s3-encryption.ts +3 -3
  9. package/dist/rules/waw016.ts +86 -0
  10. package/dist/rules/waw017.ts +53 -0
  11. package/dist/rules/waw018.ts +71 -0
  12. package/dist/rules/waw019.ts +82 -0
  13. package/dist/rules/waw020.ts +64 -0
  14. package/dist/rules/waw021.ts +53 -0
  15. package/dist/rules/waw022.ts +43 -0
  16. package/dist/rules/waw023.ts +47 -0
  17. package/dist/rules/waw024.ts +54 -0
  18. package/dist/rules/waw025.ts +43 -0
  19. package/dist/rules/waw026.ts +46 -0
  20. package/dist/rules/waw027.ts +50 -0
  21. package/dist/rules/waw028.ts +47 -0
  22. package/dist/rules/waw029.ts +62 -0
  23. package/dist/rules/waw030.ts +246 -0
  24. package/dist/skills/chant-aws.md +430 -0
  25. package/dist/types/index.d.ts +58525 -58501
  26. package/package.json +2 -2
  27. package/src/actions/actions.test.ts +75 -0
  28. package/src/actions/dynamodb.ts +36 -0
  29. package/src/actions/ecr.ts +9 -0
  30. package/src/actions/ecs.ts +5 -0
  31. package/src/actions/iam.ts +3 -0
  32. package/src/actions/index.ts +9 -0
  33. package/src/actions/lambda.ts +11 -0
  34. package/src/actions/logs.ts +4 -0
  35. package/src/actions/s3.ts +34 -0
  36. package/src/actions/sns.ts +5 -0
  37. package/src/actions/sqs.ts +15 -0
  38. package/src/codegen/__snapshots__/snapshot.test.ts.snap +20 -20
  39. package/src/codegen/docs-links.test.ts +143 -0
  40. package/src/codegen/docs.ts +294 -124
  41. package/src/codegen/generate-lexicon.ts +8 -0
  42. package/src/codegen/generate-typescript.ts +25 -1
  43. package/src/codegen/generate.ts +1 -13
  44. package/src/codegen/package.ts +2 -0
  45. package/src/codegen/typecheck.test.ts +1 -1
  46. package/src/composites/composites.test.ts +442 -0
  47. package/src/composites/fargate-alb.ts +253 -0
  48. package/src/composites/index.ts +20 -0
  49. package/src/composites/lambda-api.ts +20 -0
  50. package/src/composites/lambda-dynamodb.ts +64 -0
  51. package/src/composites/lambda-eventbridge.ts +36 -0
  52. package/src/composites/lambda-function.ts +76 -0
  53. package/src/composites/lambda-s3.ts +72 -0
  54. package/src/composites/lambda-sns.ts +30 -0
  55. package/src/composites/lambda-sqs.ts +44 -0
  56. package/src/composites/scheduled-lambda.ts +37 -0
  57. package/src/composites/vpc-default.ts +148 -0
  58. package/src/default-tags.test.ts +38 -0
  59. package/src/default-tags.ts +77 -0
  60. package/src/generated/index.d.ts +58525 -58501
  61. package/src/generated/index.ts +1351 -1351
  62. package/src/generated/lexicon-aws.json +9444 -4597
  63. package/src/import/generator.test.ts +5 -5
  64. package/src/import/generator.ts +4 -4
  65. package/src/import/roundtrip-fixtures.test.ts +2 -1
  66. package/src/import/roundtrip.test.ts +5 -5
  67. package/src/index.ts +21 -0
  68. package/src/integration.test.ts +92 -21
  69. package/src/intrinsics.ts +24 -13
  70. package/src/lint/post-synth/cf-refs.ts +99 -0
  71. package/src/lint/post-synth/ext001.test.ts +214 -31
  72. package/src/lint/post-synth/ext001.ts +32 -25
  73. package/src/lint/post-synth/waw013.test.ts +120 -0
  74. package/src/lint/post-synth/waw014.test.ts +121 -0
  75. package/src/lint/post-synth/waw015.test.ts +147 -0
  76. package/src/lint/post-synth/waw016.test.ts +141 -0
  77. package/src/lint/post-synth/waw016.ts +86 -0
  78. package/src/lint/post-synth/waw017.test.ts +130 -0
  79. package/src/lint/post-synth/waw017.ts +53 -0
  80. package/src/lint/post-synth/waw018.test.ts +109 -0
  81. package/src/lint/post-synth/waw018.ts +71 -0
  82. package/src/lint/post-synth/waw019.test.ts +138 -0
  83. package/src/lint/post-synth/waw019.ts +82 -0
  84. package/src/lint/post-synth/waw020.test.ts +125 -0
  85. package/src/lint/post-synth/waw020.ts +64 -0
  86. package/src/lint/post-synth/waw021.test.ts +81 -0
  87. package/src/lint/post-synth/waw021.ts +53 -0
  88. package/src/lint/post-synth/waw022.test.ts +54 -0
  89. package/src/lint/post-synth/waw022.ts +43 -0
  90. package/src/lint/post-synth/waw023.test.ts +53 -0
  91. package/src/lint/post-synth/waw023.ts +47 -0
  92. package/src/lint/post-synth/waw024.test.ts +64 -0
  93. package/src/lint/post-synth/waw024.ts +54 -0
  94. package/src/lint/post-synth/waw025.test.ts +42 -0
  95. package/src/lint/post-synth/waw025.ts +43 -0
  96. package/src/lint/post-synth/waw026.test.ts +54 -0
  97. package/src/lint/post-synth/waw026.ts +46 -0
  98. package/src/lint/post-synth/waw027.test.ts +63 -0
  99. package/src/lint/post-synth/waw027.ts +50 -0
  100. package/src/lint/post-synth/waw028.test.ts +68 -0
  101. package/src/lint/post-synth/waw028.ts +47 -0
  102. package/src/lint/post-synth/waw029.test.ts +179 -0
  103. package/src/lint/post-synth/waw029.ts +62 -0
  104. package/src/lint/post-synth/waw030.test.ts +800 -0
  105. package/src/lint/post-synth/waw030.ts +246 -0
  106. package/src/lint/rules/hardcoded-region.ts +1 -0
  107. package/src/lint/rules/iam-wildcard.ts +1 -0
  108. package/src/lint/rules/rules.test.ts +8 -8
  109. package/src/lint/rules/s3-encryption.ts +3 -3
  110. package/src/lsp/completions.ts +2 -0
  111. package/src/lsp/hover.ts +17 -0
  112. package/src/nested-stack-integration.test.ts +100 -0
  113. package/src/nested-stack.ts +2 -2
  114. package/src/plugin.test.ts +13 -15
  115. package/src/plugin.ts +552 -114
  116. package/src/serializer.test.ts +370 -43
  117. package/src/serializer.ts +69 -17
  118. package/src/spec/fetch.ts +10 -0
  119. package/src/spec/parse.test.ts +141 -0
  120. package/src/spec/parse.ts +40 -0
  121. package/src/taggable.ts +44 -0
  122. package/src/testdata/nested-stacks/app.ts +26 -0
  123. package/src/testdata/nested-stacks/network/outputs.ts +17 -0
  124. package/src/testdata/nested-stacks/network/security.ts +17 -0
  125. package/src/testdata/nested-stacks/network/vpc.ts +54 -0
  126. package/dist/skills/aws-cloudformation.md +0 -41
  127. package/src/codegen/rollback.test.ts +0 -80
  128. package/src/codegen/rollback.ts +0 -20
@@ -0,0 +1,179 @@
1
+ import { describe, test, expect } from "bun:test";
2
+ import { createPostSynthContext } from "@intentius/chant-test-utils";
3
+ import { waw029, checkInvalidDependsOn } from "./waw029";
4
+
5
+ function makeCtx(template: object) {
6
+ return createPostSynthContext({ aws: template });
7
+ }
8
+
9
+ describe("WAW029: Invalid DependsOn Target", () => {
10
+ test("check metadata", () => {
11
+ expect(waw029.id).toBe("WAW029");
12
+ expect(waw029.description).toContain("DependsOn");
13
+ });
14
+
15
+ test("dangling DependsOn target → error", () => {
16
+ const ctx = makeCtx({
17
+ Resources: {
18
+ MyBucket: {
19
+ Type: "AWS::S3::Bucket",
20
+ DependsOn: "MyBukcet",
21
+ Properties: {},
22
+ },
23
+ },
24
+ });
25
+ const diags = checkInvalidDependsOn(ctx);
26
+ expect(diags).toHaveLength(1);
27
+ expect(diags[0].checkId).toBe("WAW029");
28
+ expect(diags[0].severity).toBe("error");
29
+ expect(diags[0].message).toContain("MyBukcet");
30
+ expect(diags[0].message).toContain("does not exist");
31
+ expect(diags[0].entity).toBe("MyBucket");
32
+ expect(diags[0].lexicon).toBe("aws");
33
+ });
34
+
35
+ test("self-referencing DependsOn → error", () => {
36
+ const ctx = makeCtx({
37
+ Resources: {
38
+ MyBucket: {
39
+ Type: "AWS::S3::Bucket",
40
+ DependsOn: "MyBucket",
41
+ Properties: {},
42
+ },
43
+ },
44
+ });
45
+ const diags = checkInvalidDependsOn(ctx);
46
+ expect(diags).toHaveLength(1);
47
+ expect(diags[0].checkId).toBe("WAW029");
48
+ expect(diags[0].severity).toBe("error");
49
+ expect(diags[0].message).toContain("itself");
50
+ expect(diags[0].entity).toBe("MyBucket");
51
+ });
52
+
53
+ test("valid DependsOn → no diagnostic", () => {
54
+ const ctx = makeCtx({
55
+ Resources: {
56
+ MyBucket: {
57
+ Type: "AWS::S3::Bucket",
58
+ Properties: {},
59
+ },
60
+ MyFunction: {
61
+ Type: "AWS::Lambda::Function",
62
+ DependsOn: "MyBucket",
63
+ Properties: {},
64
+ },
65
+ },
66
+ });
67
+ const diags = checkInvalidDependsOn(ctx);
68
+ expect(diags).toHaveLength(0);
69
+ });
70
+
71
+ test("string DependsOn (not array) → works", () => {
72
+ const ctx = makeCtx({
73
+ Resources: {
74
+ MyBucket: {
75
+ Type: "AWS::S3::Bucket",
76
+ DependsOn: "NonExistent",
77
+ Properties: {},
78
+ },
79
+ },
80
+ });
81
+ const diags = checkInvalidDependsOn(ctx);
82
+ expect(diags).toHaveLength(1);
83
+ expect(diags[0].message).toContain("NonExistent");
84
+ });
85
+
86
+ test("multiple invalid targets → multiple diagnostics", () => {
87
+ const ctx = makeCtx({
88
+ Resources: {
89
+ MyBucket: {
90
+ Type: "AWS::S3::Bucket",
91
+ DependsOn: ["Typo1", "Typo2"],
92
+ Properties: {},
93
+ },
94
+ },
95
+ });
96
+ const diags = checkInvalidDependsOn(ctx);
97
+ expect(diags).toHaveLength(2);
98
+ expect(diags[0].message).toContain("Typo1");
99
+ expect(diags[1].message).toContain("Typo2");
100
+ });
101
+
102
+ test("no DependsOn → no diagnostic", () => {
103
+ const ctx = makeCtx({
104
+ Resources: {
105
+ MyBucket: {
106
+ Type: "AWS::S3::Bucket",
107
+ Properties: {},
108
+ },
109
+ },
110
+ });
111
+ const diags = checkInvalidDependsOn(ctx);
112
+ expect(diags).toHaveLength(0);
113
+ });
114
+
115
+ test("empty Resources → no diagnostic", () => {
116
+ const ctx = makeCtx({ Resources: {} });
117
+ const diags = checkInvalidDependsOn(ctx);
118
+ expect(diags).toHaveLength(0);
119
+ });
120
+
121
+ test("empty DependsOn array → no diagnostic", () => {
122
+ const ctx = makeCtx({
123
+ Resources: {
124
+ MyBucket: {
125
+ Type: "AWS::S3::Bucket",
126
+ DependsOn: [],
127
+ Properties: {},
128
+ },
129
+ },
130
+ });
131
+ const diags = checkInvalidDependsOn(ctx);
132
+ expect(diags).toHaveLength(0);
133
+ });
134
+
135
+ test("mixed valid and invalid in same array", () => {
136
+ const ctx = makeCtx({
137
+ Resources: {
138
+ A: { Type: "AWS::S3::Bucket", Properties: {} },
139
+ B: {
140
+ Type: "AWS::Lambda::Function",
141
+ DependsOn: ["A", "NonExistent", "B"],
142
+ Properties: {},
143
+ },
144
+ },
145
+ });
146
+ const diags = checkInvalidDependsOn(ctx);
147
+ expect(diags).toHaveLength(2);
148
+ expect(diags[0].message).toContain("NonExistent");
149
+ expect(diags[0].message).toContain("does not exist");
150
+ expect(diags[1].message).toContain("itself");
151
+ });
152
+
153
+ test("no Resources key → no diagnostic", () => {
154
+ const ctx = makeCtx({ AWSTemplateFormatVersion: "2010-09-09" });
155
+ const diags = checkInvalidDependsOn(ctx);
156
+ expect(diags).toHaveLength(0);
157
+ });
158
+
159
+ test("multiple resources each with invalid DependsOn", () => {
160
+ const ctx = makeCtx({
161
+ Resources: {
162
+ A: {
163
+ Type: "AWS::S3::Bucket",
164
+ DependsOn: "Ghost1",
165
+ Properties: {},
166
+ },
167
+ B: {
168
+ Type: "AWS::Lambda::Function",
169
+ DependsOn: "Ghost2",
170
+ Properties: {},
171
+ },
172
+ },
173
+ });
174
+ const diags = checkInvalidDependsOn(ctx);
175
+ expect(diags).toHaveLength(2);
176
+ expect(diags[0].entity).toBe("A");
177
+ expect(diags[1].entity).toBe("B");
178
+ });
179
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * WAW029: Invalid DependsOn Target
3
+ *
4
+ * Detects two cases in the serialized template:
5
+ * - Dangling reference: DependsOn target not in template.Resources
6
+ * - Self-reference: Resource depends on itself
7
+ */
8
+
9
+ import type { PostSynthCheck, PostSynthContext, PostSynthDiagnostic } from "@intentius/chant/lint/post-synth";
10
+ import { parseCFTemplate } from "./cf-refs";
11
+
12
+ export function checkInvalidDependsOn(ctx: PostSynthContext): PostSynthDiagnostic[] {
13
+ const diagnostics: PostSynthDiagnostic[] = [];
14
+
15
+ for (const [_lexicon, output] of ctx.outputs) {
16
+ const template = parseCFTemplate(output);
17
+ if (!template?.Resources) continue;
18
+
19
+ const resourceIds = new Set(Object.keys(template.Resources));
20
+
21
+ for (const [logicalId, resource] of Object.entries(template.Resources)) {
22
+ if (!resource.DependsOn) continue;
23
+
24
+ const deps = Array.isArray(resource.DependsOn)
25
+ ? resource.DependsOn
26
+ : [resource.DependsOn];
27
+
28
+ for (const dep of deps) {
29
+ if (typeof dep !== "string") continue;
30
+
31
+ if (dep === logicalId) {
32
+ diagnostics.push({
33
+ checkId: "WAW029",
34
+ severity: "error",
35
+ message: `Resource "${logicalId}" has a DependsOn on itself — self-references are invalid`,
36
+ entity: logicalId,
37
+ lexicon: "aws",
38
+ });
39
+ } else if (!resourceIds.has(dep)) {
40
+ diagnostics.push({
41
+ checkId: "WAW029",
42
+ severity: "error",
43
+ message: `Resource "${logicalId}" has DependsOn "${dep}" which does not exist in the template`,
44
+ entity: logicalId,
45
+ lexicon: "aws",
46
+ });
47
+ }
48
+ }
49
+ }
50
+ }
51
+
52
+ return diagnostics;
53
+ }
54
+
55
+ export const waw029: PostSynthCheck = {
56
+ id: "WAW029",
57
+ description: "Invalid DependsOn target — dangling reference or self-reference",
58
+
59
+ check(ctx: PostSynthContext): PostSynthDiagnostic[] {
60
+ return checkInvalidDependsOn(ctx);
61
+ },
62
+ };