@intentius/chant 0.13.1 → 0.15.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/dist/audit/catalog.d.ts +45 -5
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/proof.d.ts +3 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +4 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts +3 -0
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +8 -2
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts +39 -0
- package/dist/cli/handlers/components.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts +3 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts +4 -2
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +35 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +22 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.d.ts +110 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -0
- package/dist/codegen/pinned-upgrade.d.ts +153 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
- package/dist/codegen/rolling-upgrade.d.ts +138 -0
- package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
- package/dist/codegen/surface-snapshot.d.ts +173 -0
- package/dist/codegen/surface-snapshot.d.ts.map +1 -0
- package/dist/codegen/version-bump.d.ts +21 -0
- package/dist/codegen/version-bump.d.ts.map +1 -0
- package/dist/components/auto-release.d.ts +93 -0
- package/dist/components/auto-release.d.ts.map +1 -0
- package/dist/components/builders.d.ts +37 -0
- package/dist/components/builders.d.ts.map +1 -0
- package/dist/components/capability-plugin-loader.d.ts +111 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -0
- package/dist/components/capability-plugin-schema.d.ts +24 -0
- package/dist/components/capability-plugin-schema.d.ts.map +1 -0
- package/dist/components/capability-plugin.d.ts +85 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/components/capability.d.ts +89 -0
- package/dist/components/capability.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +204 -0
- package/dist/components/cli-support.d.ts.map +1 -0
- package/dist/components/component.d.ts +179 -0
- package/dist/components/component.d.ts.map +1 -0
- package/dist/components/config-defaults.d.ts +41 -0
- package/dist/components/config-defaults.d.ts.map +1 -0
- package/dist/components/discover.d.ts +60 -0
- package/dist/components/discover.d.ts.map +1 -0
- package/dist/components/driver-output.d.ts +20 -0
- package/dist/components/driver-output.d.ts.map +1 -0
- package/dist/components/driver.d.ts +209 -0
- package/dist/components/driver.d.ts.map +1 -0
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/manifest-persistence.d.ts +79 -0
- package/dist/components/manifest-persistence.d.ts.map +1 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
- package/dist/components/pilots/lambda.pilot.d.ts +35 -0
- package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
- package/dist/components/pilots/project.d.ts +13 -0
- package/dist/components/pilots/project.d.ts.map +1 -0
- package/dist/components/presets/ecs-fargate.d.ts +59 -0
- package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
- package/dist/components/presets/index.d.ts +29 -0
- package/dist/components/presets/index.d.ts.map +1 -0
- package/dist/components/presets/lambda.d.ts +35 -0
- package/dist/components/presets/lambda.d.ts.map +1 -0
- package/dist/components/presets/single-host-compose.d.ts +43 -0
- package/dist/components/presets/single-host-compose.d.ts.map +1 -0
- package/dist/components/registry.d.ts +29 -0
- package/dist/components/registry.d.ts.map +1 -0
- package/dist/components/starter-plugin.d.ts +51 -0
- package/dist/components/starter-plugin.d.ts.map +1 -0
- package/dist/components/temporal-codegen-loader.d.ts +27 -0
- package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/bom-writer.d.ts +155 -0
- package/dist/components/verbs/bom-writer.d.ts.map +1 -0
- package/dist/components/verbs/build-archive.d.ts +205 -0
- package/dist/components/verbs/build-archive.d.ts.map +1 -0
- package/dist/components/verbs/build.d.ts +150 -0
- package/dist/components/verbs/build.d.ts.map +1 -0
- package/dist/components/verbs/cloud-executor.d.ts +88 -0
- package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/component-bom.d.ts +103 -0
- package/dist/components/verbs/component-bom.d.ts.map +1 -0
- package/dist/components/verbs/index.d.ts +49 -0
- package/dist/components/verbs/index.d.ts.map +1 -0
- package/dist/components/verbs/license-policy.d.ts +56 -0
- package/dist/components/verbs/license-policy.d.ts.map +1 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/process-runner.d.ts +64 -0
- package/dist/components/verbs/process-runner.d.ts.map +1 -0
- package/dist/components/verbs/reproducibility.d.ts +80 -0
- package/dist/components/verbs/reproducibility.d.ts.map +1 -0
- package/dist/components/verbs/sbom-generator.d.ts +157 -0
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/sbom.d.ts +79 -0
- package/dist/components/verbs/sbom.d.ts.map +1 -0
- package/dist/components/verbs/shell.d.ts +35 -0
- package/dist/components/verbs/shell.d.ts.map +1 -0
- package/dist/components/verbs/sign.d.ts +222 -0
- package/dist/components/verbs/sign.d.ts.map +1 -0
- package/dist/components/verbs/stub.d.ts +18 -0
- package/dist/components/verbs/stub.d.ts.map +1 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/verify.d.ts +106 -0
- package/dist/components/verbs/verify.d.ts.map +1 -0
- package/dist/components/verbs/vex.d.ts +65 -0
- package/dist/components/verbs/vex.d.ts.map +1 -0
- package/dist/components/verbs/vuln-gate.d.ts +91 -0
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
- package/dist/components/verbs/vuln-scan.d.ts +116 -0
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
- package/dist/components/verbs/wait-verify.d.ts +85 -0
- package/dist/components/verbs/wait-verify.d.ts.map +1 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +78 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts +121 -0
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
- package/dist/lifecycle/build-ledger.d.ts +225 -0
- package/dist/lifecycle/build-ledger.d.ts.map +1 -0
- package/dist/lifecycle/git.d.ts +84 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +5 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
- package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
- package/dist/lifecycle/release-ledger.d.ts +122 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -0
- package/dist/lifecycle/status.d.ts +150 -0
- package/dist/lifecycle/status.d.ts.map +1 -0
- package/dist/lint/component-checks.d.ts +95 -0
- package/dist/lint/component-checks.d.ts.map +1 -0
- package/dist/lint/engine.d.ts +23 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/presets/strict.json +8 -1
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +18 -0
- package/dist/lint/rules/comp/index.d.ts.map +1 -0
- package/dist/lint/rules/comp/support.d.ts +71 -0
- package/dist/lint/rules/comp/support.d.ts.map +1 -0
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activity-registry.d.ts +11 -6
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +24 -0
- package/dist/op/activity-runtime.d.ts.map +1 -0
- package/dist/op/builders.d.ts +56 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/ownership.d.ts +20 -14
- package/dist/ownership.d.ts.map +1 -1
- package/package.json +14 -1
- package/src/audit/catalog.test.ts +74 -22
- package/src/audit/catalog.ts +74 -471
- package/src/audit/proof.ts +4 -2
- package/src/audit/report-html.test.ts +14 -7
- package/src/audit/report-model.ts +20 -9
- package/src/audit/report.test.ts +36 -13
- package/src/audit/report.ts +2 -0
- package/src/audit/rules-doc.test.ts +8 -6
- package/src/audit/rules-doc.ts +13 -5
- package/src/cli/commands/audit.ts +23 -18
- package/src/cli/commands/component-lint.test.ts +158 -0
- package/src/cli/commands/doctor.test.ts +116 -2
- package/src/cli/commands/doctor.ts +46 -0
- package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
- package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
- package/src/cli/commands/lexicon-surface-diff.ts +185 -0
- package/src/cli/commands/lint.ts +142 -1
- package/src/cli/commands/pinned-upgrade.ts +204 -0
- package/src/cli/handlers/build.ts +58 -1
- package/src/cli/handlers/components.test.ts +504 -0
- package/src/cli/handlers/components.ts +404 -0
- package/src/cli/handlers/dev.ts +60 -1
- package/src/cli/handlers/graph.ts +47 -2
- package/src/cli/handlers/misc.ts +45 -1
- package/src/cli/handlers/run.test.ts +967 -3
- package/src/cli/handlers/run.ts +618 -11
- package/src/cli/main.test.ts +66 -0
- package/src/cli/main.ts +105 -2
- package/src/cli/registry.ts +35 -0
- package/src/codegen/fetch.test.ts +84 -3
- package/src/codegen/fetch.ts +76 -2
- package/src/codegen/lexicon-regen.test.ts +298 -0
- package/src/codegen/lexicon-regen.ts +545 -0
- package/src/codegen/pinned-upgrade.test.ts +399 -0
- package/src/codegen/pinned-upgrade.ts +423 -0
- package/src/codegen/rolling-upgrade.test.ts +333 -0
- package/src/codegen/rolling-upgrade.ts +320 -0
- package/src/codegen/surface-snapshot.test.ts +461 -0
- package/src/codegen/surface-snapshot.ts +546 -0
- package/src/codegen/version-bump.test.ts +47 -0
- package/src/codegen/version-bump.ts +39 -0
- package/src/components/README.md +130 -0
- package/src/components/SPRAWL-VALIDATION.md +181 -0
- package/src/components/__fixtures__/alb-ecs-service.json +51 -0
- package/src/components/__fixtures__/dynamodb-infra.json +32 -0
- package/src/components/__fixtures__/emr-job-consumer.json +26 -0
- package/src/components/__fixtures__/jar-lib-producer.json +16 -0
- package/src/components/__fixtures__/lambda-image-processor.json +28 -0
- package/src/components/__fixtures__/neo4j-fanout.json +34 -0
- package/src/components/__fixtures__/single-host-compose.json +29 -0
- package/src/components/auto-release.test.ts +217 -0
- package/src/components/auto-release.ts +216 -0
- package/src/components/builders.test.ts +45 -0
- package/src/components/builders.ts +71 -0
- package/src/components/capability-plugin-loader.ts +218 -0
- package/src/components/capability-plugin-schema.ts +56 -0
- package/src/components/capability-plugin.test.ts +235 -0
- package/src/components/capability-plugin.ts +108 -0
- package/src/components/capability.ts +117 -0
- package/src/components/cli-support.test.ts +579 -0
- package/src/components/cli-support.ts +481 -0
- package/src/components/component-schema.test.ts +265 -0
- package/src/components/component.schema.json +235 -0
- package/src/components/component.test.ts +251 -0
- package/src/components/component.ts +255 -0
- package/src/components/config-defaults.test.ts +263 -0
- package/src/components/config-defaults.ts +145 -0
- package/src/components/discover.test.ts +352 -0
- package/src/components/discover.ts +167 -0
- package/src/components/driver-output.ts +71 -0
- package/src/components/driver.test.ts +638 -0
- package/src/components/driver.ts +690 -0
- package/src/components/index.ts +113 -0
- package/src/components/manifest-persistence.test.ts +152 -0
- package/src/components/manifest-persistence.ts +164 -0
- package/src/components/pilots/README.md +33 -0
- package/src/components/pilots/alb-ecs.pilot.ts +63 -0
- package/src/components/pilots/dynamodb.pilot.ts +59 -0
- package/src/components/pilots/jar-emr.pilot.ts +69 -0
- package/src/components/pilots/lambda.pilot.ts +55 -0
- package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
- package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
- package/src/components/pilots/pilots.test.ts +126 -0
- package/src/components/pilots/project.ts +13 -0
- package/src/components/presets/comp007-reduction.test.ts +122 -0
- package/src/components/presets/ecs-fargate.test.ts +84 -0
- package/src/components/presets/ecs-fargate.ts +103 -0
- package/src/components/presets/index.ts +32 -0
- package/src/components/presets/lambda.test.ts +35 -0
- package/src/components/presets/lambda.ts +53 -0
- package/src/components/presets/single-host-compose.test.ts +65 -0
- package/src/components/presets/single-host-compose.ts +64 -0
- package/src/components/registry.test.ts +112 -0
- package/src/components/registry.ts +37 -0
- package/src/components/starter-plugin.ts +105 -0
- package/src/components/temporal-codegen-loader.ts +41 -0
- package/src/components/verbs/__fixtures__/package-lock.json +45 -0
- package/src/components/verbs/__fixtures__/pom.xml +37 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
- package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
- package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
- package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
- package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
- package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
- package/src/components/verbs/bom-writer.test.ts +331 -0
- package/src/components/verbs/bom-writer.ts +386 -0
- package/src/components/verbs/build-archive.test.ts +251 -0
- package/src/components/verbs/build-archive.ts +296 -0
- package/src/components/verbs/build.test.ts +222 -0
- package/src/components/verbs/build.ts +252 -0
- package/src/components/verbs/cloud-executor.ts +181 -0
- package/src/components/verbs/component-bom.test.ts +219 -0
- package/src/components/verbs/component-bom.ts +189 -0
- package/src/components/verbs/index.ts +49 -0
- package/src/components/verbs/license-policy.ts +115 -0
- package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
- package/src/components/verbs/process-runner.test.ts +79 -0
- package/src/components/verbs/process-runner.ts +113 -0
- package/src/components/verbs/reproducibility.test.ts +24 -0
- package/src/components/verbs/reproducibility.ts +100 -0
- package/src/components/verbs/sbom-generator.test.ts +96 -0
- package/src/components/verbs/sbom-generator.ts +209 -0
- package/src/components/verbs/sbom.test.ts +184 -0
- package/src/components/verbs/sbom.ts +152 -0
- package/src/components/verbs/shell.test.ts +36 -0
- package/src/components/verbs/shell.ts +51 -0
- package/src/components/verbs/sign.test.ts +210 -0
- package/src/components/verbs/sign.ts +350 -0
- package/src/components/verbs/stub.ts +34 -0
- package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
- package/src/components/verbs/tool-sbom-generator.ts +192 -0
- package/src/components/verbs/verify.test.ts +159 -0
- package/src/components/verbs/verify.ts +179 -0
- package/src/components/verbs/vex.ts +182 -0
- package/src/components/verbs/vuln-gate.test.ts +201 -0
- package/src/components/verbs/vuln-gate.ts +170 -0
- package/src/components/verbs/vuln-scan.test.ts +145 -0
- package/src/components/verbs/vuln-scan.ts +266 -0
- package/src/components/verbs/wait-verify.test.ts +111 -0
- package/src/components/verbs/wait-verify.ts +171 -0
- package/src/config.test.ts +74 -1
- package/src/config.ts +219 -0
- package/src/index.ts +32 -0
- package/src/lexicon.ts +88 -0
- package/src/lifecycle/build-ledger-store.test.ts +217 -0
- package/src/lifecycle/build-ledger-store.ts +165 -0
- package/src/lifecycle/build-ledger.test.ts +349 -0
- package/src/lifecycle/build-ledger.ts +305 -0
- package/src/lifecycle/git.test.ts +118 -0
- package/src/lifecycle/git.ts +149 -14
- package/src/lifecycle/index.ts +5 -0
- package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
- package/src/lifecycle/oras-referrer-lookup.ts +110 -0
- package/src/lifecycle/release-ledger.test.ts +209 -0
- package/src/lifecycle/release-ledger.ts +185 -0
- package/src/lifecycle/status.test.ts +330 -0
- package/src/lifecycle/status.ts +278 -0
- package/src/lint/component-checks.ts +148 -0
- package/src/lint/config.test.ts +21 -0
- package/src/lint/engine.ts +11 -2
- package/src/lint/presets/relaxed.json +8 -1
- package/src/lint/presets/strict.json +8 -1
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
- package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
- package/src/lint/rules/comp/comp.test.ts +378 -0
- package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
- package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
- package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
- package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
- package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
- package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
- package/src/lint/rules/comp/index.ts +37 -0
- package/src/lint/rules/comp/support.ts +173 -0
- package/src/lsp/lexicon-providers.test.ts +55 -0
- package/src/lsp/lexicon-providers.ts +13 -3
- package/src/op/activity-registry.test.ts +38 -0
- package/src/op/activity-registry.ts +31 -12
- package/src/op/activity-runtime.ts +73 -0
- package/src/op/builders.ts +92 -0
- package/src/op/index.ts +3 -1
- package/src/ownership.test.ts +24 -26
- package/src/ownership.ts +26 -38
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BuildArchive format — the self-contained bundle `docker-build` (and the
|
|
3
|
+
* other build-family verbs) write into (#564, epic #551 "4. Build archive +
|
|
4
|
+
* deferred publish"). See docs/components/build-archive.mdx.
|
|
5
|
+
*
|
|
6
|
+
* A build archive holds four kinds of contents, enumerated by one manifest:
|
|
7
|
+
* - `image` — an image tarball in OCI layout (as `docker save` produces),
|
|
8
|
+
* content-addressed by its digest.
|
|
9
|
+
* - `template` — a synthesized deploy template (e.g. a CloudFormation
|
|
10
|
+
* document) referenced by `cfn-deploy`'s `archive:<name>` convention
|
|
11
|
+
* (see ../verbs/apply.ts's `CfnDeployInput.template`). Per #613, a
|
|
12
|
+
* `template` entry is a first-class artifact with its own content
|
|
13
|
+
* digest — peer to `image`/`asset` — so it can itself be the
|
|
14
|
+
* `subjectDigest` a `sbom`-kind entry (specifically a config-BOM,
|
|
15
|
+
* `bomKind: "config"`) is attached to.
|
|
16
|
+
* - `asset` — any other published artifact (a jar, a zip) the `publish`
|
|
17
|
+
* family's non-image backends (`publish-artifact`) promote.
|
|
18
|
+
* - `sbom` — a Bill of Materials attached to another entry's digest (#606,
|
|
19
|
+
* #613, epic #551 follow-up to #564/#568), written by either the
|
|
20
|
+
* `generate-sbom` capability (./sbom.ts, a **software** BOM over an
|
|
21
|
+
* image/jar/zip/dir) or the `extract-config-bom` capability
|
|
22
|
+
* (./config-bom.ts, a **config-BOM** over a synthesized IaC template's
|
|
23
|
+
* declared resources/nested stacks/external references). `bomKind`
|
|
24
|
+
* distinguishes the two without introducing a separate entry kind — both
|
|
25
|
+
* are content-addressed, digest-linked BOM documents, and every existing
|
|
26
|
+
* `sbom`-kind consumer (`findSbomForSubject`, the build ledger) keeps
|
|
27
|
+
* working unmodified for either kind. The archive is the **universal
|
|
28
|
+
* home** for both: an image's SBOM may also be projected as an OCI
|
|
29
|
+
* referrer at publish time (a registry-side convenience for `oras
|
|
30
|
+
* discover`/`cosign tree`), but the archive-carried copy is what makes
|
|
31
|
+
* non-image artifacts (a jar in S3, a zip, a template) and registry-less
|
|
32
|
+
* deploys (`load-image-on-host`) work identically — no registry required
|
|
33
|
+
* to read a build's BOM back.
|
|
34
|
+
*
|
|
35
|
+
* The manifest is itself content-addressed (`manifestDigest`, a stable hash
|
|
36
|
+
* over its entries) so two builds of the same inputs produce the same
|
|
37
|
+
* archive identity, and so a promoted digest can be traced back to exactly
|
|
38
|
+
* the manifest that produced it. Nothing here shells out or touches a real
|
|
39
|
+
* filesystem/docker daemon — manifest assembly is pure data, which is what
|
|
40
|
+
* lets `docker-build` (./build.ts) and `publish-image`/`load-image-on-host`
|
|
41
|
+
* (./publish.ts) build and promote an archive entirely through the injectable
|
|
42
|
+
* `CloudExecutor`, exercised in tests via `MockCloudExecutor` with no real
|
|
43
|
+
* disk/docker/AWS involved. The same is true of `generate-sbom` (./sbom.ts)
|
|
44
|
+
* and the injectable `SbomGenerator` (./sbom-generator.ts).
|
|
45
|
+
*
|
|
46
|
+
* Per #614, every `image`/`template`/`asset` entry also carries an honest,
|
|
47
|
+
* per-artifact `reproducibility` record and an optional `provenance`
|
|
48
|
+
* source->output link (see ./reproducibility.ts) — never a single blanket
|
|
49
|
+
* flag hoisted to the component, since a component that builds more than one
|
|
50
|
+
* artifact type (an image plus a synthesized template, say) has a different
|
|
51
|
+
* true answer for each.
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
// ── manifest entries ──────────────────────────────────────────────────────
|
|
55
|
+
|
|
56
|
+
import type { ArtifactReproducibility, ProvenanceLink } from "./reproducibility";
|
|
57
|
+
import { defaultReproducibility } from "./reproducibility";
|
|
58
|
+
|
|
59
|
+
export type BuildArchiveEntryKind = "image" | "template" | "asset" | "sbom";
|
|
60
|
+
|
|
61
|
+
/** One content-addressed item inside a build archive. */
|
|
62
|
+
export interface BuildArchiveEntry {
|
|
63
|
+
/** What this entry is — an OCI-layout image tarball, a synthesized template, a non-image asset (jar/zip), or an SBOM. */
|
|
64
|
+
kind: BuildArchiveEntryKind;
|
|
65
|
+
/** Path of this entry inside the archive (what `cfn-deploy`'s `archive:<path>` and `publish-image`/`publish-artifact`'s `from` reference). */
|
|
66
|
+
path: string;
|
|
67
|
+
/** Content-addressed digest of this entry's bytes (`sha256:...`). Identity for promote-by-digest. */
|
|
68
|
+
digest: string;
|
|
69
|
+
/** Declared media type, mirroring the OCI conventions the epic references (`oras discover`/`cosign tree` attach to the same digest). Defaults are assigned per `kind` by `addArchiveEntry` when omitted. For a `kind: "sbom"` entry this is the SBOM's own media type (`application/spdx+json` or `application/vnd.cyclonedx+json`) — never hardcoded, always read from the `SbomDocument` that produced the entry (./sbom-generator.ts). */
|
|
70
|
+
mediaType?: string;
|
|
71
|
+
/**
|
|
72
|
+
* For a `kind: "sbom"` entry only: the digest of the artifact this SBOM
|
|
73
|
+
* describes (an `image`/`asset` entry's `digest` elsewhere in the same
|
|
74
|
+
* manifest) — the OCI "referrer subject" relationship, recorded uniformly
|
|
75
|
+
* here regardless of whether the backend that produced it was a BuildKit
|
|
76
|
+
* attestation or a `syft` scan (#606: "the backend owns HOW it attaches
|
|
77
|
+
* ... the archive manifest records it uniformly"). Absent for non-SBOM
|
|
78
|
+
* entries.
|
|
79
|
+
*/
|
|
80
|
+
subjectDigest?: string;
|
|
81
|
+
/** For a `kind: "sbom"` entry only: number of packages/components the SBOM enumerates, when known — surfaced by `chant components status` without parsing the SBOM bytes. */
|
|
82
|
+
packageCount?: number;
|
|
83
|
+
/** For a `kind: "sbom"` entry only: which tool produced it (e.g. "syft", "buildkit") — surfaced alongside format/package count so status reports SBOM *source*. */
|
|
84
|
+
generator?: string;
|
|
85
|
+
/**
|
|
86
|
+
* For a `kind: "sbom"` entry only: whether this is a **software** BOM
|
|
87
|
+
* (over an image/jar/zip/dir's declared dependencies, ./sbom.ts) or a
|
|
88
|
+
* **config-BOM** (over a synthesized IaC template's declared resources +
|
|
89
|
+
* nested stacks + external references, ./config-bom.ts) (#613). Defaults
|
|
90
|
+
* to `"software"` when omitted, so every pre-#613 `sbom` entry (and every
|
|
91
|
+
* caller that never set this field) is unambiguously the software kind —
|
|
92
|
+
* this default must never change without a manifest version bump.
|
|
93
|
+
*/
|
|
94
|
+
bomKind?: "software" | "config";
|
|
95
|
+
/**
|
|
96
|
+
* For an `image`/`template`/`asset` entry: the honest, per-artifact
|
|
97
|
+
* reproducibility basis (#614, see ./reproducibility.ts). Assigned a
|
|
98
|
+
* kind-appropriate default by `addArchiveEntry` when omitted — see
|
|
99
|
+
* `defaultReproducibility` — so every entry that can meaningfully carry a
|
|
100
|
+
* reproducibility claim gets one without every call site having to compute
|
|
101
|
+
* it. Absent for `sbom` entries, which describe another artifact rather
|
|
102
|
+
* than being one themselves.
|
|
103
|
+
*/
|
|
104
|
+
reproducibility?: ArtifactReproducibility;
|
|
105
|
+
/**
|
|
106
|
+
* For an `image`/`template`/`asset` entry: the source ref/commit that
|
|
107
|
+
* produced this artifact's digest (#614). Optional — a caller that hasn't
|
|
108
|
+
* threaded through a source ref (e.g. a test fixture, or a build run
|
|
109
|
+
* outside a git checkout) simply omits it rather than fabricating one.
|
|
110
|
+
*/
|
|
111
|
+
provenance?: ProvenanceLink;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The manifest of contents for one build archive — the "self-contained format" #564 asks for. */
|
|
115
|
+
export interface BuildArchiveManifest {
|
|
116
|
+
/** Manifest schema version, so a future incompatible shape can be detected before being misread. */
|
|
117
|
+
version: 1;
|
|
118
|
+
/** Component this archive was built for. */
|
|
119
|
+
component: string;
|
|
120
|
+
/** ISO-8601 timestamp this manifest was assembled. */
|
|
121
|
+
createdAt: string;
|
|
122
|
+
/** Every image/template/asset this archive carries. */
|
|
123
|
+
contents: BuildArchiveEntry[];
|
|
124
|
+
/**
|
|
125
|
+
* Content-addressed digest of this manifest's own entries (`sha256:...`),
|
|
126
|
+
* stable across rebuilds of byte-identical inputs and independent of
|
|
127
|
+
* `createdAt` — so identical inputs produce the same archive identity even
|
|
128
|
+
* when built at different times, and a changed digest here always means
|
|
129
|
+
* changed contents, not merely a re-run.
|
|
130
|
+
*/
|
|
131
|
+
manifestDigest: string;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Fallback media type per entry `kind`, used only when a caller omits
|
|
136
|
+
* `mediaType` on `addArchiveEntry`. `sbom` has no single default here by
|
|
137
|
+
* design — SPDX and CycloneDX are both first-class (#606) and the actual
|
|
138
|
+
* media type always comes from the `SbomDocument` the `generate-sbom`
|
|
139
|
+
* capability produced (./sbom-generator.ts); this fallback exists only so a
|
|
140
|
+
* malformed/omitted call doesn't produce an entry with no media type at all.
|
|
141
|
+
*/
|
|
142
|
+
const DEFAULT_MEDIA_TYPES: Record<BuildArchiveEntryKind, string> = {
|
|
143
|
+
image: "application/vnd.oci.image.layout.v1.tar",
|
|
144
|
+
template: "application/json",
|
|
145
|
+
asset: "application/octet-stream",
|
|
146
|
+
sbom: "application/spdx+json",
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Deterministic content digest over arbitrary string content. Same shape as
|
|
151
|
+
* the FNV-ish fake digest `MockCloudExecutor` uses, so tests can assert on it
|
|
152
|
+
* without a real `sha256` implementation. Exported so callers that need to
|
|
153
|
+
* digest content that never goes through the `CloudExecutor` (e.g. a
|
|
154
|
+
* synthesized template's serialized bytes, see ./build.ts's
|
|
155
|
+
* `addArchiveTemplate`) share this one algorithm rather than each defining
|
|
156
|
+
* their own. Production `image`/`asset` entries instead carry the real
|
|
157
|
+
* digest their producing capability already computed (e.g. `docker-build`'s
|
|
158
|
+
* `executor.docker.build` digest).
|
|
159
|
+
*/
|
|
160
|
+
export function contentDigest(input: string): string {
|
|
161
|
+
let hash = 0;
|
|
162
|
+
for (let i = 0; i < input.length; i++) {
|
|
163
|
+
hash = (Math.imul(hash, 31) + input.charCodeAt(i)) | 0;
|
|
164
|
+
}
|
|
165
|
+
const hex = Math.abs(hash).toString(16).padStart(8, "0");
|
|
166
|
+
return `sha256:${hex.repeat(8).slice(0, 64)}`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/** Compute the aggregate `manifestDigest` over a set of entries — sorted by path so entry order never changes the digest, only content does. */
|
|
170
|
+
export function computeManifestDigest(contents: BuildArchiveEntry[]): string {
|
|
171
|
+
const sorted = [...contents].sort((a, b) => a.path.localeCompare(b.path));
|
|
172
|
+
const canonical = sorted.map((e) => `${e.kind}:${e.path}:${e.digest}`).join("\n");
|
|
173
|
+
return contentDigest(canonical);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** Start a new, empty manifest for `component`. Entries are added with `addArchiveEntry`. */
|
|
177
|
+
export function createBuildArchiveManifest(component: string, opts?: { now?: () => Date }): BuildArchiveManifest {
|
|
178
|
+
const createdAt = (opts?.now ?? (() => new Date()))().toISOString();
|
|
179
|
+
return { version: 1, component, createdAt, contents: [], manifestDigest: computeManifestDigest([]) };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Add (or replace, by `path`) one entry and return a new manifest with
|
|
184
|
+
* `manifestDigest` recomputed. Pure/immutable so callers (and tests) can hold
|
|
185
|
+
* onto a manifest snapshot before/after a step without aliasing surprises.
|
|
186
|
+
*
|
|
187
|
+
* Assigns a kind-appropriate default `reproducibility` (#614,
|
|
188
|
+
* `defaultReproducibility`) when the caller omits one — `template` entries
|
|
189
|
+
* default to `deterministic-synthesis`, `image`/`asset` entries default to
|
|
190
|
+
* `best-effort`, and `sbom` entries get none. An explicit `entry.reproducibility`
|
|
191
|
+
* (e.g. a future reproducible-build-attested image) always wins over the
|
|
192
|
+
* default. `reproducibility`/`provenance` are never part of
|
|
193
|
+
* `computeManifestDigest`'s input — they describe the artifact, they are not
|
|
194
|
+
* content the artifact's identity depends on, so recording/correcting them
|
|
195
|
+
* later never perturbs `manifestDigest`.
|
|
196
|
+
*/
|
|
197
|
+
export function addArchiveEntry(
|
|
198
|
+
manifest: BuildArchiveManifest,
|
|
199
|
+
entry: BuildArchiveEntry,
|
|
200
|
+
): BuildArchiveManifest {
|
|
201
|
+
const reproducibility =
|
|
202
|
+
entry.reproducibility ??
|
|
203
|
+
(entry.kind === "image" || entry.kind === "template" || entry.kind === "asset" || entry.kind === "sbom"
|
|
204
|
+
? defaultReproducibility(entry.kind)
|
|
205
|
+
: undefined);
|
|
206
|
+
const resolved: BuildArchiveEntry = {
|
|
207
|
+
mediaType: DEFAULT_MEDIA_TYPES[entry.kind],
|
|
208
|
+
...entry,
|
|
209
|
+
...(reproducibility ? { reproducibility } : {}),
|
|
210
|
+
};
|
|
211
|
+
const contents = [...manifest.contents.filter((e) => e.path !== resolved.path), resolved];
|
|
212
|
+
return { ...manifest, contents, manifestDigest: computeManifestDigest(contents) };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Look up one entry by archive-relative path (the same path form `cfn-deploy`'s `archive:<path>` and `publish-image`'s `from` use). */
|
|
216
|
+
export function findArchiveEntry(
|
|
217
|
+
manifest: BuildArchiveManifest,
|
|
218
|
+
path: string,
|
|
219
|
+
): BuildArchiveEntry | undefined {
|
|
220
|
+
return manifest.contents.find((e) => e.path === path);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Strip the `archive:` prefix chant's step wiring uses
|
|
225
|
+
* (e.g. `cfn-deploy`'s `template: "archive:search.template.json"`) down to
|
|
226
|
+
* the manifest-relative path. Returns the input unchanged when it carries no
|
|
227
|
+
* such prefix (a plain filesystem path outside the archive).
|
|
228
|
+
*/
|
|
229
|
+
export function archiveRelativePath(ref: string): string {
|
|
230
|
+
return ref.startsWith("archive:") ? ref.slice("archive:".length) : ref;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** All `image`-kind entries in a manifest — what a publish backend has to choose from when `from` is ambiguous/omitted. */
|
|
234
|
+
export function imageEntries(manifest: BuildArchiveManifest): BuildArchiveEntry[] {
|
|
235
|
+
return manifest.contents.filter((e) => e.kind === "image");
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** All `sbom`-kind entries in a manifest, regardless of which artifact they describe (#606). */
|
|
239
|
+
export function sbomEntries(manifest: BuildArchiveManifest): BuildArchiveEntry[] {
|
|
240
|
+
return manifest.contents.filter((e) => e.kind === "sbom");
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Find the archive-carried SBOM entry attached to a given artifact digest
|
|
245
|
+
* (an `image`/`asset` entry's `digest` elsewhere in the same manifest). This
|
|
246
|
+
* is the archive-native lookup ../../lifecycle/build-ledger.ts's
|
|
247
|
+
* `buildLedgerEntries` uses to surface "SBOM by digest" without any registry
|
|
248
|
+
* or `oras`/network access — the archive is the universal home for the SBOM
|
|
249
|
+
* regardless of artifact type (#606).
|
|
250
|
+
*/
|
|
251
|
+
export function findSbomForSubject(
|
|
252
|
+
manifest: BuildArchiveManifest,
|
|
253
|
+
subjectDigest: string,
|
|
254
|
+
): BuildArchiveEntry | undefined {
|
|
255
|
+
return manifest.contents.find((e) => e.kind === "sbom" && e.subjectDigest === subjectDigest);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Find the archive-carried **config-BOM** entry (`bomKind: "config"`)
|
|
260
|
+
* attached to a given template digest — the config-BOM analogue of
|
|
261
|
+
* `findSbomForSubject` (#613). A `template` entry's digest is computed the
|
|
262
|
+
* same way an `image`/`asset` entry's is (`contentDigest` over its bytes,
|
|
263
|
+
* see `addArchiveTemplate` in ./build.ts), so config-only/infra components
|
|
264
|
+
* with no software artifact still resolve a BOM by digest through the same
|
|
265
|
+
* lookup shape as every other artifact kind.
|
|
266
|
+
*/
|
|
267
|
+
export function findConfigBomForSubject(
|
|
268
|
+
manifest: BuildArchiveManifest,
|
|
269
|
+
subjectDigest: string,
|
|
270
|
+
): BuildArchiveEntry | undefined {
|
|
271
|
+
return manifest.contents.find(
|
|
272
|
+
(e) => e.kind === "sbom" && e.bomKind === "config" && e.subjectDigest === subjectDigest,
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** All `template`-kind entries in a manifest — every synthesized IaC document the archive carries, each a first-class artifact with its own content digest (#613). */
|
|
277
|
+
export function templateEntries(manifest: BuildArchiveManifest): BuildArchiveEntry[] {
|
|
278
|
+
return manifest.contents.filter((e) => e.kind === "template");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** All `asset`-kind entries in a manifest (non-image published artifacts — a jar, a zip). */
|
|
282
|
+
export function assetEntries(manifest: BuildArchiveManifest): BuildArchiveEntry[] {
|
|
283
|
+
return manifest.contents.filter((e) => e.kind === "asset");
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Every artifact entry in a manifest — `image`, `template`, and `asset`
|
|
288
|
+
* kinds, excluding `sbom` entries (which describe an artifact rather than
|
|
289
|
+
* being one) — the set #614's per-artifact reproducibility surface iterates
|
|
290
|
+
* over. Order is manifest insertion order; callers that need a stable order
|
|
291
|
+
* for display/JSON output sort by `path` themselves (mirroring
|
|
292
|
+
* `computeManifestDigest`'s own path-sort convention).
|
|
293
|
+
*/
|
|
294
|
+
export function artifactEntries(manifest: BuildArchiveManifest): BuildArchiveEntry[] {
|
|
295
|
+
return manifest.contents.filter((e) => e.kind !== "sbom");
|
|
296
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { addArchiveTemplate, createDockerBuildCapability, createZipPackageCapability, createJvmBuildCapability } from "./build";
|
|
3
|
+
import { createMockCloudExecutor } from "./__tests__/mock-cloud-executor";
|
|
4
|
+
import { createMockProcessRunner } from "./__tests__/mock-process-runner";
|
|
5
|
+
import { findArchiveEntry } from "./build-archive";
|
|
6
|
+
import { writeFileSync, mkdtempSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { createHash } from "node:crypto";
|
|
10
|
+
|
|
11
|
+
const ctx = { env: "dev", component: "search-service" };
|
|
12
|
+
|
|
13
|
+
describe("docker-build (#557)", () => {
|
|
14
|
+
it("builds via the injected executor and saves the tarball into the archive path, returning the built digest", async () => {
|
|
15
|
+
const mock = createMockCloudExecutor();
|
|
16
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
17
|
+
|
|
18
|
+
const output = await capability.run(ctx, { context: ".", into: "archive/search.tar" });
|
|
19
|
+
|
|
20
|
+
expect(output.archivePath).toBe("archive/search.tar");
|
|
21
|
+
expect(output.digest).toMatch(/^sha256:/);
|
|
22
|
+
expect(mock.calls.map((c) => c.method)).toEqual(["build", "save"]);
|
|
23
|
+
const buildCall = mock.calls.find((c) => c.method === "build")!;
|
|
24
|
+
expect(buildCall.args).toMatchObject({ context: "." });
|
|
25
|
+
const saveCall = mock.calls.find((c) => c.method === "save")!;
|
|
26
|
+
expect(saveCall.args).toMatchObject({ outFile: "archive/search.tar" });
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("passes dockerfile/target/buildArgs through to the executor", async () => {
|
|
30
|
+
const mock = createMockCloudExecutor();
|
|
31
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
32
|
+
|
|
33
|
+
await capability.run(ctx, {
|
|
34
|
+
context: ".",
|
|
35
|
+
dockerfile: "Dockerfile.prod",
|
|
36
|
+
target: "release",
|
|
37
|
+
buildArgs: { NODE_ENV: "production" },
|
|
38
|
+
into: "archive/x.tar",
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const buildCall = mock.calls.find((c) => c.method === "build")!;
|
|
42
|
+
expect(buildCall.args).toMatchObject({
|
|
43
|
+
dockerfile: "Dockerfile.prod",
|
|
44
|
+
target: "release",
|
|
45
|
+
buildArgs: { NODE_ENV: "production" },
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("surfaces a docker build failure as a rejected promise (never swallowed)", async () => {
|
|
50
|
+
const mock = createMockCloudExecutor({ failDocker: true });
|
|
51
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
52
|
+
await expect(capability.run(ctx, { context: ".", into: "archive/x.tar" })).rejects.toThrow(/docker build failed/);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("declares no rollback — a local build has no remote/mutable state to compensate", () => {
|
|
56
|
+
const capability = createDockerBuildCapability(createMockCloudExecutor().executor);
|
|
57
|
+
expect(capability.rollback).toBeUndefined();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe("docker-build -> BuildArchive manifest (#564)", () => {
|
|
62
|
+
it("records the built image as a manifest entry, content-addressed by its digest", async () => {
|
|
63
|
+
const mock = createMockCloudExecutor();
|
|
64
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
65
|
+
|
|
66
|
+
const output = await capability.run(ctx, { context: ".", into: "archive/search.tar" });
|
|
67
|
+
|
|
68
|
+
expect(output.manifest.component).toBe("search-service");
|
|
69
|
+
const entry = findArchiveEntry(output.manifest, "archive/search.tar");
|
|
70
|
+
expect(entry).toMatchObject({ kind: "image", digest: output.digest });
|
|
71
|
+
expect(output.manifest.manifestDigest).toMatch(/^sha256:/);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("accumulates onto a manifest threaded through from a prior build/template step", async () => {
|
|
75
|
+
const mock = createMockCloudExecutor();
|
|
76
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
77
|
+
|
|
78
|
+
const { manifest: templateManifest } = addArchiveTemplate({
|
|
79
|
+
path: "search.template.json",
|
|
80
|
+
content: JSON.stringify({ Resources: {} }),
|
|
81
|
+
});
|
|
82
|
+
const output = await capability.run(ctx, {
|
|
83
|
+
context: ".",
|
|
84
|
+
into: "archive/search.tar",
|
|
85
|
+
manifest: templateManifest,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
expect(output.manifest.contents.map((e) => e.kind).sort()).toEqual(["image", "template"]);
|
|
89
|
+
expect(output.manifest.contents).toHaveLength(2);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("two builds from identical inputs produce the same manifest digest (content-addressed, not build-order-addressed)", async () => {
|
|
93
|
+
const mockA = createMockCloudExecutor();
|
|
94
|
+
const mockB = createMockCloudExecutor();
|
|
95
|
+
const outputA = await createDockerBuildCapability(mockA.executor).run(ctx, {
|
|
96
|
+
context: ".",
|
|
97
|
+
into: "archive/search.tar",
|
|
98
|
+
});
|
|
99
|
+
const outputB = await createDockerBuildCapability(mockB.executor).run(ctx, {
|
|
100
|
+
context: ".",
|
|
101
|
+
into: "archive/search.tar",
|
|
102
|
+
});
|
|
103
|
+
expect(outputA.digest).toBe(outputB.digest);
|
|
104
|
+
expect(outputA.manifest.manifestDigest).toBe(outputB.manifest.manifestDigest);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("defaults to best-effort reproducibility, per #614 — an externally-built image, not chant's own synthesis", async () => {
|
|
108
|
+
const mock = createMockCloudExecutor();
|
|
109
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
110
|
+
const output = await capability.run(ctx, { context: ".", into: "archive/search.tar" });
|
|
111
|
+
expect(findArchiveEntry(output.manifest, "archive/search.tar")!.reproducibility).toEqual({ basis: "best-effort" });
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("records a provenance link when sourceRef is given (#614)", async () => {
|
|
115
|
+
const mock = createMockCloudExecutor();
|
|
116
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
117
|
+
const output = await capability.run(ctx, { context: ".", into: "archive/search.tar", sourceRef: "deadbeef" });
|
|
118
|
+
expect(findArchiveEntry(output.manifest, "archive/search.tar")!.provenance).toEqual({
|
|
119
|
+
sourceRef: "deadbeef",
|
|
120
|
+
artifactDigest: output.digest,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("records no provenance link when sourceRef is omitted", async () => {
|
|
125
|
+
const mock = createMockCloudExecutor();
|
|
126
|
+
const capability = createDockerBuildCapability(mock.executor);
|
|
127
|
+
const output = await capability.run(ctx, { context: ".", into: "archive/search.tar" });
|
|
128
|
+
expect(findArchiveEntry(output.manifest, "archive/search.tar")!.provenance).toBeUndefined();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
describe("addArchiveTemplate (#564)", () => {
|
|
133
|
+
it("adds a template entry whose digest depends only on content", () => {
|
|
134
|
+
const a = addArchiveTemplate({ path: "x.template.json", content: '{"a":1}' });
|
|
135
|
+
const b = addArchiveTemplate({ path: "x.template.json", content: '{"a":1}' });
|
|
136
|
+
const c = addArchiveTemplate({ path: "x.template.json", content: '{"a":2}' });
|
|
137
|
+
|
|
138
|
+
expect(a.digest).toBe(b.digest);
|
|
139
|
+
expect(a.digest).not.toBe(c.digest);
|
|
140
|
+
expect(findArchiveEntry(a.manifest, "x.template.json")).toMatchObject({ kind: "template", digest: a.digest });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("defaults to deterministic-synthesis reproducibility, per #614", () => {
|
|
144
|
+
const { manifest } = addArchiveTemplate({ path: "x.template.json", content: '{"a":1}' });
|
|
145
|
+
expect(findArchiveEntry(manifest, "x.template.json")!.reproducibility).toEqual({
|
|
146
|
+
basis: "deterministic-synthesis",
|
|
147
|
+
verifyBy: "re-synth",
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("records a provenance link when sourceRef is given (#614)", () => {
|
|
152
|
+
const { manifest, digest } = addArchiveTemplate({
|
|
153
|
+
path: "x.template.json",
|
|
154
|
+
content: '{"a":1}',
|
|
155
|
+
sourceRef: "abc123def",
|
|
156
|
+
});
|
|
157
|
+
expect(findArchiveEntry(manifest, "x.template.json")!.provenance).toEqual({
|
|
158
|
+
sourceRef: "abc123def",
|
|
159
|
+
artifactDigest: digest,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("records no provenance link when sourceRef is omitted", () => {
|
|
164
|
+
const { manifest } = addArchiveTemplate({ path: "x.template.json", content: '{"a":1}' });
|
|
165
|
+
expect(findArchiveEntry(manifest, "x.template.json")!.provenance).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe("zip-package (#557)", () => {
|
|
170
|
+
it("zips the source into the archive path and returns the content digest", async () => {
|
|
171
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-zip-"));
|
|
172
|
+
const into = join(dir, "lambda.zip");
|
|
173
|
+
writeFileSync(into, "ZIP-BYTES"); // mock runner won't actually zip; pre-create so the digest read works
|
|
174
|
+
const expected = `sha256:${createHash("sha256").update("ZIP-BYTES").digest("hex")}`;
|
|
175
|
+
const mock = createMockProcessRunner();
|
|
176
|
+
|
|
177
|
+
const out = await createZipPackageCapability(mock.runner).run(
|
|
178
|
+
{ env: "dev", component: "fn" },
|
|
179
|
+
{ source: "src", into, exclude: ["*.test.js"] },
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
expect(out).toEqual({ archivePath: into, digest: expected });
|
|
183
|
+
const cmd = mock.calls.at(-1)!.command;
|
|
184
|
+
expect(cmd).toContain(`rm -f '${into}'`); // rebuilt from scratch, not appended
|
|
185
|
+
expect(cmd).toContain(`zip -r -X '${into}' 'src'`);
|
|
186
|
+
expect(cmd).toContain(`-x '*.test.js'`);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("declares no rollback — a local build produces no remote state to compensate", () => {
|
|
190
|
+
expect(createZipPackageCapability(createMockProcessRunner().runner).rollback).toBeUndefined();
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
describe("jvm-build (#557)", () => {
|
|
195
|
+
it("runs mvn package, copies the produced jar into the archive path, and returns its digest", async () => {
|
|
196
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-jvm-"));
|
|
197
|
+
const into = join(dir, "app.jar");
|
|
198
|
+
writeFileSync(into, "JAR-BYTES"); // mock runner won't actually build; pre-create so the digest read works
|
|
199
|
+
const expected = `sha256:${createHash("sha256").update("JAR-BYTES").digest("hex")}`;
|
|
200
|
+
const mock = createMockProcessRunner();
|
|
201
|
+
|
|
202
|
+
const out = await createJvmBuildCapability(mock.runner).run(
|
|
203
|
+
{ env: "dev", component: "jar-lib" },
|
|
204
|
+
{ tool: "maven", path: "svc", into },
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
expect(out).toEqual({ archivePath: into, digest: expected });
|
|
208
|
+
expect(mock.calls[0]!.command).toContain(`mvn -q -B -f 'svc/pom.xml' package`);
|
|
209
|
+
expect(mock.calls[1]!.command).toContain(`ls 'svc/target'/*.jar`);
|
|
210
|
+
expect(mock.calls[1]!.command).toContain("-sources"); // skips sources/javadoc classifier jars
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
it("uses the gradle wrapper when tool is gradle", async () => {
|
|
214
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-jvm-"));
|
|
215
|
+
const into = join(dir, "app.jar");
|
|
216
|
+
writeFileSync(into, "X");
|
|
217
|
+
const mock = createMockProcessRunner();
|
|
218
|
+
await createJvmBuildCapability(mock.runner).run({ env: "dev", component: "lib" }, { tool: "gradle", path: "svc", into });
|
|
219
|
+
expect(mock.calls[0]!.command).toContain("./gradlew -q build");
|
|
220
|
+
expect(mock.calls[1]!.command).toContain("build/libs/*.jar");
|
|
221
|
+
});
|
|
222
|
+
});
|