@intentius/chant-lexicon-aws 0.124.45 → 0.124.48
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/capabilities/mapping.json +150 -0
- package/dist/capabilities/pack.d.ts +8 -0
- package/dist/capabilities/pack.d.ts.map +1 -0
- package/dist/capabilities/pack.js +2 -0
- package/dist/components/capability-plugin.d.ts +1 -1
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +6 -4
- package/dist/components/publish.d.ts +28 -97
- package/dist/components/publish.d.ts.map +1 -1
- package/dist/components/publish.js +42 -109
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +2 -0
- package/package.json +2 -2
- package/src/capabilities/mapping.json +150 -0
- package/src/capabilities/pack.ts +9 -0
- package/src/capabilities.test.ts +182 -0
- package/src/components/capability-plugin.ts +6 -4
- package/src/components/publish.ts +61 -193
- package/src/graph-sub-edges.test.ts +101 -0
- package/src/plugin.ts +2 -0
- package/src/testdata/capabilities-ledger/estate.ts +161 -0
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lexicon": "aws",
|
|
3
|
+
"types": "kind",
|
|
4
|
+
"refs": "cloudformation",
|
|
5
|
+
"labels": {
|
|
6
|
+
"AWS::EC2::VPC": "Vpc",
|
|
7
|
+
"AWS::EC2::NetworkInterface": "NetworkInterface",
|
|
8
|
+
"AWS::EC2::Volume": "Volume",
|
|
9
|
+
"AWS::Lambda::Function": "Function",
|
|
10
|
+
"AWS::Lambda::Url": "FunctionUrl",
|
|
11
|
+
"AWS::IAM::InstanceProfile": "InstanceProfile",
|
|
12
|
+
"AWS::IAM::Role": "Role",
|
|
13
|
+
"AWS::IAM::Policy": "Policy",
|
|
14
|
+
"AWS::IAM::ManagedPolicy": "Policy",
|
|
15
|
+
"AWS::S3::BucketPolicy": "ResourcePolicy",
|
|
16
|
+
"AWS::SQS::QueuePolicy": "ResourcePolicy",
|
|
17
|
+
"AWS::S3::Bucket": "Bucket",
|
|
18
|
+
"AWS::DynamoDB::Table": "Table",
|
|
19
|
+
"AWS::DynamoDB::GlobalTable": "Table",
|
|
20
|
+
"AWS::RDS::DBInstance": "Database",
|
|
21
|
+
"AWS::RDS::DBCluster": "Database",
|
|
22
|
+
"AWS::SecretsManager::Secret": "Secret",
|
|
23
|
+
"AWS::SQS::Queue": "Queue",
|
|
24
|
+
"AWS::EFS::FileSystem": "FileSystem",
|
|
25
|
+
"AWS::SSM::Parameter": "Parameter",
|
|
26
|
+
"AWS::ECS::Service": "Service",
|
|
27
|
+
"AWS::ECS::TaskDefinition": "TaskDefinition",
|
|
28
|
+
"AWS::RDS::DBSubnetGroup": "SubnetGroup",
|
|
29
|
+
"AWS::EC2::NatGateway": "NatGateway",
|
|
30
|
+
"AWS::ElasticLoadBalancingV2::LoadBalancer": "LoadBalancer"
|
|
31
|
+
},
|
|
32
|
+
"edges": {
|
|
33
|
+
"Instance": {
|
|
34
|
+
"IamInstanceProfile": "profile",
|
|
35
|
+
"VpcId": "vpc"
|
|
36
|
+
},
|
|
37
|
+
"LaunchTemplate": {
|
|
38
|
+
"LaunchTemplateData": {
|
|
39
|
+
"InstanceProfile": "profile"
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"Subnet": {
|
|
43
|
+
"VpcId": "vpc"
|
|
44
|
+
},
|
|
45
|
+
"SecurityGroup": {
|
|
46
|
+
"VpcId": "vpc"
|
|
47
|
+
},
|
|
48
|
+
"NetworkInterface": {
|
|
49
|
+
"SubnetId": "subnet",
|
|
50
|
+
"GroupSet": "sg"
|
|
51
|
+
},
|
|
52
|
+
"Database": {
|
|
53
|
+
"VPCSecurityGroups": "sg",
|
|
54
|
+
"VpcSecurityGroupIds": "sg",
|
|
55
|
+
"DBSubnetGroupName": "subnetGroup"
|
|
56
|
+
},
|
|
57
|
+
"Function": {
|
|
58
|
+
"Role": "role",
|
|
59
|
+
"VpcConfig": {
|
|
60
|
+
"SecurityGroup": "sg",
|
|
61
|
+
"Subnet": "subnet"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
"FunctionUrl": {
|
|
65
|
+
"TargetFunctionArn": "function"
|
|
66
|
+
},
|
|
67
|
+
"InstanceProfile": {
|
|
68
|
+
"Roles": "role"
|
|
69
|
+
},
|
|
70
|
+
"Policy": {
|
|
71
|
+
"Roles": "attachedTo"
|
|
72
|
+
},
|
|
73
|
+
"Role": {
|
|
74
|
+
"ManagedPolicyArns": "-attachedTo"
|
|
75
|
+
},
|
|
76
|
+
"ResourcePolicy": {
|
|
77
|
+
"Bucket": "policyOf",
|
|
78
|
+
"Queues": "policyOf"
|
|
79
|
+
},
|
|
80
|
+
"Service": {
|
|
81
|
+
"TaskDefinition": "task",
|
|
82
|
+
"NetworkConfiguration": {
|
|
83
|
+
"SecurityGroup": "sg",
|
|
84
|
+
"Subnet": "subnet"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"TaskDefinition": {
|
|
88
|
+
"TaskRoleArn": "role"
|
|
89
|
+
},
|
|
90
|
+
"SubnetGroup": {
|
|
91
|
+
"SubnetIds": "subnet"
|
|
92
|
+
},
|
|
93
|
+
"NatGateway": {
|
|
94
|
+
"SubnetId": "subnet"
|
|
95
|
+
},
|
|
96
|
+
"LoadBalancer": {
|
|
97
|
+
"Subnets": "subnet",
|
|
98
|
+
"SecurityGroups": "sg"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"attrs": {
|
|
102
|
+
"FunctionUrl": {
|
|
103
|
+
"authType": "AuthType"
|
|
104
|
+
},
|
|
105
|
+
"Role": {
|
|
106
|
+
"name": "RoleName"
|
|
107
|
+
},
|
|
108
|
+
"Bucket": {
|
|
109
|
+
"name": "BucketName",
|
|
110
|
+
"acl": "AccessControl",
|
|
111
|
+
"blockPublicPolicy": "PublicAccessBlockConfiguration.BlockPublicPolicy"
|
|
112
|
+
},
|
|
113
|
+
"Table": {
|
|
114
|
+
"name": "TableName"
|
|
115
|
+
},
|
|
116
|
+
"Database": {
|
|
117
|
+
"encrypted": "StorageEncrypted"
|
|
118
|
+
},
|
|
119
|
+
"FileSystem": {
|
|
120
|
+
"encrypted": "Encrypted"
|
|
121
|
+
},
|
|
122
|
+
"Volume": {
|
|
123
|
+
"encrypted": "Encrypted"
|
|
124
|
+
},
|
|
125
|
+
"Parameter": {
|
|
126
|
+
"paramType": "Type"
|
|
127
|
+
},
|
|
128
|
+
"Vpc": {
|
|
129
|
+
"isDefault": "IsDefault"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"documents": {
|
|
133
|
+
"Role": {
|
|
134
|
+
"AssumeRolePolicyDocument": "trust",
|
|
135
|
+
"Policies[].PolicyDocument": "permission"
|
|
136
|
+
},
|
|
137
|
+
"Policy": {
|
|
138
|
+
"PolicyDocument": "permission"
|
|
139
|
+
},
|
|
140
|
+
"ResourcePolicy": {
|
|
141
|
+
"PolicyDocument": "resource"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
"tags": [
|
|
145
|
+
"Tags"
|
|
146
|
+
],
|
|
147
|
+
"classificationTags": [
|
|
148
|
+
"data-classification"
|
|
149
|
+
]
|
|
150
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The aws lexicon's capability pack (#4375): its mapping of CloudFormation
|
|
3
|
+
* kinds onto the lexicon-neutral view the capability rules read. All data;
|
|
4
|
+
* CloudFormation policy documents are JSON already, so no adapter code.
|
|
5
|
+
*/
|
|
6
|
+
import type { CapabilityMapping, CapabilityPack } from "@intentius/chant/capabilities/view";
|
|
7
|
+
import mapping from "./mapping.json" with { type: "json" };
|
|
8
|
+
|
|
9
|
+
export const awsCapabilityPack: CapabilityPack = { mapping: mapping as CapabilityMapping };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability catalog over CloudFormation kinds (#4375).
|
|
3
|
+
*
|
|
4
|
+
* `testdata/capabilities-ledger/estate.ts` is the CloudFormation form of the
|
|
5
|
+
* estate chant#4361 measured the rule language on. Its hand-checked answers
|
|
6
|
+
* are identity reach 13, exfiltration 3 and blast radius 15, the same as the
|
|
7
|
+
* Terraform form's (lexicons/terraform/src/capabilities.test.ts).
|
|
8
|
+
*
|
|
9
|
+
* Three of those pairs are proved only by a reference inside a `Sub`
|
|
10
|
+
* (``Sub`${assets.Arn}/*` ``), which the graph carries as `{ $sub }` since
|
|
11
|
+
* chant#4373.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { describe, expect, it } from "vitest";
|
|
16
|
+
import { discover } from "@intentius/chant/discovery/index";
|
|
17
|
+
import { buildGraphIr, type GraphIR } from "@intentius/chant/graph-ir";
|
|
18
|
+
import { enrichEffectiveTopology } from "@intentius/chant/graph-effective";
|
|
19
|
+
import { CapabilityEngine } from "@intentius/chant/capabilities/matcher";
|
|
20
|
+
import { buildView, displayName } from "@intentius/chant/capabilities/view";
|
|
21
|
+
import { lexiconSupport, resolvePacks, shippedRules, isPublic } from "@intentius/chant/capabilities/catalog";
|
|
22
|
+
import { awsCapabilityPack } from "./capabilities/pack";
|
|
23
|
+
|
|
24
|
+
const LEDGER = join(import.meta.dirname, "testdata", "capabilities-ledger");
|
|
25
|
+
|
|
26
|
+
const engineFor = (g: GraphIR) => new CapabilityEngine(buildView(g, resolvePacks([awsCapabilityPack])), shippedRules().rules);
|
|
27
|
+
|
|
28
|
+
const ir: GraphIR = buildGraphIr((await discover(LEDGER)).entities, LEDGER);
|
|
29
|
+
const engine = engineFor(ir);
|
|
30
|
+
|
|
31
|
+
const set = (e: CapabilityEngine, name: string, args: unknown[] = []) =>
|
|
32
|
+
[...e.set(name, e.bind(name, args as never)).keys()].map(displayName).sort();
|
|
33
|
+
const pairs = (e: CapabilityEngine, name: string, args: unknown[] = []) =>
|
|
34
|
+
[...e.relation(name, e.bind(name, args as never)).out].flatMap(([a, m]) => [...m.keys()].map((b) => `${displayName(a)} ${displayName(b)}`)).sort();
|
|
35
|
+
|
|
36
|
+
const REACH = [
|
|
37
|
+
"auditRole ordersTable",
|
|
38
|
+
"batchRole auditRole",
|
|
39
|
+
"batchRole ordersTable",
|
|
40
|
+
"deployRole customerData",
|
|
41
|
+
"deployRole dbSecret",
|
|
42
|
+
"reporterRole customerData",
|
|
43
|
+
"webRole assets",
|
|
44
|
+
"webRole customerData",
|
|
45
|
+
"webRole dbSecret",
|
|
46
|
+
"webRole deployRole",
|
|
47
|
+
"workerRole assets",
|
|
48
|
+
"workerRole dbSecret",
|
|
49
|
+
"workerRole ordersTable",
|
|
50
|
+
];
|
|
51
|
+
const EXFIL = ["reporter customerData", "webServer customerData", "webServer dbSecret"];
|
|
52
|
+
const BLAST_STARTS = ["webServer", "reporter", "batch"];
|
|
53
|
+
const BLAST = [
|
|
54
|
+
...["webRole", "assets", "deployRole", "customerData", "dbSecret", "worker", "adminBox", "workerRole", "ordersTable", "customersDb"].map((x) => `webServer ${x}`),
|
|
55
|
+
"reporter reporterRole",
|
|
56
|
+
"reporter customerData",
|
|
57
|
+
"batch batchRole",
|
|
58
|
+
"batch auditRole",
|
|
59
|
+
"batch ordersTable",
|
|
60
|
+
].sort();
|
|
61
|
+
/** The pairs only a `Sub` reference proves (chant#4373). */
|
|
62
|
+
const NEEDS_SUB = {
|
|
63
|
+
reach: ["reporterRole customerData", "webRole assets", "workerRole assets"],
|
|
64
|
+
exfil: ["reporter customerData"],
|
|
65
|
+
blast: ["reporter customerData", "webServer assets"],
|
|
66
|
+
};
|
|
67
|
+
const blastOf = (e: CapabilityEngine) => pairs(e, "blast").filter((p) => BLAST_STARTS.includes(p.split(" ")[0]));
|
|
68
|
+
|
|
69
|
+
describe("the ledger's hand-checked answers on the CloudFormation form", () => {
|
|
70
|
+
it("identity reach 13, exfiltration 3, blast radius 15, three of them proved only by a Sub reference (chant#4373)", () => {
|
|
71
|
+
expect(pairs(engine, "reaches")).toEqual(REACH);
|
|
72
|
+
expect(pairs(engine, "exfiltrates")).toEqual(EXFIL);
|
|
73
|
+
expect(blastOf(engine)).toEqual(BLAST);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("leaves no statement's resource unresolved", () => {
|
|
77
|
+
const unresolved = [...engine.view.nodes.values()].filter((n) => n.label === "Statement" && n.attrs.unresolved);
|
|
78
|
+
expect(unresolved.map((n) => n.id)).toEqual([]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("finds the Sub-only pairs through the Sub's own reference", () => {
|
|
82
|
+
for (const p of NEEDS_SUB.reach) expect(pairs(engine, "reaches")).toContain(p);
|
|
83
|
+
const ev = engine.relation("reaches").out.get("reporterRole")!.get("customerData")!;
|
|
84
|
+
expect(ev.hops.at(-1)).toMatchObject({ to: "customerData", toAttr: "Arn", edge: "resource" });
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe("each capability on CloudFormation kinds", () => {
|
|
89
|
+
it("internet-facing, open-ingress and internet-reachable, the open group reached only through a launch template", () => {
|
|
90
|
+
expect(set(engine, "internet-facing")).toEqual(["adminBox", "webServer"]);
|
|
91
|
+
expect(set(engine, "open-ingress", [22])).toEqual(["webServer"]);
|
|
92
|
+
expect(set(engine, "internet-reachable")).toEqual(["reporter", "webServer"]);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("network reads the standalone SecurityGroupIngress resource as well as inline rules", () => {
|
|
96
|
+
expect(pairs(engine, "network")).toEqual([
|
|
97
|
+
"adminBox customersDb",
|
|
98
|
+
"webServer adminBox",
|
|
99
|
+
"webServer worker",
|
|
100
|
+
"worker customersDb",
|
|
101
|
+
]);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("stores-data, holds-secret (by data-classification tag) and encrypted-at-rest", () => {
|
|
105
|
+
expect(set(engine, "stores-data")).toEqual(["assets", "customerData", "customersDb", "dbSecret", "ordersTable"]);
|
|
106
|
+
expect(set(engine, "holds-secret")).toEqual(["customerData", "customersDb", "dbSecret"]);
|
|
107
|
+
expect(set(engine, "encrypted-at-rest")).toEqual(["assets", "customerData", "customersDb", "dbSecret", "ordersTable"]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("runs-as, can-assume (by reference and by ARN naming a declared role) and grants", () => {
|
|
111
|
+
expect(pairs(engine, "runs-as")).toEqual([
|
|
112
|
+
"adminBox workerRole",
|
|
113
|
+
"batch batchRole",
|
|
114
|
+
"reporter reporterRole",
|
|
115
|
+
"webServer webRole",
|
|
116
|
+
"worker workerRole",
|
|
117
|
+
]);
|
|
118
|
+
expect(pairs(engine, "can-assume")).toEqual(["batchRole auditRole", "webRole deployRole"]);
|
|
119
|
+
expect(pairs(engine, "grants", ["dynamodb:Scan"])).toEqual(["auditRole ordersTable"]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("attached-to-nothing and publicly-readable hold for nothing in the ledger, and for what a small graph declares", () => {
|
|
123
|
+
expect(set(engine, "attached-to-nothing")).toEqual([]);
|
|
124
|
+
expect(set(engine, "publicly-readable")).toEqual([]);
|
|
125
|
+
const g: GraphIR = {
|
|
126
|
+
nodes: [
|
|
127
|
+
{ id: "sg", kind: "AWS::EC2::SecurityGroup", lexicon: "aws", attrs: {} },
|
|
128
|
+
{ id: "open", kind: "AWS::S3::Bucket", lexicon: "aws", attrs: {} },
|
|
129
|
+
{ id: "openPolicy", kind: "AWS::S3::BucketPolicy", lexicon: "aws", attrs: { Bucket: { $ref: "open" }, PolicyDocument: { Statement: [{ Effect: "Allow", Principal: "*", Action: "s3:GetObject" }] } } },
|
|
130
|
+
{ id: "blocked", kind: "AWS::S3::Bucket", lexicon: "aws", attrs: { PublicAccessBlockConfiguration: { BlockPublicPolicy: true } } },
|
|
131
|
+
{ id: "blockedPolicy", kind: "AWS::S3::BucketPolicy", lexicon: "aws", attrs: { Bucket: { $ref: "blocked" }, PolicyDocument: { Statement: [{ Effect: "Allow", Principal: { AWS: "*" }, Action: "s3:GetObject" }] } } },
|
|
132
|
+
] as never,
|
|
133
|
+
edges: [
|
|
134
|
+
{ from: "openPolicy", to: "open", viaAttr: "Bucket" },
|
|
135
|
+
{ from: "blockedPolicy", to: "blocked", viaAttr: "Bucket" },
|
|
136
|
+
] as never,
|
|
137
|
+
groups: {},
|
|
138
|
+
};
|
|
139
|
+
const e = engineFor(g);
|
|
140
|
+
expect(set(e, "attached-to-nothing")).toEqual(["sg"]);
|
|
141
|
+
expect(set(e, "publicly-readable")).toEqual(["open"]);
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
it("in-default-vpc reads a live VPC's IsDefault, through the instance's VpcId or its subnet", () => {
|
|
145
|
+
const g: GraphIR = {
|
|
146
|
+
nodes: [
|
|
147
|
+
{ id: "east::vpc-default", kind: "AWS::EC2::VPC", lexicon: "aws", attrs: { IsDefault: true } },
|
|
148
|
+
{ id: "east::vpc-main", kind: "AWS::EC2::VPC", lexicon: "aws", attrs: { IsDefault: false } },
|
|
149
|
+
{ id: "east::subnet-a", kind: "AWS::EC2::Subnet", lexicon: "aws", attrs: {} },
|
|
150
|
+
{ id: "east::i-old", kind: "AWS::EC2::Instance", lexicon: "aws", attrs: {} },
|
|
151
|
+
{ id: "east::i-new", kind: "AWS::EC2::Instance", lexicon: "aws", attrs: {} },
|
|
152
|
+
{ id: "east::i-sub", kind: "AWS::EC2::Instance", lexicon: "aws", attrs: {} },
|
|
153
|
+
] as never,
|
|
154
|
+
edges: [
|
|
155
|
+
{ from: "east::i-old", to: "east::vpc-default", viaAttr: "VpcId" },
|
|
156
|
+
{ from: "east::i-new", to: "east::vpc-main", viaAttr: "VpcId" },
|
|
157
|
+
{ from: "east::i-sub", to: "east::subnet-a", viaAttr: "SubnetId" },
|
|
158
|
+
{ from: "east::subnet-a", to: "east::vpc-default", viaAttr: "VpcId" },
|
|
159
|
+
] as never,
|
|
160
|
+
groups: {},
|
|
161
|
+
};
|
|
162
|
+
expect(set(engineFor(g), "in-default-vpc")).toEqual(["i-old", "i-sub", "subnet-a"]);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("the aws mapping supplies every capability", () => {
|
|
166
|
+
for (const rule of shippedRules().rules.filter(isPublic)) {
|
|
167
|
+
expect(lexiconSupport(rule, awsCapabilityPack.mapping, "aws"), rule.name).toBe("supported");
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
describe("the effective-topology fold over the same graph", () => {
|
|
173
|
+
it("reads the standalone ingress resource too, naming its source group", () => {
|
|
174
|
+
const enriched = enrichEffectiveTopology(ir);
|
|
175
|
+
const attrs = (id: string) => enriched.nodes.find((n) => n.id === id)!.attrs as Record<string, unknown>;
|
|
176
|
+
expect(attrs("webServer").effectiveIngress).toEqual(["tcp:443:0.0.0.0/0", "tcp:22:0.0.0.0/0"]);
|
|
177
|
+
expect(attrs("webServer").internetFacing).toBe(true);
|
|
178
|
+
expect(attrs("webServer").internetFacingVia).toBe("publicRt → igw");
|
|
179
|
+
expect(attrs("worker").effectiveIngress).toEqual(["tcp:8080:sg:webSg"]);
|
|
180
|
+
expect(attrs("worker").internetFacing).toBe(false);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
import type { Capability } from "@intentius/chant/components/capability";
|
|
12
12
|
import { ownPackageVersion, type CapabilityPlugin } from "@intentius/chant/components/capability-plugin";
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import { ecrRegistryBackend, s3StorageBackend, loadImageOnHostCapability } from "./publish";
|
|
15
15
|
import { extractConfigBomCapability } from "./config-bom";
|
|
16
16
|
import {
|
|
17
17
|
cfnDeployCapability,
|
|
@@ -30,7 +30,9 @@ import { snapshotBeforeCapability, rollbackPreviousCapability } from "./safety";
|
|
|
30
30
|
export const AWS_VERB_FAMILIES = {
|
|
31
31
|
// `extract-config-bom` parses a synthesized CloudFormation template (#684).
|
|
32
32
|
sbom: ["extract-config-bom"],
|
|
33
|
-
|
|
33
|
+
// `publish-image` is core's verb (#3142, #3143); aws contributes its ECR login as a registry backend.
|
|
34
|
+
// `publish-artifact` is core's verb (#4408); aws contributes S3 as a storage backend.
|
|
35
|
+
publish: ["load-image-on-host"],
|
|
34
36
|
apply: ["cfn-deploy", "ecs-update-service", "lambda-deploy", "s3-sync", "cdn-invalidate", "run-migration"],
|
|
35
37
|
jobSubmission: ["emr-start-job-run", "emr-submit-step"],
|
|
36
38
|
hostDelivery: ["code-deploy", "copy-to-host", "remote-exec"],
|
|
@@ -42,9 +44,7 @@ export const AWS_VERB_FAMILIES = {
|
|
|
42
44
|
function awsCapabilities(): Array<Capability<never, unknown>> {
|
|
43
45
|
return [
|
|
44
46
|
extractConfigBomCapability,
|
|
45
|
-
publishImageCapability,
|
|
46
47
|
loadImageOnHostCapability,
|
|
47
|
-
publishArtifactCapability,
|
|
48
48
|
cfnDeployCapability,
|
|
49
49
|
ecsUpdateServiceCapability,
|
|
50
50
|
lambdaDeployCapability,
|
|
@@ -75,5 +75,7 @@ export const awsCapabilityPlugin: CapabilityPlugin = {
|
|
|
75
75
|
return ownPackageVersion(import.meta.url);
|
|
76
76
|
},
|
|
77
77
|
capabilities: awsCapabilities,
|
|
78
|
+
registryBackends: () => [ecrRegistryBackend],
|
|
79
|
+
storageBackends: () => [s3StorageBackend],
|
|
78
80
|
families: () => AWS_VERB_FAMILIES,
|
|
79
81
|
};
|