@kungfu-tech/buildchain 2.14.18-alpha.0 → 2.14.18-alpha.10

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 (44) hide show
  1. package/README.md +1 -0
  2. package/actions/promote-buildchain-ref/README.md +33 -30
  3. package/bin/buildchain.mjs +16 -4
  4. package/dist/site/buildchain-contract.json +86 -31
  5. package/dist/site/buildchain-site.json +88 -27
  6. package/dist/site/capability-registry.json +6 -5
  7. package/dist/site/cli-registry.json +12 -0
  8. package/dist/site/controller-registry.json +50 -6
  9. package/dist/site/kfd-claims.json +110 -21
  10. package/dist/site/kfd-upstream-aggregate.json +1 -1
  11. package/dist/site/manual-registry.json +21 -6
  12. package/dist/site/node-api-registry.json +19 -6
  13. package/dist/site/page-registry.json +70 -17
  14. package/dist/site/public-surface-audit.json +130 -23
  15. package/dist/site/publication-authority-registry.json +21 -1
  16. package/dist/site/publication-registry.json +4 -4
  17. package/dist/site/release-provenance.json +1 -0
  18. package/dist/site/site-manifest.json +18 -10
  19. package/dist/site/workflow-registry.json +62 -16
  20. package/docs/MAP.md +3 -1
  21. package/docs/github-governance-authority.md +267 -0
  22. package/docs/lifecycle-protocol.md +10 -10
  23. package/docs/publish-transaction.md +73 -4
  24. package/docs/release-governance.md +38 -24
  25. package/docs/reusable-build-surface.md +29 -11
  26. package/docs/web-surface-deployments.md +46 -0
  27. package/package.json +2 -1
  28. package/packages/core/buildchain-kfd-claims.js +2 -0
  29. package/packages/core/buildchain-publication-authority.js +1 -0
  30. package/packages/core/controller-evidence.js +1 -1
  31. package/packages/core/github-governance-authority.js +1312 -0
  32. package/packages/core/index.js +22 -0
  33. package/packages/core/publication-control-plane-audit.js +4 -1
  34. package/scripts/artifact-relay-s3.mjs +11 -1
  35. package/scripts/audit-github-governance.mjs +474 -0
  36. package/scripts/audit-publication-control-plane.mjs +41 -5
  37. package/scripts/check-inventory.mjs +8 -0
  38. package/scripts/generate-channel-promotion-workflow.mjs +3 -0
  39. package/scripts/generate-site-bundle.mjs +5 -0
  40. package/scripts/installer-publication.mjs +351 -0
  41. package/scripts/publication-commit-evidence.mjs +158 -0
  42. package/scripts/reconcile-github-governance.mjs +549 -0
  43. package/scripts/release-candidate-resolver.mjs +53 -0
  44. package/scripts/web-surface-core.mjs +127 -14
@@ -8,6 +8,7 @@ import { setTimeout as sleep } from "node:timers/promises";
8
8
  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
+ import { validateInstallerPublication, verifyInstallerPublicReadback } from "./installer-publication.mjs";
11
12
 
12
13
  const moduleDir = path.dirname(fileURLToPath(import.meta.url));
13
14
 
@@ -1004,6 +1005,18 @@ export function createWebSurfaceArtifactHash({ cwd = process.cwd(), artifactPath
1004
1005
  };
1005
1006
  }
1006
1007
 
1008
+ function installerPublicationEvidence(artifactRoot) {
1009
+ const manifestPath = path.join(artifactRoot, "installer-publication.json");
1010
+ if (!fs.existsSync(manifestPath)) return null;
1011
+ let publication;
1012
+ try {
1013
+ publication = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
1014
+ } catch (error) {
1015
+ throw new Error(`invalid installer publication manifest: ${error.message}`);
1016
+ }
1017
+ return validateInstallerPublication({ publication, artifactRoot });
1018
+ }
1019
+
1007
1020
  export function createWebSurfaceDeploymentManifest({
1008
1021
  cwd = process.cwd(),
1009
1022
  channel = "preview",
@@ -1133,6 +1146,12 @@ export function planWebSurfaceDeploy({
1133
1146
  rollbackLimitations,
1134
1147
  deployedAt,
1135
1148
  });
1149
+ const installerEvidence = installerPublicationEvidence(
1150
+ path.resolve(cwd, artifactPath || deployConfig.artifactPath || "."),
1151
+ );
1152
+ if (installerEvidence) {
1153
+ manifest.installerPublicationEvidence = installerEvidence;
1154
+ }
1136
1155
  const surfaceBindings = withImmutablePublicationPolicies(withSurfaceRoutingEvidence(manifest.surfaceBindings, {
1137
1156
  artifactPath: artifactPath || deployConfig.artifactPath || ".",
1138
1157
  files: resolvedArtifact.files,
@@ -1140,6 +1159,15 @@ export function planWebSurfaceDeploy({
1140
1159
  cwd,
1141
1160
  artifactPath: artifactPath || deployConfig.artifactPath || ".",
1142
1161
  });
1162
+ if (installerEvidence) {
1163
+ const preserved = surfaceBindings.some((binding) =>
1164
+ binding.immutablePublication?.declaredPrefixes?.includes(installerEvidence.immutablePath));
1165
+ if (!preserved) {
1166
+ throw new Error(
1167
+ `installer immutable path is not covered by append-only publication policy: ${installerEvidence.immutablePath}`,
1168
+ );
1169
+ }
1170
+ }
1143
1171
  manifest.surfaceBindings = surfaceBindings;
1144
1172
  return {
1145
1173
  schemaVersion: 1,
@@ -1953,6 +1981,42 @@ export async function checkWebSurfaceHealth({
1953
1981
  });
1954
1982
  }
1955
1983
 
1984
+ const installerPublication = manifest?.installerPublicationEvidence;
1985
+ const managedInstallerSurface =
1986
+ config.channels?.[channel]?.accessControl === "managed-network" &&
1987
+ !allowedManagedNetworkRunner;
1988
+ if (installerPublication && !managedInstallerSurface) {
1989
+ try {
1990
+ const publicBase = new URL(urls.hub || manifest?.url || Object.values(urls)[0]);
1991
+ const projected = {
1992
+ ...installerPublication,
1993
+ assets: installerPublication.assets.map((asset) => ({
1994
+ ...asset,
1995
+ friendlyUrl: new URL(new URL(asset.friendlyUrl).pathname, publicBase).href,
1996
+ immutableUrl: new URL(new URL(asset.immutableUrl).pathname, publicBase).href,
1997
+ })),
1998
+ };
1999
+ const evidence = await verifyInstallerPublicReadback({
2000
+ publication: projected,
2001
+ fetchImpl,
2002
+ });
2003
+ checks.push({
2004
+ surface: "__installer__",
2005
+ url: publicBase.href,
2006
+ status: "pass",
2007
+ evidence,
2008
+ message: "friendly and immutable installer routes match signed publication bytes and cache policy",
2009
+ });
2010
+ } catch (error) {
2011
+ checks.push({
2012
+ surface: "__installer__",
2013
+ url: urls.hub || manifest?.url || "",
2014
+ status: "fail",
2015
+ message: String(error.message || error),
2016
+ });
2017
+ }
2018
+ }
2019
+
1956
2020
  const manifestChecks = bindings.map((binding) => ({
1957
2021
  surface: binding.surface,
1958
2022
  manifestKey: binding.manifestKey,
@@ -1987,6 +2051,20 @@ function deployBindingOperations({ artifactRoot, deployConfig, manifest, binding
1987
2051
  const distribution = binding.distributionId || effectiveDeploy.cloudfront_distribution || effectiveDeploy.distribution || "";
1988
2052
  const surfaceArtifactRoot = surfaceArtifactRootFor({ artifactRoot, binding });
1989
2053
  const immutable = binding.immutablePublication;
2054
+ const installer = manifest.installerPublicationEvidence;
2055
+ const installerRoot = installer?.immutablePath || "";
2056
+ const ownsArtifactRoot = normalizeS3Key(
2057
+ binding.artifactPathPrefix || surfaceArtifactPrefix(binding),
2058
+ ) === "";
2059
+ const ownsInstallerAssets = installer?.assets?.every((asset) =>
2060
+ fs.existsSync(path.join(surfaceArtifactRoot, asset.friendly.path)));
2061
+ const installerBinding =
2062
+ installer &&
2063
+ ownsArtifactRoot &&
2064
+ ownsInstallerAssets &&
2065
+ immutable?.declaredPrefixes?.includes(installer.immutablePath)
2066
+ ? installer
2067
+ : null;
1990
2068
  const immutableVerifier = path.join(moduleDir, "web-surface-immutable-object.mjs");
1991
2069
  const verifyImmutable = (phase) => (immutable?.files || []).map((file) => ({
1992
2070
  action: `verify-immutable-artifact-${phase}`,
@@ -2007,25 +2085,59 @@ function deployBindingOperations({ artifactRoot, deployConfig, manifest, binding
2007
2085
  sha256: file.sha256,
2008
2086
  },
2009
2087
  }));
2010
- const syncImmutable = (immutable?.preservedRoots || []).map((root) => ({
2011
- action: "sync-immutable-artifact",
2088
+ const syncImmutable = (immutable?.preservedRoots || []).map((root) => {
2089
+ const isInstallerRoot = Boolean(installerBinding && root === installerRoot);
2090
+ const immutableMetadataArgs = isInstallerRoot
2091
+ ? [
2092
+ "--content-type",
2093
+ "application/octet-stream",
2094
+ "--cache-control",
2095
+ "public,max-age=31536000,immutable",
2096
+ ]
2097
+ : binding.cacheControl?.immutable
2098
+ ? ["--cache-control", binding.cacheControl.immutable]
2099
+ : [];
2100
+ return {
2101
+ action: "sync-immutable-artifact",
2102
+ surface: binding.surface,
2103
+ command: "aws",
2104
+ args: [
2105
+ "s3",
2106
+ "sync",
2107
+ path.join(surfaceArtifactRoot, root),
2108
+ s3Uri(bucket, joinS3Key(binding.objectPrefix, root)),
2109
+ "--no-overwrite",
2110
+ "--checksum-algorithm",
2111
+ "SHA256",
2112
+ ...immutableMetadataArgs,
2113
+ ],
2114
+ immutable: {
2115
+ preservedRoot: root,
2116
+ overwrite: false,
2117
+ cacheControl: isInstallerRoot
2118
+ ? "public,max-age=31536000,immutable"
2119
+ : binding.cacheControl?.immutable,
2120
+ },
2121
+ };
2122
+ });
2123
+ const publishFriendlyInstallers = (installerBinding?.assets || []).map((asset) => ({
2124
+ action: "publish-friendly-installer",
2012
2125
  surface: binding.surface,
2013
2126
  command: "aws",
2014
2127
  args: [
2015
2128
  "s3",
2016
- "sync",
2017
- path.join(surfaceArtifactRoot, root),
2018
- s3Uri(bucket, joinS3Key(binding.objectPrefix, root)),
2019
- "--no-overwrite",
2020
- "--checksum-algorithm",
2021
- "SHA256",
2022
- ...(binding.cacheControl?.immutable
2023
- ? ["--cache-control", binding.cacheControl.immutable]
2024
- : []),
2129
+ "cp",
2130
+ path.join(surfaceArtifactRoot, asset.friendly.path),
2131
+ s3Uri(bucket, joinS3Key(binding.objectPrefix, asset.friendly.path)),
2132
+ "--content-type",
2133
+ asset.contentType,
2134
+ "--cache-control",
2135
+ "public,max-age=300,must-revalidate",
2025
2136
  ],
2026
- immutable: {
2027
- preservedRoot: root,
2028
- overwrite: false,
2137
+ installer: {
2138
+ name: asset.name,
2139
+ digest: asset.digest,
2140
+ cacheControl: "public,max-age=300,must-revalidate",
2029
2141
  },
2030
2142
  }));
2031
2143
  const operations = [
@@ -2068,6 +2180,7 @@ function deployBindingOperations({ artifactRoot, deployConfig, manifest, binding
2068
2180
  excludes: binding.mutableDeleteExcludes || [],
2069
2181
  }]
2070
2182
  : []),
2183
+ ...publishFriendlyInstallers,
2071
2184
  ...directoryIndexAliasOperations({ surfaceArtifactRoot, bucket, binding }),
2072
2185
  {
2073
2186
  action: "write-deployment-manifest",