@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.
- package/bin/buildchain.mjs +126 -72
- package/bin/internal/trust-release-cli.mjs +15 -537
- package/bin/internal/trust-release-command-handlers.mjs +14 -0
- package/bin/internal/trust-release-inspection-handlers.mjs +175 -0
- package/bin/internal/trust-release-release-handlers.mjs +317 -0
- package/bin/internal/trust-release-verification-handlers.mjs +306 -0
- package/dist/site/buildchain-contract.json +35 -24
- package/dist/site/buildchain-site.json +22 -10
- package/dist/site/controller-registry.json +16 -3
- package/dist/site/kfd-claims.json +9 -7
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +2 -2
- package/dist/site/node-api-registry.json +7 -7
- package/dist/site/page-registry.json +9 -4
- package/dist/site/public-surface-audit.json +56 -8
- package/dist/site/publication-registry.json +4 -4
- package/dist/site/release-model.json +7 -0
- package/dist/site/site-manifest.json +6 -6
- package/dist/site/workflow-registry.json +13 -5
- package/docs/MAP.md +1 -1
- package/docs/release-propagation.md +166 -8
- package/package.json +1 -1
- package/packages/core/buildchain-kfd-claims.js +1 -1
- package/packages/core/controller-evidence.js +8 -1
- package/packages/core/index.js +1 -13
- package/packages/core/paper-npm-bootstrap.js +492 -0
- package/packages/core/paper.js +271 -669
- package/packages/core/public-surface-cli.js +12 -1
- package/packages/core/release-passport.js +67 -71
- package/packages/core/release-propagation-common.js +64 -0
- package/packages/core/release-propagation-execution-profile.js +59 -0
- package/packages/core/release-propagation-release.js +196 -0
- package/packages/core/release-propagation-stage-evidence.js +364 -0
- package/packages/core/release-propagation-work-capture.js +64 -0
- package/packages/core/release-propagation-work-constants.js +34 -0
- package/packages/core/release-propagation-work-control.js +203 -0
- package/packages/core/release-propagation-work-transitions.js +145 -0
- package/packages/core/release-propagation-work.js +517 -0
- package/packages/core/release-propagation.js +34 -158
- package/scripts/aws-windows-jit-controller-core.mjs +269 -0
- package/scripts/aws-windows-jit-controller.mjs +502 -0
- package/scripts/check-internal-architecture.mjs +178 -52
- package/scripts/check-maintainability.mjs +76 -17
- package/scripts/generate-site-bundle.mjs +16 -7
- package/scripts/maintainability-metrics.mjs +24 -4
- package/scripts/release-propagation.mjs +126 -0
- package/scripts/resolve-artifact-transfer-mode.mjs +117 -0
- package/scripts/web-surface-core.mjs +46 -207
- package/scripts/web-surface-routing.mjs +286 -0
package/packages/core/paper.js
CHANGED
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
scaffoldPackageJson,
|
|
46
46
|
scaffoldReadme,
|
|
47
47
|
} from "./paper-scaffold-content.js";
|
|
48
|
+
import { executePaperNpmBootstrap as executePaperNpmBootstrapOperation } from "./paper-npm-bootstrap.js";
|
|
48
49
|
|
|
49
50
|
export { PAPER_PATHS, resolvePaperRepository } from "./paper-repository.js";
|
|
50
51
|
export {
|
|
@@ -1230,8 +1231,7 @@ function releaseTransactionFacts(candidates, version) {
|
|
|
1230
1231
|
};
|
|
1231
1232
|
}
|
|
1232
1233
|
|
|
1233
|
-
|
|
1234
|
-
const resolvedCwd = path.resolve(cwd);
|
|
1234
|
+
function collectPaperGovernanceFacts(resolvedCwd) {
|
|
1235
1235
|
const configResult = paperConfig(resolvedCwd);
|
|
1236
1236
|
const loaded = configResult.loaded;
|
|
1237
1237
|
const publication = loaded?.config?.publication;
|
|
@@ -1272,7 +1272,13 @@ export function collectPaperStatus({ cwd = process.cwd() } = {}) {
|
|
|
1272
1272
|
gitRepo.ok &&
|
|
1273
1273
|
gitRepo.stdout === "true",
|
|
1274
1274
|
);
|
|
1275
|
+
return {
|
|
1276
|
+
configResult, loaded, publication, packageName, version, configFact,
|
|
1277
|
+
scaffoldFacts, contractLockError, scaffoldOk, governedOk,
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1275
1280
|
|
|
1281
|
+
function collectPaperEvidenceFacts(resolvedCwd, publication, version) {
|
|
1276
1282
|
const admissionInputs = [PAPER_PATHS.capability, PAPER_PATHS.admission].map(
|
|
1277
1283
|
(relativePath) => ({
|
|
1278
1284
|
relativePath,
|
|
@@ -1330,6 +1336,82 @@ export function collectPaperStatus({ cwd = process.cwd() } = {}) {
|
|
|
1330
1336
|
visibility.value,
|
|
1331
1337
|
"production",
|
|
1332
1338
|
);
|
|
1339
|
+
return {
|
|
1340
|
+
admitted, bootstrapValue, trustValue, content, reproducibility, deterministic,
|
|
1341
|
+
sealedOk, sealedError, candidates, transactionFacts, packagePublished,
|
|
1342
|
+
alphaComplete, stagingVisible, productionVisible,
|
|
1343
|
+
};
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
function paperStatusBlockingNextActions({ stateMap, deterministic, transactionFacts }) {
|
|
1347
|
+
const actions = [];
|
|
1348
|
+
if (!stateMap.scaffolded.satisfied) {
|
|
1349
|
+
actions.push({
|
|
1350
|
+
id: "scaffold-paper",
|
|
1351
|
+
command: "buildchain paper scaffold --help",
|
|
1352
|
+
description: "Plan a no-overwrite Buildchain paper scaffold.",
|
|
1353
|
+
});
|
|
1354
|
+
} else if (!stateMap.governed.satisfied) {
|
|
1355
|
+
actions.push({
|
|
1356
|
+
id: "restore-governance",
|
|
1357
|
+
command: "buildchain paper preflight --json",
|
|
1358
|
+
description:
|
|
1359
|
+
"Repair the Git/contract-lock governance checks reported by preflight.",
|
|
1360
|
+
});
|
|
1361
|
+
} else if (!stateMap["content-ready"].satisfied) {
|
|
1362
|
+
actions.push({
|
|
1363
|
+
id: "complete-paper-content",
|
|
1364
|
+
command: "make check",
|
|
1365
|
+
description: "Add every declared paper source and metadata input.",
|
|
1366
|
+
});
|
|
1367
|
+
} else if (!deterministic) {
|
|
1368
|
+
actions.push({
|
|
1369
|
+
id: "build-reproducible-artifact",
|
|
1370
|
+
command: "buildchain paper build --execute --json",
|
|
1371
|
+
description:
|
|
1372
|
+
"Run the existing two-clean-build reproducibility gate and promote exact bytes.",
|
|
1373
|
+
});
|
|
1374
|
+
} else if (
|
|
1375
|
+
!stateMap.bootstrapped.satisfied ||
|
|
1376
|
+
!stateMap["trust-bound"].satisfied
|
|
1377
|
+
) {
|
|
1378
|
+
actions.push({
|
|
1379
|
+
id: "bootstrap-npm",
|
|
1380
|
+
command: "buildchain paper bootstrap npm --json",
|
|
1381
|
+
description:
|
|
1382
|
+
"Inspect the dry-run npm bootstrap and Trusted Publishing handoff.",
|
|
1383
|
+
});
|
|
1384
|
+
} else if (!stateMap["alpha-complete"].satisfied) {
|
|
1385
|
+
actions.push({
|
|
1386
|
+
id: transactionFacts.selected ? "resume-alpha" : "start-alpha",
|
|
1387
|
+
command: transactionFacts.selected
|
|
1388
|
+
? "buildchain paper resume --json"
|
|
1389
|
+
: "buildchain paper alpha --json",
|
|
1390
|
+
description: transactionFacts.selected
|
|
1391
|
+
? "Resume the exact sealed release transaction."
|
|
1392
|
+
: "Plan the protected dev-to-alpha publication PR.",
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
return actions;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
export function collectPaperStatus({ cwd = process.cwd() } = {}) {
|
|
1399
|
+
const resolvedCwd = path.resolve(cwd);
|
|
1400
|
+
const governance = collectPaperGovernanceFacts(resolvedCwd);
|
|
1401
|
+
const evidence = collectPaperEvidenceFacts(
|
|
1402
|
+
resolvedCwd,
|
|
1403
|
+
governance.publication,
|
|
1404
|
+
governance.version,
|
|
1405
|
+
);
|
|
1406
|
+
const {
|
|
1407
|
+
configResult, loaded, publication, packageName, version, configFact,
|
|
1408
|
+
scaffoldFacts, contractLockError, scaffoldOk, governedOk,
|
|
1409
|
+
} = governance;
|
|
1410
|
+
const {
|
|
1411
|
+
admitted, bootstrapValue, trustValue, content, reproducibility, deterministic,
|
|
1412
|
+
sealedOk, sealedError, candidates, transactionFacts, packagePublished,
|
|
1413
|
+
alphaComplete, stagingVisible, productionVisible,
|
|
1414
|
+
} = evidence;
|
|
1333
1415
|
|
|
1334
1416
|
const states = [
|
|
1335
1417
|
state(
|
|
@@ -1439,54 +1521,7 @@ export function collectPaperStatus({ cwd = process.cwd() } = {}) {
|
|
|
1439
1521
|
const highestEvidenceState =
|
|
1440
1522
|
[...states].reverse().find((entry) => entry.satisfied)?.id || "none";
|
|
1441
1523
|
const stateMap = Object.fromEntries(states.map((entry) => [entry.id, entry]));
|
|
1442
|
-
const blockingNextActions =
|
|
1443
|
-
if (!stateMap.scaffolded.satisfied) {
|
|
1444
|
-
blockingNextActions.push({
|
|
1445
|
-
id: "scaffold-paper",
|
|
1446
|
-
command: "buildchain paper scaffold --help",
|
|
1447
|
-
description: "Plan a no-overwrite Buildchain paper scaffold.",
|
|
1448
|
-
});
|
|
1449
|
-
} else if (!stateMap.governed.satisfied) {
|
|
1450
|
-
blockingNextActions.push({
|
|
1451
|
-
id: "restore-governance",
|
|
1452
|
-
command: "buildchain paper preflight --json",
|
|
1453
|
-
description:
|
|
1454
|
-
"Repair the Git/contract-lock governance checks reported by preflight.",
|
|
1455
|
-
});
|
|
1456
|
-
} else if (!stateMap["content-ready"].satisfied) {
|
|
1457
|
-
blockingNextActions.push({
|
|
1458
|
-
id: "complete-paper-content",
|
|
1459
|
-
command: "make check",
|
|
1460
|
-
description: "Add every declared paper source and metadata input.",
|
|
1461
|
-
});
|
|
1462
|
-
} else if (!deterministic) {
|
|
1463
|
-
blockingNextActions.push({
|
|
1464
|
-
id: "build-reproducible-artifact",
|
|
1465
|
-
command: "buildchain paper build --execute --json",
|
|
1466
|
-
description:
|
|
1467
|
-
"Run the existing two-clean-build reproducibility gate and promote exact bytes.",
|
|
1468
|
-
});
|
|
1469
|
-
} else if (
|
|
1470
|
-
!stateMap.bootstrapped.satisfied ||
|
|
1471
|
-
!stateMap["trust-bound"].satisfied
|
|
1472
|
-
) {
|
|
1473
|
-
blockingNextActions.push({
|
|
1474
|
-
id: "bootstrap-npm",
|
|
1475
|
-
command: "buildchain paper bootstrap npm --json",
|
|
1476
|
-
description:
|
|
1477
|
-
"Inspect the dry-run npm bootstrap and Trusted Publishing handoff.",
|
|
1478
|
-
});
|
|
1479
|
-
} else if (!stateMap["alpha-complete"].satisfied) {
|
|
1480
|
-
blockingNextActions.push({
|
|
1481
|
-
id: transactionFacts.selected ? "resume-alpha" : "start-alpha",
|
|
1482
|
-
command: transactionFacts.selected
|
|
1483
|
-
? "buildchain paper resume --json"
|
|
1484
|
-
: "buildchain paper alpha --json",
|
|
1485
|
-
description: transactionFacts.selected
|
|
1486
|
-
? "Resume the exact sealed release transaction."
|
|
1487
|
-
: "Plan the protected dev-to-alpha publication PR.",
|
|
1488
|
-
});
|
|
1489
|
-
}
|
|
1524
|
+
const blockingNextActions = paperStatusBlockingNextActions({ stateMap, deterministic, transactionFacts });
|
|
1490
1525
|
return {
|
|
1491
1526
|
schemaVersion: 1,
|
|
1492
1527
|
contract: PAPER_STATUS_CONTRACT,
|
|
@@ -2050,146 +2085,8 @@ function localToolchainObservation(cwd, publication) {
|
|
|
2050
2085
|
};
|
|
2051
2086
|
}
|
|
2052
2087
|
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
buildchainRoot = process.cwd(),
|
|
2056
|
-
buildchainVersion = "",
|
|
2057
|
-
buildchainRef = "v3",
|
|
2058
|
-
buildchainSha = "",
|
|
2059
|
-
registry = NPM_REGISTRY,
|
|
2060
|
-
offline = false,
|
|
2061
|
-
agentEntryMode = "contract",
|
|
2062
|
-
} = {}) {
|
|
2063
|
-
const resolvedCwd = path.resolve(cwd);
|
|
2064
|
-
const status = collectPaperStatus({ cwd: resolvedCwd });
|
|
2065
|
-
const provisioning = validatePaperProvisioningAuthority(resolvedCwd);
|
|
2066
|
-
const configResult = paperConfig(resolvedCwd);
|
|
2067
|
-
let validation;
|
|
2068
|
-
let validationError = "";
|
|
2069
|
-
try {
|
|
2070
|
-
validation = validateBuildchainConfig(resolvedCwd, {
|
|
2071
|
-
requireLifecycleStages: ["verify"],
|
|
2072
|
-
});
|
|
2073
|
-
} catch (error) {
|
|
2074
|
-
validationError = error.message;
|
|
2075
|
-
}
|
|
2076
|
-
const runtime = runtimeFacts({
|
|
2077
|
-
buildchainRoot,
|
|
2078
|
-
buildchainVersion,
|
|
2079
|
-
buildchainRef: provisioning.value?.runtime?.ref || buildchainRef,
|
|
2080
|
-
buildchainSha,
|
|
2081
|
-
});
|
|
2082
|
-
const agentEntry = collectPaperAgentEntry({
|
|
2083
|
-
cwd: resolvedCwd,
|
|
2084
|
-
buildchainSha: runtime.resolvedSha,
|
|
2085
|
-
mode: agentEntryMode,
|
|
2086
|
-
});
|
|
2087
|
-
const lockPath = path.resolve(resolvedCwd, PAPER_PATHS.contractLock);
|
|
2088
|
-
let lockEvaluation = {
|
|
2089
|
-
status: "missing-lock",
|
|
2090
|
-
compatible: false,
|
|
2091
|
-
drift: false,
|
|
2092
|
-
reasons: ["Buildchain contract lock is missing"],
|
|
2093
|
-
};
|
|
2094
|
-
try {
|
|
2095
|
-
const lock = readBuildchainContractLock(lockPath);
|
|
2096
|
-
if (lock) {
|
|
2097
|
-
const current = runtimeContractWorld(buildchainRoot);
|
|
2098
|
-
lockEvaluation = evaluateBuildchainContractLock({
|
|
2099
|
-
lock,
|
|
2100
|
-
current,
|
|
2101
|
-
runtimeRef: runtime.ref,
|
|
2102
|
-
runtimeSha: runtime.resolvedSha,
|
|
2103
|
-
runtimeClass: /alpha/i.test(runtime.ref) ? "alpha" : "stable",
|
|
2104
|
-
});
|
|
2105
|
-
}
|
|
2106
|
-
} catch (error) {
|
|
2107
|
-
lockEvaluation = {
|
|
2108
|
-
status: "invalid-lock",
|
|
2109
|
-
compatible: false,
|
|
2110
|
-
drift: false,
|
|
2111
|
-
reasons: [error.message],
|
|
2112
|
-
};
|
|
2113
|
-
}
|
|
2114
|
-
const source = {
|
|
2115
|
-
repositoryRoot: gitValue(resolvedCwd, ["rev-parse", "--show-toplevel"]),
|
|
2116
|
-
head: gitValue(resolvedCwd, ["rev-parse", "HEAD"]),
|
|
2117
|
-
tree: gitValue(resolvedCwd, ["rev-parse", "HEAD^{tree}"]),
|
|
2118
|
-
branch: gitValue(resolvedCwd, ["branch", "--show-current"]),
|
|
2119
|
-
clean: gitResult(resolvedCwd, ["status", "--porcelain"]).stdout === "",
|
|
2120
|
-
};
|
|
2121
|
-
const packageName = status.identity.package;
|
|
2122
|
-
const repository = status.identity.repository;
|
|
2123
|
-
const expectedPublisher = expectedPaperTrustedPublisher(provisioning.value, {
|
|
2124
|
-
repository,
|
|
2125
|
-
workflow: path.posix.basename(PAPER_PATHS.releaseWorkflow),
|
|
2126
|
-
});
|
|
2127
|
-
const npm =
|
|
2128
|
-
offline || !packageName
|
|
2129
|
-
? {
|
|
2130
|
-
package: {
|
|
2131
|
-
status: "unknown",
|
|
2132
|
-
exists: null,
|
|
2133
|
-
version: "",
|
|
2134
|
-
registry,
|
|
2135
|
-
errorCode: offline ? "offline" : "package-unresolved",
|
|
2136
|
-
},
|
|
2137
|
-
auth: {
|
|
2138
|
-
status: "unknown",
|
|
2139
|
-
authenticated: null,
|
|
2140
|
-
identity: "",
|
|
2141
|
-
errorCode: offline ? "offline" : "package-unresolved",
|
|
2142
|
-
},
|
|
2143
|
-
trust: {
|
|
2144
|
-
status: "unknown",
|
|
2145
|
-
configured: null,
|
|
2146
|
-
publishers: [],
|
|
2147
|
-
errorCode: offline ? "offline" : "package-unresolved",
|
|
2148
|
-
},
|
|
2149
|
-
}
|
|
2150
|
-
: {
|
|
2151
|
-
package: liveNpmPackageObservation(
|
|
2152
|
-
packageName,
|
|
2153
|
-
registry,
|
|
2154
|
-
resolvedCwd,
|
|
2155
|
-
),
|
|
2156
|
-
auth: liveNpmAuthObservation(registry, resolvedCwd),
|
|
2157
|
-
trust: liveNpmTrustObservation(
|
|
2158
|
-
packageName,
|
|
2159
|
-
registry,
|
|
2160
|
-
resolvedCwd,
|
|
2161
|
-
expectedPublisher,
|
|
2162
|
-
),
|
|
2163
|
-
};
|
|
2164
|
-
const repositoryPermissions = offline
|
|
2165
|
-
? {
|
|
2166
|
-
status: "unknown",
|
|
2167
|
-
repository,
|
|
2168
|
-
canWrite: null,
|
|
2169
|
-
errorCode: "offline",
|
|
2170
|
-
}
|
|
2171
|
-
: liveRepositoryPermissionObservation(repository, resolvedCwd);
|
|
2172
|
-
const repositoryActions = offline
|
|
2173
|
-
? {
|
|
2174
|
-
status: "unknown",
|
|
2175
|
-
defaultWorkflowPermissions: "",
|
|
2176
|
-
canApprovePullRequestReviews: null,
|
|
2177
|
-
errorCode: "offline",
|
|
2178
|
-
}
|
|
2179
|
-
: liveRepositoryActionsPolicyObservation(repository, resolvedCwd);
|
|
2180
|
-
const generatedWriteAuthority = offline
|
|
2181
|
-
? {
|
|
2182
|
-
status: "unknown",
|
|
2183
|
-
configured: null,
|
|
2184
|
-
mode: "",
|
|
2185
|
-
errorCode: "offline",
|
|
2186
|
-
}
|
|
2187
|
-
: liveGeneratedWriteAuthorityObservation(repository, resolvedCwd);
|
|
2188
|
-
const toolchain = localToolchainObservation(
|
|
2189
|
-
resolvedCwd,
|
|
2190
|
-
configResult.loaded?.config?.publication,
|
|
2191
|
-
);
|
|
2192
|
-
const checks = [
|
|
2088
|
+
function paperPreflightLocalChecks({ agentEntry, provisioning, validationError, source, toolchain, runtime, lockEvaluation }) {
|
|
2089
|
+
return [
|
|
2193
2090
|
...agentEntry.checks.map((entry) => ({
|
|
2194
2091
|
...entry,
|
|
2195
2092
|
blocking: true,
|
|
@@ -2256,6 +2153,11 @@ export function collectPaperPreflight({
|
|
|
2256
2153
|
? `Buildchain runtime contract is ${lockEvaluation.status}.`
|
|
2257
2154
|
: `Buildchain runtime contract is not admitted: ${(lockEvaluation.reasons || []).join("; ")}`,
|
|
2258
2155
|
},
|
|
2156
|
+
];
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
function paperPreflightRepositoryChecks({ repositoryPermissions, repositoryActions, generatedWriteAuthority }) {
|
|
2160
|
+
return [
|
|
2259
2161
|
{
|
|
2260
2162
|
id: "repository.write-permission",
|
|
2261
2163
|
status:
|
|
@@ -2309,6 +2211,11 @@ export function collectPaperPreflight({
|
|
|
2309
2211
|
? "No GitHub App or compatible narrow generated-write credential is configured."
|
|
2310
2212
|
: `Generated-write authority is unknown (${generatedWriteAuthority.errorCode}).`,
|
|
2311
2213
|
},
|
|
2214
|
+
];
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
function paperPreflightPublicationChecks({ npm, status }) {
|
|
2218
|
+
return [
|
|
2312
2219
|
{
|
|
2313
2220
|
id: "npm.package",
|
|
2314
2221
|
status:
|
|
@@ -2365,24 +2272,19 @@ export function collectPaperPreflight({
|
|
|
2365
2272
|
: `${status.conflicts.length} release-state conflict(s) require repair.`,
|
|
2366
2273
|
},
|
|
2367
2274
|
];
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
const
|
|
2372
|
-
(entry) =>
|
|
2373
|
-
entry.scope === "external-mutation" &&
|
|
2374
|
-
["fail", "pending", "unknown"].includes(entry.status),
|
|
2375
|
-
);
|
|
2376
|
-
const nextActions = [];
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
function paperPreflightNextActions({ validationError, source, lockEvaluation, npm, repositoryActions, generatedWriteAuthority, status }) {
|
|
2278
|
+
const actions = [];
|
|
2377
2279
|
if (validationError) {
|
|
2378
|
-
|
|
2280
|
+
actions.push({
|
|
2379
2281
|
id: "repair-config",
|
|
2380
2282
|
command: "buildchain validate --require-lifecycle-stages verify",
|
|
2381
2283
|
description: validationError,
|
|
2382
2284
|
});
|
|
2383
2285
|
}
|
|
2384
2286
|
if (!source.clean) {
|
|
2385
|
-
|
|
2287
|
+
actions.push({
|
|
2386
2288
|
id: "commit-source",
|
|
2387
2289
|
command: "git status --short",
|
|
2388
2290
|
description:
|
|
@@ -2390,7 +2292,7 @@ export function collectPaperPreflight({
|
|
|
2390
2292
|
});
|
|
2391
2293
|
}
|
|
2392
2294
|
if (!lockEvaluation.compatible) {
|
|
2393
|
-
|
|
2295
|
+
actions.push({
|
|
2394
2296
|
id: "refresh-contract-lock",
|
|
2395
2297
|
command: "buildchain paper scaffold --json",
|
|
2396
2298
|
description:
|
|
@@ -2398,7 +2300,7 @@ export function collectPaperPreflight({
|
|
|
2398
2300
|
});
|
|
2399
2301
|
}
|
|
2400
2302
|
if (npm.package.exists === false || npm.trust.configured === false) {
|
|
2401
|
-
|
|
2303
|
+
actions.push({
|
|
2402
2304
|
id: "bootstrap-npm",
|
|
2403
2305
|
command: "buildchain paper bootstrap npm --json",
|
|
2404
2306
|
description:
|
|
@@ -2410,7 +2312,7 @@ export function collectPaperPreflight({
|
|
|
2410
2312
|
(repositoryActions.defaultWorkflowPermissions !== "read" ||
|
|
2411
2313
|
repositoryActions.canApprovePullRequestReviews !== false)
|
|
2412
2314
|
) {
|
|
2413
|
-
|
|
2315
|
+
actions.push({
|
|
2414
2316
|
id: "constrain-repository-actions",
|
|
2415
2317
|
command: "",
|
|
2416
2318
|
description:
|
|
@@ -2418,7 +2320,7 @@ export function collectPaperPreflight({
|
|
|
2418
2320
|
});
|
|
2419
2321
|
}
|
|
2420
2322
|
if (generatedWriteAuthority.configured === false) {
|
|
2421
|
-
|
|
2323
|
+
actions.push({
|
|
2422
2324
|
id: "configure-generated-write-authority",
|
|
2423
2325
|
command: "",
|
|
2424
2326
|
description:
|
|
@@ -2426,12 +2328,149 @@ export function collectPaperPreflight({
|
|
|
2426
2328
|
});
|
|
2427
2329
|
}
|
|
2428
2330
|
if (status.deterministicBuild.status !== "qualifying") {
|
|
2429
|
-
|
|
2331
|
+
actions.push({
|
|
2430
2332
|
id: "build-paper",
|
|
2431
2333
|
command: "buildchain paper build --execute --json",
|
|
2432
2334
|
description: "Run the existing qualifying two-clean-build gate.",
|
|
2433
2335
|
});
|
|
2434
2336
|
}
|
|
2337
|
+
return actions;
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
export function collectPaperPreflight({
|
|
2341
|
+
cwd = process.cwd(),
|
|
2342
|
+
buildchainRoot = process.cwd(),
|
|
2343
|
+
buildchainVersion = "",
|
|
2344
|
+
buildchainRef = "v3",
|
|
2345
|
+
buildchainSha = "",
|
|
2346
|
+
registry = NPM_REGISTRY,
|
|
2347
|
+
offline = false,
|
|
2348
|
+
agentEntryMode = "contract",
|
|
2349
|
+
} = {}) {
|
|
2350
|
+
const resolvedCwd = path.resolve(cwd);
|
|
2351
|
+
const status = collectPaperStatus({ cwd: resolvedCwd });
|
|
2352
|
+
const provisioning = validatePaperProvisioningAuthority(resolvedCwd);
|
|
2353
|
+
const configResult = paperConfig(resolvedCwd);
|
|
2354
|
+
let validation;
|
|
2355
|
+
let validationError = "";
|
|
2356
|
+
try {
|
|
2357
|
+
validation = validateBuildchainConfig(resolvedCwd, { requireLifecycleStages: ["verify"] });
|
|
2358
|
+
} catch (error) {
|
|
2359
|
+
validationError = error.message;
|
|
2360
|
+
}
|
|
2361
|
+
const runtime = runtimeFacts({
|
|
2362
|
+
buildchainRoot, buildchainVersion,
|
|
2363
|
+
buildchainRef: provisioning.value?.runtime?.ref || buildchainRef, buildchainSha,
|
|
2364
|
+
});
|
|
2365
|
+
const agentEntry = collectPaperAgentEntry({ cwd: resolvedCwd, buildchainSha: runtime.resolvedSha, mode: agentEntryMode });
|
|
2366
|
+
const lockPath = path.resolve(resolvedCwd, PAPER_PATHS.contractLock);
|
|
2367
|
+
let lockEvaluation = {
|
|
2368
|
+
status: "missing-lock",
|
|
2369
|
+
compatible: false,
|
|
2370
|
+
drift: false,
|
|
2371
|
+
reasons: ["Buildchain contract lock is missing"],
|
|
2372
|
+
};
|
|
2373
|
+
try {
|
|
2374
|
+
const lock = readBuildchainContractLock(lockPath);
|
|
2375
|
+
if (lock) {
|
|
2376
|
+
const current = runtimeContractWorld(buildchainRoot);
|
|
2377
|
+
lockEvaluation = evaluateBuildchainContractLock({
|
|
2378
|
+
lock,
|
|
2379
|
+
current,
|
|
2380
|
+
runtimeRef: runtime.ref,
|
|
2381
|
+
runtimeSha: runtime.resolvedSha,
|
|
2382
|
+
runtimeClass: /alpha/i.test(runtime.ref) ? "alpha" : "stable",
|
|
2383
|
+
});
|
|
2384
|
+
}
|
|
2385
|
+
} catch (error) {
|
|
2386
|
+
lockEvaluation = {
|
|
2387
|
+
status: "invalid-lock",
|
|
2388
|
+
compatible: false,
|
|
2389
|
+
drift: false,
|
|
2390
|
+
reasons: [error.message],
|
|
2391
|
+
};
|
|
2392
|
+
}
|
|
2393
|
+
const source = {
|
|
2394
|
+
repositoryRoot: gitValue(resolvedCwd, ["rev-parse", "--show-toplevel"]),
|
|
2395
|
+
head: gitValue(resolvedCwd, ["rev-parse", "HEAD"]),
|
|
2396
|
+
tree: gitValue(resolvedCwd, ["rev-parse", "HEAD^{tree}"]),
|
|
2397
|
+
branch: gitValue(resolvedCwd, ["branch", "--show-current"]),
|
|
2398
|
+
clean: gitResult(resolvedCwd, ["status", "--porcelain"]).stdout === "",
|
|
2399
|
+
};
|
|
2400
|
+
const packageName = status.identity.package;
|
|
2401
|
+
const repository = status.identity.repository;
|
|
2402
|
+
const expectedPublisher = expectedPaperTrustedPublisher(provisioning.value, {
|
|
2403
|
+
repository, workflow: path.posix.basename(PAPER_PATHS.releaseWorkflow),
|
|
2404
|
+
});
|
|
2405
|
+
const npm =
|
|
2406
|
+
offline || !packageName
|
|
2407
|
+
? {
|
|
2408
|
+
package: {
|
|
2409
|
+
status: "unknown",
|
|
2410
|
+
exists: null,
|
|
2411
|
+
version: "",
|
|
2412
|
+
registry,
|
|
2413
|
+
errorCode: offline ? "offline" : "package-unresolved",
|
|
2414
|
+
},
|
|
2415
|
+
auth: {
|
|
2416
|
+
status: "unknown",
|
|
2417
|
+
authenticated: null,
|
|
2418
|
+
identity: "",
|
|
2419
|
+
errorCode: offline ? "offline" : "package-unresolved",
|
|
2420
|
+
},
|
|
2421
|
+
trust: {
|
|
2422
|
+
status: "unknown",
|
|
2423
|
+
configured: null,
|
|
2424
|
+
publishers: [],
|
|
2425
|
+
errorCode: offline ? "offline" : "package-unresolved",
|
|
2426
|
+
},
|
|
2427
|
+
}
|
|
2428
|
+
: {
|
|
2429
|
+
package: liveNpmPackageObservation(packageName, registry, resolvedCwd),
|
|
2430
|
+
auth: liveNpmAuthObservation(registry, resolvedCwd),
|
|
2431
|
+
trust: liveNpmTrustObservation(packageName, registry, resolvedCwd, expectedPublisher),
|
|
2432
|
+
};
|
|
2433
|
+
const repositoryPermissions = offline
|
|
2434
|
+
? {
|
|
2435
|
+
status: "unknown",
|
|
2436
|
+
repository,
|
|
2437
|
+
canWrite: null,
|
|
2438
|
+
errorCode: "offline",
|
|
2439
|
+
}
|
|
2440
|
+
: liveRepositoryPermissionObservation(repository, resolvedCwd);
|
|
2441
|
+
const repositoryActions = offline
|
|
2442
|
+
? {
|
|
2443
|
+
status: "unknown",
|
|
2444
|
+
defaultWorkflowPermissions: "",
|
|
2445
|
+
canApprovePullRequestReviews: null,
|
|
2446
|
+
errorCode: "offline",
|
|
2447
|
+
}
|
|
2448
|
+
: liveRepositoryActionsPolicyObservation(repository, resolvedCwd);
|
|
2449
|
+
const generatedWriteAuthority = offline
|
|
2450
|
+
? {
|
|
2451
|
+
status: "unknown",
|
|
2452
|
+
configured: null,
|
|
2453
|
+
mode: "",
|
|
2454
|
+
errorCode: "offline",
|
|
2455
|
+
}
|
|
2456
|
+
: liveGeneratedWriteAuthorityObservation(repository, resolvedCwd);
|
|
2457
|
+
const toolchain = localToolchainObservation(resolvedCwd, configResult.loaded?.config?.publication);
|
|
2458
|
+
const checks = [
|
|
2459
|
+
...paperPreflightLocalChecks({ agentEntry, provisioning, validationError, source, toolchain, runtime, lockEvaluation }),
|
|
2460
|
+
...paperPreflightRepositoryChecks({ repositoryPermissions, repositoryActions, generatedWriteAuthority }),
|
|
2461
|
+
...paperPreflightPublicationChecks({ npm, status }),
|
|
2462
|
+
];
|
|
2463
|
+
const blockingChecks = checks.filter(
|
|
2464
|
+
(entry) => entry.blocking && ["fail", "unknown"].includes(entry.status),
|
|
2465
|
+
);
|
|
2466
|
+
const externalMutationChecks = checks.filter(
|
|
2467
|
+
(entry) =>
|
|
2468
|
+
entry.scope === "external-mutation" &&
|
|
2469
|
+
["fail", "pending", "unknown"].includes(entry.status),
|
|
2470
|
+
);
|
|
2471
|
+
const nextActions = paperPreflightNextActions({
|
|
2472
|
+
validationError, source, lockEvaluation, npm, repositoryActions, generatedWriteAuthority, status,
|
|
2473
|
+
});
|
|
2435
2474
|
return {
|
|
2436
2475
|
schemaVersion: 1,
|
|
2437
2476
|
contract: PAPER_PREFLIGHT_CONTRACT,
|
|
@@ -2725,467 +2764,30 @@ function bootstrapPackageShape({ packageName, version }) {
|
|
|
2725
2764
|
};
|
|
2726
2765
|
}
|
|
2727
2766
|
|
|
2728
|
-
export function executePaperNpmBootstrap({
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
const name = normalizePackageName(
|
|
2755
|
-
packageName ||
|
|
2756
|
-
configResult.loaded.config.publish?.package ||
|
|
2757
|
-
configResult.loaded.config.publish?.mainPackage,
|
|
2758
|
-
);
|
|
2759
|
-
const repo = normalizeRepository(
|
|
2760
|
-
repository || resolvePaperRepository(resolvedCwd),
|
|
2761
|
-
);
|
|
2762
|
-
const provisioning = validatePaperProvisioningAuthority(resolvedCwd);
|
|
2763
|
-
if (!provisioning.valid) {
|
|
2764
|
-
throw new Error(
|
|
2765
|
-
`paper npm bootstrap requires a valid provisioning authority: ${provisioning.errors.join("; ")}`,
|
|
2766
|
-
);
|
|
2767
|
-
}
|
|
2768
|
-
const expectedPublisher = expectedPaperTrustedPublisher(provisioning.value);
|
|
2769
|
-
if (
|
|
2770
|
-
provisioning.value.package?.name !== name ||
|
|
2771
|
-
expectedPublisher.repository !== repo ||
|
|
2772
|
-
expectedPublisher.workflow !== toPosix(workflow).replace(/^\/+/, "") ||
|
|
2773
|
-
expectedPublisher.environment !== String(environment || "")
|
|
2774
|
-
) {
|
|
2775
|
-
throw new Error(
|
|
2776
|
-
"paper npm bootstrap coordinates differ from the exact provisioning authority",
|
|
2777
|
-
);
|
|
2778
|
-
}
|
|
2779
|
-
if (execute && confirmedPackage !== name) {
|
|
2780
|
-
throw new Error(
|
|
2781
|
-
`real npm bootstrap requires --confirm-public-package ${name}`,
|
|
2782
|
-
);
|
|
2783
|
-
}
|
|
2784
|
-
if (execute && offline) {
|
|
2785
|
-
throw new Error("real npm bootstrap cannot run with --offline");
|
|
2786
|
-
}
|
|
2787
|
-
if (execute && (!repo || !workflow)) {
|
|
2788
|
-
throw new Error(
|
|
2789
|
-
"real npm bootstrap requires GitHub repository and workflow coordinates",
|
|
2790
|
-
);
|
|
2791
|
-
}
|
|
2792
|
-
const packageObservation = offline
|
|
2793
|
-
? {
|
|
2794
|
-
status: "unknown",
|
|
2795
|
-
exists: null,
|
|
2796
|
-
version: "",
|
|
2797
|
-
registry,
|
|
2798
|
-
errorCode: "offline",
|
|
2799
|
-
}
|
|
2800
|
-
: liveNpmPackageObservation(name, registry, resolvedCwd);
|
|
2801
|
-
const auth = offline
|
|
2802
|
-
? {
|
|
2803
|
-
status: "unknown",
|
|
2804
|
-
authenticated: null,
|
|
2805
|
-
identity: "",
|
|
2806
|
-
errorCode: "offline",
|
|
2807
|
-
}
|
|
2808
|
-
: liveNpmAuthObservation(registry, resolvedCwd);
|
|
2809
|
-
const plan = {
|
|
2810
|
-
schemaVersion: 1,
|
|
2811
|
-
contract: PAPER_NPM_BOOTSTRAP_CONTRACT,
|
|
2812
|
-
ok: true,
|
|
2813
|
-
dryRun: !execute,
|
|
2814
|
-
externalMutation: execute,
|
|
2815
|
-
package: {
|
|
2816
|
-
name,
|
|
2817
|
-
bootstrapVersion,
|
|
2818
|
-
registry,
|
|
2819
|
-
existsBefore: packageObservation.exists,
|
|
2820
|
-
observedVersion: packageObservation.version,
|
|
2821
|
-
},
|
|
2822
|
-
repository: {
|
|
2823
|
-
github: repo,
|
|
2824
|
-
workflow,
|
|
2825
|
-
environment,
|
|
2826
|
-
},
|
|
2827
|
-
authority: {
|
|
2828
|
-
digest: provisioning.value.authorityDigest,
|
|
2829
|
-
policyDigest: provisioning.value.policy.policyDigest,
|
|
2830
|
-
},
|
|
2831
|
-
auth: {
|
|
2832
|
-
authenticated: auth.authenticated,
|
|
2833
|
-
identity: auth.identity,
|
|
2834
|
-
errorCode: auth.errorCode,
|
|
2835
|
-
},
|
|
2836
|
-
publish: {
|
|
2837
|
-
status: packageObservation.exists === true ? "existing" : "planned",
|
|
2838
|
-
distTag: "bootstrap",
|
|
2839
|
-
access: "public",
|
|
2840
|
-
},
|
|
2841
|
-
trust: {
|
|
2842
|
-
status: "planned",
|
|
2843
|
-
urls: [],
|
|
2844
|
-
},
|
|
2845
|
-
receipts: [],
|
|
2846
|
-
nextActions: execute
|
|
2847
|
-
? []
|
|
2848
|
-
: [
|
|
2849
|
-
{
|
|
2850
|
-
id: "confirm-public-bootstrap",
|
|
2851
|
-
command: `buildchain paper bootstrap npm --execute --confirm-public-package ${name} --json`,
|
|
2852
|
-
description:
|
|
2853
|
-
"After reviewing this dry-run, bootstrap the exact public package and configure GitHub Trusted Publishing.",
|
|
2854
|
-
},
|
|
2855
|
-
],
|
|
2856
|
-
};
|
|
2857
|
-
if (!execute) {
|
|
2858
|
-
const dryRunRoot = fs.mkdtempSync(
|
|
2859
|
-
path.join(os.tmpdir(), "buildchain-paper-bootstrap-dry-run-"),
|
|
2860
|
-
);
|
|
2861
|
-
try {
|
|
2862
|
-
fs.writeFileSync(
|
|
2863
|
-
path.join(dryRunRoot, "package.json"),
|
|
2864
|
-
jsonText(
|
|
2865
|
-
bootstrapPackageShape({
|
|
2866
|
-
packageName: name,
|
|
2867
|
-
version: bootstrapVersion,
|
|
2868
|
-
}),
|
|
2869
|
-
),
|
|
2870
|
-
);
|
|
2871
|
-
const configArgs = userconfig ? ["--userconfig", userconfig] : [];
|
|
2872
|
-
const pack = commandResult(
|
|
2873
|
-
"npm",
|
|
2874
|
-
[
|
|
2875
|
-
"pack",
|
|
2876
|
-
"--dry-run",
|
|
2877
|
-
"--json",
|
|
2878
|
-
"--ignore-scripts",
|
|
2879
|
-
`--registry=${registry}`,
|
|
2880
|
-
...configArgs,
|
|
2881
|
-
],
|
|
2882
|
-
{ cwd: dryRunRoot },
|
|
2883
|
-
);
|
|
2884
|
-
const publish = commandResult(
|
|
2885
|
-
"npm",
|
|
2886
|
-
[
|
|
2887
|
-
"publish",
|
|
2888
|
-
"--dry-run",
|
|
2889
|
-
"--ignore-scripts",
|
|
2890
|
-
"--access",
|
|
2891
|
-
"public",
|
|
2892
|
-
"--tag",
|
|
2893
|
-
"bootstrap",
|
|
2894
|
-
`--registry=${registry}`,
|
|
2895
|
-
...configArgs,
|
|
2896
|
-
],
|
|
2897
|
-
{ cwd: dryRunRoot },
|
|
2898
|
-
);
|
|
2899
|
-
return {
|
|
2900
|
-
...plan,
|
|
2901
|
-
ok: pack.ok && publish.ok,
|
|
2902
|
-
errorCode: !pack.ok
|
|
2903
|
-
? "npm-pack-dry-run-failed"
|
|
2904
|
-
: !publish.ok
|
|
2905
|
-
? "npm-publish-dry-run-failed"
|
|
2906
|
-
: "",
|
|
2907
|
-
dryRunChecks: {
|
|
2908
|
-
minimalPackageOnly: true,
|
|
2909
|
-
pack: {
|
|
2910
|
-
status: pack.ok ? "pass" : "fail",
|
|
2911
|
-
entryCount: (() => {
|
|
2912
|
-
const parsed = safeParseJson(pack.stdout);
|
|
2913
|
-
const value = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
2914
|
-
return Array.isArray(value?.files) ? value.files.length : 0;
|
|
2915
|
-
})(),
|
|
2916
|
-
},
|
|
2917
|
-
publish: {
|
|
2918
|
-
status: publish.ok ? "pass" : "fail",
|
|
2919
|
-
registry,
|
|
2920
|
-
access: "public",
|
|
2921
|
-
distTag: "bootstrap",
|
|
2922
|
-
},
|
|
2923
|
-
},
|
|
2924
|
-
};
|
|
2925
|
-
} finally {
|
|
2926
|
-
fs.rmSync(dryRunRoot, { recursive: true, force: true });
|
|
2927
|
-
}
|
|
2928
|
-
}
|
|
2929
|
-
if (packageObservation.exists === null) {
|
|
2930
|
-
return {
|
|
2931
|
-
...plan,
|
|
2932
|
-
ok: false,
|
|
2933
|
-
errorCode: "npm-package-status-unknown",
|
|
2934
|
-
publish: {
|
|
2935
|
-
...plan.publish,
|
|
2936
|
-
status: "blocked",
|
|
2937
|
-
},
|
|
2938
|
-
trust: {
|
|
2939
|
-
status: "blocked",
|
|
2940
|
-
urls: [],
|
|
2941
|
-
},
|
|
2942
|
-
nextActions: [
|
|
2943
|
-
{
|
|
2944
|
-
id: "verify-npm-package",
|
|
2945
|
-
command: `npm view ${name} version --json --registry=${registry}`,
|
|
2946
|
-
description:
|
|
2947
|
-
"Resolve whether the exact public package exists before any publish mutation.",
|
|
2948
|
-
},
|
|
2949
|
-
],
|
|
2950
|
-
};
|
|
2951
|
-
}
|
|
2952
|
-
if (auth.authenticated !== true) {
|
|
2953
|
-
return {
|
|
2954
|
-
...plan,
|
|
2955
|
-
ok: false,
|
|
2956
|
-
errorCode: "npm-auth-required",
|
|
2957
|
-
publish: {
|
|
2958
|
-
...plan.publish,
|
|
2959
|
-
status: "blocked",
|
|
2960
|
-
},
|
|
2961
|
-
trust: {
|
|
2962
|
-
status: "blocked",
|
|
2963
|
-
urls: [],
|
|
2964
|
-
},
|
|
2965
|
-
nextActions: [
|
|
2966
|
-
{
|
|
2967
|
-
id: "authenticate-npm",
|
|
2968
|
-
command: `npm whoami --registry=${registry}`,
|
|
2969
|
-
description:
|
|
2970
|
-
"Authenticate npm without sharing token contents, then rerun the exact bootstrap command.",
|
|
2971
|
-
},
|
|
2972
|
-
],
|
|
2973
|
-
};
|
|
2974
|
-
}
|
|
2975
|
-
const tempRoot = fs.mkdtempSync(
|
|
2976
|
-
path.join(os.tmpdir(), "buildchain-paper-bootstrap-"),
|
|
2977
|
-
);
|
|
2978
|
-
try {
|
|
2979
|
-
fs.writeFileSync(
|
|
2980
|
-
path.join(tempRoot, "package.json"),
|
|
2981
|
-
jsonText(
|
|
2982
|
-
bootstrapPackageShape({ packageName: name, version: bootstrapVersion }),
|
|
2983
|
-
),
|
|
2984
|
-
);
|
|
2985
|
-
const configArgs = userconfig ? ["--userconfig", userconfig] : [];
|
|
2986
|
-
const pack = commandResult(
|
|
2987
|
-
"npm",
|
|
2988
|
-
[
|
|
2989
|
-
"pack",
|
|
2990
|
-
"--dry-run",
|
|
2991
|
-
"--json",
|
|
2992
|
-
"--ignore-scripts",
|
|
2993
|
-
`--registry=${registry}`,
|
|
2994
|
-
...configArgs,
|
|
2995
|
-
],
|
|
2996
|
-
{ cwd: tempRoot },
|
|
2997
|
-
);
|
|
2998
|
-
if (!pack.ok) {
|
|
2999
|
-
return {
|
|
3000
|
-
...plan,
|
|
3001
|
-
ok: false,
|
|
3002
|
-
errorCode: "npm-pack-dry-run-failed",
|
|
3003
|
-
publish: { ...plan.publish, status: "blocked" },
|
|
3004
|
-
trust: { status: "blocked", urls: [] },
|
|
3005
|
-
};
|
|
3006
|
-
}
|
|
3007
|
-
const publishDryRun = commandResult(
|
|
3008
|
-
"npm",
|
|
3009
|
-
[
|
|
3010
|
-
"publish",
|
|
3011
|
-
"--dry-run",
|
|
3012
|
-
"--ignore-scripts",
|
|
3013
|
-
"--access",
|
|
3014
|
-
"public",
|
|
3015
|
-
"--tag",
|
|
3016
|
-
"bootstrap",
|
|
3017
|
-
`--registry=${registry}`,
|
|
3018
|
-
...configArgs,
|
|
3019
|
-
],
|
|
3020
|
-
{ cwd: tempRoot },
|
|
3021
|
-
);
|
|
3022
|
-
if (!publishDryRun.ok) {
|
|
3023
|
-
return {
|
|
3024
|
-
...plan,
|
|
3025
|
-
ok: false,
|
|
3026
|
-
errorCode: "npm-publish-dry-run-failed",
|
|
3027
|
-
publish: { ...plan.publish, status: "blocked" },
|
|
3028
|
-
trust: { status: "blocked", urls: [] },
|
|
3029
|
-
};
|
|
3030
|
-
}
|
|
3031
|
-
let publishStatus =
|
|
3032
|
-
packageObservation.exists === true ? "existing" : "published";
|
|
3033
|
-
if (packageObservation.exists !== true) {
|
|
3034
|
-
const published = commandResult(
|
|
3035
|
-
"npm",
|
|
3036
|
-
[
|
|
3037
|
-
"publish",
|
|
3038
|
-
"--ignore-scripts",
|
|
3039
|
-
"--access",
|
|
3040
|
-
"public",
|
|
3041
|
-
"--tag",
|
|
3042
|
-
"bootstrap",
|
|
3043
|
-
`--registry=${registry}`,
|
|
3044
|
-
...configArgs,
|
|
3045
|
-
],
|
|
3046
|
-
{ cwd: tempRoot, timeout: 60000 },
|
|
3047
|
-
);
|
|
3048
|
-
if (!published.ok) {
|
|
3049
|
-
const failure = {
|
|
3050
|
-
...plan,
|
|
3051
|
-
ok: false,
|
|
3052
|
-
errorCode: "npm-publish-failed",
|
|
3053
|
-
publish: { ...plan.publish, status: "failed" },
|
|
3054
|
-
trust: { status: "blocked", urls: [] },
|
|
3055
|
-
};
|
|
3056
|
-
failure.receipts = [
|
|
3057
|
-
writePaperReceipt(resolvedCwd, PAPER_PATHS.npmBootstrap, failure),
|
|
3058
|
-
];
|
|
3059
|
-
return failure;
|
|
3060
|
-
}
|
|
3061
|
-
}
|
|
3062
|
-
const trustArgs = [
|
|
3063
|
-
"trust",
|
|
3064
|
-
"github",
|
|
3065
|
-
name,
|
|
3066
|
-
"--repo",
|
|
3067
|
-
repo,
|
|
3068
|
-
"--file",
|
|
3069
|
-
workflow,
|
|
3070
|
-
...(environment ? ["--env", environment] : []),
|
|
3071
|
-
"--allow-publish",
|
|
3072
|
-
"--yes",
|
|
3073
|
-
"--json",
|
|
3074
|
-
`--registry=${registry}`,
|
|
3075
|
-
...configArgs,
|
|
3076
|
-
];
|
|
3077
|
-
const trustCommand = commandResult("npm", trustArgs, {
|
|
3078
|
-
cwd: resolvedCwd,
|
|
3079
|
-
timeout: 60000,
|
|
3080
|
-
});
|
|
3081
|
-
const parsedTrust = safeParseJson(trustCommand.stdout);
|
|
3082
|
-
const urls = [
|
|
3083
|
-
...extractUrls(
|
|
3084
|
-
parsedTrust || `${trustCommand.stdout}\n${trustCommand.stderr}`,
|
|
3085
|
-
),
|
|
3086
|
-
];
|
|
3087
|
-
const trustList =
|
|
3088
|
-
trustCommand.ok && urls.length === 0
|
|
3089
|
-
? liveNpmTrustObservation(
|
|
3090
|
-
name,
|
|
3091
|
-
registry,
|
|
3092
|
-
resolvedCwd,
|
|
3093
|
-
expectedPublisher,
|
|
3094
|
-
)
|
|
3095
|
-
: {
|
|
3096
|
-
status: "unknown",
|
|
3097
|
-
configured: null,
|
|
3098
|
-
publishers: [],
|
|
3099
|
-
errorCode:
|
|
3100
|
-
urls.length > 0 ? "web-action-required" : "npm-trust-failed",
|
|
3101
|
-
};
|
|
3102
|
-
const trustStatus =
|
|
3103
|
-
trustCommand.ok && trustList.configured === true
|
|
3104
|
-
? "configured"
|
|
3105
|
-
: urls.length > 0
|
|
3106
|
-
? "action-required"
|
|
3107
|
-
: "failed";
|
|
3108
|
-
const packageAfter = liveNpmPackageObservation(name, registry, resolvedCwd);
|
|
3109
|
-
const packageVerified = packageAfter.exists === true;
|
|
3110
|
-
const receipt = {
|
|
3111
|
-
...plan,
|
|
3112
|
-
ok: trustStatus !== "failed" && packageVerified,
|
|
3113
|
-
dryRun: false,
|
|
3114
|
-
externalMutation: true,
|
|
3115
|
-
errorCode:
|
|
3116
|
-
trustStatus === "failed"
|
|
3117
|
-
? "npm-trust-failed"
|
|
3118
|
-
: packageVerified
|
|
3119
|
-
? ""
|
|
3120
|
-
: "npm-package-readback-failed",
|
|
3121
|
-
package: {
|
|
3122
|
-
...plan.package,
|
|
3123
|
-
existsAfter: packageAfter.exists,
|
|
3124
|
-
observedVersionAfter: packageAfter.version,
|
|
3125
|
-
readbackStatus: packageAfter.status,
|
|
3126
|
-
},
|
|
3127
|
-
publish: {
|
|
3128
|
-
...plan.publish,
|
|
3129
|
-
status: publishStatus,
|
|
3130
|
-
},
|
|
3131
|
-
trust: {
|
|
3132
|
-
status: trustStatus,
|
|
3133
|
-
urls,
|
|
3134
|
-
expectedPublisher,
|
|
3135
|
-
exactBinding: trustList.exactBinding === true,
|
|
3136
|
-
publishers: trustList.publishers,
|
|
3137
|
-
},
|
|
3138
|
-
nextActions:
|
|
3139
|
-
trustStatus === "configured" && packageVerified
|
|
3140
|
-
? [
|
|
3141
|
-
{
|
|
3142
|
-
id: "paper-preflight",
|
|
3143
|
-
command: "buildchain paper preflight --json",
|
|
3144
|
-
description:
|
|
3145
|
-
"Verify package existence and Trusted Publisher binding from live read-only sources.",
|
|
3146
|
-
},
|
|
3147
|
-
]
|
|
3148
|
-
: trustStatus === "action-required" && packageVerified
|
|
3149
|
-
? [
|
|
3150
|
-
{
|
|
3151
|
-
id: "complete-npm-web-action",
|
|
3152
|
-
command: "",
|
|
3153
|
-
description:
|
|
3154
|
-
"Open the exact npm URL returned below, complete the web step, then rerun preflight.",
|
|
3155
|
-
urls,
|
|
3156
|
-
},
|
|
3157
|
-
]
|
|
3158
|
-
: !packageVerified
|
|
3159
|
-
? [
|
|
3160
|
-
{
|
|
3161
|
-
id: "verify-npm-package-readback",
|
|
3162
|
-
command: `npm view ${name} version --json --registry=${registry}`,
|
|
3163
|
-
description:
|
|
3164
|
-
"The mutation returned but the official registry did not prove package existence; do not infer success.",
|
|
3165
|
-
},
|
|
3166
|
-
]
|
|
3167
|
-
: [
|
|
3168
|
-
{
|
|
3169
|
-
id: "retry-npm-trust",
|
|
3170
|
-
command: `buildchain paper bootstrap npm --execute --confirm-public-package ${name} --json`,
|
|
3171
|
-
description:
|
|
3172
|
-
"The package exists; retry only the idempotent Trusted Publisher configuration path.",
|
|
3173
|
-
},
|
|
3174
|
-
],
|
|
3175
|
-
};
|
|
3176
|
-
receipt.receipts = [
|
|
3177
|
-
writePaperReceipt(resolvedCwd, PAPER_PATHS.npmBootstrap, receipt),
|
|
3178
|
-
];
|
|
3179
|
-
if (
|
|
3180
|
-
packageVerified &&
|
|
3181
|
-
(trustStatus === "configured" || trustStatus === "action-required")
|
|
3182
|
-
) {
|
|
3183
|
-
receipt.receipts.push(
|
|
3184
|
-
writePaperReceipt(resolvedCwd, PAPER_PATHS.npmTrust, receipt),
|
|
3185
|
-
);
|
|
3186
|
-
}
|
|
3187
|
-
return receipt;
|
|
3188
|
-
} finally {
|
|
3189
|
-
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
3190
|
-
}
|
|
2767
|
+
export function executePaperNpmBootstrap(options = {}) {
|
|
2768
|
+
return executePaperNpmBootstrapOperation(options, {
|
|
2769
|
+
DEFAULT_BOOTSTRAP_VERSION,
|
|
2770
|
+
NPM_REGISTRY,
|
|
2771
|
+
PAPER_NPM_BOOTSTRAP_CONTRACT,
|
|
2772
|
+
PAPER_PATHS,
|
|
2773
|
+
bootstrapPackageShape,
|
|
2774
|
+
commandResult,
|
|
2775
|
+
expectedPaperTrustedPublisher,
|
|
2776
|
+
extractUrls,
|
|
2777
|
+
fs,
|
|
2778
|
+
jsonText,
|
|
2779
|
+
liveNpmAuthObservation,
|
|
2780
|
+
liveNpmPackageObservation,
|
|
2781
|
+
liveNpmTrustObservation,
|
|
2782
|
+
normalizePackageName,
|
|
2783
|
+
normalizeRepository,
|
|
2784
|
+
os,
|
|
2785
|
+
paperConfig,
|
|
2786
|
+
path,
|
|
2787
|
+
resolvePaperRepository,
|
|
2788
|
+
safeParseJson,
|
|
2789
|
+
toPosix,
|
|
2790
|
+
validatePaperProvisioningAuthority,
|
|
2791
|
+
writePaperReceipt,
|
|
2792
|
+
});
|
|
3191
2793
|
}
|