@intentius/chant 0.13.1 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +45 -5
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/proof.d.ts +3 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +4 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts +3 -0
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +8 -2
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts +39 -0
- package/dist/cli/handlers/components.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts +3 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts +4 -2
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +35 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +22 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.d.ts +110 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -0
- package/dist/codegen/pinned-upgrade.d.ts +153 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
- package/dist/codegen/rolling-upgrade.d.ts +138 -0
- package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
- package/dist/codegen/surface-snapshot.d.ts +173 -0
- package/dist/codegen/surface-snapshot.d.ts.map +1 -0
- package/dist/codegen/version-bump.d.ts +21 -0
- package/dist/codegen/version-bump.d.ts.map +1 -0
- package/dist/components/auto-release.d.ts +93 -0
- package/dist/components/auto-release.d.ts.map +1 -0
- package/dist/components/builders.d.ts +37 -0
- package/dist/components/builders.d.ts.map +1 -0
- package/dist/components/capability-plugin-loader.d.ts +111 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -0
- package/dist/components/capability-plugin-schema.d.ts +24 -0
- package/dist/components/capability-plugin-schema.d.ts.map +1 -0
- package/dist/components/capability-plugin.d.ts +85 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/components/capability.d.ts +89 -0
- package/dist/components/capability.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +204 -0
- package/dist/components/cli-support.d.ts.map +1 -0
- package/dist/components/component.d.ts +179 -0
- package/dist/components/component.d.ts.map +1 -0
- package/dist/components/config-defaults.d.ts +41 -0
- package/dist/components/config-defaults.d.ts.map +1 -0
- package/dist/components/discover.d.ts +60 -0
- package/dist/components/discover.d.ts.map +1 -0
- package/dist/components/driver-output.d.ts +20 -0
- package/dist/components/driver-output.d.ts.map +1 -0
- package/dist/components/driver.d.ts +209 -0
- package/dist/components/driver.d.ts.map +1 -0
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/manifest-persistence.d.ts +79 -0
- package/dist/components/manifest-persistence.d.ts.map +1 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
- package/dist/components/pilots/lambda.pilot.d.ts +35 -0
- package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
- package/dist/components/pilots/project.d.ts +13 -0
- package/dist/components/pilots/project.d.ts.map +1 -0
- package/dist/components/presets/ecs-fargate.d.ts +59 -0
- package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
- package/dist/components/presets/index.d.ts +29 -0
- package/dist/components/presets/index.d.ts.map +1 -0
- package/dist/components/presets/lambda.d.ts +35 -0
- package/dist/components/presets/lambda.d.ts.map +1 -0
- package/dist/components/presets/single-host-compose.d.ts +43 -0
- package/dist/components/presets/single-host-compose.d.ts.map +1 -0
- package/dist/components/registry.d.ts +29 -0
- package/dist/components/registry.d.ts.map +1 -0
- package/dist/components/starter-plugin.d.ts +51 -0
- package/dist/components/starter-plugin.d.ts.map +1 -0
- package/dist/components/temporal-codegen-loader.d.ts +27 -0
- package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/bom-writer.d.ts +155 -0
- package/dist/components/verbs/bom-writer.d.ts.map +1 -0
- package/dist/components/verbs/build-archive.d.ts +205 -0
- package/dist/components/verbs/build-archive.d.ts.map +1 -0
- package/dist/components/verbs/build.d.ts +150 -0
- package/dist/components/verbs/build.d.ts.map +1 -0
- package/dist/components/verbs/cloud-executor.d.ts +88 -0
- package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/component-bom.d.ts +103 -0
- package/dist/components/verbs/component-bom.d.ts.map +1 -0
- package/dist/components/verbs/index.d.ts +49 -0
- package/dist/components/verbs/index.d.ts.map +1 -0
- package/dist/components/verbs/license-policy.d.ts +56 -0
- package/dist/components/verbs/license-policy.d.ts.map +1 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/process-runner.d.ts +64 -0
- package/dist/components/verbs/process-runner.d.ts.map +1 -0
- package/dist/components/verbs/reproducibility.d.ts +80 -0
- package/dist/components/verbs/reproducibility.d.ts.map +1 -0
- package/dist/components/verbs/sbom-generator.d.ts +157 -0
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/sbom.d.ts +79 -0
- package/dist/components/verbs/sbom.d.ts.map +1 -0
- package/dist/components/verbs/shell.d.ts +35 -0
- package/dist/components/verbs/shell.d.ts.map +1 -0
- package/dist/components/verbs/sign.d.ts +222 -0
- package/dist/components/verbs/sign.d.ts.map +1 -0
- package/dist/components/verbs/stub.d.ts +18 -0
- package/dist/components/verbs/stub.d.ts.map +1 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/verify.d.ts +106 -0
- package/dist/components/verbs/verify.d.ts.map +1 -0
- package/dist/components/verbs/vex.d.ts +65 -0
- package/dist/components/verbs/vex.d.ts.map +1 -0
- package/dist/components/verbs/vuln-gate.d.ts +91 -0
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
- package/dist/components/verbs/vuln-scan.d.ts +116 -0
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
- package/dist/components/verbs/wait-verify.d.ts +85 -0
- package/dist/components/verbs/wait-verify.d.ts.map +1 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +78 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts +121 -0
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
- package/dist/lifecycle/build-ledger.d.ts +225 -0
- package/dist/lifecycle/build-ledger.d.ts.map +1 -0
- package/dist/lifecycle/git.d.ts +84 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +5 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
- package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
- package/dist/lifecycle/release-ledger.d.ts +122 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -0
- package/dist/lifecycle/status.d.ts +150 -0
- package/dist/lifecycle/status.d.ts.map +1 -0
- package/dist/lint/component-checks.d.ts +95 -0
- package/dist/lint/component-checks.d.ts.map +1 -0
- package/dist/lint/engine.d.ts +23 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/presets/strict.json +8 -1
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +18 -0
- package/dist/lint/rules/comp/index.d.ts.map +1 -0
- package/dist/lint/rules/comp/support.d.ts +71 -0
- package/dist/lint/rules/comp/support.d.ts.map +1 -0
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activity-registry.d.ts +11 -6
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +24 -0
- package/dist/op/activity-runtime.d.ts.map +1 -0
- package/dist/op/builders.d.ts +59 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/ownership.d.ts +20 -14
- package/dist/ownership.d.ts.map +1 -1
- package/package.json +14 -1
- package/src/audit/catalog.test.ts +74 -22
- package/src/audit/catalog.ts +74 -471
- package/src/audit/proof.ts +4 -2
- package/src/audit/report-html.test.ts +14 -7
- package/src/audit/report-model.ts +20 -9
- package/src/audit/report.test.ts +36 -13
- package/src/audit/report.ts +2 -0
- package/src/audit/rules-doc.test.ts +8 -6
- package/src/audit/rules-doc.ts +13 -5
- package/src/cli/commands/audit.ts +23 -18
- package/src/cli/commands/component-lint.test.ts +158 -0
- package/src/cli/commands/doctor.test.ts +116 -2
- package/src/cli/commands/doctor.ts +46 -0
- package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
- package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
- package/src/cli/commands/lexicon-surface-diff.ts +185 -0
- package/src/cli/commands/lint.ts +142 -1
- package/src/cli/commands/pinned-upgrade.ts +204 -0
- package/src/cli/handlers/build.ts +58 -1
- package/src/cli/handlers/components.test.ts +504 -0
- package/src/cli/handlers/components.ts +404 -0
- package/src/cli/handlers/dev.ts +60 -1
- package/src/cli/handlers/graph.ts +47 -2
- package/src/cli/handlers/misc.ts +45 -1
- package/src/cli/handlers/run.test.ts +967 -3
- package/src/cli/handlers/run.ts +618 -11
- package/src/cli/main.test.ts +66 -0
- package/src/cli/main.ts +105 -2
- package/src/cli/registry.ts +35 -0
- package/src/codegen/fetch.test.ts +84 -3
- package/src/codegen/fetch.ts +76 -2
- package/src/codegen/lexicon-regen.test.ts +298 -0
- package/src/codegen/lexicon-regen.ts +545 -0
- package/src/codegen/pinned-upgrade.test.ts +399 -0
- package/src/codegen/pinned-upgrade.ts +423 -0
- package/src/codegen/rolling-upgrade.test.ts +333 -0
- package/src/codegen/rolling-upgrade.ts +320 -0
- package/src/codegen/surface-snapshot.test.ts +461 -0
- package/src/codegen/surface-snapshot.ts +546 -0
- package/src/codegen/version-bump.test.ts +47 -0
- package/src/codegen/version-bump.ts +39 -0
- package/src/components/README.md +130 -0
- package/src/components/SPRAWL-VALIDATION.md +181 -0
- package/src/components/__fixtures__/alb-ecs-service.json +51 -0
- package/src/components/__fixtures__/dynamodb-infra.json +32 -0
- package/src/components/__fixtures__/emr-job-consumer.json +26 -0
- package/src/components/__fixtures__/jar-lib-producer.json +16 -0
- package/src/components/__fixtures__/lambda-image-processor.json +28 -0
- package/src/components/__fixtures__/neo4j-fanout.json +34 -0
- package/src/components/__fixtures__/single-host-compose.json +29 -0
- package/src/components/auto-release.test.ts +217 -0
- package/src/components/auto-release.ts +216 -0
- package/src/components/builders.test.ts +45 -0
- package/src/components/builders.ts +71 -0
- package/src/components/capability-plugin-loader.ts +218 -0
- package/src/components/capability-plugin-schema.ts +56 -0
- package/src/components/capability-plugin.test.ts +235 -0
- package/src/components/capability-plugin.ts +108 -0
- package/src/components/capability.ts +117 -0
- package/src/components/cli-support.test.ts +579 -0
- package/src/components/cli-support.ts +481 -0
- package/src/components/component-schema.test.ts +265 -0
- package/src/components/component.schema.json +235 -0
- package/src/components/component.test.ts +251 -0
- package/src/components/component.ts +255 -0
- package/src/components/config-defaults.test.ts +263 -0
- package/src/components/config-defaults.ts +145 -0
- package/src/components/discover.test.ts +352 -0
- package/src/components/discover.ts +167 -0
- package/src/components/driver-output.ts +71 -0
- package/src/components/driver.test.ts +638 -0
- package/src/components/driver.ts +690 -0
- package/src/components/index.ts +113 -0
- package/src/components/manifest-persistence.test.ts +152 -0
- package/src/components/manifest-persistence.ts +164 -0
- package/src/components/pilots/README.md +33 -0
- package/src/components/pilots/alb-ecs.pilot.ts +63 -0
- package/src/components/pilots/dynamodb.pilot.ts +59 -0
- package/src/components/pilots/jar-emr.pilot.ts +69 -0
- package/src/components/pilots/lambda.pilot.ts +55 -0
- package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
- package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
- package/src/components/pilots/pilots.test.ts +126 -0
- package/src/components/pilots/project.ts +13 -0
- package/src/components/presets/comp007-reduction.test.ts +122 -0
- package/src/components/presets/ecs-fargate.test.ts +84 -0
- package/src/components/presets/ecs-fargate.ts +103 -0
- package/src/components/presets/index.ts +32 -0
- package/src/components/presets/lambda.test.ts +35 -0
- package/src/components/presets/lambda.ts +53 -0
- package/src/components/presets/single-host-compose.test.ts +65 -0
- package/src/components/presets/single-host-compose.ts +64 -0
- package/src/components/registry.test.ts +112 -0
- package/src/components/registry.ts +37 -0
- package/src/components/starter-plugin.ts +105 -0
- package/src/components/temporal-codegen-loader.ts +41 -0
- package/src/components/verbs/__fixtures__/package-lock.json +45 -0
- package/src/components/verbs/__fixtures__/pom.xml +37 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
- package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
- package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
- package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
- package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
- package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
- package/src/components/verbs/bom-writer.test.ts +331 -0
- package/src/components/verbs/bom-writer.ts +386 -0
- package/src/components/verbs/build-archive.test.ts +251 -0
- package/src/components/verbs/build-archive.ts +296 -0
- package/src/components/verbs/build.test.ts +222 -0
- package/src/components/verbs/build.ts +252 -0
- package/src/components/verbs/cloud-executor.ts +181 -0
- package/src/components/verbs/component-bom.test.ts +219 -0
- package/src/components/verbs/component-bom.ts +189 -0
- package/src/components/verbs/index.ts +49 -0
- package/src/components/verbs/license-policy.ts +115 -0
- package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
- package/src/components/verbs/process-runner.test.ts +79 -0
- package/src/components/verbs/process-runner.ts +113 -0
- package/src/components/verbs/reproducibility.test.ts +24 -0
- package/src/components/verbs/reproducibility.ts +100 -0
- package/src/components/verbs/sbom-generator.test.ts +96 -0
- package/src/components/verbs/sbom-generator.ts +209 -0
- package/src/components/verbs/sbom.test.ts +184 -0
- package/src/components/verbs/sbom.ts +152 -0
- package/src/components/verbs/shell.test.ts +36 -0
- package/src/components/verbs/shell.ts +51 -0
- package/src/components/verbs/sign.test.ts +210 -0
- package/src/components/verbs/sign.ts +350 -0
- package/src/components/verbs/stub.ts +34 -0
- package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
- package/src/components/verbs/tool-sbom-generator.ts +192 -0
- package/src/components/verbs/verify.test.ts +159 -0
- package/src/components/verbs/verify.ts +179 -0
- package/src/components/verbs/vex.ts +182 -0
- package/src/components/verbs/vuln-gate.test.ts +201 -0
- package/src/components/verbs/vuln-gate.ts +170 -0
- package/src/components/verbs/vuln-scan.test.ts +145 -0
- package/src/components/verbs/vuln-scan.ts +266 -0
- package/src/components/verbs/wait-verify.test.ts +111 -0
- package/src/components/verbs/wait-verify.ts +171 -0
- package/src/config.test.ts +74 -1
- package/src/config.ts +219 -0
- package/src/index.ts +32 -0
- package/src/lexicon.ts +88 -0
- package/src/lifecycle/build-ledger-store.test.ts +217 -0
- package/src/lifecycle/build-ledger-store.ts +165 -0
- package/src/lifecycle/build-ledger.test.ts +349 -0
- package/src/lifecycle/build-ledger.ts +305 -0
- package/src/lifecycle/git.test.ts +118 -0
- package/src/lifecycle/git.ts +149 -14
- package/src/lifecycle/index.ts +5 -0
- package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
- package/src/lifecycle/oras-referrer-lookup.ts +110 -0
- package/src/lifecycle/release-ledger.test.ts +209 -0
- package/src/lifecycle/release-ledger.ts +185 -0
- package/src/lifecycle/status.test.ts +330 -0
- package/src/lifecycle/status.ts +278 -0
- package/src/lint/component-checks.ts +148 -0
- package/src/lint/config.test.ts +21 -0
- package/src/lint/engine.ts +11 -2
- package/src/lint/presets/relaxed.json +8 -1
- package/src/lint/presets/strict.json +8 -1
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
- package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
- package/src/lint/rules/comp/comp.test.ts +378 -0
- package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
- package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
- package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
- package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
- package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
- package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
- package/src/lint/rules/comp/index.ts +37 -0
- package/src/lint/rules/comp/support.ts +173 -0
- package/src/lsp/lexicon-providers.test.ts +55 -0
- package/src/lsp/lexicon-providers.ts +13 -3
- package/src/op/activity-registry.test.ts +38 -0
- package/src/op/activity-registry.ts +31 -12
- package/src/op/activity-runtime.ts +73 -0
- package/src/op/builders.ts +99 -0
- package/src/op/index.ts +3 -1
- package/src/ownership.test.ts +24 -26
- package/src/ownership.ts +26 -38
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
import { tmpdir } from "os";
|
|
5
|
+
import {
|
|
6
|
+
checkRollingUpgrade,
|
|
7
|
+
classifyDelta,
|
|
8
|
+
diffRollingSurface,
|
|
9
|
+
computeAzureApiVersionDelta,
|
|
10
|
+
extractAzureProvider,
|
|
11
|
+
diffAzureApiVersions,
|
|
12
|
+
} from "./rolling-upgrade";
|
|
13
|
+
import type { SurfaceSnapshot } from "./surface-snapshot";
|
|
14
|
+
import type { RegenResult, RegenOptions } from "./lexicon-regen";
|
|
15
|
+
import { diffSurface } from "./surface-snapshot";
|
|
16
|
+
|
|
17
|
+
// ── Fixture snapshots ─────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
function baselineAws(): SurfaceSnapshot {
|
|
20
|
+
return {
|
|
21
|
+
schemaVersion: 1,
|
|
22
|
+
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
23
|
+
entries: {
|
|
24
|
+
Bucket: {
|
|
25
|
+
kind: "resource",
|
|
26
|
+
resourceType: "AWS::S3::Bucket",
|
|
27
|
+
attrs: ["Arn"],
|
|
28
|
+
props: ["BucketName:false", "Tags:false"],
|
|
29
|
+
taggable: true,
|
|
30
|
+
},
|
|
31
|
+
Bucket_Tag: { kind: "property", resourceType: "AWS::S3::Bucket.Tag" },
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Adds a new resource → additive upgrade. */
|
|
37
|
+
function freshAwsAdditive(): SurfaceSnapshot {
|
|
38
|
+
const s = baselineAws();
|
|
39
|
+
s.entries.Table = {
|
|
40
|
+
kind: "resource",
|
|
41
|
+
resourceType: "AWS::DynamoDB::Table",
|
|
42
|
+
attrs: ["Arn"],
|
|
43
|
+
props: ["TableName:false"],
|
|
44
|
+
taggable: true,
|
|
45
|
+
};
|
|
46
|
+
return s;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Removes a resource → breaking upgrade. */
|
|
50
|
+
function freshAwsBreaking(): SurfaceSnapshot {
|
|
51
|
+
const s = baselineAws();
|
|
52
|
+
delete s.entries.Bucket_Tag;
|
|
53
|
+
return s;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function azureBaseline(): SurfaceSnapshot {
|
|
57
|
+
return {
|
|
58
|
+
schemaVersion: 1,
|
|
59
|
+
generatedAt: "2026-01-01T00:00:00.000Z",
|
|
60
|
+
entries: {
|
|
61
|
+
StorageAccount: {
|
|
62
|
+
kind: "resource",
|
|
63
|
+
resourceType: "Microsoft.Storage/storageAccounts",
|
|
64
|
+
props: ["name:true"],
|
|
65
|
+
},
|
|
66
|
+
VirtualMachine: {
|
|
67
|
+
kind: "resource",
|
|
68
|
+
resourceType: "Microsoft.Compute/virtualMachines",
|
|
69
|
+
props: ["name:true"],
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Adds a resource from a brand-new provider. */
|
|
76
|
+
function azureFreshNewProvider(): SurfaceSnapshot {
|
|
77
|
+
const s = azureBaseline();
|
|
78
|
+
s.entries.Vault = {
|
|
79
|
+
kind: "resource",
|
|
80
|
+
resourceType: "Microsoft.KeyVault/vaults",
|
|
81
|
+
props: ["name:true"],
|
|
82
|
+
};
|
|
83
|
+
return s;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// ── Mock regen ────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
function makeRegen(
|
|
89
|
+
fresh: SurfaceSnapshot | null,
|
|
90
|
+
baseline: SurfaceSnapshot,
|
|
91
|
+
ok = true,
|
|
92
|
+
): (opts: RegenOptions) => Promise<RegenResult> {
|
|
93
|
+
return async () => {
|
|
94
|
+
const delta = fresh
|
|
95
|
+
? diffSurface(baseline, fresh)
|
|
96
|
+
: { added: [], changed: [], removed: [], severity: "none" as const };
|
|
97
|
+
const changed =
|
|
98
|
+
delta.added.length > 0 || delta.changed.length > 0 || delta.removed.length > 0;
|
|
99
|
+
return {
|
|
100
|
+
ok,
|
|
101
|
+
changed,
|
|
102
|
+
severity: delta.severity,
|
|
103
|
+
delta,
|
|
104
|
+
deltaText: changed ? "delta" : "",
|
|
105
|
+
failures: ok ? [] : [{ step: "generate", output: "boom" }],
|
|
106
|
+
freshSnapshot: fresh,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── Test dir helper ───────────────────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
/** Create a fake lexicon dir with a package.json and committed baseline snapshot. */
|
|
114
|
+
function makeLexiconDir(name: string, baseline: SurfaceSnapshot): string {
|
|
115
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-rolling-"));
|
|
116
|
+
writeFileSync(
|
|
117
|
+
join(dir, "package.json"),
|
|
118
|
+
JSON.stringify({ name: `@intentius/chant-lexicon-${name}` }),
|
|
119
|
+
);
|
|
120
|
+
writeFileSync(join(dir, "surface.snapshot.json"), JSON.stringify(baseline, null, 2));
|
|
121
|
+
mkdirSync(join(dir, "src", "generated"), { recursive: true });
|
|
122
|
+
return dir;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── classifyDelta (pure) ──────────────────────────────────────────────
|
|
126
|
+
|
|
127
|
+
describe("classifyDelta", () => {
|
|
128
|
+
test("unchanged surface → no upgrade, none severity", () => {
|
|
129
|
+
const delta = diffRollingSurface(baselineAws(), baselineAws());
|
|
130
|
+
expect(classifyDelta(delta)).toEqual({ hasUpgrade: false, severity: "none" });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("added resource → upgrade, additive severity", () => {
|
|
134
|
+
const delta = diffRollingSurface(baselineAws(), freshAwsAdditive());
|
|
135
|
+
expect(classifyDelta(delta)).toEqual({ hasUpgrade: true, severity: "additive" });
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
test("removed resource → upgrade, breaking severity", () => {
|
|
139
|
+
const delta = diffRollingSurface(baselineAws(), freshAwsBreaking());
|
|
140
|
+
const c = classifyDelta(delta);
|
|
141
|
+
expect(c.hasUpgrade).toBe(true);
|
|
142
|
+
expect(c.severity).toBe("breaking");
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// ── checkRollingUpgrade (mocked regen) ────────────────────────────────
|
|
147
|
+
|
|
148
|
+
describe("checkRollingUpgrade — surface changed vs unchanged", () => {
|
|
149
|
+
test("unchanged surface → hasUpgrade false", async () => {
|
|
150
|
+
const dir = makeLexiconDir("aws", baselineAws());
|
|
151
|
+
try {
|
|
152
|
+
const res = await checkRollingUpgrade({
|
|
153
|
+
lexiconDir: dir,
|
|
154
|
+
_regenFn: makeRegen(baselineAws(), baselineAws()),
|
|
155
|
+
});
|
|
156
|
+
expect(res.lexicon).toBe("aws");
|
|
157
|
+
expect(res.hasUpgrade).toBe(false);
|
|
158
|
+
expect(res.severity).toBe("none");
|
|
159
|
+
expect(res.validationOk).toBe(true);
|
|
160
|
+
expect(res.deltaText).toBe("");
|
|
161
|
+
} finally {
|
|
162
|
+
rmSync(dir, { recursive: true, force: true });
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
test("additive surface change → hasUpgrade true, additive", async () => {
|
|
167
|
+
const dir = makeLexiconDir("aws", baselineAws());
|
|
168
|
+
try {
|
|
169
|
+
const res = await checkRollingUpgrade({
|
|
170
|
+
lexiconDir: dir,
|
|
171
|
+
_regenFn: makeRegen(freshAwsAdditive(), baselineAws()),
|
|
172
|
+
});
|
|
173
|
+
expect(res.hasUpgrade).toBe(true);
|
|
174
|
+
expect(res.severity).toBe("additive");
|
|
175
|
+
expect(res.delta.added.map((a) => a.name)).toContain("Table");
|
|
176
|
+
expect(res.deltaText).not.toBe("");
|
|
177
|
+
} finally {
|
|
178
|
+
rmSync(dir, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("breaking surface change → hasUpgrade true, breaking", async () => {
|
|
183
|
+
const dir = makeLexiconDir("aws", baselineAws());
|
|
184
|
+
try {
|
|
185
|
+
const res = await checkRollingUpgrade({
|
|
186
|
+
lexiconDir: dir,
|
|
187
|
+
_regenFn: makeRegen(freshAwsBreaking(), baselineAws()),
|
|
188
|
+
});
|
|
189
|
+
expect(res.hasUpgrade).toBe(true);
|
|
190
|
+
expect(res.severity).toBe("breaking");
|
|
191
|
+
expect(res.delta.removed.map((r) => r.name)).toContain("Bucket_Tag");
|
|
192
|
+
} finally {
|
|
193
|
+
rmSync(dir, { recursive: true, force: true });
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("failed regen surfaces validationOk=false and failures", async () => {
|
|
198
|
+
const dir = makeLexiconDir("aws", baselineAws());
|
|
199
|
+
try {
|
|
200
|
+
const res = await checkRollingUpgrade({
|
|
201
|
+
lexiconDir: dir,
|
|
202
|
+
_regenFn: makeRegen(freshAwsAdditive(), baselineAws(), false),
|
|
203
|
+
});
|
|
204
|
+
expect(res.validationOk).toBe(false);
|
|
205
|
+
expect(res.failures.length).toBeGreaterThan(0);
|
|
206
|
+
// Still reports the delta so the failure carries the diff
|
|
207
|
+
expect(res.hasUpgrade).toBe(true);
|
|
208
|
+
} finally {
|
|
209
|
+
rmSync(dir, { recursive: true, force: true });
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// ── azure lexicon detection + apiVersionDelta ─────────────────────────
|
|
215
|
+
|
|
216
|
+
describe("checkRollingUpgrade — azure", () => {
|
|
217
|
+
test("detects azure lexicon by package name", async () => {
|
|
218
|
+
const dir = makeLexiconDir("azure", azureBaseline());
|
|
219
|
+
try {
|
|
220
|
+
const res = await checkRollingUpgrade({
|
|
221
|
+
lexiconDir: dir,
|
|
222
|
+
_regenFn: makeRegen(azureBaseline(), azureBaseline()),
|
|
223
|
+
});
|
|
224
|
+
expect(res.lexicon).toBe("azure");
|
|
225
|
+
} finally {
|
|
226
|
+
rmSync(dir, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("new provider shows up in apiVersionDelta", async () => {
|
|
231
|
+
const dir = makeLexiconDir("azure", azureBaseline());
|
|
232
|
+
try {
|
|
233
|
+
const res = await checkRollingUpgrade({
|
|
234
|
+
lexiconDir: dir,
|
|
235
|
+
_regenFn: makeRegen(azureFreshNewProvider(), azureBaseline()),
|
|
236
|
+
});
|
|
237
|
+
expect(res.hasUpgrade).toBe(true);
|
|
238
|
+
const kv = res.apiVersionDelta.find((c) => c.provider === "Microsoft.KeyVault");
|
|
239
|
+
expect(kv).toBeDefined();
|
|
240
|
+
expect(kv!.kind).toBe("added");
|
|
241
|
+
} finally {
|
|
242
|
+
rmSync(dir, { recursive: true, force: true });
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
test("aws has empty apiVersionDelta", async () => {
|
|
247
|
+
const dir = makeLexiconDir("aws", baselineAws());
|
|
248
|
+
try {
|
|
249
|
+
const res = await checkRollingUpgrade({
|
|
250
|
+
lexiconDir: dir,
|
|
251
|
+
_regenFn: makeRegen(freshAwsAdditive(), baselineAws()),
|
|
252
|
+
});
|
|
253
|
+
expect(res.apiVersionDelta).toEqual([]);
|
|
254
|
+
} finally {
|
|
255
|
+
rmSync(dir, { recursive: true, force: true });
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// ── extractAzureProvider (pure) ───────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
describe("extractAzureProvider", () => {
|
|
263
|
+
test("extracts provider from resourceType", () => {
|
|
264
|
+
expect(extractAzureProvider("Microsoft.Storage/storageAccounts")).toBe("Microsoft.Storage");
|
|
265
|
+
expect(extractAzureProvider("Microsoft.Compute/virtualMachines/extensions")).toBe(
|
|
266
|
+
"Microsoft.Compute",
|
|
267
|
+
);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test("returns null for non-ARM types", () => {
|
|
271
|
+
expect(extractAzureProvider("AWS::S3::Bucket")).toBeNull();
|
|
272
|
+
expect(extractAzureProvider("")).toBeNull();
|
|
273
|
+
expect(extractAzureProvider("Microsoft.Storage")).toBeNull();
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
// ── computeAzureApiVersionDelta (pure) ────────────────────────────────
|
|
278
|
+
|
|
279
|
+
describe("computeAzureApiVersionDelta", () => {
|
|
280
|
+
test("reports added and removed providers", () => {
|
|
281
|
+
const delta = computeAzureApiVersionDelta(azureBaseline(), azureFreshNewProvider());
|
|
282
|
+
expect(delta).toHaveLength(1);
|
|
283
|
+
expect(delta[0]).toMatchObject({ provider: "Microsoft.KeyVault", kind: "added" });
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test("no change when providers identical", () => {
|
|
287
|
+
expect(computeAzureApiVersionDelta(azureBaseline(), azureBaseline())).toEqual([]);
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
test("reports removed provider", () => {
|
|
291
|
+
const shrunk: SurfaceSnapshot = {
|
|
292
|
+
...azureBaseline(),
|
|
293
|
+
entries: { StorageAccount: azureBaseline().entries.StorageAccount },
|
|
294
|
+
};
|
|
295
|
+
const delta = computeAzureApiVersionDelta(azureBaseline(), shrunk);
|
|
296
|
+
expect(delta).toEqual([
|
|
297
|
+
{ provider: "Microsoft.Compute", before: "latest", after: null, kind: "removed" },
|
|
298
|
+
]);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
// ── diffAzureApiVersions (pure) ───────────────────────────────────────
|
|
303
|
+
|
|
304
|
+
describe("diffAzureApiVersions", () => {
|
|
305
|
+
test("detects version bump as updated", () => {
|
|
306
|
+
const base = new Map([["Microsoft.Compute", "2022-03-01"]]);
|
|
307
|
+
const fresh = new Map([["Microsoft.Compute", "2023-07-01"]]);
|
|
308
|
+
const delta = diffAzureApiVersions(base, fresh);
|
|
309
|
+
expect(delta).toEqual([
|
|
310
|
+
{
|
|
311
|
+
provider: "Microsoft.Compute",
|
|
312
|
+
before: "2022-03-01",
|
|
313
|
+
after: "2023-07-01",
|
|
314
|
+
kind: "updated",
|
|
315
|
+
},
|
|
316
|
+
]);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
test("detects added and removed providers", () => {
|
|
320
|
+
const base = new Map([["Microsoft.Old", "2020-01-01"]]);
|
|
321
|
+
const fresh = new Map([["Microsoft.New", "2024-01-01"]]);
|
|
322
|
+
const delta = diffAzureApiVersions(base, fresh);
|
|
323
|
+
expect(delta).toEqual([
|
|
324
|
+
{ provider: "Microsoft.New", before: null, after: "2024-01-01", kind: "added" },
|
|
325
|
+
{ provider: "Microsoft.Old", before: "2020-01-01", after: null, kind: "removed" },
|
|
326
|
+
]);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
test("no change when versions identical", () => {
|
|
330
|
+
const m = new Map([["Microsoft.Storage", "2023-01-01"]]);
|
|
331
|
+
expect(diffAzureApiVersions(m, new Map(m))).toEqual([]);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rolling-spec drift detection for aws, azure, and github lexicons.
|
|
3
|
+
*
|
|
4
|
+
* These lexicons have no pinned version constant — "latest" is fetched on every
|
|
5
|
+
* regen. An upgrade means regenerating from current-latest and diffing the
|
|
6
|
+
* produced API surface against the committed baseline (surface.snapshot.json).
|
|
7
|
+
* If the surface changed and validation passed, a PR can be opened with the
|
|
8
|
+
* delta as the review payload.
|
|
9
|
+
*
|
|
10
|
+
* This module contains only pure business logic (detecting drift, classifying
|
|
11
|
+
* it, formatting the report). It calls regenLexicon from #524 for the actual
|
|
12
|
+
* regen/validate work, and never runs a live regen itself.
|
|
13
|
+
*
|
|
14
|
+
* azure extra delta:
|
|
15
|
+
* The Azure regen depends on `latestVersionPerProvider`, which picks one API
|
|
16
|
+
* version per ARM provider. When new providers appear or existing ones get a
|
|
17
|
+
* newer GA/preview version, that shows up in the surface diff. In addition,
|
|
18
|
+
* this module computes an `apiVersionDelta` to surface those version changes
|
|
19
|
+
* separately, so reviewers can see "Microsoft.Compute moved 2022-03-01 →
|
|
20
|
+
* 2023-07-01" without reading the raw surface diff.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { existsSync, readFileSync } from "fs";
|
|
24
|
+
import { join } from "path";
|
|
25
|
+
import {
|
|
26
|
+
diffSurface,
|
|
27
|
+
formatDelta,
|
|
28
|
+
parseSnapshot,
|
|
29
|
+
type SurfaceDelta,
|
|
30
|
+
type ChangeSeverity,
|
|
31
|
+
type SurfaceSnapshot,
|
|
32
|
+
} from "./surface-snapshot";
|
|
33
|
+
import { regenLexicon, SNAPSHOT_FILENAME, type RegenOptions, type RegenResult } from "./lexicon-regen";
|
|
34
|
+
|
|
35
|
+
// ── Public types ──────────────────────────────────────────────────────
|
|
36
|
+
|
|
37
|
+
export type RollingLexicon = "aws" | "azure" | "github";
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* An API-version change for one Azure ARM provider.
|
|
41
|
+
* Only populated for the azure lexicon.
|
|
42
|
+
*/
|
|
43
|
+
export interface AzureApiVersionChange {
|
|
44
|
+
provider: string;
|
|
45
|
+
before: string | null;
|
|
46
|
+
after: string | null;
|
|
47
|
+
/** "added" when provider is new; "updated" when version bumped; "removed" when gone. */
|
|
48
|
+
kind: "added" | "updated" | "removed";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The result of a rolling-upgrade check for one lexicon.
|
|
53
|
+
*/
|
|
54
|
+
export interface RollingUpgradeResult {
|
|
55
|
+
/** Lexicon identifier. */
|
|
56
|
+
lexicon: RollingLexicon;
|
|
57
|
+
/** True when the surface changed versus the committed baseline. */
|
|
58
|
+
hasUpgrade: boolean;
|
|
59
|
+
/** Severity of the surface delta. "none" when the surface is unchanged. */
|
|
60
|
+
severity: ChangeSeverity;
|
|
61
|
+
/** Structured surface delta. */
|
|
62
|
+
delta: SurfaceDelta;
|
|
63
|
+
/** Human-readable delta text. Empty when no changes. */
|
|
64
|
+
deltaText: string;
|
|
65
|
+
/** Whether regen+validation passed. False means the delta is unreliable. */
|
|
66
|
+
validationOk: boolean;
|
|
67
|
+
/** Failures captured during regen. */
|
|
68
|
+
failures: RegenResult["failures"];
|
|
69
|
+
/** azure-only: per-provider API version changes. Empty for aws/github. */
|
|
70
|
+
apiVersionDelta: AzureApiVersionChange[];
|
|
71
|
+
/** The fresh snapshot produced by the regen. Null when regen failed. */
|
|
72
|
+
freshSnapshot: SurfaceSnapshot | null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Options for checkRollingUpgrade.
|
|
77
|
+
*/
|
|
78
|
+
export interface CheckRollingUpgradeOptions {
|
|
79
|
+
/** Root of the lexicon package (must contain package.json and surface.snapshot.json). */
|
|
80
|
+
lexiconDir: string;
|
|
81
|
+
/** Force re-fetch of the upstream spec (bypass cache). Default: false. */
|
|
82
|
+
force?: boolean;
|
|
83
|
+
/** Print subprocess output while running. Default: false. */
|
|
84
|
+
verbose?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Override for the regen function — inject a mock in tests.
|
|
87
|
+
* Defaults to the production regenLexicon.
|
|
88
|
+
*/
|
|
89
|
+
_regenFn?: (opts: RegenOptions) => Promise<RegenResult>;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ── Main entry ────────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Check whether the rolling spec has drifted since the committed baseline.
|
|
96
|
+
*
|
|
97
|
+
* Calls regenLexicon (from #524) to regenerate from current-latest, then diffs
|
|
98
|
+
* the resulting surface against the committed surface.snapshot.json. Returns
|
|
99
|
+
* hasUpgrade=true when the surface changed and validation passed.
|
|
100
|
+
*
|
|
101
|
+
* For azure, also computes an apiVersionDelta showing which ARM providers gained
|
|
102
|
+
* a new latest API version since the baseline was snapshotted.
|
|
103
|
+
*
|
|
104
|
+
* Never throws — all failures are captured in the result.
|
|
105
|
+
*/
|
|
106
|
+
export async function checkRollingUpgrade(
|
|
107
|
+
opts: CheckRollingUpgradeOptions,
|
|
108
|
+
): Promise<RollingUpgradeResult> {
|
|
109
|
+
const {
|
|
110
|
+
lexiconDir,
|
|
111
|
+
force = false,
|
|
112
|
+
verbose = false,
|
|
113
|
+
_regenFn = regenLexicon,
|
|
114
|
+
} = opts;
|
|
115
|
+
|
|
116
|
+
const lexicon = detectLexicon(lexiconDir);
|
|
117
|
+
|
|
118
|
+
const regenResult = await _regenFn({
|
|
119
|
+
lexiconDir,
|
|
120
|
+
force,
|
|
121
|
+
verbose,
|
|
122
|
+
skipBundle: false,
|
|
123
|
+
skipBuild: false,
|
|
124
|
+
skipLint: false,
|
|
125
|
+
skipExamples: true,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
const apiVersionDelta: AzureApiVersionChange[] = [];
|
|
129
|
+
|
|
130
|
+
if (lexicon === "azure" && regenResult.freshSnapshot) {
|
|
131
|
+
const baselinePath = join(lexiconDir, SNAPSHOT_FILENAME);
|
|
132
|
+
if (existsSync(baselinePath)) {
|
|
133
|
+
try {
|
|
134
|
+
const baselineJSON = readFileSync(baselinePath, "utf-8");
|
|
135
|
+
const baseline = parseSnapshot(baselineJSON);
|
|
136
|
+
apiVersionDelta.push(...computeAzureApiVersionDelta(baseline, regenResult.freshSnapshot));
|
|
137
|
+
} catch {
|
|
138
|
+
// Ignore — apiVersionDelta stays empty; the surface diff is still valid
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return buildResult(lexicon, regenResult, apiVersionDelta);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ── Lexicon detection ─────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Detect which rolling lexicon a directory belongs to by its package name.
|
|
150
|
+
* Falls back to directory-name matching.
|
|
151
|
+
*/
|
|
152
|
+
function detectLexicon(lexiconDir: string): RollingLexicon {
|
|
153
|
+
try {
|
|
154
|
+
const pkgPath = join(lexiconDir, "package.json");
|
|
155
|
+
if (existsSync(pkgPath)) {
|
|
156
|
+
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8")) as { name?: string };
|
|
157
|
+
const name = pkg.name ?? "";
|
|
158
|
+
if (name.includes("azure")) return "azure";
|
|
159
|
+
if (name.includes("github")) return "github";
|
|
160
|
+
}
|
|
161
|
+
} catch {
|
|
162
|
+
// Fall through to directory-based detection
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const normalized = lexiconDir.replace(/\\/g, "/");
|
|
166
|
+
if (/\/azure(\/|$)/.test(normalized)) return "azure";
|
|
167
|
+
if (/\/github(\/|$)/.test(normalized)) return "github";
|
|
168
|
+
return "aws";
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ── Azure API-version delta ───────────────────────────────────────────
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Compute provider-level additions and removals between two azure snapshots.
|
|
175
|
+
*
|
|
176
|
+
* The snapshot resourceType values for azure look like
|
|
177
|
+
* "Microsoft.Storage/storageAccounts". This function extracts the provider
|
|
178
|
+
* name (the part before the first "/") and reports which providers appeared,
|
|
179
|
+
* disappeared, or (when version strings are supplied via diffAzureApiVersions)
|
|
180
|
+
* bumped their API version.
|
|
181
|
+
*
|
|
182
|
+
* Use diffAzureApiVersions when you have access to actual API version strings
|
|
183
|
+
* (e.g. from the lexicon's latestVersionPerProvider output in a CI run).
|
|
184
|
+
*/
|
|
185
|
+
export function computeAzureApiVersionDelta(
|
|
186
|
+
baseline: SurfaceSnapshot,
|
|
187
|
+
fresh: SurfaceSnapshot,
|
|
188
|
+
): AzureApiVersionChange[] {
|
|
189
|
+
const baseProviders = new Set<string>();
|
|
190
|
+
const freshProviders = new Set<string>();
|
|
191
|
+
|
|
192
|
+
for (const entry of Object.values(baseline.entries)) {
|
|
193
|
+
const p = extractAzureProvider(entry.resourceType);
|
|
194
|
+
if (p) baseProviders.add(p);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
for (const entry of Object.values(fresh.entries)) {
|
|
198
|
+
const p = extractAzureProvider(entry.resourceType);
|
|
199
|
+
if (p) freshProviders.add(p);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
const changes: AzureApiVersionChange[] = [];
|
|
203
|
+
|
|
204
|
+
for (const p of freshProviders) {
|
|
205
|
+
if (!baseProviders.has(p)) {
|
|
206
|
+
changes.push({ provider: p, before: null, after: "latest", kind: "added" });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
for (const p of baseProviders) {
|
|
211
|
+
if (!freshProviders.has(p)) {
|
|
212
|
+
changes.push({ provider: p, before: "latest", after: null, kind: "removed" });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return changes.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Extract the Azure ARM provider name from a resourceType string.
|
|
221
|
+
*
|
|
222
|
+
* Input: "Microsoft.Storage/storageAccounts"
|
|
223
|
+
* Output: "Microsoft.Storage"
|
|
224
|
+
*
|
|
225
|
+
* Returns null for non-ARM resource types (e.g. empty string or non-Microsoft prefix).
|
|
226
|
+
*/
|
|
227
|
+
export function extractAzureProvider(resourceType: string): string | null {
|
|
228
|
+
if (!resourceType.startsWith("Microsoft.")) return null;
|
|
229
|
+
const slash = resourceType.indexOf("/");
|
|
230
|
+
if (slash === -1) return null;
|
|
231
|
+
return resourceType.slice(0, slash);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Diff actual API version strings per provider between two regen runs.
|
|
236
|
+
*
|
|
237
|
+
* Use this when the caller has access to the azure lexicon's
|
|
238
|
+
* latestVersionPerProvider output. Produces a richer delta that includes
|
|
239
|
+
* version bumps ("updated"), not just provider additions/removals.
|
|
240
|
+
*
|
|
241
|
+
* @param baseVersions Map<provider, apiVersion> from the previous regen.
|
|
242
|
+
* @param freshVersions Map<provider, apiVersion> from the current regen.
|
|
243
|
+
*/
|
|
244
|
+
export function diffAzureApiVersions(
|
|
245
|
+
baseVersions: Map<string, string>,
|
|
246
|
+
freshVersions: Map<string, string>,
|
|
247
|
+
): AzureApiVersionChange[] {
|
|
248
|
+
const changes: AzureApiVersionChange[] = [];
|
|
249
|
+
|
|
250
|
+
for (const [provider, freshVersion] of freshVersions) {
|
|
251
|
+
const baseVersion = baseVersions.get(provider) ?? null;
|
|
252
|
+
if (baseVersion === null) {
|
|
253
|
+
changes.push({ provider, before: null, after: freshVersion, kind: "added" });
|
|
254
|
+
} else if (baseVersion !== freshVersion) {
|
|
255
|
+
changes.push({ provider, before: baseVersion, after: freshVersion, kind: "updated" });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
for (const [provider, baseVersion] of baseVersions) {
|
|
260
|
+
if (!freshVersions.has(provider)) {
|
|
261
|
+
changes.push({ provider, before: baseVersion, after: null, kind: "removed" });
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return changes.sort((a, b) => a.provider.localeCompare(b.provider));
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── Pure decision functions ───────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Diff two surface snapshots.
|
|
272
|
+
*
|
|
273
|
+
* Pure function re-exported for callers that import rolling-upgrade and want to
|
|
274
|
+
* compute the delta without importing surface-snapshot directly.
|
|
275
|
+
*/
|
|
276
|
+
export function diffRollingSurface(
|
|
277
|
+
baseline: SurfaceSnapshot,
|
|
278
|
+
fresh: SurfaceSnapshot,
|
|
279
|
+
): SurfaceDelta {
|
|
280
|
+
return diffSurface(baseline, fresh);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Classify a delta as an upgrade and determine its severity.
|
|
285
|
+
*
|
|
286
|
+
* Pure function — no I/O. Unit-testable with fixture snapshots.
|
|
287
|
+
* Used by the CLI and the checkRollingUpgrade entry point.
|
|
288
|
+
*/
|
|
289
|
+
export function classifyDelta(delta: SurfaceDelta): {
|
|
290
|
+
hasUpgrade: boolean;
|
|
291
|
+
severity: ChangeSeverity;
|
|
292
|
+
} {
|
|
293
|
+
const hasUpgrade =
|
|
294
|
+
delta.added.length > 0 || delta.changed.length > 0 || delta.removed.length > 0;
|
|
295
|
+
return { hasUpgrade, severity: hasUpgrade ? delta.severity : "none" };
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// ── Result builder ────────────────────────────────────────────────────
|
|
299
|
+
|
|
300
|
+
function buildResult(
|
|
301
|
+
lexicon: RollingLexicon,
|
|
302
|
+
regenResult: RegenResult,
|
|
303
|
+
apiVersionDelta: AzureApiVersionChange[],
|
|
304
|
+
): RollingUpgradeResult {
|
|
305
|
+
const delta = regenResult.delta;
|
|
306
|
+
const { hasUpgrade, severity } = classifyDelta(delta);
|
|
307
|
+
const deltaText = hasUpgrade ? formatDelta(delta) : "";
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
lexicon,
|
|
311
|
+
hasUpgrade,
|
|
312
|
+
severity,
|
|
313
|
+
delta,
|
|
314
|
+
deltaText,
|
|
315
|
+
validationOk: regenResult.ok,
|
|
316
|
+
failures: regenResult.failures,
|
|
317
|
+
apiVersionDelta,
|
|
318
|
+
freshSnapshot: regenResult.freshSnapshot,
|
|
319
|
+
};
|
|
320
|
+
}
|