@kungfu-tech/buildchain 2.0.15-alpha.0 → 2.0.15-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/docs/web-surface-deployments.md +49 -4
- package/package.json +1 -1
- package/scripts/web-surface-core.mjs +39 -0
- package/scripts/web-surface.mjs +1 -0
package/README.md
CHANGED
|
@@ -106,8 +106,8 @@ Buildchain v2 ships these active surfaces:
|
|
|
106
106
|
manifests, publish-gate source locks, resolved release manifests, and
|
|
107
107
|
aggregate build summaries;
|
|
108
108
|
- `.github/workflows/.web-surface.yml` as the reusable site/app surface for PR
|
|
109
|
-
preview plans, closed-PR preview cleanup
|
|
110
|
-
|
|
109
|
+
preview plans and optional apply, closed-PR preview cleanup apply, push-main
|
|
110
|
+
staging apply, and explicit production environment gates;
|
|
111
111
|
- `actions/run-lifecycle` for callers that need the same lifecycle/manifest
|
|
112
112
|
contract inside their own workflows;
|
|
113
113
|
- governance-closed self-promotion through `Buildchain Ref Promotion`.
|
|
@@ -285,10 +285,55 @@ The reusable workflow maps GitHub events to Buildchain web-surface semantics:
|
|
|
285
285
|
| `push` to `main` | validate, build, verify, and plan `staging` from the merged `main` SHA |
|
|
286
286
|
| `workflow_dispatch` with `production-approved = true` | plan `production` and enter the configured GitHub Environment gate |
|
|
287
287
|
|
|
288
|
-
The workflow deliberately plans and emits manifests by default.
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
288
|
+
The workflow deliberately plans and emits manifests by default. Live mutation is
|
|
289
|
+
opt-in per channel:
|
|
290
|
+
|
|
291
|
+
```yaml
|
|
292
|
+
permissions:
|
|
293
|
+
contents: read
|
|
294
|
+
id-token: write
|
|
295
|
+
pull-requests: write
|
|
296
|
+
|
|
297
|
+
jobs:
|
|
298
|
+
web-surface:
|
|
299
|
+
uses: kungfu-systems/buildchain/.github/workflows/.web-surface.yml@v2
|
|
300
|
+
with:
|
|
301
|
+
buildchain-ref: v2
|
|
302
|
+
build-command: pnpm run build
|
|
303
|
+
verify-command: pnpm run check
|
|
304
|
+
artifact-path: dist
|
|
305
|
+
preview-apply: true
|
|
306
|
+
preview-cleanup-apply: true
|
|
307
|
+
preview-aws-role-arn: arn:aws:iam::123456789012:role/site-preview-github-actions
|
|
308
|
+
staging-apply: true
|
|
309
|
+
staging-aws-role-arn: arn:aws:iam::123456789012:role/site-staging-github-actions
|
|
310
|
+
production-apply: false
|
|
311
|
+
production-aws-role-arn: arn:aws:iam::123456789012:role/site-production-github-actions
|
|
312
|
+
production-environment: production
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
When enabled, Buildchain owns the full release apply state machine:
|
|
316
|
+
|
|
317
|
+
- PR preview deploys run `deploy-apply --dry-run false` with the preview role
|
|
318
|
+
and update a single idempotent PR comment.
|
|
319
|
+
- Closed PR cleanup runs `cleanup-apply --dry-run false` with the preview role
|
|
320
|
+
only.
|
|
321
|
+
- Pushes to `main` run staging `deploy-apply --dry-run false` with the staging
|
|
322
|
+
role.
|
|
323
|
+
- Production runs only on `workflow_dispatch` when both `production-approved`
|
|
324
|
+
and `production-apply` are true, and the job is gated by the configured GitHub
|
|
325
|
+
Environment.
|
|
326
|
+
|
|
327
|
+
Callers must grant `id-token: write` for OIDC role assumption. Preview comments
|
|
328
|
+
also need `pull-requests: write`. The AWS roles remain caller-owned and should
|
|
329
|
+
be scoped by channel: preview can mutate only preview resources, staging can
|
|
330
|
+
mutate only staging resources, and production can mutate only production
|
|
331
|
+
resources.
|
|
332
|
+
|
|
333
|
+
Apply mode fails closed when the deploy config still contains placeholder AWS
|
|
334
|
+
targets such as `pending-preview-distribution`. Planning can use placeholders
|
|
335
|
+
for dry-run-only design work, but live apply requires concrete bucket and
|
|
336
|
+
CloudFront distribution identifiers.
|
|
292
337
|
|
|
293
338
|
## Site Repository Shape
|
|
294
339
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kungfu-tech/buildchain",
|
|
3
|
-
"version": "2.0.15-alpha.
|
|
3
|
+
"version": "2.0.15-alpha.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Kungfu Buildchain reusable workflows, release governance, and CLI tooling.",
|
|
6
6
|
"repository": "https://github.com/kungfu-systems/buildchain",
|
|
@@ -223,6 +223,31 @@ function appliedStatus({ dryRun, operations, noOp = false }) {
|
|
|
223
223
|
return dryRun ? "planned" : "applied";
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
+
function isPlaceholderValue(value) {
|
|
227
|
+
const normalized = String(value || "").trim().toLowerCase();
|
|
228
|
+
return (
|
|
229
|
+
normalized === "" ||
|
|
230
|
+
normalized === "pending" ||
|
|
231
|
+
normalized.startsWith("pending-") ||
|
|
232
|
+
normalized.startsWith("pending_") ||
|
|
233
|
+
normalized.includes("placeholder") ||
|
|
234
|
+
normalized.includes("example.")
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function assertConcreteAwsDeployConfig({ deployConfig, channel, operation }) {
|
|
239
|
+
const bucket = deployConfig.bucket || deployConfig.target || "";
|
|
240
|
+
const distribution = deployConfig.cloudfront_distribution || deployConfig.distribution || "";
|
|
241
|
+
if (isPlaceholderValue(bucket)) {
|
|
242
|
+
throw new Error(`web-surface ${operation} apply requires concrete deploy.${channel}.bucket or deploy.${channel}.target`);
|
|
243
|
+
}
|
|
244
|
+
if (isPlaceholderValue(distribution)) {
|
|
245
|
+
throw new Error(
|
|
246
|
+
`web-surface ${operation} apply requires concrete deploy.${channel}.cloudfront_distribution or deploy.${channel}.distribution`,
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
226
251
|
function deployManifestKey(deployConfig, manifest) {
|
|
227
252
|
return joinS3Key(manifestPrefixFor(deployConfig), `${manifest.alias || manifest.channel}.json`);
|
|
228
253
|
}
|
|
@@ -485,6 +510,13 @@ export function applyWebSurfaceDeploy({
|
|
|
485
510
|
if (resolvedPlan.adapter !== "aws-s3-cloudfront") {
|
|
486
511
|
throw new Error(`web-surface deploy apply does not support adapter: ${resolvedPlan.adapter}`);
|
|
487
512
|
}
|
|
513
|
+
if (!dryRun) {
|
|
514
|
+
assertConcreteAwsDeployConfig({
|
|
515
|
+
deployConfig,
|
|
516
|
+
channel: resolvedPlan.channel,
|
|
517
|
+
operation: "deploy",
|
|
518
|
+
});
|
|
519
|
+
}
|
|
488
520
|
const bucket = deployConfig.bucket || deployConfig.target || "";
|
|
489
521
|
const artifactRoot = path.resolve(cwd, resolvedPlan.artifact.path);
|
|
490
522
|
const objectPrefix = objectPrefixFor(deployConfig, resolvedPlan.manifest.alias || resolvedPlan.manifest.channel);
|
|
@@ -669,6 +701,13 @@ export function applyWebSurfaceCleanup({
|
|
|
669
701
|
if (cleanup.adapter !== "aws-s3-cloudfront") {
|
|
670
702
|
throw new Error(`web-surface cleanup apply does not support adapter: ${cleanup.adapter}`);
|
|
671
703
|
}
|
|
704
|
+
if (!dryRun) {
|
|
705
|
+
assertConcreteAwsDeployConfig({
|
|
706
|
+
deployConfig,
|
|
707
|
+
channel: cleanup.channel,
|
|
708
|
+
operation: "cleanup",
|
|
709
|
+
});
|
|
710
|
+
}
|
|
672
711
|
const bucket = deployConfig.bucket || deployConfig.target || "";
|
|
673
712
|
const operations = cleanup.entries.flatMap((entry) => {
|
|
674
713
|
const entryOperations = [
|
package/scripts/web-surface.mjs
CHANGED
|
@@ -125,6 +125,7 @@ export function webSurfaceCli() {
|
|
|
125
125
|
"web-surface-apply-mode": result.applyMode,
|
|
126
126
|
"web-surface-apply-status": result.status,
|
|
127
127
|
"web-surface-manifest-json": JSON.stringify(result.manifest),
|
|
128
|
+
"web-surface-apply-result-json": JSON.stringify(result),
|
|
128
129
|
});
|
|
129
130
|
assertApplySucceeded(result);
|
|
130
131
|
return result;
|