@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,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: GCP, through Cloud Asset Inventory's `searchAllResources` on
|
|
3
|
+
* one project, paged.
|
|
4
|
+
*
|
|
5
|
+
* Nothing is enabled for the person. The Cloud Asset API has to be on before
|
|
6
|
+
* a project can be searched, and turning it on changes the project. When the
|
|
7
|
+
* search answers SERVICE_DISABLED, the lister lists nothing for the project,
|
|
8
|
+
* marks every coverage entry `read-failed`, and puts the enable command in a
|
|
9
|
+
* note for the person to run. The guard (packages/core/src/cloud-lister/guard.ts) admits no
|
|
10
|
+
* Service Usage call at all, so the lister could not enable it if it tried.
|
|
11
|
+
*
|
|
12
|
+
* Types go in `assetTypes`, a tag filter in the query as `labels.KEY=VALUE`
|
|
13
|
+
* terms. Locations are filtered here, after the search, because floci-gcp's
|
|
14
|
+
* query subset has no location term.
|
|
15
|
+
*
|
|
16
|
+
* The pinned floci-gcp (ghcr.io/lex00/floci-gcp, source 641e6e8) serves this
|
|
17
|
+
* call under the path prefix `/cloudasset` (pass `http://localhost:4588/cloudasset`
|
|
18
|
+
* as the endpoint), for project scopes only, over the assets of four
|
|
19
|
+
* services (Compute, Cloud Storage, IAM, Pub/Sub), with SERVICE_DISABLED
|
|
20
|
+
* answered as GCP answers it when its Service Usage enforcement is on.
|
|
21
|
+
*/
|
|
22
|
+
import { buildResource, describeFailure, listedVerdict, noteTagFilter, withThrottleRetry } from "./common.js";
|
|
23
|
+
import { resolveGcpToken, ListerConfigError } from "./credentials.js";
|
|
24
|
+
import { jsonBody } from "./transport.js";
|
|
25
|
+
const PAGE_SIZE = 500;
|
|
26
|
+
const MAX_PAGES = 10000;
|
|
27
|
+
const PROJECT = /^[A-Za-z0-9._:-]+$/;
|
|
28
|
+
const LABEL_PART = /^[A-Za-z0-9_\-]+$/;
|
|
29
|
+
export function enableCommand(project) {
|
|
30
|
+
return `gcloud services enable cloudasset.googleapis.com --project=${project}`;
|
|
31
|
+
}
|
|
32
|
+
export function searchUrl(target, project, params) {
|
|
33
|
+
const base = (target.endpoint ?? "https://cloudasset.googleapis.com").replace(/\/+$/, "");
|
|
34
|
+
const url = new URL(`${base}/v1/projects/${encodeURIComponent(project)}:searchAllResources`);
|
|
35
|
+
for (const t of params.assetTypes ?? [])
|
|
36
|
+
url.searchParams.append("assetTypes", t);
|
|
37
|
+
if (params.query)
|
|
38
|
+
url.searchParams.set("query", params.query);
|
|
39
|
+
url.searchParams.set("pageSize", String(PAGE_SIZE));
|
|
40
|
+
if (params.pageToken)
|
|
41
|
+
url.searchParams.set("pageToken", params.pageToken);
|
|
42
|
+
return url.toString();
|
|
43
|
+
}
|
|
44
|
+
/** The `query` for a tag filter, or undefined. Exported for tests. */
|
|
45
|
+
export function labelQuery(filter) {
|
|
46
|
+
const entries = Object.entries(filter ?? {});
|
|
47
|
+
if (entries.length === 0)
|
|
48
|
+
return undefined;
|
|
49
|
+
return entries
|
|
50
|
+
.map(([k, v]) => {
|
|
51
|
+
if (!LABEL_PART.test(k) || !LABEL_PART.test(v))
|
|
52
|
+
throw new ListerConfigError(`gcp label filter ${k}=${v} is not a plain label key and value`);
|
|
53
|
+
return `labels.${k}=${v}`;
|
|
54
|
+
})
|
|
55
|
+
.join(" AND ");
|
|
56
|
+
}
|
|
57
|
+
function gcpError(res) {
|
|
58
|
+
const body = jsonBody(res);
|
|
59
|
+
const e = Array.isArray(body) ? body[0]?.error : body?.error;
|
|
60
|
+
const reasons = [...(e?.details ?? []), ...(e?.errors ?? [])]
|
|
61
|
+
.map((d) => d.reason ?? "")
|
|
62
|
+
.filter(Boolean);
|
|
63
|
+
return { status: e?.status ?? "", message: e?.message ?? "", reasons };
|
|
64
|
+
}
|
|
65
|
+
export function isServiceDisabled(res) {
|
|
66
|
+
if (res.status !== 403)
|
|
67
|
+
return false;
|
|
68
|
+
const err = gcpError(res);
|
|
69
|
+
return err.reasons.includes("SERVICE_DISABLED") || err.reasons.includes("accessNotConfigured") || /has not been used in project|is disabled/i.test(err.message);
|
|
70
|
+
}
|
|
71
|
+
export async function listGcp(ctx, target, chains, retryDelays) {
|
|
72
|
+
const { scope } = ctx;
|
|
73
|
+
if (!PROJECT.test(scope.scopeId))
|
|
74
|
+
throw new ListerConfigError(`gcp project ${JSON.stringify(scope.scopeId)} is not a project id`);
|
|
75
|
+
const token = await resolveGcpToken(target, chains);
|
|
76
|
+
const query = labelQuery(scope.tagFilter);
|
|
77
|
+
const assetTypes = scope.types === "*" ? undefined : scope.types;
|
|
78
|
+
const wantLocations = scope.locations === "*" ? undefined : new Set(scope.locations.map((l) => l.toLowerCase()));
|
|
79
|
+
const typesCovered = scope.types === "*" ? ["*"] : [...scope.types];
|
|
80
|
+
const locationsCovered = scope.locations === "*" ? ["*"] : [...scope.locations].map((l) => l.toLowerCase());
|
|
81
|
+
noteTagFilter(ctx, "as labels terms in the Cloud Asset query");
|
|
82
|
+
const found = [];
|
|
83
|
+
let pageToken;
|
|
84
|
+
for (let page = 0; page < MAX_PAGES; page++) {
|
|
85
|
+
const url = searchUrl(target, scope.scopeId, { assetTypes, query, pageToken });
|
|
86
|
+
const headers = { accept: "application/json" };
|
|
87
|
+
if (token !== null)
|
|
88
|
+
headers.authorization = `Bearer ${token}`;
|
|
89
|
+
const res = await withThrottleRetry(() => ctx.transport.send({ substrate: "gcp", method: "GET", url, headers }), (r) => r.status === 429, retryDelays);
|
|
90
|
+
const observedAt = ctx.now().toISOString();
|
|
91
|
+
if (res.status >= 400) {
|
|
92
|
+
const err = gcpError(res);
|
|
93
|
+
const detail = describeFailure(res, err.status, err.message);
|
|
94
|
+
if (isServiceDisabled(res)) {
|
|
95
|
+
const why = `Cloud Asset API is disabled on project ${scope.scopeId}`;
|
|
96
|
+
for (const t of typesCovered)
|
|
97
|
+
for (const l of locationsCovered)
|
|
98
|
+
ctx.coverage.push({ listedType: t, location: l, verdict: "read-failed", detail: why });
|
|
99
|
+
ctx.notes.push({
|
|
100
|
+
code: "api-disabled",
|
|
101
|
+
message: `${why}, so nothing was listed for it. chant never enables an API; enabling it changes the project. To list it, run the command yourself and index again.`,
|
|
102
|
+
command: enableCommand(scope.scopeId),
|
|
103
|
+
});
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const verdict = res.status === 401 || res.status === 403 ? "no-credentials" : "read-failed";
|
|
107
|
+
for (const t of typesCovered)
|
|
108
|
+
for (const l of locationsCovered)
|
|
109
|
+
ctx.coverage.push({ listedType: t, location: l, verdict, detail });
|
|
110
|
+
ctx.notes.push({ code: verdict === "no-credentials" ? "no-credentials" : "read-failed", message: `searchAllResources on project ${scope.scopeId} failed: ${detail}` });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const parsed = jsonBody(res);
|
|
114
|
+
for (const r of parsed?.results ?? []) {
|
|
115
|
+
const name = typeof r.name === "string" ? r.name : undefined;
|
|
116
|
+
const assetType = typeof r.assetType === "string" ? r.assetType : undefined;
|
|
117
|
+
if (!name || !assetType)
|
|
118
|
+
continue;
|
|
119
|
+
const location = (typeof r.location === "string" && r.location ? r.location : "global").toLowerCase();
|
|
120
|
+
if (wantLocations && !wantLocations.has(location))
|
|
121
|
+
continue;
|
|
122
|
+
const tags = {};
|
|
123
|
+
if (r.labels && typeof r.labels === "object") {
|
|
124
|
+
for (const [k, v] of Object.entries(r.labels))
|
|
125
|
+
tags[k] = String(v ?? "");
|
|
126
|
+
}
|
|
127
|
+
const cloudIds = [{ kind: "provider-id", value: name }];
|
|
128
|
+
const attrs = r.additionalAttributes;
|
|
129
|
+
if (attrs && typeof attrs.selfLink === "string")
|
|
130
|
+
cloudIds.push({ kind: "self-link", value: attrs.selfLink });
|
|
131
|
+
const { labels: _labels, ...properties } = r;
|
|
132
|
+
found.push({ listedType: assetType, location, nativeId: name, cloudIds, tags, properties, observedAt, labels: true });
|
|
133
|
+
}
|
|
134
|
+
pageToken = parsed?.nextPageToken || undefined;
|
|
135
|
+
if (!pageToken)
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
for (const r of found)
|
|
139
|
+
ctx.resources.push(buildResource(ctx, r));
|
|
140
|
+
for (const t of typesCovered)
|
|
141
|
+
for (const l of locationsCovered)
|
|
142
|
+
ctx.coverage.push({ listedType: t, location: l, ...listedVerdict(scope) });
|
|
143
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: read-only by construction.
|
|
3
|
+
*
|
|
4
|
+
* Every request the lister makes is a {@link WireCall}, and every WireCall
|
|
5
|
+
* goes through {@link assertReadCall} before anything reaches the network
|
|
6
|
+
* (packages/core/src/cloud-lister/transport.ts is the only sender). The check classifies the
|
|
7
|
+
* call from what would go on the wire (method, path, `X-Amz-Target`), never
|
|
8
|
+
* from a label the caller attaches, and admits only the operations in
|
|
9
|
+
* {@link READ_OPERATIONS}:
|
|
10
|
+
*
|
|
11
|
+
* - aws: Cloud Control `ListResources` (a POST, but the JSON protocol's only
|
|
12
|
+
* verb; the target header names the operation);
|
|
13
|
+
* - azure: Resource Graph's query, `POST /providers/Microsoft.ResourceGraph/resources`
|
|
14
|
+
* (a read that takes its KQL in the body);
|
|
15
|
+
* - gcp: Cloud Asset `searchAllResources`, a GET. Nothing under
|
|
16
|
+
* `serviceusage` is admitted, so the lister cannot enable the Cloud Asset
|
|
17
|
+
* API on a project (#1029: "nothing is enabled for the person");
|
|
18
|
+
* - kubernetes: GET discovery (`/api`, `/apis`, `/api/v1`, `/apis/<g>/<v>`)
|
|
19
|
+
* and GET collection lists, never `watch`.
|
|
20
|
+
*
|
|
21
|
+
* packages/core/src/cloud-lister/guard.test.ts holds the allowlist to exactly this set and
|
|
22
|
+
* shows a mutating call of each substrate refused.
|
|
23
|
+
*/
|
|
24
|
+
import type { Substrate } from "./types.js";
|
|
25
|
+
export type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS";
|
|
26
|
+
/** One HTTP request as it would be sent. */
|
|
27
|
+
export interface WireCall {
|
|
28
|
+
substrate: Substrate;
|
|
29
|
+
method: HttpMethod;
|
|
30
|
+
url: string;
|
|
31
|
+
headers: Record<string, string>;
|
|
32
|
+
body?: string;
|
|
33
|
+
}
|
|
34
|
+
/** The only operations the lister may send, by substrate. */
|
|
35
|
+
export declare const READ_OPERATIONS: Readonly<Record<Substrate, readonly string[]>>;
|
|
36
|
+
export declare class MutatingCallRefused extends Error {
|
|
37
|
+
readonly call: Pick<WireCall, "substrate" | "method" | "url">;
|
|
38
|
+
readonly operation: string;
|
|
39
|
+
constructor(call: Pick<WireCall, "substrate" | "method" | "url">, operation: string);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The operation a call performs, read off the wire. Anything this cannot
|
|
43
|
+
* name precisely comes back as `<substrate>:unknown:<detail>`, which no
|
|
44
|
+
* allowlist entry matches.
|
|
45
|
+
*/
|
|
46
|
+
export declare function classifyCall(call: WireCall): string;
|
|
47
|
+
/** Throws {@link MutatingCallRefused} unless the call is one of {@link READ_OPERATIONS}. */
|
|
48
|
+
export declare function assertReadCall(call: WireCall): string;
|
|
49
|
+
//# sourceMappingURL=guard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/cloud-lister/guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1F,4CAA4C;AAC5C,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,SAAS,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,6DAA6D;AAC7D,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC,CAK1E,CAAC;AAEF,qBAAa,mBAAoB,SAAQ,KAAK;IAE1C,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAC;IAC7D,QAAQ,CAAC,SAAS,EAAE,MAAM;IAF5B,YACW,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,WAAW,GAAG,QAAQ,GAAG,KAAK,CAAC,EACpD,SAAS,EAAE,MAAM,EAI3B;CACF;AAQD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAqCnD;AAED,4FAA4F;AAC5F,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAIrD"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: read-only by construction.
|
|
3
|
+
*
|
|
4
|
+
* Every request the lister makes is a {@link WireCall}, and every WireCall
|
|
5
|
+
* goes through {@link assertReadCall} before anything reaches the network
|
|
6
|
+
* (packages/core/src/cloud-lister/transport.ts is the only sender). The check classifies the
|
|
7
|
+
* call from what would go on the wire (method, path, `X-Amz-Target`), never
|
|
8
|
+
* from a label the caller attaches, and admits only the operations in
|
|
9
|
+
* {@link READ_OPERATIONS}:
|
|
10
|
+
*
|
|
11
|
+
* - aws: Cloud Control `ListResources` (a POST, but the JSON protocol's only
|
|
12
|
+
* verb; the target header names the operation);
|
|
13
|
+
* - azure: Resource Graph's query, `POST /providers/Microsoft.ResourceGraph/resources`
|
|
14
|
+
* (a read that takes its KQL in the body);
|
|
15
|
+
* - gcp: Cloud Asset `searchAllResources`, a GET. Nothing under
|
|
16
|
+
* `serviceusage` is admitted, so the lister cannot enable the Cloud Asset
|
|
17
|
+
* API on a project (#1029: "nothing is enabled for the person");
|
|
18
|
+
* - kubernetes: GET discovery (`/api`, `/apis`, `/api/v1`, `/apis/<g>/<v>`)
|
|
19
|
+
* and GET collection lists, never `watch`.
|
|
20
|
+
*
|
|
21
|
+
* packages/core/src/cloud-lister/guard.test.ts holds the allowlist to exactly this set and
|
|
22
|
+
* shows a mutating call of each substrate refused.
|
|
23
|
+
*/
|
|
24
|
+
/** The only operations the lister may send, by substrate. */
|
|
25
|
+
export const READ_OPERATIONS = {
|
|
26
|
+
aws: ["cloudcontrol:ListResources"],
|
|
27
|
+
azure: ["resourcegraph:resources"],
|
|
28
|
+
gcp: ["cloudasset:searchAllResources"],
|
|
29
|
+
kubernetes: ["k8s:discovery", "k8s:list"],
|
|
30
|
+
};
|
|
31
|
+
export class MutatingCallRefused extends Error {
|
|
32
|
+
constructor(call, operation) {
|
|
33
|
+
super(`chant's cloud lister refused ${call.method} ${call.url} (${operation}): only ${READ_OPERATIONS[call.substrate].join(", ")} may be sent`);
|
|
34
|
+
this.call = call;
|
|
35
|
+
this.operation = operation;
|
|
36
|
+
this.name = "MutatingCallRefused";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function header(headers, name) {
|
|
40
|
+
const lower = name.toLowerCase();
|
|
41
|
+
for (const [k, v] of Object.entries(headers))
|
|
42
|
+
if (k.toLowerCase() === lower)
|
|
43
|
+
return v;
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The operation a call performs, read off the wire. Anything this cannot
|
|
48
|
+
* name precisely comes back as `<substrate>:unknown:<detail>`, which no
|
|
49
|
+
* allowlist entry matches.
|
|
50
|
+
*/
|
|
51
|
+
export function classifyCall(call) {
|
|
52
|
+
const url = new URL(call.url);
|
|
53
|
+
const path = url.pathname;
|
|
54
|
+
switch (call.substrate) {
|
|
55
|
+
case "aws": {
|
|
56
|
+
const target = header(call.headers, "x-amz-target") ?? "";
|
|
57
|
+
const m = /^CloudApiService\.([A-Za-z]+)$/.exec(target);
|
|
58
|
+
if (call.method === "POST" && m)
|
|
59
|
+
return `cloudcontrol:${m[1]}`;
|
|
60
|
+
return `aws:unknown:${call.method} ${target || path}`;
|
|
61
|
+
}
|
|
62
|
+
case "azure": {
|
|
63
|
+
if (call.method === "POST" && /\/providers\/microsoft\.resourcegraph\/resources$/i.test(path)) {
|
|
64
|
+
return "resourcegraph:resources";
|
|
65
|
+
}
|
|
66
|
+
return `azure:unknown:${call.method} ${path}`;
|
|
67
|
+
}
|
|
68
|
+
case "gcp": {
|
|
69
|
+
const m = /\/v1\/(projects|folders|organizations)\/[^/:]+:([A-Za-z]+)$/.exec(path);
|
|
70
|
+
if (call.method === "GET" && m && m[2] === "searchAllResources" && !/serviceusage/i.test(url.hostname + path)) {
|
|
71
|
+
return "cloudasset:searchAllResources";
|
|
72
|
+
}
|
|
73
|
+
return `gcp:unknown:${call.method} ${path}`;
|
|
74
|
+
}
|
|
75
|
+
case "kubernetes": {
|
|
76
|
+
if (call.method !== "GET")
|
|
77
|
+
return `k8s:unknown:${call.method} ${path}`;
|
|
78
|
+
const watch = url.searchParams.get("watch");
|
|
79
|
+
if (watch !== null && watch !== "false" && watch !== "0")
|
|
80
|
+
return `k8s:watch:${path}`;
|
|
81
|
+
if (/^\/(api|apis)\/?$/.test(path))
|
|
82
|
+
return "k8s:discovery";
|
|
83
|
+
if (/^\/api\/v1\/?$/.test(path))
|
|
84
|
+
return "k8s:discovery";
|
|
85
|
+
if (/^\/apis\/[^/]+\/[^/]+\/?$/.test(path))
|
|
86
|
+
return "k8s:discovery";
|
|
87
|
+
// A collection: /api/v1/<plural> or /apis/<g>/<v>/<plural>. A named
|
|
88
|
+
// object, a subresource (logs, exec, proxy) or a namespaced path is not.
|
|
89
|
+
if (/^\/api\/v1\/[a-z0-9.-]+$/.test(path))
|
|
90
|
+
return "k8s:list";
|
|
91
|
+
if (/^\/apis\/[^/]+\/[^/]+\/[a-z0-9.-]+$/.test(path))
|
|
92
|
+
return "k8s:list";
|
|
93
|
+
return `k8s:unknown:${call.method} ${path}`;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/** Throws {@link MutatingCallRefused} unless the call is one of {@link READ_OPERATIONS}. */
|
|
98
|
+
export function assertReadCall(call) {
|
|
99
|
+
const operation = classifyCall(call);
|
|
100
|
+
if (!READ_OPERATIONS[call.substrate].includes(operation))
|
|
101
|
+
throw new MutatingCallRefused(call, operation);
|
|
102
|
+
return operation;
|
|
103
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: a listed node's id, ruled on behold#1025 (Q2):
|
|
3
|
+
* `<substrate>/<scopeId>/<location>/<listedType>/<nativeId>`.
|
|
4
|
+
*
|
|
5
|
+
* Several of those parts carry `/` of their own: a Kubernetes type
|
|
6
|
+
* (`apps/v1/Deployment`), an ARM type (`microsoft.storage/storageaccounts`),
|
|
7
|
+
* and most native ids (an ARM id, `namespace/name`). The id stays readable and
|
|
8
|
+
* parses back by escaping `%` and `/` in the first four parts only. The native
|
|
9
|
+
* id is last, so everything after the fourth separator is it, unescaped: the
|
|
10
|
+
* exact string the aws matcher (chant#4523) compares with `declaredIdentifier`.
|
|
11
|
+
*/
|
|
12
|
+
import type { Substrate } from "./types.js";
|
|
13
|
+
export interface ListedNodeIdParts {
|
|
14
|
+
substrate: Substrate;
|
|
15
|
+
scopeId: string;
|
|
16
|
+
location: string;
|
|
17
|
+
listedType: string;
|
|
18
|
+
nativeId: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function listedNodeId(parts: ListedNodeIdParts): string;
|
|
21
|
+
/** The parts back from an id {@link listedNodeId} wrote; `undefined` for anything else. */
|
|
22
|
+
export declare function parseListedNodeId(id: string): ListedNodeIdParts | undefined;
|
|
23
|
+
//# sourceMappingURL=ids.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ids.d.ts","sourceRoot":"","sources":["../../src/cloud-lister/ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAUzC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAQ7D;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS,CAY3E"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: a listed node's id, ruled on behold#1025 (Q2):
|
|
3
|
+
* `<substrate>/<scopeId>/<location>/<listedType>/<nativeId>`.
|
|
4
|
+
*
|
|
5
|
+
* Several of those parts carry `/` of their own: a Kubernetes type
|
|
6
|
+
* (`apps/v1/Deployment`), an ARM type (`microsoft.storage/storageaccounts`),
|
|
7
|
+
* and most native ids (an ARM id, `namespace/name`). The id stays readable and
|
|
8
|
+
* parses back by escaping `%` and `/` in the first four parts only. The native
|
|
9
|
+
* id is last, so everything after the fourth separator is it, unescaped: the
|
|
10
|
+
* exact string the aws matcher (chant#4523) compares with `declaredIdentifier`.
|
|
11
|
+
*/
|
|
12
|
+
function escapeSegment(s) {
|
|
13
|
+
return s.replace(/%/g, "%25").replace(/\//g, "%2F");
|
|
14
|
+
}
|
|
15
|
+
function unescapeSegment(s) {
|
|
16
|
+
return s.replace(/%2F/gi, "/").replace(/%25/g, "%");
|
|
17
|
+
}
|
|
18
|
+
export function listedNodeId(parts) {
|
|
19
|
+
return [
|
|
20
|
+
escapeSegment(parts.substrate),
|
|
21
|
+
escapeSegment(parts.scopeId),
|
|
22
|
+
escapeSegment(parts.location),
|
|
23
|
+
escapeSegment(parts.listedType),
|
|
24
|
+
parts.nativeId,
|
|
25
|
+
].join("/");
|
|
26
|
+
}
|
|
27
|
+
/** The parts back from an id {@link listedNodeId} wrote; `undefined` for anything else. */
|
|
28
|
+
export function parseListedNodeId(id) {
|
|
29
|
+
const parts = [];
|
|
30
|
+
let rest = id;
|
|
31
|
+
for (let i = 0; i < 4; i++) {
|
|
32
|
+
const at = rest.indexOf("/");
|
|
33
|
+
if (at < 0)
|
|
34
|
+
return undefined;
|
|
35
|
+
parts.push(unescapeSegment(rest.slice(0, at)));
|
|
36
|
+
rest = rest.slice(at + 1);
|
|
37
|
+
}
|
|
38
|
+
const [substrate, scopeId, location, listedType] = parts;
|
|
39
|
+
if (substrate !== "aws" && substrate !== "azure" && substrate !== "gcp" && substrate !== "kubernetes")
|
|
40
|
+
return undefined;
|
|
41
|
+
return { substrate, scopeId, location, listedType, nativeId: rest };
|
|
42
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only cloud lister `chant index` runs (chant#4532; built as
|
|
3
|
+
* behold#1029 and moved here on the ruling that every model lives in chant,
|
|
4
|
+
* https://github.com/INTENTIUS/behold/issues/1024#issuecomment-6433236820).
|
|
5
|
+
*
|
|
6
|
+
* One call lists one substrate and one account, subscription, project or
|
|
7
|
+
* cluster (behold#1025 ruling Q6) and returns a {@link ListingResult}: the
|
|
8
|
+
* design's listing-result source shape, which chant's `typeListing`
|
|
9
|
+
* (chant#4521) types into an `IndexDocument`. It has no command of its own
|
|
10
|
+
* (`chant index` and `behold index` both reach it through
|
|
11
|
+
* ../lifecycle/cloud-index.ts), reads no project or configuration, and works
|
|
12
|
+
* in an empty directory.
|
|
13
|
+
*
|
|
14
|
+
* Read-only by construction: no cloud SDK client is built. Every request is
|
|
15
|
+
* a plain HTTP call through one {@link Transport}, which refuses anything
|
|
16
|
+
* outside the read allowlist (packages/core/src/cloud-lister/guard.ts) and, when the run
|
|
17
|
+
* names an endpoint, anything not sent to that endpoint's origin. There is
|
|
18
|
+
* no estate, no record store and no write call.
|
|
19
|
+
*/
|
|
20
|
+
import { type AwsTarget } from "./aws.js";
|
|
21
|
+
import { type AzureTarget } from "./azure.js";
|
|
22
|
+
import { type GcpTarget } from "./gcp.js";
|
|
23
|
+
import { type KubernetesTarget } from "./kubernetes.js";
|
|
24
|
+
import { type CredentialChains } from "./credentials.js";
|
|
25
|
+
import { type Fetcher, type TransportOptions } from "./transport.js";
|
|
26
|
+
import type { CloudScope, ListingResult } from "./types.js";
|
|
27
|
+
export type { CloudScope, ListingResult, ListedResource, CoverageEntry, IndexNote, CloudId, ListedFacts, MarkerFact, Substrate, TagFilter } from "./types.js";
|
|
28
|
+
export type { AwsTarget } from "./aws.js";
|
|
29
|
+
export type { AzureTarget } from "./azure.js";
|
|
30
|
+
export type { GcpTarget } from "./gcp.js";
|
|
31
|
+
export type { KubernetesTarget } from "./kubernetes.js";
|
|
32
|
+
export { kubeTargetFromKubeconfig } from "./kubernetes.js";
|
|
33
|
+
export { ListerConfigError } from "./credentials.js";
|
|
34
|
+
export { MutatingCallRefused, READ_OPERATIONS } from "./guard.js";
|
|
35
|
+
export { OriginRefused } from "./transport.js";
|
|
36
|
+
export { listedNodeId, parseListedNodeId } from "./ids.js";
|
|
37
|
+
/** Where and how to reach the scope's substrate. The variant must match `scope.substrate`. */
|
|
38
|
+
export type SubstrateTarget = {
|
|
39
|
+
substrate: "aws";
|
|
40
|
+
aws: AwsTarget;
|
|
41
|
+
} | {
|
|
42
|
+
substrate: "azure";
|
|
43
|
+
azure: AzureTarget;
|
|
44
|
+
} | {
|
|
45
|
+
substrate: "gcp";
|
|
46
|
+
gcp: GcpTarget;
|
|
47
|
+
} | {
|
|
48
|
+
substrate: "kubernetes";
|
|
49
|
+
kubernetes: KubernetesTarget;
|
|
50
|
+
};
|
|
51
|
+
export interface ListOptions {
|
|
52
|
+
/** Replaces the network (tests). */
|
|
53
|
+
fetcher?: Fetcher;
|
|
54
|
+
/** Replaces the real-cloud SDK credential chains (tests prove none is touched with an endpoint). */
|
|
55
|
+
chains?: CredentialChains;
|
|
56
|
+
now?: () => Date;
|
|
57
|
+
/** Throttle backoff, in ms; tests pass `[]`. */
|
|
58
|
+
retryDelays?: readonly number[];
|
|
59
|
+
/** The caller's version (chant's, or behold's when behold calls in), for `source.version`. */
|
|
60
|
+
version?: string;
|
|
61
|
+
/** Sees every call that passed the guard (tests record with it). */
|
|
62
|
+
onSend?: TransportOptions["onSend"];
|
|
63
|
+
}
|
|
64
|
+
/** The scope as the stamp records it: lists sorted and deduplicated (#1025 "Stamp"). */
|
|
65
|
+
export declare function canonicalScope(scope: CloudScope): CloudScope;
|
|
66
|
+
export declare function listCloud(scope: CloudScope, target: SubstrateTarget, options?: ListOptions): Promise<ListingResult>;
|
|
67
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cloud-lister/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAa,KAAK,WAAW,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrE,OAAO,EAAuB,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,EAAa,KAAK,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC9F,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAEzD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC3J,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,YAAY,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3C,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,YAAY,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAExD,8FAA8F;AAC9F,MAAM,MAAM,eAAe,GACvB;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACpC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GAC1C;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,GAAG,EAAE,SAAS,CAAA;CAAE,GACpC;IAAE,SAAS,EAAE,YAAY,CAAC;IAAC,UAAU,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oGAAoG;IACpG,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;IACjB,gDAAgD;IAChD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC,8FAA8F;IAC9F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;CACrC;AAOD,wFAAwF;AACxF,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,UAAU,CAU5D;AAeD,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAyC7H"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-only cloud lister `chant index` runs (chant#4532; built as
|
|
3
|
+
* behold#1029 and moved here on the ruling that every model lives in chant,
|
|
4
|
+
* https://github.com/INTENTIUS/behold/issues/1024#issuecomment-6433236820).
|
|
5
|
+
*
|
|
6
|
+
* One call lists one substrate and one account, subscription, project or
|
|
7
|
+
* cluster (behold#1025 ruling Q6) and returns a {@link ListingResult}: the
|
|
8
|
+
* design's listing-result source shape, which chant's `typeListing`
|
|
9
|
+
* (chant#4521) types into an `IndexDocument`. It has no command of its own
|
|
10
|
+
* (`chant index` and `behold index` both reach it through
|
|
11
|
+
* ../lifecycle/cloud-index.ts), reads no project or configuration, and works
|
|
12
|
+
* in an empty directory.
|
|
13
|
+
*
|
|
14
|
+
* Read-only by construction: no cloud SDK client is built. Every request is
|
|
15
|
+
* a plain HTTP call through one {@link Transport}, which refuses anything
|
|
16
|
+
* outside the read allowlist (packages/core/src/cloud-lister/guard.ts) and, when the run
|
|
17
|
+
* names an endpoint, anything not sent to that endpoint's origin. There is
|
|
18
|
+
* no estate, no record store and no write call.
|
|
19
|
+
*/
|
|
20
|
+
import { sortResult } from "./common.js";
|
|
21
|
+
import { listAws } from "./aws.js";
|
|
22
|
+
import { listAzure } from "./azure.js";
|
|
23
|
+
import { listGcp } from "./gcp.js";
|
|
24
|
+
import { listKubernetes } from "./kubernetes.js";
|
|
25
|
+
import { sdkCredentialChains } from "./credentials.js";
|
|
26
|
+
import { Transport } from "./transport.js";
|
|
27
|
+
export { kubeTargetFromKubeconfig } from "./kubernetes.js";
|
|
28
|
+
export { ListerConfigError } from "./credentials.js";
|
|
29
|
+
export { MutatingCallRefused, READ_OPERATIONS } from "./guard.js";
|
|
30
|
+
export { OriginRefused } from "./transport.js";
|
|
31
|
+
export { listedNodeId, parseListedNodeId } from "./ids.js";
|
|
32
|
+
function sortedUnique(values) {
|
|
33
|
+
if (values === "*")
|
|
34
|
+
return "*";
|
|
35
|
+
return [...new Set(values)].sort();
|
|
36
|
+
}
|
|
37
|
+
/** The scope as the stamp records it: lists sorted and deduplicated (#1025 "Stamp"). */
|
|
38
|
+
export function canonicalScope(scope) {
|
|
39
|
+
return {
|
|
40
|
+
substrate: scope.substrate,
|
|
41
|
+
scopeId: scope.scopeId,
|
|
42
|
+
locations: sortedUnique(scope.locations),
|
|
43
|
+
types: sortedUnique(scope.types),
|
|
44
|
+
...(scope.tagFilter && Object.keys(scope.tagFilter).length > 0
|
|
45
|
+
? { tagFilter: Object.fromEntries(Object.entries(scope.tagFilter).sort(([a], [b]) => (a < b ? -1 : 1))) }
|
|
46
|
+
: {}),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function endpointAndTls(target) {
|
|
50
|
+
switch (target.substrate) {
|
|
51
|
+
case "aws":
|
|
52
|
+
return { endpoint: target.aws.endpoint, tls: target.aws.tls };
|
|
53
|
+
case "azure":
|
|
54
|
+
return { endpoint: target.azure.endpoint, tls: target.azure.tls };
|
|
55
|
+
case "gcp":
|
|
56
|
+
return { endpoint: target.gcp.endpoint, tls: target.gcp.tls };
|
|
57
|
+
case "kubernetes":
|
|
58
|
+
return { endpoint: target.kubernetes.server, tls: target.kubernetes.tls };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export async function listCloud(scope, target, options = {}) {
|
|
62
|
+
if (scope.substrate !== target.substrate) {
|
|
63
|
+
throw new Error(`scope is ${scope.substrate} but the target is ${target.substrate}`);
|
|
64
|
+
}
|
|
65
|
+
const canonical = canonicalScope(scope);
|
|
66
|
+
const now = options.now ?? (() => new Date());
|
|
67
|
+
const { endpoint, tls } = endpointAndTls(target);
|
|
68
|
+
const transport = new Transport({
|
|
69
|
+
fetcher: options.fetcher,
|
|
70
|
+
tls,
|
|
71
|
+
...(endpoint !== undefined ? { pinnedOrigin: endpoint } : {}),
|
|
72
|
+
...(options.onSend ? { onSend: options.onSend } : {}),
|
|
73
|
+
});
|
|
74
|
+
const chains = options.chains ?? sdkCredentialChains;
|
|
75
|
+
const ctx = { scope: canonical, transport, now, resources: [], coverage: [], notes: [] };
|
|
76
|
+
const startedAt = now().toISOString();
|
|
77
|
+
switch (target.substrate) {
|
|
78
|
+
case "aws":
|
|
79
|
+
await listAws(ctx, target.aws, chains, options.retryDelays);
|
|
80
|
+
break;
|
|
81
|
+
case "azure":
|
|
82
|
+
await listAzure(ctx, target.azure, chains, options.retryDelays);
|
|
83
|
+
break;
|
|
84
|
+
case "gcp":
|
|
85
|
+
await listGcp(ctx, target.gcp, chains, options.retryDelays);
|
|
86
|
+
break;
|
|
87
|
+
case "kubernetes":
|
|
88
|
+
await listKubernetes(ctx, target.kubernetes, options.retryDelays);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
sortResult(ctx);
|
|
92
|
+
return {
|
|
93
|
+
listing: "v1",
|
|
94
|
+
source: { name: "chant-lister", version: options.version ?? "unknown" },
|
|
95
|
+
scope: canonical,
|
|
96
|
+
startedAt,
|
|
97
|
+
completedAt: now().toISOString(),
|
|
98
|
+
resources: ctx.resources,
|
|
99
|
+
coverage: ctx.coverage,
|
|
100
|
+
notes: ctx.notes,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* behold#1029: Kubernetes, through API discovery and then one LIST per
|
|
3
|
+
* served kind, paged with `continue`.
|
|
4
|
+
*
|
|
5
|
+
* The lister does not go through `@intentius/chant-k8s-client`. That client
|
|
6
|
+
* builds a full read and write client, and its only network seam
|
|
7
|
+
* (`requestLayer`) replaces the whole HTTP send, so the read-only guard could
|
|
8
|
+
* not sit in front of its real transport. Discovery and LIST are plain GETs,
|
|
9
|
+
* so they go through the lister's own guarded transport like every other
|
|
10
|
+
* substrate, with the cluster's server, token and certificates passed
|
|
11
|
+
* explicitly. {@link kubeTargetFromKubeconfig} reads those from a kubeconfig
|
|
12
|
+
* the caller names, and refuses an exec plugin or an auth provider: those
|
|
13
|
+
* are credential chains, and the lister takes static credentials only.
|
|
14
|
+
*
|
|
15
|
+
* Locations are namespaces. A cluster-scoped object's location is `cluster`;
|
|
16
|
+
* it is listed when the scope's locations are `*` or include `cluster`. With
|
|
17
|
+
* types `*`, events and leases are left out (they change on every read, so
|
|
18
|
+
* every version's digest would differ) and a note says so.
|
|
19
|
+
*
|
|
20
|
+
* kind (the pinned `kindest/node` in choudoufu's live/kind-node-image) runs a
|
|
21
|
+
* real API server, so discovery and LIST are served as on any cluster.
|
|
22
|
+
*/
|
|
23
|
+
import { type ListerContext } from "./common.js";
|
|
24
|
+
import { type TlsOptions } from "./transport.js";
|
|
25
|
+
export interface KubernetesTarget {
|
|
26
|
+
/** The API server, e.g. `https://127.0.0.1:6443`. */
|
|
27
|
+
server: string;
|
|
28
|
+
/** A bearer token; absent when the client certificate in `tls` authenticates. */
|
|
29
|
+
token?: string;
|
|
30
|
+
tls?: TlsOptions;
|
|
31
|
+
}
|
|
32
|
+
/** A served, listable kind from discovery. */
|
|
33
|
+
export interface ServedKind {
|
|
34
|
+
group: string;
|
|
35
|
+
version: string;
|
|
36
|
+
kind: string;
|
|
37
|
+
plural: string;
|
|
38
|
+
namespaced: boolean;
|
|
39
|
+
/** `v1/Pod`, `apps/v1/Deployment`: the lister's `listedType`. */
|
|
40
|
+
listedType: string;
|
|
41
|
+
}
|
|
42
|
+
export declare function listedTypeOf(group: string, version: string, kind: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* Every listable kind the cluster serves: the core group's `v1`, and for each
|
|
45
|
+
* other group its preferred version plus any version a requested type names.
|
|
46
|
+
*/
|
|
47
|
+
export declare function discover(ctx: ListerContext, target: KubernetesTarget, requested: ReadonlySet<string> | undefined, retryDelays?: readonly number[]): Promise<ServedKind[]>;
|
|
48
|
+
/** `labelSelector` for a tag filter, or undefined. Exported for tests. */
|
|
49
|
+
export declare function labelSelector(filter: Readonly<Record<string, string>> | undefined): string | undefined;
|
|
50
|
+
export declare function listKubernetes(ctx: ListerContext, target: KubernetesTarget, retryDelays?: readonly number[]): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* A {@link KubernetesTarget} from a kubeconfig the caller names (its text,
|
|
53
|
+
* and the directory relative file paths resolve against). Static credentials
|
|
54
|
+
* only: a token, a token file, or a client certificate and key. An exec
|
|
55
|
+
* plugin or an auth provider is refused.
|
|
56
|
+
*/
|
|
57
|
+
export declare function kubeTargetFromKubeconfig(text: string, opts?: {
|
|
58
|
+
context?: string;
|
|
59
|
+
baseDir?: string;
|
|
60
|
+
}): KubernetesTarget & {
|
|
61
|
+
contextName: string;
|
|
62
|
+
clusterName: string;
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=kubernetes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kubernetes.d.ts","sourceRoot":"","sources":["../../src/cloud-lister/kubernetes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAmF,KAAK,aAAa,EAAE,MAAM,UAAU,CAAC;AAG/H,OAAO,EAAY,KAAK,UAAU,EAAqB,MAAM,aAAa,CAAC;AAE3E,MAAM,WAAW,gBAAgB;IAC/B,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,UAAU,CAAC;CAClB;AAED,8CAA8C;AAC9C,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,OAAO,CAAC;IACpB,iEAAiE;IACjE,UAAU,EAAE,MAAM,CAAC;CACpB;AASD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEjF;AAkCD;;;GAGG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,aAAa,EAClB,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,EAC1C,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAC9B,OAAO,CAAC,UAAU,EAAE,CAAC,CAiCvB;AAED,0EAA0E;AAC1E,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAStG;AAED,wBAAsB,cAAc,CAAC,GAAG,EAAE,aAAa,EAAE,MAAM,EAAE,gBAAgB,EAAE,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA0FjI;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,gBAAgB,GAAG;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAqCzK"}
|