@kungfu-tech/buildchain 3.0.4-alpha.2 → 3.0.4-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/bin/buildchain.mjs +126 -72
  2. package/bin/internal/trust-release-cli.mjs +15 -537
  3. package/bin/internal/trust-release-command-handlers.mjs +14 -0
  4. package/bin/internal/trust-release-inspection-handlers.mjs +175 -0
  5. package/bin/internal/trust-release-release-handlers.mjs +317 -0
  6. package/bin/internal/trust-release-verification-handlers.mjs +306 -0
  7. package/dist/site/buildchain-contract.json +35 -24
  8. package/dist/site/buildchain-site.json +22 -10
  9. package/dist/site/controller-registry.json +16 -3
  10. package/dist/site/kfd-claims.json +9 -7
  11. package/dist/site/kfd-upstream-aggregate.json +1 -1
  12. package/dist/site/manual-registry.json +2 -2
  13. package/dist/site/node-api-registry.json +7 -7
  14. package/dist/site/page-registry.json +9 -4
  15. package/dist/site/public-surface-audit.json +56 -8
  16. package/dist/site/publication-registry.json +4 -4
  17. package/dist/site/release-model.json +7 -0
  18. package/dist/site/site-manifest.json +6 -6
  19. package/dist/site/workflow-registry.json +13 -5
  20. package/docs/MAP.md +1 -1
  21. package/docs/release-propagation.md +166 -8
  22. package/package.json +1 -1
  23. package/packages/core/buildchain-kfd-claims.js +1 -1
  24. package/packages/core/controller-evidence.js +8 -1
  25. package/packages/core/index.js +1 -13
  26. package/packages/core/paper-npm-bootstrap.js +492 -0
  27. package/packages/core/paper.js +271 -669
  28. package/packages/core/public-surface-cli.js +12 -1
  29. package/packages/core/release-passport.js +67 -71
  30. package/packages/core/release-propagation-common.js +64 -0
  31. package/packages/core/release-propagation-execution-profile.js +59 -0
  32. package/packages/core/release-propagation-release.js +196 -0
  33. package/packages/core/release-propagation-stage-evidence.js +364 -0
  34. package/packages/core/release-propagation-work-capture.js +64 -0
  35. package/packages/core/release-propagation-work-constants.js +34 -0
  36. package/packages/core/release-propagation-work-control.js +203 -0
  37. package/packages/core/release-propagation-work-transitions.js +145 -0
  38. package/packages/core/release-propagation-work.js +517 -0
  39. package/packages/core/release-propagation.js +34 -158
  40. package/scripts/aws-windows-jit-controller-core.mjs +269 -0
  41. package/scripts/aws-windows-jit-controller.mjs +502 -0
  42. package/scripts/check-internal-architecture.mjs +178 -52
  43. package/scripts/check-maintainability.mjs +76 -17
  44. package/scripts/generate-site-bundle.mjs +16 -7
  45. package/scripts/maintainability-metrics.mjs +24 -4
  46. package/scripts/release-propagation.mjs +126 -0
  47. package/scripts/resolve-artifact-transfer-mode.mjs +117 -0
  48. package/scripts/web-surface-core.mjs +46 -207
  49. package/scripts/web-surface-routing.mjs +286 -0
@@ -3,9 +3,17 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import {
6
+ claimReleasePropagationWork,
7
+ completeReleasePropagationWork,
6
8
  createReleasePropagationReceipt,
9
+ createReleasePropagationStageReceipt,
10
+ createReleasePropagationWork,
7
11
  planReleasePropagation,
8
12
  readReleasePropagationJson,
13
+ recordReleasePropagationStage,
14
+ repairReleasePropagationWork,
15
+ resumeReleasePropagationWork,
16
+ verifyReleasePropagationWork,
9
17
  writeReleasePropagationLock,
10
18
  } from "../packages/core/release-propagation.js";
11
19
 
@@ -25,6 +33,34 @@ function usage() {
25
33
  [--production-state <state>]
26
34
  [--observed-at <iso-8601>]
27
35
  [--output <file>] [--json]
36
+ buildchain release-propagation work create --plan <json-or-path>
37
+ --expected-downstream-base-sha <git-sha>
38
+ [--work-context <json-or-path>]
39
+ [--target <id-or-repo>]
40
+ [--output <file>] [--json]
41
+ buildchain release-propagation work status --work <json-or-path> [--json]
42
+ buildchain release-propagation work resume --work <json-or-path> [--json]
43
+ buildchain release-propagation work claim --work <json-or-path>
44
+ --authority <json-or-path>
45
+ --expected-work-root <sha256:...>
46
+ [--family-state <json-or-path>]
47
+ [--output <file>] [--json]
48
+ buildchain release-propagation work receipt --work <json-or-path>
49
+ --receipt-input <json-or-path>
50
+ [--output <file>] [--json]
51
+ buildchain release-propagation work record --work <json-or-path>
52
+ --receipt <json-or-path>
53
+ --expected-work-root <sha256:...>
54
+ [--output <file>] [--json]
55
+ buildchain release-propagation work repair --work <json-or-path>
56
+ --receipt <json-or-path>
57
+ --expected-work-root <sha256:...>
58
+ [--output <file>] [--json]
59
+ buildchain release-propagation work complete --work <json-or-path>
60
+ --receipt <json-or-path>
61
+ --completion-decision <json-or-path>
62
+ --expected-work-root <sha256:...>
63
+ [--output <file>] [--json]
28
64
  `;
29
65
  }
30
66
 
@@ -49,6 +85,92 @@ function writeOutput(filePath, value) {
49
85
  fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`);
50
86
  }
51
87
 
88
+ function readJsonFlag(args, name) {
89
+ return readReleasePropagationJson(readFlag(args, name), {
90
+ label: `--${name}`,
91
+ cwd: process.cwd(),
92
+ });
93
+ }
94
+
95
+ function readOptionalJsonFlag(args, name) {
96
+ return args.includes(`--${name}`) ? readJsonFlag(args, name) : undefined;
97
+ }
98
+
99
+ function emitWorkResult(args, value, summary) {
100
+ writeOutput(readFlag(args, "output", ""), value);
101
+ if (hasFlag(args, "json")) {
102
+ printJson(value);
103
+ } else {
104
+ process.stdout.write(`${summary}\n`);
105
+ }
106
+ }
107
+
108
+ function runWorkCli(args) {
109
+ const [mode = "", ...workArgs] = args;
110
+ if (!mode || mode === "--help" || mode === "-h") {
111
+ process.stdout.write(usage());
112
+ return;
113
+ }
114
+ if (mode === "create") {
115
+ const result = createReleasePropagationWork({
116
+ plan: readJsonFlag(workArgs, "plan"),
117
+ target: readFlag(workArgs, "target", ""),
118
+ workContext: readOptionalJsonFlag(workArgs, "work-context"),
119
+ expectedDownstreamBaseSha: readFlag(workArgs, "expected-downstream-base-sha"),
120
+ });
121
+ emitWorkResult(workArgs, result, `release propagation work: ${result.contentRoot}`);
122
+ return;
123
+ }
124
+ if (mode === "status" || mode === "resume") {
125
+ const work = readJsonFlag(workArgs, "work");
126
+ const result = mode === "resume"
127
+ ? resumeReleasePropagationWork(work)
128
+ : verifyReleasePropagationWork(work);
129
+ emitWorkResult(workArgs, result, `release propagation next action: ${result.nextAction.action} ${result.currentStage}`);
130
+ return;
131
+ }
132
+ if (mode === "claim") {
133
+ const result = claimReleasePropagationWork({
134
+ work: readJsonFlag(workArgs, "work"),
135
+ authority: readJsonFlag(workArgs, "authority"),
136
+ familyState: readOptionalJsonFlag(workArgs, "family-state"),
137
+ expectedWorkRoot: readFlag(workArgs, "expected-work-root"),
138
+ });
139
+ emitWorkResult(workArgs, result, `release propagation work claimed: ${result.contentRoot}`);
140
+ return;
141
+ }
142
+ if (mode === "receipt") {
143
+ const work = readJsonFlag(workArgs, "work");
144
+ const input = readJsonFlag(workArgs, "receipt-input");
145
+ const result = createReleasePropagationStageReceipt({ work, ...input });
146
+ emitWorkResult(workArgs, result, `release propagation stage receipt: ${result.receiptRoot}`);
147
+ return;
148
+ }
149
+ if (mode === "record" || mode === "repair") {
150
+ const transition = {
151
+ work: readJsonFlag(workArgs, "work"),
152
+ receipt: readJsonFlag(workArgs, "receipt"),
153
+ expectedWorkRoot: readFlag(workArgs, "expected-work-root"),
154
+ };
155
+ const result = mode === "record"
156
+ ? recordReleasePropagationStage(transition)
157
+ : repairReleasePropagationWork(transition);
158
+ emitWorkResult(workArgs, result, `release propagation work advanced: ${result.contentRoot}`);
159
+ return;
160
+ }
161
+ if (mode === "complete") {
162
+ const result = completeReleasePropagationWork({
163
+ work: readJsonFlag(workArgs, "work"),
164
+ receipt: readJsonFlag(workArgs, "receipt"),
165
+ completionDecision: readJsonFlag(workArgs, "completion-decision"),
166
+ expectedWorkRoot: readFlag(workArgs, "expected-work-root"),
167
+ });
168
+ emitWorkResult(workArgs, result, `release propagation work complete: ${result.contentRoot}`);
169
+ return;
170
+ }
171
+ throw new Error(`unsupported release-propagation work command: ${mode}`);
172
+ }
173
+
52
174
  export function runReleasePropagationCli(argv = process.argv.slice(2)) {
53
175
  const [mode = "", ...args] = argv;
54
176
  if (!mode || mode === "--help" || mode === "-h") {
@@ -80,6 +202,10 @@ export function runReleasePropagationCli(argv = process.argv.slice(2)) {
80
202
  }
81
203
  return;
82
204
  }
205
+ if (mode === "work") {
206
+ runWorkCli(args);
207
+ return;
208
+ }
83
209
  if (mode === "write-lock") {
84
210
  const plan = readReleasePropagationJson(readFlag(args, "plan"), {
85
211
  label: "--plan",
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { pathToFileURL } from "node:url";
6
+
7
+ const VALID_MODES = new Set(["github-artifacts", "s3-to-github-artifacts"]);
8
+
9
+ function firstValue(...values) {
10
+ return values.find((value) => String(value || "").trim()) || "";
11
+ }
12
+
13
+ function resolveArtifactTransferMode(env = process.env) {
14
+ const mode = env.INPUT_TRANSFER_MODE || "github-artifacts";
15
+ if (!VALID_MODES.has(mode)) {
16
+ throw new Error(
17
+ `artifact-transfer-mode must be github-artifacts or s3-to-github-artifacts, got: ${mode}`,
18
+ );
19
+ }
20
+ if (mode === "github-artifacts") {
21
+ return {
22
+ mode,
23
+ s3Bucket: "",
24
+ s3Region: "",
25
+ s3Prefix: "",
26
+ oidcAudience: "",
27
+ };
28
+ }
29
+ const s3Bucket = firstValue(env.INPUT_S3_BUCKET, env.VAR_S3_BUCKET);
30
+ const s3Region = firstValue(env.INPUT_S3_REGION, env.VAR_S3_REGION);
31
+ const s3Prefix = firstValue(
32
+ env.INPUT_S3_PREFIX,
33
+ env.VAR_S3_PREFIX,
34
+ "buildchain-artifacts",
35
+ );
36
+ const uploadRole = firstValue(
37
+ env.INPUT_S3_UPLOAD_ROLE_ARN,
38
+ env.VAR_S3_UPLOAD_ROLE_ARN,
39
+ env.SECRET_S3_UPLOAD_ROLE_ARN,
40
+ env.INPUT_S3_ROLE_ARN,
41
+ env.VAR_S3_ROLE_ARN,
42
+ env.SECRET_S3_ROLE_ARN,
43
+ );
44
+ const downloadRole = firstValue(
45
+ env.INPUT_S3_DOWNLOAD_ROLE_ARN,
46
+ env.VAR_S3_DOWNLOAD_ROLE_ARN,
47
+ env.SECRET_S3_DOWNLOAD_ROLE_ARN,
48
+ env.INPUT_S3_ROLE_ARN,
49
+ env.VAR_S3_ROLE_ARN,
50
+ env.SECRET_S3_ROLE_ARN,
51
+ );
52
+ if (!s3Bucket) {
53
+ throw new Error(
54
+ "artifact-transfer-mode=s3-to-github-artifacts requires artifact-relay-s3-bucket or BUILDCHAIN_ARTIFACT_RELAY_S3_BUCKET",
55
+ );
56
+ }
57
+ if (!s3Region) {
58
+ throw new Error(
59
+ "artifact-transfer-mode=s3-to-github-artifacts requires artifact-relay-s3-region or BUILDCHAIN_ARTIFACT_RELAY_S3_REGION",
60
+ );
61
+ }
62
+ if (!uploadRole) {
63
+ throw new Error(
64
+ "artifact-transfer-mode=s3-to-github-artifacts requires an upload role ARN input, variable, or secret",
65
+ );
66
+ }
67
+ if (!downloadRole) {
68
+ throw new Error(
69
+ "artifact-transfer-mode=s3-to-github-artifacts requires a download role ARN input, variable, or secret",
70
+ );
71
+ }
72
+ const oidcAudience = firstValue(
73
+ env.INPUT_OIDC_AUDIENCE,
74
+ env.VAR_OIDC_AUDIENCE,
75
+ s3Region.startsWith("cn-") ? "sts.amazonaws.com.cn" : "sts.amazonaws.com",
76
+ );
77
+ return { mode, s3Bucket, s3Region, s3Prefix, oidcAudience };
78
+ }
79
+
80
+ function writeArtifactTransferOutputs(outputPath, resolution) {
81
+ if (!outputPath) {
82
+ throw new Error("GITHUB_OUTPUT is required");
83
+ }
84
+ fs.mkdirSync(path.dirname(path.resolve(outputPath)), { recursive: true });
85
+ fs.appendFileSync(
86
+ outputPath,
87
+ [
88
+ `mode=${resolution.mode}`,
89
+ `s3-bucket=${resolution.s3Bucket}`,
90
+ `s3-region=${resolution.s3Region}`,
91
+ `s3-prefix=${resolution.s3Prefix}`,
92
+ `oidc-audience=${resolution.oidcAudience}`,
93
+ "",
94
+ ].join("\n"),
95
+ );
96
+ }
97
+
98
+ function main() {
99
+ const resolution = resolveArtifactTransferMode();
100
+ writeArtifactTransferOutputs(process.env.GITHUB_OUTPUT, resolution);
101
+ }
102
+
103
+ if (
104
+ process.argv[1] &&
105
+ import.meta.url === pathToFileURL(path.resolve(process.argv[1])).href
106
+ ) {
107
+ try {
108
+ main();
109
+ } catch (error) {
110
+ console.error(
111
+ `::error::${error instanceof Error ? error.message : String(error)}`,
112
+ );
113
+ process.exitCode = 1;
114
+ }
115
+ }
116
+
117
+ export { resolveArtifactTransferMode, writeArtifactTransferOutputs };
@@ -9,6 +9,29 @@ import { fileURLToPath } from "node:url";
9
9
  import { loadBuildchainConfig, validateBuildchainConfig } from "../packages/core/buildchain-config.js";
10
10
  import { createSurfaceTimestampPolicy } from "../packages/core/surface-manifest.js";
11
11
  import { validateInstallerPublication, verifyInstallerPublicReadback } from "./installer-publication.mjs";
12
+ import {
13
+ classifyPreviewAlias,
14
+ resolveChannelUrl,
15
+ resolvePathOnlyUrl,
16
+ resolveSurfaceUrl,
17
+ manifestPrefixFor,
18
+ objectPrefixFor,
19
+ normalizeSurfacePath,
20
+ surfaceDeployConfig,
21
+ surfaceObjectPrefixFor,
22
+ normalizeS3Key,
23
+ joinS3Key,
24
+ joinUrlPath,
25
+ urlWithPath,
26
+ s3Uri,
27
+ cdnPath,
28
+ cdnWildcardPath,
29
+ viewerWildcardPath,
30
+ surfaceArtifactPrefix,
31
+ surfaceArtifactRootFor,
32
+ syncStaticArtifactArgs,
33
+ mutableCacheControlArgs,
34
+ } from "./web-surface-routing.mjs";
12
35
 
13
36
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
14
37
 
@@ -89,231 +112,47 @@ function retentionConfig(config, channel) {
89
112
  };
90
113
  }
91
114
 
92
- function classifyPreviewAlias(alias) {
93
- if (/^pr-\d+$/.test(alias)) {
94
- return {
95
- kind: "pr",
96
- mutable: true,
97
- retentionClass: "preview-pr-ephemeral",
98
- retentionKey: "pr_days",
99
- };
100
- }
101
- if (/^sha-[0-9a-f]{6,40}$/i.test(alias)) {
102
- return {
103
- kind: "sha",
104
- mutable: false,
105
- retentionClass: "preview-sha-immutable",
106
- retentionKey: "sha_days",
107
- };
108
- }
109
- return {
110
- kind: "custom",
111
- mutable: true,
112
- retentionClass: "preview-custom-ephemeral",
113
- retentionKey: "pr_days",
114
- };
115
- }
116
115
 
117
- function resolveChannelUrl(channel, alias) {
118
- if (channel.urlPattern) {
119
- if (!alias) {
120
- throw new Error(`channel ${channel.name} requires alias for url_pattern`);
121
- }
122
- return channel.urlPattern.replaceAll("{alias}", alias);
123
- }
124
- return channel.url;
125
- }
126
116
 
127
- function resolvePathOnlyUrl(channel, sourcePath, alias) {
128
- const base = resolveChannelUrl(channel, alias);
129
- const url = new URL(base);
130
- const normalizedPath = normalizeSurfacePath(sourcePath);
131
- if (normalizedPath === "/") {
132
- return `${url.origin}/`;
133
- }
134
- return new URL(normalizedPath.replace(/^\//, ""), `${url.origin}/`).toString();
135
- }
136
117
 
137
- function resolveSurfaceUrl({ surface, channel, channelName, alias }) {
138
- if (channelName === "preview" && surface.previewUrlPattern) {
139
- if (!alias) {
140
- throw new Error(`surface ${surface.name} requires alias for preview_url_pattern`);
141
- }
142
- return surface.previewUrlPattern.replaceAll("{alias}", alias);
143
- }
144
- if (channelName === "staging" && surface.stagingUrl) {
145
- return surface.stagingUrl;
146
- }
147
- if (channelName === "production" && surface.productionUrl) {
148
- return surface.productionUrl;
149
- }
150
- if (surface.pathOnly) {
151
- return resolvePathOnlyUrl(channel, surface.path, alias);
152
- }
153
- const key = channelName === "preview"
154
- ? "preview_url_pattern"
155
- : `${channelName}_url`;
156
- throw new Error(`surfaces.${surface.name}.${key} is required for channel ${channelName}`);
157
- }
158
118
 
159
- function manifestPrefixFor(deployConfig) {
160
- return deployConfig.manifest_prefix || ".buildchain/deployments";
161
- }
162
119
 
163
- function objectPrefixFor(deployConfig, alias) {
164
- if (Object.hasOwn(deployConfig, "prefix")) {
165
- return normalizeS3Key(deployConfig.prefix);
166
- }
167
- return alias || "preview";
168
- }
169
120
 
170
- function normalizeSurfacePath(value) {
171
- const normalized = `/${String(value || "/").replace(/^\/+/, "")}`.replace(/\/{2,}/g, "/");
172
- if (normalized === "/") {
173
- return normalized;
174
- }
175
- return normalized.endsWith("/") ? normalized : `${normalized}/`;
176
- }
177
121
 
178
- function surfaceDeployConfig(deployConfig, surfaceName) {
179
- const overrides = deployConfig.surfaces?.[surfaceName];
180
- if (!overrides || typeof overrides !== "object" || Array.isArray(overrides)) {
181
- return deployConfig;
182
- }
183
- return {
184
- ...deployConfig,
185
- ...overrides,
186
- cacheControl: deployConfig.cacheControl || overrides.cacheControl
187
- ? { ...(deployConfig.cacheControl || {}), ...(overrides.cacheControl || {}) }
188
- : undefined,
189
- surfaces: deployConfig.surfaces,
190
- secretRefs: [
191
- ...new Set([
192
- ...(deployConfig.secretRefs || []),
193
- ...(Array.isArray(overrides.secretRefs) ? overrides.secretRefs : []),
194
- ]),
195
- ],
196
- artifactPath: overrides.artifactPath || deployConfig.artifactPath,
197
- };
198
- }
199
122
 
200
- function surfaceObjectPrefixFor({ deployConfig, surface, alias }) {
201
- const effective = surfaceDeployConfig(deployConfig, surface.name);
202
- if (Object.hasOwn(effective, "prefix")) {
203
- return normalizeS3Key(effective.prefix);
204
- }
205
- const root = objectPrefixFor(deployConfig, alias);
206
- const surfacePath = normalizeS3Key(surface.path);
207
- if (!surfacePath) {
208
- return root;
209
- }
210
- return joinS3Key(root, surfacePath);
211
- }
212
123
 
213
- function normalizeS3Key(value) {
214
- return String(value || "")
215
- .replace(/^\/+/, "")
216
- .replace(/\/{2,}/g, "/")
217
- .replace(/\/+$/, "");
218
- }
219
124
 
220
- function joinS3Key(...parts) {
221
- return normalizeS3Key(parts.filter(Boolean).join("/"));
222
- }
223
125
 
224
- function joinUrlPath(...parts) {
225
- const raw = parts.join("/");
226
- const normalized = normalizeS3Key(raw);
227
- if (!normalized) {
228
- return "/";
229
- }
230
- return raw.endsWith("/") ? `/${normalized}/` : `/${normalized}`;
231
- }
232
126
 
233
- function urlWithPath(baseUrl, requestPath) {
234
- const url = new URL(baseUrl);
235
- url.pathname = joinUrlPath(requestPath);
236
- url.search = "";
237
- url.hash = "";
238
- return url.toString();
239
- }
240
127
 
241
- function s3Uri(bucket, key = "") {
242
- if (!bucket) {
243
- throw new Error("aws-s3-cloudfront adapter requires a bucket or target");
244
- }
245
- const normalizedKey = normalizeS3Key(key);
246
- return normalizedKey ? `s3://${bucket}/${normalizedKey}` : `s3://${bucket}`;
247
- }
248
128
 
249
- function cdnPath(value) {
250
- const normalized = normalizeS3Key(value);
251
- return normalized ? `/${normalized}` : "/";
252
- }
253
129
 
254
- function cdnWildcardPath(value) {
255
- const normalized = normalizeS3Key(value);
256
- return normalized ? `/${normalized}/*` : "/*";
257
- }
258
130
 
259
- function viewerWildcardPath(binding) {
260
- try {
261
- return cdnWildcardPath(new URL(binding.url).pathname);
262
- } catch {
263
- return cdnWildcardPath(binding.objectPrefix);
264
- }
265
- }
266
131
 
267
- function surfaceArtifactPrefix(binding) {
268
- return normalizeS3Key(binding.sourcePath);
269
- }
270
132
 
271
- function surfaceArtifactRootFor({ artifactRoot, binding }) {
272
- const prefix = normalizeS3Key(binding.artifactPathPrefix || surfaceArtifactPrefix(binding));
273
- const root = prefix ? path.join(artifactRoot, prefix) : artifactRoot;
274
- if (fs.existsSync(root)) {
275
- return root;
276
- }
277
- return artifactRoot;
278
- }
279
-
280
- function syncStaticArtifactArgs({ artifactRoot, bucket, objectPrefix, deleteExcludes = [], cacheControl = "" }) {
281
- const args = ["s3", "sync", artifactRoot, s3Uri(bucket, objectPrefix), "--delete"];
282
- if (!objectPrefix) {
283
- args.push("--exclude", ".buildchain/*");
284
- }
285
- for (const pattern of deleteExcludes) {
286
- args.push("--exclude", pattern);
287
- }
288
- if (cacheControl) {
289
- args.push("--cache-control", cacheControl);
290
- }
291
- return args;
292
- }
293
-
294
- function mutableCacheControlArgs({ artifactRoot, bucket, objectPrefix, cacheControl = "", excludePatterns = [] }) {
295
- if (!cacheControl) return [];
296
- const args = [
297
- "s3",
298
- "cp",
299
- artifactRoot,
300
- s3Uri(bucket, objectPrefix),
301
- "--recursive",
302
- "--exclude",
303
- "*",
304
- "--include",
305
- "*.html",
306
- "--include",
307
- "*.json",
308
- "--include",
309
- "*.xml",
310
- ];
311
- for (const pattern of excludePatterns) {
312
- args.push("--exclude", pattern);
313
- }
314
- args.push("--cache-control", cacheControl);
315
- return args;
316
- }
133
+
134
+
135
+
136
+
137
+
138
+
139
+
140
+
141
+
142
+
143
+
144
+
145
+
146
+
147
+
148
+
149
+
150
+
151
+
152
+
153
+
154
+
155
+
317
156
 
318
157
  const PUBLICATION_ARCHIVE_POLICY_CONTRACT = "kungfu-buildchain-publication-archive-policy";
319
158
  const OBSERVED_EVIDENCE_OWNERSHIP_CONTRACT = "kungfu-buildchain-observed-evidence-ownership";