@intentius/chant 0.57.0 → 0.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts +13 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +73 -37
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +10 -22
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +273 -16
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +79 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +149 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +29 -9
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +185 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +93 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +96 -29
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +194 -1
- package/src/cli/commands/lint.ts +205 -7
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +82 -2
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +3 -3
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +296 -16
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +154 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/pipeline-change-gate.test.ts +2 -2
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +161 -0
- package/src/op/activities/reconcile.ts +354 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +110 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +106 -26
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
package/src/audit/discover.ts
CHANGED
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
* `detectTemplate` (which only knows Compose's `services:`) can't see them.
|
|
22
22
|
* - Helm charts are a directory BUNDLE keyed by `Chart.yaml`; the helm checks
|
|
23
23
|
* read `output.files`, so the whole chart is one AuditInput.
|
|
24
|
+
* - Terraform is also a directory BUNDLE, keyed by that directory's own
|
|
25
|
+
* `.tf` filenames, not recursively: a nested directory with its own
|
|
26
|
+
* `.tf` files (e.g. `modules/foo`) is its own AuditInput, UNLESS another
|
|
27
|
+
* directory's `.tf` calls it as a local module, in which case it is a
|
|
28
|
+
* child module of that root and is parsed as part of it (#2217). `.tf`
|
|
29
|
+
* isn't YAML/JSON either, so `detectTemplate` can't see it.
|
|
24
30
|
* - k8s `detectTemplate` matches any `apiVersion`+`kind`, including GCP Config
|
|
25
31
|
* Connector (`cnrm.cloud.google.com`) resources and fountain
|
|
26
32
|
* (`fountain.dev/v1`) manifests, so gcp and fountain must be tried first.
|
|
@@ -29,14 +35,15 @@
|
|
|
29
35
|
*/
|
|
30
36
|
|
|
31
37
|
import { readdirSync, readFileSync, statSync } from "fs";
|
|
32
|
-
import { basename, join, relative } from "path";
|
|
38
|
+
import { basename, join, relative, resolve } from "path";
|
|
33
39
|
import { parseYAML } from "../yaml";
|
|
34
40
|
import type { LexiconPlugin } from "../lexicon";
|
|
35
41
|
import type { AuditInput, AuditLexicon } from "./core";
|
|
36
42
|
import { isNginxConfigPath } from "./nginx";
|
|
43
|
+
import { gitignoreCoversTerraformState, isTerraformStatePath } from "./terraform-state";
|
|
37
44
|
|
|
38
45
|
/** Lexicons the auditor knows how to detect and run checks for. */
|
|
39
|
-
export const AUDIT_LEXICONS = ["github", "gitlab", "forgejo", "k8s", "docker", "aws", "azure", "gcp", "helm", "fountain"] as const;
|
|
46
|
+
export const AUDIT_LEXICONS = ["github", "gitlab", "forgejo", "k8s", "docker", "aws", "azure", "gcp", "helm", "fountain", "terraform"] as const;
|
|
40
47
|
|
|
41
48
|
/**
|
|
42
49
|
* Load the plugins used for detection. Each is loaded in isolation (no
|
|
@@ -63,6 +70,8 @@ export async function loadAuditPlugins(names: readonly string[] = AUDIT_LEXICONS
|
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
const WALK_SKIP = new Set(["node_modules", ".git", "dist"]);
|
|
73
|
+
/** Terraform's local working directory: recorded by the walk, never entered (TF023). */
|
|
74
|
+
const TERRAFORM_WORK_DIR = ".terraform";
|
|
66
75
|
/** Dot-directories the walk descends into anyway (CI lives here). */
|
|
67
76
|
const WALK_DOT_DIRS = new Set([".github", ".forgejo"]);
|
|
68
77
|
const MAX_WALK_FILES = 1000;
|
|
@@ -80,7 +89,15 @@ function walkFiles(dir: string, out: string[]): void {
|
|
|
80
89
|
}
|
|
81
90
|
for (const e of entries.sort((a, b) => (a.name < b.name ? -1 : 1))) {
|
|
82
91
|
if (out.length >= MAX_WALK_FILES) return;
|
|
83
|
-
if (e.name.startsWith(".") && e.isDirectory() && !WALK_DOT_DIRS.has(e.name))
|
|
92
|
+
if (e.name.startsWith(".") && e.isDirectory() && !WALK_DOT_DIRS.has(e.name)) {
|
|
93
|
+
// `.terraform/` is never descended into: it is machine-generated,
|
|
94
|
+
// routinely hundreds of megabytes of provider binaries, and nothing in
|
|
95
|
+
// it is worth reading. Its presence is itself the finding (TF023), so
|
|
96
|
+
// the directory path alone is recorded and `collectCandidates` hands it
|
|
97
|
+
// on with no content.
|
|
98
|
+
if (e.name === TERRAFORM_WORK_DIR) out.push(join(dir, e.name));
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
84
101
|
if (WALK_SKIP.has(e.name)) continue;
|
|
85
102
|
const full = join(dir, e.name);
|
|
86
103
|
if (e.isDirectory()) walkFiles(full, out);
|
|
@@ -105,6 +122,10 @@ function isDockerfileName(name: string): boolean {
|
|
|
105
122
|
return name === "Dockerfile" || name.startsWith("Dockerfile.") || name.endsWith(".Dockerfile") || name.endsWith(".dockerfile");
|
|
106
123
|
}
|
|
107
124
|
|
|
125
|
+
function isTerraformFileName(name: string): boolean {
|
|
126
|
+
return /\.tf$/i.test(name);
|
|
127
|
+
}
|
|
128
|
+
|
|
108
129
|
/**
|
|
109
130
|
* Filenames the secrets scan (#443) wants that no lexicon otherwise reads —
|
|
110
131
|
* dotenv files and key/cert material. Included in `isCandidatePath` so both
|
|
@@ -294,11 +315,11 @@ export function isCandidatePath(path: string): boolean {
|
|
|
294
315
|
* (path, filename, a few content markers) with no lexicon plugin involved.
|
|
295
316
|
* Names the lexicon that would have claimed a file when that lexicon isn't
|
|
296
317
|
* installed (#1623). Deliberately coarse: precision comes from the plugin's
|
|
297
|
-
* `detectTemplate`, which is exactly what's missing in that case.
|
|
298
|
-
*
|
|
299
|
-
*
|
|
318
|
+
* `detectTemplate`, which is exactly what's missing in that case. `terraform`
|
|
319
|
+
* is a lexicon like any other here: a `.tf` file hints at it by name, the
|
|
320
|
+
* same way `Chart.yaml` hints at helm.
|
|
300
321
|
*/
|
|
301
|
-
export type LexiconHint = AuditLexicon
|
|
322
|
+
export type LexiconHint = AuditLexicon;
|
|
302
323
|
|
|
303
324
|
export function hintLexiconForFile(path: string, content: string): LexiconHint | undefined {
|
|
304
325
|
const name = basename(path);
|
|
@@ -306,7 +327,7 @@ export function hintLexiconForFile(path: string, content: string): LexiconHint |
|
|
|
306
327
|
if (ci) return ci;
|
|
307
328
|
if (isDockerfileName(name)) return "docker";
|
|
308
329
|
if (name === "Chart.yaml") return "helm";
|
|
309
|
-
if (
|
|
330
|
+
if (isTerraformFileName(name)) return "terraform";
|
|
310
331
|
const head = content.slice(0, 64 * 1024);
|
|
311
332
|
if (/cnrm\.cloud\.google\.com/.test(head)) return "gcp";
|
|
312
333
|
if (/fountain\.dev\/v1/.test(head)) return "fountain";
|
|
@@ -371,25 +392,175 @@ function classifyHelm(files: RepoFile[], plugin: DetectPlugin | undefined): { in
|
|
|
371
392
|
return { inputs, prefixes };
|
|
372
393
|
}
|
|
373
394
|
|
|
395
|
+
/**
|
|
396
|
+
* A `source` attribute naming a local path, the only module source Terraform
|
|
397
|
+
* reads from the repository itself. A registry or git source ("hashicorp/aws",
|
|
398
|
+
* "git::https://...") never starts with `./` or `../`, and `source` inside
|
|
399
|
+
* `required_providers` is a registry address, so the prefix is what tells the
|
|
400
|
+
* two apart without an HCL parser here. `classifyTerraform` uses this to tell
|
|
401
|
+
* a root module from a directory that is somebody's child module; the lexicon
|
|
402
|
+
* plugin parses the calls properly once it has the root.
|
|
403
|
+
*/
|
|
404
|
+
const LOCAL_MODULE_SOURCE = /(?:^|[\s{,])source\s*=\s*"(\.{1,2}\/[^"]*)"/g;
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Resolve `rel` against the repo-relative directory `dir`. Returns undefined
|
|
408
|
+
* when the path climbs above the audited root, which is a directory this walk
|
|
409
|
+
* never read and so can never be one of its inputs.
|
|
410
|
+
*/
|
|
411
|
+
function resolveRepoDir(dir: string, rel: string): string | undefined {
|
|
412
|
+
const parts = dir === "" ? [] : dir.split("/");
|
|
413
|
+
for (const segment of rel.split("/")) {
|
|
414
|
+
if (segment === "" || segment === ".") continue;
|
|
415
|
+
if (segment === "..") {
|
|
416
|
+
if (parts.length === 0) return undefined;
|
|
417
|
+
parts.pop();
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
parts.push(segment);
|
|
421
|
+
}
|
|
422
|
+
return parts.join("/");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* The directories that are somebody's local child module: a `.tf` file in
|
|
427
|
+
* another directory of this walk calls them with a relative `source`.
|
|
428
|
+
*
|
|
429
|
+
* They are dropped as audit inputs of their own, because the root that calls
|
|
430
|
+
* them parses them as child scopes (the terraform plugin's `auditEntities`
|
|
431
|
+
* descends from `AuditInput.dir`, #2217). Auditing them twice would report
|
|
432
|
+
* every finding in them twice, once per scope, and auditing them as roots is
|
|
433
|
+
* what made `chant audit` disagree with `chant build` about which rules apply
|
|
434
|
+
* to a child module at all.
|
|
435
|
+
*
|
|
436
|
+
* A directory a cycle reaches but no root does is kept: `a` calling `b`
|
|
437
|
+
* calling `a` is a configuration Terraform refuses, and dropping both would
|
|
438
|
+
* leave the files audited by nothing.
|
|
439
|
+
*/
|
|
440
|
+
function calledAsLocalModule(byDir: Map<string, Record<string, string>>): Set<string> {
|
|
441
|
+
const callees = new Map<string, Set<string>>();
|
|
442
|
+
const called = new Set<string>();
|
|
443
|
+
for (const [dir, bundle] of byDir) {
|
|
444
|
+
const targets = new Set<string>();
|
|
445
|
+
for (const source of Object.values(bundle)) {
|
|
446
|
+
for (const match of source.matchAll(LOCAL_MODULE_SOURCE)) {
|
|
447
|
+
const target = resolveRepoDir(dir, match[1]);
|
|
448
|
+
if (target === undefined || target === dir || !byDir.has(target)) continue;
|
|
449
|
+
targets.add(target);
|
|
450
|
+
called.add(target);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
callees.set(dir, targets);
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const queue = [...byDir.keys()].filter((dir) => !called.has(dir));
|
|
457
|
+
const reached = new Set<string>(queue);
|
|
458
|
+
while (queue.length > 0) {
|
|
459
|
+
for (const target of callees.get(queue.shift()!) ?? []) {
|
|
460
|
+
if (reached.has(target)) continue;
|
|
461
|
+
reached.add(target);
|
|
462
|
+
queue.push(target);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return new Set([...called].filter((dir) => reached.has(dir)));
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Collect Terraform root modules as directory bundles from an in-memory file
|
|
470
|
+
* set, modeled on `classifyHelm`. Unlike a Helm chart (its whole subtree is
|
|
471
|
+
* one bundle), a Terraform root module references only its own sibling
|
|
472
|
+
* files, so grouping is by each `.tf` file's immediate directory, not
|
|
473
|
+
* recursive.
|
|
474
|
+
*
|
|
475
|
+
* A directory another one calls as a local module is not a root module and
|
|
476
|
+
* gets no input of its own (#2217): the root that calls it parses it as a
|
|
477
|
+
* child scope, which is what Terraform does and what `chant build` already
|
|
478
|
+
* did. That descent reads the child's directory from disk, so it only happens
|
|
479
|
+
* when `baseDir` says a local walk found these files; an in-memory file set
|
|
480
|
+
* with no directory behind it keeps every `.tf` directory as its own input,
|
|
481
|
+
* as before.
|
|
482
|
+
*
|
|
483
|
+
* Returns inputs plus the exact `.tf` paths claimed, so the loose-file pass in
|
|
484
|
+
* `classifyFiles` can skip them — a child module's files are claimed too, by
|
|
485
|
+
* the root that will parse them.
|
|
486
|
+
*/
|
|
487
|
+
function classifyTerraform(
|
|
488
|
+
files: RepoFile[],
|
|
489
|
+
plugin: DetectPlugin | undefined,
|
|
490
|
+
baseDir?: string,
|
|
491
|
+
): { inputs: AuditInput[]; claimed: Set<string> } {
|
|
492
|
+
const inputs: AuditInput[] = [];
|
|
493
|
+
const claimed = new Set<string>();
|
|
494
|
+
if (!plugin) return { inputs, claimed };
|
|
495
|
+
const byDir = new Map<string, Record<string, string>>();
|
|
496
|
+
for (const f of files) {
|
|
497
|
+
if (!isTerraformFileName(basename(f.path))) continue;
|
|
498
|
+
const slash = f.path.lastIndexOf("/");
|
|
499
|
+
const dir = slash === -1 ? "" : f.path.slice(0, slash);
|
|
500
|
+
const name = slash === -1 ? f.path : f.path.slice(slash + 1);
|
|
501
|
+
const bundle = byDir.get(dir) ?? {};
|
|
502
|
+
bundle[name] = f.content;
|
|
503
|
+
byDir.set(dir, bundle);
|
|
504
|
+
claimed.add(f.path);
|
|
505
|
+
}
|
|
506
|
+
const childModules = baseDir === undefined ? new Set<string>() : calledAsLocalModule(byDir);
|
|
507
|
+
for (const [dir, bundle] of byDir) {
|
|
508
|
+
if (childModules.has(dir)) continue;
|
|
509
|
+
// `content` is the whole root module, every `.tf` in filename order with a
|
|
510
|
+
// `# file:` line comment (legal HCL) marking each boundary, so a lexicon's
|
|
511
|
+
// `auditEntities(content)` sees the module Terraform itself would load,
|
|
512
|
+
// not one arbitrary file of it. `files` keeps the per-file split, and
|
|
513
|
+
// `dir` is where the local modules it calls are read from.
|
|
514
|
+
const content = Object.keys(bundle)
|
|
515
|
+
.sort()
|
|
516
|
+
.map((name) => `# file: ${name}\n${bundle[name]}`)
|
|
517
|
+
.join("\n");
|
|
518
|
+
inputs.push({
|
|
519
|
+
path: dir === "" ? "." : dir,
|
|
520
|
+
content,
|
|
521
|
+
lexicon: "terraform",
|
|
522
|
+
files: bundle,
|
|
523
|
+
...(baseDir === undefined ? {} : { dir: resolve(baseDir, dir), baseDir }),
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
return { inputs, claimed };
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/** Where a set of classified files came from, when they came from a local walk (#2217). */
|
|
530
|
+
export interface ClassifyOptions {
|
|
531
|
+
/**
|
|
532
|
+
* Absolute path of the directory that was walked. Travels onto the inputs
|
|
533
|
+
* whose `path` names a directory, so a lexicon's `auditEntities` can read
|
|
534
|
+
* the files that directory references (terraform's local module calls).
|
|
535
|
+
* Omit for an in-memory or fetched file set: there is no directory to read.
|
|
536
|
+
*/
|
|
537
|
+
baseDir?: string;
|
|
538
|
+
}
|
|
539
|
+
|
|
374
540
|
/**
|
|
375
541
|
* Classify an in-memory set of repo files into per-lexicon audit inputs. Pure
|
|
376
542
|
* (no fs, no network) so the local walk and the remote tree-fetch share exactly
|
|
377
543
|
* one detection path. Each file maps to at most one lexicon: CI by path,
|
|
378
|
-
* Dockerfiles by name, Helm charts
|
|
379
|
-
* precedence-ordered content detectors
|
|
380
|
-
* `detectTemplate`). Lexicons whose plugin isn't
|
|
544
|
+
* Dockerfiles by name, Helm charts and Terraform root modules as directory
|
|
545
|
+
* bundles, everything else by the precedence-ordered content detectors
|
|
546
|
+
* (delegating to each plugin's `detectTemplate`). Lexicons whose plugin isn't
|
|
547
|
+
* provided are skipped.
|
|
381
548
|
*/
|
|
382
|
-
export function classifyFiles(files: RepoFile[], plugins: DetectPlugin[]): AuditInput[] {
|
|
549
|
+
export function classifyFiles(files: RepoFile[], plugins: DetectPlugin[], opts: ClassifyOptions = {}): AuditInput[] {
|
|
383
550
|
const byName = new Map(plugins.map((p) => [p.name, p]));
|
|
551
|
+
const baseDir = opts.baseDir === undefined ? undefined : resolve(opts.baseDir);
|
|
384
552
|
|
|
385
553
|
// Helm claims whole chart directories first; chart-internal files are excluded
|
|
386
554
|
// from the loose-file pass so templates aren't double-audited.
|
|
387
555
|
const helm = classifyHelm(files, byName.get("helm"));
|
|
388
556
|
const underChart = (p: string): boolean => helm.prefixes.some((pre) => (pre === "" ? true : p.startsWith(pre)));
|
|
389
557
|
|
|
390
|
-
const
|
|
558
|
+
const terraform = classifyTerraform(files, byName.get("terraform"), baseDir);
|
|
559
|
+
|
|
560
|
+
const inputs: AuditInput[] = [...helm.inputs, ...terraform.inputs];
|
|
391
561
|
for (const { path, content } of files) {
|
|
392
562
|
if (underChart(path)) continue;
|
|
563
|
+
if (terraform.claimed.has(path)) continue;
|
|
393
564
|
const name = basename(path);
|
|
394
565
|
|
|
395
566
|
const ci = ciLexiconForPath(path);
|
|
@@ -420,20 +591,33 @@ export function classifyFiles(files: RepoFile[], plugins: DetectPlugin[]): Audit
|
|
|
420
591
|
* lexicon whose plugin isn't provided, so a caller can scope discovery.
|
|
421
592
|
*/
|
|
422
593
|
export function discoverByDetection(root: string, plugins: DetectPlugin[]): AuditInput[] {
|
|
423
|
-
return classifyFiles(collectCandidates(root), plugins);
|
|
594
|
+
return classifyFiles(collectCandidates(root), plugins, { baseDir: root });
|
|
424
595
|
}
|
|
425
596
|
|
|
426
597
|
/** The walk half of `discoverByDetection`: candidate files read into memory, paths relative to the root. */
|
|
427
598
|
export function collectCandidates(root: string): RepoFile[] {
|
|
428
599
|
const all: string[] = [];
|
|
429
600
|
walkFiles(root, all);
|
|
601
|
+
// TF023 reads paths, not content: a `.tfstate` can be tens of megabytes of
|
|
602
|
+
// machine-generated JSON, and the finding is that it is in the repository at
|
|
603
|
+
// all. The root `.gitignore` is what separates "committed" from "merely on
|
|
604
|
+
// disk" here — a Terraform working tree almost always has an ignored
|
|
605
|
+
// `.terraform/` in it, and reporting that would make TF023 fire on every
|
|
606
|
+
// local audit. A fetched repository has no such ambiguity (its file list is
|
|
607
|
+
// the tracked files) and is not filtered.
|
|
608
|
+
const gitignore = readSafe(join(root, ".gitignore")) ?? "";
|
|
430
609
|
const files: RepoFile[] = [];
|
|
431
610
|
for (const full of all) {
|
|
432
611
|
const path = relative(root, full);
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
612
|
+
if (isTerraformStatePath(path)) {
|
|
613
|
+
if (!gitignoreCoversTerraformState(gitignore, path)) files.push({ path, content: "" });
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
// `.tf` is read locally so `classifyTerraform` can bundle real content.
|
|
617
|
+
// It stays out of `isCandidatePath` so remote fetches still never pull HCL.
|
|
618
|
+
if (isTerraformFileName(basename(path))) {
|
|
619
|
+
const content = readSafe(full);
|
|
620
|
+
if (content !== undefined) files.push({ path, content });
|
|
437
621
|
continue;
|
|
438
622
|
}
|
|
439
623
|
if (!isCandidatePath(path)) continue;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prior art for these audit rules: the open-source tools whose checks cover the
|
|
3
|
+
* same condition, credited per rule. See packages/core/src/audit/prior-art.ts for
|
|
4
|
+
* the registry, the relation vocabulary, and why this is credit rather than
|
|
5
|
+
* authority. Kept by hand; the prior-art sweep (scripts/prior-art-sweep.ts) reports
|
|
6
|
+
* when a credited tool's index no longer lists a rule cited here.
|
|
7
|
+
*/
|
|
8
|
+
import type { Lineage } from "./prior-art";
|
|
9
|
+
|
|
10
|
+
export const coreAuditLineage: Record<string, Lineage[]> = {
|
|
11
|
+
AGT002: [
|
|
12
|
+
{ tool: "agent-audit", rule: "auth-bypass/env-secret-in-config", url: "https://raw.githubusercontent.com/piiiico/agent-audit/main/README.md", relation: "equivalent" },
|
|
13
|
+
{ tool: "mcp-audit", rule: "Secrets Detection", url: "https://raw.githubusercontent.com/apisec-inc/mcp-audit/main/README.md", relation: "overlaps" },
|
|
14
|
+
{ tool: "agent-scan", rule: "W008", url: "https://raw.githubusercontent.com/invariantlabs-ai/mcp-scan/main/docs/issue-codes.md", relation: "overlaps" },
|
|
15
|
+
],
|
|
16
|
+
COR020: [
|
|
17
|
+
{ tool: "cfn-lint", rule: "E3004", url: "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/rules.md#E3004", relation: "equivalent" },
|
|
18
|
+
],
|
|
19
|
+
EXT001: [
|
|
20
|
+
{ tool: "cfn-lint", url: "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/cfn-schema-specification.md#extending-the-schemas-with-new-keywords", relation: "equivalent" },
|
|
21
|
+
{ tool: "cfn-lint", rule: "E3014", url: "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/rules.md#E3014", relation: "equivalent" },
|
|
22
|
+
{ tool: "cfn-lint", rule: "E3021", url: "https://github.com/aws-cloudformation/cfn-lint/blob/main/docs/rules.md#E3021", relation: "equivalent" },
|
|
23
|
+
],
|
|
24
|
+
NGX001: [
|
|
25
|
+
{ tool: "gixy-ng", rule: "weak_ssl_tls", url: "https://gixy.getpagespeed.com/plugins/weak_ssl_tls/", relation: "overlaps" },
|
|
26
|
+
],
|
|
27
|
+
NGX002: [
|
|
28
|
+
{ tool: "gixy-ng", rule: "weak_ssl_tls", url: "https://gixy.getpagespeed.com/plugins/weak_ssl_tls/", relation: "overlaps" },
|
|
29
|
+
],
|
|
30
|
+
NGX004: [
|
|
31
|
+
{ tool: "gixy", rule: "alias_traversal", url: "https://github.com/yandex/gixy", relation: "equivalent" },
|
|
32
|
+
{ tool: "gixy-ng", rule: "alias_traversal", url: "https://gixy.getpagespeed.com/plugins/aliastraversal/", relation: "equivalent" },
|
|
33
|
+
],
|
|
34
|
+
NGX005: [
|
|
35
|
+
{ tool: "gixy-ng", rule: "status_page_exposed", url: "https://gixy.getpagespeed.com/checks/status-page-exposed/", relation: "overlaps" },
|
|
36
|
+
],
|
|
37
|
+
NGX006: [
|
|
38
|
+
{ tool: "gixy-ng", rule: "version_disclosure", url: "https://gixy.getpagespeed.com/plugins/version_disclosure/", relation: "equivalent" },
|
|
39
|
+
],
|
|
40
|
+
SEC001: [
|
|
41
|
+
{ tool: "gitleaks", rule: "aws-access-token", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "equivalent" },
|
|
42
|
+
{ tool: "trufflehog", rule: "aws", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/aws/access_keys/accesskey.go", relation: "overlaps" },
|
|
43
|
+
{ tool: "detect-secrets", rule: "AWSKeyDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/aws.py", relation: "equivalent" },
|
|
44
|
+
],
|
|
45
|
+
SEC002: [
|
|
46
|
+
{ tool: "gitleaks", rule: "generic-api-key", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
47
|
+
{ tool: "trufflehog", rule: "aws", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/aws/access_keys/accesskey.go", relation: "overlaps" },
|
|
48
|
+
{ tool: "detect-secrets", rule: "AWSKeyDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/aws.py", relation: "overlaps" },
|
|
49
|
+
],
|
|
50
|
+
SEC003: [
|
|
51
|
+
{ tool: "gitleaks", rule: "github-pat", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
52
|
+
{ tool: "trufflehog", rule: "github", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/github/v2/github.go", relation: "equivalent" },
|
|
53
|
+
{ tool: "detect-secrets", rule: "GitHubTokenDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/github_token.py", relation: "overlaps" },
|
|
54
|
+
],
|
|
55
|
+
SEC004: [
|
|
56
|
+
{ tool: "gitleaks", rule: "slack-bot-token", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
57
|
+
{ tool: "trufflehog", rule: "slack", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/slack/slack.go", relation: "overlaps" },
|
|
58
|
+
{ tool: "detect-secrets", rule: "SlackDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/slack.py", relation: "overlaps" },
|
|
59
|
+
],
|
|
60
|
+
SEC005: [
|
|
61
|
+
{ tool: "gitleaks", rule: "gcp-api-key", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "equivalent" },
|
|
62
|
+
{ tool: "trufflehog", rule: "googlegemini", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/googlegemini/googlegemini.go", relation: "overlaps" },
|
|
63
|
+
],
|
|
64
|
+
SEC006: [
|
|
65
|
+
{ tool: "gitleaks", rule: "stripe-access-token", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
66
|
+
{ tool: "trufflehog", rule: "stripe", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/stripe/stripe.go", relation: "overlaps" },
|
|
67
|
+
{ tool: "detect-secrets", rule: "StripeDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/stripe.py", relation: "overlaps" },
|
|
68
|
+
],
|
|
69
|
+
SEC007: [
|
|
70
|
+
{ tool: "gitleaks", rule: "private-key", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "equivalent" },
|
|
71
|
+
{ tool: "trufflehog", rule: "privatekey", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/privatekey/privatekey.go", relation: "equivalent" },
|
|
72
|
+
{ tool: "detect-secrets", rule: "PrivateKeyDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/private_key.py", relation: "equivalent" },
|
|
73
|
+
],
|
|
74
|
+
SEC008: [
|
|
75
|
+
{ tool: "gitleaks", rule: "curl-auth-header", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
76
|
+
],
|
|
77
|
+
SEC009: [
|
|
78
|
+
{ tool: "detect-secrets", rule: "BasicAuthDetector", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/basic_auth.py", relation: "equivalent" },
|
|
79
|
+
{ tool: "trufflehog", rule: "uri", url: "https://github.com/trufflesecurity/trufflehog/blob/main/pkg/detectors/uri/uri.go", relation: "overlaps" },
|
|
80
|
+
{ tool: "gitleaks", rule: "curl-auth-user", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
81
|
+
],
|
|
82
|
+
SEC010: [
|
|
83
|
+
{ tool: "detect-secrets", rule: "Base64HighEntropyString", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/high_entropy_strings.py", relation: "overlaps" },
|
|
84
|
+
{ tool: "detect-secrets", rule: "HexHighEntropyString", url: "https://github.com/Yelp/detect-secrets/blob/master/detect_secrets/plugins/high_entropy_strings.py", relation: "overlaps" },
|
|
85
|
+
{ tool: "gitleaks", rule: "generic-api-key", url: "https://github.com/gitleaks/gitleaks/blob/master/config/gitleaks.toml", relation: "overlaps" },
|
|
86
|
+
],
|
|
87
|
+
// TF023 is the one TF id core owns (./terraform-state.ts); the rest of the
|
|
88
|
+
// family credits its prior art from lexicons/terraform/src/lint/audit-lineage.ts.
|
|
89
|
+
// No linter or scanner in #2107's survey checks for committed state, but the
|
|
90
|
+
// style guide's .gitignore section names the exact files, so the document is
|
|
91
|
+
// both the authority and the first written statement of the rule.
|
|
92
|
+
TF023: [
|
|
93
|
+
{
|
|
94
|
+
tool: "hashicorp-style-guide",
|
|
95
|
+
rule: ".gitignore: do not commit terraform.tfstate, terraform.tfstate.* backups, or the .terraform directory",
|
|
96
|
+
url: "https://developer.hashicorp.com/terraform/language/style#gitignore",
|
|
97
|
+
relation: "equivalent",
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
};
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prior art for chant's audit rules.
|
|
3
|
+
*
|
|
4
|
+
* Most of what `chant audit` checks has been checked before by a dedicated
|
|
5
|
+
* open-source tool: zizmor and poutine for GitHub Actions, hadolint for
|
|
6
|
+
* Dockerfiles, cfn-lint and cfn_nag for CloudFormation, kube-linter and
|
|
7
|
+
* kube-score for Kubernetes manifests, gitleaks for secrets, and so on. chant's
|
|
8
|
+
* rules were written independently against the emitted output, but the ideas
|
|
9
|
+
* are shared, and the people who wrote them down first deserve the credit.
|
|
10
|
+
*
|
|
11
|
+
* A rule declares its lineage as `Lineage[]` on its `RuleMeta` entry: which
|
|
12
|
+
* tool, which upstream rule, where it is documented, and how the two relate.
|
|
13
|
+
* `PRIOR_ART` is the registry those entries key into, so a tool is named,
|
|
14
|
+
* linked and licensed once. The audit rules reference renders both, the
|
|
15
|
+
* markdown and HTML reports credit the tool beside the finding, and the SARIF
|
|
16
|
+
* and JSON outputs carry the entries verbatim for consumers.
|
|
17
|
+
*
|
|
18
|
+
* Lineage is credit, not authority. `authority` (./catalog.ts) is a standard
|
|
19
|
+
* or vendor document that says a finding matters; lineage is a tool that
|
|
20
|
+
* checks the same condition. The two are independent: a rule may have either,
|
|
21
|
+
* both, or neither, and lineage never changes a rule's category or tier.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** How a chant rule relates to the upstream check it credits. */
|
|
25
|
+
export type LineageRelation =
|
|
26
|
+
/** Same condition, same scope. */
|
|
27
|
+
| "equivalent"
|
|
28
|
+
/** The core condition is shared; one side is narrower or broader, or a different dialect of the same control. */
|
|
29
|
+
| "overlaps"
|
|
30
|
+
/** chant checks a strict superset of the upstream check. */
|
|
31
|
+
| "extends";
|
|
32
|
+
|
|
33
|
+
/** One credit: an upstream tool's rule that checks what this chant rule checks. */
|
|
34
|
+
export interface Lineage {
|
|
35
|
+
/** A key of {@link PRIOR_ART}. */
|
|
36
|
+
tool: PriorArtTool;
|
|
37
|
+
/** The upstream rule id or check name, in the tool's own vocabulary (e.g. `template-injection`, `DL3007`, `CKV_AWS_18`). Omitted when the tool has no per-rule ids. */
|
|
38
|
+
rule?: string;
|
|
39
|
+
/** Where the upstream rule is documented. */
|
|
40
|
+
url: string;
|
|
41
|
+
relation: LineageRelation;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** A tool (or, for a few families, a vendor validator) that chant's rules credit. */
|
|
45
|
+
export interface PriorArtEntry {
|
|
46
|
+
name: string;
|
|
47
|
+
url: string;
|
|
48
|
+
/** SPDX identifier where confirmed, else "unverified" or "n/a" for documentation. */
|
|
49
|
+
license: string;
|
|
50
|
+
/** What kind of thing this is, so the rendered credit is honest about it. */
|
|
51
|
+
kind: "scanner" | "vendor-validator" | "specification";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The registry of prior art. Keys are the slugs `Lineage.tool` uses. Populated
|
|
56
|
+
* from the per-family research recorded in the PR that introduced lineage; the
|
|
57
|
+
* prior-art sweep (scripts/prior-art-sweep.ts) reads the same table.
|
|
58
|
+
*/
|
|
59
|
+
export const PRIOR_ART = {
|
|
60
|
+
"checkov": { name: "Checkov", url: "https://www.checkov.io/", license: "Apache-2.0", kind: "scanner" },
|
|
61
|
+
"kics": { name: "KICS", url: "https://docs.kics.io/", license: "Apache-2.0", kind: "scanner" },
|
|
62
|
+
"zizmor": { name: "zizmor", url: "https://docs.zizmor.sh/", license: "MIT", kind: "scanner" },
|
|
63
|
+
"cfn-nag": { name: "cfn_nag", url: "https://github.com/stelligent/cfn_nag", license: "MIT", kind: "scanner" },
|
|
64
|
+
"gitlab-docs": { name: "GitLab CI/CD YAML reference", url: "https://docs.gitlab.com/ci/yaml/", license: "CC-BY-SA-4.0", kind: "specification" },
|
|
65
|
+
"guard-rules-registry": { name: "AWS Guard Rules Registry", url: "https://github.com/aws-cloudformation/aws-guard-rules-registry", license: "Apache-2.0", kind: "scanner" },
|
|
66
|
+
"polaris": { name: "Fairwinds Polaris", url: "https://polaris.docs.fairwinds.com/", license: "Apache-2.0", kind: "scanner" },
|
|
67
|
+
"kube-linter": { name: "KubeLinter", url: "https://github.com/stackrox/kube-linter", license: "Apache-2.0", kind: "scanner" },
|
|
68
|
+
"kube-score": { name: "kube-score", url: "https://github.com/zegl/kube-score", license: "MIT", kind: "scanner" },
|
|
69
|
+
"psrule-azure": { name: "PSRule for Azure", url: "https://azure.github.io/PSRule.Rules.Azure/", license: "MIT", kind: "scanner" },
|
|
70
|
+
"gcp-policy-library": { name: "Google Cloud Policy Library", url: "https://github.com/GoogleCloudPlatform/policy-library", license: "Apache-2.0", kind: "scanner" },
|
|
71
|
+
"poutine": { name: "poutine", url: "https://boostsecurityio.github.io/poutine/", license: "Apache-2.0", kind: "scanner" },
|
|
72
|
+
"scorecard": { name: "OpenSSF Scorecard", url: "https://github.com/ossf/scorecard", license: "Apache-2.0", kind: "scanner" },
|
|
73
|
+
"cfn-lint": { name: "cfn-lint", url: "https://github.com/aws-cloudformation/cfn-lint", license: "MIT-0", kind: "scanner" },
|
|
74
|
+
"controlplane-docs": { name: "Control Plane reference documentation", url: "https://docs.controlplane.com", license: "n/a", kind: "specification" },
|
|
75
|
+
"gitleaks": { name: "gitleaks", url: "https://github.com/gitleaks/gitleaks", license: "MIT", kind: "scanner" },
|
|
76
|
+
"octoscan": { name: "octoscan", url: "https://github.com/synacktiv/octoscan", license: "GPL-3.0", kind: "scanner" },
|
|
77
|
+
"detect-secrets": { name: "detect-secrets", url: "https://github.com/Yelp/detect-secrets", license: "Apache-2.0", kind: "scanner" },
|
|
78
|
+
"actionlint": { name: "actionlint", url: "https://github.com/rhysd/actionlint", license: "MIT", kind: "scanner" },
|
|
79
|
+
"trufflehog": { name: "TruffleHog", url: "https://github.com/trufflesecurity/trufflehog", license: "AGPL-3.0", kind: "scanner" },
|
|
80
|
+
"gixy-ng": { name: "gixy-ng (maintained Gixy fork)", url: "https://github.com/dvershinin/gixy", license: "MPL-2.0", kind: "scanner" },
|
|
81
|
+
"kubesec": { name: "kubesec", url: "https://kubesec.io/", license: "Apache-2.0", kind: "scanner" },
|
|
82
|
+
"datree": { name: "Datree", url: "https://hub.datree.io/built-in-rules", license: "Apache-2.0", kind: "scanner" },
|
|
83
|
+
"helm-lint": { name: "helm lint", url: "https://helm.sh/docs/helm/helm_lint/", license: "Apache-2.0", kind: "vendor-validator" },
|
|
84
|
+
"cedar-validator": { name: "Cedar policy validator", url: "https://docs.cedarpolicy.com/policies/validation.html", license: "Apache-2.0", kind: "vendor-validator" },
|
|
85
|
+
"flux-docs": { name: "Flux Kustomization API reference", url: "https://fluxcd.io/flux/components/kustomize/kustomizations/", license: "n/a", kind: "specification" },
|
|
86
|
+
"hadolint": { name: "hadolint", url: "https://github.com/hadolint/hadolint", license: "GPL-3.0", kind: "scanner" },
|
|
87
|
+
"agent-audit": { name: "agent-audit", url: "https://github.com/piiiico/agent-audit", license: "MIT", kind: "scanner" },
|
|
88
|
+
"arm-ttk": { name: "ARM Template Toolkit (arm-ttk)", url: "https://github.com/Azure/arm-ttk", license: "MIT", kind: "scanner" },
|
|
89
|
+
"bicep-linter": { name: "Bicep linter", url: "https://learn.microsoft.com/en-us/azure/azure-resource-manager/bicep/linter", license: "MIT", kind: "scanner" },
|
|
90
|
+
"cedar-cli": { name: "Cedar CLI", url: "https://github.com/cedar-policy/cedar/tree/main/cedar-policy-cli", license: "Apache-2.0", kind: "vendor-validator" },
|
|
91
|
+
"dockle": { name: "Dockle", url: "https://github.com/goodwithtech/dockle", license: "Apache-2.0", kind: "scanner" },
|
|
92
|
+
"mcp-audit": { name: "mcp-audit (APIsec)", url: "https://github.com/apisec-inc/mcp-audit", license: "MIT", kind: "scanner" },
|
|
93
|
+
"render-docs": { name: "Render Blueprint YAML reference", url: "https://render.com/docs/blueprint-spec", license: "n/a", kind: "specification" },
|
|
94
|
+
"agent-scan": { name: "Snyk Agent Scan (formerly mcp-scan)", url: "https://github.com/invariantlabs-ai/mcp-scan", license: "Apache-2.0", kind: "scanner" },
|
|
95
|
+
"cedar-docs": { name: "Cedar policy language reference", url: "https://docs.cedarpolicy.com/policies/json-format.html", license: "n/a", kind: "specification" },
|
|
96
|
+
"cedar-policy-crate": { name: "cedar-policy crate (PolicySet loader)", url: "https://docs.rs/cedar-policy/latest/cedar_policy/", license: "Apache-2.0", kind: "vendor-validator" },
|
|
97
|
+
"chart-testing": { name: "chart-testing (ct)", url: "https://github.com/helm/chart-testing", license: "Apache-2.0", kind: "vendor-validator" },
|
|
98
|
+
"fly-docs": { name: "Fly Machines API reference", url: "https://fly.io/docs/machines/api/machines-resource/", license: "n/a", kind: "specification" },
|
|
99
|
+
"gixy": { name: "Gixy", url: "https://github.com/yandex/gixy", license: "MPL-2.0", kind: "scanner" },
|
|
100
|
+
"kube-bench": { name: "kube-bench", url: "https://github.com/aquasecurity/kube-bench", license: "Apache-2.0", kind: "scanner" },
|
|
101
|
+
"pluto": { name: "Pluto", url: "https://github.com/FairwindsOps/pluto", license: "Apache-2.0", kind: "scanner" },
|
|
102
|
+
"choudoufu": { name: "choudoufu", url: "https://github.com/INTENTIUS/choudoufu", license: "MPL-2.0", kind: "scanner" },
|
|
103
|
+
// Terraform lint family (#2107). Registry entries recorded in
|
|
104
|
+
// lexicons/terraform/src/lint/audit-lineage.ts's header comment; added here
|
|
105
|
+
// the first time a shipped rule cites them (#2109).
|
|
106
|
+
"tflint-ruleset-terraform": { name: "tflint-ruleset-terraform", url: "https://github.com/terraform-linters/tflint-ruleset-terraform", license: "MPL-2.0", kind: "scanner" },
|
|
107
|
+
"terraform-sentinel-policies": { name: "HashiCorp reference Sentinel policies", url: "https://github.com/hashicorp/terraform-sentinel-policies", license: "MPL-2.0", kind: "specification" },
|
|
108
|
+
"hashicorp-style-guide": { name: "HashiCorp Terraform style guide", url: "https://developer.hashicorp.com/terraform/language/style", license: "n/a", kind: "specification" },
|
|
109
|
+
"aws-terraform-prescriptive-guidance": { name: "AWS prescriptive guidance for Terraform", url: "https://docs.aws.amazon.com/prescriptive-guidance/latest/terraform-aws-provider-best-practices/", license: "n/a", kind: "specification" },
|
|
110
|
+
// A multi-page series; a credit cites the specific page and fragment, not
|
|
111
|
+
// this landing URL. First cited by TF014 and TF015 (#2112).
|
|
112
|
+
"gcp-terraform-best-practices": { name: "Google Cloud Terraform best-practices series", url: "https://docs.cloud.google.com/docs/terraform/best-practices/general-style-structure", license: "n/a", kind: "specification" },
|
|
113
|
+
"tflint-ruleset-redeploy": { name: "tflint-ruleset-redeploy", url: "https://github.com/RedeployAB/tflint-ruleset-redeploy", license: "0BSD", kind: "scanner" },
|
|
114
|
+
"tflint-ruleset-avm": { name: "tflint-ruleset-avm (Azure Verified Modules)", url: "https://github.com/Azure/tflint-ruleset-avm", license: "MIT", kind: "scanner" },
|
|
115
|
+
// tfsec is frozen rather than archived, and its docs site 404s above v0.61.x,
|
|
116
|
+
// so its credits cite pinned repository paths (a tag or `master`), never the
|
|
117
|
+
// docs site. The three `general/secrets` checks chant credits live only here:
|
|
118
|
+
// trivy dropped them when it absorbed tfsec.
|
|
119
|
+
"tfsec": { name: "tfsec", url: "https://github.com/aquasecurity/tfsec", license: "MIT", kind: "scanner" },
|
|
120
|
+
// Semgrep's engine is LGPL-2.1 but its rules are not: they ship under the
|
|
121
|
+
// proprietary Semgrep Rules License v1.0, which forbids redistribution. So
|
|
122
|
+
// this entry carries no SPDX id, and no semgrep rule text is ever copied into
|
|
123
|
+
// this repository — a credit by name and link is the whole of it (#2107).
|
|
124
|
+
"semgrep": { name: "Semgrep Registry rules", url: "https://github.com/semgrep/semgrep-rules", license: "Semgrep Rules License v1.0 (proprietary, not an SPDX id)", kind: "scanner" },
|
|
125
|
+
} as const satisfies Record<string, PriorArtEntry>;
|
|
126
|
+
|
|
127
|
+
export type PriorArtTool = keyof typeof PRIOR_ART;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Attach lineage to a catalog in place. A lexicon keeps its lineage in a
|
|
131
|
+
* sibling `audit-lineage.ts` (one `Record<ruleId, Lineage[]>`) and calls this
|
|
132
|
+
* once at the bottom of its `audit-catalog.ts`, so the prose metadata and the
|
|
133
|
+
* credits stay next to each other but the credits can be regenerated by the
|
|
134
|
+
* prior-art sweep without touching the rule text. Throws at module load if the
|
|
135
|
+
* lineage names a rule the catalog does not have: a stale id is a bug, not a
|
|
136
|
+
* silent no-op.
|
|
137
|
+
*/
|
|
138
|
+
export function applyLineage<T extends { id: string; lineage?: Lineage[] }>(
|
|
139
|
+
catalog: Record<string, T>,
|
|
140
|
+
lineage: Record<string, Lineage[]>,
|
|
141
|
+
): void {
|
|
142
|
+
for (const [id, entries] of Object.entries(lineage)) {
|
|
143
|
+
const rule = catalog[id];
|
|
144
|
+
if (!rule) throw new Error(`audit lineage names ${id}, which this catalog does not define`);
|
|
145
|
+
if (entries.length > 0) rule.lineage = entries;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Render one lineage entry as "tool rule (relation)" for prose contexts. */
|
|
150
|
+
export function lineageLabel(l: Lineage): string {
|
|
151
|
+
const tool = (PRIOR_ART as Record<string, PriorArtEntry>)[l.tool]?.name ?? l.tool;
|
|
152
|
+
return l.rule ? `${tool} ${l.rule}` : tool;
|
|
153
|
+
}
|