@intentius/chant-lexicon-aws 0.46.0 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/read-client.d.ts +10 -2
- package/dist/api/read-client.d.ts.map +1 -1
- package/dist/codegen/generate-lexicon.d.ts +5 -0
- package/dist/codegen/generate-lexicon.d.ts.map +1 -1
- package/dist/components/host-delivery.d.ts +4 -3
- package/dist/components/host-delivery.d.ts.map +1 -1
- package/dist/composites/agentcore-agent.d.ts +26 -1
- package/dist/composites/agentcore-agent.d.ts.map +1 -1
- package/dist/composites/bucket-deployment.d.ts +82 -0
- package/dist/composites/bucket-deployment.d.ts.map +1 -0
- package/dist/composites/dynamodb-table.d.ts +45 -0
- package/dist/composites/dynamodb-table.d.ts.map +1 -0
- package/dist/composites/ec2-instance-bundle.d.ts +61 -0
- package/dist/composites/ec2-instance-bundle.d.ts.map +1 -0
- package/dist/composites/ecr-repository.d.ts +49 -0
- package/dist/composites/ecr-repository.d.ts.map +1 -0
- package/dist/composites/fargate-service.d.ts +16 -0
- package/dist/composites/fargate-service.d.ts.map +1 -1
- package/dist/composites/index.d.ts +16 -2
- package/dist/composites/index.d.ts.map +1 -1
- package/dist/composites/monitoring-stack.d.ts +99 -0
- package/dist/composites/monitoring-stack.d.ts.map +1 -0
- package/dist/composites/nlb-service.d.ts +48 -0
- package/dist/composites/nlb-service.d.ts.map +1 -0
- package/dist/composites/step-functions-workflow.d.ts +36 -0
- package/dist/composites/step-functions-workflow.d.ts.map +1 -0
- package/dist/deep-observe.d.ts +45 -0
- package/dist/deep-observe.d.ts.map +1 -1
- package/dist/deep-topology.d.ts +104 -0
- package/dist/deep-topology.d.ts.map +1 -0
- package/dist/effect-receipt-row.d.ts +92 -0
- package/dist/effect-receipt-row.d.ts.map +1 -0
- package/dist/index.d.ts +7 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/integrity.json +14 -6
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/post-synth/cf-refs.d.ts +17 -0
- package/dist/lint/post-synth/cf-refs.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/waw016.d.ts +10 -2
- package/dist/lint/post-synth/waw016.d.ts.map +1 -1
- package/dist/lint/post-synth/waw061.d.ts +19 -0
- package/dist/lint/post-synth/waw061.d.ts.map +1 -0
- package/dist/lint/post-synth/waw062.d.ts +19 -0
- package/dist/lint/post-synth/waw062.d.ts.map +1 -0
- package/dist/lint/post-synth/waw063.d.ts +35 -0
- package/dist/lint/post-synth/waw063.d.ts.map +1 -0
- package/dist/lint/post-synth/waw064.d.ts +17 -0
- package/dist/lint/post-synth/waw064.d.ts.map +1 -0
- package/dist/lint/post-synth/waw065.d.ts +23 -0
- package/dist/lint/post-synth/waw065.d.ts.map +1 -0
- package/dist/lint/post-synth/waw066.d.ts +25 -0
- package/dist/lint/post-synth/waw066.d.ts.map +1 -0
- package/dist/lint/post-synth/waw067.d.ts +24 -0
- package/dist/lint/post-synth/waw067.d.ts.map +1 -0
- package/dist/lint/post-synth/waw068.d.ts +20 -0
- package/dist/lint/post-synth/waw068.d.ts.map +1 -0
- package/dist/manifest.json +1 -1
- package/dist/meta.json +34 -0
- package/dist/okf/index.md +8 -0
- package/dist/okf/rules/WAW061.md +17 -0
- package/dist/okf/rules/WAW062.md +27 -0
- package/dist/okf/rules/WAW063.md +19 -0
- package/dist/okf/rules/WAW064.md +18 -0
- package/dist/okf/rules/WAW065.md +25 -0
- package/dist/okf/rules/WAW066.md +22 -0
- package/dist/okf/rules/WAW067.md +20 -0
- package/dist/okf/rules/WAW068.md +19 -0
- package/dist/okf/types/Action.md +1 -0
- package/dist/okf/types/AutoScalingGroup.md +1 -0
- package/dist/okf/types/Bucket.md +1 -0
- package/dist/okf/types/EC2Route.md +2 -0
- package/dist/okf/types/ECRRepository.md +1 -0
- package/dist/okf/types/Function.md +1 -0
- package/dist/okf/types/IamPolicy.md +1 -0
- package/dist/okf/types/InternetGateway.md +4 -0
- package/dist/okf/types/LaunchTemplate.md +1 -0
- package/dist/okf/types/LoadBalancer.md +1 -0
- package/dist/okf/types/ManagedPolicy.md +2 -0
- package/dist/okf/types/Map.md +5 -0
- package/dist/okf/types/NatGateway.md +4 -0
- package/dist/okf/types/Role.md +2 -0
- package/dist/okf/types/RouteTable.md +4 -0
- package/dist/okf/types/SecurityGroup.md +1 -0
- package/dist/okf/types/StateMachine.md +4 -0
- package/dist/okf/types/Subnet.md +6 -0
- package/dist/okf/types/SubnetRouteTableAssociation.md +5 -0
- package/dist/okf/types/Table.md +4 -0
- package/dist/okf/types/TransitGateway.md +6 -0
- package/dist/okf/types/TransitGatewayAttachment.md +4 -0
- package/dist/okf/types/TransitGatewayPeeringAttachment.md +4 -0
- package/dist/okf/types/TransitGatewayRoute.md +5 -0
- package/dist/okf/types/TransitGatewayRouteTable.md +4 -0
- package/dist/okf/types/TransitGatewayRouteTableAssociation.md +4 -0
- package/dist/okf/types/TransitGatewayRouteTablePropagation.md +4 -0
- package/dist/okf/types/TransitGatewayVpcAttachment.md +4 -0
- package/dist/okf/types/Type.md +8 -0
- package/dist/okf/types/VPNConnection.md +4 -0
- package/dist/okf/types/VPNGateway.md +4 -0
- package/dist/okf/types/Vpc.md +1 -0
- package/dist/op/activities/index.d.ts +6 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/builders.d.ts +47 -0
- package/dist/op/builders.d.ts.map +1 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/receipt-store.d.ts +109 -0
- package/dist/receipt-store.d.ts.map +1 -0
- package/dist/rules/cf-refs.ts +40 -0
- package/dist/rules/waw016.ts +37 -16
- package/dist/rules/waw061.ts +67 -0
- package/dist/rules/waw062.ts +0 -0
- package/dist/rules/waw063.ts +0 -0
- package/dist/rules/waw064.ts +52 -0
- package/dist/rules/waw065.ts +110 -0
- package/dist/rules/waw066.ts +155 -0
- package/dist/rules/waw067.ts +114 -0
- package/dist/rules/waw068.ts +78 -0
- package/dist/serializer.d.ts.map +1 -1
- package/dist/skills/chant-aws-carve-terraform.md +26 -23
- package/dist/spec/parse.d.ts +7 -0
- package/dist/spec/parse.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/api/read-client.test.ts +9 -0
- package/src/api/read-client.ts +15 -2
- package/src/codegen/fallback.ts +1 -0
- package/src/codegen/generate-lexicon.ts +6 -0
- package/src/codegen/sam.ts +9 -0
- package/src/components/host-delivery.ts +4 -3
- package/src/composites/agentcore-agent.ts +35 -13
- package/src/composites/bucket-deployment.test.ts +84 -0
- package/src/composites/bucket-deployment.ts +153 -0
- package/src/composites/composites.test.ts +325 -0
- package/src/composites/dynamodb-table.test.ts +154 -0
- package/src/composites/dynamodb-table.ts +124 -0
- package/src/composites/ec2-instance-bundle.ts +134 -0
- package/src/composites/ecr-repository.test.ts +118 -0
- package/src/composites/ecr-repository.ts +117 -0
- package/src/composites/fargate-service.ts +19 -3
- package/src/composites/index.ts +21 -2
- package/src/composites/monitoring-stack.test.ts +130 -0
- package/src/composites/monitoring-stack.ts +164 -0
- package/src/composites/nlb-service.ts +117 -0
- package/src/composites/step-functions-workflow.ts +127 -0
- package/src/deep-observe.test.ts +201 -1
- package/src/deep-observe.ts +204 -0
- package/src/deep-topology.test.ts +392 -0
- package/src/deep-topology.ts +237 -0
- package/src/effect-receipt-row.test.ts +164 -0
- package/src/effect-receipt-row.ts +147 -0
- package/src/generated/lexicon-aws.json +34 -0
- package/src/index.ts +36 -7
- package/src/lint/audit-catalog.ts +16 -0
- package/src/lint/post-synth/cf-refs.ts +40 -0
- package/src/lint/post-synth/index.ts +16 -0
- package/src/lint/post-synth/waw016.test.ts +61 -4
- package/src/lint/post-synth/waw016.ts +37 -16
- package/src/lint/post-synth/waw061.test.ts +99 -0
- package/src/lint/post-synth/waw061.ts +67 -0
- package/src/lint/post-synth/waw062.test.ts +109 -0
- package/src/lint/post-synth/waw062.ts +0 -0
- package/src/lint/post-synth/waw063.test.ts +220 -0
- package/src/lint/post-synth/waw063.ts +0 -0
- package/src/lint/post-synth/waw064.test.ts +79 -0
- package/src/lint/post-synth/waw064.ts +52 -0
- package/src/lint/post-synth/waw065.test.ts +90 -0
- package/src/lint/post-synth/waw065.ts +110 -0
- package/src/lint/post-synth/waw066.test.ts +108 -0
- package/src/lint/post-synth/waw066.ts +155 -0
- package/src/lint/post-synth/waw067.test.ts +79 -0
- package/src/lint/post-synth/waw067.ts +114 -0
- package/src/lint/post-synth/waw068.test.ts +74 -0
- package/src/lint/post-synth/waw068.ts +78 -0
- package/src/lsp/hover.ts +17 -2
- package/src/op/activities/index.ts +15 -0
- package/src/op/builders.test.ts +61 -0
- package/src/op/builders.ts +72 -0
- package/src/plugin.ts +41 -10
- package/src/receipt-store.test.ts +204 -0
- package/src/receipt-store.ts +315 -0
- package/src/serializer.ts +105 -2
- package/src/skills/chant-aws-carve-terraform.md +26 -23
- package/src/spec/parse.test.ts +74 -0
- package/src/spec/parse.ts +26 -6
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep-read sources for the EC2 topology types (#1269).
|
|
3
|
+
*
|
|
4
|
+
* chant's distinguishing answers are folds over topology: `internetFacing`
|
|
5
|
+
* resolves subnet -> route table -> internet gateway, `effectiveIngress`
|
|
6
|
+
* resolves rules across attached security groups, and the default-VPC
|
|
7
|
+
* classification (`defaults.ts`) reads the provider's own markers. The inputs
|
|
8
|
+
* to all of them are the types this file covers — with only the original four
|
|
9
|
+
* kinds readable, a deep snapshot of an EC2 estate carried almost no
|
|
10
|
+
* properties, and a snapshot-backed query could answer identity questions but
|
|
11
|
+
* not a single fold question.
|
|
12
|
+
*
|
|
13
|
+
* Two sources, chosen per type:
|
|
14
|
+
*
|
|
15
|
+
* - The container types (VPC, subnet, route table, internet gateway) read
|
|
16
|
+
* through the EC2 describes. The fold facts live there and nowhere else:
|
|
17
|
+
* `IsDefault`, `DefaultForAz` and a subnet's live `MapPublicIpOnLaunch` are
|
|
18
|
+
* not part of the CloudFormation resource model, so Cloud Control cannot
|
|
19
|
+
* report them. The describes are also bulk (one call per type for the whole
|
|
20
|
+
* stack) and are implemented by the emulators that do not serve Cloud
|
|
21
|
+
* Control's `GetResource`.
|
|
22
|
+
*
|
|
23
|
+
* - The join types (route, association, gateway attachment) and the two whose
|
|
24
|
+
* describes do not fit a flat bulk join (instance rows nest inside
|
|
25
|
+
* reservations; launch-template data lives in a separate versions call) read
|
|
26
|
+
* through Cloud Control, which returns their model in the declared side's
|
|
27
|
+
* own shape.
|
|
28
|
+
*
|
|
29
|
+
* Each type carries its normalization entries alongside (#1269's note: adding
|
|
30
|
+
* a type without them trades a hole for a false positive, which is worse).
|
|
31
|
+
* They are merged into the tables in `deep-observe.ts`.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import type { DeepSource } from "./deep-observe";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* `describe-vpcs` -> the `AWS::EC2::VPC` resource model, plus `IsDefault`.
|
|
38
|
+
*
|
|
39
|
+
* `IsDefault` is the provider's own marker for the VPC nobody wrote — the fact
|
|
40
|
+
* the default classification reads — and it exists only on this surface.
|
|
41
|
+
* Carried even though the model does not name it; the diff subtracts it as a
|
|
42
|
+
* service default (`false`, gated on source silence) so a CloudFormation-made
|
|
43
|
+
* VPC does not report it as undeclared drift.
|
|
44
|
+
*/
|
|
45
|
+
export function vpcToModel(row: Record<string, unknown>): Record<string, unknown> {
|
|
46
|
+
return {
|
|
47
|
+
// The schema's readOnlyProperties prune the id after the ownership check.
|
|
48
|
+
...(typeof row.VpcId === "string" ? { VpcId: row.VpcId } : {}),
|
|
49
|
+
...(typeof row.CidrBlock === "string" ? { CidrBlock: row.CidrBlock } : {}),
|
|
50
|
+
...(typeof row.InstanceTenancy === "string" ? { InstanceTenancy: row.InstanceTenancy } : {}),
|
|
51
|
+
...(typeof row.IsDefault === "boolean" ? { IsDefault: row.IsDefault } : {}),
|
|
52
|
+
...nonEmptyTags(row),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* `describe-subnets` -> the `AWS::EC2::Subnet` resource model, plus
|
|
58
|
+
* `DefaultForAz`.
|
|
59
|
+
*
|
|
60
|
+
* `MapPublicIpOnLaunch` is half of `internetFacing`; `DefaultForAz` is the
|
|
61
|
+
* provider's default-subnet marker, off the model for the same reason as a
|
|
62
|
+
* VPC's `IsDefault` and handled the same way.
|
|
63
|
+
*/
|
|
64
|
+
export function subnetToModel(row: Record<string, unknown>): Record<string, unknown> {
|
|
65
|
+
return {
|
|
66
|
+
...(typeof row.SubnetId === "string" ? { SubnetId: row.SubnetId } : {}),
|
|
67
|
+
...(typeof row.VpcId === "string" ? { VpcId: row.VpcId } : {}),
|
|
68
|
+
...(typeof row.CidrBlock === "string" ? { CidrBlock: row.CidrBlock } : {}),
|
|
69
|
+
...(typeof row.AvailabilityZone === "string" ? { AvailabilityZone: row.AvailabilityZone } : {}),
|
|
70
|
+
...(typeof row.AvailabilityZoneId === "string" ? { AvailabilityZoneId: row.AvailabilityZoneId } : {}),
|
|
71
|
+
...(typeof row.MapPublicIpOnLaunch === "boolean" ? { MapPublicIpOnLaunch: row.MapPublicIpOnLaunch } : {}),
|
|
72
|
+
...(typeof row.AssignIpv6AddressOnCreation === "boolean"
|
|
73
|
+
? { AssignIpv6AddressOnCreation: row.AssignIpv6AddressOnCreation }
|
|
74
|
+
: {}),
|
|
75
|
+
...(typeof row.EnableDns64 === "boolean" ? { EnableDns64: row.EnableDns64 } : {}),
|
|
76
|
+
...(typeof row.Ipv6Native === "boolean" ? { Ipv6Native: row.Ipv6Native } : {}),
|
|
77
|
+
...(typeof row.DefaultForAz === "boolean" ? { DefaultForAz: row.DefaultForAz } : {}),
|
|
78
|
+
...nonEmptyTags(row),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* `describe-route-tables` -> the `AWS::EC2::RouteTable` resource model.
|
|
84
|
+
*
|
|
85
|
+
* The row also carries `Routes` and `Associations`, and this mapping drops
|
|
86
|
+
* them on purpose: a template declares each route as its own
|
|
87
|
+
* `AWS::EC2::Route` and each association as its own
|
|
88
|
+
* `AWS::EC2::SubnetRouteTableAssociation`, both covered below, so carrying
|
|
89
|
+
* them here would report every declared route twice — once as an undeclared
|
|
90
|
+
* array on the table and once through its own resource.
|
|
91
|
+
*/
|
|
92
|
+
export function routeTableToModel(row: Record<string, unknown>): Record<string, unknown> {
|
|
93
|
+
return {
|
|
94
|
+
...(typeof row.RouteTableId === "string" ? { RouteTableId: row.RouteTableId } : {}),
|
|
95
|
+
...(typeof row.VpcId === "string" ? { VpcId: row.VpcId } : {}),
|
|
96
|
+
...nonEmptyTags(row),
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** `describe-internet-gateways` -> the `AWS::EC2::InternetGateway` model, which is tags and nothing else. */
|
|
101
|
+
export function internetGatewayToModel(row: Record<string, unknown>): Record<string, unknown> {
|
|
102
|
+
return {
|
|
103
|
+
...(typeof row.InternetGatewayId === "string" ? { InternetGatewayId: row.InternetGatewayId } : {}),
|
|
104
|
+
...nonEmptyTags(row),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* An empty tag set is the absence of tags, not a value. EC2 always sends the
|
|
110
|
+
* key, so carrying it through reports `Tags: <undeclared> -> []` on every
|
|
111
|
+
* untagged resource — agreement rendered as drift. Same rule as the
|
|
112
|
+
* security-group mapping.
|
|
113
|
+
*/
|
|
114
|
+
function nonEmptyTags(row: Record<string, unknown>): Record<string, unknown> {
|
|
115
|
+
return Array.isArray(row.Tags) && row.Tags.length > 0 ? { Tags: row.Tags } : {};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* The topology types' entries for `DEEP_SOURCES`.
|
|
120
|
+
*
|
|
121
|
+
* The routing-chain joins are addressed by their physical id — for a
|
|
122
|
+
* registry-backed type CloudFormation's physical id *is* the Cloud Control
|
|
123
|
+
* identifier (`rtb-…|0.0.0.0/0` for a route) — so Cloud Control's
|
|
124
|
+
* one-get-per-resource shape fits them exactly and returns the declared
|
|
125
|
+
* model's own field names.
|
|
126
|
+
*/
|
|
127
|
+
export const EC2_TOPOLOGY_SOURCES: Record<string, DeepSource> = {
|
|
128
|
+
"AWS::EC2::VPC": {
|
|
129
|
+
via: "ec2",
|
|
130
|
+
argv: ["ec2", "describe-vpcs"],
|
|
131
|
+
idFlag: "--vpc-ids",
|
|
132
|
+
key: "Vpcs",
|
|
133
|
+
id: "VpcId",
|
|
134
|
+
toModel: vpcToModel,
|
|
135
|
+
},
|
|
136
|
+
"AWS::EC2::Subnet": {
|
|
137
|
+
via: "ec2",
|
|
138
|
+
argv: ["ec2", "describe-subnets"],
|
|
139
|
+
idFlag: "--subnet-ids",
|
|
140
|
+
key: "Subnets",
|
|
141
|
+
id: "SubnetId",
|
|
142
|
+
toModel: subnetToModel,
|
|
143
|
+
},
|
|
144
|
+
"AWS::EC2::RouteTable": {
|
|
145
|
+
via: "ec2",
|
|
146
|
+
argv: ["ec2", "describe-route-tables"],
|
|
147
|
+
idFlag: "--route-table-ids",
|
|
148
|
+
key: "RouteTables",
|
|
149
|
+
id: "RouteTableId",
|
|
150
|
+
toModel: routeTableToModel,
|
|
151
|
+
},
|
|
152
|
+
"AWS::EC2::InternetGateway": {
|
|
153
|
+
via: "ec2",
|
|
154
|
+
argv: ["ec2", "describe-internet-gateways"],
|
|
155
|
+
idFlag: "--internet-gateway-ids",
|
|
156
|
+
key: "InternetGateways",
|
|
157
|
+
id: "InternetGatewayId",
|
|
158
|
+
toModel: internetGatewayToModel,
|
|
159
|
+
},
|
|
160
|
+
// The `0.0.0.0/0` -> igw edge `internetFacing` walks.
|
|
161
|
+
"AWS::EC2::Route": { via: "cloud-control" },
|
|
162
|
+
// Subnet -> route table.
|
|
163
|
+
"AWS::EC2::SubnetRouteTableAssociation": { via: "cloud-control" },
|
|
164
|
+
// Igw -> VPC.
|
|
165
|
+
"AWS::EC2::VPCGatewayAttachment": { via: "cloud-control" },
|
|
166
|
+
// Subnet, security groups, launch template — the instance end of both folds.
|
|
167
|
+
"AWS::EC2::Instance": { via: "cloud-control" },
|
|
168
|
+
// The indirect security-group hop `effectiveIngress` resolves through.
|
|
169
|
+
"AWS::EC2::LaunchTemplate": { via: "cloud-control" },
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Service defaults for the topology types, merged into
|
|
174
|
+
* `AWS_SERVICE_DEFAULTS`. Subtracted on the live side only where source never
|
|
175
|
+
* declared the property — which is how the fold facts (`IsDefault`,
|
|
176
|
+
* `DefaultForAz`, a live `MapPublicIpOnLaunch`) stay in the snapshot for a
|
|
177
|
+
* query to read while never surfacing as drift on a resource CloudFormation
|
|
178
|
+
* itself created.
|
|
179
|
+
*/
|
|
180
|
+
export const EC2_TOPOLOGY_SERVICE_DEFAULTS: Record<string, Record<string, unknown>> = {
|
|
181
|
+
"AWS::EC2::VPC": {
|
|
182
|
+
InstanceTenancy: "default",
|
|
183
|
+
IsDefault: false,
|
|
184
|
+
},
|
|
185
|
+
"AWS::EC2::Subnet": {
|
|
186
|
+
MapPublicIpOnLaunch: false,
|
|
187
|
+
AssignIpv6AddressOnCreation: false,
|
|
188
|
+
EnableDns64: false,
|
|
189
|
+
Ipv6Native: false,
|
|
190
|
+
DefaultForAz: false,
|
|
191
|
+
},
|
|
192
|
+
"AWS::EC2::Instance": {
|
|
193
|
+
Tenancy: "default",
|
|
194
|
+
Monitoring: false,
|
|
195
|
+
EbsOptimized: false,
|
|
196
|
+
SourceDestCheck: true,
|
|
197
|
+
DisableApiTermination: false,
|
|
198
|
+
},
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Values the service picks when the template does not supply one, merged into
|
|
203
|
+
* `AWS_GENERATED_NAMES`. A subnet that names no availability zone gets one
|
|
204
|
+
* assigned — a different one is real placement drift only when the template
|
|
205
|
+
* had an opinion, which is exactly the counterpart gate.
|
|
206
|
+
*/
|
|
207
|
+
export const EC2_TOPOLOGY_GENERATED_NAMES: Record<string, ReadonlySet<string>> = {
|
|
208
|
+
"AWS::EC2::Subnet": new Set(["AvailabilityZone", "AvailabilityZoneId"]),
|
|
209
|
+
"AWS::EC2::Instance": new Set(["AvailabilityZone"]),
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Declared properties a type's source cannot see (#1269).
|
|
214
|
+
*
|
|
215
|
+
* `describe-vpcs` does not return the DNS attributes — they live behind
|
|
216
|
+
* `describe-vpc-attribute` — and neither describe returns the IPAM inputs,
|
|
217
|
+
* which are consumed at creation. A declared value for one of these has
|
|
218
|
+
* nothing live to stand against, so the diff would report `value -> <absent>`
|
|
219
|
+
* on every clean apply: a blind spot rendered as drift. Pruned on the
|
|
220
|
+
* declared side, and only where the live tree is silent, so a source that
|
|
221
|
+
* does report the field (Cloud Control, some day) is still compared.
|
|
222
|
+
*/
|
|
223
|
+
export const AWS_DEEP_BLIND_SPOTS: Record<string, ReadonlySet<string>> = {
|
|
224
|
+
"AWS::EC2::VPC": new Set([
|
|
225
|
+
"EnableDnsSupport",
|
|
226
|
+
"EnableDnsHostnames",
|
|
227
|
+
"Ipv4IpamPoolId",
|
|
228
|
+
"Ipv4NetmaskLength",
|
|
229
|
+
]),
|
|
230
|
+
"AWS::EC2::Subnet": new Set([
|
|
231
|
+
"Ipv6CidrBlock",
|
|
232
|
+
"Ipv4IpamPoolId",
|
|
233
|
+
"Ipv4NetmaskLength",
|
|
234
|
+
"Ipv6IpamPoolId",
|
|
235
|
+
"Ipv6NetmaskLength",
|
|
236
|
+
]),
|
|
237
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
EffectReceipt,
|
|
4
|
+
receiptParameterName,
|
|
5
|
+
AWS_EFFECT_RECEIPT_ENTITY_TYPE,
|
|
6
|
+
EFFECT_RECEIPTS_METADATA_KEY,
|
|
7
|
+
RECEIPT_UNRESOLVED_VALUE_NOTE,
|
|
8
|
+
} from "./effect-receipt-row";
|
|
9
|
+
import { awsSerializer } from "./serializer";
|
|
10
|
+
import { AWS_TAG_OWNERSHIP_KEYS } from "./ownership";
|
|
11
|
+
import {
|
|
12
|
+
EXISTENCE_EXPECTATION,
|
|
13
|
+
isEffectReceipt,
|
|
14
|
+
receiptExpectation,
|
|
15
|
+
EFFECT_RECEIPT_MARKER,
|
|
16
|
+
} from "@intentius/chant/effect-receipt";
|
|
17
|
+
import { receiptCheckInput } from "@intentius/chant/op/receipt-store";
|
|
18
|
+
import { coreReceiptChecks, RECEIPT_PLAIN_STORE_CHECK_ID } from "@intentius/chant/lint/receipt-checks";
|
|
19
|
+
import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
|
|
20
|
+
import { INTRINSIC_MARKER } from "@intentius/chant/intrinsic";
|
|
21
|
+
import type { PostSynthContext } from "@intentius/chant/lint/post-synth";
|
|
22
|
+
|
|
23
|
+
/** A minimal deploy-time reference, for the placeholder-value case. */
|
|
24
|
+
const someRef = { [INTRINSIC_MARKER]: true as const, toJSON: () => ({ Ref: "other" }) };
|
|
25
|
+
|
|
26
|
+
function serializeReceipts(
|
|
27
|
+
receipts: Map<string, Declarable>,
|
|
28
|
+
ownership?: { stack: string; env?: string },
|
|
29
|
+
): { Metadata?: Record<string, unknown>; Resources: Record<string, unknown> } {
|
|
30
|
+
const out = awsSerializer.serialize(new Map(), [], {
|
|
31
|
+
...(ownership ? { ownership } : {}),
|
|
32
|
+
receipts,
|
|
33
|
+
});
|
|
34
|
+
return JSON.parse(typeof out === "string" ? out : out.primary);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function metadataRows(template: { Metadata?: Record<string, unknown> }) {
|
|
38
|
+
return template.Metadata?.[EFFECT_RECEIPTS_METADATA_KEY] as Record<
|
|
39
|
+
string,
|
|
40
|
+
{ Type: string; Properties: Record<string, unknown> }
|
|
41
|
+
>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("EffectReceipt (aws materialization row)", () => {
|
|
45
|
+
it("declares under the aws lexicon with the real resource kind, carrying the marker", () => {
|
|
46
|
+
const r = EffectReceipt("seeded", { effect: "db-seed", flavor: "existence" });
|
|
47
|
+
expect(r.lexicon).toBe("aws");
|
|
48
|
+
expect(r.entityType).toBe(AWS_EFFECT_RECEIPT_ENTITY_TYPE);
|
|
49
|
+
expect(isEffectReceipt(r)).toBe(true);
|
|
50
|
+
expect(r.props.Type).toBe("String");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("is accepted by the effect() step's receiptCheckInput, expectation stamped when static", () => {
|
|
54
|
+
const r = EffectReceipt("seeded", { effect: "db-seed", flavor: "hash", inputs: { v: 1 } });
|
|
55
|
+
const input = receiptCheckInput(r);
|
|
56
|
+
expect(input.receipt.effect).toBe("db-seed");
|
|
57
|
+
expect(input.expectation).toBe(receiptExpectation(r));
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("validates the effect as a path segment at declaration", () => {
|
|
61
|
+
expect(() => EffectReceipt("bad", { effect: "a/b", flavor: "existence" })).toThrow(/path segment/);
|
|
62
|
+
expect(() => EffectReceipt("bad", { effect: "", flavor: "existence" })).toThrow(/non-empty/);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe("receiptParameterName", () => {
|
|
67
|
+
it("derives /chant-receipts/<stack>/<env>/<effect>", () => {
|
|
68
|
+
expect(receiptParameterName("demo", "dev", "db-seed")).toBe("/chant-receipts/demo/dev/db-seed");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("refuses a segment that would deepen the hierarchy", () => {
|
|
72
|
+
expect(() => receiptParameterName("a/b", "dev", "seed")).toThrow(/stack/);
|
|
73
|
+
expect(() => receiptParameterName("demo", "", "seed")).toThrow(/env/);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("awsSerializer receipt rows", () => {
|
|
78
|
+
const ownership = { stack: "demo", env: "dev" };
|
|
79
|
+
|
|
80
|
+
it("renders each receipt as a plain-String SSM parameter row at the derived path, ownership-tagged", () => {
|
|
81
|
+
const seeded = EffectReceipt("seeded", { effect: "db-seed", flavor: "hash", inputs: { v: 1 } });
|
|
82
|
+
const template = serializeReceipts(new Map([["seeded", seeded]]), ownership);
|
|
83
|
+
const row = metadataRows(template).seeded;
|
|
84
|
+
expect(row.Type).toBe("AWS::SSM::Parameter");
|
|
85
|
+
expect(row.Properties.Name).toBe("/chant-receipts/demo/dev/db-seed");
|
|
86
|
+
expect(row.Properties.Type).toBe("String");
|
|
87
|
+
expect(row.Properties.Value).toBe(receiptExpectation(seeded));
|
|
88
|
+
expect(row.Properties.Tags).toContainEqual({ Key: AWS_TAG_OWNERSHIP_KEYS.managedBy, Value: "chant" });
|
|
89
|
+
expect(row.Properties.Tags).toContainEqual({ Key: AWS_TAG_OWNERSHIP_KEYS.stack, Value: "demo" });
|
|
90
|
+
expect(row.Properties.Tags).toContainEqual({ Key: AWS_TAG_OWNERSHIP_KEYS.env, Value: "dev" });
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("keeps the receipt out of Resources — the section appliers write from", () => {
|
|
94
|
+
const seeded = EffectReceipt("seeded", { effect: "db-seed", flavor: "existence" });
|
|
95
|
+
const template = serializeReceipts(new Map([["seeded", seeded]]), ownership);
|
|
96
|
+
expect(Object.keys(template.Resources)).toHaveLength(0);
|
|
97
|
+
expect(metadataRows(template).seeded).toBeDefined();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("renders the existence expectation for an existence receipt", () => {
|
|
101
|
+
const r = EffectReceipt("booted", { effect: "bootstrap", flavor: "existence" });
|
|
102
|
+
const template = serializeReceipts(new Map([["booted", r]]), ownership);
|
|
103
|
+
expect(metadataRows(template).booted.Properties.Value).toBe(EXISTENCE_EXPECTATION);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("renders the placeholder note, never a placeholder digest, for reference inputs", () => {
|
|
107
|
+
const r = EffectReceipt("wired", { effect: "wire-up", flavor: "hash", inputs: { target: someRef } });
|
|
108
|
+
const template = serializeReceipts(new Map([["wired", r]]), ownership);
|
|
109
|
+
expect(metadataRows(template).wired.Properties.Value).toBe(RECEIPT_UNRESOLVED_VALUE_NOTE);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it("errors when no ownership marker resolves", () => {
|
|
113
|
+
const r = EffectReceipt("seeded", { effect: "db-seed", flavor: "existence" });
|
|
114
|
+
expect(() => serializeReceipts(new Map([["seeded", r]]))).toThrow(/ownership/);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("errors when ownership resolves no env — the segment is explicit, never guessed", () => {
|
|
118
|
+
const r = EffectReceipt("seeded", { effect: "db-seed", flavor: "existence" });
|
|
119
|
+
expect(() => serializeReceipts(new Map([["seeded", r]]), { stack: "demo" })).toThrow(/env/);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("emits no receipt block when the context carries no receipts", () => {
|
|
123
|
+
const out = awsSerializer.serialize(new Map(), [], { ownership });
|
|
124
|
+
const template = JSON.parse(typeof out === "string" ? out : out.primary);
|
|
125
|
+
expect(template.Metadata?.[EFFECT_RECEIPTS_METADATA_KEY]).toBeUndefined();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe("#1833's plain-store guard over the aws row", () => {
|
|
130
|
+
const check = coreReceiptChecks().find((c) => c.id === RECEIPT_PLAIN_STORE_CHECK_ID)!;
|
|
131
|
+
|
|
132
|
+
function runCheck(entities: Map<string, Declarable>) {
|
|
133
|
+
const ctx: PostSynthContext = {
|
|
134
|
+
outputs: new Map(),
|
|
135
|
+
entities,
|
|
136
|
+
buildResult: { outputs: new Map(), entities, warnings: [], errors: [], sourceFileCount: 0 },
|
|
137
|
+
};
|
|
138
|
+
return check.check(ctx);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
it("passes the factory's row — SSM plain String", () => {
|
|
142
|
+
const r = EffectReceipt("seeded", { effect: "db-seed", flavor: "existence" });
|
|
143
|
+
expect(runCheck(new Map([["seeded", r]]))).toEqual([]);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("fails a SecureString fixture", () => {
|
|
147
|
+
const secure = {
|
|
148
|
+
[DECLARABLE_MARKER]: true as const,
|
|
149
|
+
[EFFECT_RECEIPT_MARKER]: true as const,
|
|
150
|
+
lexicon: "aws",
|
|
151
|
+
entityType: "AWS::SSM::Parameter",
|
|
152
|
+
name: "sneaky",
|
|
153
|
+
effect: "db-seed",
|
|
154
|
+
flavor: "existence" as const,
|
|
155
|
+
inputs: {},
|
|
156
|
+
props: { Type: "SecureString" },
|
|
157
|
+
};
|
|
158
|
+
const diagnostics = runCheck(new Map([["sneaky", secure as unknown as Declarable]]));
|
|
159
|
+
expect(diagnostics).toHaveLength(1);
|
|
160
|
+
expect(diagnostics[0].checkId).toBe(RECEIPT_PLAIN_STORE_CHECK_ID);
|
|
161
|
+
expect(diagnostics[0].severity).toBe("error");
|
|
162
|
+
expect(diagnostics[0].message).toMatch(/SecureString/);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The aws effect-receipt materialization row (#1835, epic #1703): an effect
|
|
3
|
+
* receipt stored as an `AWS::SSM::Parameter`, plain `String`, at
|
|
4
|
+
* `/chant-receipts/<stack>/<env>/<effect>`.
|
|
5
|
+
*
|
|
6
|
+
* Core's `EffectReceipt` factory (#1831) declares a receipt under the `chant`
|
|
7
|
+
* pseudo-lexicon, which no serializer claims — the designed shape until a
|
|
8
|
+
* lexicon materializes it. This module is that materialization for aws: the
|
|
9
|
+
* {@link EffectReceipt} factory here produces the same declaration shape but
|
|
10
|
+
* under `lexicon: "aws"`, so the build partitions it to the aws serializer,
|
|
11
|
+
* #1832's write-exclusion seam withholds it from the apply-bound entity set,
|
|
12
|
+
* and the serializer renders it for visibility through
|
|
13
|
+
* `SerializeContext.receipts` (see ./serializer.ts).
|
|
14
|
+
*
|
|
15
|
+
* Path identity (epic decision 4): the parameter name derives from the SAME
|
|
16
|
+
* ownership-block fields that stamp markers — `ownership.stack` and an
|
|
17
|
+
* explicit `ownership.env` — plus the receipt's `effect`. One derivation,
|
|
18
|
+
* {@link receiptParameterName}, shared by the serializer (the rendered row),
|
|
19
|
+
* the receipt store (../receipt-store.ts — what `receiptRead`/`receiptWrite`
|
|
20
|
+
* actually touch), and the observation leg (plan's live read). No env, no
|
|
21
|
+
* path: the callers error rather than guessing a segment.
|
|
22
|
+
*
|
|
23
|
+
* Plain store (epic decision 7, #1833's COR023): the parameter type is pinned
|
|
24
|
+
* to `String` at the source — the factory does not take a type, and the
|
|
25
|
+
* declared `props.Type` is the literal `"String"`. A receipt value is a
|
|
26
|
+
* witness (an existence marker or a `sha256:` digest), never a secret; a
|
|
27
|
+
* `SecureString` invites masking and rotation semantics that defeat the
|
|
28
|
+
* observe-and-compare loop, and the lint guard fails it.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { DECLARABLE_MARKER, type Declarable } from "@intentius/chant/declarable";
|
|
32
|
+
import {
|
|
33
|
+
EffectReceipt as CoreEffectReceipt,
|
|
34
|
+
EFFECT_RECEIPT_MARKER,
|
|
35
|
+
type EffectReceiptFlavor,
|
|
36
|
+
type EffectReceiptOptions,
|
|
37
|
+
} from "@intentius/chant/effect-receipt";
|
|
38
|
+
|
|
39
|
+
/** The entityType of the aws materialization row — the real resource kind the
|
|
40
|
+
* receipt is stored as, which is what lint's plain-store guard checks. */
|
|
41
|
+
export const AWS_EFFECT_RECEIPT_ENTITY_TYPE = "AWS::SSM::Parameter";
|
|
42
|
+
|
|
43
|
+
/** Template-level `Metadata` key the serializer renders receipt rows under.
|
|
44
|
+
* Beside `chant:ownership` (./ownership.ts) and like it deliberately outside
|
|
45
|
+
* `Resources` — the applier writes from `Resources`, and a receipt must never
|
|
46
|
+
* enter the apply-bound document (#1832; the `effect()` step is the sole
|
|
47
|
+
* writer, epic decision 3). */
|
|
48
|
+
export const EFFECT_RECEIPTS_METADATA_KEY = "chant:effect-receipts";
|
|
49
|
+
|
|
50
|
+
/** Every receipt parameter lives under this prefix, so read-only IAM can be
|
|
51
|
+
* scoped to `arn:…:parameter/chant-receipts/*` and nothing else. */
|
|
52
|
+
export const RECEIPT_PATH_PREFIX = "/chant-receipts";
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The rendered `Value` of a hash-flavor receipt that still carries reference
|
|
56
|
+
* inputs at synthesis. References resolve at plan and at run, never at
|
|
57
|
+
* synthesis (epic decision 5) — so the row carries this note instead of a
|
|
58
|
+
* digest hashed over placeholders.
|
|
59
|
+
*/
|
|
60
|
+
export const RECEIPT_UNRESOLVED_VALUE_NOTE =
|
|
61
|
+
"unresolved at synthesis — reference inputs; the expectation resolves at plan and at run (chant #1703, decision 5)";
|
|
62
|
+
|
|
63
|
+
/** One path segment of the receipt parameter name. SSM hierarchical names are
|
|
64
|
+
* `/`-separated `[\w.-]+` segments, and the identity must stay one segment per
|
|
65
|
+
* field — a `/` inside a stack name would silently deepen the hierarchy. */
|
|
66
|
+
const PATH_SEGMENT = /^[\w.-]+$/;
|
|
67
|
+
|
|
68
|
+
function checkSegment(field: string, value: string): string {
|
|
69
|
+
if (!PATH_SEGMENT.test(value)) {
|
|
70
|
+
throw new Error(
|
|
71
|
+
`receipt path: ${field} "${value}" is not a valid SSM path segment — ` +
|
|
72
|
+
`use only letters, digits, ".", "_", "-" (the segment becomes one level of ` +
|
|
73
|
+
`${RECEIPT_PATH_PREFIX}/<stack>/<env>/<effect>)`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* The SSM parameter name of one effect's receipt:
|
|
81
|
+
* `/chant-receipts/<stack>/<env>/<effect>`, from the resolved ownership
|
|
82
|
+
* marker fields (epic decision 4). The single source of the path identity —
|
|
83
|
+
* the serializer's rendered row, the receipt store's reads and writes, and
|
|
84
|
+
* the observation leg all call this.
|
|
85
|
+
*/
|
|
86
|
+
export function receiptParameterName(stack: string, env: string, effect: string): string {
|
|
87
|
+
return `${RECEIPT_PATH_PREFIX}/${checkSegment("stack", stack)}/${checkSegment("env", env)}/${checkSegment("effect", effect)}`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* An aws-materialized effect receipt: core's declaration shape (so
|
|
92
|
+
* `isEffectReceipt`, `effect(...)`, lint, and the plan engine all recognize it
|
|
93
|
+
* through the marker), under the aws lexicon and the real resource kind, with
|
|
94
|
+
* the store variant pinned plain.
|
|
95
|
+
*/
|
|
96
|
+
export interface AwsEffectReceiptDeclaration extends Declarable {
|
|
97
|
+
readonly [EFFECT_RECEIPT_MARKER]: true;
|
|
98
|
+
readonly lexicon: "aws";
|
|
99
|
+
readonly entityType: typeof AWS_EFFECT_RECEIPT_ENTITY_TYPE;
|
|
100
|
+
/** The receipt's own name (the export-level identity of the witness). */
|
|
101
|
+
readonly name: string;
|
|
102
|
+
/** The effect this receipt witnesses — the path's final segment. */
|
|
103
|
+
readonly effect: string;
|
|
104
|
+
/** How the receipt is compared: mere presence, or a digest of the inputs. */
|
|
105
|
+
readonly flavor: EffectReceiptFlavor;
|
|
106
|
+
/** The effect's inputs as recorded at synthesis (references as placeholders). */
|
|
107
|
+
readonly inputs: Readonly<Record<string, unknown>>;
|
|
108
|
+
/** The declared parameter variant — pinned `String` at the source, which is
|
|
109
|
+
* the concrete half of #1833's plain-store guard. */
|
|
110
|
+
readonly props: { readonly Type: "String" };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Declare an aws-materialized effect receipt. Same signature and semantics as
|
|
115
|
+
* core's `EffectReceipt` (#1831) — the options are validated and frozen by the
|
|
116
|
+
* core factory — but the declaration lands in the aws partition, so the aws
|
|
117
|
+
* serializer renders the `AWS::SSM::Parameter` row and the receipt store
|
|
118
|
+
* (../receipt-store.ts) is its writer. Pass the returned const straight to the
|
|
119
|
+
* `effect(...)` op step.
|
|
120
|
+
*/
|
|
121
|
+
export function EffectReceipt(name: string, options: EffectReceiptOptions): AwsEffectReceiptDeclaration {
|
|
122
|
+
// Fail at declaration, not at serialize: the effect is the path's final
|
|
123
|
+
// segment, and a name that cannot become a segment has no receipt address.
|
|
124
|
+
if (typeof options?.effect === "string" && options.effect.length > 0) {
|
|
125
|
+
checkSegment("effect", options.effect);
|
|
126
|
+
}
|
|
127
|
+
const core = CoreEffectReceipt(name, options);
|
|
128
|
+
const decl: AwsEffectReceiptDeclaration = {
|
|
129
|
+
[DECLARABLE_MARKER]: true,
|
|
130
|
+
[EFFECT_RECEIPT_MARKER]: true,
|
|
131
|
+
lexicon: "aws",
|
|
132
|
+
entityType: AWS_EFFECT_RECEIPT_ENTITY_TYPE,
|
|
133
|
+
name: core.name,
|
|
134
|
+
effect: core.effect,
|
|
135
|
+
flavor: core.flavor,
|
|
136
|
+
// The same frozen structure the core factory built — intrinsic inputs stay
|
|
137
|
+
// live so discovery can stamp logical names onto attr-refs.
|
|
138
|
+
inputs: core.inputs,
|
|
139
|
+
props: Object.freeze({ Type: "String" as const }),
|
|
140
|
+
};
|
|
141
|
+
// Declared fields immutable, object extensible for discovery's own
|
|
142
|
+
// symbol-keyed metadata — the same lock the core factory applies.
|
|
143
|
+
for (const key of Object.keys(decl)) {
|
|
144
|
+
Object.defineProperty(decl, key, { writable: false, configurable: false });
|
|
145
|
+
}
|
|
146
|
+
return decl;
|
|
147
|
+
}
|
|
@@ -6222,6 +6222,9 @@
|
|
|
6222
6222
|
"deprecatedProperties": [
|
|
6223
6223
|
"DeleteStorageConnectors"
|
|
6224
6224
|
],
|
|
6225
|
+
"inferredDeprecations": [
|
|
6226
|
+
"DeleteStorageConnectors"
|
|
6227
|
+
],
|
|
6225
6228
|
"tagging": {
|
|
6226
6229
|
"taggable": true,
|
|
6227
6230
|
"tagOnCreate": true,
|
|
@@ -11669,6 +11672,9 @@
|
|
|
11669
11672
|
"deprecatedProperties": [
|
|
11670
11673
|
"AccessControl"
|
|
11671
11674
|
],
|
|
11675
|
+
"inferredDeprecations": [
|
|
11676
|
+
"AccessControl"
|
|
11677
|
+
],
|
|
11672
11678
|
"tagging": {
|
|
11673
11679
|
"taggable": true,
|
|
11674
11680
|
"tagOnCreate": true,
|
|
@@ -14989,6 +14995,9 @@
|
|
|
14989
14995
|
"deprecatedProperties": [
|
|
14990
14996
|
"ComputeModel"
|
|
14991
14997
|
],
|
|
14998
|
+
"inferredDeprecations": [
|
|
14999
|
+
"ComputeModel"
|
|
15000
|
+
],
|
|
14992
15001
|
"replacementStrategy": "delete_then_create",
|
|
14993
15002
|
"tagging": {
|
|
14994
15003
|
"taggable": true,
|
|
@@ -15385,6 +15394,9 @@
|
|
|
15385
15394
|
"deprecatedProperties": [
|
|
15386
15395
|
"ComputeModel"
|
|
15387
15396
|
],
|
|
15397
|
+
"inferredDeprecations": [
|
|
15398
|
+
"ComputeModel"
|
|
15399
|
+
],
|
|
15388
15400
|
"conditionalCreateOnly": [
|
|
15389
15401
|
"DbNodes"
|
|
15390
15402
|
],
|
|
@@ -17085,6 +17097,9 @@
|
|
|
17085
17097
|
"deprecatedProperties": [
|
|
17086
17098
|
"Deprecated"
|
|
17087
17099
|
],
|
|
17100
|
+
"inferredDeprecations": [
|
|
17101
|
+
"Deprecated"
|
|
17102
|
+
],
|
|
17088
17103
|
"tagging": {
|
|
17089
17104
|
"taggable": true,
|
|
17090
17105
|
"tagOnCreate": true,
|
|
@@ -29032,6 +29047,9 @@
|
|
|
29032
29047
|
"TdeCredentialPassword",
|
|
29033
29048
|
"DBSecurityGroups"
|
|
29034
29049
|
],
|
|
29050
|
+
"inferredDeprecations": [
|
|
29051
|
+
"DBSecurityGroups"
|
|
29052
|
+
],
|
|
29035
29053
|
"conditionalCreateOnly": [
|
|
29036
29054
|
"AutoMinorVersionUpgrade",
|
|
29037
29055
|
"AvailabilityZone",
|
|
@@ -33246,6 +33264,9 @@
|
|
|
33246
33264
|
"deprecatedProperties": [
|
|
33247
33265
|
"ImageScanningConfiguration"
|
|
33248
33266
|
],
|
|
33267
|
+
"inferredDeprecations": [
|
|
33268
|
+
"ImageScanningConfiguration"
|
|
33269
|
+
],
|
|
33249
33270
|
"tagging": {
|
|
33250
33271
|
"taggable": true,
|
|
33251
33272
|
"tagOnCreate": true,
|
|
@@ -41749,6 +41770,9 @@
|
|
|
41749
41770
|
"deprecatedProperties": [
|
|
41750
41771
|
"Runtime"
|
|
41751
41772
|
],
|
|
41773
|
+
"inferredDeprecations": [
|
|
41774
|
+
"Runtime"
|
|
41775
|
+
],
|
|
41752
41776
|
"conditionalCreateOnly": [
|
|
41753
41777
|
"DurableConfig"
|
|
41754
41778
|
],
|
|
@@ -49621,6 +49645,10 @@
|
|
|
49621
49645
|
"ElasticGpuSpecifications",
|
|
49622
49646
|
"ElasticInferenceAccelerators"
|
|
49623
49647
|
],
|
|
49648
|
+
"inferredDeprecations": [
|
|
49649
|
+
"ElasticGpuSpecifications",
|
|
49650
|
+
"ElasticInferenceAccelerators"
|
|
49651
|
+
],
|
|
49624
49652
|
"conditionalCreateOnly": [
|
|
49625
49653
|
"AdditionalInfo",
|
|
49626
49654
|
"Affinity",
|
|
@@ -64878,6 +64906,9 @@
|
|
|
64878
64906
|
"deprecatedProperties": [
|
|
64879
64907
|
"DBPort"
|
|
64880
64908
|
],
|
|
64909
|
+
"inferredDeprecations": [
|
|
64910
|
+
"DBPort"
|
|
64911
|
+
],
|
|
64881
64912
|
"tagging": {
|
|
64882
64913
|
"taggable": true,
|
|
64883
64914
|
"tagOnCreate": true,
|
|
@@ -100101,6 +100132,9 @@
|
|
|
100101
100132
|
"deprecatedProperties": [
|
|
100102
100133
|
"State"
|
|
100103
100134
|
],
|
|
100135
|
+
"inferredDeprecations": [
|
|
100136
|
+
"State"
|
|
100137
|
+
],
|
|
100104
100138
|
"tagging": {
|
|
100105
100139
|
"taggable": true,
|
|
100106
100140
|
"tagOnCreate": true,
|