@intentius/chant 0.13.0 → 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/fetch.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/fetch.test.ts +112 -8
- package/src/audit/fetch.ts +53 -8
- 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
|
@@ -11,6 +11,12 @@ import {
|
|
|
11
11
|
getHeadCommit,
|
|
12
12
|
pushLifecycle,
|
|
13
13
|
StaleLifecycleBranchError,
|
|
14
|
+
appendReleaseRecordLine,
|
|
15
|
+
readReleaseLedgerLines,
|
|
16
|
+
listLedgerEnvironments,
|
|
17
|
+
writeBlobToPath,
|
|
18
|
+
readBlobFromPath,
|
|
19
|
+
listFilesInDir,
|
|
14
20
|
} from "./git";
|
|
15
21
|
|
|
16
22
|
function git(args: string[], cwd: string): { stdout: string; exitCode: number } {
|
|
@@ -83,6 +89,57 @@ describe("lifecycle/git", () => {
|
|
|
83
89
|
});
|
|
84
90
|
});
|
|
85
91
|
|
|
92
|
+
// ── Generic blob helpers used by ./build-ledger-store.ts (#609) ────────────
|
|
93
|
+
|
|
94
|
+
describe("writeBlobToPath / readBlobFromPath / listFilesInDir (generic, non-env namespaces)", () => {
|
|
95
|
+
test("writes/reads a blob under an arbitrary top-level directory, not just an env", async () => {
|
|
96
|
+
await withTestDir(async (dir) => {
|
|
97
|
+
await initRepo(dir);
|
|
98
|
+
const sha = await writeBlobToPath("_builds", "sha256_abc.json", '{"a":1}', "Build manifest", { cwd: dir });
|
|
99
|
+
expect(sha).toMatch(/^[0-9a-f]{40}$/);
|
|
100
|
+
|
|
101
|
+
const out = await readBlobFromPath("_builds", "sha256_abc.json", { cwd: dir });
|
|
102
|
+
expect(JSON.parse(out!)).toEqual({ a: 1 });
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("readBlobFromPath returns null for a missing directory/file", async () => {
|
|
107
|
+
await withTestDir(async (dir) => {
|
|
108
|
+
await initRepo(dir);
|
|
109
|
+
expect(await readBlobFromPath("_builds", "missing.json", { cwd: dir })).toBeNull();
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("listFilesInDir lists every file directly under a directory", async () => {
|
|
114
|
+
await withTestDir(async (dir) => {
|
|
115
|
+
await initRepo(dir);
|
|
116
|
+
await writeBlobToPath("_builds", "a.json", "{}", "m", { cwd: dir });
|
|
117
|
+
await writeBlobToPath("_builds", "b.json", "{}", "m", { cwd: dir });
|
|
118
|
+
const files = await listFilesInDir("_builds", { cwd: dir });
|
|
119
|
+
expect(files.sort()).toEqual(["a.json", "b.json"]);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
test("listFilesInDir returns empty for a directory that doesn't exist yet", async () => {
|
|
124
|
+
await withTestDir(async (dir) => {
|
|
125
|
+
await initRepo(dir);
|
|
126
|
+
expect(await listFilesInDir("_builds", { cwd: dir })).toEqual([]);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("a non-env top-level directory (_builds) coexists with per-env snapshot/release directories", async () => {
|
|
131
|
+
await withTestDir(async (dir) => {
|
|
132
|
+
await initRepo(dir);
|
|
133
|
+
await writeSnapshot("prod", "aws", JSON.stringify({ a: 1 }), { cwd: dir });
|
|
134
|
+
await writeBlobToPath("_builds", "sha256_abc.json", '{"b":2}', "Build manifest", { cwd: dir });
|
|
135
|
+
|
|
136
|
+
expect(await readSnapshot("prod", "aws", { cwd: dir })).toBeTruthy();
|
|
137
|
+
const out = await readBlobFromPath("_builds", "sha256_abc.json", { cwd: dir });
|
|
138
|
+
expect(JSON.parse(out!)).toEqual({ b: 2 });
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
86
143
|
test("listSnapshots returns commit history of the orphan branch", async () => {
|
|
87
144
|
await withTestDir(async (dir) => {
|
|
88
145
|
await initRepo(dir);
|
|
@@ -188,4 +245,65 @@ describe("lifecycle/git", () => {
|
|
|
188
245
|
expect(err.expected).toBeNull();
|
|
189
246
|
expect(err.message).toContain("moved");
|
|
190
247
|
});
|
|
248
|
+
|
|
249
|
+
// ── Release ledger plumbing (#568) ──────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
describe("release ledger plumbing", () => {
|
|
252
|
+
test("appendReleaseRecordLine creates the orphan branch and is readable via readReleaseLedgerLines", async () => {
|
|
253
|
+
await withTestDir(async (dir) => {
|
|
254
|
+
await initRepo(dir);
|
|
255
|
+
const sha = await appendReleaseRecordLine("prod", '{"v":1}', { cwd: dir });
|
|
256
|
+
expect(sha).toMatch(/^[0-9a-f]{40}$/);
|
|
257
|
+
const lines = await readReleaseLedgerLines("prod", { cwd: dir });
|
|
258
|
+
expect(lines).toEqual(['{"v":1}']);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
test("readReleaseLedgerLines returns [] for an environment with no ledger", async () => {
|
|
263
|
+
await withTestDir(async (dir) => {
|
|
264
|
+
await initRepo(dir);
|
|
265
|
+
expect(await readReleaseLedgerLines("prod", { cwd: dir })).toEqual([]);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
test("appendReleaseRecordLine appends rather than overwrites", async () => {
|
|
270
|
+
await withTestDir(async (dir) => {
|
|
271
|
+
await initRepo(dir);
|
|
272
|
+
await appendReleaseRecordLine("prod", '{"v":1}', { cwd: dir });
|
|
273
|
+
await appendReleaseRecordLine("prod", '{"v":2}', { cwd: dir });
|
|
274
|
+
await appendReleaseRecordLine("prod", '{"v":3}', { cwd: dir });
|
|
275
|
+
expect(await readReleaseLedgerLines("prod", { cwd: dir })).toEqual(['{"v":1}', '{"v":2}', '{"v":3}']);
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
test("release ledger and snapshot files coexist under the same env directory", async () => {
|
|
280
|
+
await withTestDir(async (dir) => {
|
|
281
|
+
await initRepo(dir);
|
|
282
|
+
await writeSnapshot("prod", "aws", JSON.stringify({ a: 1 }), { cwd: dir });
|
|
283
|
+
await appendReleaseRecordLine("prod", '{"v":1}', { cwd: dir });
|
|
284
|
+
// Both must survive — the release ledger uses a different filename
|
|
285
|
+
// ("releases.jsonl") than any lexicon snapshot ("<lexicon>.json").
|
|
286
|
+
expect(await readSnapshot("prod", "aws", { cwd: dir })).toBeTruthy();
|
|
287
|
+
expect(await readReleaseLedgerLines("prod", { cwd: dir })).toEqual(['{"v":1}']);
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
test("listLedgerEnvironments finds every env with a release ledger, ignoring envs that only have snapshots", async () => {
|
|
292
|
+
await withTestDir(async (dir) => {
|
|
293
|
+
await initRepo(dir);
|
|
294
|
+
await writeSnapshot("dev", "aws", JSON.stringify({ a: 1 }), { cwd: dir }); // snapshot only, no ledger
|
|
295
|
+
await appendReleaseRecordLine("staging", '{"v":1}', { cwd: dir });
|
|
296
|
+
await appendReleaseRecordLine("prod", '{"v":1}', { cwd: dir });
|
|
297
|
+
|
|
298
|
+
expect(await listLedgerEnvironments({ cwd: dir })).toEqual(["prod", "staging"]);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
test("listLedgerEnvironments returns [] when the orphan branch doesn't exist yet", async () => {
|
|
303
|
+
await withTestDir(async (dir) => {
|
|
304
|
+
await initRepo(dir);
|
|
305
|
+
expect(await listLedgerEnvironments({ cwd: dir })).toEqual([]);
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
});
|
|
191
309
|
});
|
package/src/lifecycle/git.ts
CHANGED
|
@@ -9,14 +9,31 @@ import { getRuntime } from "../runtime-adapter";
|
|
|
9
9
|
const STATE_BRANCH = "chant/lifecycle";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Write a
|
|
12
|
+
* Write a blob to an arbitrary `<environment>/<filename>` path on the orphan
|
|
13
|
+
* branch, preserving every other env/file entry already on the branch.
|
|
13
14
|
*
|
|
14
|
-
* Pipeline: hash-object → mktree → commit-tree → update-ref
|
|
15
|
+
* Pipeline: hash-object → mktree → commit-tree → update-ref. Factored out of
|
|
16
|
+
* `writeSnapshot` so the release ledger (#568, epic #551 "Build & deploy
|
|
17
|
+
* observability") can reuse the identical git-plumbing path for a different
|
|
18
|
+
* filename (`releases.jsonl`) under the same env directory, rather than a
|
|
19
|
+
* parallel storage mechanism.
|
|
20
|
+
*
|
|
21
|
+
* Exported (not just used internally) so ./build-ledger-store.ts (#609) can
|
|
22
|
+
* reuse this exact plumbing for a top-level directory that isn't really an
|
|
23
|
+
* "environment" (`_builds`, keyed by manifest digest rather than env name) —
|
|
24
|
+
* a build archive is promoted by digest across environments, never owned by
|
|
25
|
+
* one, so it belongs in its own digest-keyed namespace on the same orphan
|
|
26
|
+
* branch rather than duplicated per env. The parameter is still named
|
|
27
|
+
* `environment` because it is literally the first path segment / root-tree
|
|
28
|
+
* entry name this function's tree-building logic groups by; callers outside
|
|
29
|
+
* this module that pass a non-env value (like `_builds`) are relying on that
|
|
30
|
+
* generic behavior, not on any env-specific semantics.
|
|
15
31
|
*/
|
|
16
|
-
export async function
|
|
32
|
+
export async function writeBlobToPath(
|
|
17
33
|
environment: string,
|
|
18
|
-
|
|
19
|
-
|
|
34
|
+
filename: string,
|
|
35
|
+
content: string,
|
|
36
|
+
commitMessage: string,
|
|
20
37
|
opts?: { cwd?: string },
|
|
21
38
|
): Promise<string> {
|
|
22
39
|
const rt = getRuntime();
|
|
@@ -25,7 +42,7 @@ export async function writeSnapshot(
|
|
|
25
42
|
// 1. Write blob — hash-object reads from stdin, but spawn() doesn't expose
|
|
26
43
|
// a stdin handle, so we run via a shell pipeline (`echo … | git hash-object`).
|
|
27
44
|
const blobResult = await rt.spawn(
|
|
28
|
-
["sh", "-c", `echo '${
|
|
45
|
+
["sh", "-c", `echo '${content.replace(/'/g, "'\\''")}' | git hash-object -w --stdin`],
|
|
29
46
|
{ cwd },
|
|
30
47
|
);
|
|
31
48
|
if (blobResult.exitCode !== 0) {
|
|
@@ -33,13 +50,12 @@ export async function writeSnapshot(
|
|
|
33
50
|
}
|
|
34
51
|
const blobSha = blobResult.stdout.trim();
|
|
35
52
|
|
|
36
|
-
// 2. Read existing tree (if branch exists) to preserve other env/
|
|
53
|
+
// 2. Read existing tree (if branch exists) to preserve other env/file entries
|
|
37
54
|
const existingTree = await readTree(cwd);
|
|
38
55
|
|
|
39
56
|
// 3. Build new tree entries
|
|
40
|
-
const path = `${environment}/${
|
|
57
|
+
const path = `${environment}/${filename}`;
|
|
41
58
|
const entries = mergeTreeEntry(existingTree, path, blobSha);
|
|
42
|
-
const treeInput = entries.map((e) => `${e.mode} ${e.type} ${e.sha}\t${e.name}`).join("\n");
|
|
43
59
|
|
|
44
60
|
// mktree needs a nested tree structure. Build env subtree first, then root tree.
|
|
45
61
|
// Build env subtree
|
|
@@ -84,7 +100,7 @@ export async function writeSnapshot(
|
|
|
84
100
|
const parentRef = await getStateBranchTip(cwd);
|
|
85
101
|
const parentArgs = parentRef ? ["-p", parentRef] : [];
|
|
86
102
|
const commitResult = await rt.spawn(
|
|
87
|
-
["git", "commit-tree", ...parentArgs, "-m",
|
|
103
|
+
["git", "commit-tree", ...parentArgs, "-m", commitMessage, rootTreeSha],
|
|
88
104
|
{ cwd },
|
|
89
105
|
);
|
|
90
106
|
if (commitResult.exitCode !== 0) {
|
|
@@ -105,22 +121,141 @@ export async function writeSnapshot(
|
|
|
105
121
|
}
|
|
106
122
|
|
|
107
123
|
/**
|
|
108
|
-
* Read a
|
|
124
|
+
* Read a blob from an arbitrary `<environment>/<filename>` path on the orphan
|
|
125
|
+
* branch. Returns null when the path doesn't exist (missing branch, env, or
|
|
126
|
+
* file). Sibling of `writeBlobToPath`. Exported for the same reason
|
|
127
|
+
* `writeBlobToPath` is — ./build-ledger-store.ts (#609) reads manifests back
|
|
128
|
+
* from the `_builds` namespace through this identical helper.
|
|
109
129
|
*/
|
|
110
|
-
export async function
|
|
130
|
+
export async function readBlobFromPath(
|
|
111
131
|
environment: string,
|
|
112
|
-
|
|
132
|
+
filename: string,
|
|
113
133
|
opts?: { cwd?: string },
|
|
114
134
|
): Promise<string | null> {
|
|
115
135
|
const rt = getRuntime();
|
|
116
136
|
const result = await rt.spawn(
|
|
117
|
-
["git", "show", `${STATE_BRANCH}:${environment}/${
|
|
137
|
+
["git", "show", `${STATE_BRANCH}:${environment}/${filename}`],
|
|
118
138
|
{ cwd: opts?.cwd },
|
|
119
139
|
);
|
|
120
140
|
if (result.exitCode !== 0) return null;
|
|
121
141
|
return result.stdout;
|
|
122
142
|
}
|
|
123
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Write a state snapshot JSON to the orphan branch.
|
|
146
|
+
*
|
|
147
|
+
* Pipeline: hash-object → mktree → commit-tree → update-ref
|
|
148
|
+
*/
|
|
149
|
+
export async function writeSnapshot(
|
|
150
|
+
environment: string,
|
|
151
|
+
lexicon: string,
|
|
152
|
+
json: string,
|
|
153
|
+
opts?: { cwd?: string },
|
|
154
|
+
): Promise<string> {
|
|
155
|
+
return writeBlobToPath(environment, `${lexicon}.json`, json, "State snapshot", opts);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Read a snapshot from the orphan branch.
|
|
160
|
+
*/
|
|
161
|
+
export async function readSnapshot(
|
|
162
|
+
environment: string,
|
|
163
|
+
lexicon: string,
|
|
164
|
+
opts?: { cwd?: string },
|
|
165
|
+
): Promise<string | null> {
|
|
166
|
+
return readBlobFromPath(environment, `${lexicon}.json`, opts);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Append one immutable release record line to `<environment>/releases.jsonl`
|
|
171
|
+
* on the orphan branch (#568, epic #551 "Build & deploy observability"). Same
|
|
172
|
+
* git-plumbing path `writeSnapshot` uses, just a different filename under the
|
|
173
|
+
* env directory and append-only (JSON Lines) instead of replace-whole-file:
|
|
174
|
+
* each deploy adds one line, never rewrites a previous one, so the ledger
|
|
175
|
+
* stays a durable, append-only history rather than a point-in-time snapshot.
|
|
176
|
+
*
|
|
177
|
+
* Low-level plumbing over an already-serialized line; ../release-ledger.ts's
|
|
178
|
+
* `appendReleaseRecord` is the typed, validated public API most callers want
|
|
179
|
+
* — named distinctly here (`ReleaseRecordLine`) to avoid re-export ambiguity
|
|
180
|
+
* between the two modules.
|
|
181
|
+
*
|
|
182
|
+
* Returns the new orphan-branch commit SHA — the caller still owns pushing
|
|
183
|
+
* via `pushLifecycle` under the same concurrent-write lease `writeSnapshot`
|
|
184
|
+
* uses.
|
|
185
|
+
*/
|
|
186
|
+
export async function appendReleaseRecordLine(
|
|
187
|
+
environment: string,
|
|
188
|
+
recordJson: string,
|
|
189
|
+
opts?: { cwd?: string },
|
|
190
|
+
): Promise<string> {
|
|
191
|
+
const filename = "releases.jsonl";
|
|
192
|
+
const existing = await readBlobFromPath(environment, filename, opts);
|
|
193
|
+
const content = existing ? `${existing.replace(/\n$/, "")}\n${recordJson}` : recordJson;
|
|
194
|
+
return writeBlobToPath(environment, filename, content, "Release record", opts);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Read every release record line for `environment` from the orphan branch,
|
|
199
|
+
* oldest first, as raw JSON strings. Returns `[]` when no ledger exists yet
|
|
200
|
+
* for that env (never throws — a component that has never recorded a deploy
|
|
201
|
+
* is a normal, expected state). ../release-ledger.ts's `readReleaseLedger`
|
|
202
|
+
* parses/validates these lines into typed `ReleaseRecord`s.
|
|
203
|
+
*/
|
|
204
|
+
export async function readReleaseLedgerLines(
|
|
205
|
+
environment: string,
|
|
206
|
+
opts?: { cwd?: string },
|
|
207
|
+
): Promise<string[]> {
|
|
208
|
+
const content = await readBlobFromPath(environment, "releases.jsonl", opts);
|
|
209
|
+
if (!content) return [];
|
|
210
|
+
return content.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* List every environment that has a release ledger on the orphan branch —
|
|
215
|
+
* the root-level directories under `chant/lifecycle` that carry a
|
|
216
|
+
* `releases.jsonl` entry. Used by `chant components status` (no env arg) to
|
|
217
|
+
* discover which environments to report on.
|
|
218
|
+
*/
|
|
219
|
+
export async function listLedgerEnvironments(opts?: { cwd?: string }): Promise<string[]> {
|
|
220
|
+
const tip = await getStateBranchTip(opts?.cwd);
|
|
221
|
+
if (!tip) return [];
|
|
222
|
+
const rt = getRuntime();
|
|
223
|
+
const rootResult = await rt.spawn(["git", "ls-tree", STATE_BRANCH], { cwd: opts?.cwd });
|
|
224
|
+
if (rootResult.exitCode !== 0) return [];
|
|
225
|
+
|
|
226
|
+
const envs: string[] = [];
|
|
227
|
+
const lines = rootResult.stdout.trim().split("\n").filter(Boolean);
|
|
228
|
+
for (const line of lines) {
|
|
229
|
+
const match = line.match(/^(\d+)\s+(\w+)\s+([0-9a-f]+)\t(.+)$/);
|
|
230
|
+
if (!match) continue;
|
|
231
|
+
const [, , type, , name] = match;
|
|
232
|
+
if (type !== "tree") continue;
|
|
233
|
+
const hasLedger = await readBlobFromPath(name, "releases.jsonl", opts);
|
|
234
|
+
if (hasLedger) envs.push(name);
|
|
235
|
+
}
|
|
236
|
+
return envs.sort();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* List every filename directly under `<dir>/` on the orphan branch (no
|
|
241
|
+
* recursion), or `[]` when the branch/directory doesn't exist yet. Generic
|
|
242
|
+
* sibling of `readEnvironmentSnapshots`'s inline file listing, factored out
|
|
243
|
+
* so ./build-ledger-store.ts (#609) can enumerate every persisted build
|
|
244
|
+
* manifest (`_builds/<digest>.json`) without duplicating this `git ls-tree
|
|
245
|
+
* --name-only` call.
|
|
246
|
+
*/
|
|
247
|
+
export async function listFilesInDir(dir: string, opts?: { cwd?: string }): Promise<string[]> {
|
|
248
|
+
const tip = await getStateBranchTip(opts?.cwd);
|
|
249
|
+
if (!tip) return [];
|
|
250
|
+
const rt = getRuntime();
|
|
251
|
+
const lsResult = await rt.spawn(
|
|
252
|
+
["git", "ls-tree", "--name-only", `${STATE_BRANCH}:${dir}/`],
|
|
253
|
+
{ cwd: opts?.cwd },
|
|
254
|
+
);
|
|
255
|
+
if (lsResult.exitCode !== 0) return [];
|
|
256
|
+
return lsResult.stdout.trim().split("\n").filter(Boolean);
|
|
257
|
+
}
|
|
258
|
+
|
|
124
259
|
/**
|
|
125
260
|
* Read all snapshots for an environment (all lexicons).
|
|
126
261
|
*/
|
package/src/lifecycle/index.ts
CHANGED
|
@@ -5,3 +5,8 @@ export * from "./snapshot";
|
|
|
5
5
|
export * from "./live-diff";
|
|
6
6
|
export * from "./change-set";
|
|
7
7
|
export * from "./affected";
|
|
8
|
+
export * from "./release-ledger";
|
|
9
|
+
export * from "./build-ledger";
|
|
10
|
+
export * from "./build-ledger-store";
|
|
11
|
+
export * from "./oras-referrer-lookup";
|
|
12
|
+
export * from "./status";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests the real `ReferrerLookup` backend (#610, ./oras-referrer-lookup.ts)
|
|
3
|
+
* against a `MockProcessRunner`
|
|
4
|
+
* (../components/verbs/__tests__/mock-process-runner.ts) — no live `oras`,
|
|
5
|
+
* no live registry. Asserts the `oras discover` command constructed, that
|
|
6
|
+
* its JSON output is parsed and classified into `Referrer[]`, and that a
|
|
7
|
+
* missing `oras` binary surfaces `ToolNotAvailableError`.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it } from "vitest";
|
|
11
|
+
import { createOrasReferrerLookup } from "./oras-referrer-lookup";
|
|
12
|
+
import { ToolNotAvailableError } from "../components/verbs/process-runner";
|
|
13
|
+
import { createMockProcessRunner } from "../components/verbs/__tests__/mock-process-runner";
|
|
14
|
+
|
|
15
|
+
const REPO = "123.dkr.ecr.us-east-1.amazonaws.com/search";
|
|
16
|
+
const DIGEST = "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
|
|
17
|
+
|
|
18
|
+
function orasOutput(manifests: Array<{ digest: string; mediaType: string; artifactType?: string }>): string {
|
|
19
|
+
return JSON.stringify({ manifests });
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
describe("createOrasReferrerLookup (#610)", () => {
|
|
23
|
+
it("constructs the oras discover command against repo@digest", async () => {
|
|
24
|
+
const mock = createMockProcessRunner({ responses: { "oras discover": orasOutput([]) } });
|
|
25
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
26
|
+
|
|
27
|
+
await lookup.discover(DIGEST);
|
|
28
|
+
|
|
29
|
+
const call = mock.calls.find((c) => c.command.startsWith("oras discover"))!;
|
|
30
|
+
expect(call.command).toBe(`oras discover --format json '${REPO}@${DIGEST}'`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("classifies an spdx/cyclonedx manifest as an sbom referrer", async () => {
|
|
34
|
+
const mock = createMockProcessRunner({
|
|
35
|
+
responses: {
|
|
36
|
+
"oras discover": orasOutput([
|
|
37
|
+
{ digest: "sha256:sbom1", mediaType: "application/vnd.oci.image.manifest.v1+json", artifactType: "application/spdx+json" },
|
|
38
|
+
]),
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
42
|
+
|
|
43
|
+
const referrers = await lookup.discover(DIGEST);
|
|
44
|
+
|
|
45
|
+
expect(referrers).toEqual([
|
|
46
|
+
{ kind: "sbom", mediaType: "application/spdx+json", digest: "sha256:sbom1", location: `${REPO}@sha256:sbom1` },
|
|
47
|
+
]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("classifies an in-toto/slsa manifest as a provenance referrer", async () => {
|
|
51
|
+
const mock = createMockProcessRunner({
|
|
52
|
+
responses: {
|
|
53
|
+
"oras discover": orasOutput([
|
|
54
|
+
{ digest: "sha256:prov1", mediaType: "application/vnd.oci.image.manifest.v1+json", artifactType: "application/vnd.in-toto+json" },
|
|
55
|
+
]),
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
59
|
+
|
|
60
|
+
const referrers = await lookup.discover(DIGEST);
|
|
61
|
+
expect(referrers[0]?.kind).toBe("provenance");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("classifies a cosign signature manifest as a signature referrer", async () => {
|
|
65
|
+
const mock = createMockProcessRunner({
|
|
66
|
+
responses: {
|
|
67
|
+
"oras discover": orasOutput([
|
|
68
|
+
{ digest: "sha256:sig1", mediaType: "application/vnd.dev.cosign.simplesigning.v1+json", artifactType: "application/vnd.dev.cosign.signature" },
|
|
69
|
+
]),
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
73
|
+
|
|
74
|
+
const referrers = await lookup.discover(DIGEST);
|
|
75
|
+
expect(referrers[0]?.kind).toBe("signature");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("skips a manifest of an unrecognized artifact type rather than guessing", async () => {
|
|
79
|
+
const mock = createMockProcessRunner({
|
|
80
|
+
responses: {
|
|
81
|
+
"oras discover": orasOutput([
|
|
82
|
+
{ digest: "sha256:unknown1", mediaType: "application/vnd.acme.something+json", artifactType: "application/vnd.acme.something+json" },
|
|
83
|
+
]),
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
87
|
+
|
|
88
|
+
expect(await lookup.discover(DIGEST)).toEqual([]);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("returns [] when oras reports no manifests", async () => {
|
|
92
|
+
const mock = createMockProcessRunner({ responses: { "oras discover": orasOutput([]) } });
|
|
93
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
94
|
+
expect(await lookup.discover(DIGEST)).toEqual([]);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("returns [] rather than throwing on unparseable oras output", async () => {
|
|
98
|
+
const mock = createMockProcessRunner({ responses: { "oras discover": "not json" } });
|
|
99
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
100
|
+
expect(await lookup.discover(DIGEST)).toEqual([]);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("throws ToolNotAvailableError when oras is not installed", async () => {
|
|
104
|
+
const mock = createMockProcessRunner({ tools: { oras: false } });
|
|
105
|
+
const lookup = createOrasReferrerLookup({ repo: REPO, runner: mock.runner });
|
|
106
|
+
await expect(lookup.discover(DIGEST)).rejects.toThrow(ToolNotAvailableError);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("strips a trailing slash from repo before composing the reference", async () => {
|
|
110
|
+
const mock = createMockProcessRunner({ responses: { "oras discover": orasOutput([]) } });
|
|
111
|
+
const lookup = createOrasReferrerLookup({ repo: `${REPO}/`, runner: mock.runner });
|
|
112
|
+
await lookup.discover(DIGEST);
|
|
113
|
+
const call = mock.calls.find((c) => c.command.startsWith("oras discover"))!;
|
|
114
|
+
expect(call.command).toContain(`${REPO}@${DIGEST}`);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Real `ReferrerLookup` backend (#610, epic #551 follow-up to #568's
|
|
3
|
+
* `ReferrerLookup` interface). Shells out to `oras discover --format json
|
|
4
|
+
* <digest>` — the OCI distribution spec's referrers API, as exposed by the
|
|
5
|
+
* `oras` CLI — through the same injectable `ProcessRunner`
|
|
6
|
+
* (../components/verbs/process-runner.ts) the deep-scan `SbomGenerator`
|
|
7
|
+
* backend (../components/verbs/tool-sbom-generator.ts) and `publish-image`'s
|
|
8
|
+
* referrer-attach step share, mirroring ../components/verbs/cloud-executor.ts's
|
|
9
|
+
* `CloudExecutor` pattern once more: production code shells out, tests inject
|
|
10
|
+
* a `MockProcessRunner` and never touch a real registry/`oras` binary.
|
|
11
|
+
*
|
|
12
|
+
* Not the process-wide default: ./build-ledger.ts's `noopReferrerLookup`
|
|
13
|
+
* remains that (reports no referrers, no network, no registry credentials
|
|
14
|
+
* required) for exactly the reason `notImplementedSbomGenerator` and
|
|
15
|
+
* `SbomGenerator`'s hermetic backend aren't `sbom-generator.ts`'s default
|
|
16
|
+
* either — a project opts into the real registry-backed lookup explicitly
|
|
17
|
+
* (`buildLedgerEntries(manifest, createOrasReferrerLookup())`) rather than
|
|
18
|
+
* every previously-network-free build-ledger query silently starting to hit
|
|
19
|
+
* a registry.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import {
|
|
23
|
+
defaultProcessRunner,
|
|
24
|
+
q,
|
|
25
|
+
requireTool,
|
|
26
|
+
type ProcessRunner,
|
|
27
|
+
} from "../components/verbs/process-runner";
|
|
28
|
+
import type { Referrer, ReferrerKind, ReferrerLookup } from "./build-ledger";
|
|
29
|
+
|
|
30
|
+
/** Shape of one entry in `oras discover --format json`'s `manifests[]` array — the fields this module actually reads, not oras's full manifest descriptor. */
|
|
31
|
+
interface OrasManifestDescriptor {
|
|
32
|
+
digest: string;
|
|
33
|
+
mediaType: string;
|
|
34
|
+
/** oras nests the referrer's own artifact type here for a referrers-API-discovered entry. */
|
|
35
|
+
artifactType?: string;
|
|
36
|
+
annotations?: Record<string, string>;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Shape of `oras discover --format json <ref>`'s top-level output. */
|
|
40
|
+
interface OrasDiscoverOutput {
|
|
41
|
+
manifests?: OrasManifestDescriptor[];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Classify one oras-reported referrer manifest into a `ReferrerKind`, keyed
|
|
46
|
+
* off its `artifactType`/media type — the same three kinds
|
|
47
|
+
* ../components/verbs/build-ledger.ts's `Referrer.kind` already models
|
|
48
|
+
* (`sbom`, `provenance`, `signature`). An unrecognized artifact type is
|
|
49
|
+
* skipped (returns `undefined`) rather than guessed at, since a wrong
|
|
50
|
+
* classification (e.g. reporting a signature as an SBOM) would be worse than
|
|
51
|
+
* omitting it — the caller only ever sees referrers this module is confident
|
|
52
|
+
* about.
|
|
53
|
+
*/
|
|
54
|
+
function classify(descriptor: OrasManifestDescriptor): ReferrerKind | undefined {
|
|
55
|
+
const type = (descriptor.artifactType ?? descriptor.mediaType ?? "").toLowerCase();
|
|
56
|
+
if (type.includes("spdx") || type.includes("cyclonedx") || type.includes("sbom")) return "sbom";
|
|
57
|
+
if (type.includes("in-toto") || type.includes("provenance") || type.includes("slsa")) return "provenance";
|
|
58
|
+
if (type.includes("cosign") || type.includes("signature") || type.includes("sig.")) return "signature";
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface OrasReferrerLookupOptions {
|
|
63
|
+
/** Injected process boundary. Defaults to the real, `child_process`-backed runner. */
|
|
64
|
+
runner?: ProcessRunner;
|
|
65
|
+
/** Registry/repo prefix `digest` is resolved against (e.g. `123.dkr.ecr.us-east-1.amazonaws.com/search`) — `oras discover` needs a full `repo@digest` reference, not a bare digest. Required; a `ReferrerLookup.discover(digest)` call with no repo context has nothing to query. */
|
|
66
|
+
repo: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Build a real `ReferrerLookup` backed by `oras discover`. `discover(digest)`
|
|
71
|
+
* runs `oras discover --format json <repo>@<digest>` and maps every returned
|
|
72
|
+
* manifest into a `Referrer`, classified by `classify` above. Returns `[]`
|
|
73
|
+
* (never throws) when `oras` reports no referrers for a digest — an image
|
|
74
|
+
* with no attached SBOM/provenance/signature is a normal outcome, not an
|
|
75
|
+
* error. Throws `ToolNotAvailableError`
|
|
76
|
+
* (../components/verbs/process-runner.ts) if `oras` itself is not installed,
|
|
77
|
+
* so a misconfigured environment fails loudly rather than silently reporting
|
|
78
|
+
* "no referrers" for every digest.
|
|
79
|
+
*/
|
|
80
|
+
export function createOrasReferrerLookup(options: OrasReferrerLookupOptions): ReferrerLookup {
|
|
81
|
+
const runner = options.runner ?? defaultProcessRunner();
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
async discover(digest: string): Promise<Referrer[]> {
|
|
85
|
+
await requireTool(runner, "oras", `discover OCI referrers for ${options.repo}@${digest}`);
|
|
86
|
+
const ref = `${options.repo.replace(/\/+$/, "")}@${digest}`;
|
|
87
|
+
const { stdout } = await runner.run(`oras discover --format json ${q(ref)}`);
|
|
88
|
+
|
|
89
|
+
let parsed: OrasDiscoverOutput;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(stdout) as OrasDiscoverOutput;
|
|
92
|
+
} catch {
|
|
93
|
+
return []; // no referrers / unexpected output shape — degrade to "none known", never throw on a parse hiccup.
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const referrers: Referrer[] = [];
|
|
97
|
+
for (const descriptor of parsed.manifests ?? []) {
|
|
98
|
+
const kind = classify(descriptor);
|
|
99
|
+
if (!kind) continue;
|
|
100
|
+
referrers.push({
|
|
101
|
+
kind,
|
|
102
|
+
mediaType: descriptor.artifactType ?? descriptor.mediaType,
|
|
103
|
+
digest: descriptor.digest,
|
|
104
|
+
location: `${options.repo}@${descriptor.digest}`,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
return referrers;
|
|
108
|
+
},
|
|
109
|
+
};
|
|
110
|
+
}
|