@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
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component-native release orchestration — capability contract, starter verb
|
|
3
|
+
* set, and the thin interpret driver (epic #551, #554/#556). The pilot AWS
|
|
4
|
+
* leaves have real implementations over an injectable `CloudExecutor` (#557);
|
|
5
|
+
* every other verb remains a typed stub. See https://intentius.io/chant/components/orchestration/
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
type Archetype,
|
|
10
|
+
type Wiring,
|
|
11
|
+
type StackOutputReference,
|
|
12
|
+
type BuildSpec,
|
|
13
|
+
type Step,
|
|
14
|
+
type Gate,
|
|
15
|
+
type Phase,
|
|
16
|
+
type Component,
|
|
17
|
+
phase,
|
|
18
|
+
gate,
|
|
19
|
+
stackOutput,
|
|
20
|
+
inferArchetype,
|
|
21
|
+
projectToJson,
|
|
22
|
+
isComponent,
|
|
23
|
+
} from "./component";
|
|
24
|
+
export {
|
|
25
|
+
type DiscoveredComponent,
|
|
26
|
+
type ComponentDiscoveryResult,
|
|
27
|
+
discoverComponents,
|
|
28
|
+
} from "./discover";
|
|
29
|
+
export {
|
|
30
|
+
type ListedComponent,
|
|
31
|
+
type ListComponentsResult,
|
|
32
|
+
type DescribedComponent,
|
|
33
|
+
type DescribeComponentResult,
|
|
34
|
+
type ComponentGraphResult,
|
|
35
|
+
type GenerateLexicon,
|
|
36
|
+
type GenerateComponentsResult,
|
|
37
|
+
type RunComponentsOptions,
|
|
38
|
+
type RunComponentsResult,
|
|
39
|
+
type ResolvedComponentTargets,
|
|
40
|
+
listComponents,
|
|
41
|
+
describeComponent,
|
|
42
|
+
computeComponentGraph,
|
|
43
|
+
generateComponentsPipeline,
|
|
44
|
+
runComponents,
|
|
45
|
+
findComponentGate,
|
|
46
|
+
resolveComponentTargets,
|
|
47
|
+
} from "./cli-support";
|
|
48
|
+
export { renderDriverHuman, renderDriverJson } from "./driver-output";
|
|
49
|
+
export {
|
|
50
|
+
type Capability,
|
|
51
|
+
type CapabilityInput,
|
|
52
|
+
type CapabilityOutput,
|
|
53
|
+
type DeployContext,
|
|
54
|
+
CapabilityRegistry,
|
|
55
|
+
CapabilityNotImplementedError,
|
|
56
|
+
} from "./capability";
|
|
57
|
+
export { createCapabilityRegistry, STARTER_VERB_FAMILIES } from "./registry";
|
|
58
|
+
export {
|
|
59
|
+
type CapabilityPlugin,
|
|
60
|
+
type CapabilityManifest,
|
|
61
|
+
isCapabilityPlugin,
|
|
62
|
+
} from "./capability-plugin";
|
|
63
|
+
export {
|
|
64
|
+
CapabilityManifestSchema,
|
|
65
|
+
type CapabilityManifestParsed,
|
|
66
|
+
validateCapabilityManifest,
|
|
67
|
+
} from "./capability-plugin-schema";
|
|
68
|
+
export {
|
|
69
|
+
loadCapabilityPlugin,
|
|
70
|
+
loadCapabilityPlugins,
|
|
71
|
+
registerCapabilityPlugins,
|
|
72
|
+
buildCapabilityRegistry,
|
|
73
|
+
type BuildCapabilityRegistryOptions,
|
|
74
|
+
MalformedCapabilityPluginError,
|
|
75
|
+
DuplicateCapabilityKindError,
|
|
76
|
+
} from "./capability-plugin-loader";
|
|
77
|
+
export { starterCapabilityPlugin } from "./starter-plugin";
|
|
78
|
+
export * from "./verbs/index";
|
|
79
|
+
export * from "./builders";
|
|
80
|
+
export {
|
|
81
|
+
type DriverStep,
|
|
82
|
+
type DriverGate,
|
|
83
|
+
type DriverPhase,
|
|
84
|
+
type DriverComponent,
|
|
85
|
+
type DriverStepRecord,
|
|
86
|
+
type DriverComponentResult,
|
|
87
|
+
type DriverRunResult,
|
|
88
|
+
type ComponentGraph,
|
|
89
|
+
type InterpretRunOptions,
|
|
90
|
+
type WiringValue,
|
|
91
|
+
resolveComponentGraph,
|
|
92
|
+
resolveWiring,
|
|
93
|
+
resolveStepInput,
|
|
94
|
+
runComponentDeploy,
|
|
95
|
+
runInterpretDriver,
|
|
96
|
+
DriverGateUnsupportedError,
|
|
97
|
+
DependencyCycleError,
|
|
98
|
+
UnknownDependencyError,
|
|
99
|
+
DriverRunFailure,
|
|
100
|
+
} from "./driver";
|
|
101
|
+
export {
|
|
102
|
+
EcsFargateComponent,
|
|
103
|
+
type EcsFargateComponentConfig,
|
|
104
|
+
LambdaComponent,
|
|
105
|
+
type LambdaComponentConfig,
|
|
106
|
+
SingleHostComposeComponent,
|
|
107
|
+
type SingleHostComposeComponentConfig,
|
|
108
|
+
} from "./presets/index";
|
|
109
|
+
export {
|
|
110
|
+
type ComponentTemporalCodegen,
|
|
111
|
+
type ComponentTemporalCodegenOptions,
|
|
112
|
+
loadComponentTemporalCodegen,
|
|
113
|
+
} from "./temporal-codegen-loader";
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { describe, test, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import type { DriverStepRecord } from "./driver";
|
|
3
|
+
import { createBuildArchiveManifest, addArchiveEntry, type BuildArchiveManifest } from "./verbs/build-archive";
|
|
4
|
+
|
|
5
|
+
const persistBuildManifestMock = vi.fn();
|
|
6
|
+
const pushLifecycleMock = vi.fn();
|
|
7
|
+
|
|
8
|
+
vi.mock("../lifecycle/build-ledger-store", () => ({
|
|
9
|
+
persistBuildManifest: (...args: unknown[]) => persistBuildManifestMock(...args),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("../lifecycle/git", () => ({
|
|
13
|
+
pushLifecycle: (...args: unknown[]) => pushLifecycleMock(...args),
|
|
14
|
+
}));
|
|
15
|
+
|
|
16
|
+
const {
|
|
17
|
+
maybePersistBuildManifest,
|
|
18
|
+
extractRunManifest,
|
|
19
|
+
extractRunManifestFromPhaseOutputs,
|
|
20
|
+
} = await import("./manifest-persistence");
|
|
21
|
+
|
|
22
|
+
function makeManifest(component: string, digest: string): BuildArchiveManifest {
|
|
23
|
+
let manifest = createBuildArchiveManifest(component, { now: () => new Date("2026-01-01T00:00:00.000Z") });
|
|
24
|
+
manifest = addArchiveEntry(manifest, { kind: "image", path: "image.tar", digest });
|
|
25
|
+
return manifest;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function buildRecord(manifest: BuildArchiveManifest): DriverStepRecord {
|
|
29
|
+
return {
|
|
30
|
+
component: manifest.component,
|
|
31
|
+
phase: "Build",
|
|
32
|
+
kind: "docker-build",
|
|
33
|
+
status: "ok",
|
|
34
|
+
durationMs: 5,
|
|
35
|
+
output: { archivePath: "image.tar", digest: manifest.contents[0]!.digest, manifest },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function applyRecord(): DriverStepRecord {
|
|
40
|
+
return { component: "svc", phase: "Apply", kind: "cfn-deploy", status: "ok", durationMs: 5, output: { ok: true } };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
describe("extractRunManifest", () => {
|
|
44
|
+
test("finds the manifest from a build-shaped step output", () => {
|
|
45
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
46
|
+
expect(extractRunManifest([buildRecord(manifest)])).toEqual(manifest);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("returns undefined when no step produced a manifest", () => {
|
|
50
|
+
expect(extractRunManifest([applyRecord()])).toBeUndefined();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("ignores failed/skipped steps", () => {
|
|
54
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
55
|
+
const failed: DriverStepRecord = { ...buildRecord(manifest), status: "fail", output: undefined };
|
|
56
|
+
expect(extractRunManifest([failed])).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("takes the last (most-accumulated) manifest when multiple build steps ran", () => {
|
|
60
|
+
const first = makeManifest("svc", "sha256:first");
|
|
61
|
+
let second = makeManifest("svc", "sha256:first");
|
|
62
|
+
second = addArchiveEntry(second, { kind: "image", path: "second.tar", digest: "sha256:second" });
|
|
63
|
+
|
|
64
|
+
const result = extractRunManifest([buildRecord(first), buildRecord(second)]);
|
|
65
|
+
expect(result).toEqual(second);
|
|
66
|
+
expect(result?.contents).toHaveLength(2);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("extractRunManifestFromPhaseOutputs", () => {
|
|
71
|
+
test("finds the manifest across phase outputs (Temporal workflow result shape)", () => {
|
|
72
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
73
|
+
expect(
|
|
74
|
+
extractRunManifestFromPhaseOutputs({
|
|
75
|
+
Build: { archivePath: "image.tar", digest: "sha256:abc", manifest },
|
|
76
|
+
Apply: { ok: true },
|
|
77
|
+
}),
|
|
78
|
+
).toEqual(manifest);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("returns undefined for undefined/empty phaseOutputs", () => {
|
|
82
|
+
expect(extractRunManifestFromPhaseOutputs(undefined)).toBeUndefined();
|
|
83
|
+
expect(extractRunManifestFromPhaseOutputs({})).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe("maybePersistBuildManifest", () => {
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
persistBuildManifestMock.mockReset();
|
|
90
|
+
pushLifecycleMock.mockReset().mockResolvedValue(true);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("success with a manifest in records -> persists and pushes", async () => {
|
|
94
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
95
|
+
persistBuildManifestMock.mockResolvedValue({ commit: "a".repeat(40) });
|
|
96
|
+
|
|
97
|
+
const outcome = await maybePersistBuildManifest({ success: true, records: [buildRecord(manifest)] });
|
|
98
|
+
|
|
99
|
+
expect(outcome).toEqual({ persisted: true, commit: "a".repeat(40), manifestDigest: manifest.manifestDigest });
|
|
100
|
+
expect(persistBuildManifestMock).toHaveBeenCalledTimes(1);
|
|
101
|
+
expect(persistBuildManifestMock.mock.calls[0][0]).toEqual(manifest);
|
|
102
|
+
expect(pushLifecycleMock).toHaveBeenCalledTimes(1);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("a pre-resolved manifest (Temporal path) takes precedence over records", async () => {
|
|
106
|
+
const preResolved = makeManifest("svc", "sha256:temporal");
|
|
107
|
+
persistBuildManifestMock.mockResolvedValue({ commit: "b".repeat(40) });
|
|
108
|
+
|
|
109
|
+
const outcome = await maybePersistBuildManifest({
|
|
110
|
+
success: true,
|
|
111
|
+
manifest: preResolved,
|
|
112
|
+
records: [buildRecord(makeManifest("svc", "sha256:ignored"))],
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
expect(outcome).toMatchObject({ persisted: true, manifestDigest: preResolved.manifestDigest });
|
|
116
|
+
expect(persistBuildManifestMock.mock.calls[0][0]).toEqual(preResolved);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("failure (run.success = false) -> persists nothing (dry-run/failed-deploy safety)", async () => {
|
|
120
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
121
|
+
const outcome = await maybePersistBuildManifest({ success: false, records: [buildRecord(manifest)] });
|
|
122
|
+
expect(outcome).toEqual({ persisted: false, reason: "run-not-successful" });
|
|
123
|
+
expect(persistBuildManifestMock).not.toHaveBeenCalled();
|
|
124
|
+
expect(pushLifecycleMock).not.toHaveBeenCalled();
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test("opt-out (options.disabled) -> persists nothing, even on a successful run with a manifest", async () => {
|
|
128
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
129
|
+
const outcome = await maybePersistBuildManifest(
|
|
130
|
+
{ success: true, records: [buildRecord(manifest)] },
|
|
131
|
+
{ disabled: true },
|
|
132
|
+
);
|
|
133
|
+
expect(outcome).toEqual({ persisted: false, reason: "opted-out" });
|
|
134
|
+
expect(persistBuildManifestMock).not.toHaveBeenCalled();
|
|
135
|
+
expect(pushLifecycleMock).not.toHaveBeenCalled();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("no manifest in the run's records -> skipped, not an error (infra-only/apply-only component)", async () => {
|
|
139
|
+
const outcome = await maybePersistBuildManifest({ success: true, records: [applyRecord()] });
|
|
140
|
+
expect(outcome).toEqual({ persisted: false, reason: "no-manifest" });
|
|
141
|
+
expect(persistBuildManifestMock).not.toHaveBeenCalled();
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
test("persist failure -> reported as an error result, not thrown, and never masks the successful deploy", async () => {
|
|
145
|
+
const manifest = makeManifest("svc", "sha256:abc");
|
|
146
|
+
persistBuildManifestMock.mockRejectedValue(new Error("git write failed"));
|
|
147
|
+
|
|
148
|
+
await expect(
|
|
149
|
+
maybePersistBuildManifest({ success: true, records: [buildRecord(manifest)] }),
|
|
150
|
+
).resolves.toMatchObject({ persisted: false, reason: "error", error: "git write failed" });
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persist a component run's `BuildArchiveManifest` after a successful `chant
|
|
3
|
+
* run --components <name> --env <env>` (#609, epic #551 follow-up to
|
|
4
|
+
* #564/#568/#606/#613/#614). Mirrors ./auto-release.ts's shape exactly —
|
|
5
|
+
* same "extract from step records, then call a lifecycle-layer writer, then
|
|
6
|
+
* push, and never let a write failure fail an already-successful deploy"
|
|
7
|
+
* structure — because it is solving the same class of problem: the driver
|
|
8
|
+
* produces something worth recording durably, but the driver itself must
|
|
9
|
+
* stay capability-agnostic (../components/driver.ts takes no dependency on
|
|
10
|
+
* ../lifecycle/*), so the CLI performs the write as a post-run step.
|
|
11
|
+
*
|
|
12
|
+
* **Why here, not the driver.** Same reasoning as ./auto-release.ts's module
|
|
13
|
+
* doc: a manifest write is a git commit + push, a non-idempotent side effect
|
|
14
|
+
* with real-world I/O — exactly what `driver.ts` resists taking on (it is
|
|
15
|
+
* exercised in tests against a bare `CapabilityRegistry` with no lifecycle
|
|
16
|
+
* dependency at all) and what Temporal workflow code must never do directly
|
|
17
|
+
* (replay-safety). The CLI calls this after `runComponents`/`handle.result()`
|
|
18
|
+
* reports success, the same place `maybeRecordAutoRelease` is already
|
|
19
|
+
* called from (../cli/handlers/run.ts).
|
|
20
|
+
*
|
|
21
|
+
* **Extraction is duck-typed, not capability-specific.** `docker-build`,
|
|
22
|
+
* `generate-sbom`, `extract-config-bom`, and `addArchiveTemplate` (the
|
|
23
|
+
* build-family capabilities/helpers, ../components/verbs/build.ts,
|
|
24
|
+
* ./verbs/sbom.ts, ./verbs/config-bom.ts) all return `{ ..., manifest:
|
|
25
|
+
* BuildArchiveManifest }` — the accumulation convention documented on each of
|
|
26
|
+
* their inputs ("manifest to extend... same accumulation convention"). This
|
|
27
|
+
* module scans a run's step outputs for that shape, exactly the way
|
|
28
|
+
* ./auto-release.ts's `extractRunDigest` scans for a publish-shaped output,
|
|
29
|
+
* so a new build-family capability that follows the same `{ manifest }`
|
|
30
|
+
* output convention is picked up automatically — no branch here names a
|
|
31
|
+
* specific capability `kind`.
|
|
32
|
+
*/
|
|
33
|
+
import { persistBuildManifest } from "../lifecycle/build-ledger-store";
|
|
34
|
+
import { pushLifecycle } from "../lifecycle/git";
|
|
35
|
+
import type { BuildArchiveManifest } from "./verbs/build-archive";
|
|
36
|
+
import type { DriverStepRecord } from "./driver";
|
|
37
|
+
|
|
38
|
+
/** A step output shaped like it carries a `BuildArchiveManifest` — duck-typed the same way ./auto-release.ts's `isPublishShaped` detects a publish result. */
|
|
39
|
+
function isManifestShaped(output: unknown): output is { manifest: BuildArchiveManifest } {
|
|
40
|
+
return (
|
|
41
|
+
!!output &&
|
|
42
|
+
typeof output === "object" &&
|
|
43
|
+
"manifest" in output &&
|
|
44
|
+
!!(output as { manifest?: unknown }).manifest &&
|
|
45
|
+
typeof (output as { manifest?: unknown }).manifest === "object"
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Find the most fully-accumulated `BuildArchiveManifest` a component run
|
|
51
|
+
* produced, by scanning its step records for the last manifest-bearing
|
|
52
|
+
* output — mirroring `extractRunDigest`'s "last wins" convention, which is
|
|
53
|
+
* also the correct one here: every build-family capability's `manifest`
|
|
54
|
+
* input/output accumulates onto whatever manifest came before it in the same
|
|
55
|
+
* phase (see ../components/verbs/build.ts's `DockerBuildInput.manifest`
|
|
56
|
+
* doc), so the *last* manifest-bearing step output in run order is always
|
|
57
|
+
* the fullest one — a template + SBOM + config-BOM composition's final step
|
|
58
|
+
* carries every earlier entry too, not just its own.
|
|
59
|
+
*/
|
|
60
|
+
export function extractRunManifest(records: DriverStepRecord[]): BuildArchiveManifest | undefined {
|
|
61
|
+
let found: BuildArchiveManifest | undefined;
|
|
62
|
+
for (const record of records) {
|
|
63
|
+
if (record.status !== "ok") continue;
|
|
64
|
+
if (isManifestShaped(record.output)) {
|
|
65
|
+
found = record.output.manifest;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return found;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Same manifest extraction as `extractRunManifest`, but over a component
|
|
73
|
+
* Temporal workflow's returned `phaseOutputs` (`{ [phase]: output }`) —
|
|
74
|
+
* mirroring ./auto-release.ts's `extractRunDigestFromPhaseOutputs`, the
|
|
75
|
+
* `--temporal` CLI path's counterpart, since that path never sees individual
|
|
76
|
+
* step records either.
|
|
77
|
+
*/
|
|
78
|
+
export function extractRunManifestFromPhaseOutputs(
|
|
79
|
+
phaseOutputs: Record<string, Record<string, unknown>> | undefined,
|
|
80
|
+
): BuildArchiveManifest | undefined {
|
|
81
|
+
let found: BuildArchiveManifest | undefined;
|
|
82
|
+
for (const output of Object.values(phaseOutputs ?? {})) {
|
|
83
|
+
if (isManifestShaped(output)) {
|
|
84
|
+
found = output.manifest;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return found;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Explicit reasons `maybePersistBuildManifest` declined to write — never a thrown error, mirroring ./auto-release.ts's `AutoReleaseSkipReason`. */
|
|
91
|
+
export type ManifestPersistSkipReason = "opted-out" | "run-not-successful" | "no-manifest";
|
|
92
|
+
|
|
93
|
+
export type ManifestPersistResult =
|
|
94
|
+
| { persisted: true; commit: string; manifestDigest: string }
|
|
95
|
+
| { persisted: false; reason: ManifestPersistSkipReason }
|
|
96
|
+
| { persisted: false; reason: "error"; error: string };
|
|
97
|
+
|
|
98
|
+
/** Input describing one component's completed run — the manifest-persistence counterpart of ./auto-release.ts's `AutoReleaseRunInfo`. */
|
|
99
|
+
export interface ManifestPersistRunInfo {
|
|
100
|
+
/** Whether the run reported overall success. A caller must not call this for a non-terminal/in-progress run — mirrors `AutoReleaseRunInfo.success`. */
|
|
101
|
+
success: boolean;
|
|
102
|
+
/** The component's step records (local executor), used to locate the accumulated manifest via `extractRunManifest`. Mutually exclusive with `manifest`. */
|
|
103
|
+
records?: DriverStepRecord[];
|
|
104
|
+
/** A manifest already resolved by the caller (e.g. a future durable/Temporal path that has its own phaseOutputs-shaped extraction). Takes precedence over `records` when both are given. */
|
|
105
|
+
manifest?: BuildArchiveManifest;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Opt-out knobs for manifest persistence, mirroring ./auto-release.ts's `AutoReleaseOptions`. */
|
|
109
|
+
export interface ManifestPersistOptions {
|
|
110
|
+
/** `--no-release-record` / `chant.config.ts`'s `release.autoRecord: false` also gates manifest persistence — both are "durably record this successful deploy" side effects with the same opt-out story, so one flag/config knob controls both rather than introducing a second, easy-to-forget switch. Default: persistence is ON. */
|
|
111
|
+
disabled?: boolean;
|
|
112
|
+
/** Working directory for the git plumbing calls (tests). */
|
|
113
|
+
cwd?: string;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* After a successful `chant run --components <name> --env <env>` (local
|
|
118
|
+
* executor), persist the run's accumulated `BuildArchiveManifest` (if any)
|
|
119
|
+
* to the durable build-manifest store (../lifecycle/build-ledger-store.ts)
|
|
120
|
+
* and push it — or explain, without throwing, why it didn't. Never called
|
|
121
|
+
* for a failed run, matching `maybeRecordAutoRelease`'s contract exactly.
|
|
122
|
+
*
|
|
123
|
+
* Skips (returns `{ persisted: false, reason }`, never throws):
|
|
124
|
+
* - `options.disabled` — the opt-out flag/config was set.
|
|
125
|
+
* - `run.success` false — defensive; callers should not reach here on
|
|
126
|
+
* failure. A dry-run/failed deploy persists nothing, by construction —
|
|
127
|
+
* this is also what makes a dry run safe: `chant run --components` never
|
|
128
|
+
* calls this function at all unless the run actually completed.
|
|
129
|
+
* - no manifest found in the run's records — a component with no
|
|
130
|
+
* build-family step (an infra-only/apply-only component, or a
|
|
131
|
+
* build-less `Publish`-only producer that reused a prior archive) has
|
|
132
|
+
* nothing to persist. This is the expected common case for most deploys,
|
|
133
|
+
* not an error.
|
|
134
|
+
*
|
|
135
|
+
* Write/push failures (any error `persistBuildManifest`/`pushLifecycle`
|
|
136
|
+
* throw) are reported as `{ persisted: false, reason: "error", error }`
|
|
137
|
+
* rather than propagated — same "never turn a successful deploy into a
|
|
138
|
+
* failing CLI invocation" contract `maybeRecordAutoRelease` already
|
|
139
|
+
* establishes for release records.
|
|
140
|
+
*/
|
|
141
|
+
export async function maybePersistBuildManifest(
|
|
142
|
+
run: ManifestPersistRunInfo,
|
|
143
|
+
options: ManifestPersistOptions = {},
|
|
144
|
+
): Promise<ManifestPersistResult> {
|
|
145
|
+
if (options.disabled) {
|
|
146
|
+
return { persisted: false, reason: "opted-out" };
|
|
147
|
+
}
|
|
148
|
+
if (!run.success) {
|
|
149
|
+
return { persisted: false, reason: "run-not-successful" };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const manifest = run.manifest ?? extractRunManifest(run.records ?? []);
|
|
153
|
+
if (!manifest) {
|
|
154
|
+
return { persisted: false, reason: "no-manifest" };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
const { commit } = await persistBuildManifest(manifest, { cwd: options.cwd });
|
|
159
|
+
await pushLifecycle({ cwd: options.cwd });
|
|
160
|
+
return { persisted: true, commit, manifestDigest: manifest.manifestDigest };
|
|
161
|
+
} catch (err) {
|
|
162
|
+
return { persisted: false, reason: "error", error: err instanceof Error ? err.message : String(err) };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Pilot component definitions
|
|
2
|
+
|
|
3
|
+
Three concrete components authored against the [Component contract](../../../../../docs/src/content/docs/components/component-contract.mdx), picked (epic [#551](https://github.com/INTENTIUS/chant/issues/551)) to be the three most-different real components chant deploys today. Each is provided as:
|
|
4
|
+
|
|
5
|
+
- a **TypeScript authoring form** (`*.pilot.ts`) — composed using the real capability `kind` verbs and typed inputs from [`../verbs`](../verbs/), against the real typed `Component`/`phase()`/`gate()`/`stackOutput()` authoring frontend (`../component.ts`, Phase 2, [#560](https://github.com/INTENTIUS/chant/issues/560)). Prior to #560 these pilots authored against a local stopgap shape (`authoring-shape.ts`, now deleted) that mirrored `component.schema.json` field-for-field as a placeholder; migrating them to import `../component` instead was a like-for-like swap since the two shapes matched 1:1 by design.
|
|
6
|
+
- its **JSON projection** (`project.ts` + [`pilots.test.ts`](./pilots.test.ts)) — asserted equal to the existing fixture in [`../__fixtures__/`](../__fixtures__/) that already validates against the schema ([#553](https://github.com/INTENTIUS/chant/issues/553)/[#571](https://github.com/INTENTIUS/chant/pull/571)). The fixture stays the one authoritative JSON document per pilot; this directory does not fork a second copy.
|
|
7
|
+
|
|
8
|
+
## Mapping to the epic's axes
|
|
9
|
+
|
|
10
|
+
The epic ([#551](https://github.com/INTENTIUS/chant/issues/551)) picked these three specifically to exercise different points on each axis at once, so three components prove more than three would if they were shape-variations of each other.
|
|
11
|
+
|
|
12
|
+
| Pilot | File / fixture | build vs no-build | single vs fan-out | sticky vs simple apply | cross-stack wiring | auto vs no rollback |
|
|
13
|
+
|---|---|---|---|---|---|---|
|
|
14
|
+
| **Neo4j per-instance fan-out** | [`neo4j-fanout.pilot.ts`](./neo4j-fanout.pilot.ts) / [`neo4j-fanout.json`](../__fixtures__/neo4j-fanout.json) | no-build (`infra`, applies pre-built templates) | **fan-out** — one component composes 3 per-instance mini-compositions (`cfn-deploy` + `code-deploy` + `wait-cluster-healthy`), seed-first then rolling, gated at node 1 | simple apply (no `onReplace`/`stageGsi` — no sticky CFN concerns here) | none (self-contained cluster, no shared-stack imports) | **auto** — `code-deploy` (AWS CodeDeploy) rollback is native/automatic on failure, declared once inside the capability, never scripted per node |
|
|
15
|
+
| **DynamoDB table** | [`dynamodb.pilot.ts`](./dynamodb.pilot.ts) / [`dynamodb-infra.json`](../__fixtures__/dynamodb-infra.json) | no-build (`infra`, applies an existing table template) | single (one `cfn-deploy`, no fan-out) | **sticky** — `onReplace: "block"` refuses a replacing changeset (data loss guard); `stageGsi: true` stages the GSI add→backfill→remove instead of an in-place replace | none | no rollback declared — a blocked replacement is not something to compensate, it is a stop |
|
|
16
|
+
| **ALB/ECS target** | [`alb-ecs.pilot.ts`](./alb-ecs.pilot.ts) / [`alb-ecs-service.json`](../__fixtures__/alb-ecs-service.json) | **build** — `docker-build` → `publish-image` (promote by digest at deploy time) | single (one service, one `cfn-deploy` + `ecs-update-service`) | simple apply (no replacement-sensitive resource here) | **cross-stack** — imports `shared-alb`'s `ListenerArn`/`ClusterArn`/`Subnets` via `stackOutput()`, replacing the `describe-stacks \| jq` glue in [`examples/gitlab-aws-alb-api/src/pipeline.ts`](../../../../../examples/gitlab-aws-alb-api/src/pipeline.ts) | **no** (component-declared) — `ecs-update-service`/`cfn-deploy` have no native automatic rollback for an already-running service swap, so the component supplies an explicit `rollback` phase (`rollback-previous`) rather than relying on capability compensation |
|
|
17
|
+
|
|
18
|
+
Read together, the three cover every cell at least once: build only shows up for ALB/ECS, fan-out only for Neo4j, sticky-apply only for DynamoDB, cross-stack only for ALB/ECS, and both rollback styles (capability-native vs component-declared) appear once each.
|
|
19
|
+
|
|
20
|
+
## A fourth component (#558): image-processor Lambda
|
|
21
|
+
|
|
22
|
+
[`lambda.pilot.ts`](./lambda.pilot.ts) / [`lambda-image-processor.json`](../__fixtures__/lambda-image-processor.json) adds a fourth component, added after the three above to validate the sprawl metric ([#551](https://github.com/INTENTIUS/chant/issues/551)#definition-of-done-the-sprawl-metric), not to re-cover the same axes. It reuses `docker-build`/`publish-image` unchanged (build + promote-by-digest is identical to ALB/ECS's) but its Apply phase dispatches to `lambda-deploy` instead of `cfn-deploy` — the first component in the set with no CloudFormation stack in its apply step at all. `lambda-deploy` was the one new capability this component needed; see [`../SPRAWL-VALIDATION.md`](../SPRAWL-VALIDATION.md) for the full accounting and the ALB/ECS pipeline-glue before/after.
|
|
23
|
+
|
|
24
|
+
## Why the fixture is authoritative, not this directory
|
|
25
|
+
|
|
26
|
+
[#555](https://github.com/INTENTIUS/chant/issues/555) explicitly scopes "committed under an `examples/` or `fixtures/` path" — the schema's own `__fixtures__/` already holds real components drawn from this epic, including these three. Duplicating them here as a second JSON copy would immediately be the "composition copy-paste" / definition-sprawl failure mode the epic itself guards against ([#551](https://github.com/INTENTIUS/chant/issues/551)#failure-modes). Instead:
|
|
27
|
+
|
|
28
|
+
- `../__fixtures__/*.json` remains the one JSON document per pilot, already covered by [`../component-schema.test.ts`](../component-schema.test.ts).
|
|
29
|
+
- This directory adds the TypeScript authoring form the issue also asks for, and [`pilots.test.ts`](./pilots.test.ts) asserts the two never drift apart — if a pilot's composition changes, the fixture is the file to update, and the test fails loudly if only one side moves.
|
|
30
|
+
|
|
31
|
+
## What's out of scope here
|
|
32
|
+
|
|
33
|
+
Per the issue: running these compositions (the [Phase 1 driver](https://github.com/INTENTIUS/chant/issues/556)) and real capability implementations ([#557](https://github.com/INTENTIUS/chant/issues/557)) are separate issues. Every capability referenced below is still a typed stub (see [`../verbs/`](../verbs/)) — `run()`/`rollback()` throw `CapabilityNotImplementedError`. Nothing here executes anything.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pilot: ALB/ECS target (#555, epic #551).
|
|
3
|
+
*
|
|
4
|
+
* Exercises the build + cross-stack + auto-rollback axes: `docker-build` →
|
|
5
|
+
* `publish-image` (promote by digest, deploy-time) → `cfn-deploy` (importing
|
|
6
|
+
* the shared ALB's listener/cluster/subnets as cross-stack outputs, resolved
|
|
7
|
+
* by `chant graph --stacks` rather than a `describe-stacks | jq` pipeline
|
|
8
|
+
* step — see composition-and-wiring.mdx#cross-stack-outputs) →
|
|
9
|
+
* `ecs-update-service` → `wait-steady-state` + `health-gate`.
|
|
10
|
+
*
|
|
11
|
+
* This is the direct component-native replacement for the hand-rolled GitLab
|
|
12
|
+
* pipeline in `examples/gitlab-aws-alb-api/src/pipeline.ts`: the
|
|
13
|
+
* `describe-stacks`/`jq` glue in that pipeline's `deployService` job is
|
|
14
|
+
* exactly the cross-stack `stackOutput()` wiring below, and its
|
|
15
|
+
* `docker build`/`docker push` steps are the `docker-build` + `publish-image`
|
|
16
|
+
* capabilities. `service` archetype: build → publish → apply → verify, the
|
|
17
|
+
* fullest of the three archetypes.
|
|
18
|
+
*
|
|
19
|
+
* The JSON projection of this pilot is authoritative at
|
|
20
|
+
* ../__fixtures__/alb-ecs-service.json (already schema-validated by
|
|
21
|
+
* component-schema.test.ts) — this module is the real typed `Component`
|
|
22
|
+
* authoring form (#560, ../component.ts) that composes to that same
|
|
23
|
+
* document; see ./pilots.test.ts, which asserts the two never diverge.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { Component } from "../component";
|
|
27
|
+
import { phase, stackOutput } from "../component";
|
|
28
|
+
|
|
29
|
+
/** The shared ALB stack's exported outputs this service imports — the cross-stack wiring axis. */
|
|
30
|
+
const sharedAlbOutputs = {
|
|
31
|
+
listenerArn: stackOutput("shared-alb", "ListenerArn"),
|
|
32
|
+
clusterArn: stackOutput("shared-alb", "ClusterArn"),
|
|
33
|
+
subnets: stackOutput("shared-alb", "Subnets"),
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const searchService: Component = {
|
|
37
|
+
name: "search-service",
|
|
38
|
+
archetype: "service",
|
|
39
|
+
dependsOn: ["shared-alb"],
|
|
40
|
+
build: { kind: "docker-build", context: ".", into: "archive" },
|
|
41
|
+
deploy: [
|
|
42
|
+
phase("Publish", [{ kind: "publish-image", from: "archive", to: "$env.registry" }]),
|
|
43
|
+
phase("Apply", [
|
|
44
|
+
{
|
|
45
|
+
kind: "cfn-deploy",
|
|
46
|
+
template: "archive:search.template.json",
|
|
47
|
+
imageRef: "@Publish.digest",
|
|
48
|
+
inputs: sharedAlbOutputs,
|
|
49
|
+
},
|
|
50
|
+
{ kind: "ecs-update-service", cluster: "$env.cluster", service: "search" },
|
|
51
|
+
]),
|
|
52
|
+
phase("Verify", [
|
|
53
|
+
{ kind: "wait-steady-state", service: "search" },
|
|
54
|
+
{ kind: "health-gate", path: "/healthz" },
|
|
55
|
+
]),
|
|
56
|
+
],
|
|
57
|
+
// No native `rollback` on ecs-update-service/cfn-deploy for an already-running
|
|
58
|
+
// service swap — the component declares an explicit compensation phase
|
|
59
|
+
// (auto/no-rollback axis: this is the "no automatic capability rollback,
|
|
60
|
+
// component supplies its own" side, contrasted with code-deploy's native
|
|
61
|
+
// automatic rollback in the Neo4j pilot).
|
|
62
|
+
rollback: [phase("Rollback", [{ kind: "rollback-previous", service: "search", cluster: "$env.cluster" }])],
|
|
63
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pilot: DynamoDB table (#555, epic #551).
|
|
3
|
+
*
|
|
4
|
+
* Exercises the sticky-apply axis: `cfn-deploy` carries declarative safety
|
|
5
|
+
* options — `onReplace: "block"` refuses a changeset that would replace the
|
|
6
|
+
* table (losing data) rather than update it in place, and `stageGsi: true`
|
|
7
|
+
* stages a GSI change (add → backfill → remove) instead of an in-place
|
|
8
|
+
* replace. That stickiness lives inside the `cfn-deploy` capability, exposed
|
|
9
|
+
* as options, not scripted per component — see
|
|
10
|
+
* capabilities.mdx#stickiness-lives-in-the-capability. `infra` archetype: no
|
|
11
|
+
* build, apply → verify only. Verify fans out in parallel: the stack wait and
|
|
12
|
+
* a GSI backfill migration have no ordering dependency on each other.
|
|
13
|
+
*
|
|
14
|
+
* The JSON projection of this pilot is authoritative at
|
|
15
|
+
* ../__fixtures__/dynamodb-infra.json (already schema-validated by
|
|
16
|
+
* component-schema.test.ts) — this module is the real typed `Component`
|
|
17
|
+
* authoring form (#560, ../component.ts) that composes to that same
|
|
18
|
+
* document; see ./pilots.test.ts, which asserts the two never diverge.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { Component } from "../component";
|
|
22
|
+
import { phase } from "../component";
|
|
23
|
+
|
|
24
|
+
// `cfn-deploy`'s safety fields, kept as a plain literal here: the pilot is
|
|
25
|
+
// agnostic component *data* naming the `cfn-deploy` kind, so it does not import
|
|
26
|
+
// the AWS capability's types (those live in the aws lexicon now). The `onReplace`
|
|
27
|
+
// value must match `cfn-deploy`'s `CfnReplacePolicy` union.
|
|
28
|
+
const cfnSafetyOptions: { onReplace: "block" | "allow" | "snapshot-first"; stageGsi: boolean } = {
|
|
29
|
+
onReplace: "block",
|
|
30
|
+
stageGsi: true,
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const ordersTable: Component = {
|
|
34
|
+
name: "orders-table",
|
|
35
|
+
archetype: "infra",
|
|
36
|
+
dependsOn: [],
|
|
37
|
+
deploy: [
|
|
38
|
+
phase("Apply", [
|
|
39
|
+
{ kind: "cfn-deploy", template: "archive:orders-table.template.json", ...cfnSafetyOptions },
|
|
40
|
+
]),
|
|
41
|
+
phase(
|
|
42
|
+
"Verify",
|
|
43
|
+
[
|
|
44
|
+
{ kind: "wait-for-stack", stack: "orders-table" },
|
|
45
|
+
{
|
|
46
|
+
kind: "run-migration",
|
|
47
|
+
script: "archive:migrations/backfill-gsi.sql",
|
|
48
|
+
// A GSI backfill has no clean inverse: once items are re-projected
|
|
49
|
+
// onto the new index, "rolling back" the migration would mean a
|
|
50
|
+
// second migration to undo it, not a mechanical compensation the
|
|
51
|
+
// capability could run automatically — see COMP003
|
|
52
|
+
// (lint-rules/composition.mdx) for the opt-out convention.
|
|
53
|
+
noRollback: "GSI backfill is forward-only; undoing it needs a second, hand-written migration, not automatic compensation",
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
{ parallel: true },
|
|
57
|
+
),
|
|
58
|
+
],
|
|
59
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pilot pair: JAR producer -> EMR consumer, cross-component artifact outputs
|
|
3
|
+
* (#561, epic #551).
|
|
4
|
+
*
|
|
5
|
+
* This is the epic's worked example for cross-component wiring (#551
|
|
6
|
+
* §"Cross-component outputs", docs/components/composition-and-wiring.mdx
|
|
7
|
+
* §"Cross-component outputs"): a **producer-library** component
|
|
8
|
+
* (`jar-lib`) that only builds and publishes an artifact — no apply, no
|
|
9
|
+
* service — paired with an **infra** consumer (`emr-job`) that submits an
|
|
10
|
+
* EMR job run against the producer's published S3 URI.
|
|
11
|
+
*
|
|
12
|
+
* The wiring itself needs no new machinery: `dependsOn: ["jar-lib"]` orders
|
|
13
|
+
* the producer first (`resolveComponentGraph`, ../driver.ts), and
|
|
14
|
+
* `"@jar-lib.publish.uri"` is the same `@<component>.publish.uri|digest|key`
|
|
15
|
+
* reference form `resolveWiring` (../driver.ts) already resolves generically
|
|
16
|
+
* from `componentOutputs`, which `runComponentDeploy` already populates from
|
|
17
|
+
* any step whose output carries `uri`/`digest`/`key` (`findPublishOutput`) —
|
|
18
|
+
* both landed with #556/#560 and are exercised by ../driver.test.ts's
|
|
19
|
+
* "wires a cross-component artifact reference" case. What #561 actually adds
|
|
20
|
+
* is: this pair authored as real typed `Component`s (rather than only the
|
|
21
|
+
* hand-written JSON fixtures), and a real `emr-start-job-run`/`wait-job`
|
|
22
|
+
* capability implementation (../verbs/job-submission.ts,
|
|
23
|
+
* ../verbs/wait-verify.ts) so the pair runs to completion against a mocked
|
|
24
|
+
* `CloudExecutor` instead of throwing `CapabilityNotImplementedError`.
|
|
25
|
+
*
|
|
26
|
+
* The JSON projections of these two components are authoritative at
|
|
27
|
+
* ../__fixtures__/jar-lib-producer.json and
|
|
28
|
+
* ../__fixtures__/emr-job-consumer.json (pre-existing, from #560) — this
|
|
29
|
+
* module is the real typed `Component` authoring form that composes to those
|
|
30
|
+
* same documents; see ./pilots.test.ts, which asserts the two never diverge.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
import type { Component } from "../component";
|
|
34
|
+
import { phase } from "../component";
|
|
35
|
+
|
|
36
|
+
/** Producer: a JAR built from a Maven project, published to S3. Publish-only deploy — no apply phase at all, the defining shape of the `producer-library` archetype. */
|
|
37
|
+
export const jarLib: Component = {
|
|
38
|
+
name: "jar-lib",
|
|
39
|
+
archetype: "producer-library",
|
|
40
|
+
dependsOn: [],
|
|
41
|
+
build: { kind: "jvm-build", context: ".", into: "archive" },
|
|
42
|
+
deploy: [
|
|
43
|
+
// → @jar-lib.publish.uri / @jar-lib.publish.digest, resolved by the graph
|
|
44
|
+
// for any downstream consumer — never known by this component itself.
|
|
45
|
+
phase("Publish", [{ kind: "publish-artifact", from: "archive", to: "$env.s3" }]),
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/** Consumer: an EMR job run reading the producer's published JAR by S3 URI. `dependsOn: ["jar-lib"]` orders the producer first; the graph resolves the reference into the Submit step. */
|
|
50
|
+
export const emrJob: Component = {
|
|
51
|
+
name: "emr-job",
|
|
52
|
+
archetype: "infra",
|
|
53
|
+
dependsOn: ["jar-lib"],
|
|
54
|
+
deploy: [
|
|
55
|
+
phase("Submit", [
|
|
56
|
+
{
|
|
57
|
+
kind: "emr-start-job-run",
|
|
58
|
+
jar: "@jar-lib.publish.uri",
|
|
59
|
+
args: ["--input", "$env.inputPath", "--output", "$env.outputPath"],
|
|
60
|
+
// A submitted EMR job run has no automatic "undo": stopping a
|
|
61
|
+
// running/completed job is not the same as reverting whatever it
|
|
62
|
+
// already wrote, so compensation is a human/runbook decision, not a
|
|
63
|
+
// mechanical capability rollback — see COMP003 (lint-rules/composition.mdx).
|
|
64
|
+
noRollback: "a submitted job run has no automatic undo; cancelling it does not revert data it already wrote",
|
|
65
|
+
},
|
|
66
|
+
]),
|
|
67
|
+
phase("Verify", [{ kind: "wait-job", runId: "@Submit.runId" }]),
|
|
68
|
+
],
|
|
69
|
+
};
|