@intentius/chant 0.124.51 → 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 +17 -3
- 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 +224 -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/covered-round.d.ts +173 -0
- package/dist/components/covered-round.d.ts.map +1 -0
- package/dist/components/covered-round.js +200 -0
- 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 +42 -1
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +74 -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 +7 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +5 -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 +62 -7
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +354 -53
- 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/components/wave-plan.d.ts +2 -0
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +4 -1
- 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 +92 -3
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +62 -3
- 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 +76 -3
- 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 +16 -3
- 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 +238 -0
- package/src/components/cli-support.ts +70 -14
- package/src/components/covered-round.test.ts +166 -0
- package/src/components/covered-round.ts +293 -0
- 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 +101 -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 +59 -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 +728 -4
- package/src/components/pr-run.ts +395 -55
- 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/components/wave-plan.ts +5 -2
- 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 +57 -1
- package/src/pr-loop.ts +154 -6
- 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 +76 -3
- 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,125 @@
|
|
|
1
|
+
{
|
|
2
|
+
"missing": [
|
|
3
|
+
"cacheTopic"
|
|
4
|
+
],
|
|
5
|
+
"orphan": [],
|
|
6
|
+
"runtimeChildren": [],
|
|
7
|
+
"disappeared": [
|
|
8
|
+
"strayTopic"
|
|
9
|
+
],
|
|
10
|
+
"newlyObserved": [
|
|
11
|
+
"alertsTopic",
|
|
12
|
+
"quietSg",
|
|
13
|
+
"webSg"
|
|
14
|
+
],
|
|
15
|
+
"driftedSinceSnapshot": [
|
|
16
|
+
{
|
|
17
|
+
"name": "appRole",
|
|
18
|
+
"type": "AWS::IAM::Role",
|
|
19
|
+
"changes": [
|
|
20
|
+
{
|
|
21
|
+
"path": "status",
|
|
22
|
+
"oldValue": "CREATE_COMPLETE",
|
|
23
|
+
"newValue": "EXTERNAL"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"path": "lastUpdated",
|
|
27
|
+
"oldValue": "2026-10-26T06:31:45.132045382Z"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": "attributes.region",
|
|
31
|
+
"oldValue": "us-east-1"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"path": "attributes.Arn",
|
|
35
|
+
"newValue": "arn:aws:iam::000000000000:role/ry-app-role"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "attributes.RoleName",
|
|
39
|
+
"newValue": "ry-app-role"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "attributes.Path",
|
|
43
|
+
"newValue": "/"
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "dataBucket",
|
|
49
|
+
"type": "AWS::S3::Bucket",
|
|
50
|
+
"changes": [
|
|
51
|
+
{
|
|
52
|
+
"path": "status",
|
|
53
|
+
"oldValue": "CREATE_COMPLETE",
|
|
54
|
+
"newValue": "UPDATE_COMPLETE"
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"path": "lastUpdated",
|
|
58
|
+
"oldValue": "2026-10-26T06:31:45.132492549Z",
|
|
59
|
+
"newValue": "2026-10-26T06:32:00.156983792Z"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "dataBucketPolicy",
|
|
65
|
+
"type": "AWS::S3::BucketPolicy",
|
|
66
|
+
"changes": [
|
|
67
|
+
{
|
|
68
|
+
"path": "status",
|
|
69
|
+
"oldValue": "CREATE_COMPLETE",
|
|
70
|
+
"newValue": "UPDATE_COMPLETE"
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
"path": "physicalId",
|
|
74
|
+
"oldValue": "bucket-policy-4516bdd6",
|
|
75
|
+
"newValue": "bucket-policy-993b2ead"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"path": "lastUpdated",
|
|
79
|
+
"oldValue": "2026-10-26T06:31:45.133049215Z",
|
|
80
|
+
"newValue": "2026-10-26T06:32:00.157473792Z"
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "eventsTopic",
|
|
86
|
+
"type": "AWS::SNS::Topic",
|
|
87
|
+
"changes": [
|
|
88
|
+
{
|
|
89
|
+
"path": "status",
|
|
90
|
+
"oldValue": "CREATE_COMPLETE",
|
|
91
|
+
"newValue": "UPDATE_COMPLETE"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "lastUpdated",
|
|
95
|
+
"oldValue": "2026-10-26T06:31:45.132664465Z",
|
|
96
|
+
"newValue": "2026-10-26T06:32:00.157185292Z"
|
|
97
|
+
}
|
|
98
|
+
]
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"name": "taskQueue",
|
|
102
|
+
"type": "AWS::SQS::Queue",
|
|
103
|
+
"changes": [
|
|
104
|
+
{
|
|
105
|
+
"path": "status",
|
|
106
|
+
"oldValue": "CREATE_COMPLETE",
|
|
107
|
+
"newValue": "UPDATE_COMPLETE"
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
"path": "lastUpdated",
|
|
111
|
+
"oldValue": "2026-10-26T06:31:45.132903549Z",
|
|
112
|
+
"newValue": "2026-10-26T06:32:00.157365833Z"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
],
|
|
117
|
+
"unchanged": [],
|
|
118
|
+
"unobserved": [],
|
|
119
|
+
"queried": {
|
|
120
|
+
"appRole": "cloudcontrol:GetResource:AWS::IAM::Role:ry-app-role"
|
|
121
|
+
},
|
|
122
|
+
"definitions": {
|
|
123
|
+
"cacheTopic": "cfbb459653feffdc748e920ae9f0eb9a0c78d8efcd82cc21b74371be533e2e66"
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -137,6 +137,20 @@ describe("discoverByDetection (unified, detectTemplate-driven)", () => {
|
|
|
137
137
|
expect(found.find((i) => i.path === "live/app")!.content).toContain("# file: terragrunt.hcl");
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
+
test(".tf.json, .tofu and .tofu.json files join the terraform bundle beside .tf (chant#4457)", () => {
|
|
141
|
+
const files = [
|
|
142
|
+
{ path: "app/main.tf", content: 'resource "x" "a" {}\n' },
|
|
143
|
+
{ path: "app/extra.tf.json", content: '{"resource": {"x": {"b": {}}}}\n' },
|
|
144
|
+
{ path: "app/tofu.tofu", content: 'resource "x" "c" {}\n' },
|
|
145
|
+
{ path: "app/tofu.tofu.json", content: '{"resource": {"x": {"d": {}}}}\n' },
|
|
146
|
+
];
|
|
147
|
+
const found = classifyFiles(files, [terraform]);
|
|
148
|
+
expect(targets(found)).toEqual(["terraform:app"]);
|
|
149
|
+
expect(Object.keys(found[0]!.files!).sort()).toEqual(["extra.tf.json", "main.tf", "tofu.tofu", "tofu.tofu.json"]);
|
|
150
|
+
expect(hintLexiconForFile("app/extra.tf.json", "{}")).toBe("terraform");
|
|
151
|
+
expect(hintLexiconForFile("app/tofu.tofu", "")).toBe("terraform");
|
|
152
|
+
});
|
|
153
|
+
|
|
140
154
|
test("without the terraform plugin, .tf files are classified into nothing (skipped, same as an unloaded helm)", () => {
|
|
141
155
|
const found = discoverByDetection(fixture("audit-terraform"), []);
|
|
142
156
|
expect(found).toEqual([]);
|
package/src/audit/discover.ts
CHANGED
|
@@ -153,7 +153,9 @@ function isDockerfileName(name: string): boolean {
|
|
|
153
153
|
function isTerraformFileName(name: string): boolean {
|
|
154
154
|
// `terragrunt.hcl` and `root.hcl` ride in the terraform bundle (#3417): the
|
|
155
155
|
// terraform lexicon reads them into Terragrunt entities, apart from modules.
|
|
156
|
-
|
|
156
|
+
// `.tf.json`, `.tofu` and `.tofu.json` are configuration too (chant#4457);
|
|
157
|
+
// which of them a root reads is the lexicon's call, by its binary.
|
|
158
|
+
return /\.(tf|tofu)(\.json)?$/i.test(name) || name === "terragrunt.hcl" || name === "root.hcl";
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
/**
|
package/src/behaviour.ts
CHANGED
|
@@ -411,7 +411,7 @@ export interface PredictedBehaviour {
|
|
|
411
411
|
* at an address that is answering perfectly well.
|
|
412
412
|
*/
|
|
413
413
|
export type BehaviourUnpredictedReason =
|
|
414
|
-
| Exclude<UnobservedReason, "no-credentials">
|
|
414
|
+
| Exclude<UnobservedReason, "no-credentials" | "not-reached">
|
|
415
415
|
| "no-engine"
|
|
416
416
|
| "engine-unreachable"
|
|
417
417
|
| "engine-out-of-credit"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"templates": [
|
|
4
|
+
{
|
|
5
|
+
"id": "dependents",
|
|
6
|
+
"title": "What depends on it",
|
|
7
|
+
"question": "what reads this resource, directly or through others, in its own project",
|
|
8
|
+
"sources": ["chant"],
|
|
9
|
+
"inputs": [
|
|
10
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
11
|
+
],
|
|
12
|
+
"reads": "source",
|
|
13
|
+
"query": { "kind": "path", "text": "->*{{node}}" }
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "dependencies",
|
|
17
|
+
"title": "What it depends on",
|
|
18
|
+
"question": "what this resource reads, directly or through others, in its own project",
|
|
19
|
+
"sources": ["chant"],
|
|
20
|
+
"inputs": [
|
|
21
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
22
|
+
],
|
|
23
|
+
"reads": "source",
|
|
24
|
+
"query": { "kind": "path", "text": "<-*{{node}}" }
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "paths-to-kind",
|
|
28
|
+
"title": "Paths from it to a kind",
|
|
29
|
+
"question": "does this resource reach anything of a given kind, and by which path",
|
|
30
|
+
"sources": ["chant"],
|
|
31
|
+
"inputs": [
|
|
32
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." },
|
|
33
|
+
{ "name": "kind", "kind": "term", "description": "A kind or type, as kind: takes it (aws_internet_gateway, EC2::InternetGateway)." }
|
|
34
|
+
],
|
|
35
|
+
"reads": "source",
|
|
36
|
+
"query": { "kind": "path", "text": "{{node}} ->*kind:{{kind}}" }
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"id": "capability",
|
|
40
|
+
"title": "Whether a capability holds for it",
|
|
41
|
+
"question": "does a capability from the catalog hold for this resource",
|
|
42
|
+
"sources": ["chant"],
|
|
43
|
+
"inputs": [
|
|
44
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." },
|
|
45
|
+
{ "name": "capability", "kind": "term", "description": "A capability from chant's catalog, with its arguments: internet-reachable(22)." }
|
|
46
|
+
],
|
|
47
|
+
"reads": "source",
|
|
48
|
+
"query": { "kind": "path", "text": "{{node}} cap:{{capability}}" }
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"id": "drift",
|
|
52
|
+
"title": "Drift",
|
|
53
|
+
"question": "has this resource drifted from its declaration in an environment",
|
|
54
|
+
"sources": ["chant"],
|
|
55
|
+
"inputs": [
|
|
56
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." },
|
|
57
|
+
{ "name": "env", "kind": "scope", "description": "The environment to read live." }
|
|
58
|
+
],
|
|
59
|
+
"reads": "live",
|
|
60
|
+
"query": { "kind": "path", "text": "{{node}}" },
|
|
61
|
+
"note": "Draws the node in the environment's live read, coloured by drift."
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"id": "dependents-all",
|
|
65
|
+
"title": "What depends on it, across every source",
|
|
66
|
+
"question": "what reads this resource, in any project, root or stack loaded into the session",
|
|
67
|
+
"inputs": [
|
|
68
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
69
|
+
],
|
|
70
|
+
"reads": "session",
|
|
71
|
+
"query": {
|
|
72
|
+
"kind": "cypher",
|
|
73
|
+
"text": "MATCH (o:Resource)-[:REF*1..6]->(r:Resource {key: $key}) RETURN DISTINCT o.key AS key, o.kind AS kind, o.scopeKey AS scope"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"id": "dependencies-all",
|
|
78
|
+
"title": "What it depends on, across every source",
|
|
79
|
+
"question": "what this resource reads, in any project, root or stack loaded into the session",
|
|
80
|
+
"inputs": [
|
|
81
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
82
|
+
],
|
|
83
|
+
"reads": "session",
|
|
84
|
+
"query": {
|
|
85
|
+
"kind": "cypher",
|
|
86
|
+
"text": "MATCH (r:Resource {key: $key})-[:REF*1..6]->(o:Resource) RETURN DISTINCT o.key AS key, o.kind AS kind, o.scopeKey AS scope"
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"id": "ownership",
|
|
91
|
+
"title": "Ownership",
|
|
92
|
+
"question": "who owns this cloud ID, and which other sources know the same object",
|
|
93
|
+
"inputs": [
|
|
94
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
95
|
+
],
|
|
96
|
+
"reads": "session",
|
|
97
|
+
"query": {
|
|
98
|
+
"kind": "cypher",
|
|
99
|
+
"text": "MATCH (r:Resource {key: $key}) OPTIONAL MATCH (r)-[:KNOWN_AS]->(:CloudId)<-[:KNOWN_AS]-(o:Resource) WHERE o.key <> r.key RETURN r.key AS key, r.ownership AS ownership, r.engineOwnership AS engineOwnership, r.facts AS facts, r.observedAt AS observedAt, collect(DISTINCT o.key) AS sameObject"
|
|
100
|
+
},
|
|
101
|
+
"note": "ownership is chant's marker verdict, owned or foreign. engineOwnership is an engine's, bound, unowned, pending or foreign. Absent is unknown, never guessed. A cloud listing reads markers only."
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "same-object",
|
|
105
|
+
"title": "The same object in other sources",
|
|
106
|
+
"question": "where else is the object behind this resource declared or recorded",
|
|
107
|
+
"inputs": [
|
|
108
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
109
|
+
],
|
|
110
|
+
"reads": "session",
|
|
111
|
+
"query": {
|
|
112
|
+
"kind": "cypher",
|
|
113
|
+
"text": "MATCH (r:Resource {key: $key})-[:KNOWN_AS]->(c:CloudId)<-[:KNOWN_AS]-(o:Resource) WHERE o.scopeKey <> r.scopeKey RETURN DISTINCT o.key AS key, o.scopeKey AS scope, c.value AS cloudId, c.kind AS cloudIdKind"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "readers",
|
|
118
|
+
"title": "Who reads it from another estate or root",
|
|
119
|
+
"question": "which other estate or root reads this resource",
|
|
120
|
+
"inputs": [
|
|
121
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
122
|
+
],
|
|
123
|
+
"reads": "session",
|
|
124
|
+
"query": {
|
|
125
|
+
"kind": "cypher",
|
|
126
|
+
"text": "MATCH (o:Resource)-[e:REF]->(r:Resource {key: $key}) WHERE o.scopeKey <> r.scopeKey RETURN o.key AS key, o.scopeKey AS scope, e.viaAttr AS via, e.origin AS origin, e.rule AS rule UNION MATCH (r:Resource {key: $key})-[:KNOWN_AS]->(:CloudId)<-[:KNOWN_AS]-(t:Resource)<-[e:REF]-(o:Resource) WHERE o.scopeKey <> r.scopeKey RETURN o.key AS key, o.scopeKey AS scope, e.viaAttr AS via, e.origin AS origin, e.rule AS rule"
|
|
127
|
+
},
|
|
128
|
+
"note": "A derived edge (origin derived, rule identity:<kind>) is an identity match, not a declared reference."
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
"id": "history",
|
|
132
|
+
"title": "History",
|
|
133
|
+
"question": "how has this resource's record changed over time",
|
|
134
|
+
"inputs": [
|
|
135
|
+
{ "name": "node", "kind": "resource", "description": "The resource: a name, an IR id, a block address or a cloud ID." }
|
|
136
|
+
],
|
|
137
|
+
"reads": "snapshots",
|
|
138
|
+
"query": {
|
|
139
|
+
"kind": "cypher",
|
|
140
|
+
"text": "MATCH (r:Resource {key: $key}) RETURN r.key AS key, r.facts AS facts, r.version AS version, r.observedAt AS observedAt"
|
|
141
|
+
},
|
|
142
|
+
"note": "The record's versions come from facts.recordVersions, when the engine ran with -history or --versions. Snapshot history (chant#4519's store) is not loaded into the session yet."
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Investigation templates (#4531): the catalog's second kind of entry. Every
|
|
3
|
+
* shipped template holds to the entry kind, every path template parses as a
|
|
4
|
+
* chant search query and runs against a fixture graph, and the data file is
|
|
5
|
+
* exported for behold and choudoufu.
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { describe, expect, it } from "vitest";
|
|
10
|
+
import type { GraphIR } from "../graph-ir";
|
|
11
|
+
import { __searchInternals, resolveKindTerms } from "../cli/handlers/search";
|
|
12
|
+
import { NEXT_RELEASE } from "../release-floors";
|
|
13
|
+
import {
|
|
14
|
+
CAPABILITY_TEMPLATES_FLOOR,
|
|
15
|
+
TemplateCatalogError,
|
|
16
|
+
expandTemplate,
|
|
17
|
+
investigationTemplates,
|
|
18
|
+
parseTemplates,
|
|
19
|
+
type TemplateEntry,
|
|
20
|
+
} from "./templates";
|
|
21
|
+
import data from "./templates.json" with { type: "json" };
|
|
22
|
+
|
|
23
|
+
const { parseQuery, matchTerm } = __searchInternals;
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* A CloudFormation project's graph: an instance in a subnet in a VPC, and a
|
|
27
|
+
* security group nothing uses. Edges point from the consumer to what it
|
|
28
|
+
* references. The ids share no substring, since a bare word matches by
|
|
29
|
+
* substring.
|
|
30
|
+
*/
|
|
31
|
+
const node = (id: string, kind: string) => ({ id, kind, lexicon: "aws", attrs: {} });
|
|
32
|
+
const fixture = (): GraphIR =>
|
|
33
|
+
({
|
|
34
|
+
nodes: [
|
|
35
|
+
node("AppVpc", "AWS::EC2::VPC"),
|
|
36
|
+
node("AppSubnet", "AWS::EC2::Subnet"),
|
|
37
|
+
node("WebHost", "AWS::EC2::Instance"),
|
|
38
|
+
node("SpareGroup", "AWS::EC2::SecurityGroup"),
|
|
39
|
+
],
|
|
40
|
+
edges: [
|
|
41
|
+
{ from: "AppSubnet", to: "AppVpc", kind: "ref", viaAttr: "VpcId", toAttr: "id" },
|
|
42
|
+
{ from: "WebHost", to: "AppSubnet", kind: "ref", viaAttr: "SubnetId", toAttr: "id" },
|
|
43
|
+
],
|
|
44
|
+
groups: {},
|
|
45
|
+
}) as unknown as GraphIR;
|
|
46
|
+
|
|
47
|
+
/** Run a chant search query over a graph as runSearch matches it, returning the matched ids. */
|
|
48
|
+
function search(ir: GraphIR, query: string): string[] {
|
|
49
|
+
const terms = parseQuery(query);
|
|
50
|
+
resolveKindTerms(terms, ir.nodes);
|
|
51
|
+
const byId = new Map(ir.nodes.map((n) => [n.id, n]));
|
|
52
|
+
return ir.nodes.filter((n) => terms.every((t) => matchTerm(n, t, ir, byId))).map((n) => n.id).sort();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Each path template's run against the fixture: the inputs, and the ids the
|
|
57
|
+
* query must match. A path template missing here fails the test below.
|
|
58
|
+
*/
|
|
59
|
+
const PATH_CASES: Record<string, { inputs: Record<string, string>; matches: string[] }[]> = {
|
|
60
|
+
dependents: [
|
|
61
|
+
{ inputs: { node: "AppVpc" }, matches: ["AppSubnet", "WebHost"] },
|
|
62
|
+
{ inputs: { node: "WebHost" }, matches: [] },
|
|
63
|
+
],
|
|
64
|
+
dependencies: [
|
|
65
|
+
{ inputs: { node: "WebHost" }, matches: ["AppSubnet", "AppVpc"] },
|
|
66
|
+
{ inputs: { node: "AppVpc" }, matches: [] },
|
|
67
|
+
],
|
|
68
|
+
"paths-to-kind": [
|
|
69
|
+
{ inputs: { node: "WebHost", kind: "AWS::EC2::VPC" }, matches: ["WebHost"] },
|
|
70
|
+
{ inputs: { node: "SpareGroup", kind: "AWS::EC2::VPC" }, matches: [] },
|
|
71
|
+
],
|
|
72
|
+
capability: [
|
|
73
|
+
{ inputs: { node: "SpareGroup", capability: "attached-to-nothing" }, matches: ["SpareGroup"] },
|
|
74
|
+
{ inputs: { node: "WebHost", capability: "attached-to-nothing" }, matches: [] },
|
|
75
|
+
],
|
|
76
|
+
drift: [{ inputs: { node: "WebHost", env: "prod" }, matches: ["WebHost"] }],
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/** The set behold#1027 stubbed in behold's src/graph-db/templates.ts. */
|
|
80
|
+
const BEHOLD_STUB = [
|
|
81
|
+
"dependents",
|
|
82
|
+
"dependencies",
|
|
83
|
+
"paths-to-kind",
|
|
84
|
+
"capability",
|
|
85
|
+
"drift",
|
|
86
|
+
"dependents-all",
|
|
87
|
+
"dependencies-all",
|
|
88
|
+
"ownership",
|
|
89
|
+
"same-object",
|
|
90
|
+
"readers",
|
|
91
|
+
"history",
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
describe("the shipped templates", () => {
|
|
95
|
+
it("parse, and are behold's stubbed set", () => {
|
|
96
|
+
const templates = investigationTemplates();
|
|
97
|
+
expect(templates.map((t) => t.id)).toEqual(BEHOLD_STUB);
|
|
98
|
+
for (const t of templates) {
|
|
99
|
+
expect(t.inputs[0], t.id).toMatchObject({ name: "node", kind: "resource" });
|
|
100
|
+
expect(t.question.length, t.id).toBeGreaterThan(0);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("say which language each expands to: the in-project questions are path patterns, the cross-source ones Cypher", () => {
|
|
105
|
+
const byKind = (k: string) => investigationTemplates().filter((t) => t.query.kind === k).map((t) => t.id);
|
|
106
|
+
expect(byKind("path")).toEqual(["dependents", "dependencies", "paths-to-kind", "capability", "drift"]);
|
|
107
|
+
expect(byKind("cypher")).toEqual(["dependents-all", "dependencies-all", "ownership", "same-object", "readers", "history"]);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("every path template parses as a chant search query and runs against the fixture", () => {
|
|
111
|
+
const paths = investigationTemplates().filter((t) => t.query.kind === "path");
|
|
112
|
+
expect(Object.keys(PATH_CASES).sort()).toEqual(paths.map((t) => t.id).sort());
|
|
113
|
+
for (const t of paths) {
|
|
114
|
+
for (const c of PATH_CASES[t.id]!) {
|
|
115
|
+
const expanded = expandTemplate(t, c.inputs);
|
|
116
|
+
expect(() => parseQuery(expanded.text), `${t.id}: ${expanded.text}`).not.toThrow();
|
|
117
|
+
expect(search(fixture(), expanded.text), `${t.id}: ${expanded.text}`).toEqual(c.matches);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("a scope input says where the query is read and stays out of its text", () => {
|
|
123
|
+
const drift = investigationTemplates().find((t) => t.id === "drift")!;
|
|
124
|
+
expect(expandTemplate(drift, { node: "WebHost", env: "prod" })).toEqual({
|
|
125
|
+
template: "drift",
|
|
126
|
+
kind: "path",
|
|
127
|
+
reads: "live",
|
|
128
|
+
text: "WebHost",
|
|
129
|
+
scope: { env: "prod" },
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("a Cypher template binds the node as $key and splices nothing into its text", () => {
|
|
134
|
+
for (const t of investigationTemplates().filter((x) => x.query.kind === "cypher")) {
|
|
135
|
+
const e = expandTemplate(t, { node: "chant:app/AppVpc" });
|
|
136
|
+
expect(e.text, t.id).toBe(t.query.text);
|
|
137
|
+
expect(e.params, t.id).toEqual({ key: "chant:app/AppVpc" });
|
|
138
|
+
expect(e.text, t.id).not.toContain("chant:app/AppVpc");
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("ownership returns chant's verdict and the engine's as two columns, as behold's stub does (behold#906 Q4, behold#1031)", () => {
|
|
143
|
+
const t = investigationTemplates().find((x) => x.id === "ownership")!;
|
|
144
|
+
expect(t.query.text).toContain("r.ownership AS ownership");
|
|
145
|
+
expect(t.query.text).toContain("r.engineOwnership AS engineOwnership");
|
|
146
|
+
expect(t.query.text).not.toMatch(/coalesce\(/i);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it("refuses a value that would add a second search term, a missing input and an unknown one", () => {
|
|
150
|
+
const t = investigationTemplates().find((x) => x.id === "paths-to-kind")!;
|
|
151
|
+
expect(() => expandTemplate(t, { node: "WebHost", kind: "aws_vpc cap:blast" })).toThrow(/not one search term/);
|
|
152
|
+
expect(() => expandTemplate(t, { node: "WebHost" })).toThrow(/needs kind/);
|
|
153
|
+
expect(() => expandTemplate(t, { node: "WebHost", kind: "aws_vpc", env: "prod" })).toThrow(/takes no input env/);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe("the entry kind", () => {
|
|
158
|
+
const valid = (): TemplateEntry => ({
|
|
159
|
+
id: "t",
|
|
160
|
+
title: "T",
|
|
161
|
+
question: "what is it",
|
|
162
|
+
inputs: [{ name: "node", kind: "resource", description: "the resource" }],
|
|
163
|
+
reads: "source",
|
|
164
|
+
query: { kind: "path", text: "->*{{node}}" },
|
|
165
|
+
});
|
|
166
|
+
const parse = (...templates: unknown[]) => parseTemplates({ version: 1, templates });
|
|
167
|
+
const refuses = (patch: Record<string, unknown>, message: RegExp) =>
|
|
168
|
+
expect(() => parse({ ...valid(), ...patch })).toThrow(message);
|
|
169
|
+
|
|
170
|
+
it("reads a valid entry", () => {
|
|
171
|
+
expect(parse(valid())).toEqual([valid()]);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("refuses an entry that does not hold to it, naming the template", () => {
|
|
175
|
+
expect(() => parseTemplates({ version: 2, templates: [] })).toThrow(TemplateCatalogError);
|
|
176
|
+
expect(() => parse(valid(), valid())).toThrow(/template t: is defined twice/);
|
|
177
|
+
refuses({ id: "Bad Id" }, /needs an id/);
|
|
178
|
+
refuses({ question: "" }, /needs the question/);
|
|
179
|
+
refuses({ reads: "everything" }, /reads is one of/);
|
|
180
|
+
refuses({ query: { kind: "sql", text: "SELECT 1" } }, /query is/);
|
|
181
|
+
refuses({ inputs: [] }, /one resource input, first/);
|
|
182
|
+
refuses({ inputs: [{ name: "env", kind: "scope", description: "e" }, ...valid().inputs] }, /one resource input, first/);
|
|
183
|
+
refuses({ inputs: [...valid().inputs, { name: "kind", kind: "term", description: "k" }] }, /never uses kind/);
|
|
184
|
+
refuses({ query: { kind: "path", text: "->*{{other}}" } }, /names no input/);
|
|
185
|
+
refuses({ query: { kind: "path", text: "->*$key" } }, /not \$parameters/);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("holds a Cypher query to reading, with the node as $key and its inputs as parameters", () => {
|
|
189
|
+
const cypher = (text: string) => ({ query: { kind: "cypher", text } });
|
|
190
|
+
expect(() => parse({ ...valid(), ...cypher("MATCH (r:Resource {key: $key}) RETURN r") })).not.toThrow();
|
|
191
|
+
refuses(cypher("MATCH (r:Resource {key: '{{node}}'}) RETURN r"), /never spliced/);
|
|
192
|
+
refuses(cypher("MATCH (r:Resource {key: $key}) DETACH DELETE r"), /only reads/);
|
|
193
|
+
refuses(cypher("RETURN 1"), /reading clause/);
|
|
194
|
+
refuses(cypher("MATCH (r:Resource {key: $key} RETURN r"), /do not balance/);
|
|
195
|
+
refuses(cypher("MATCH (r:Resource {key: $id}) RETURN r"), /binds the resource as \$key/);
|
|
196
|
+
refuses(cypher("MATCH (r:Resource {key: $key, kind: $kind}) RETURN r"), /\$kind names no input/);
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
describe("the export", () => {
|
|
201
|
+
it("ships templates.json as @intentius/chant/capabilities/templates.json, the data the catalog reads", () => {
|
|
202
|
+
const pkg = JSON.parse(readFileSync(join(import.meta.dirname, "..", "..", "package.json"), "utf-8")) as { exports: Record<string, unknown> };
|
|
203
|
+
expect(pkg.exports["./capabilities/templates.json"]).toBe("./src/capabilities/templates.json");
|
|
204
|
+
const onDisk = JSON.parse(readFileSync(join(import.meta.dirname, "templates.json"), "utf-8")) as unknown;
|
|
205
|
+
expect(onDisk).toEqual(data);
|
|
206
|
+
expect(parseTemplates(onDisk)).toEqual(investigationTemplates());
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("carries its floor at the next release", () => {
|
|
210
|
+
expect(CAPABILITY_TEMPLATES_FLOOR).toBe(NEXT_RELEASE);
|
|
211
|
+
});
|
|
212
|
+
});
|