@kungfu-tech/buildchain 4.1.3-alpha.9 → 4.1.4-alpha.0
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/AGENTS.md +11 -13
- package/CONTRIBUTING.md +32 -9
- package/README.md +56 -140
- package/actions/release/promotion/ref/README.md +1 -1
- package/architecture/action-taxonomy.json +1 -1
- package/architecture/agent-change-map.md +32 -45
- package/architecture/build-orchestration.json +1 -1
- package/architecture/capability-state-machine-manifest.json +5 -5
- package/architecture/ci-lane-change-budget.json +92 -92
- package/architecture/code-layout.json +2 -12
- package/architecture/core-mechanisms.json +38 -39
- package/architecture/cross-platform-adopter-qualification.json +1 -1
- package/architecture/dev-delivery-orchestration.json +2 -2
- package/architecture/floating-consumer-policy.json +3 -3
- package/architecture/internal-capabilities.json +27 -28
- package/architecture/maintainability-debt.json +60 -94
- package/architecture/maintainability-policy.json +7 -13
- package/architecture/minimal-consumer-migration.json +43 -5014
- package/architecture/platform-stage-checkpoints.json +1 -1
- package/architecture/release-tail-contract.json +2 -2
- package/architecture/release-topology.json +33 -25
- package/architecture/stage-capsule-qualification.json +1 -1
- package/architecture/universal-workflow-bootstrap.json +60 -60
- package/architecture/universal-workflow-capability-policy.json +3 -3
- package/architecture/universal-workflow-fault-campaign.json +7 -7
- package/architecture/workflow-taxonomy.json +59 -60
- package/contracts/fixtures/v4-tail-reseal-v1/valid.json +1 -1
- package/dist/site/buildchain-contract.json +138 -66
- package/dist/site/buildchain-site.json +257 -331
- package/dist/site/capability-registry.json +4 -4
- package/dist/site/cli-registry.json +6 -142
- package/dist/site/controller-registry.json +19 -19
- package/dist/site/kfd-claims.json +481 -529
- package/dist/site/kfd-upstream-aggregate.json +1 -1
- package/dist/site/manual-registry.json +22 -22
- package/dist/site/node-api-registry.json +82 -339
- package/dist/site/page-registry.json +229 -304
- package/dist/site/public-surface-audit.json +544 -754
- package/dist/site/publication-authority-registry.json +316 -316
- package/dist/site/publication-registry.json +1 -1
- package/dist/site/site-manifest.json +23 -23
- package/dist/site/workflow-registry.json +1071 -1027
- package/docs/MAP.md +28 -20
- package/docs/auditable-demo.md +17 -49
- package/docs/bootstrap-recovery.md +46 -37
- package/docs/cli-reference.md +2 -46
- package/docs/cli.md +97 -186
- package/docs/code-organization.md +7 -5
- package/docs/dev-alpha-candidate-patrol.md +19 -42
- package/docs/dev-delivery-orchestration.md +15 -11
- package/docs/dev-delivery-qualification-landing-adr.md +10 -9
- package/docs/dev-delivery-warrant.md +17 -16
- package/docs/dev-qualification-patrol.md +25 -20
- package/docs/getting-started.md +80 -139
- package/docs/github-artifact-attestation.md +31 -81
- package/docs/install.md +66 -30
- package/docs/lifecycle-protocol.md +19 -57
- package/docs/migration-inventory.md +17 -45
- package/docs/next-development-transition.md +13 -13
- package/docs/node-api-reference.md +122 -138
- package/docs/oci-publication.md +13 -10
- package/docs/publication-artifacts.md +128 -486
- package/docs/publication-authority.md +15 -45
- package/docs/publish-transaction.md +13 -11
- package/docs/release-candidate.md +126 -355
- package/docs/release-discussions.md +36 -67
- package/docs/release-flow.md +80 -339
- package/docs/release-governance.md +114 -962
- package/docs/release-promotion-request.md +45 -43
- package/docs/release-propagation.md +13 -27
- package/docs/release-tail-provider-plane.md +38 -65
- package/docs/reusable-build-surface.md +78 -196
- package/docs/runtime-train-validation.md +8 -6
- package/docs/stable-candidate-patrol.md +13 -66
- package/docs/v4-adopter-delivery.md +15 -15
- package/docs/v4-declarative-release-tail-migration.md +19 -17
- package/docs/v4-production-release.md +11 -6
- package/docs/v4-publication-rehearsal.md +12 -27
- package/docs/v4-stage-capsule.md +14 -20
- package/docs/v4-tail-reseal.md +34 -20
- package/docs/web-surface-deployments.md +26 -264
- package/docs/workflow-catalog.md +31 -31
- package/docs/workflow-path-migration.md +10 -4
- package/package.json +5 -4
- package/packages/core/adoption/buildchain-kfd-claims.js +7 -7
- package/packages/core/adoption/cli/output.mjs +1 -9
- package/packages/core/adoption/cli/product-gate.mjs +1 -15
- package/packages/core/adoption/cli/project.mjs +9 -10
- package/packages/core/adoption/cli/standards.mjs +1 -14
- package/packages/core/adoption/cli/support.mjs +0 -2
- package/packages/core/adoption/cli/surface-register.mjs +0 -2
- package/packages/core/adoption/commands/init-repo.mjs +77 -485
- package/packages/core/adoption/consumer-init.js +279 -0
- package/packages/core/adoption/qualification/admission.js +1 -1
- package/packages/core/build/cli/cache.mjs +0 -2
- package/packages/core/build/cli/facts.mjs +0 -3
- package/packages/core/build/cli/homebrew.mjs +0 -4
- package/packages/core/build/cli/lifecycle.mjs +0 -3
- package/packages/core/build/github-artifact-attestation.js +2 -2
- package/packages/core/build/platform-stage-checkpoints.js +1 -1
- package/packages/core/build/signing/dispatch.js +1 -1
- package/packages/core/consumer/buildchain-config.js +9 -0
- package/packages/core/consumer/contract/inspection.js +351 -9
- package/packages/core/consumer/contract/javascript-syntax.js +439 -0
- package/packages/core/consumer/contract/javascript-values.js +61 -0
- package/packages/core/consumer/contract/javascript.js +555 -0
- package/packages/core/consumer/contract/local-validation.js +84 -0
- package/packages/core/contracts/buildchain-contract.js +39 -8
- package/packages/core/contracts/cli/introspection.mjs +1 -9
- package/packages/core/contracts/public-surface-cli.js +0 -1
- package/packages/core/dev-delivery/dev-delivery-contract-surface.js +2 -2
- package/packages/core/governance/buildchain-publication-authority.js +24 -24
- package/packages/core/governance/cli/doctor.mjs +58 -42
- package/packages/core/governance/commands/architecture.mjs +6 -1
- package/packages/core/governance/commands/audit-publication-control-plane.mjs +1 -1
- package/packages/core/governance/commands/workflow-friction-report.mjs +1 -1
- package/packages/core/governance/github-governance-authority.js +2 -2
- package/packages/core/governance/publication/collection.js +1 -1
- package/packages/core/index.js +1 -3
- package/packages/core/observability/cli/candidate.mjs +0 -2
- package/packages/core/observability/cli/context.mjs +0 -5
- package/packages/core/observability/cli/diagnostics.mjs +0 -7
- package/packages/core/observability/cli/events.mjs +2 -10
- package/packages/core/paper/commands/paper-work-fleet-cli.mjs +1 -1
- package/packages/core/paper/commands/paper.mjs +33 -422
- package/packages/core/paper/consumer-status.js +72 -0
- package/packages/core/paper/operations/identity.js +0 -3
- package/packages/core/paper/operations/migration.js +460 -0
- package/packages/core/paper/operations/preflight-checks.js +8 -68
- package/packages/core/paper/operations/scaffold.js +16 -326
- package/packages/core/paper/operations/status.js +27 -53
- package/packages/core/paper/paper-agent-entry.js +36 -147
- package/packages/core/paper/paper-fleet.js +24 -39
- package/packages/core/paper/paper-repository.js +16 -0
- package/packages/core/paper/paper-runtime-channels.js +1 -1
- package/packages/core/paper/paper-scaffold-content.js +153 -162
- package/packages/core/paper/paper-work.js +3 -10
- package/packages/core/paper/paper.js +43 -5
- package/packages/core/providers/github/artifact-attestation.js +1 -1
- package/packages/core/providers/github/pipeline-context-artifacts.js +172 -0
- package/packages/core/providers/github/pipeline-release-evidence.js +17 -98
- package/packages/core/providers/github/pipeline-stable-baseline.js +86 -0
- package/packages/core/providers/github/pipeline-stable-source.js +22 -4
- package/packages/core/providers/github/release-evidence-assets.js +97 -0
- package/packages/core/publication/authority/control-plane.js +2 -2
- package/packages/core/publication/authority/seal.js +1 -1
- package/packages/core/publication/cli/dispatch.mjs +1 -12
- package/packages/core/publication/pipeline/actions.js +16 -9
- package/packages/core/publication/pipeline/apply.js +17 -9
- package/packages/core/publication/pipeline/context.js +29 -0
- package/packages/core/publication/pipeline/journal.js +13 -1
- package/packages/core/publication/pipeline/prepare.js +15 -6
- package/packages/core/publication/pipeline/recovery-import.js +1 -1
- package/packages/core/publication/pipeline/recovery-materials.js +63 -1
- package/packages/core/publication/pipeline/recovery-prepare.js +21 -9
- package/packages/core/publication/pipeline/stable-entry.js +12 -3
- package/packages/core/publication/pipeline/stable-products.js +21 -19
- package/packages/core/publication/pipeline/version-actions.js +15 -6
- package/packages/core/publication/publication-rehearsal-projection.js +0 -9
- package/packages/core/release/cli/dispatch.mjs +1 -4
- package/packages/core/release/cli/inspection-handlers.mjs +1 -33
- package/packages/core/release/cli/release-handlers.mjs +2 -19
- package/packages/core/release/cli/verification-handlers.mjs +4 -25
- package/packages/core/release/next-development-projection.js +13 -13
- package/packages/core/release/passport/locations.js +13 -8
- package/packages/core/release/release-passport.js +70 -5
- package/packages/core/web/cli/badges.mjs +0 -4
- package/packages/core/web/publication-admission.js +1 -1
- package/packages/core/web/publication-capability.js +1 -1
- package/packages/core/web/readme-badges.js +1 -1
- package/packages/core/workflow/cli/main.mjs +1 -4
- package/packages/core/workflow/cli/process.mjs +1 -1
- package/packages/core/workflow/commands/buildchain-cli-help.mjs +2 -8
- package/packages/core/workflow/engine/conformance.js +1 -1
- package/packages/core/workflow/pipeline/build.js +21 -1
- package/packages/core/workflow/pipeline/delivery-observation.js +6 -2
- package/packages/core/workflow/workflow-taxonomy.mjs +61 -17
- package/scripts/check-code-layout.mjs +2 -0
- package/scripts/check-core-mechanism-inventory.mjs +29 -13
- package/scripts/check-floating-consumer-policy-contract.mjs +3 -3
- package/scripts/check-inventory.mjs +27 -27
- package/scripts/check-maintainability.mjs +28 -5
- package/scripts/check-public-dogfood-contract.mjs +3 -3
- package/scripts/check-release-topology.mjs +1 -1
- package/scripts/check-self-consumer-contract.mjs +7 -7
- package/scripts/check-universal-workflow-bootstrap.mjs +1 -1
- package/scripts/generate-channel-promotion-workflow.mjs +1 -1
- package/scripts/generate-minimal-consumer-contract.mjs +21 -1
- package/scripts/generate-site-bundle.mjs +2 -1
- package/scripts/generate-tail-reseal-fixture.mjs +3 -3
- package/scripts/inventory/promotion.mjs +1 -1
- package/scripts/next-development-self-dogfood-harness.mjs +1 -1
- package/scripts/next-development-self-dogfood.mjs +4 -4
- package/scripts/site-capability-metadata.mjs +2 -6
- package/scripts/source-metric-lineage.mjs +62 -7
- package/scripts/verify-golden-path.mjs +31 -35
- package/templates/native-dev-delivery.yml +1 -1
- package/templates/universal-buildchain-bootstrap.yml +1 -1
- package/packages/core/paper/operations/bootstrap.js +0 -75
- package/packages/core/paper/operations/plans.js +0 -213
- package/packages/core/paper/operations/provisioning.js +0 -113
- package/packages/core/paper/operations/scaffold-config.js +0 -77
- package/packages/core/paper/operations/scaffold-workflows.js +0 -116
- package/packages/core/paper/operations/workspace.js +0 -60
- package/packages/core/paper/paper-npm-bootstrap.js +0 -492
|
@@ -3,34 +3,14 @@ import path from "node:path";
|
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { verifyInfraContractEvidenceBundle } from "../../providers/commands/infra-contract-core.mjs";
|
|
5
5
|
import { verifyBuildchainLogEvents } from "../../observability/logging.js";
|
|
6
|
+
import { verifyReleasePassport } from "../release-passport.js";
|
|
7
|
+
import { verifyPublicationAdmission } from "../../publication/publication-authority.js";
|
|
6
8
|
import {
|
|
7
|
-
explainReleaseLineDryRun,
|
|
8
|
-
formatReleaseLineDryRun,
|
|
9
|
-
} from "../release-line-dry-run.js";
|
|
10
|
-
import {
|
|
11
|
-
planReleaseLineBootstrap,
|
|
12
|
-
writeReleaseLineBootstrapVersionState,
|
|
13
|
-
} from "../release-line-bootstrap.js";
|
|
14
|
-
import { collectGitHubReleasePassport } from "../passport/collection.js";
|
|
15
|
-
import { explainReleasePassport, verifyReleasePassport } from "../release-passport.js";
|
|
16
|
-
import {
|
|
17
|
-
createPublicationAdmission,
|
|
18
|
-
createRunnerProvenance,
|
|
19
|
-
verifyPublicationAdmission,
|
|
20
|
-
} from "../../publication/publication-authority.js";
|
|
21
|
-
import {
|
|
22
|
-
createGitHubArtifactAttestationPolicy,
|
|
23
9
|
createGitHubArtifactAttestationVerificationPlan,
|
|
24
10
|
verifyGitHubArtifactAttestationEvidence,
|
|
25
11
|
} from "../../build/github-artifact-attestation.js";
|
|
26
|
-
import {
|
|
27
|
-
|
|
28
|
-
verifyArtifactPassport,
|
|
29
|
-
} from "../../build/artifact-passport.js";
|
|
30
|
-
import {
|
|
31
|
-
projectArtifactVerificationEnvelopeToKfx,
|
|
32
|
-
verifyArtifactVerificationEnvelope,
|
|
33
|
-
} from "../../build/artifact-verification-envelope.js";
|
|
12
|
+
import { verifyArtifactPassport } from "../../build/artifact-passport.js";
|
|
13
|
+
import { verifyArtifactVerificationEnvelope } from "../../build/artifact-verification-envelope.js";
|
|
34
14
|
import {
|
|
35
15
|
artifactEnvelopeOptions,
|
|
36
16
|
printJson,
|
|
@@ -38,7 +18,6 @@ import {
|
|
|
38
18
|
readFlag,
|
|
39
19
|
readJsonInput,
|
|
40
20
|
readRepeatedFlag,
|
|
41
|
-
writeJsonFile,
|
|
42
21
|
} from "../../contracts/cli/options.mjs";
|
|
43
22
|
|
|
44
23
|
async function verifyGitHubArtifactAttestationCommand({
|
|
@@ -266,19 +266,19 @@ invalid.
|
|
|
266
266
|
|
|
267
267
|
## Public self-dogfood and adoption
|
|
268
268
|
|
|
269
|
-
\`.github/workflows/
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
269
|
+
\`.github/workflows/buildchain.yml\` calls the published
|
|
270
|
+
\`public-ops-pipeline.yml@v4\` entry. Products declare their verification commands
|
|
271
|
+
in schema-2 TOML, including the full repository check on each required platform.
|
|
272
|
+
Next-development preparation, independent review, protected merge and settlement
|
|
273
|
+
remain runtime responsibilities.
|
|
274
|
+
|
|
275
|
+
\`.github/workflows/buildchain-recover.yml\` calls
|
|
276
|
+
\`public-ops-recover.yml@v4\` with one exact attempt and an optional temporary
|
|
277
|
+
repaired runtime. It preserves completed publication evidence while continuing
|
|
278
|
+
unfinished follow-ups. Both callers use the same generated bytes as external
|
|
279
|
+
consumers. Tool-maintained locks and retained receipts bind exact runtime SHAs.
|
|
280
|
+
Earlier Stage Capsule and channel-build proofs retain their historical source
|
|
281
|
+
identities; they do not define additional current consumer entrypoints.
|
|
282
282
|
|
|
283
283
|
## Local adapter
|
|
284
284
|
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import fs from "node:fs";
|
|
3
|
-
import { readJsonFile } from "./files.js";
|
|
4
3
|
import https from "node:https";
|
|
5
4
|
import http from "node:http";
|
|
6
5
|
import { nonEmptyString } from "./identity.js";
|
|
7
|
-
export async function resolveSiblingJson(basePath, relativePath) {
|
|
6
|
+
export async function resolveSiblingJson(basePath, relativePath, options) {
|
|
8
7
|
if (!basePath || !relativePath) {
|
|
9
8
|
return undefined;
|
|
10
9
|
}
|
|
11
10
|
if (/^https?:\/\//.test(relativePath)) {
|
|
12
|
-
return readJsonFromLocation(relativePath);
|
|
11
|
+
return readJsonFromLocation(relativePath, 0, options);
|
|
13
12
|
}
|
|
14
13
|
if (/^https?:\/\//.test(basePath)) {
|
|
15
|
-
return readJsonFromLocation(
|
|
14
|
+
return readJsonFromLocation(
|
|
15
|
+
new URL(relativePath, basePath).toString(),
|
|
16
|
+
0,
|
|
17
|
+
options,
|
|
18
|
+
);
|
|
16
19
|
}
|
|
17
20
|
const candidate = path.resolve(path.dirname(basePath), relativePath);
|
|
18
21
|
if (!fs.existsSync(candidate)) {
|
|
19
22
|
return undefined;
|
|
20
23
|
}
|
|
21
|
-
return
|
|
24
|
+
return readJsonFromLocation(candidate, 0, options);
|
|
22
25
|
}
|
|
23
26
|
export async function readJsonFromLocation(
|
|
24
27
|
location,
|
|
25
28
|
redirectCount = 0,
|
|
26
|
-
{ timeoutMs = 15_000 } = {},
|
|
29
|
+
{ timeoutMs = 15_000, raw = false } = {},
|
|
27
30
|
) {
|
|
28
31
|
const input = nonEmptyString(location, "location");
|
|
29
32
|
if (!Number.isInteger(timeoutMs) || timeoutMs <= 0) {
|
|
@@ -47,6 +50,7 @@ export async function readJsonFromLocation(
|
|
|
47
50
|
response.resume();
|
|
48
51
|
readJsonFromLocation(nextLocation, redirectCount + 1, {
|
|
49
52
|
timeoutMs,
|
|
53
|
+
raw,
|
|
50
54
|
}).then(resolve, reject);
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
@@ -64,7 +68,7 @@ export async function readJsonFromLocation(
|
|
|
64
68
|
});
|
|
65
69
|
response.on("end", () => {
|
|
66
70
|
try {
|
|
67
|
-
resolve(JSON.parse(body));
|
|
71
|
+
resolve(raw ? body : JSON.parse(body));
|
|
68
72
|
} catch (error) {
|
|
69
73
|
reject(error);
|
|
70
74
|
}
|
|
@@ -78,5 +82,6 @@ export async function readJsonFromLocation(
|
|
|
78
82
|
request.on("error", reject);
|
|
79
83
|
});
|
|
80
84
|
}
|
|
81
|
-
|
|
85
|
+
const bytes = fs.readFileSync(input, "utf8");
|
|
86
|
+
return raw ? bytes : JSON.parse(bytes);
|
|
82
87
|
}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { verifyPublishedDocuments } from "../publication/pipeline/stable-products.js";
|
|
1
5
|
import { resolveReleasePassportVerificationInputs } from "./release-passport-contract.js";
|
|
2
6
|
import { nowIso } from "./passport/identity.js";
|
|
3
7
|
import {
|
|
@@ -5,6 +9,56 @@ import {
|
|
|
5
9
|
resolveSiblingJson,
|
|
6
10
|
} from "./passport/locations.js";
|
|
7
11
|
import { createReleaseCheckReport } from "./passport/report.js";
|
|
12
|
+
|
|
13
|
+
async function verifyPipelinePassport(location, release, checkedAt, execute) {
|
|
14
|
+
const directory = fs.mkdtempSync(
|
|
15
|
+
path.join(fs.realpathSync(os.tmpdir()), "buildchain-passport-"),
|
|
16
|
+
);
|
|
17
|
+
const report = {
|
|
18
|
+
schemaVersion: 1,
|
|
19
|
+
contract: "kungfu-buildchain-release-check-report",
|
|
20
|
+
checkedAt,
|
|
21
|
+
verificationScope: "signed-release-metadata",
|
|
22
|
+
artifactBytesVerified: false,
|
|
23
|
+
providerStateVerified: false,
|
|
24
|
+
completeness: { artifactCount: 0 },
|
|
25
|
+
issues: [],
|
|
26
|
+
};
|
|
27
|
+
try {
|
|
28
|
+
const values = { release };
|
|
29
|
+
for (const name of ["plan", "qualification", "capsules", "invocation"])
|
|
30
|
+
values[name] = await resolveSiblingJson(
|
|
31
|
+
location,
|
|
32
|
+
`buildchain.${name}.json`,
|
|
33
|
+
);
|
|
34
|
+
const bundle = await resolveSiblingJson(
|
|
35
|
+
location,
|
|
36
|
+
"buildchain.attestation.json",
|
|
37
|
+
{ raw: true },
|
|
38
|
+
);
|
|
39
|
+
verifyPublishedDocuments(values, bundle, {
|
|
40
|
+
directory,
|
|
41
|
+
token: process.env.GH_TOKEN || process.env.GITHUB_TOKEN,
|
|
42
|
+
execute,
|
|
43
|
+
});
|
|
44
|
+
report.completeness.artifactCount = values.qualification.artifacts.length;
|
|
45
|
+
report.source = release.source;
|
|
46
|
+
report.release = release.release;
|
|
47
|
+
} catch {
|
|
48
|
+
report.issues.push({
|
|
49
|
+
level: "error",
|
|
50
|
+
code: "pipeline.evidence",
|
|
51
|
+
message:
|
|
52
|
+
"Signed release metadata verification failed. Supply all five unchanged companion files and GitHub CLI with attestation verification support.",
|
|
53
|
+
});
|
|
54
|
+
} finally {
|
|
55
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
report.ok = report.issues.length === 0;
|
|
58
|
+
report.trust = report.ok ? "pass" : "fail";
|
|
59
|
+
return report;
|
|
60
|
+
}
|
|
61
|
+
|
|
8
62
|
export async function verifyReleasePassport({
|
|
9
63
|
passportLocation,
|
|
10
64
|
artifactEvidenceLocation = "",
|
|
@@ -17,7 +71,16 @@ export async function verifyReleasePassport({
|
|
|
17
71
|
kfdAdopterManifestGateLocation = "",
|
|
18
72
|
kfdSupportEvidenceLocation = "",
|
|
19
73
|
checkedAt = nowIso(),
|
|
74
|
+
execute,
|
|
20
75
|
} = {}) {
|
|
76
|
+
const passport = await readJsonFromLocation(passportLocation);
|
|
77
|
+
if (passport?.schema === "kungfu.buildchain.release-passport/v4")
|
|
78
|
+
return verifyPipelinePassport(
|
|
79
|
+
passportLocation,
|
|
80
|
+
passport,
|
|
81
|
+
checkedAt,
|
|
82
|
+
execute,
|
|
83
|
+
);
|
|
21
84
|
const evidence = await resolveReleasePassportVerificationInputs({
|
|
22
85
|
passportLocation,
|
|
23
86
|
locations: {
|
|
@@ -34,10 +97,7 @@ export async function verifyReleasePassport({
|
|
|
34
97
|
readJson: readJsonFromLocation,
|
|
35
98
|
resolveSibling: resolveSiblingJson,
|
|
36
99
|
});
|
|
37
|
-
return createReleaseCheckReport({
|
|
38
|
-
...evidence,
|
|
39
|
-
checkedAt,
|
|
40
|
-
});
|
|
100
|
+
return createReleaseCheckReport({ ...evidence, checkedAt });
|
|
41
101
|
}
|
|
42
102
|
export async function explainReleasePassport({
|
|
43
103
|
passportLocation,
|
|
@@ -46,7 +106,9 @@ export async function explainReleasePassport({
|
|
|
46
106
|
const report = await verifyReleasePassport({ passportLocation });
|
|
47
107
|
const passport = await readJsonFromLocation(passportLocation);
|
|
48
108
|
const nextAction = report.ok
|
|
49
|
-
? "
|
|
109
|
+
? report.verificationScope === "signed-release-metadata"
|
|
110
|
+
? "verify-artifact-bytes-and-review-policy"
|
|
111
|
+
: "install-or-upgrade-after-policy-review"
|
|
50
112
|
: "block-release-and-report-verification-failure";
|
|
51
113
|
return {
|
|
52
114
|
schemaVersion: 1,
|
|
@@ -54,6 +116,9 @@ export async function explainReleasePassport({
|
|
|
54
116
|
audience: forAudience,
|
|
55
117
|
release: passport.release,
|
|
56
118
|
trust: report.trust,
|
|
119
|
+
verificationScope: report.verificationScope,
|
|
120
|
+
artifactBytesVerified: report.artifactBytesVerified,
|
|
121
|
+
providerStateVerified: report.providerStateVerified,
|
|
57
122
|
complete: report.ok,
|
|
58
123
|
artifactCount: report.completeness.artifactCount,
|
|
59
124
|
runnerPolicy: passport.runnerPolicy,
|
|
@@ -56,7 +56,7 @@ export function assembleWebPublicationAdmission({
|
|
|
56
56
|
"managed web-surface publication requires an ephemeral GitHub-hosted Actions runner",
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
|
-
const workflowPath = ".github/workflows
|
|
59
|
+
const workflowPath = ".github/workflows/.release-web.yml";
|
|
60
60
|
const publisherWorkflowPath = workflowPath;
|
|
61
61
|
const controlPlaneAudit = createPublicationControlPlaneAudit({
|
|
62
62
|
repository,
|
|
@@ -36,7 +36,7 @@ export function verifyWebPublicationCapability(request, now = Date.now()) {
|
|
|
36
36
|
}
|
|
37
37
|
const roleArn = required(request, "roleArn");
|
|
38
38
|
const exact = {
|
|
39
|
-
workflowPath: ".github/workflows
|
|
39
|
+
workflowPath: ".github/workflows/.release-web.yml",
|
|
40
40
|
repository: required(request, "repository"),
|
|
41
41
|
sourceSha: required(request, "sourceSha").toLowerCase(),
|
|
42
42
|
runtimeSha: required(request, "runtimeSha").toLowerCase(),
|
|
@@ -457,7 +457,7 @@ function normalizePackageRepository(repository) {
|
|
|
457
457
|
function discoverWorkflowFacts({ cwd, repository, badgeConfig = {} }) {
|
|
458
458
|
const workflowDir = path.join(cwd, ".github", "workflows");
|
|
459
459
|
const configured = normalizeStringArray(badgeConfig.workflows);
|
|
460
|
-
const defaults = ["verify.yml", "build.yml", "buildchain-ref-promotion.yml"];
|
|
460
|
+
const defaults = ["verify.yml", ".build-candidate.yml", "buildchain-ref-promotion.yml"];
|
|
461
461
|
const names = configured.length > 0 ? configured : defaults;
|
|
462
462
|
if (!fs.existsSync(workflowDir)) {
|
|
463
463
|
return [];
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { initializeCliRuntime } from "../../contracts/cli/context.mjs";
|
|
2
2
|
import { BUILDCHAIN_USAGE } from "../commands/buildchain-cli-help.mjs";
|
|
3
3
|
import { formatCliHelp } from "../../contracts/cli-reference.js";
|
|
4
|
-
import {
|
|
5
|
-
TRUST_RELEASE_COMMANDS,
|
|
6
|
-
dispatchTrustReleaseCommand,
|
|
7
|
-
} from "../../release/cli/trust-release.mjs";
|
|
4
|
+
import { TRUST_RELEASE_COMMANDS } from "../../release/cli/trust-release.mjs";
|
|
8
5
|
import { dispatchRegisteredCommand } from "../../contracts/command-registry.mjs";
|
|
9
6
|
import { handleAdopterDeliveryCommand } from "../../adoption/cli/dispatch.mjs";
|
|
10
7
|
import { handleKfdCommand } from "../../adoption/cli/kfd.mjs";
|
|
@@ -20,7 +20,7 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
20
20
|
[--cold-fallback-status not-run|passed|failed]
|
|
21
21
|
[--output <file>] [--json]
|
|
22
22
|
buildchain candidate timeline --input <file-or-json> [--output <file>] [--json]
|
|
23
|
-
buildchain init [--cwd <dir>] [--type package|native|
|
|
23
|
+
buildchain init [--cwd <dir>] [--type npm|binary|paper|package|native|publication-artifact|anchored-package] [--force]
|
|
24
24
|
[--package-manager pnpm|npm|yarn] [--runner-preset <preset>]
|
|
25
25
|
[--artifact-name <name>]
|
|
26
26
|
buildchain validate [--cwd <dir>] [--require-version-state]
|
|
@@ -253,7 +253,7 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
253
253
|
[--output <file>] [--promote]
|
|
254
254
|
[--no-toolchain-pull]
|
|
255
255
|
[--allow-unpinned-toolchain] [--json]
|
|
256
|
-
buildchain paper scaffold --
|
|
256
|
+
buildchain paper scaffold --repository <owner/repo> [--package <name>] [--write] [--json]
|
|
257
257
|
buildchain paper migrate [--cwd <dir>] [--write] [--json]
|
|
258
258
|
buildchain paper work start <topic> [--cwd <dir>] [--branch <branch>] [--execute] [--json]
|
|
259
259
|
buildchain paper work submit [--cwd <dir>] [--title <title>] [--body <body>] [--execute] [--json]
|
|
@@ -261,13 +261,7 @@ export const BUILDCHAIN_USAGE = `Usage:
|
|
|
261
261
|
buildchain paper fleet update [--root <dir>] [--write] [--json]
|
|
262
262
|
buildchain paper agent verify [--cwd <dir>] [--offline] [--json]
|
|
263
263
|
buildchain paper preflight [--cwd <dir>] [--offline] [--json]
|
|
264
|
-
buildchain paper bootstrap npm [--cwd <dir>] [--execute]
|
|
265
|
-
[--confirm-public-package <name>] [--json]
|
|
266
|
-
buildchain paper build [--cwd <dir>] [--execute] [--json]
|
|
267
|
-
buildchain paper alpha [--cwd <dir>] [--source-ref <ref>] [--target-ref <ref>]
|
|
268
|
-
[--execute] [--json]
|
|
269
264
|
buildchain paper status [--cwd <dir>] [--json]
|
|
270
|
-
buildchain paper resume [--cwd <dir>] [--runtime-ref <ref>] [--execute] [--json]
|
|
271
265
|
buildchain release-propagation <plan|write-lock|work|entry|pickup> ...
|
|
272
266
|
buildchain badges readme [--cwd <dir>] [--readme <path>] [--check] [--write] [--json]
|
|
273
267
|
buildchain badges bundle [--cwd <dir>] [--readme <path>] [--claims <csv>] [--check] [--write] [--json]
|
|
@@ -52,7 +52,7 @@ export function executeBootstrapConformance(
|
|
|
52
52
|
const source = fs.readFileSync(path.join(runtimeRoot, relative), "utf8");
|
|
53
53
|
if (
|
|
54
54
|
relative !== architecture.bootstrap.publicWorkflow &&
|
|
55
|
-
!/(?:\.\/)?\.github\/workflows
|
|
55
|
+
!/(?:\.\/)?\.github\/workflows\/\.ops-bootstrap\.yml/u.test(source)
|
|
56
56
|
)
|
|
57
57
|
fail(`candidate Bootstrap facade is not governed: ${relative}`);
|
|
58
58
|
}
|
|
@@ -3,12 +3,15 @@ import path from "node:path";
|
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
5
5
|
import { bindConsumerSource } from "../../consumer/contract/identity.js";
|
|
6
|
+
import { inspectConsumerContract } from "../../consumer/contract/inspection.js";
|
|
7
|
+
import { validateConsumerWiring } from "../../consumer/contract/local-validation.js";
|
|
6
8
|
import { recordDigest } from "../../release/discussion/envelope.js";
|
|
7
9
|
import { consumerCommandSession } from "../../runtime/consumer-shell.js";
|
|
8
10
|
import { createNativeChildEnvironment } from "../../dev-delivery/native/execution.js";
|
|
9
11
|
|
|
10
12
|
function inspectTrackedBytes(cwd, tree) {
|
|
11
13
|
const root = fs.realpathSync(cwd);
|
|
14
|
+
const files = Object.create(null);
|
|
12
15
|
const entries = execFileSync(
|
|
13
16
|
"git",
|
|
14
17
|
["-C", root, "ls-tree", "-r", "-z", tree],
|
|
@@ -48,7 +51,13 @@ function inspectTrackedBytes(cwd, tree) {
|
|
|
48
51
|
throw new Error(
|
|
49
52
|
`Build tracked source bytes differ from the admitted tree: ${file}`,
|
|
50
53
|
);
|
|
54
|
+
Object.defineProperty(files, file, {
|
|
55
|
+
enumerable: true,
|
|
56
|
+
get: () =>
|
|
57
|
+
link ? fs.readlinkSync(absolute) : fs.readFileSync(absolute, "utf8"),
|
|
58
|
+
});
|
|
51
59
|
}
|
|
60
|
+
return files;
|
|
52
61
|
}
|
|
53
62
|
|
|
54
63
|
export function inspectPipelineSource(cwd, expected) {
|
|
@@ -82,7 +91,18 @@ export function inspectPipelineSource(cwd, expected) {
|
|
|
82
91
|
"Build source has tracked modifications at its verification boundary",
|
|
83
92
|
);
|
|
84
93
|
// Index flags and local Git filters cannot qualify different product bytes.
|
|
85
|
-
inspectTrackedBytes(cwd, expected.tree);
|
|
94
|
+
const files = inspectTrackedBytes(cwd, expected.tree);
|
|
95
|
+
const { channel } = validateConsumerWiring(cwd, expected.configPath);
|
|
96
|
+
const inspection = inspectConsumerContract(files, {
|
|
97
|
+
channel,
|
|
98
|
+
configPath: expected.configPath,
|
|
99
|
+
});
|
|
100
|
+
if (inspection.controlIssues.length)
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Consumer control wiring is invalid: ${inspection.controlIssues.join("; ")}`,
|
|
103
|
+
);
|
|
104
|
+
// Unresolved product language/tool edges are not a static safety proof.
|
|
105
|
+
// Execution remains confined to the runtime's read-only product jobs below.
|
|
86
106
|
return plan;
|
|
87
107
|
}
|
|
88
108
|
|
|
@@ -65,9 +65,13 @@ export async function observePipelineWorker(session, current, queue, host) {
|
|
|
65
65
|
run,
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
|
+
// Retained executions keep the workflow identity that actually produced them.
|
|
69
|
+
// The old path is read-only evidence, never a new dispatch or consumer alias.
|
|
68
70
|
const entries = (run.referenced_workflows || []).filter((entry) =>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
[".ops-dev-auto-merge.yml", "public-ops-dev-auto-merge.yml"].some((file) =>
|
|
72
|
+
entry.path?.startsWith(
|
|
73
|
+
`kungfu-systems/buildchain/.github/workflows/${file}@`,
|
|
74
|
+
),
|
|
71
75
|
),
|
|
72
76
|
);
|
|
73
77
|
if (entries.length !== 1) return null;
|
|
@@ -64,13 +64,12 @@ function validateEntries(policy, errors) {
|
|
|
64
64
|
if (
|
|
65
65
|
entry.path &&
|
|
66
66
|
!(
|
|
67
|
-
[".build", "
|
|
68
|
-
|
|
69
|
-
) && entry.path === `.github/workflows/${entry.id}.yml`
|
|
67
|
+
[".build", "buildchain", "buildchain-recover"].includes(entry.id) &&
|
|
68
|
+
entry.path === `.github/workflows/${entry.id}.yml`
|
|
70
69
|
)
|
|
71
70
|
)
|
|
72
71
|
errors.push(
|
|
73
|
-
`${entry.id}: explicit path is reserved for build
|
|
72
|
+
`${entry.id}: explicit path is reserved for the internal build engine and generated consumer pair`,
|
|
74
73
|
);
|
|
75
74
|
const file = workflowPath(entry);
|
|
76
75
|
if (!WORKFLOW.test(file) || paths.has(file))
|
|
@@ -82,6 +81,33 @@ function validateEntries(policy, errors) {
|
|
|
82
81
|
);
|
|
83
82
|
validateEntryOwnership(entry, errors);
|
|
84
83
|
}
|
|
84
|
+
const publicEntries = policy.entries.filter(
|
|
85
|
+
(entry) => entry.role === "public",
|
|
86
|
+
);
|
|
87
|
+
if (
|
|
88
|
+
policy.entries
|
|
89
|
+
.filter((entry) => entry.role === "self")
|
|
90
|
+
.map((entry) => entry.id)
|
|
91
|
+
.sort()
|
|
92
|
+
.join(",") !== "buildchain,buildchain-recover"
|
|
93
|
+
)
|
|
94
|
+
errors.push(
|
|
95
|
+
"repository event roots must be exactly the generated consumer pair",
|
|
96
|
+
);
|
|
97
|
+
if (
|
|
98
|
+
publicEntries.length !== 2 ||
|
|
99
|
+
["pipeline", "recover"].some(
|
|
100
|
+
(purpose) =>
|
|
101
|
+
!publicEntries.some(
|
|
102
|
+
(entry) =>
|
|
103
|
+
entry.id === purpose &&
|
|
104
|
+
entry.category === "ops" &&
|
|
105
|
+
entry.purpose === purpose &&
|
|
106
|
+
entry.invocation === "reusable",
|
|
107
|
+
),
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
errors.push("consumer public entries must be exactly pipeline and recover");
|
|
85
111
|
return policy.entries;
|
|
86
112
|
}
|
|
87
113
|
|
|
@@ -100,11 +126,9 @@ export function discoverWorkflowFiles(root) {
|
|
|
100
126
|
return visit(directory).sort();
|
|
101
127
|
}
|
|
102
128
|
|
|
103
|
-
function validateWorkflow(
|
|
129
|
+
function validateWorkflow(entry, text, declared, errors) {
|
|
130
|
+
if (typeof text !== "string") return;
|
|
104
131
|
const file = workflowPath(entry),
|
|
105
|
-
absolute = path.join(root, file);
|
|
106
|
-
if (!fs.existsSync(absolute) || !fs.lstatSync(absolute).isFile()) return;
|
|
107
|
-
const text = fs.readFileSync(absolute, "utf8"),
|
|
108
132
|
document = parseWorkflowDocument(text);
|
|
109
133
|
if (
|
|
110
134
|
(entry.invocation === "reusable") !==
|
|
@@ -258,23 +282,41 @@ function validateGateIntegration(root, errors) {
|
|
|
258
282
|
|
|
259
283
|
export function checkWorkflowTaxonomy(
|
|
260
284
|
root,
|
|
261
|
-
{ integration = true, documentation = true } = {},
|
|
285
|
+
{ integration = true, documentation = true, files } = {},
|
|
262
286
|
) {
|
|
263
287
|
const errors = [],
|
|
264
|
-
policy =
|
|
288
|
+
policy = files
|
|
289
|
+
? JSON.parse(files[TAXONOMY_PATH] || "null")
|
|
290
|
+
: readWorkflowTaxonomy(root),
|
|
265
291
|
entries = validateEntries(policy, errors);
|
|
266
292
|
if (errors.length) return { ok: false, errors };
|
|
293
|
+
files ??= Object.fromEntries(
|
|
294
|
+
discoverWorkflowFiles(root).map((file) => {
|
|
295
|
+
const absolute = path.join(root, file);
|
|
296
|
+
return [
|
|
297
|
+
file,
|
|
298
|
+
fs.lstatSync(absolute).isFile()
|
|
299
|
+
? fs.readFileSync(absolute, "utf8")
|
|
300
|
+
: null,
|
|
301
|
+
];
|
|
302
|
+
}),
|
|
303
|
+
);
|
|
267
304
|
const declared = new Set(entries.map(workflowPath)),
|
|
268
|
-
observed = new Set(
|
|
305
|
+
observed = new Set(
|
|
306
|
+
Object.keys(files).filter((file) =>
|
|
307
|
+
/^\.github\/workflows\/.*\.ya?ml$/iu.test(file),
|
|
308
|
+
),
|
|
309
|
+
);
|
|
269
310
|
for (const file of observed) {
|
|
270
311
|
if (!declared.has(file)) errors.push(`unregistered workflow: ${file}`);
|
|
271
|
-
if (
|
|
312
|
+
if (typeof files[file] !== "string")
|
|
272
313
|
errors.push(`workflow must be a regular file: ${file}`);
|
|
273
314
|
}
|
|
274
315
|
for (const file of declared)
|
|
275
316
|
if (!observed.has(file))
|
|
276
317
|
errors.push(`registered workflow missing: ${file}`);
|
|
277
|
-
for (const entry of entries)
|
|
318
|
+
for (const entry of entries)
|
|
319
|
+
validateWorkflow(entry, files[workflowPath(entry)], declared, errors);
|
|
278
320
|
if (integration) validateGateIntegration(root, errors);
|
|
279
321
|
if (documentation) {
|
|
280
322
|
const file = path.join(root, TAXONOMY_DOC);
|
|
@@ -324,9 +366,9 @@ export function renderWorkflowCatalog(policy) {
|
|
|
324
366
|
"",
|
|
325
367
|
"Generated from `architecture/workflow-taxonomy.json`. Every workflow has one canonical implementation; alternate paths and historical forwarding aliases are rejected.",
|
|
326
368
|
"",
|
|
327
|
-
"
|
|
369
|
+
"The two public workflows own normal pipeline execution and exact-attempt recovery. Component workflows are internal runtime implementation, including once-only setup and the dispatch signing service; consumers do not wire these components. Self workflows are the generated consumer pair. Actions own execution steps; JS adapters and Rust/WASM own implementation.",
|
|
328
370
|
"",
|
|
329
|
-
"Names use `public
|
|
371
|
+
"Names use `public-ops-pipeline.yml`, `public-ops-recover.yml`, internal `.<category>-<purpose>.yml`, and the generated self callers `buildchain.yml` and `buildchain-recover.yml`. Categories are `build`, `release`, and `ops`; the internal build engine retains `.build.yml`.",
|
|
330
372
|
"",
|
|
331
373
|
"Register ownership before adding a workflow. `pnpm run check:workflows` validates source, calls, required CI integration and independent review ownership. `pnpm run generate:workflows` regenerates this catalog.",
|
|
332
374
|
"",
|
|
@@ -366,6 +408,8 @@ function validateEntryOwnership(entry, errors) {
|
|
|
366
408
|
errors.push(`${entry.id}: invalid invocation`);
|
|
367
409
|
if ((entry.role === "self") !== (entry.invocation === "repository"))
|
|
368
410
|
errors.push(`${entry.id}: role and invocation disagree`);
|
|
369
|
-
if (entry.
|
|
370
|
-
errors.push(
|
|
411
|
+
if (entry.invocation === "dispatch-service" && entry.role !== "component")
|
|
412
|
+
errors.push(
|
|
413
|
+
`${entry.id}: dispatch services must remain internal components`,
|
|
414
|
+
);
|
|
371
415
|
}
|
|
@@ -204,6 +204,8 @@ export function inspectPublicActionNodes(actions, publicNodes) {
|
|
|
204
204
|
const issues = [];
|
|
205
205
|
if (!Array.isArray(publicNodes))
|
|
206
206
|
return ["public Action registry must be an array"];
|
|
207
|
+
if (publicNodes.length)
|
|
208
|
+
issues.push("Actions are internal runtime nodes; consumers use pipeline and recovery workflows");
|
|
207
209
|
const known = new Set(
|
|
208
210
|
actions.map((action) => action.directory.replace(/^actions\//u, "")),
|
|
209
211
|
);
|
|
@@ -34,15 +34,24 @@ function registrySurfaceIds(root) {
|
|
|
34
34
|
(entry) => `cli:${entry.id}`,
|
|
35
35
|
);
|
|
36
36
|
const workflows = loadJson(root, "dist/site/workflow-registry.json");
|
|
37
|
-
const workflowIds = workflows.workflows.flatMap((entry) =>
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
const workflowIds = workflows.workflows.flatMap((entry) =>
|
|
38
|
+
[entry.id, ...(entry.taxonomy ? [entry.taxonomy.id] : [])].map((id) => [
|
|
39
|
+
`workflow:${id}`,
|
|
40
|
+
entry.apiRole === "public" ? "public" : "internal",
|
|
41
|
+
]),
|
|
42
|
+
);
|
|
43
|
+
const actionIds = workflows.actions.map((entry) => [
|
|
44
|
+
`action:${entry.id}`,
|
|
45
|
+
entry.apiRole === "public" ? "public" : "internal",
|
|
40
46
|
]);
|
|
41
|
-
const actionIds = workflows.actions.map((entry) => `action:${entry.id}`);
|
|
42
47
|
const exports = Object.keys(loadJson(root, "package.json").exports).map(
|
|
43
48
|
(entry) => `export:${entry}`,
|
|
44
49
|
);
|
|
45
|
-
return new
|
|
50
|
+
return new Map(
|
|
51
|
+
[...cli, ...exports]
|
|
52
|
+
.map((id) => [id, "public"])
|
|
53
|
+
.concat(workflowIds, actionIds),
|
|
54
|
+
);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
function listFiles(root, relativeRoot) {
|
|
@@ -99,12 +108,12 @@ function validateOwnership(mechanism, ownedSources, issues) {
|
|
|
99
108
|
}
|
|
100
109
|
|
|
101
110
|
function validateSurfaces(mechanism, surfaces, issues) {
|
|
102
|
-
for (const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
111
|
+
for (const role of ["public", "internal"])
|
|
112
|
+
for (const surface of mechanism[`${role}Surfaces`] || [])
|
|
113
|
+
if (surfaces.get(surface) !== role)
|
|
114
|
+
issues.push(
|
|
115
|
+
`${mechanism.id}: ${role} surface is absent or has a different role in generated/package registries: ${surface}`,
|
|
116
|
+
);
|
|
108
117
|
}
|
|
109
118
|
|
|
110
119
|
function validateGitRefStore(root, mechanism, issues) {
|
|
@@ -140,12 +149,15 @@ function validateReverseScanReferences(root, reverseScan, issues) {
|
|
|
140
149
|
function validateSurfaceKinds(inventory, issues) {
|
|
141
150
|
const surfaceKinds = new Set(
|
|
142
151
|
(inventory.mechanisms || []).flatMap((mechanism) =>
|
|
143
|
-
|
|
152
|
+
[
|
|
153
|
+
...(mechanism.publicSurfaces || []),
|
|
154
|
+
...(mechanism.internalSurfaces || []),
|
|
155
|
+
].map((surface) => surface.split(":")[0]),
|
|
144
156
|
),
|
|
145
157
|
);
|
|
146
158
|
for (const kind of ["action", "cli", "export", "workflow"]) {
|
|
147
159
|
if (!surfaceKinds.has(kind))
|
|
148
|
-
issues.push(`reverse scan has no ${kind}
|
|
160
|
+
issues.push(`reverse scan has no ${kind} surface coverage`);
|
|
149
161
|
}
|
|
150
162
|
return surfaceKinds;
|
|
151
163
|
}
|
|
@@ -329,6 +341,10 @@ function checkCoreMechanismInventory({
|
|
|
329
341
|
(sum, entry) => sum + entry.publicSurfaces.length,
|
|
330
342
|
0,
|
|
331
343
|
),
|
|
344
|
+
internalSurfaces: inventory.mechanisms.reduce(
|
|
345
|
+
(sum, entry) => sum + (entry.internalSurfaces || []).length,
|
|
346
|
+
0,
|
|
347
|
+
),
|
|
332
348
|
dependencyCycles: inventory.maintainability.dependencyCycles,
|
|
333
349
|
...reverseScan,
|
|
334
350
|
};
|