@aws/cloudformation-validate 1.9.0-beta → 1.10.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/README.md +252 -87
- package/THIRD-PARTY-LICENSES.txt +79 -0
- package/bindings_wasm.d.ts +114 -111
- package/bindings_wasm.js +121 -17
- package/bindings_wasm_bg.wasm +0 -0
- package/bindings_wasm_bg.wasm.d.ts +10 -11
- package/index.d.ts +72 -10
- package/index.js +211 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
# CloudFormation Validate for Node.js
|
|
2
2
|
|
|
3
|
-
Validate AWS CloudFormation templates from JavaScript or TypeScript and catch schema violations,
|
|
4
|
-
best-practice findings before deployment - in your editor, build, or CI.
|
|
3
|
+
Validate AWS CloudFormation templates from JavaScript or TypeScript and catch schema violations, semantic errors,
|
|
4
|
+
security risks, and best-practice findings before deployment - in your editor, build, service, or CI.
|
|
5
5
|
|
|
6
|
-
- **Offline** - all rules and resource schemas are bundled
|
|
7
|
-
|
|
6
|
+
- **Offline** - all rules and CloudFormation resource schemas are bundled; nothing is fetched at runtime and no AWS
|
|
7
|
+
credentials are needed.
|
|
8
|
+
- **Fast** - engines and schemas compile once and are reused across validations; typical templates validate in under a
|
|
9
|
+
second.
|
|
10
|
+
- **Self-contained** - the WebAssembly module is bundled in the package; there are no native dependencies.
|
|
11
|
+
|
|
12
|
+
All types are exported from the `@aws/cloudformation-validate` package.
|
|
8
13
|
|
|
9
14
|
## Installation
|
|
10
15
|
|
|
@@ -14,6 +19,8 @@ Available on [npm](https://www.npmjs.com/package/@aws/cloudformation-validate) a
|
|
|
14
19
|
npm install @aws/cloudformation-validate
|
|
15
20
|
```
|
|
16
21
|
|
|
22
|
+
Requires Node.js 20 or later. The package has no runtime dependencies.
|
|
23
|
+
|
|
17
24
|
## Quick start
|
|
18
25
|
|
|
19
26
|
Engines, models, and validators hold off-heap memory - call `.free()` when done with each object:
|
|
@@ -23,7 +30,7 @@ import { RegoEngine, TemplateFile } from "@aws/cloudformation-validate";
|
|
|
23
30
|
|
|
24
31
|
const engine = new RegoEngine();
|
|
25
32
|
try {
|
|
26
|
-
const report = engine.
|
|
33
|
+
const report = engine.validateTemplate(new TemplateFile("template.yaml"));
|
|
27
34
|
for (const d of report.diagnostics) {
|
|
28
35
|
console.log(`[${d.severity}] ${d.ruleId}: ${d.message}`);
|
|
29
36
|
}
|
|
@@ -32,35 +39,54 @@ try {
|
|
|
32
39
|
}
|
|
33
40
|
```
|
|
34
41
|
|
|
35
|
-
Each diagnostic identifies the rule, severity, affected
|
|
36
|
-
[
|
|
42
|
+
Each diagnostic identifies the rule, severity, affected entity and property, and source location - see
|
|
43
|
+
[Diagnostic](#diagnostic). A complete, runnable project is in
|
|
37
44
|
[examples](https://github.com/aws-cloudformation/cloudformation-validate/tree/main/src/bindings-wasm/examples).
|
|
38
45
|
|
|
46
|
+
Engines are expensive to construct (rules compile once) and cheap to reuse - create one engine and validate many
|
|
47
|
+
templates. Every fallible call throws on failure - the thrown value is the error message string from the validation
|
|
48
|
+
core, so handle it with `catch (error) { String(error) }`; internal panics are caught at the WASM boundary and surface
|
|
49
|
+
the same way, never a process abort. `version()` returns the version of the bundled validation core.
|
|
50
|
+
|
|
51
|
+
A template is passed as a `TemplateFile`, which wraps a filesystem path: the engine reads the bytes and uses the path
|
|
52
|
+
for diagnostic source locations.
|
|
53
|
+
|
|
39
54
|
## Engine
|
|
40
55
|
|
|
41
56
|
`RegoEngine` and `CelEngine` both implement the `Engine` interface and are interchangeable - they produce identical
|
|
42
|
-
diagnostics for the same template and config.
|
|
57
|
+
diagnostics for the same template and config. `CompositeEngine` implements the same interface and layers custom Rego,
|
|
58
|
+
CEL, and Guard rules on top of the built-in rules - see [CompositeEngine](#compositeengine).
|
|
43
59
|
|
|
44
60
|
### `Engine` interface
|
|
45
61
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
62
|
+
```typescript
|
|
63
|
+
interface Engine {
|
|
64
|
+
validateTemplate(template: TemplateFile, config?: ValidateConfig): ValidationReport;
|
|
65
|
+
validateAwsCliCommand(request: AwsCliCommand): AwsCliCommandValidation;
|
|
66
|
+
listRules(): RuleInfo[];
|
|
67
|
+
engineName(): string;
|
|
68
|
+
free(): void;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
| Method | Returns | Description |
|
|
73
|
+
|---------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
74
|
+
| `validateTemplate(template, config?)` | `ValidationReport` | Validates the template and returns a report. `config.detailLevel` (default `DETAILED`) selects how much per-diagnostic context is populated: `DETAILED` adds documentation URLs, rule descriptions, phase tags, and `ViolationContext`; `STANDARD` leaves those enrichment fields absent |
|
|
75
|
+
| `validateAwsCliCommand(request)` | `AwsCliCommandValidation` | Models an AWS CLI command as CloudFormation resource state and validates it - see [AWS CLI command validation](#aws-cli-command-validation) |
|
|
76
|
+
| `listRules()` | `RuleInfo[]` | Returns metadata for every built-in and loaded custom rule |
|
|
77
|
+
| `engineName()` | `string` | `"rego"`, `"cel"`, or `"composite"` |
|
|
78
|
+
| `free()` | `void` | Releases the engine's off-heap memory; the engine must not be used afterwards |
|
|
53
79
|
|
|
54
80
|
### `EngineConfig`
|
|
55
81
|
|
|
56
|
-
Passed to the constructor. All fields are optional
|
|
82
|
+
Passed to the constructor. All fields are optional: the rule lists default to empty and an omitted
|
|
57
83
|
`schemaValidatorConfig` uses only the bundled schemas.
|
|
58
84
|
|
|
59
85
|
```typescript
|
|
60
86
|
interface EngineConfig {
|
|
61
|
-
customRules?: RuleSource[];
|
|
62
|
-
guardRules?: RuleSource[];
|
|
63
|
-
schemaValidatorConfig?: SchemaValidatorConfig; //
|
|
87
|
+
customRules?: RuleSource[]; // engine-native rules (Rego for RegoEngine, CEL for CelEngine)
|
|
88
|
+
guardRules?: RuleSource[]; // CloudFormation Guard DSL rules - evaluated by the Guard evaluator
|
|
89
|
+
schemaValidatorConfig?: SchemaValidatorConfig; // additional resource provider schemas
|
|
64
90
|
}
|
|
65
91
|
|
|
66
92
|
interface SchemaValidatorConfig {
|
|
@@ -70,14 +96,6 @@ interface SchemaValidatorConfig {
|
|
|
70
96
|
type RuleSource = ExternalRuleSource | RuleFile;
|
|
71
97
|
type SchemaSource = AdditionalSchemaSource | SchemaFile;
|
|
72
98
|
|
|
73
|
-
class RuleFile {
|
|
74
|
-
constructor(path: string); // rule file read from disk; the path becomes the rule source name
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
class SchemaFile {
|
|
78
|
-
constructor(path: string, typeName?: string); // schema file; typeName defaults to the value inside the JSON
|
|
79
|
-
}
|
|
80
|
-
|
|
81
99
|
interface ExternalRuleSource {
|
|
82
100
|
name: string; // identifier shown in diagnostics (e.g. file path)
|
|
83
101
|
content: string; // full rule source text
|
|
@@ -87,17 +105,35 @@ interface AdditionalSchemaSource {
|
|
|
87
105
|
typeName?: string; // omit to use the typeName inside the schema JSON
|
|
88
106
|
schema: string; // complete resource provider schema JSON
|
|
89
107
|
}
|
|
90
|
-
```
|
|
91
108
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
`typeName`.
|
|
109
|
+
class RuleFile {
|
|
110
|
+
constructor(path: string); // rule file read from disk; the path becomes the rule source name
|
|
111
|
+
}
|
|
96
112
|
|
|
97
|
-
|
|
98
|
-
|
|
113
|
+
class SchemaFile {
|
|
114
|
+
constructor(path: string, typeName?: string); // schema file; typeName defaults to the value inside the JSON
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
| Field | Default | Description |
|
|
119
|
+
|-------------------------|-------------|-----------------------------------------------------------------------------------------------|
|
|
120
|
+
| `customRules` | `[]` | Engine-native rules: Rego source for `RegoEngine`, CEL JSON for `CelEngine` |
|
|
121
|
+
| `guardRules` | `[]` | CloudFormation Guard DSL rules, evaluated by the Guard evaluator identically in every engine |
|
|
122
|
+
| `schemaValidatorConfig` | `undefined` | Optional `SchemaValidatorConfig` whose `additionalSchemas` are merged over the bundled schemas |
|
|
123
|
+
|
|
124
|
+
Each rule is an `ExternalRuleSource` - `name` identifies the rule in diagnostics and `content` is the full rule source
|
|
125
|
+
text. Pass a `RuleFile` to load one from disk (the same pattern as `TemplateFile` for templates), or an
|
|
126
|
+
`ExternalRuleSource` when you already have the rule text in memory. Each additional schema is an
|
|
127
|
+
`AdditionalSchemaSource` - a complete resource provider schema JSON plus an optional `typeName` that may be omitted when
|
|
128
|
+
the schema JSON contains its own `typeName`; `SchemaFile` loads one from disk. Additional schemas extend the bundled
|
|
129
|
+
schemas or register resource types CloudFormation has not published yet; a malformed, contradictory, or unsupported
|
|
130
|
+
schema fails engine construction rather than silently weakening validation. Guard rules are evaluated by the
|
|
131
|
+
CloudFormation Guard evaluator itself against the template as written, so every engine reports exactly what `cfn-guard
|
|
132
|
+
validate` reports; a Guard file that does not parse also fails engine construction. The two forms can be mixed freely:
|
|
99
133
|
|
|
100
134
|
```typescript
|
|
135
|
+
import { CelEngine, RuleFile, SchemaFile } from "@aws/cloudformation-validate";
|
|
136
|
+
|
|
101
137
|
const engine = new CelEngine({
|
|
102
138
|
customRules: [new RuleFile("rules/s3_encryption.json")],
|
|
103
139
|
guardRules: [new RuleFile("rules/compliance.guard")],
|
|
@@ -107,15 +143,66 @@ const engine = new CelEngine({
|
|
|
107
143
|
});
|
|
108
144
|
```
|
|
109
145
|
|
|
146
|
+
See [Custom Rules](../CUSTOM_RULES.md) for the Rego, CEL, and Guard rule formats and
|
|
147
|
+
[Additional Resource Provider Schemas](../validation-engine/API.md#additional-resource-provider-schemas) for the schema
|
|
148
|
+
merge model.
|
|
149
|
+
|
|
150
|
+
### `CompositeEngine`
|
|
151
|
+
|
|
152
|
+
`CompositeEngine` implements the same `Engine` interface but takes a `CompositeEngineConfig`. It evaluates every
|
|
153
|
+
built-in rule with a fixed built-in CEL evaluator and layers the caller-supplied custom rules on top: custom CEL and
|
|
154
|
+
Guard rules run alongside that built-in engine, while custom Rego rules run in a separate external engine that is
|
|
155
|
+
constructed only when Rego rules are supplied. With no custom rules it produces the same built-in diagnostics as
|
|
156
|
+
`RegoEngine` and `CelEngine`, and `engineName()` returns `"composite"`. Because the composite fixes which engine owns
|
|
157
|
+
the built-ins, the config has no `customRules` field - it carries only the custom rules layered on top:
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
interface CompositeEngineConfig {
|
|
161
|
+
regoRules?: RuleSource[]; // custom Rego rules, run by the external engine
|
|
162
|
+
celRules?: RuleSource[]; // custom CEL rules, run by the built-in engine
|
|
163
|
+
guardRules?: RuleSource[]; // CloudFormation Guard DSL rules, evaluated alongside the built-in engine
|
|
164
|
+
schemaValidatorConfig?: SchemaValidatorConfig; // additional resource provider schemas, observed by both inner engines
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
| Field | Default | Description |
|
|
169
|
+
|-------------------------|-------------|--------------------------------------------------------------------------------------------------|
|
|
170
|
+
| `regoRules` | `[]` | Custom Rego rules layered on top of the built-in rules, run by the external engine |
|
|
171
|
+
| `celRules` | `[]` | Custom CEL rules layered on top of the built-in rules, run by the built-in engine |
|
|
172
|
+
| `guardRules` | `[]` | CloudFormation Guard DSL rules layered on top of the built-in rules, evaluated alongside the built-in engine |
|
|
173
|
+
| `schemaValidatorConfig` | `undefined` | Optional `SchemaValidatorConfig`, observed by both inner engines |
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
import { CompositeEngine, RuleFile, TemplateFile } from "@aws/cloudformation-validate";
|
|
177
|
+
|
|
178
|
+
const engine = new CompositeEngine({
|
|
179
|
+
regoRules: [new RuleFile("rules/s3_naming.rego")],
|
|
180
|
+
guardRules: [new RuleFile("rules/compliance.guard")],
|
|
181
|
+
});
|
|
182
|
+
try {
|
|
183
|
+
const report = engine.validateTemplate(new TemplateFile("template.yaml"));
|
|
184
|
+
} finally {
|
|
185
|
+
engine.free();
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
110
189
|
## ValidateConfig
|
|
111
190
|
|
|
112
|
-
Controls filtering, severity, parameter overrides, and behavior
|
|
113
|
-
`{}` uses
|
|
191
|
+
Controls filtering, detail, severity, parameter overrides, and behavior for one validation call. All fields have
|
|
192
|
+
defaults - omitting the config or passing `{}` uses them.
|
|
193
|
+
|
|
194
|
+
```typescript
|
|
195
|
+
const report = engine.validateTemplate(new TemplateFile("template.yaml"), {
|
|
196
|
+
exclude: { ids: ["I1002"] },
|
|
197
|
+
severityLevel: "WARN",
|
|
198
|
+
});
|
|
199
|
+
```
|
|
114
200
|
|
|
115
201
|
```typescript
|
|
116
202
|
interface ValidateConfig {
|
|
117
203
|
include?: RuleFilterConfig;
|
|
118
204
|
exclude?: RuleFilterConfig;
|
|
205
|
+
detailLevel?: DetailLevel;
|
|
119
206
|
severityLevel?: Severity;
|
|
120
207
|
parameterOverrides?: Record<string, string>;
|
|
121
208
|
pseudoParameterOverrides?: PseudoParameterOverrides;
|
|
@@ -124,15 +211,16 @@ interface ValidateConfig {
|
|
|
124
211
|
}
|
|
125
212
|
```
|
|
126
213
|
|
|
127
|
-
| Field | Default | Description
|
|
128
|
-
|
|
129
|
-
| `include` | `{}` (all rules) | When set, only matching rules produce diagnostics. Empty means include everything.
|
|
130
|
-
| `exclude` | `{}` (nothing excluded) | Matching rules are suppressed. Applied after `include`.
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
214
|
+
| Field | Default | Description |
|
|
215
|
+
|----------------------------|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
216
|
+
| `include` | `{}` (all rules) | When set, only matching rules produce diagnostics. Empty means include everything. |
|
|
217
|
+
| `exclude` | `{}` (nothing excluded) | Matching rules are suppressed. Applied after `include`. |
|
|
218
|
+
| `detailLevel` | `"DETAILED"` | Per-diagnostic context. `"DETAILED"` populates documentation URLs, rule descriptions, phase tags, and `ViolationContext`; `"STANDARD"` leaves those enrichment fields absent. |
|
|
219
|
+
| `severityLevel` | `"INFO"` | Minimum severity threshold. Diagnostics below this level are dropped. Values: `DEBUG`, `INFO`, `WARN`, `ERROR`, `FATAL`. |
|
|
220
|
+
| `parameterOverrides` | `{}` | Override template parameter values during resolution. Keys are parameter logical IDs. |
|
|
221
|
+
| `pseudoParameterOverrides` | all `undefined` | Override CloudFormation pseudo-parameters (`AWS::AccountId`, `AWS::Region`, etc.). |
|
|
222
|
+
| `strict` | `false` | When `true`, `WARN`-severity diagnostics are upgraded to `ERROR`. |
|
|
223
|
+
| `disableBuiltinRules` | `false` | When `true`, all built-in rules (schema validation, Step Functions, engine rules) are skipped; only custom and Guard rules are evaluated. |
|
|
136
224
|
|
|
137
225
|
### RuleFilterConfig
|
|
138
226
|
|
|
@@ -140,14 +228,14 @@ Both `include` and `exclude` use this structure. All fields are additive - a rul
|
|
|
140
228
|
|
|
141
229
|
```typescript
|
|
142
230
|
interface RuleFilterConfig {
|
|
143
|
-
ids?: string[];
|
|
144
|
-
categories?: string[];
|
|
145
|
-
idRanges?: IdRange[];
|
|
146
|
-
idPatterns?: string[];
|
|
147
|
-
resourceIds?: ResourceIdFilter[];
|
|
148
|
-
logicalIds?: LogicalIdFilter[];
|
|
231
|
+
ids?: string[]; // exact rule IDs, e.g. ["E3012", "W3010"]
|
|
232
|
+
categories?: string[]; // category names, e.g. ["security", "best_practices"]
|
|
233
|
+
idRanges?: IdRange[]; // numeric ranges, e.g. { prefix: "E", start: 3000, end: 3099 }
|
|
234
|
+
idPatterns?: string[]; // regex patterns matched against rule IDs
|
|
235
|
+
resourceIds?: ResourceIdFilter[]; // a rule (or every rule) on a logical resource ID
|
|
236
|
+
logicalIds?: LogicalIdFilter[]; // a rule (or every rule) on a named template entity
|
|
149
237
|
resourceTypes?: ResourceTypeFilter[]; // a rule (or every rule) on a resource type
|
|
150
|
-
services?: ServiceFilter[];
|
|
238
|
+
services?: ServiceFilter[]; // a rule (or every rule) on a service, e.g. "AWS::AutoScaling"
|
|
151
239
|
}
|
|
152
240
|
|
|
153
241
|
// resourceIds / logicalIds / resourceTypes / services each carry an optional ruleId:
|
|
@@ -168,7 +256,7 @@ the same value). An optional `entityType` scopes a `LogicalIdFilter` to entities
|
|
|
168
256
|
|
|
169
257
|
### PseudoParameterOverrides
|
|
170
258
|
|
|
171
|
-
Override CloudFormation pseudo-parameters used during intrinsic function resolution. All fields optional - when
|
|
259
|
+
Override CloudFormation pseudo-parameters used during intrinsic function resolution. All fields are optional - when
|
|
172
260
|
`undefined`, the engine uses built-in defaults (e.g. region defaults to `us-east-1`).
|
|
173
261
|
|
|
174
262
|
```typescript
|
|
@@ -183,14 +271,6 @@ interface PseudoParameterOverrides {
|
|
|
183
271
|
}
|
|
184
272
|
```
|
|
185
273
|
|
|
186
|
-
## TemplateFile
|
|
187
|
-
|
|
188
|
-
Wraps a filesystem path. Engines read the file bytes internally.
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
const template = new TemplateFile("path/to/template.yaml");
|
|
192
|
-
```
|
|
193
|
-
|
|
194
274
|
## TemplateModel
|
|
195
275
|
|
|
196
276
|
Parses a template into the resolved `SemanticModel` for direct inspection - the same model the engines evaluate rules
|
|
@@ -207,58 +287,135 @@ const model = new TemplateModel(new TemplateFile("template.yaml"));
|
|
|
207
287
|
| `outputs()` | `Record<string, ResolvedOutput>` | Outputs with resolved values and export names |
|
|
208
288
|
| `conditions()` | `string[]` | Condition names defined in the template |
|
|
209
289
|
| `transforms()` | `string[]` | Transform declarations (e.g. `AWS::Serverless-2016-10-31`) |
|
|
210
|
-
| `formatVersion()` | `string
|
|
211
|
-
| `description()` | `string
|
|
290
|
+
| `formatVersion()` | `string \| undefined` | `AWSTemplateFormatVersion` value |
|
|
291
|
+
| `description()` | `string \| undefined` | Template description |
|
|
212
292
|
| `toDiagnosticModel()` | `DiagnosticModel` | Full diagnostic model including reference graph, condition implications, and resolution sources |
|
|
213
|
-
| `sourceLocation(path)` | `SourceSpan
|
|
214
|
-
| `free()` | `void` | Releases
|
|
293
|
+
| `sourceLocation(path)` | `SourceSpan \| null` | Source line/column span for a JSON path (e.g. `Resources/MyBucket/Properties/BucketName`) |
|
|
294
|
+
| `free()` | `void` | Releases the model's off-heap memory; the model must not be used afterwards |
|
|
215
295
|
|
|
216
296
|
## SchemaValidator
|
|
217
297
|
|
|
218
|
-
Runs schema validation independently from the rule engines. Checks each resource against compiled CloudFormation
|
|
219
|
-
provider schemas and produces `FATAL`-severity diagnostics for structural violations.
|
|
298
|
+
Runs schema validation independently from the rule engines. Checks each resource against the compiled CloudFormation
|
|
299
|
+
provider schemas and produces `FATAL`-severity diagnostics for structural violations. The optional constructor argument
|
|
300
|
+
is the same `SchemaValidatorConfig` accepted by `EngineConfig`; omitting it uses only the bundled schemas.
|
|
220
301
|
|
|
221
302
|
```typescript
|
|
222
303
|
const validator = new SchemaValidator();
|
|
223
|
-
|
|
224
|
-
validator.
|
|
304
|
+
try {
|
|
305
|
+
const diagnostics = validator.validate(new TemplateFile("template.yaml"), "us-east-1");
|
|
306
|
+
} finally {
|
|
307
|
+
validator.free();
|
|
308
|
+
}
|
|
225
309
|
```
|
|
226
310
|
|
|
227
|
-
| Method
|
|
228
|
-
|
|
229
|
-
| `
|
|
230
|
-
| `
|
|
231
|
-
| `
|
|
232
|
-
| `
|
|
311
|
+
| Method | Returns | Description |
|
|
312
|
+
|--------------------------------|-------------------|------------------------------------------------------------------------------------------------------------------|
|
|
313
|
+
| `new SchemaValidator(config?)` | `SchemaValidator` | Constructs a validator; an omitted `SchemaValidatorConfig` uses only the bundled schemas |
|
|
314
|
+
| `validate(template, region?)` | `Diagnostic[]` | Schema diagnostics at `STANDARD` detail - the enrichment fields are absent. `region` defaults to `"us-east-1"`. |
|
|
315
|
+
| `listRules()` | `RuleInfo[]` | Schema rule metadata |
|
|
316
|
+
| `schemaCount()` | `number` | Number of compiled provider schemas |
|
|
317
|
+
| `free()` | `void` | Releases the validator's off-heap memory; the validator must not be used afterwards |
|
|
318
|
+
|
|
319
|
+
## AWS CLI command validation
|
|
320
|
+
|
|
321
|
+
`validateAwsCliCommand` models an AWS CLI (or SDK) API call as CloudFormation resource state and validates it offline
|
|
322
|
+
before it is sent. It classifies the operation, maps it to a CloudFormation resource type through a closed, generated
|
|
323
|
+
adapter catalog, synthesizes a template from the supplied parameters, and runs the normal template pipeline on it. A
|
|
324
|
+
`TemplateBody` parameter of a CloudFormation operation is validated as-is. Any request that cannot be modeled exactly -
|
|
325
|
+
an unregistered operation, a parameter without a lossless property mapping, or a value outside a CloudFormation
|
|
326
|
+
constraint the API itself does not enforce - is skipped with a reason, never guessed.
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
import { AwsCliCommand, RegoEngine } from "@aws/cloudformation-validate";
|
|
330
|
+
|
|
331
|
+
const engine = new RegoEngine();
|
|
332
|
+
try {
|
|
333
|
+
const request = new AwsCliCommand("s3", "CreateBucket", { Bucket: "example-bucket" });
|
|
334
|
+
const validation = engine.validateAwsCliCommand(request);
|
|
335
|
+
if (validation.status === "VALIDATED") {
|
|
336
|
+
for (const d of validation.report!.diagnostics) {
|
|
337
|
+
console.log(`[${d.severity}] ${d.ruleId}: ${d.message}`);
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
340
|
+
console.log(`skipped (${validation.operationKind}): ${validation.reason}`);
|
|
341
|
+
}
|
|
342
|
+
} finally {
|
|
343
|
+
engine.free();
|
|
344
|
+
}
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
class AwsCliCommand {
|
|
349
|
+
constructor(
|
|
350
|
+
serviceName: string, // canonical botocore service name, e.g. "s3" or "cloudformation"
|
|
351
|
+
operationName: string, // API operation name, e.g. "CreateBucket"
|
|
352
|
+
parameters: Record<string, unknown>, // request parameters (a plain object with string keys)
|
|
353
|
+
options?: AwsCliCommandOptions,
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
interface AwsCliCommandOptions {
|
|
358
|
+
servicePrefix?: string; // signing prefix; context only
|
|
359
|
+
httpMethod?: string; // classification hint ("GET"/"HEAD"/"DELETE") for unrecognized verbs
|
|
360
|
+
isReadOnly?: boolean; // true classifies the operation as READ_ONLY
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
- `serviceName` is matched case-insensitively. Signing names, endpoint aliases, and ARN prefixes are never resolved;
|
|
365
|
+
translate an SDK's service identity first.
|
|
366
|
+
- `parameters` accepts nested plain objects and arrays, strings, numbers, `bigint`, booleans, `null`, `Uint8Array`,
|
|
367
|
+
and `Date` (serialized as ISO 8601). Any other value is carried as an explicit unsupported marker, and because
|
|
368
|
+
synthesis is all-or-nothing the request is then skipped with a reason naming the offending parameter - no parameter
|
|
369
|
+
is ever silently dropped.
|
|
370
|
+
|
|
371
|
+
The result is an `AwsCliCommandValidation`:
|
|
372
|
+
|
|
373
|
+
| Field | Description |
|
|
374
|
+
|------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|
375
|
+
| `operationKind` | `AwsCliOperationKind`: `"READ_ONLY"`, `"CLOUD_FORMATION_CREATE"`, `"CLOUD_FORMATION_UPDATE"`, `"CLOUD_FORMATION_DELETE"`, `"DATA_PLANE_MUTATION"`, or `"UNMAPPED_MUTATION"` |
|
|
376
|
+
| `status` | `AwsCliCommandValidationStatus`: `"VALIDATED"` when the modeled template ran through the pipeline, `"SKIPPED"` otherwise |
|
|
377
|
+
| `templateSource` | `AwsCliTemplateSource \| null`: `"TEMPLATE_BODY"`, `"CLOUD_CONTROL_DESIRED_STATE"`, `"SYNTHESIZED_CREATE"`, or `"SYNTHESIZED_UPDATE"`; `null` when skipped |
|
|
378
|
+
| `resourceTypes` | `string[]` - CloudFormation resource types the operation maps to |
|
|
379
|
+
| `reason` | `string` - why the request was validated or skipped |
|
|
380
|
+
| `report` | `ValidationReport \| null` - present when `"VALIDATED"`. The configuration is fixed: `STANDARD` detail level and a `WARN` severity floor |
|
|
381
|
+
| `template` | `Uint8Array \| null` - the exact template bytes that were validated (the caller's `TemplateBody` unchanged, or the synthesized JSON); `null` when skipped |
|
|
382
|
+
|
|
383
|
+
The full contract - the adapter catalog, all-or-nothing mapping, and which rules are dropped for synthesized state -
|
|
384
|
+
is documented in [validation-engine/API.md](../validation-engine/API.md#validating-an-aws-cli-command).
|
|
233
385
|
|
|
234
386
|
## Report Types
|
|
235
387
|
|
|
236
|
-
###
|
|
388
|
+
### ValidationReport
|
|
389
|
+
|
|
390
|
+
`validateTemplate` always returns a `ValidationReport` - a template syntax failure is returned as a report with
|
|
391
|
+
status `"ERROR"` and an `F1101` diagnostic; only infrastructure or engine failures throw:
|
|
237
392
|
|
|
238
393
|
```typescript
|
|
239
|
-
interface
|
|
394
|
+
interface ValidationReport {
|
|
240
395
|
filePath: string;
|
|
241
396
|
status: "OK" | "ANALYSIS_INCOMPLETE" | "ERROR"; // ERROR is a pipeline failure; ANALYSIS_INCOMPLETE may omit findings
|
|
242
397
|
version: string;
|
|
243
398
|
metadata: ReportMetadata;
|
|
244
399
|
performance: PerformanceMetrics;
|
|
245
|
-
diagnostics:
|
|
400
|
+
diagnostics: Diagnostic[];
|
|
246
401
|
}
|
|
247
402
|
```
|
|
248
403
|
|
|
249
|
-
|
|
250
|
-
`ruleDescription`, `phase` (`PARSE` | `SCHEMA` | `LINT`), and `context` (`ViolationContext` with
|
|
251
|
-
`
|
|
404
|
+
Every finding is a `Diagnostic` (see [Diagnostic](#diagnostic)). Its enrichment fields - `documentationUrl`,
|
|
405
|
+
`ruleDescription`, `phase` (`PARSE` | `SCHEMA` | `LINT`), and `context` (`ViolationContext` with `actualValue`,
|
|
406
|
+
`expectedConstraint`, `resolutionSource`, etc.) - are populated only at `detailLevel` `"DETAILED"` (the default);
|
|
407
|
+
validating at `"STANDARD"` leaves them absent, keeping the base diagnostic fields.
|
|
252
408
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
409
|
+
`metadata` carries the summary counts, the number of suppressed diagnostics, the resources scanned and rules
|
|
410
|
+
evaluated, the strict flag and severity threshold used, and optional budget-exhaustion records. Each budget-exhaustion
|
|
411
|
+
record retains a stable machine-readable kind and also includes a human-readable description sentence, the numeric
|
|
412
|
+
limit, and whether that specific exhaustion makes analysis incomplete. `requiredPropertyCombinations` is context-only,
|
|
413
|
+
so its `analysisIncomplete` value is `false` and the report can remain `"OK"`.
|
|
257
414
|
|
|
258
|
-
###
|
|
415
|
+
### Diagnostic
|
|
259
416
|
|
|
260
417
|
```typescript
|
|
261
|
-
interface
|
|
418
|
+
interface Diagnostic {
|
|
262
419
|
ruleId: string; // e.g. "E3012", "F1001", "W3010"
|
|
263
420
|
severity: Severity; // "FATAL" | "ERROR" | "WARN" | "INFO" | "DEBUG"
|
|
264
421
|
message: string;
|
|
@@ -273,6 +430,11 @@ interface StandardDiagnostic {
|
|
|
273
430
|
endColumn?: number;
|
|
274
431
|
relatedResources?: RelatedResource[];
|
|
275
432
|
conditionScenario?: Record<string, boolean>; // condition truth assignment that triggers this diagnostic
|
|
433
|
+
// Enrichment fields: populated at detailLevel "DETAILED" (the default), absent at "STANDARD".
|
|
434
|
+
documentationUrl?: string;
|
|
435
|
+
ruleDescription?: string;
|
|
436
|
+
phase?: "PARSE" | "SCHEMA" | "LINT"; // pipeline stage that produced the finding
|
|
437
|
+
context?: ViolationContext; // actualValue, expectedConstraint, resolutionSource, etc.
|
|
276
438
|
}
|
|
277
439
|
|
|
278
440
|
// The named template entity a diagnostic is attributed to. The entity type is the
|
|
@@ -286,3 +448,6 @@ interface Entity {
|
|
|
286
448
|
type EntityType = "Resource" | "Parameter" | "Output" | "Mapping" | "Metadata"
|
|
287
449
|
| "Rule" | "Condition" | "Transform" | "FormatVersion" | "Description";
|
|
288
450
|
```
|
|
451
|
+
|
|
452
|
+
`Severity`, `RuleOrigin`, and `DetailLevel` are string-literal union types (`"WARN"`, `"GUARD"`, `"STANDARD"`, ...), as
|
|
453
|
+
is the report `status` (`"OK"`, `"ANALYSIS_INCOMPLETE"`, `"ERROR"`).
|
package/THIRD-PARTY-LICENSES.txt
CHANGED
|
@@ -2380,6 +2380,85 @@ See the License for the specific language governing permissions and
|
|
|
2380
2380
|
limitations under the License.
|
|
2381
2381
|
|
|
2382
2382
|
|
|
2383
|
+
******************************
|
|
2384
|
+
|
|
2385
|
+
cloudformation-validate-composite-engine
|
|
2386
|
+
1.10.0 <https://github.com/aws-cloudformation/cloudformation-validate>
|
|
2387
|
+
Apache License
|
|
2388
|
+
Version 2.0, January 2004
|
|
2389
|
+
http://www.apache.org/licenses/
|
|
2390
|
+
|
|
2391
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
2392
|
+
|
|
2393
|
+
1. Definitions.
|
|
2394
|
+
|
|
2395
|
+
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
|
|
2396
|
+
|
|
2397
|
+
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
|
|
2398
|
+
|
|
2399
|
+
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
|
|
2400
|
+
|
|
2401
|
+
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
|
|
2402
|
+
|
|
2403
|
+
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
|
|
2404
|
+
|
|
2405
|
+
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
|
|
2406
|
+
|
|
2407
|
+
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
|
|
2408
|
+
|
|
2409
|
+
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
|
|
2410
|
+
|
|
2411
|
+
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
|
|
2412
|
+
|
|
2413
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
|
|
2414
|
+
|
|
2415
|
+
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
|
|
2416
|
+
|
|
2417
|
+
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
|
|
2418
|
+
|
|
2419
|
+
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
|
|
2420
|
+
|
|
2421
|
+
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
|
|
2422
|
+
|
|
2423
|
+
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
|
|
2424
|
+
|
|
2425
|
+
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
|
|
2426
|
+
|
|
2427
|
+
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
|
|
2428
|
+
|
|
2429
|
+
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
|
|
2430
|
+
|
|
2431
|
+
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
|
|
2432
|
+
|
|
2433
|
+
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
|
|
2434
|
+
|
|
2435
|
+
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
|
|
2436
|
+
|
|
2437
|
+
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
|
|
2438
|
+
|
|
2439
|
+
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
|
|
2440
|
+
|
|
2441
|
+
END OF TERMS AND CONDITIONS
|
|
2442
|
+
|
|
2443
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
2444
|
+
|
|
2445
|
+
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
|
|
2446
|
+
|
|
2447
|
+
Copyright [yyyy] [name of copyright owner]
|
|
2448
|
+
|
|
2449
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
2450
|
+
you may not use this file except in compliance with the License.
|
|
2451
|
+
You may obtain a copy of the License at
|
|
2452
|
+
|
|
2453
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
2454
|
+
|
|
2455
|
+
Unless required by applicable law or agreed to in writing, software
|
|
2456
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
2457
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
2458
|
+
See the License for the specific language governing permissions and
|
|
2459
|
+
limitations under the License.
|
|
2460
|
+
|
|
2461
|
+
|
|
2383
2462
|
******************************
|
|
2384
2463
|
|
|
2385
2464
|
colored
|