@intentius/chant 0.124.52 → 0.124.54
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/discover.d.ts.map +1 -1
- package/dist/audit/discover.js +3 -1
- package/dist/behaviour.d.ts +1 -1
- package/dist/behaviour.d.ts.map +1 -1
- package/dist/capabilities/templates.d.ts +65 -0
- package/dist/capabilities/templates.d.ts.map +1 -0
- package/dist/capabilities/templates.js +193 -0
- package/dist/capabilities/templates.json +145 -0
- package/dist/change-set-graph.d.ts +35 -3
- package/dist/change-set-graph.d.ts.map +1 -1
- package/dist/change-set-graph.js +60 -9
- package/dist/change-set.d.ts +65 -7
- package/dist/change-set.d.ts.map +1 -1
- package/dist/change-set.js +23 -12
- package/dist/ci-identity.d.ts +7 -2
- package/dist/ci-identity.d.ts.map +1 -1
- package/dist/ci-identity.js +4 -1
- package/dist/cli/commands/import-index.d.ts +52 -0
- package/dist/cli/commands/import-index.d.ts.map +1 -0
- package/dist/cli/commands/import-index.js +226 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +4 -2
- package/dist/cli/handlers/components.d.ts.map +1 -1
- package/dist/cli/handlers/components.js +11 -2
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +16 -3
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +22 -4
- package/dist/cli/handlers/index-cloud.d.ts +14 -0
- package/dist/cli/handlers/index-cloud.d.ts.map +1 -0
- package/dist/cli/handlers/index-cloud.js +22 -0
- package/dist/cli/handlers/index-diff.d.ts +18 -0
- package/dist/cli/handlers/index-diff.d.ts.map +1 -0
- package/dist/cli/handlers/index-diff.js +142 -0
- package/dist/cli/handlers/lifecycle-drift.d.ts +25 -0
- package/dist/cli/handlers/lifecycle-drift.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-drift.js +64 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.js +188 -28
- package/dist/cli/handlers/misc.d.ts +9 -0
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/misc.js +77 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +15 -2
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +89 -15
- package/dist/cli/handlers/query.d.ts.map +1 -1
- package/dist/cli/handlers/query.js +28 -4
- package/dist/cli/handlers/scenario.d.ts.map +1 -1
- package/dist/cli/handlers/scenario.js +8 -7
- package/dist/cli/handlers/search.d.ts +34 -4
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +216 -36
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +55 -1
- package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -1
- package/dist/cli/mcp/lifecycle-tools.js +3 -2
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.js +4 -3
- package/dist/cli/mcp/workspace-tools.js +1 -1
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +55 -2
- package/dist/cli/registry.d.ts +19 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cloud-lister/aws.d.ts +35 -0
- package/dist/cloud-lister/aws.d.ts.map +1 -0
- package/dist/cloud-lister/aws.js +203 -0
- package/dist/cloud-lister/azure.d.ts +34 -0
- package/dist/cloud-lister/azure.d.ts.map +1 -0
- package/dist/cloud-lister/azure.js +129 -0
- package/dist/cloud-lister/common.d.ts +40 -0
- package/dist/cloud-lister/common.d.ts.map +1 -0
- package/dist/cloud-lister/common.js +83 -0
- package/dist/cloud-lister/credentials.d.ts +50 -0
- package/dist/cloud-lister/credentials.d.ts.map +1 -0
- package/dist/cloud-lister/credentials.js +86 -0
- package/dist/cloud-lister/fakes.d.ts +27 -0
- package/dist/cloud-lister/fakes.d.ts.map +1 -0
- package/dist/cloud-lister/fakes.js +50 -0
- package/dist/cloud-lister/gcp.d.ts +42 -0
- package/dist/cloud-lister/gcp.d.ts.map +1 -0
- package/dist/cloud-lister/gcp.js +143 -0
- package/dist/cloud-lister/guard.d.ts +49 -0
- package/dist/cloud-lister/guard.d.ts.map +1 -0
- package/dist/cloud-lister/guard.js +103 -0
- package/dist/cloud-lister/ids.d.ts +23 -0
- package/dist/cloud-lister/ids.d.ts.map +1 -0
- package/dist/cloud-lister/ids.js +42 -0
- package/dist/cloud-lister/index.d.ts +67 -0
- package/dist/cloud-lister/index.d.ts.map +1 -0
- package/dist/cloud-lister/index.js +102 -0
- package/dist/cloud-lister/kubernetes.d.ts +64 -0
- package/dist/cloud-lister/kubernetes.d.ts.map +1 -0
- package/dist/cloud-lister/kubernetes.js +276 -0
- package/dist/cloud-lister/markers.d.ts +31 -0
- package/dist/cloud-lister/markers.d.ts.map +1 -0
- package/dist/cloud-lister/markers.js +73 -0
- package/dist/cloud-lister/mask.d.ts +31 -0
- package/dist/cloud-lister/mask.d.ts.map +1 -0
- package/dist/cloud-lister/mask.js +74 -0
- package/dist/cloud-lister/sigv4.d.ts +29 -0
- package/dist/cloud-lister/sigv4.d.ts.map +1 -0
- package/dist/cloud-lister/sigv4.js +54 -0
- package/dist/cloud-lister/transport.d.ts +55 -0
- package/dist/cloud-lister/transport.d.ts.map +1 -0
- package/dist/cloud-lister/transport.js +86 -0
- package/dist/cloud-lister/types.d.ts +121 -0
- package/dist/cloud-lister/types.d.ts.map +1 -0
- package/dist/cloud-lister/types.js +24 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.js +6 -0
- package/dist/components/capability-plugin.d.ts +9 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability.d.ts +215 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/cli-support.d.ts +21 -0
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/cli-support.js +58 -14
- package/dist/components/declared-reads.d.ts +38 -0
- package/dist/components/declared-reads.d.ts.map +1 -0
- package/dist/components/declared-reads.js +131 -0
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/deploy-units.js +4 -0
- package/dist/components/driver.d.ts +34 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +66 -3
- package/dist/components/fan-out-run.d.ts +23 -1
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-run.js +82 -14
- package/dist/components/fan-out-support.d.ts +6 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out-support.js +4 -1
- package/dist/components/fan-out.d.ts +28 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/groups.d.ts +229 -0
- package/dist/components/groups.d.ts.map +1 -0
- package/dist/components/groups.js +760 -0
- package/dist/components/index.d.ts +6 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +4 -0
- package/dist/components/plan-shape-conformance.d.ts +48 -0
- package/dist/components/plan-shape-conformance.d.ts.map +1 -0
- package/dist/components/plan-shape-conformance.js +122 -0
- package/dist/components/pr-run.d.ts +41 -4
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +209 -39
- package/dist/components/promote-rounds.d.ts +9 -0
- package/dist/components/promote-rounds.d.ts.map +1 -1
- package/dist/components/promote-rounds.js +23 -2
- package/dist/components/promote.d.ts +17 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/promote.js +36 -6
- package/dist/components/release-gate.d.ts +23 -1
- package/dist/components/release-gate.d.ts.map +1 -1
- package/dist/components/release-gate.js +97 -33
- package/dist/components/run-groups.d.ts +58 -0
- package/dist/components/run-groups.d.ts.map +1 -0
- package/dist/components/run-groups.js +78 -0
- package/dist/components/starter-plugin.d.ts +1 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/starter-plugin.js +6 -1
- package/dist/components/verbs/index.d.ts +1 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/index.js +1 -0
- package/dist/components/verbs/member-outputs.d.ts +187 -0
- package/dist/components/verbs/member-outputs.d.ts.map +1 -0
- package/dist/components/verbs/member-outputs.js +218 -0
- package/dist/config.d.ts +60 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +27 -0
- package/dist/deep-observation.d.ts +1 -13
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/deep-observation.js +5 -22
- package/dist/drift-record.d.ts +542 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +886 -0
- package/dist/engine-facts.d.ts +144 -0
- package/dist/engine-facts.d.ts.map +1 -0
- package/dist/engine-facts.js +14 -0
- package/dist/graph-ir.d.ts +153 -2
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-ir.js +224 -6
- package/dist/graph-refs.d.ts +145 -0
- package/dist/graph-refs.d.ts.map +1 -1
- package/dist/graph-refs.js +305 -0
- package/dist/graph-schema/fixtures/adopt.json +15 -0
- package/dist/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
- package/dist/graph-schema/fixtures/index.json +68 -0
- package/dist/graph-schema/fixtures/plunge.engine-graph.json +158 -0
- package/dist/graph-schema/fixtures.d.ts +23 -0
- package/dist/graph-schema/fixtures.d.ts.map +1 -0
- package/dist/graph-schema/fixtures.js +246 -0
- package/dist/graph-schema/generate.d.ts +15 -0
- package/dist/graph-schema/generate.d.ts.map +1 -0
- package/dist/graph-schema/generate.js +267 -0
- package/dist/graph-schema/graph.schema.json +1387 -0
- package/dist/health.schema.json +2 -1
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/instance-nodes.d.ts +159 -0
- package/dist/instance-nodes.d.ts.map +1 -0
- package/dist/instance-nodes.js +231 -0
- package/dist/lexicon.d.ts +72 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/adoption-file.d.ts +56 -0
- package/dist/lifecycle/adoption-file.d.ts.map +1 -0
- package/dist/lifecycle/adoption-file.js +123 -0
- package/dist/lifecycle/cloud-index.d.ts +186 -0
- package/dist/lifecycle/cloud-index.d.ts.map +1 -0
- package/dist/lifecycle/cloud-index.js +618 -0
- package/dist/lifecycle/derive-edges.d.ts +59 -0
- package/dist/lifecycle/derive-edges.d.ts.map +1 -0
- package/dist/lifecycle/derive-edges.js +126 -0
- package/dist/lifecycle/git.d.ts +10 -9
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/git.js +7 -1
- package/dist/lifecycle/identity-match.d.ts +133 -0
- package/dist/lifecycle/identity-match.d.ts.map +1 -0
- package/dist/lifecycle/identity-match.js +147 -0
- package/dist/lifecycle/index-diff.d.ts +224 -0
- package/dist/lifecycle/index-diff.d.ts.map +1 -0
- package/dist/lifecycle/index-diff.js +327 -0
- package/dist/lifecycle/index-document.d.ts +130 -0
- package/dist/lifecycle/index-document.d.ts.map +1 -0
- package/dist/lifecycle/index-document.js +189 -0
- package/dist/lifecycle/index-drift.d.ts +121 -0
- package/dist/lifecycle/index-drift.d.ts.map +1 -0
- package/dist/lifecycle/index-drift.js +178 -0
- package/dist/lifecycle/index-import.d.ts +168 -0
- package/dist/lifecycle/index-import.d.ts.map +1 -0
- package/dist/lifecycle/index-import.js +515 -0
- package/dist/lifecycle/index-join.d.ts +129 -0
- package/dist/lifecycle/index-join.d.ts.map +1 -0
- package/dist/lifecycle/index-join.js +248 -0
- package/dist/lifecycle/index.d.ts +4 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/index.js +4 -0
- package/dist/lifecycle/observation-baseline.d.ts +61 -21
- package/dist/lifecycle/observation-baseline.d.ts.map +1 -1
- package/dist/lifecycle/observation-baseline.js +144 -19
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/observe.js +6 -1
- package/dist/lifecycle/query.d.ts +45 -4
- package/dist/lifecycle/query.d.ts.map +1 -1
- package/dist/lifecycle/query.js +89 -7
- package/dist/lifecycle/replay.d.ts +10 -3
- package/dist/lifecycle/replay.d.ts.map +1 -1
- package/dist/lifecycle/replay.js +10 -6
- package/dist/lifecycle/scenario.d.ts +4 -3
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/snapshot-store-fake.d.ts +9 -0
- package/dist/lifecycle/snapshot-store-fake.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store-fake.js +21 -0
- package/dist/lifecycle/snapshot-store-s3.d.ts +102 -0
- package/dist/lifecycle/snapshot-store-s3.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store-s3.js +254 -0
- package/dist/lifecycle/snapshot-store.d.ts +170 -0
- package/dist/lifecycle/snapshot-store.d.ts.map +1 -0
- package/dist/lifecycle/snapshot-store.js +832 -0
- package/dist/lifecycle/snapshot.d.ts +11 -0
- package/dist/lifecycle/snapshot.d.ts.map +1 -1
- package/dist/lifecycle/snapshot.js +18 -5
- package/dist/lifecycle/type-listing.d.ts +148 -0
- package/dist/lifecycle/type-listing.d.ts.map +1 -0
- package/dist/lifecycle/type-listing.js +166 -0
- package/dist/lint/component-checks.d.ts +15 -1
- package/dist/lint/component-checks.d.ts.map +1 -1
- package/dist/lint/component-checks.js +1 -0
- package/dist/lint/presets/relaxed.json +2 -1
- package/dist/lint/presets/strict.json +2 -1
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/fail/dns.component.js +13 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp008/pass/dns.component.js +8 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts +33 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp008-applies-signal-only-root.js +123 -0
- package/dist/lint/rules/comp/index.d.ts +2 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/comp/index.js +4 -1
- package/dist/observation.d.ts +19 -2
- package/dist/observation.d.ts.map +1 -1
- package/dist/observation.js +18 -1
- package/dist/op/activities/activity-contracts.d.ts +1 -1
- package/dist/op/activities/activity-contracts.js +1 -1
- package/dist/op/activities/change-set.d.ts +6 -4
- package/dist/op/activities/change-set.d.ts.map +1 -1
- package/dist/op/activities/change-set.js +4 -2
- package/dist/op/activity-failure.d.ts +27 -0
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +1 -1
- package/dist/op/local-executor.d.ts +5 -1
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +22 -8
- package/dist/pr-loop.d.ts +56 -1
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +51 -1
- package/dist/pulumi-urn.d.ts +101 -0
- package/dist/pulumi-urn.d.ts.map +1 -0
- package/dist/pulumi-urn.js +131 -0
- package/dist/release-floors.d.ts +23 -0
- package/dist/release-floors.d.ts.map +1 -0
- package/dist/release-floors.js +22 -0
- package/dist/sensitive-key.d.ts +23 -0
- package/dist/sensitive-key.d.ts.map +1 -0
- package/dist/sensitive-key.js +31 -0
- package/dist/wave-runtime.mjs +234 -234
- package/dist/workspace/adoption-report.d.ts +53 -0
- package/dist/workspace/adoption-report.d.ts.map +1 -0
- package/dist/workspace/adoption-report.js +76 -0
- package/dist/workspace/capabilities-contract.d.ts +7 -0
- package/dist/workspace/capabilities-contract.d.ts.map +1 -1
- package/dist/workspace/capabilities-contract.js +2 -1
- package/dist/workspace/capabilities.schema.json +98 -0
- package/dist/workspace/change-set.schema.json +42 -3
- package/dist/workspace/ci-cloud-identity.d.ts +13 -1
- package/dist/workspace/ci-cloud-identity.d.ts.map +1 -1
- package/dist/workspace/ci-cloud-identity.js +30 -1
- package/dist/workspace/compose-graph.d.ts +10 -1
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/compose-graph.js +6 -1
- package/dist/workspace/conformance/index.d.ts +1 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/index.js +6 -1
- package/dist/workspace/drift-cli.d.ts +81 -0
- package/dist/workspace/drift-cli.d.ts.map +1 -0
- package/dist/workspace/drift-cli.js +317 -0
- package/dist/workspace/drift.schema.json +672 -0
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +3 -0
- package/dist/workspace/graph.schema.json +72 -0
- package/dist/workspace/init.d.ts +5 -1
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/init.js +55 -9
- package/dist/workspace/ledger.schema.json +1 -1
- package/dist/workspace/nested-graph.d.ts.map +1 -1
- package/dist/workspace/nested-graph.js +2 -0
- package/dist/workspace/pr-report.schema.json +51 -2
- package/dist/workspace/promote-waves.d.ts +112 -0
- package/dist/workspace/promote-waves.d.ts.map +1 -0
- package/dist/workspace/promote-waves.js +290 -0
- package/dist/workspace/promote.d.ts +84 -2
- package/dist/workspace/promote.d.ts.map +1 -1
- package/dist/workspace/promote.js +347 -61
- package/dist/workspace/reason-codes.d.ts +12 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +14 -0
- package/dist/workspace/search-contract.d.ts +3 -3
- package/dist/workspace/search-contract.d.ts.map +1 -1
- package/dist/workspace/search-contract.js +2 -0
- package/dist/workspace/search.schema.json +103 -5
- package/package.json +14 -1
- package/src/__fixtures__/drift-record/README.md +58 -0
- package/src/__fixtures__/drift-record/choudoufu-cone.ndjson +4 -0
- package/src/__fixtures__/drift-record/choudoufu-resource.ndjson +3 -0
- package/src/__fixtures__/drift-record/component-status-ledger.json +65 -0
- package/src/__fixtures__/drift-record/component-status.json +91 -0
- package/src/__fixtures__/drift-record/deep-diff.json +259 -0
- package/src/__fixtures__/drift-record/lifecycle-diff-live.json +825 -0
- package/src/__fixtures__/drift-record/live-diff.json +125 -0
- package/src/audit/discover.e2e.test.ts +14 -0
- package/src/audit/discover.ts +3 -1
- package/src/behaviour.ts +1 -1
- package/src/capabilities/templates.json +145 -0
- package/src/capabilities/templates.test.ts +212 -0
- package/src/capabilities/templates.ts +204 -0
- package/src/change-set-bundle.test.ts +83 -0
- package/src/change-set-graph.ts +80 -9
- package/src/change-set.test.ts +24 -0
- package/src/change-set.ts +77 -14
- package/src/ci-identity-targets.test.ts +23 -0
- package/src/ci-identity.ts +10 -4
- package/src/cli/commands/import-index.test.ts +117 -0
- package/src/cli/commands/import-index.ts +265 -0
- package/src/cli/commands/lint.ts +4 -2
- package/src/cli/handlers/components.test.ts +9 -0
- package/src/cli/handlers/components.ts +12 -2
- package/src/cli/handlers/fan-out.ts +17 -3
- package/src/cli/handlers/graph.test.ts +42 -0
- package/src/cli/handlers/graph.ts +26 -4
- package/src/cli/handlers/index-cloud.ts +32 -0
- package/src/cli/handlers/index-diff.test.ts +68 -0
- package/src/cli/handlers/index-diff.ts +146 -0
- package/src/cli/handlers/ledger-root-member.test.ts +161 -0
- package/src/cli/handlers/lifecycle-drift.ts +68 -0
- package/src/cli/handlers/lifecycle.test.ts +33 -11
- package/src/cli/handlers/lifecycle.ts +205 -30
- package/src/cli/handlers/misc.ts +73 -0
- package/src/cli/handlers/pr-waves-blocked.test.ts +37 -2
- package/src/cli/handlers/pr.ts +14 -2
- package/src/cli/handlers/promote.test.ts +64 -0
- package/src/cli/handlers/promote.ts +81 -6
- package/src/cli/handlers/query.ts +27 -4
- package/src/cli/handlers/run-declared-reads-cli.test.ts +187 -0
- package/src/cli/handlers/run-groups-cli.test.ts +229 -0
- package/src/cli/handlers/scenario.test.ts +13 -0
- package/src/cli/handlers/scenario.ts +8 -7
- package/src/cli/handlers/search-index.test.ts +255 -0
- package/src/cli/handlers/search-json.test.ts +1 -1
- package/src/cli/handlers/search-ownership.test.ts +194 -0
- package/src/cli/handlers/search.ts +271 -38
- package/src/cli/main.test.ts +7 -0
- package/src/cli/main.ts +56 -1
- package/src/cli/mcp/lifecycle-tools.ts +3 -2
- package/src/cli/mcp/resource-handlers.ts +4 -3
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/cli/parse-args.ts +40 -2
- package/src/cli/registry.ts +19 -1
- package/src/cloud-lister/aws.test.ts +202 -0
- package/src/cloud-lister/aws.ts +226 -0
- package/src/cloud-lister/azure.test.ts +132 -0
- package/src/cloud-lister/azure.ts +142 -0
- package/src/cloud-lister/common.ts +115 -0
- package/src/cloud-lister/credentials.ts +110 -0
- package/src/cloud-lister/fakes.ts +66 -0
- package/src/cloud-lister/gcp.test.ts +121 -0
- package/src/cloud-lister/gcp.ts +159 -0
- package/src/cloud-lister/guard.test.ts +198 -0
- package/src/cloud-lister/guard.ts +111 -0
- package/src/cloud-lister/ids.ts +54 -0
- package/src/cloud-lister/index.ts +134 -0
- package/src/cloud-lister/kubernetes.test.ts +160 -0
- package/src/cloud-lister/kubernetes.ts +284 -0
- package/src/cloud-lister/markers.ts +74 -0
- package/src/cloud-lister/mask.ts +77 -0
- package/src/cloud-lister/shape.test.ts +81 -0
- package/src/cloud-lister/sigv4.ts +70 -0
- package/src/cloud-lister/transport.ts +118 -0
- package/src/cloud-lister/types.ts +135 -0
- package/src/components/capability-plugin-loader.ts +4 -0
- package/src/components/capability-plugin.ts +10 -0
- package/src/components/capability.ts +229 -0
- package/src/components/cli-support.ts +70 -14
- package/src/components/declared-reads.test.ts +103 -0
- package/src/components/declared-reads.ts +134 -0
- package/src/components/deploy-units.ts +4 -0
- package/src/components/driver.ts +89 -4
- package/src/components/fan-out-run.ts +95 -15
- package/src/components/fan-out-support.ts +10 -1
- package/src/components/fan-out.ts +30 -0
- package/src/components/groups.test.ts +320 -0
- package/src/components/groups.ts +880 -0
- package/src/components/index.ts +42 -0
- package/src/components/plan-shape-conformance.ts +130 -0
- package/src/components/pr-env-run-bundle.test.ts +2 -0
- package/src/components/pr-run.test.ts +516 -3
- package/src/components/pr-run.ts +231 -41
- package/src/components/promote-rounds.ts +25 -2
- package/src/components/promote.ts +55 -5
- package/src/components/registry.test.ts +1 -1
- package/src/components/release-gate.ts +115 -30
- package/src/components/release-groups.test.ts +362 -0
- package/src/components/run-groups.ts +113 -0
- package/src/components/starter-plugin.ts +6 -0
- package/src/components/verbs/index.ts +1 -0
- package/src/components/verbs/member-outputs.test.ts +205 -0
- package/src/components/verbs/member-outputs.ts +308 -0
- package/src/config.ts +44 -0
- package/src/deep-observation.ts +5 -23
- package/src/drift-record.test.ts +596 -0
- package/src/drift-record.ts +1206 -0
- package/src/engine-facts.guard.test.ts +111 -0
- package/src/engine-facts.test.ts +178 -0
- package/src/engine-facts.ts +154 -0
- package/src/gated-waves-bundle.test.ts +2 -0
- package/src/graph-ir-live.test.ts +92 -0
- package/src/graph-ir.ts +317 -7
- package/src/graph-refs.ts +416 -0
- package/src/graph-schema/fixtures/adopt.json +15 -0
- package/src/graph-schema/fixtures/choudoufu.engine-graph.json +169 -0
- package/src/graph-schema/fixtures/index.json +68 -0
- package/src/graph-schema/fixtures/plunge.engine-graph.json +158 -0
- package/src/graph-schema/fixtures.ts +267 -0
- package/src/graph-schema/generate.ts +263 -0
- package/src/graph-schema/graph-schema.test.ts +153 -0
- package/src/graph-schema/graph.schema.json +1387 -0
- package/src/health.schema.json +2 -1
- package/src/identity.ts +2 -0
- package/src/index.ts +2 -0
- package/src/instance-nodes.ts +288 -0
- package/src/lexicon.ts +76 -0
- package/src/lifecycle/__fixtures__/index-diff/20261026T120000Z-aaaaaaaaaaaa.json +149 -0
- package/src/lifecycle/__fixtures__/index-diff/20261026T130000Z-bbbbbbbbbbbb.json +127 -0
- package/src/lifecycle/adoption-file.test.ts +100 -0
- package/src/lifecycle/adoption-file.ts +154 -0
- package/src/lifecycle/cloud-index.test.ts +517 -0
- package/src/lifecycle/cloud-index.ts +736 -0
- package/src/lifecycle/derive-edges.test.ts +193 -0
- package/src/lifecycle/derive-edges.ts +182 -0
- package/src/lifecycle/git.ts +10 -4
- package/src/lifecycle/identity-match.test.ts +308 -0
- package/src/lifecycle/identity-match.ts +257 -0
- package/src/lifecycle/index-diff.test.ts +198 -0
- package/src/lifecycle/index-diff.ts +476 -0
- package/src/lifecycle/index-document.test.ts +64 -0
- package/src/lifecycle/index-document.ts +299 -0
- package/src/lifecycle/index-drift.test.ts +191 -0
- package/src/lifecycle/index-drift.ts +304 -0
- package/src/lifecycle/index-import.test.ts +255 -0
- package/src/lifecycle/index-import.ts +634 -0
- package/src/lifecycle/index-join.test.ts +250 -0
- package/src/lifecycle/index-join.ts +304 -0
- package/src/lifecycle/index-store-load-bearing.test.ts +187 -0
- package/src/lifecycle/index.ts +4 -0
- package/src/lifecycle/member-ledger.test.ts +25 -7
- package/src/lifecycle/observation-baseline.test.ts +72 -1
- package/src/lifecycle/observation-baseline.ts +190 -27
- package/src/lifecycle/observe.ts +6 -1
- package/src/lifecycle/query.test.ts +69 -1
- package/src/lifecycle/query.ts +103 -10
- package/src/lifecycle/replay.test.ts +9 -5
- package/src/lifecycle/replay.ts +9 -5
- package/src/lifecycle/scenario.ts +4 -3
- package/src/lifecycle/snapshot-store-fake.ts +29 -0
- package/src/lifecycle/snapshot-store-s3.ts +316 -0
- package/src/lifecycle/snapshot-store.test.ts +385 -0
- package/src/lifecycle/snapshot-store.ts +981 -0
- package/src/lifecycle/snapshot.test.ts +13 -0
- package/src/lifecycle/snapshot.ts +23 -6
- package/src/lifecycle/type-listing.test.ts +166 -0
- package/src/lifecycle/type-listing.ts +309 -0
- package/src/lint/component-checks.ts +17 -1
- package/src/lint/config.test.ts +3 -0
- package/src/lint/presets/relaxed.json +2 -1
- package/src/lint/presets/strict.json +2 -1
- package/src/lint/rules/__fixtures__/comp/comp008/fail/dns.component.ts +15 -0
- package/src/lint/rules/__fixtures__/comp/comp008/pass/dns.component.ts +10 -0
- package/src/lint/rules/comp/comp.test.ts +2 -1
- package/src/lint/rules/comp/comp008-applies-signal-only-root.ts +121 -0
- package/src/lint/rules/comp/comp008.test.ts +77 -0
- package/src/lint/rules/comp/index.ts +4 -1
- package/src/observation-edges.test.ts +33 -0
- package/src/observation.ts +36 -1
- package/src/op/activities/activity-contracts.ts +1 -1
- package/src/op/activities/change-set.ts +8 -5
- package/src/op/activity-failure.ts +36 -0
- package/src/op/index.ts +2 -1
- package/src/op/local-executor.test.ts +80 -0
- package/src/op/local-executor.ts +27 -9
- package/src/pr-loop-bundle.test.ts +5 -2
- package/src/pr-loop.test.ts +43 -0
- package/src/pr-loop.ts +111 -2
- package/src/pulumi-urn.ts +151 -0
- package/src/release-floors.ts +22 -0
- package/src/sensitive-key.ts +34 -0
- package/src/workspace/adoption-report.test.ts +61 -0
- package/src/workspace/adoption-report.ts +103 -0
- package/src/workspace/capabilities-contract.test.ts +4 -0
- package/src/workspace/capabilities-contract.ts +9 -1
- package/src/workspace/capabilities.schema.json +98 -0
- package/src/workspace/change-set.schema.json +42 -3
- package/src/workspace/ci-cloud-identity.ts +31 -1
- package/src/workspace/compose-graph.test.ts +12 -0
- package/src/workspace/compose-graph.ts +12 -1
- package/src/workspace/conformance/conformance.e2e.test.ts +2 -1
- package/src/workspace/conformance/index.ts +6 -1
- package/src/workspace/drift-cli.test.ts +65 -0
- package/src/workspace/drift-cli.ts +365 -0
- package/src/workspace/drift.schema.json +672 -0
- package/src/workspace/graph-cli.ts +5 -0
- package/src/workspace/graph.schema.json +72 -0
- package/src/workspace/init.test.ts +38 -1
- package/src/workspace/init.ts +50 -8
- package/src/workspace/intent-gaps.test.ts +18 -2
- package/src/workspace/ledger.schema.json +1 -1
- package/src/workspace/nested-graph.ts +1 -0
- package/src/workspace/pr-report.schema.json +51 -2
- package/src/workspace/promote-waves.test.ts +296 -0
- package/src/workspace/promote-waves.ts +340 -0
- package/src/workspace/promote.test.ts +158 -4
- package/src/workspace/promote.ts +398 -57
- package/src/workspace/reason-codes.test.ts +4 -1
- package/src/workspace/reason-codes.ts +14 -0
- package/src/workspace/search-contract.ts +2 -0
- package/src/workspace/search.schema.json +103 -5
|
@@ -0,0 +1,517 @@
|
|
|
1
|
+
// chant#4532: `chant index <substrate>` and `indexCloud`, moved from behold#1026.
|
|
2
|
+
// The refusal of every action flag, the default store location, the pipeline
|
|
3
|
+
// (typeListing, deriveEdges, a stamped write) over a fake lister, and that
|
|
4
|
+
// nothing is written outside the store. Nothing here opens a socket: the lister
|
|
5
|
+
// is faked, or the real one runs over a fake fetcher.
|
|
6
|
+
import { mkdirSync, mkdtempSync, readdirSync, statSync } from "node:fs";
|
|
7
|
+
import { tmpdir } from "node:os";
|
|
8
|
+
import { join, relative, sep } from "node:path";
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import { fakeFetcher, json, refusingChains } from "../cloud-lister/fakes";
|
|
11
|
+
import type { ParsedArgs } from "../cli/registry";
|
|
12
|
+
import {
|
|
13
|
+
ACTION_FLAGS,
|
|
14
|
+
CLOUD_INDEX_FLOOR,
|
|
15
|
+
chantUserStoreDir,
|
|
16
|
+
findChantProject,
|
|
17
|
+
indexCloud,
|
|
18
|
+
IndexUsageError,
|
|
19
|
+
listCloud,
|
|
20
|
+
parseIndexArgs,
|
|
21
|
+
planIndexStore,
|
|
22
|
+
runCloudIndex,
|
|
23
|
+
scopeAndTarget,
|
|
24
|
+
type CloudScope,
|
|
25
|
+
type IndexStore,
|
|
26
|
+
type ListingResult,
|
|
27
|
+
type RunCloudIndexOptions,
|
|
28
|
+
type StorePlan,
|
|
29
|
+
type SubstrateTarget,
|
|
30
|
+
} from "./cloud-index";
|
|
31
|
+
import type { IndexDocument } from "./index-document";
|
|
32
|
+
import { NEXT_RELEASE } from "../release-floors";
|
|
33
|
+
import { createSnapshotStore } from "./snapshot-store";
|
|
34
|
+
|
|
35
|
+
const ACCOUNT = "000000000000";
|
|
36
|
+
const ENDPOINT = "http://localhost:4566";
|
|
37
|
+
const EMULATOR_ENV = { AWS_ACCESS_KEY_ID: "test", AWS_SECRET_ACCESS_KEY: "test" };
|
|
38
|
+
|
|
39
|
+
function listing(scope: CloudScope, startedAt: string): ListingResult {
|
|
40
|
+
const at = startedAt;
|
|
41
|
+
const res = (listedType: string, nativeId: string, properties: Record<string, unknown>) => {
|
|
42
|
+
const location = listedType.startsWith("AWS::IAM::") ? "global" : "us-east-1";
|
|
43
|
+
return {
|
|
44
|
+
id: `aws/${scope.scopeId}/${location}/${listedType}/${nativeId}`,
|
|
45
|
+
listedType,
|
|
46
|
+
location,
|
|
47
|
+
nativeId,
|
|
48
|
+
cloudIds: [{ kind: "import-id" as const, value: nativeId }],
|
|
49
|
+
tags: {},
|
|
50
|
+
properties,
|
|
51
|
+
observedAt: at,
|
|
52
|
+
facts: { cloudIds: [{ kind: "import-id" as const, value: nativeId }], observedAt: at },
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
return {
|
|
56
|
+
listing: "v1",
|
|
57
|
+
source: { name: "chant-lister", version: "test" },
|
|
58
|
+
scope,
|
|
59
|
+
startedAt: at,
|
|
60
|
+
completedAt: at,
|
|
61
|
+
resources: [
|
|
62
|
+
res("AWS::S3::Bucket", "web-assets", { BucketName: "web-assets", Arn: "arn:aws:s3:::web-assets" }),
|
|
63
|
+
res("AWS::IAM::Role", "app-role", { RoleName: "app-role", Arn: `arn:aws:iam::${scope.scopeId}:role/app-role` }),
|
|
64
|
+
],
|
|
65
|
+
coverage: [
|
|
66
|
+
{ listedType: "AWS::IAM::Role", location: "global", verdict: "listed" },
|
|
67
|
+
{ listedType: "AWS::S3::Bucket", location: "us-east-1", verdict: "listed" },
|
|
68
|
+
],
|
|
69
|
+
notes: [],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** A lister that records what it was asked and answers {@link listing}, one second later each call. */
|
|
74
|
+
function fakeLister(start = "2026-10-26T12:00:00.000Z") {
|
|
75
|
+
const calls: Array<{ scope: CloudScope; target: SubstrateTarget }> = [];
|
|
76
|
+
let t = Date.parse(start);
|
|
77
|
+
return {
|
|
78
|
+
calls,
|
|
79
|
+
list: async (scope: CloudScope, target: SubstrateTarget) => {
|
|
80
|
+
calls.push({ scope, target });
|
|
81
|
+
const at = new Date(t).toISOString();
|
|
82
|
+
t += 1000;
|
|
83
|
+
return listing(scope, at);
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** A store that keeps writes in memory, and records each plan it was opened for. */
|
|
89
|
+
function fakeStore() {
|
|
90
|
+
const writes: IndexDocument[] = [];
|
|
91
|
+
const opened: StorePlan[] = [];
|
|
92
|
+
const store: IndexStore = {
|
|
93
|
+
kind: "local",
|
|
94
|
+
where: "fake-store",
|
|
95
|
+
writable: true,
|
|
96
|
+
async writeIndex(doc) {
|
|
97
|
+
writes.push(doc);
|
|
98
|
+
const name = `${doc.stamp.observedAt.replace(/[-:]|\.\d{3}/g, "")}-${doc.stamp.digest.slice(0, 12)}.json`;
|
|
99
|
+
return { written: true, path: `${doc.stamp.scopeKey}/${name}` };
|
|
100
|
+
},
|
|
101
|
+
async listIndex() {
|
|
102
|
+
return [];
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
writes,
|
|
107
|
+
opened,
|
|
108
|
+
openStore: async (plan: StorePlan) => {
|
|
109
|
+
opened.push(plan);
|
|
110
|
+
return store;
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function tempTree() {
|
|
116
|
+
const root = mkdtempSync(join(tmpdir(), "chant-index-"));
|
|
117
|
+
const cwd = join(root, "cwd");
|
|
118
|
+
const home = join(root, "home");
|
|
119
|
+
const xdg = join(root, "xdg");
|
|
120
|
+
for (const d of [cwd, home, xdg]) mkdirSync(d, { recursive: true });
|
|
121
|
+
return { root, cwd, home, xdg };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** Every file under `root`, relative and sorted. */
|
|
125
|
+
function files(root: string, rel = ""): string[] {
|
|
126
|
+
const out: string[] = [];
|
|
127
|
+
for (const n of readdirSync(join(root, rel)).sort()) {
|
|
128
|
+
const r = rel ? join(rel, n) : n;
|
|
129
|
+
if (statSync(join(root, r)).isDirectory()) out.push(...files(root, r));
|
|
130
|
+
else out.push(r);
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function capture() {
|
|
136
|
+
const out: string[] = [];
|
|
137
|
+
const err: string[] = [];
|
|
138
|
+
return { out, err, stdout: (s: string) => void out.push(s), stderr: (s: string) => void err.push(s) };
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const noLexicons: RunCloudIndexOptions["lexicons"] = async () => ({ lexicons: [] });
|
|
142
|
+
|
|
143
|
+
describe("the floor", () => {
|
|
144
|
+
it("names the next release", () => {
|
|
145
|
+
expect(CLOUD_INDEX_FLOOR).toBe(NEXT_RELEASE);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("chant index refuses every action flag", () => {
|
|
150
|
+
it("names the flag, wherever it sits and in either form", () => {
|
|
151
|
+
for (const flag of ACTION_FLAGS) {
|
|
152
|
+
for (const argv of [["aws", flag], [flag, "aws"], ["aws", "--account", ACCOUNT, `${flag}=1`]]) {
|
|
153
|
+
let caught: unknown;
|
|
154
|
+
try {
|
|
155
|
+
parseIndexArgs(argv);
|
|
156
|
+
} catch (e) {
|
|
157
|
+
caught = e;
|
|
158
|
+
}
|
|
159
|
+
expect(caught, `${argv.join(" ")}`).toBeInstanceOf(IndexUsageError);
|
|
160
|
+
expect((caught as IndexUsageError).actionFlag).toBe(flag);
|
|
161
|
+
expect((caught as Error).message).toMatch(/read-only/);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("the action flags include every action verb", () => {
|
|
167
|
+
for (const f of ["--apply", "--deploy", "--destroy", "--rollback", "--op", "--approve", "--enable-api", "--yes"]) expect(ACTION_FLAGS).toContain(f);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("stops before the lister or the store is touched", async () => {
|
|
171
|
+
const t = tempTree();
|
|
172
|
+
const store = fakeStore();
|
|
173
|
+
const lister = fakeLister();
|
|
174
|
+
const io = capture();
|
|
175
|
+
let lexiconLookups = 0;
|
|
176
|
+
for (const flag of ACTION_FLAGS) {
|
|
177
|
+
const code = await runCloudIndex(["aws", "--account", ACCOUNT, "--regions", "us-east-1", flag], {
|
|
178
|
+
cwd: t.cwd,
|
|
179
|
+
home: t.home,
|
|
180
|
+
env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
|
|
181
|
+
stdout: io.stdout,
|
|
182
|
+
stderr: io.stderr,
|
|
183
|
+
list: lister.list,
|
|
184
|
+
openStore: store.openStore,
|
|
185
|
+
lexicons: async () => {
|
|
186
|
+
lexiconLookups++;
|
|
187
|
+
return { lexicons: [] };
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
expect(code, flag).toBe(2);
|
|
191
|
+
}
|
|
192
|
+
expect(store.opened).toEqual([]);
|
|
193
|
+
expect(lexiconLookups).toBe(0);
|
|
194
|
+
expect(lister.calls).toEqual([]);
|
|
195
|
+
expect(store.writes).toEqual([]);
|
|
196
|
+
expect(io.out).toEqual([]);
|
|
197
|
+
expect(io.err.join("")).toMatch(/chant index is read-only and refuses --apply/);
|
|
198
|
+
expect(files(t.root)).toEqual([]);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it("the registry entry refuses an action flag core's parser kept", async () => {
|
|
202
|
+
const { runIndexCommand } = await import("../cli/handlers/index-cloud");
|
|
203
|
+
const args = { command: "index", path: "aws", positionals: ["aws"], format: "", fix: false, watch: false, verbose: false, help: false, live: false, yes: true } as unknown as ParsedArgs;
|
|
204
|
+
const code = await runIndexCommand({ args, plugins: [], serializers: [] });
|
|
205
|
+
expect(code).toBe(2);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("an unknown flag is a usage error, not a pass", () => {
|
|
209
|
+
expect(() => parseIndexArgs(["aws", "--frobnicate"])).toThrow(/unknown argument/);
|
|
210
|
+
expect(() => parseIndexArgs(["--account", ACCOUNT])).toThrow(/needs a substrate/);
|
|
211
|
+
expect(() => parseIndexArgs(["cloudflare"])).toThrow(/unknown substrate/);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("names the caller's command", () => {
|
|
215
|
+
expect(() => parseIndexArgs(["aws", "--apply"], "behold index")).toThrow(/^behold index is read-only and refuses --apply/);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
describe("chant index over a fake lister", () => {
|
|
220
|
+
it("lists the scope asked for, types it, derives edges and writes one version", async () => {
|
|
221
|
+
const t = tempTree();
|
|
222
|
+
const store = fakeStore();
|
|
223
|
+
const lister = fakeLister();
|
|
224
|
+
const io = capture();
|
|
225
|
+
const code = await runCloudIndex(
|
|
226
|
+
["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1,eu-west-1", "--types", "AWS::S3::Bucket,AWS::IAM::Role", "--tag", "team=web"],
|
|
227
|
+
{ cwd: t.cwd, home: t.home, env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg }, stdout: io.stdout, stderr: io.stderr, list: lister.list, openStore: store.openStore, lexicons: noLexicons },
|
|
228
|
+
);
|
|
229
|
+
expect(io.err).toEqual([]);
|
|
230
|
+
expect(code).toBe(0);
|
|
231
|
+
expect(lister.calls).toHaveLength(1);
|
|
232
|
+
expect(lister.calls[0].scope).toEqual({
|
|
233
|
+
substrate: "aws",
|
|
234
|
+
scopeId: ACCOUNT,
|
|
235
|
+
locations: ["us-east-1", "eu-west-1"],
|
|
236
|
+
types: ["AWS::S3::Bucket", "AWS::IAM::Role"],
|
|
237
|
+
tagFilter: { team: "web" },
|
|
238
|
+
});
|
|
239
|
+
expect(lister.calls[0].target).toEqual({ substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } });
|
|
240
|
+
// The default store is the per-user one (no project, no --store).
|
|
241
|
+
expect(store.opened).toEqual([{ kind: "user", dir: join(t.xdg, "chant") }]);
|
|
242
|
+
expect(store.writes).toHaveLength(1);
|
|
243
|
+
const doc = store.writes[0];
|
|
244
|
+
// chant's typeListing ran: path-style ids, kept as unknown kind with no lexicon.
|
|
245
|
+
expect(doc.graph.nodes.map((n) => n.id).sort()).toEqual([`aws/${ACCOUNT}/global/AWS::IAM::Role/app-role`, `aws/${ACCOUNT}/us-east-1/AWS::S3::Bucket/web-assets`]);
|
|
246
|
+
expect(doc.graph.nodes.every((n) => n.unmappedKind === true)).toBe(true);
|
|
247
|
+
expect(doc.stamp.source).toMatchObject({ kind: "cloud", name: "chant-lister" });
|
|
248
|
+
const text = io.out.join("");
|
|
249
|
+
expect(text).toMatch(/2 nodes \(0 typed, 2 of unknown kind\), 0 derived edges/);
|
|
250
|
+
expect(text).toMatch(/^chant index: wrote \d{8}T\d{6}Z-[0-9a-f]{12}\.json under cloud\/aws\/000000000000\/\S+ in fake-store$/m);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("a second run writes a second version", async () => {
|
|
254
|
+
const t = tempTree();
|
|
255
|
+
const store = fakeStore();
|
|
256
|
+
const lister = fakeLister();
|
|
257
|
+
const opts: RunCloudIndexOptions = { cwd: t.cwd, home: t.home, env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg }, stdout: () => {}, stderr: () => {}, list: lister.list, openStore: store.openStore, lexicons: noLexicons };
|
|
258
|
+
expect(await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], opts)).toBe(0);
|
|
259
|
+
expect(await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], opts)).toBe(0);
|
|
260
|
+
expect(store.writes.map((d) => d.stamp.observedAt)).toEqual(["2026-10-26T12:00:00.000Z", "2026-10-26T12:00:01.000Z"]);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("--json prints one object with the verdict fields", async () => {
|
|
264
|
+
const t = tempTree();
|
|
265
|
+
const store = fakeStore();
|
|
266
|
+
const io = capture();
|
|
267
|
+
const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--json"], {
|
|
268
|
+
cwd: t.cwd,
|
|
269
|
+
home: t.home,
|
|
270
|
+
env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
|
|
271
|
+
stdout: io.stdout,
|
|
272
|
+
stderr: io.stderr,
|
|
273
|
+
list: fakeLister().list,
|
|
274
|
+
openStore: store.openStore,
|
|
275
|
+
lexicons: noLexicons,
|
|
276
|
+
});
|
|
277
|
+
expect(code).toBe(0);
|
|
278
|
+
const summary = JSON.parse(io.out.join(""));
|
|
279
|
+
expect(summary).toMatchObject({ substrate: "aws", scopeId: ACCOUNT, written: true, nodes: 2, coverage: { listed: 2, notObserved: 0 } });
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("with an endpoint and no static credentials it is refused, and no SDK chain is asked", async () => {
|
|
283
|
+
const t = tempTree();
|
|
284
|
+
const store = fakeStore();
|
|
285
|
+
const chains = refusingChains();
|
|
286
|
+
const fake = fakeFetcher(() => undefined);
|
|
287
|
+
const io = capture();
|
|
288
|
+
const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
|
|
289
|
+
cwd: t.cwd,
|
|
290
|
+
home: t.home,
|
|
291
|
+
env: { XDG_DATA_HOME: t.xdg },
|
|
292
|
+
stdout: io.stdout,
|
|
293
|
+
stderr: io.stderr,
|
|
294
|
+
listOptions: { fetcher: fake.fetcher, chains, retryDelays: [] },
|
|
295
|
+
openStore: store.openStore,
|
|
296
|
+
lexicons: noLexicons,
|
|
297
|
+
});
|
|
298
|
+
expect(code).toBe(2);
|
|
299
|
+
expect(io.err.join("")).toMatch(/needs static credentials/);
|
|
300
|
+
expect(chains.count).toEqual({ aws: 0, azure: 0, gcp: 0 });
|
|
301
|
+
expect(fake.calls).toEqual([]);
|
|
302
|
+
expect(store.writes).toEqual([]);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("the command itself writes nothing: with a fake store the tree is unchanged", async () => {
|
|
306
|
+
const t = tempTree();
|
|
307
|
+
const store = fakeStore();
|
|
308
|
+
await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
|
|
309
|
+
cwd: t.cwd,
|
|
310
|
+
home: t.home,
|
|
311
|
+
env: { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg },
|
|
312
|
+
stdout: () => {},
|
|
313
|
+
stderr: () => {},
|
|
314
|
+
list: fakeLister().list,
|
|
315
|
+
openStore: store.openStore,
|
|
316
|
+
lexicons: noLexicons,
|
|
317
|
+
});
|
|
318
|
+
expect(store.writes).toHaveLength(1);
|
|
319
|
+
expect(files(t.root)).toEqual([]);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it("a read-only store is refused before anything is listed", async () => {
|
|
323
|
+
const lister = fakeLister();
|
|
324
|
+
const io = capture();
|
|
325
|
+
const ro: IndexStore = { kind: "orphan-branch", where: "chant/lifecycle", writable: false, writeIndex: async () => ({ written: false }), listIndex: async () => [] };
|
|
326
|
+
const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
|
|
327
|
+
env: EMULATOR_ENV,
|
|
328
|
+
stdout: io.stdout,
|
|
329
|
+
stderr: io.stderr,
|
|
330
|
+
list: lister.list,
|
|
331
|
+
openStore: async () => ro,
|
|
332
|
+
lexicons: noLexicons,
|
|
333
|
+
});
|
|
334
|
+
expect(code).toBe(2);
|
|
335
|
+
expect(lister.calls).toEqual([]);
|
|
336
|
+
expect(io.err.join("")).toMatch(/read-only/);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
describe("indexCloud, the library function", () => {
|
|
341
|
+
it("runs list, typeListing, deriveEdges and one write, and returns all three", async () => {
|
|
342
|
+
const store = fakeStore();
|
|
343
|
+
const lister = fakeLister();
|
|
344
|
+
const scope: CloudScope = { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" };
|
|
345
|
+
const target: SubstrateTarget = { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } };
|
|
346
|
+
const s = await store.openStore({ kind: "user", dir: "/unused" });
|
|
347
|
+
const r = await indexCloud({ scope, target, store: s, lexicons: [], version: "9.9.9" }, { list: lister.list });
|
|
348
|
+
expect(lister.calls).toEqual([{ scope, target }]);
|
|
349
|
+
expect(r.listing.resources).toHaveLength(2);
|
|
350
|
+
expect(r.doc.stamp.scopeKey.startsWith(`cloud/aws/${ACCOUNT}/`)).toBe(true);
|
|
351
|
+
expect(r.write.written).toBe(true);
|
|
352
|
+
expect(store.writes).toEqual([r.doc]);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("types through a lexicon's listedTypes and runs its catalog", async () => {
|
|
356
|
+
const store = fakeStore();
|
|
357
|
+
const s = await store.openStore({ kind: "user", dir: "/unused" });
|
|
358
|
+
// A lexicon whose kind for every AWS type is the type itself, with an empty catalog.
|
|
359
|
+
const lexicon = {
|
|
360
|
+
name: "aws",
|
|
361
|
+
listedTypes: { substrate: "aws" as const, kindFor: (t: string) => t },
|
|
362
|
+
referenceCatalog: { identities: [], refs: [] },
|
|
363
|
+
};
|
|
364
|
+
const r = await indexCloud(
|
|
365
|
+
{
|
|
366
|
+
scope: { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" },
|
|
367
|
+
target: { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } },
|
|
368
|
+
store: s,
|
|
369
|
+
lexicons: [lexicon],
|
|
370
|
+
},
|
|
371
|
+
{ list: fakeLister().list },
|
|
372
|
+
);
|
|
373
|
+
expect(r.doc.graph.nodes.map((n) => n.kind).sort()).toEqual(["AWS::IAM::Role", "AWS::S3::Bucket"]);
|
|
374
|
+
expect(r.doc.graph.nodes.some((n) => n.unmappedKind === true)).toBe(false);
|
|
375
|
+
// Whatever a catalog draws is derived; an empty one draws nothing.
|
|
376
|
+
expect(r.doc.graph.edges).toEqual([]);
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it("a store whose write throws is an IndexWriteError, after the listing", async () => {
|
|
380
|
+
const { IndexWriteError } = await import("./cloud-index");
|
|
381
|
+
const boom: IndexStore = { kind: "local", where: "x", writable: true, writeIndex: async () => { throw new Error("disk full"); }, listIndex: async () => [] };
|
|
382
|
+
await expect(
|
|
383
|
+
indexCloud(
|
|
384
|
+
{ scope: { substrate: "aws", scopeId: ACCOUNT, locations: ["us-east-1"], types: "*" }, target: { substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "t", secretAccessKey: "t" } } }, store: boom, lexicons: [] },
|
|
385
|
+
{ list: fakeLister().list },
|
|
386
|
+
),
|
|
387
|
+
).rejects.toBeInstanceOf(IndexWriteError);
|
|
388
|
+
});
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
describe("scope and target from flags and the environment", () => {
|
|
392
|
+
const deps = { cwd: "/w", home: "/h" };
|
|
393
|
+
it("aws takes its region from AWS_REGION and its endpoint from AWS_ENDPOINT_URL", () => {
|
|
394
|
+
const { scope, target } = scopeAndTarget(parseIndexArgs(["aws", "--account", ACCOUNT]), { ...deps, env: { ...EMULATOR_ENV, AWS_REGION: "us-west-2", AWS_ENDPOINT_URL: ENDPOINT } });
|
|
395
|
+
expect(scope).toEqual({ substrate: "aws", scopeId: ACCOUNT, locations: ["us-west-2"], types: "*" });
|
|
396
|
+
expect(target).toEqual({ substrate: "aws", aws: { endpoint: ENDPOINT, credentials: { accessKeyId: "test", secretAccessKey: "test" } } });
|
|
397
|
+
});
|
|
398
|
+
it("azure and gcp read chant's token variables", () => {
|
|
399
|
+
const az = scopeAndTarget(parseIndexArgs(["azure", "--subscription", "s", "--endpoint", "https://localhost:4577"]), { ...deps, env: { CHANT_AZURE_TOKEN: "a" } });
|
|
400
|
+
expect(az.target).toEqual({ substrate: "azure", azure: { endpoint: "https://localhost:4577", token: "a" } });
|
|
401
|
+
const g = scopeAndTarget(parseIndexArgs(["gcp", "--project", "p", "--endpoint", "http://localhost:4588/cloudasset"]), { ...deps, env: { CHANT_GCP_TOKEN: "g" } });
|
|
402
|
+
expect(g.target).toEqual({ substrate: "gcp", gcp: { endpoint: "http://localhost:4588/cloudasset", token: "g" } });
|
|
403
|
+
});
|
|
404
|
+
it("gcp --anonymous sends no token, and needs an endpoint", () => {
|
|
405
|
+
const { target } = scopeAndTarget(parseIndexArgs(["gcp", "--project", "plc-corpus", "--endpoint", "http://localhost:4588/cloudasset", "--anonymous"]), { ...deps, env: {} });
|
|
406
|
+
expect(target).toEqual({ substrate: "gcp", gcp: { endpoint: "http://localhost:4588/cloudasset", token: null } });
|
|
407
|
+
expect(() => parseIndexArgs(["gcp", "--project", "p", "--anonymous"])).toThrow(/needs --endpoint/);
|
|
408
|
+
});
|
|
409
|
+
it("needs a scope id, and skips TLS checks only on loopback", () => {
|
|
410
|
+
expect(() => scopeAndTarget(parseIndexArgs(["azure"]), { ...deps, env: {} })).toThrow(/--subscription/);
|
|
411
|
+
expect(() => scopeAndTarget(parseIndexArgs(["azure", "--subscription", "s", "--endpoint", "https://management.azure.com", "--insecure-skip-verify"]), { ...deps, env: {} })).toThrow(/loopback/);
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
describe("the default store location (behold#1025 Q4)", () => {
|
|
416
|
+
it("is chant's per-user data directory", () => {
|
|
417
|
+
expect(chantUserStoreDir({ XDG_DATA_HOME: "/x" }, "/h")).toBe(join("/x", "chant"));
|
|
418
|
+
expect(chantUserStoreDir({}, "/h")).toBe(join("/h", ".local", "share", "chant"));
|
|
419
|
+
expect(chantUserStoreDir({ XDG_DATA_HOME: "relative" }, "/h")).toBe(join("/h", ".local", "share", "chant"));
|
|
420
|
+
expect(chantUserStoreDir({ CHANT_INDEX_DIR: "/d/index" }, "/h")).toBe("/d");
|
|
421
|
+
expect(() => chantUserStoreDir({ CHANT_INDEX_DIR: "/d/elsewhere" }, "/h")).toThrow(/must end in \/index/);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it("is used with no project and no --store, wherever the command runs", () => {
|
|
425
|
+
const none = () => false;
|
|
426
|
+
const dflt = () => chantUserStoreDir({ XDG_DATA_HOME: "/x" }, "/h");
|
|
427
|
+
expect(planIndexStore({ cwd: "/a/b", env: {}, defaultStoreDir: dflt, exists: none })).toEqual({ kind: "user", dir: join("/x", "chant") });
|
|
428
|
+
expect(planIndexStore({ cwd: "/elsewhere", env: {}, defaultStoreDir: dflt, exists: none })).toEqual({ kind: "user", dir: join("/x", "chant") });
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
it("is the caller's when it passes one (behold's userIndexDir parent)", async () => {
|
|
432
|
+
const store = fakeStore();
|
|
433
|
+
await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1"], {
|
|
434
|
+
command: "behold index",
|
|
435
|
+
defaultStoreDir: () => "/x/behold",
|
|
436
|
+
env: EMULATOR_ENV,
|
|
437
|
+
cwd: "/",
|
|
438
|
+
exists: () => false,
|
|
439
|
+
stdout: () => {},
|
|
440
|
+
stderr: () => {},
|
|
441
|
+
list: fakeLister().list,
|
|
442
|
+
openStore: store.openStore,
|
|
443
|
+
lexicons: noLexicons,
|
|
444
|
+
});
|
|
445
|
+
expect(store.opened).toEqual([{ kind: "user", dir: "/x/behold" }]);
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
it("gives way to a chant project's store, and to --store", () => {
|
|
449
|
+
const exists = (p: string) => p === join("/proj", "chant.config.ts");
|
|
450
|
+
const dflt = () => "/unused";
|
|
451
|
+
expect(findChantProject(join("/proj", "sub"), exists)).toBe("/proj");
|
|
452
|
+
expect(planIndexStore({ cwd: join("/proj", "sub"), env: {}, defaultStoreDir: dflt, exists })).toEqual({ kind: "project", projectDir: "/proj" });
|
|
453
|
+
const local = planIndexStore({ store: "local:out", cwd: "/w", env: {}, defaultStoreDir: dflt, exists });
|
|
454
|
+
expect(local).toMatchObject({ kind: "spec", configured: { store: "local" }, env: { CHANT_SNAPSHOT_STORE: "local", CHANT_SNAPSHOT_STORE_DIR: join("/w", "out") } });
|
|
455
|
+
const s3 = planIndexStore({ store: "s3://bucket/some/prefix/", cwd: "/w", env: {}, defaultStoreDir: dflt });
|
|
456
|
+
expect(s3).toMatchObject({ kind: "spec", env: { CHANT_SNAPSHOT_STORE: "s3", CHANT_SNAPSHOT_S3_BUCKET: "bucket", CHANT_SNAPSHOT_S3_PREFIX: "some/prefix" } });
|
|
457
|
+
expect(planIndexStore({ store: "git-ref:refs/x", cwd: "/w", env: {}, defaultStoreDir: dflt })).toMatchObject({ configured: { store: "git-ref", ref: "refs/x" } });
|
|
458
|
+
expect(() => planIndexStore({ store: "orphan-branch", cwd: "/w", env: {}, defaultStoreDir: dflt })).toThrow(/read-only/);
|
|
459
|
+
expect(() => planIndexStore({ store: "ftp://x", cwd: "/w", env: {}, defaultStoreDir: dflt })).toThrow(/not a store spec/);
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
describe("chant index with the real local store", () => {
|
|
464
|
+
it("writes only under the per-user store, and two runs give two versions under one scope.json", async () => {
|
|
465
|
+
const t = tempTree();
|
|
466
|
+
const lister = fakeLister();
|
|
467
|
+
const env = { ...EMULATOR_ENV, XDG_DATA_HOME: t.xdg };
|
|
468
|
+
const opts: RunCloudIndexOptions = { cwd: t.cwd, home: t.home, env, stdout: () => {}, stderr: () => {}, list: lister.list, lexicons: noLexicons, exists: () => false };
|
|
469
|
+
const argv = ["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--types", "AWS::S3::Bucket,AWS::IAM::Role"];
|
|
470
|
+
expect(await runCloudIndex(argv, opts)).toBe(0);
|
|
471
|
+
expect(await runCloudIndex(argv, opts)).toBe(0);
|
|
472
|
+
|
|
473
|
+
const all = files(t.root);
|
|
474
|
+
const storeIndex = relative(t.root, join(t.xdg, "chant", "index")) + sep;
|
|
475
|
+
expect(all.length).toBeGreaterThan(0);
|
|
476
|
+
for (const f of all) expect(f.startsWith(storeIndex), f).toBe(true);
|
|
477
|
+
expect(files(t.cwd)).toEqual([]);
|
|
478
|
+
expect(files(t.home)).toEqual([]);
|
|
479
|
+
|
|
480
|
+
const versions = all.filter((f) => /\d{8}T\d{6}Z-[0-9a-f]{12}\.json$/.test(f));
|
|
481
|
+
expect(versions).toHaveLength(2);
|
|
482
|
+
expect(all.filter((f) => f.endsWith(`${sep}scope.json`))).toHaveLength(1);
|
|
483
|
+
expect(versions.every((v) => v.includes(`${sep}cloud${sep}aws${sep}${ACCOUNT}${sep}`))).toBe(true);
|
|
484
|
+
|
|
485
|
+
const store = createSnapshotStore({ store: "local", dir: join(t.xdg, "chant") }, { cwd: t.cwd });
|
|
486
|
+
const scopeKey = relative(storeIndex, versions[0]).split(sep).slice(0, -1).join("/");
|
|
487
|
+
expect(await store.listIndex(scopeKey)).toHaveLength(2);
|
|
488
|
+
});
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
describe("the real lister through the command", () => {
|
|
492
|
+
it("lists over a fake fetcher with static credentials and sends only reads", async () => {
|
|
493
|
+
const store = fakeStore();
|
|
494
|
+
const fake = fakeFetcher(() => json(200, { TypeName: "AWS::S3::Bucket", ResourceDescriptions: [] }));
|
|
495
|
+
const chains = refusingChains();
|
|
496
|
+
const code = await runCloudIndex(["aws", "--endpoint", ENDPOINT, "--account", ACCOUNT, "--regions", "us-east-1", "--types", "AWS::S3::Bucket"], {
|
|
497
|
+
env: EMULATOR_ENV,
|
|
498
|
+
cwd: "/",
|
|
499
|
+
exists: () => false,
|
|
500
|
+
stdout: () => {},
|
|
501
|
+
stderr: () => {},
|
|
502
|
+
listOptions: { fetcher: fake.fetcher, chains, retryDelays: [] },
|
|
503
|
+
openStore: store.openStore,
|
|
504
|
+
lexicons: noLexicons,
|
|
505
|
+
});
|
|
506
|
+
expect(code).toBe(0);
|
|
507
|
+
expect(fake.calls).toHaveLength(1);
|
|
508
|
+
expect(fake.calls[0].headers["x-amz-target"] ?? fake.calls[0].headers["X-Amz-Target"]).toBe("CloudApiService.ListResources");
|
|
509
|
+
expect(chains.count).toEqual({ aws: 0, azure: 0, gcp: 0 });
|
|
510
|
+
expect(store.writes).toHaveLength(1);
|
|
511
|
+
});
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
// listCloud is the lister's own export, re-exported for library callers.
|
|
515
|
+
it("re-exports the lister", () => {
|
|
516
|
+
expect(typeof listCloud).toBe("function");
|
|
517
|
+
});
|