@intentius/chant-lexicon-aws 0.124.46 → 0.124.49

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.
@@ -11,7 +11,7 @@ import { type CapabilityPlugin } from "@intentius/chant/components/capability-pl
11
11
  /** The AWS verb families this plugin contributes, grouped for `families()` — mirrors core's `STARTER_VERB_FAMILIES` shape. */
12
12
  export declare const AWS_VERB_FAMILIES: {
13
13
  readonly sbom: readonly ["extract-config-bom"];
14
- readonly publish: readonly ["publish-image", "load-image-on-host", "publish-artifact"];
14
+ readonly publish: readonly ["load-image-on-host"];
15
15
  readonly apply: readonly ["cfn-deploy", "ecs-update-service", "lambda-deploy", "s3-sync", "cdn-invalidate", "run-migration"];
16
16
  readonly jobSubmission: readonly ["emr-start-job-run", "emr-submit-step"];
17
17
  readonly hostDelivery: readonly ["code-deploy", "copy-to-host", "remote-exec"];
@@ -1 +1 @@
1
- {"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAiBzG,8HAA8H;AAC9H,eAAO,MAAM,iBAAiB;aAE5B,IAAI,YAAG,oBAAoB;aAC3B,OAAO,YAAG,eAAe,EAAE,oBAAoB,EAAE,kBAAkB;aACnE,KAAK,YAAG,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe;aACzG,aAAa,YAAG,mBAAmB,EAAE,iBAAiB;aACtD,YAAY,YAAG,aAAa,EAAE,cAAc,EAAE,aAAa;aAC3D,UAAU,YAAG,gBAAgB,EAAE,mBAAmB,EAAE,UAAU;aAC9D,MAAM,YAAG,iBAAiB,EAAE,mBAAmB;CACvC,CAAC;AA4BX,yHAAyH;AACzH,eAAO,MAAM,mBAAmB,EAAE,gBAWjC,CAAC"}
1
+ {"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../src/components/capability-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,+CAA+C,CAAC;AAiBzG,8HAA8H;AAC9H,eAAO,MAAM,iBAAiB;aAE5B,IAAI,YAAG,oBAAoB;aAG3B,OAAO,YAAG,oBAAoB;aAC9B,KAAK,YAAG,YAAY,EAAE,oBAAoB,EAAE,eAAe,EAAE,SAAS,EAAE,gBAAgB,EAAE,eAAe;aACzG,aAAa,YAAG,mBAAmB,EAAE,iBAAiB;aACtD,YAAY,YAAG,aAAa,EAAE,cAAc,EAAE,aAAa;aAC3D,UAAU,YAAG,gBAAgB,EAAE,mBAAmB,EAAE,UAAU;aAC9D,MAAM,YAAG,iBAAiB,EAAE,mBAAmB;CACvC,CAAC;AA0BX,yHAAyH;AACzH,eAAO,MAAM,mBAAmB,EAAE,gBAajC,CAAC"}
@@ -8,7 +8,7 @@
8
8
  * set carries only the agnostic verbs; the cloud leaves live here.
9
9
  */
10
10
  import { ownPackageVersion } from "@intentius/chant/components/capability-plugin";
11
- import { publishImageCapability, loadImageOnHostCapability, publishArtifactCapability } from "./publish.js";
11
+ import { ecrRegistryBackend, s3StorageBackend, loadImageOnHostCapability } from "./publish.js";
12
12
  import { extractConfigBomCapability } from "./config-bom.js";
13
13
  import { cfnDeployCapability, ecsUpdateServiceCapability, lambdaDeployCapability, s3SyncCapability, cdnInvalidateCapability, runMigrationCapability, } from "./apply.js";
14
14
  import { emrStartJobRunCapability, emrSubmitStepCapability } from "./job-submission.js";
@@ -19,7 +19,9 @@ import { snapshotBeforeCapability, rollbackPreviousCapability } from "./safety.j
19
19
  export const AWS_VERB_FAMILIES = {
20
20
  // `extract-config-bom` parses a synthesized CloudFormation template (#684).
21
21
  sbom: ["extract-config-bom"],
22
- publish: ["publish-image", "load-image-on-host", "publish-artifact"],
22
+ // `publish-image` is core's verb (#3142, #3143); aws contributes its ECR login as a registry backend.
23
+ // `publish-artifact` is core's verb (#4408); aws contributes S3 as a storage backend.
24
+ publish: ["load-image-on-host"],
23
25
  apply: ["cfn-deploy", "ecs-update-service", "lambda-deploy", "s3-sync", "cdn-invalidate", "run-migration"],
24
26
  jobSubmission: ["emr-start-job-run", "emr-submit-step"],
25
27
  hostDelivery: ["code-deploy", "copy-to-host", "remote-exec"],
@@ -30,9 +32,7 @@ export const AWS_VERB_FAMILIES = {
30
32
  function awsCapabilities() {
31
33
  return [
32
34
  extractConfigBomCapability,
33
- publishImageCapability,
34
35
  loadImageOnHostCapability,
35
- publishArtifactCapability,
36
36
  cfnDeployCapability,
37
37
  ecsUpdateServiceCapability,
38
38
  lambdaDeployCapability,
@@ -62,5 +62,7 @@ export const awsCapabilityPlugin = {
62
62
  return ownPackageVersion(import.meta.url);
63
63
  },
64
64
  capabilities: awsCapabilities,
65
+ registryBackends: () => [ecrRegistryBackend],
66
+ storageBackends: () => [s3StorageBackend],
65
67
  families: () => AWS_VERB_FAMILIES,
66
68
  };
@@ -47,89 +47,25 @@
47
47
  import type { Capability } from "@intentius/chant/components/capability";
48
48
  import { type CloudExecutor } from "./cloud-executor.js";
49
49
  import { type ProcessRunner } from "@intentius/chant/components/verbs/process-runner";
50
+ import { type PublishImageBackend, type RegistryLoginBackend } from "@intentius/chant/components/verbs/publish-image";
51
+ import { type ArtifactStorageBackend, type PublishArtifactInput, type PublishArtifactOutput } from "@intentius/chant/components/verbs/publish-artifact";
52
+ export type { PublishImageInput, PublishImageOutput, PublishImageBackend, ReferrerAttachResult, } from "@intentius/chant/components/verbs/publish-image";
50
53
  /**
51
- * Common input shape both image-publish backends accept: promote the image
52
- * bytes at archive path `from` to wherever the deploy target can consume
53
- * them. `to` (registry) and `host` (bare host) are each meaningful to only
54
- * one backend, so a component authors one step shape (see
55
- * docs/components/build-archive.mdx) and the env-selected backend (see
56
- * `selectPublishBackend` below) reads whichever field it needs — the
57
- * unselected backend's field is simply unused, never a pipeline fork.
54
+ * The aws lexicon's registry login for core's `publish-image` (#3142, #3143):
55
+ * `aws ecr get-login-password | docker login`. The aws plugin contributes it;
56
+ * core owns load, tag, push and the digest read-back.
58
57
  */
59
- export interface PublishImageInput {
60
- /** Path of the image tarball inside the build archive (as produced by `docker-build`; an `archive:`-prefixed reference is accepted and stripped). */
61
- from: string;
62
- /** Destination registry — required by `publish-image`, ignored by `load-image-on-host` (e.g. `$env.registry` resolved by the orchestrator). */
63
- to?: string;
64
- /** Target host — required by `load-image-on-host`, ignored by `publish-image` (SSM instance id, hostname, or host group). */
65
- host?: string;
66
- /** Destination path for the tarball on the host, used only by `load-image-on-host`. Default: `/tmp/chant-archive/<basename of from>`. */
67
- hostPath?: string;
68
- /** Additional tags to apply alongside the digest, used only by `publish-image`. */
69
- tags?: string[];
70
- /**
71
- * #610: the artifact's software SBOM (typically wired from a prior
72
- * `generate-sbom` step's `sbom` output — see ./sbom.ts's
73
- * `GenerateSbomOutput`) to attach as an OCI referrer on the pushed image
74
- * digest, via `oras attach`. Used only by `publish-image`; ignored by
75
- * `load-image-on-host` (registry-less — nothing to attach to). Omit to
76
- * skip the attach step entirely (the archive-carried copy remains the
77
- * SBOM's home either way).
78
- */
79
- sbom?: {
80
- bytes: string;
81
- mediaType: string;
82
- };
83
- /**
84
- * #610: the component-level aggregate BOM (wired from
85
- * ./component-bom.ts's `aggregateComponentBom` output), attached as a
86
- * second OCI referrer alongside `sbom` when supplied. Optional and
87
- * independent of `sbom` — a caller may attach either, both, or neither.
88
- */
89
- componentBom?: {
90
- bytes: string;
91
- mediaType: string;
92
- };
93
- }
94
- /** Result of `publish-image`'s best-effort OCI-referrer attach step (#610) — always present when `input.sbom`/`input.componentBom` was supplied, `undefined` when neither was (nothing to attach, attach step skipped entirely). */
95
- export interface ReferrerAttachResult {
96
- /** True once every requested attach (`sbom`, `componentBom`) succeeded. `false` if `oras` was unavailable or any `oras attach` invocation failed. */
97
- attached: boolean;
98
- /** Human-readable reason `attached` is `false` (e.g. "oras is not installed"), omitted when `attached` is `true`. */
99
- reason?: string;
100
- }
101
- export interface PublishImageOutput {
102
- /** Content-addressed digest of the promoted image (`sha256:...`) — what the apply step references. */
103
- digest: string;
104
- /** Image reference the apply step can pull/run: `registry/repo@sha256:...` for `publish-image`, a host-local reference for `load-image-on-host`. */
105
- uri: string;
106
- /** #610: outcome of the best-effort SBOM/component-BOM referrer attach, when `input.sbom`/`input.componentBom` was supplied. `undefined` for `load-image-on-host` (no attach concept — registry-less) and for `publish-image` calls that supplied neither. */
107
- referrerAttach?: ReferrerAttachResult;
108
- }
58
+ export declare function createEcrRegistryBackend(executor?: CloudExecutor): RegistryLoginBackend;
59
+ /** The ECR backend the aws plugin contributes, over the real `CloudExecutor`. */
60
+ export declare const ecrRegistryBackend: RegistryLoginBackend;
109
61
  /**
110
- * Common shape both image-publish backends satisfy: promote the image bytes
111
- * held in the build archive to wherever the deploy target can consume them,
112
- * and return the identity the apply step references. The backend is
113
- * selected per environment (`selectPublishBackend`), never per component.
114
- */
115
- export type PublishImageBackend = Capability<PublishImageInput, PublishImageOutput>;
116
- /**
117
- * Promote a built image from the archive into the environment's container
118
- * registry: `docker load` the archived tarball, tag it for `to` (the env
119
- * registry), `aws ecr get-login-password | docker login`, then `docker push`.
120
- * Returns the pushed image's registry digest — what `cfn-deploy`/
121
- * `ecs-update-service` reference via `imageRef: "@Publish.digest"`. No
122
- * rollback: an already-pushed, still-valid image in the registry is not
123
- * itself a problem to compensate (immutable, content-addressed, and simply
124
- * unreferenced if a later step fails) — the opt-out this capability takes.
125
- *
126
- * #610: when `input.sbom` and/or `input.componentBom` are supplied, also
127
- * attaches them as OCI referrers on the pushed digest via `oras attach` (see
128
- * `attachReferrers` above) — best-effort, guarded on `oras` availability,
129
- * surfaced on the output's `referrerAttach` rather than failing the publish.
62
+ * `publish-image` with ECR as its only login backend: core's verb, bound to
63
+ * this executor. Kept so aws-only callers and tests build it the way they
64
+ * always did; behaviour is unchanged (load, tag, ECR login, push, optional
65
+ * referrer attach).
130
66
  */
131
67
  export declare function createPublishImageCapability(executor?: CloudExecutor, processRunner?: ProcessRunner): PublishImageBackend;
132
- /** Default `publish-image` capability, backed by the real `CloudExecutor`. */
68
+ /** `publish-image` bound to the real executor; the registered verb is core's, with this lexicon's ECR backend injected. */
133
69
  export declare const publishImageCapability: PublishImageBackend;
134
70
  /**
135
71
  * Copy the image tarball straight onto a host and `docker load` it there —
@@ -167,28 +103,23 @@ export type PublishImageBackendKind = "publish-image" | "load-image-on-host";
167
103
  * backends built above.
168
104
  */
169
105
  export declare function selectPublishBackend(kind: PublishImageBackendKind, backends?: Partial<Record<PublishImageBackendKind, PublishImageBackend>>): PublishImageBackend;
170
- export interface PublishArtifactInput {
171
- /** Path of the artifact inside the build archive (e.g. a jar or zip). */
172
- from: string;
173
- /** Destination (e.g. `$env.s3` resolved by the orchestrator). */
174
- to: string;
175
- }
176
- export interface PublishArtifactOutput {
177
- /** Location the artifact was published to — referenced downstream as `@<component>.publish.uri`. */
178
- uri: string;
179
- /** Content hash of the published artifact. */
180
- digest: string;
181
- }
182
- /** Promote a non-image artifact (jar, zip, arbitrary asset) from the archive to S3/CodeArtifact. */
106
+ export type { PublishArtifactInput, PublishArtifactOutput } from "@intentius/chant/components/verbs/publish-artifact";
107
+ /**
108
+ * The aws lexicon's storage backend for core's `publish-artifact`: `aws s3 cp`
109
+ * (endpoint-aware through the `CloudExecutor`). Core owns the digest and the
110
+ * object URI; this only uploads.
111
+ */
112
+ export declare function createS3StorageBackend(executor?: CloudExecutor): ArtifactStorageBackend;
113
+ /** The S3 backend the aws plugin contributes, over the real `CloudExecutor`. */
114
+ export declare const s3StorageBackend: ArtifactStorageBackend;
183
115
  /**
184
- * Publish a single archive artifact (a jar, zip, or asset) to S3 via `aws s3 cp`
185
- * (endpoint-aware through the `CloudExecutor`). Returns the object's URI —
186
- * referenced downstream as `@<component>.publish.uri` — and a content digest of
187
- * the exact bytes uploaded.
116
+ * `publish-artifact` with S3 as its only storage backend: core's verb, bound
117
+ * to this executor. Kept so aws-only callers and tests build it the way they
118
+ * always did; behaviour is unchanged (upload, return uri + content digest).
188
119
  */
189
120
  export declare function createPublishArtifactCapability(executor?: CloudExecutor): Capability<PublishArtifactInput, PublishArtifactOutput>;
190
- /** Default `publish-artifact` capability, backed by the real `CloudExecutor`. */
121
+ /** Default `publish-artifact`, bound to the real executor; the registered verb is core's, with this lexicon's S3 backend injected. */
191
122
  export declare const publishArtifactCapability: Capability<PublishArtifactInput, PublishArtifactOutput>;
192
- /** Alias for `publish-artifact` — same capability, the docs/epic use both names for the same verb. */
123
+ /** Alias for `publish-artifact`: same capability, the docs/epic use both names for the same verb. */
193
124
  export declare const publishAssetCapability: Capability<PublishArtifactInput, PublishArtifactOutput>;
194
125
  //# sourceMappingURL=publish.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/components/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AAGzE,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAA2B,KAAK,aAAa,EAAE,MAAM,kDAAkD,CAAC;AAI/G;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,qJAAqJ;IACrJ,IAAI,EAAE,MAAM,CAAC;IACb,+IAA+I;IAC/I,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,6HAA6H;IAC7H,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,yIAAyI;IACzI,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mFAAmF;IACnF,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;;;;OAQG;IACH,IAAI,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C;;;;;OAKG;IACH,YAAY,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CACrD;AAED,oOAAoO;AACpO,MAAM,WAAW,oBAAoB;IACnC,qJAAqJ;IACrJ,QAAQ,EAAE,OAAO,CAAC;IAClB,qHAAqH;IACrH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,sGAAsG;IACtG,MAAM,EAAE,MAAM,CAAC;IACf,oJAAoJ;IACpJ,GAAG,EAAE,MAAM,CAAC;IACZ,8PAA8P;IAC9P,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC;AAED;;;;;GAKG;AACH,MAAM,MAAM,mBAAmB,GAAG,UAAU,CAAC,iBAAiB,EAAE,kBAAkB,CAAC,CAAC;AA4DpF;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,GAAE,aAAsC,EAChD,aAAa,GAAE,aAAsC,GACpD,mBAAmB,CAgCrB;AAED,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,EAAE,mBAAoD,CAAC;AAU1F;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,GAAE,aAAsC,GAC/C,mBAAmB,CAYrB;AAED,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,EAAE,mBAAuD,CAAC;AAIhG,wGAAwG;AACxG,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAE7E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,GAAE,OAAO,CAAC,MAAM,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,CAGrE,GACA,mBAAmB,CAQrB;AAID,MAAM,WAAW,oBAAoB;IACnC,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,qBAAqB;IACpC,oGAAoG;IACpG,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,oGAAoG;AACpG;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,GAAE,aAAsC,GAC/C,UAAU,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAYzD;AAED,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,EAAE,UAAU,CAAC,oBAAoB,EAAE,qBAAqB,CAC3D,CAAC;AAEpC,sGAAsG;AACtG,eAAO,MAAM,sBAAsB,yDAA4B,CAAC"}
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/components/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACzE,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE5E,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,kDAAkD,CAAC;AAC5G,OAAO,EAEL,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EAC1B,MAAM,iDAAiD,CAAC;AAEzD,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC3B,MAAM,oDAAoD,CAAC;AAI5D,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,iDAAiD,CAAC;AAIzD;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,oBAAoB,CAOvF;AAED,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,EAAE,oBAAiD,CAAC;AAEnF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,GAAE,aAAsC,EAChD,aAAa,GAAE,aAAsC,GACpD,mBAAmB,CAErB;AAED,2HAA2H;AAC3H,eAAO,MAAM,sBAAsB,EAAE,mBAAoD,CAAC;AAU1F;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,GAAE,aAAsC,GAC/C,mBAAmB,CAYrB;AAED,mFAAmF;AACnF,eAAO,MAAM,yBAAyB,EAAE,mBAAuD,CAAC;AAIhG,wGAAwG;AACxG,MAAM,MAAM,uBAAuB,GAAG,eAAe,GAAG,oBAAoB,CAAC;AAE7E;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,QAAQ,GAAE,OAAO,CAAC,MAAM,CAAC,uBAAuB,EAAE,mBAAmB,CAAC,CAGrE,GACA,mBAAmB,CAQrB;AAID,YAAY,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oDAAoD,CAAC;AAEtH;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,CAAC,EAAE,aAAa,GAAG,sBAAsB,CAOvF;AAED,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,EAAE,sBAAiD,CAAC;AAEjF;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,GAAE,aAAsC,GAC/C,UAAU,CAAC,oBAAoB,EAAE,qBAAqB,CAAC,CAEzD;AAED,sIAAsI;AACtI,eAAO,MAAM,yBAAyB,EAAE,UAAU,CAAC,oBAAoB,EAAE,qBAAqB,CAC3D,CAAC;AAEpC,qGAAqG;AACrG,eAAO,MAAM,sBAAsB,yDAA4B,CAAC"}
@@ -44,107 +44,37 @@
44
44
  * image is already successfully promoted by the time this step runs — the
45
45
  * one part of this capability that is genuinely best-effort.
46
46
  */
47
- import { readFileSync } from "node:fs";
48
- import { createHash } from "node:crypto";
49
47
  import { defaultCloudExecutor } from "./cloud-executor.js";
50
48
  import { archiveRelativePath } from "@intentius/chant/components/verbs/build-archive";
51
- import { defaultProcessRunner, q } from "@intentius/chant/components/verbs/process-runner";
52
- // ── publish-image (registry backend) ────────────────────────────────────────
49
+ import { defaultProcessRunner } from "@intentius/chant/components/verbs/process-runner";
50
+ import { createPublishImageCapability as createCorePublishImage, } from "@intentius/chant/components/verbs/publish-image";
51
+ import { createPublishArtifactCapability as createCorePublishArtifact, } from "@intentius/chant/components/verbs/publish-artifact";
52
+ // ── publish-image: the ECR backend (the verb itself is core's) ──────────────
53
53
  /**
54
- * Attempt to `oras attach` one referrer document (SBOM or component BOM) to
55
- * `imageRef`'s digest. Writes the document's bytes to a scratch file (`oras
56
- * attach` reads from a file path, not stdin) and shells out through
57
- * `runner`. Never throws — a failure here is reported back to the caller as
58
- * `{ ok: false, reason }` so a missing/erroring `oras` never fails the
59
- * publish itself (see `attachReferrers`'s doc comment for why).
54
+ * The aws lexicon's registry login for core's `publish-image` (#3142, #3143):
55
+ * `aws ecr get-login-password | docker login`. The aws plugin contributes it;
56
+ * core owns load, tag, push and the digest read-back.
60
57
  */
61
- async function attachOneReferrer(runner, imageRef, doc, label) {
62
- try {
63
- const scratchFile = `/tmp/chant-referrer-attach/${label}-${Date.now()}.json`;
64
- await runner.run(`mkdir -p ${q("/tmp/chant-referrer-attach")}`);
65
- await runner.run(`printf '%s' ${q(doc.bytes)} > ${q(scratchFile)}`);
66
- await runner.run(`oras attach --artifact-type ${q(doc.mediaType)} ${q(imageRef)} ${q(scratchFile)}:${q(doc.mediaType)}`);
67
- return { ok: true };
68
- }
69
- catch (err) {
70
- return { ok: false, reason: err instanceof Error ? err.message : String(err) };
71
- }
72
- }
73
- /**
74
- * Best-effort OCI-referrer attach for a just-pushed image (#610): attaches
75
- * `input.sbom` and/or `input.componentBom`, when supplied, to `imageRef` via
76
- * `oras attach`. Guarded on `oras` availability — a missing binary is
77
- * reported back as `{ attached: false, reason }` rather than thrown, since
78
- * the image itself is already successfully promoted by the time this step
79
- * runs (attach is additive registry-side convenience on top of the
80
- * archive-carried copy, per this module's doc comment, never a condition the
81
- * core promote-by-digest job depends on). Returns `undefined` when neither
82
- * `input.sbom` nor `input.componentBom` was supplied — nothing to attach,
83
- * skipped entirely, no `oras` call at all.
84
- */
85
- async function attachReferrers(runner, imageRef, input) {
86
- if (!input.sbom && !input.componentBom)
87
- return undefined;
88
- if (!(await runner.available("oras"))) {
89
- return { attached: false, reason: `"oras" is not installed or not on PATH — required to attach OCI referrers` };
90
- }
91
- const results = [];
92
- if (input.sbom)
93
- results.push(await attachOneReferrer(runner, imageRef, input.sbom, "sbom"));
94
- if (input.componentBom)
95
- results.push(await attachOneReferrer(runner, imageRef, input.componentBom, "component-bom"));
96
- const failed = results.find((r) => !r.ok);
97
- return failed ? { attached: false, reason: failed.reason } : { attached: true };
58
+ export function createEcrRegistryBackend(executor) {
59
+ return {
60
+ name: "ecr",
61
+ matches: (registry) => /\.dkr\.ecr(-fips)?\.[a-z0-9-]+\.amazonaws\.com(\.cn)?$/.test(registry),
62
+ // The real executor is built on first login, so loading the plugin shells out to nothing.
63
+ login: (registry) => (executor ?? defaultCloudExecutor()).ecr.login(registry),
64
+ };
98
65
  }
66
+ /** The ECR backend the aws plugin contributes, over the real `CloudExecutor`. */
67
+ export const ecrRegistryBackend = createEcrRegistryBackend();
99
68
  /**
100
- * Promote a built image from the archive into the environment's container
101
- * registry: `docker load` the archived tarball, tag it for `to` (the env
102
- * registry), `aws ecr get-login-password | docker login`, then `docker push`.
103
- * Returns the pushed image's registry digest — what `cfn-deploy`/
104
- * `ecs-update-service` reference via `imageRef: "@Publish.digest"`. No
105
- * rollback: an already-pushed, still-valid image in the registry is not
106
- * itself a problem to compensate (immutable, content-addressed, and simply
107
- * unreferenced if a later step fails) — the opt-out this capability takes.
108
- *
109
- * #610: when `input.sbom` and/or `input.componentBom` are supplied, also
110
- * attaches them as OCI referrers on the pushed digest via `oras attach` (see
111
- * `attachReferrers` above) — best-effort, guarded on `oras` availability,
112
- * surfaced on the output's `referrerAttach` rather than failing the publish.
69
+ * `publish-image` with ECR as its only login backend: core's verb, bound to
70
+ * this executor. Kept so aws-only callers and tests build it the way they
71
+ * always did; behaviour is unchanged (load, tag, ECR login, push, optional
72
+ * referrer attach).
113
73
  */
114
74
  export function createPublishImageCapability(executor = defaultCloudExecutor(), processRunner = defaultProcessRunner()) {
115
- return {
116
- kind: "publish-image",
117
- async run(_ctx, input) {
118
- if (!input.to)
119
- throw new Error(`publish-image "${input.from}": "to" (destination registry) is required`);
120
- // `docker load` reports the archived image's local reference — a name:tag
121
- // for a tagged build, or an image id. It's a valid `docker tag` source but
122
- // never a registry digest, so the promoted digest is read back from the
123
- // push below, not constructed from this.
124
- const { digest: localRef } = await executor.docker.load({ inFile: archiveRelativePath(input.from) });
125
- const repo = input.to.replace(/\/+$/, "");
126
- // Publish under a tag: docker can neither tag nor push a digest-qualified
127
- // reference (`repo@sha256:...`), so the transport is a tag and the stable
128
- // identifier is the digest the push returns.
129
- const pushRef = `${repo}:latest`;
130
- await executor.docker.tag({ source: localRef, target: pushRef });
131
- const registry = repo.split("/")[0];
132
- await executor.ecr.login(registry);
133
- const { digest: pushed } = await executor.docker.push({ image: pushRef });
134
- // Normalize to a bare `sha256:...`, whether the client returned that or a
135
- // full `repo@sha256:...` RepoDigest.
136
- const digest = pushed.includes("@") ? pushed.slice(pushed.indexOf("@") + 1) : pushed;
137
- for (const tag of input.tags ?? []) {
138
- const tagged = `${repo}:${tag}`;
139
- await executor.docker.tag({ source: localRef, target: tagged });
140
- await executor.docker.push({ image: tagged });
141
- }
142
- const referrerAttach = await attachReferrers(processRunner, `${repo}@${digest}`, input);
143
- return { digest, uri: `${repo}@${digest}`, ...(referrerAttach ? { referrerAttach } : {}) };
144
- },
145
- };
75
+ return createCorePublishImage({ docker: executor.docker, processRunner, backends: [createEcrRegistryBackend(executor)] });
146
76
  }
147
- /** Default `publish-image` capability, backed by the real `CloudExecutor`. */
77
+ /** `publish-image` bound to the real executor; the registered verb is core's, with this lexicon's ECR backend injected. */
148
78
  export const publishImageCapability = createPublishImageCapability();
149
79
  // ── load-image-on-host (host backend) ───────────────────────────────────────
150
80
  /** Default on-host tarball destination when `hostPath` is omitted, derived from the archive path's basename. */
@@ -208,27 +138,30 @@ export function selectPublishBackend(kind, backends = {
208
138
  }
209
139
  return backend;
210
140
  }
211
- /** Promote a non-image artifact (jar, zip, arbitrary asset) from the archive to S3/CodeArtifact. */
212
141
  /**
213
- * Publish a single archive artifact (a jar, zip, or asset) to S3 via `aws s3 cp`
214
- * (endpoint-aware through the `CloudExecutor`). Returns the object's URI —
215
- * referenced downstream as `@<component>.publish.uri` — and a content digest of
216
- * the exact bytes uploaded.
142
+ * The aws lexicon's storage backend for core's `publish-artifact`: `aws s3 cp`
143
+ * (endpoint-aware through the `CloudExecutor`). Core owns the digest and the
144
+ * object URI; this only uploads.
217
145
  */
218
- export function createPublishArtifactCapability(executor = defaultCloudExecutor()) {
146
+ export function createS3StorageBackend(executor) {
219
147
  return {
220
- kind: "publish-artifact",
221
- async run(_ctx, input) {
222
- const localPath = archiveRelativePath(input.from);
223
- const digest = `sha256:${createHash("sha256").update(readFileSync(localPath)).digest("hex")}`;
224
- const basename = localPath.split("/").pop() ?? localPath;
225
- const uri = input.to.endsWith("/") ? `${input.to}${basename}` : input.to;
226
- await executor.s3.cp({ from: localPath, to: uri });
227
- return { uri, digest };
228
- },
148
+ name: "s3",
149
+ matches: (uri) => uri.startsWith("s3://"),
150
+ // The real executor is built on first upload, so loading the plugin shells out to nothing.
151
+ upload: (args) => (executor ?? defaultCloudExecutor()).s3.cp(args),
229
152
  };
230
153
  }
231
- /** Default `publish-artifact` capability, backed by the real `CloudExecutor`. */
154
+ /** The S3 backend the aws plugin contributes, over the real `CloudExecutor`. */
155
+ export const s3StorageBackend = createS3StorageBackend();
156
+ /**
157
+ * `publish-artifact` with S3 as its only storage backend: core's verb, bound
158
+ * to this executor. Kept so aws-only callers and tests build it the way they
159
+ * always did; behaviour is unchanged (upload, return uri + content digest).
160
+ */
161
+ export function createPublishArtifactCapability(executor = defaultCloudExecutor()) {
162
+ return createCorePublishArtifact({ backends: [createS3StorageBackend(executor)] });
163
+ }
164
+ /** Default `publish-artifact`, bound to the real executor; the registered verb is core's, with this lexicon's S3 backend injected. */
232
165
  export const publishArtifactCapability = createPublishArtifactCapability();
233
- /** Alias for `publish-artifact` — same capability, the docs/epic use both names for the same verb. */
166
+ /** Alias for `publish-artifact`: same capability, the docs/epic use both names for the same verb. */
234
167
  export const publishAssetCapability = publishArtifactCapability;
@@ -1,5 +1,7 @@
1
1
  import type { TemplateParser, TemplateIR } from "@intentius/chant/import/parser";
2
2
  import { BaseValueParser } from "@intentius/chant/import/base-parser";
3
+ import yaml from "js-yaml";
4
+ export declare const CF_SCHEMA: yaml.Schema;
3
5
  /**
4
6
  * Parser for CloudFormation JSON templates.
5
7
  * Extends BaseValueParser for generic recursive value walking;
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EAKX,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AA4KtE;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,eAAgB,YAAW,cAAc;IACrE;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA4BjC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CASrC;IAEH,OAAO,CAAC,6BAA6B;IAUrC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,CAuJtG;CACF"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/import/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,UAAU,EAKX,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,IAAI,MAAM,SAAS,CAAC;AAyG3B,eAAO,MAAM,SAAS,aAA2C,CAAC;AAkElE;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,eAAgB,YAAW,cAAc;IACrE;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CA4BjC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,gBAAgB,CASrC;IAEH,OAAO,CAAC,6BAA6B;IAUrC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,eAAe;IAWvB;;OAEG;IACH,OAAO,CAAC,YAAY;IAYpB;;OAEG;IACH,OAAO,CAAC,eAAe;IAgBvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAkBtB;;OAEG;IACH,OAAO,CAAC,eAAe;IAUvB;;OAEG;IACH,SAAS,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,GAAG,IAAI,CAuJtG;CACF"}
@@ -102,7 +102,7 @@ const cfnYamlTypes = [
102
102
  construct: (data) => ({ Condition: data }),
103
103
  }),
104
104
  ];
105
- const CF_SCHEMA = yaml.DEFAULT_SCHEMA.extend(cfnYamlTypes);
105
+ export const CF_SCHEMA = yaml.DEFAULT_SCHEMA.extend(cfnYamlTypes);
106
106
  /** Parameter keys import carries besides Type, Description and Default. */
107
107
  const PARAMETER_CONSTRAINT_KEYS = [
108
108
  "AllowedValues",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "8c88e8750ff98569d97921403ae44dfba0065e512d6dee2de6a912897cd84e66",
4
+ "manifest.json": "1faf3be1e82f5522c3e68e47075e42fecbd612aed648a58632778973376570cc",
5
5
  "meta.json": "6f48557ed4203cbdeafdb47e7270fdf3533f6d6e6189987246301ed8e72170e9",
6
6
  "types/index.d.ts": "8651f9ae166668f4311eea1fe61c3fe235f345947951c1d23d1df24a4fd3384f",
7
7
  "rules/hardcoded-region.ts": "957eadcaa9f39cc17d21437565d7a94607d9b082cf28918b178fa067f07498a9",
@@ -75,5 +75,5 @@
75
75
  "skills/chant-aws-eks.md": "8789255709ff004ad0a875fd5999edcdc66fc6e33d710db058d9f42703bcfdfe",
76
76
  "skills/chant-aws-carve-terraform.md": "8780b94ce60aded935938d5ef20ea667738354051da1bf9ca6d70d9886f65d21"
77
77
  },
78
- "composite": "c3e022363a232d4ee358a6f31700ecb1ee3d51b871d2a1efddb4655291562233"
78
+ "composite": "1a1d9184cfab96a1e828dbec19a1848c145ec74ab63cc8c1fb04d50dd2048250"
79
79
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws",
3
- "version": "0.124.46",
3
+ "version": "0.124.49",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "AWS",
6
6
  "intrinsics": [
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAqQ,MAAM,0BAA0B,CAAC;AAwCjU;yEACyE;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAiBnD,eAAO,MAAM,SAAS,EAAE,aAgkCvB,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAqQ,MAAM,0BAA0B,CAAC;AAyCjU;yEACyE;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAiBnD,eAAO,MAAM,SAAS,EAAE,aA+kCvB,CAAC"}
package/dist/plugin.js CHANGED
@@ -24,6 +24,7 @@ import { canDescribe, describeOwnProperties, stampRegion } from "./properties.js
24
24
  import { stampProviderDefaults } from "./defaults.js";
25
25
  import { resolveTemplateAttrs } from "./live-attrs.js";
26
26
  import { CFParser } from "./import/parser.js";
27
+ import { lastMemberReport, readCloudFormationMember, setLastMemberReport } from "./workspace-member.js";
27
28
  import { CFGenerator } from "./import/generator.js";
28
29
  import { parseStackTemplate } from "./import/live-export.js";
29
30
  import { awsCompletions } from "./lsp/completions.js";
@@ -49,6 +50,22 @@ const OWNERSHIP_UNRESOLVED_NOTE = "ownership filter not applied on describeResou
49
50
  export const awsPlugin = {
50
51
  behaviourKinds: awsBehaviourKinds,
51
52
  name: "aws",
53
+ // A cloudformation workspace member's reader project (#3179): the template's
54
+ // resources as nodes, its Ref, GetAtt, Sub and DependsOn as edges. See
55
+ // ./workspace-member.ts.
56
+ async buildRoots(ctx) {
57
+ setLastMemberReport(undefined);
58
+ const member = ctx.config.aws?.member;
59
+ if (!member)
60
+ return { entities: new Map() };
61
+ const read = readCloudFormationMember({ member });
62
+ setLastMemberReport(read.report);
63
+ return { entities: read.entities, warnings: read.warnings };
64
+ },
65
+ graphMeta() {
66
+ const report = lastMemberReport();
67
+ return report ? { awsMember: report } : undefined;
68
+ },
52
69
  // The thin read's marker channel is the STACK's own tags (#1998), read off
53
70
  // the DescribeStacks call it already makes for the outputs.
54
71
  // describe-stack-resources carries no per-resource tags, so the stack is the
@@ -0,0 +1,34 @@
1
+ import { type Declarable } from "@intentius/chant/declarable";
2
+ export interface AwsMemberConfig {
3
+ /** `cloudformation` (the default) or `cdk`. */
4
+ kind?: "cloudformation" | "cdk";
5
+ /** The member's directory, absolute. */
6
+ dir: string;
7
+ /** Names the entities (`<label>/Bucket`): the member's name. */
8
+ label?: string;
9
+ }
10
+ /** What the read found, carried on the graph's `meta.awsMember`. */
11
+ export interface AwsMemberReport {
12
+ /** The template files read, relative to the member's directory (or its assembly's). */
13
+ templates: string[];
14
+ objects: number;
15
+ /** CDK only: false when the app has no synthesized assembly to read. */
16
+ synthesized?: boolean;
17
+ /** Why nothing was read; set with `synthesized: false`. */
18
+ reason?: string;
19
+ }
20
+ export declare function readCloudFormationMember(opts: {
21
+ member: AwsMemberConfig;
22
+ }): {
23
+ entities: Map<string, Declarable>;
24
+ warnings: string[];
25
+ report: AwsMemberReport;
26
+ };
27
+ /**
28
+ * The report of the read in this process. `graphMeta` receives only the
29
+ * entities, so the hook that read the member leaves its report here for the
30
+ * hook that publishes it; `chant graph` runs the two in order in one process.
31
+ */
32
+ export declare function setLastMemberReport(report: AwsMemberReport | undefined): void;
33
+ export declare function lastMemberReport(): AwsMemberReport | undefined;
34
+ //# sourceMappingURL=workspace-member.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace-member.d.ts","sourceRoot":"","sources":["../src/workspace-member.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAqB,KAAK,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAKjF,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,CAAC;IAChC,wCAAwC;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,uFAAuF;IACvF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoED,wBAAgB,wBAAwB,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAAG;IAC3E,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,eAAe,CAAC;CACzB,CA4DA;AAID;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAE7E;AAED,wBAAgB,gBAAgB,IAAI,eAAe,GAAG,SAAS,CAE9D"}