@intentius/chant 0.13.1 → 0.15.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 +45 -5
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/proof.d.ts +3 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +4 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts +3 -0
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +8 -2
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
- package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/components.d.ts +39 -0
- package/dist/cli/handlers/components.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts +3 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/graph.d.ts +4 -2
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +35 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts +22 -0
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.d.ts +110 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -0
- package/dist/codegen/pinned-upgrade.d.ts +153 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
- package/dist/codegen/rolling-upgrade.d.ts +138 -0
- package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
- package/dist/codegen/surface-snapshot.d.ts +173 -0
- package/dist/codegen/surface-snapshot.d.ts.map +1 -0
- package/dist/codegen/version-bump.d.ts +21 -0
- package/dist/codegen/version-bump.d.ts.map +1 -0
- package/dist/components/auto-release.d.ts +93 -0
- package/dist/components/auto-release.d.ts.map +1 -0
- package/dist/components/builders.d.ts +37 -0
- package/dist/components/builders.d.ts.map +1 -0
- package/dist/components/capability-plugin-loader.d.ts +111 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -0
- package/dist/components/capability-plugin-schema.d.ts +24 -0
- package/dist/components/capability-plugin-schema.d.ts.map +1 -0
- package/dist/components/capability-plugin.d.ts +85 -0
- package/dist/components/capability-plugin.d.ts.map +1 -0
- package/dist/components/capability.d.ts +89 -0
- package/dist/components/capability.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +204 -0
- package/dist/components/cli-support.d.ts.map +1 -0
- package/dist/components/component.d.ts +179 -0
- package/dist/components/component.d.ts.map +1 -0
- package/dist/components/config-defaults.d.ts +41 -0
- package/dist/components/config-defaults.d.ts.map +1 -0
- package/dist/components/discover.d.ts +60 -0
- package/dist/components/discover.d.ts.map +1 -0
- package/dist/components/driver-output.d.ts +20 -0
- package/dist/components/driver-output.d.ts.map +1 -0
- package/dist/components/driver.d.ts +209 -0
- package/dist/components/driver.d.ts.map +1 -0
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/manifest-persistence.d.ts +79 -0
- package/dist/components/manifest-persistence.d.ts.map +1 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
- package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
- package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
- package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
- package/dist/components/pilots/lambda.pilot.d.ts +35 -0
- package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
- package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
- package/dist/components/pilots/project.d.ts +13 -0
- package/dist/components/pilots/project.d.ts.map +1 -0
- package/dist/components/presets/ecs-fargate.d.ts +59 -0
- package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
- package/dist/components/presets/index.d.ts +29 -0
- package/dist/components/presets/index.d.ts.map +1 -0
- package/dist/components/presets/lambda.d.ts +35 -0
- package/dist/components/presets/lambda.d.ts.map +1 -0
- package/dist/components/presets/single-host-compose.d.ts +43 -0
- package/dist/components/presets/single-host-compose.d.ts.map +1 -0
- package/dist/components/registry.d.ts +29 -0
- package/dist/components/registry.d.ts.map +1 -0
- package/dist/components/starter-plugin.d.ts +51 -0
- package/dist/components/starter-plugin.d.ts.map +1 -0
- package/dist/components/temporal-codegen-loader.d.ts +27 -0
- package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
- package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/bom-writer.d.ts +155 -0
- package/dist/components/verbs/bom-writer.d.ts.map +1 -0
- package/dist/components/verbs/build-archive.d.ts +205 -0
- package/dist/components/verbs/build-archive.d.ts.map +1 -0
- package/dist/components/verbs/build.d.ts +150 -0
- package/dist/components/verbs/build.d.ts.map +1 -0
- package/dist/components/verbs/cloud-executor.d.ts +88 -0
- package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
- package/dist/components/verbs/component-bom.d.ts +103 -0
- package/dist/components/verbs/component-bom.d.ts.map +1 -0
- package/dist/components/verbs/index.d.ts +49 -0
- package/dist/components/verbs/index.d.ts.map +1 -0
- package/dist/components/verbs/license-policy.d.ts +56 -0
- package/dist/components/verbs/license-policy.d.ts.map +1 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/process-runner.d.ts +64 -0
- package/dist/components/verbs/process-runner.d.ts.map +1 -0
- package/dist/components/verbs/reproducibility.d.ts +80 -0
- package/dist/components/verbs/reproducibility.d.ts.map +1 -0
- package/dist/components/verbs/sbom-generator.d.ts +157 -0
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/sbom.d.ts +79 -0
- package/dist/components/verbs/sbom.d.ts.map +1 -0
- package/dist/components/verbs/shell.d.ts +35 -0
- package/dist/components/verbs/shell.d.ts.map +1 -0
- package/dist/components/verbs/sign.d.ts +222 -0
- package/dist/components/verbs/sign.d.ts.map +1 -0
- package/dist/components/verbs/stub.d.ts +18 -0
- package/dist/components/verbs/stub.d.ts.map +1 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
- package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
- package/dist/components/verbs/verify.d.ts +106 -0
- package/dist/components/verbs/verify.d.ts.map +1 -0
- package/dist/components/verbs/vex.d.ts +65 -0
- package/dist/components/verbs/vex.d.ts.map +1 -0
- package/dist/components/verbs/vuln-gate.d.ts +91 -0
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
- package/dist/components/verbs/vuln-scan.d.ts +116 -0
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
- package/dist/components/verbs/wait-verify.d.ts +85 -0
- package/dist/components/verbs/wait-verify.d.ts.map +1 -0
- package/dist/config.d.ts +205 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +78 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/build-ledger-store.d.ts +121 -0
- package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
- package/dist/lifecycle/build-ledger.d.ts +225 -0
- package/dist/lifecycle/build-ledger.d.ts.map +1 -0
- package/dist/lifecycle/git.d.ts +84 -0
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +5 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
- package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
- package/dist/lifecycle/release-ledger.d.ts +122 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -0
- package/dist/lifecycle/status.d.ts +150 -0
- package/dist/lifecycle/status.d.ts.map +1 -0
- package/dist/lint/component-checks.d.ts +95 -0
- package/dist/lint/component-checks.d.ts.map +1 -0
- package/dist/lint/engine.d.ts +23 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/presets/strict.json +8 -1
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +18 -0
- package/dist/lint/rules/comp/index.d.ts.map +1 -0
- package/dist/lint/rules/comp/support.d.ts +71 -0
- package/dist/lint/rules/comp/support.d.ts.map +1 -0
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activity-registry.d.ts +11 -6
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +24 -0
- package/dist/op/activity-runtime.d.ts.map +1 -0
- package/dist/op/builders.d.ts +56 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/index.d.ts +2 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/ownership.d.ts +20 -14
- package/dist/ownership.d.ts.map +1 -1
- package/package.json +14 -1
- package/src/audit/catalog.test.ts +74 -22
- package/src/audit/catalog.ts +74 -471
- package/src/audit/proof.ts +4 -2
- package/src/audit/report-html.test.ts +14 -7
- package/src/audit/report-model.ts +20 -9
- package/src/audit/report.test.ts +36 -13
- package/src/audit/report.ts +2 -0
- package/src/audit/rules-doc.test.ts +8 -6
- package/src/audit/rules-doc.ts +13 -5
- package/src/cli/commands/audit.ts +23 -18
- package/src/cli/commands/component-lint.test.ts +158 -0
- package/src/cli/commands/doctor.test.ts +116 -2
- package/src/cli/commands/doctor.ts +46 -0
- package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
- package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
- package/src/cli/commands/lexicon-surface-diff.ts +185 -0
- package/src/cli/commands/lint.ts +142 -1
- package/src/cli/commands/pinned-upgrade.ts +204 -0
- package/src/cli/handlers/build.ts +58 -1
- package/src/cli/handlers/components.test.ts +504 -0
- package/src/cli/handlers/components.ts +404 -0
- package/src/cli/handlers/dev.ts +60 -1
- package/src/cli/handlers/graph.ts +47 -2
- package/src/cli/handlers/misc.ts +45 -1
- package/src/cli/handlers/run.test.ts +967 -3
- package/src/cli/handlers/run.ts +618 -11
- package/src/cli/main.test.ts +66 -0
- package/src/cli/main.ts +105 -2
- package/src/cli/registry.ts +35 -0
- package/src/codegen/fetch.test.ts +84 -3
- package/src/codegen/fetch.ts +76 -2
- package/src/codegen/lexicon-regen.test.ts +298 -0
- package/src/codegen/lexicon-regen.ts +545 -0
- package/src/codegen/pinned-upgrade.test.ts +399 -0
- package/src/codegen/pinned-upgrade.ts +423 -0
- package/src/codegen/rolling-upgrade.test.ts +333 -0
- package/src/codegen/rolling-upgrade.ts +320 -0
- package/src/codegen/surface-snapshot.test.ts +461 -0
- package/src/codegen/surface-snapshot.ts +546 -0
- package/src/codegen/version-bump.test.ts +47 -0
- package/src/codegen/version-bump.ts +39 -0
- package/src/components/README.md +130 -0
- package/src/components/SPRAWL-VALIDATION.md +181 -0
- package/src/components/__fixtures__/alb-ecs-service.json +51 -0
- package/src/components/__fixtures__/dynamodb-infra.json +32 -0
- package/src/components/__fixtures__/emr-job-consumer.json +26 -0
- package/src/components/__fixtures__/jar-lib-producer.json +16 -0
- package/src/components/__fixtures__/lambda-image-processor.json +28 -0
- package/src/components/__fixtures__/neo4j-fanout.json +34 -0
- package/src/components/__fixtures__/single-host-compose.json +29 -0
- package/src/components/auto-release.test.ts +217 -0
- package/src/components/auto-release.ts +216 -0
- package/src/components/builders.test.ts +45 -0
- package/src/components/builders.ts +71 -0
- package/src/components/capability-plugin-loader.ts +218 -0
- package/src/components/capability-plugin-schema.ts +56 -0
- package/src/components/capability-plugin.test.ts +235 -0
- package/src/components/capability-plugin.ts +108 -0
- package/src/components/capability.ts +117 -0
- package/src/components/cli-support.test.ts +579 -0
- package/src/components/cli-support.ts +481 -0
- package/src/components/component-schema.test.ts +265 -0
- package/src/components/component.schema.json +235 -0
- package/src/components/component.test.ts +251 -0
- package/src/components/component.ts +255 -0
- package/src/components/config-defaults.test.ts +263 -0
- package/src/components/config-defaults.ts +145 -0
- package/src/components/discover.test.ts +352 -0
- package/src/components/discover.ts +167 -0
- package/src/components/driver-output.ts +71 -0
- package/src/components/driver.test.ts +638 -0
- package/src/components/driver.ts +690 -0
- package/src/components/index.ts +113 -0
- package/src/components/manifest-persistence.test.ts +152 -0
- package/src/components/manifest-persistence.ts +164 -0
- package/src/components/pilots/README.md +33 -0
- package/src/components/pilots/alb-ecs.pilot.ts +63 -0
- package/src/components/pilots/dynamodb.pilot.ts +59 -0
- package/src/components/pilots/jar-emr.pilot.ts +69 -0
- package/src/components/pilots/lambda.pilot.ts +55 -0
- package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
- package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
- package/src/components/pilots/pilots.test.ts +126 -0
- package/src/components/pilots/project.ts +13 -0
- package/src/components/presets/comp007-reduction.test.ts +122 -0
- package/src/components/presets/ecs-fargate.test.ts +84 -0
- package/src/components/presets/ecs-fargate.ts +103 -0
- package/src/components/presets/index.ts +32 -0
- package/src/components/presets/lambda.test.ts +35 -0
- package/src/components/presets/lambda.ts +53 -0
- package/src/components/presets/single-host-compose.test.ts +65 -0
- package/src/components/presets/single-host-compose.ts +64 -0
- package/src/components/registry.test.ts +112 -0
- package/src/components/registry.ts +37 -0
- package/src/components/starter-plugin.ts +105 -0
- package/src/components/temporal-codegen-loader.ts +41 -0
- package/src/components/verbs/__fixtures__/package-lock.json +45 -0
- package/src/components/verbs/__fixtures__/pom.xml +37 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
- package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
- package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
- package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
- package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
- package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
- package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
- package/src/components/verbs/bom-writer.test.ts +331 -0
- package/src/components/verbs/bom-writer.ts +386 -0
- package/src/components/verbs/build-archive.test.ts +251 -0
- package/src/components/verbs/build-archive.ts +296 -0
- package/src/components/verbs/build.test.ts +222 -0
- package/src/components/verbs/build.ts +252 -0
- package/src/components/verbs/cloud-executor.ts +181 -0
- package/src/components/verbs/component-bom.test.ts +219 -0
- package/src/components/verbs/component-bom.ts +189 -0
- package/src/components/verbs/index.ts +49 -0
- package/src/components/verbs/license-policy.ts +115 -0
- package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
- package/src/components/verbs/process-runner.test.ts +79 -0
- package/src/components/verbs/process-runner.ts +113 -0
- package/src/components/verbs/reproducibility.test.ts +24 -0
- package/src/components/verbs/reproducibility.ts +100 -0
- package/src/components/verbs/sbom-generator.test.ts +96 -0
- package/src/components/verbs/sbom-generator.ts +209 -0
- package/src/components/verbs/sbom.test.ts +184 -0
- package/src/components/verbs/sbom.ts +152 -0
- package/src/components/verbs/shell.test.ts +36 -0
- package/src/components/verbs/shell.ts +51 -0
- package/src/components/verbs/sign.test.ts +210 -0
- package/src/components/verbs/sign.ts +350 -0
- package/src/components/verbs/stub.ts +34 -0
- package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
- package/src/components/verbs/tool-sbom-generator.ts +192 -0
- package/src/components/verbs/verify.test.ts +159 -0
- package/src/components/verbs/verify.ts +179 -0
- package/src/components/verbs/vex.ts +182 -0
- package/src/components/verbs/vuln-gate.test.ts +201 -0
- package/src/components/verbs/vuln-gate.ts +170 -0
- package/src/components/verbs/vuln-scan.test.ts +145 -0
- package/src/components/verbs/vuln-scan.ts +266 -0
- package/src/components/verbs/wait-verify.test.ts +111 -0
- package/src/components/verbs/wait-verify.ts +171 -0
- package/src/config.test.ts +74 -1
- package/src/config.ts +219 -0
- package/src/index.ts +32 -0
- package/src/lexicon.ts +88 -0
- package/src/lifecycle/build-ledger-store.test.ts +217 -0
- package/src/lifecycle/build-ledger-store.ts +165 -0
- package/src/lifecycle/build-ledger.test.ts +349 -0
- package/src/lifecycle/build-ledger.ts +305 -0
- package/src/lifecycle/git.test.ts +118 -0
- package/src/lifecycle/git.ts +149 -14
- package/src/lifecycle/index.ts +5 -0
- package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
- package/src/lifecycle/oras-referrer-lookup.ts +110 -0
- package/src/lifecycle/release-ledger.test.ts +209 -0
- package/src/lifecycle/release-ledger.ts +185 -0
- package/src/lifecycle/status.test.ts +330 -0
- package/src/lifecycle/status.ts +278 -0
- package/src/lint/component-checks.ts +148 -0
- package/src/lint/config.test.ts +21 -0
- package/src/lint/engine.ts +11 -2
- package/src/lint/presets/relaxed.json +8 -1
- package/src/lint/presets/strict.json +8 -1
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
- package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
- package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
- package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
- package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
- package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
- package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
- package/src/lint/rules/comp/comp.test.ts +378 -0
- package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
- package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
- package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
- package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
- package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
- package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
- package/src/lint/rules/comp/index.ts +37 -0
- package/src/lint/rules/comp/support.ts +173 -0
- package/src/lsp/lexicon-providers.test.ts +55 -0
- package/src/lsp/lexicon-providers.ts +13 -3
- package/src/op/activity-registry.test.ts +38 -0
- package/src/op/activity-registry.ts +31 -12
- package/src/op/activity-runtime.ts +73 -0
- package/src/op/builders.ts +92 -0
- package/src/op/index.ts +3 -1
- package/src/ownership.test.ts +24 -26
- package/src/ownership.ts +26 -38
package/src/audit/proof.ts
CHANGED
|
@@ -12,13 +12,15 @@
|
|
|
12
12
|
* the patched output differs only where intended — the diff proves it.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import { RULE_CATALOG } from "./catalog";
|
|
15
|
+
import { RULE_CATALOG, type RuleMeta } from "./catalog";
|
|
16
16
|
|
|
17
17
|
export interface ProveOptions {
|
|
18
18
|
/** Resolve an action ref (e.g. "actions/checkout@v4") to a 40-char SHA. */
|
|
19
19
|
resolveSha?: (action: string, ref: string) => string | undefined;
|
|
20
20
|
/** Resolve a container image (e.g. "node:20") to a "sha256:..." digest. */
|
|
21
21
|
resolveDigest?: (image: string) => string | undefined;
|
|
22
|
+
/** Resolved audit catalog for the check's `fixKind`/remediation lookup (#687). Defaults to core's static `RULE_CATALOG`. */
|
|
23
|
+
catalog?: Record<string, RuleMeta>;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export interface ProofResult {
|
|
@@ -150,7 +152,7 @@ function narrowWriteAll(content: string): { patched: string; changed: boolean }
|
|
|
150
152
|
* Returns `applied: false` with guidance for non-deterministic findings.
|
|
151
153
|
*/
|
|
152
154
|
export function proveFix(checkId: string, content: string, opts: ProveOptions = {}): ProofResult {
|
|
153
|
-
const cat = RULE_CATALOG[checkId];
|
|
155
|
+
const cat = (opts.catalog ?? RULE_CATALOG)[checkId];
|
|
154
156
|
if (cat && cat.fixKind !== "deterministic") {
|
|
155
157
|
return notApplied(checkId, "guidance", cat.remediation || "Manual fix required.");
|
|
156
158
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { describe, test, expect } from "vitest";
|
|
1
|
+
import { describe, test, expect, beforeAll } from "vitest";
|
|
2
|
+
import { resolveAuditCatalog, type RuleMeta } from "./catalog";
|
|
2
3
|
import { renderHtml, type AuditSnapshot } from "./report-html";
|
|
3
4
|
import type { AuditFinding } from "./core";
|
|
4
5
|
|
|
@@ -29,9 +30,15 @@ const SNAPSHOT: AuditSnapshot = {
|
|
|
29
30
|
toolVersion: "0.4.0",
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
|
|
34
|
+
let CATALOG: Record<string, RuleMeta>;
|
|
35
|
+
beforeAll(async () => { CATALOG = await resolveAuditCatalog(["github", "gitlab"]); });
|
|
36
|
+
/** renderHtml with the migrated github/gitlab catalog injected (#687). */
|
|
37
|
+
const html2 = (findings: AuditFinding[], opts: Parameters<typeof renderHtml>[1] = {}) => renderHtml(findings, { ...opts, catalog: CATALOG });
|
|
38
|
+
|
|
32
39
|
describe("renderHtml", () => {
|
|
33
40
|
test("produces a self-contained HTML document with sections and snapshot", () => {
|
|
34
|
-
const html =
|
|
41
|
+
const html = html2(FINDINGS, { files: [{ path: ".github/workflows/ci.yml", content: CI }], snapshot: SNAPSHOT });
|
|
35
42
|
expect(html.startsWith("<!doctype html>")).toBe(true);
|
|
36
43
|
expect(html).toContain("<style>"); // inline CSS, self-contained
|
|
37
44
|
expect(html).toContain("owner/repo");
|
|
@@ -43,7 +50,7 @@ describe("renderHtml", () => {
|
|
|
43
50
|
});
|
|
44
51
|
|
|
45
52
|
test("embeds the machine-readable JSON report (parseable, escaped)", () => {
|
|
46
|
-
const html =
|
|
53
|
+
const html = html2(FINDINGS, { snapshot: SNAPSHOT });
|
|
47
54
|
const m = html.match(/<script type="application\/json" id="chant-audit-report">(.*?)<\/script>/s);
|
|
48
55
|
expect(m).not.toBeNull();
|
|
49
56
|
// No raw "<" can break out of the script element.
|
|
@@ -58,25 +65,25 @@ describe("renderHtml", () => {
|
|
|
58
65
|
const evil: AuditFinding[] = [
|
|
59
66
|
{ checkId: "GHA036", severity: "error", message: "<script>alert(1)</script>", file: "a.yml", lexicon: "github" },
|
|
60
67
|
];
|
|
61
|
-
const html =
|
|
68
|
+
const html = html2(evil);
|
|
62
69
|
expect(html).not.toContain("<script>alert(1)</script>");
|
|
63
70
|
expect(html).toContain("<script>");
|
|
64
71
|
});
|
|
65
72
|
|
|
66
73
|
test("applies theme knobs (title, accent)", () => {
|
|
67
|
-
const html =
|
|
74
|
+
const html = html2(FINDINGS, { theme: { title: "Acme Security", accent: "#ff0000" } });
|
|
68
75
|
expect(html).toContain("<title>Acme Security</title>");
|
|
69
76
|
expect(html).toContain("#ff0000");
|
|
70
77
|
});
|
|
71
78
|
|
|
72
79
|
test("honours a full template override", () => {
|
|
73
|
-
const html =
|
|
80
|
+
const html = html2(FINDINGS, { template: "<html>{{title}}::{{body}}</html>", theme: { title: "X" } });
|
|
74
81
|
expect(html.startsWith("<html>X::")).toBe(true);
|
|
75
82
|
expect(html).toContain("Quick wins"); // body still rendered
|
|
76
83
|
});
|
|
77
84
|
|
|
78
85
|
test("clean report when no findings", () => {
|
|
79
|
-
const html =
|
|
86
|
+
const html = html2([]);
|
|
80
87
|
expect(html).toContain("No issues found.");
|
|
81
88
|
expect(html).not.toContain("Quick wins");
|
|
82
89
|
});
|
|
@@ -112,9 +112,9 @@ export interface AuditReportJson {
|
|
|
112
112
|
findings: SerializedFinding[];
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
export function metaFor(id: string): RuleMeta {
|
|
115
|
+
export function metaFor(id: string, catalog: Record<string, RuleMeta> = RULE_CATALOG): RuleMeta {
|
|
116
116
|
return (
|
|
117
|
-
|
|
117
|
+
catalog[id] ?? {
|
|
118
118
|
id,
|
|
119
119
|
tier: "report-only" as Tier,
|
|
120
120
|
fixKind: "guidance",
|
|
@@ -146,7 +146,12 @@ function clusterName(m: RuleMeta): string {
|
|
|
146
146
|
return m.authority?.[0]?.name ?? "General hardening";
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
function buildQuickWins(
|
|
149
|
+
function buildQuickWins(
|
|
150
|
+
findings: EnrichedFinding[],
|
|
151
|
+
contents: Map<string, string>,
|
|
152
|
+
proveOpts: ProveOptions,
|
|
153
|
+
catalog: Record<string, RuleMeta> = RULE_CATALOG,
|
|
154
|
+
): QuickWinFile[] {
|
|
150
155
|
const out: QuickWinFile[] = [];
|
|
151
156
|
for (const [file, group] of byFile(findings)) {
|
|
152
157
|
const ids = [...new Set(group.map((f) => f.checkId))].sort();
|
|
@@ -157,10 +162,10 @@ function buildQuickWins(findings: EnrichedFinding[], contents: Map<string, strin
|
|
|
157
162
|
|
|
158
163
|
if (original !== undefined) {
|
|
159
164
|
for (const id of ids) {
|
|
160
|
-
const res = proveFix(id, patched ?? original, proveOpts);
|
|
165
|
+
const res = proveFix(id, patched ?? original, { ...proveOpts, catalog });
|
|
161
166
|
if (res.applied && res.patched !== undefined) {
|
|
162
167
|
patched = res.patched;
|
|
163
|
-
addressed.push(metaFor(id));
|
|
168
|
+
addressed.push(metaFor(id, catalog));
|
|
164
169
|
} else if (res.reason === "needs-input") {
|
|
165
170
|
needsInput.push(...group.filter((f) => f.checkId === id));
|
|
166
171
|
}
|
|
@@ -215,11 +220,14 @@ export interface BuildModelOptions {
|
|
|
215
220
|
files?: Array<{ path: string; content: string }>;
|
|
216
221
|
resolveSha?: ProveOptions["resolveSha"];
|
|
217
222
|
resolveDigest?: ProveOptions["resolveDigest"];
|
|
223
|
+
/** The resolved audit catalog (core static + active lexicons' contributions, #687). Defaults to core's static `RULE_CATALOG`. */
|
|
224
|
+
catalog?: Record<string, RuleMeta>;
|
|
218
225
|
}
|
|
219
226
|
|
|
220
227
|
/** Build the structured report model from raw findings. */
|
|
221
228
|
export function buildReportModel(findings: AuditFinding[], opts: BuildModelOptions = {}): ReportModel {
|
|
222
|
-
const
|
|
229
|
+
const catalog = opts.catalog ?? RULE_CATALOG;
|
|
230
|
+
const enriched: EnrichedFinding[] = findings.map((f) => ({ ...f, meta: metaFor(f.checkId, catalog) }));
|
|
223
231
|
const contents = new Map((opts.files ?? []).map((f) => [f.path, f.content]));
|
|
224
232
|
|
|
225
233
|
const mergeWorthy = enriched.filter((f) => f.meta.tier === "merge-worthy");
|
|
@@ -252,7 +260,7 @@ export function buildReportModel(findings: AuditFinding[], opts: BuildModelOptio
|
|
|
252
260
|
|
|
253
261
|
return {
|
|
254
262
|
counts,
|
|
255
|
-
quickWins: buildQuickWins(quickWinFindings, contents, { resolveSha: opts.resolveSha, resolveDigest: opts.resolveDigest }),
|
|
263
|
+
quickWins: buildQuickWins(quickWinFindings, contents, { resolveSha: opts.resolveSha, resolveDigest: opts.resolveDigest }, catalog),
|
|
256
264
|
needsReview: buildClusters(needsReviewFindings),
|
|
257
265
|
reportOnly: [...reportOnly].sort(sortFindings),
|
|
258
266
|
findings: [...shown].sort(sortFindings),
|
|
@@ -260,8 +268,11 @@ export function buildReportModel(findings: AuditFinding[], opts: BuildModelOptio
|
|
|
260
268
|
}
|
|
261
269
|
|
|
262
270
|
/** Build the versioned, machine-readable JSON report (stable contract). */
|
|
263
|
-
export function buildReportJson(
|
|
264
|
-
|
|
271
|
+
export function buildReportJson(
|
|
272
|
+
findings: AuditFinding[],
|
|
273
|
+
opts: { snapshot?: AuditSnapshot; toolVersion?: string; catalog?: Record<string, RuleMeta> } = {},
|
|
274
|
+
): AuditReportJson {
|
|
275
|
+
const model = buildReportModel(findings, { catalog: opts.catalog });
|
|
265
276
|
const version = opts.toolVersion ?? opts.snapshot?.toolVersion ?? "0.0.0";
|
|
266
277
|
return {
|
|
267
278
|
schemaVersion: REPORT_SCHEMA_VERSION,
|
package/src/audit/report.test.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { describe, test, expect } from "vitest";
|
|
2
|
-
import {
|
|
1
|
+
import { describe, test, expect, beforeAll } from "vitest";
|
|
2
|
+
import { resolveAuditCatalog, type RuleMeta } from "./catalog";
|
|
3
|
+
import { renderMarkdown, type RenderOptions } from "./report";
|
|
3
4
|
import type { AuditFinding } from "./core";
|
|
4
5
|
|
|
5
6
|
const CI = `name: CI
|
|
@@ -21,15 +22,21 @@ const FINDINGS: AuditFinding[] = [
|
|
|
21
22
|
{ checkId: "GHA022", severity: "info", message: "no timeout.", file: ".github/workflows/ci.yml", lexicon: "github" },
|
|
22
23
|
];
|
|
23
24
|
|
|
25
|
+
|
|
26
|
+
let CATALOG: Record<string, RuleMeta>;
|
|
27
|
+
beforeAll(async () => { CATALOG = await resolveAuditCatalog(["github", "gitlab"]); });
|
|
28
|
+
/** renderMarkdown with the migrated github/gitlab catalog injected (#687). */
|
|
29
|
+
const md = (findings: AuditFinding[], opts: RenderOptions = {}) => renderMarkdown(findings, { ...opts, catalog: CATALOG });
|
|
30
|
+
|
|
24
31
|
describe("renderMarkdown — reworked structure", () => {
|
|
25
32
|
test("summary counts by tier and severity", () => {
|
|
26
|
-
const out =
|
|
33
|
+
const out = md(FINDINGS, { target: "owner/repo" });
|
|
27
34
|
expect(out).toContain("Target: owner/repo");
|
|
28
35
|
expect(out).toContain("5 findings — 2 quick-win, 2 needs-review, 1 report-only (1 error, 3 warning, 1 info).");
|
|
29
36
|
});
|
|
30
37
|
|
|
31
38
|
test("quick wins show a real combined diff when file content is provided", () => {
|
|
32
|
-
const out =
|
|
39
|
+
const out = md(FINDINGS, { files: [{ path: ".github/workflows/ci.yml", content: CI }] });
|
|
33
40
|
expect(out).toContain("## Quick wins (deterministic)");
|
|
34
41
|
expect(out).toContain("Addresses [GHA033](https://intentius.io/chant/lint-rules/audit-rules/#gha033) (Blanket write-all permissions)");
|
|
35
42
|
// merge-worthy findings cite their external authority (#351 links surfaced in the layout)
|
|
@@ -41,14 +48,14 @@ describe("renderMarkdown — reworked structure", () => {
|
|
|
41
48
|
});
|
|
42
49
|
|
|
43
50
|
test("pin findings without a SHA resolver are listed, not diffed", () => {
|
|
44
|
-
const out =
|
|
51
|
+
const out = md(FINDINGS, { files: [{ path: ".github/workflows/ci.yml", content: CI }] });
|
|
45
52
|
expect(out).toContain("Needs a value before it can be auto-patched:");
|
|
46
53
|
expect(out).toContain("**[GHA021](https://intentius.io/chant/lint-rules/audit-rules/#gha021)**");
|
|
47
54
|
});
|
|
48
55
|
|
|
49
56
|
test("pin findings are diffed when a SHA resolver is supplied", () => {
|
|
50
57
|
const sha = "11bd71901bbe5b1630ceea73d27597364c9af683";
|
|
51
|
-
const out =
|
|
58
|
+
const out = md(FINDINGS, {
|
|
52
59
|
files: [{ path: ".github/workflows/ci.yml", content: CI }],
|
|
53
60
|
resolveSha: () => sha,
|
|
54
61
|
});
|
|
@@ -62,14 +69,14 @@ describe("renderMarkdown — reworked structure", () => {
|
|
|
62
69
|
{ checkId: "GHA021", severity: "warning", message: "unpinned checkout.", file: ".github/workflows/ci.yml", lexicon: "github", entity: "build" },
|
|
63
70
|
{ checkId: "GHA029", severity: "warning", message: "unpinned acme.", file: ".github/workflows/ci.yml", lexicon: "github", entity: "build" },
|
|
64
71
|
];
|
|
65
|
-
const out =
|
|
72
|
+
const out = md(findings, { files: [{ path: ".github/workflows/ci.yml", content }], resolveSha: () => sha });
|
|
66
73
|
// Both actions pinned in one combined diff; neither listed as "needs a value".
|
|
67
74
|
expect(out).toContain("```diff");
|
|
68
75
|
expect(out).not.toContain("Needs a value before it can be auto-patched");
|
|
69
76
|
});
|
|
70
77
|
|
|
71
78
|
test("guidance findings cluster by authority", () => {
|
|
72
|
-
const out =
|
|
79
|
+
const out = md(FINDINGS);
|
|
73
80
|
expect(out).toContain("<summary>Needs review (guidance)");
|
|
74
81
|
// GHA035 and GHA018 both share the pwn-request authority → one cluster.
|
|
75
82
|
expect(out).toContain("Preventing pwn requests");
|
|
@@ -80,7 +87,7 @@ describe("renderMarkdown — reworked structure", () => {
|
|
|
80
87
|
});
|
|
81
88
|
|
|
82
89
|
test("report-only hygiene goes in a collapsible table", () => {
|
|
83
|
-
const out =
|
|
90
|
+
const out = md(FINDINGS);
|
|
84
91
|
expect(out).toContain("<details>");
|
|
85
92
|
expect(out).toContain("<summary>Report-only (hygiene)");
|
|
86
93
|
expect(out).toContain("| [GHA022](https://intentius.io/chant/lint-rules/audit-rules/#gha022) |");
|
|
@@ -91,7 +98,7 @@ describe("renderMarkdown — reworked structure", () => {
|
|
|
91
98
|
{ checkId: "WGL016", severity: "error", message: "hardcoded secret.", file: ".gitlab-ci.yml", lexicon: "gitlab", entity: "DB_PASSWORD" },
|
|
92
99
|
{ checkId: "WGL021", severity: "warning", message: "unused variable.", file: ".gitlab-ci.yml", lexicon: "gitlab", entity: "DB_PASSWORD" },
|
|
93
100
|
];
|
|
94
|
-
const out =
|
|
101
|
+
const out = md(findings);
|
|
95
102
|
expect(out).toContain("WGL016");
|
|
96
103
|
expect(out).not.toContain("WGL021"); // suppressed — same entity already flagged
|
|
97
104
|
expect(out).toContain("1 finding — ");
|
|
@@ -102,20 +109,36 @@ describe("renderMarkdown — reworked structure", () => {
|
|
|
102
109
|
{ checkId: "GHA021", severity: "warning", message: "unpinned.", file: ".github/workflows/ci.yml", lexicon: "github", entity: "build" },
|
|
103
110
|
{ checkId: "GHA022", severity: "info", message: "no timeout.", file: ".github/workflows/ci.yml", lexicon: "github", entity: "build" },
|
|
104
111
|
];
|
|
105
|
-
const out =
|
|
112
|
+
const out = md(findings);
|
|
106
113
|
expect(out).toContain("GHA022"); // unrelated hygiene on the same job is kept
|
|
107
114
|
});
|
|
108
115
|
|
|
109
116
|
test("clean report when there are no findings", () => {
|
|
110
|
-
const out =
|
|
117
|
+
const out = md([]);
|
|
111
118
|
expect(out).toContain("No issues found.");
|
|
112
119
|
expect(out).not.toContain("Quick wins");
|
|
113
120
|
});
|
|
114
121
|
|
|
115
122
|
test("omits empty sections", () => {
|
|
116
|
-
const onlyGuidance =
|
|
123
|
+
const onlyGuidance = md([FINDINGS[2]]); // GHA035 only
|
|
117
124
|
expect(onlyGuidance).toContain("<summary>Needs review (guidance)");
|
|
118
125
|
expect(onlyGuidance).not.toContain("## Quick wins");
|
|
119
126
|
expect(onlyGuidance).not.toContain("Report-only");
|
|
120
127
|
});
|
|
121
128
|
});
|
|
129
|
+
|
|
130
|
+
describe("catalog threading (#687)", () => {
|
|
131
|
+
test("buildReportModel uses a passed-in catalog over core's static one", async () => {
|
|
132
|
+
const { buildReportModel } = await import("./report-model");
|
|
133
|
+
const findings: AuditFinding[] = [
|
|
134
|
+
{ checkId: "ZZZ999", severity: "warning", message: "made up", file: "x.yml", lexicon: "github" },
|
|
135
|
+
];
|
|
136
|
+
// Not in the static catalog → default model treats it as report-only.
|
|
137
|
+
expect(buildReportModel(findings).counts.quickWin).toBe(0);
|
|
138
|
+
// A resolved catalog (as a lexicon would contribute) makes it a deterministic merge-worthy fix.
|
|
139
|
+
const catalog = {
|
|
140
|
+
ZZZ999: { id: "ZZZ999", tier: "merge-worthy" as const, fixKind: "deterministic" as const, category: "security" as const, title: "Made up", remediation: "fix it", yamlBased: true },
|
|
141
|
+
};
|
|
142
|
+
expect(buildReportModel(findings, { catalog }).counts.quickWin).toBe(1);
|
|
143
|
+
});
|
|
144
|
+
});
|
package/src/audit/report.ts
CHANGED
|
@@ -37,6 +37,8 @@ export interface RenderOptions {
|
|
|
37
37
|
resolveDigest?: ProveOptions["resolveDigest"];
|
|
38
38
|
/** Coverage caveats shown near the top (e.g. unresolved GitLab includes). */
|
|
39
39
|
notes?: string[];
|
|
40
|
+
/** Resolved audit catalog (core static + active lexicons' contributions, #687). Defaults to core's static catalog. */
|
|
41
|
+
catalog?: Record<string, RuleMeta>;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
function escapeCell(s: string): string {
|
|
@@ -2,19 +2,21 @@ import { describe, test, expect } from "vitest";
|
|
|
2
2
|
import { readFileSync } from "fs";
|
|
3
3
|
import { fileURLToPath } from "url";
|
|
4
4
|
import { renderRulesReference } from "./rules-doc";
|
|
5
|
-
import {
|
|
5
|
+
import { resolveAuditCatalog, ruleDocUrl } from "./catalog";
|
|
6
|
+
import { AUDIT_LEXICONS } from "./discover";
|
|
6
7
|
|
|
7
8
|
const PAGE = fileURLToPath(new URL("../../../../docs/src/content/docs/lint-rules/audit-rules.mdx", import.meta.url));
|
|
8
9
|
|
|
9
10
|
describe("audit rules reference", () => {
|
|
10
|
-
test("committed page is in sync with the catalog (regenerate if this fails)", () => {
|
|
11
|
+
test("committed page is in sync with the catalog (regenerate if this fails)", async () => {
|
|
11
12
|
const committed = readFileSync(PAGE, "utf-8");
|
|
12
|
-
expect(committed).toBe(renderRulesReference());
|
|
13
|
+
expect(committed).toBe(await renderRulesReference());
|
|
13
14
|
});
|
|
14
15
|
|
|
15
|
-
test("every rule has an anchor reachable from ruleDocUrl", () => {
|
|
16
|
-
const page = renderRulesReference();
|
|
17
|
-
|
|
16
|
+
test("every rule has an anchor reachable from ruleDocUrl", async () => {
|
|
17
|
+
const page = await renderRulesReference();
|
|
18
|
+
const catalog = await resolveAuditCatalog([...AUDIT_LEXICONS]);
|
|
19
|
+
for (const id of Object.keys(catalog)) {
|
|
18
20
|
// `### GHA033` → Starlight slug `#gha033`, which ruleDocUrl targets.
|
|
19
21
|
expect(page).toContain(`### ${id}`);
|
|
20
22
|
expect(ruleDocUrl(id)).toBe(`https://intentius.io/chant/lint-rules/audit-rules/#${id.toLowerCase()}`);
|
package/src/audit/rules-doc.ts
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
* (lowercased) — the anchor `ruleDocUrl()` links to.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { resolveAuditCatalog, type RuleMeta } from "./catalog";
|
|
11
|
+
import { AUDIT_LEXICONS } from "./discover";
|
|
11
12
|
|
|
12
13
|
const GROUPS: Array<{ heading: string; prefixes: string[]; blurb: string }> = [
|
|
13
14
|
{ heading: "GitHub Actions (GHA)", prefixes: ["GHA"], blurb: "Also applied to Forgejo workflows, which are GitHub-dialect." },
|
|
@@ -29,11 +30,18 @@ function ruleBlock(m: RuleMeta): string {
|
|
|
29
30
|
return `### ${m.id}\n\n**${m.title}** — ${tags}\n\n${m.remediation}${authority}`;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Render the full audit rules reference page (frontmatter + body). Aggregates
|
|
35
|
+
* the catalog across every audit lexicon (#687) — each provider's rule metadata
|
|
36
|
+
* now lives in its own lexicon and is merged over core's static entries — so the
|
|
37
|
+
* doc lists them all. Async because it loads the lexicon plugins to collect
|
|
38
|
+
* their contributed catalogs; a doc-build step has all lexicons installed.
|
|
39
|
+
*/
|
|
40
|
+
export async function renderRulesReference(): Promise<string> {
|
|
41
|
+
const catalog = await resolveAuditCatalog([...AUDIT_LEXICONS]);
|
|
42
|
+
const ids = Object.keys(catalog).sort();
|
|
35
43
|
const sections = GROUPS.map(({ heading, prefixes, blurb }) => {
|
|
36
|
-
const blocks = ids.filter((id) => prefixes.some((p) => id.startsWith(p))).map((id) => ruleBlock(
|
|
44
|
+
const blocks = ids.filter((id) => prefixes.some((p) => id.startsWith(p))).map((id) => ruleBlock(catalog[id]));
|
|
37
45
|
if (blocks.length === 0) return "";
|
|
38
46
|
return `## ${heading}\n${blurb ? `\n${blurb}\n` : ""}\n${blocks.join("\n\n")}`;
|
|
39
47
|
}).filter(Boolean);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { existsSync, statSync, writeFileSync } from "fs";
|
|
9
9
|
import { auditFiles, type AuditInput, type AuditFinding, type ChecksProvider } from "../../audit/core";
|
|
10
10
|
import { discoverByDetection, classifyFiles, loadAuditPlugins, AUDIT_LEXICONS } from "../../audit/discover";
|
|
11
|
-
import { RULE_CATALOG } from "../../audit/catalog";
|
|
11
|
+
import { RULE_CATALOG, resolveAuditCatalog, type RuleMeta } from "../../audit/catalog";
|
|
12
12
|
import { renderMarkdown } from "../../audit/report";
|
|
13
13
|
import { renderHtml, type ReportTheme } from "../../audit/report-html";
|
|
14
14
|
import { buildReportJson, type AuditSnapshot } from "../../audit/report-model";
|
|
@@ -88,12 +88,12 @@ function githubToken(env: NodeJS.ProcessEnv = process.env): string | undefined {
|
|
|
88
88
|
return env.GITHUB_TOKEN ?? env.CHANT_AUDIT_GITHUB_TOKEN;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
function isMergeWorthy(f: AuditFinding): boolean {
|
|
92
|
-
return
|
|
91
|
+
function isMergeWorthy(f: AuditFinding, catalog: Record<string, RuleMeta> = RULE_CATALOG): boolean {
|
|
92
|
+
return catalog[f.checkId]?.tier === "merge-worthy";
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
function exitCodeFor(findings: AuditFinding[], failOn: AuditFailOn): number {
|
|
96
|
-
if (failOn === "merge-worthy") return findings.some(isMergeWorthy) ? 1 : 0;
|
|
95
|
+
function exitCodeFor(findings: AuditFinding[], failOn: AuditFailOn, catalog: Record<string, RuleMeta> = RULE_CATALOG): number {
|
|
96
|
+
if (failOn === "merge-worthy") return findings.some((f) => isMergeWorthy(f, catalog)) ? 1 : 0;
|
|
97
97
|
if (failOn === "warning") {
|
|
98
98
|
return findings.some((f) => f.severity === "error" || f.severity === "warning") ? 1 : 0;
|
|
99
99
|
}
|
|
@@ -116,12 +116,12 @@ export function coverageNotes(inputs: AuditInput[]): string[] {
|
|
|
116
116
|
return notes;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
function renderStylish(findings: AuditFinding[], scanned: string[], notes: string[]): string {
|
|
119
|
+
function renderStylish(findings: AuditFinding[], scanned: string[], notes: string[], catalog: Record<string, RuleMeta> = RULE_CATALOG): string {
|
|
120
120
|
const lines: string[] = [];
|
|
121
121
|
for (const note of notes) lines.push(`Note: ${note}`);
|
|
122
122
|
if (notes.length > 0) lines.push("");
|
|
123
|
-
const mw = findings.filter(isMergeWorthy);
|
|
124
|
-
const ro = findings.filter((f) => !isMergeWorthy(f));
|
|
123
|
+
const mw = findings.filter((f) => isMergeWorthy(f, catalog));
|
|
124
|
+
const ro = findings.filter((f) => !isMergeWorthy(f, catalog));
|
|
125
125
|
lines.push(
|
|
126
126
|
`Audited ${scanned.length} file${scanned.length === 1 ? "" : "s"} — ` +
|
|
127
127
|
`${findings.length} finding${findings.length === 1 ? "" : "s"} ` +
|
|
@@ -132,7 +132,7 @@ function renderStylish(findings: AuditFinding[], scanned: string[], notes: strin
|
|
|
132
132
|
lines.push("", title);
|
|
133
133
|
for (const f of list) {
|
|
134
134
|
const where = f.entity ? `${f.file} (${f.entity})` : f.file;
|
|
135
|
-
const title =
|
|
135
|
+
const title = catalog[f.checkId]?.title ?? f.checkId;
|
|
136
136
|
lines.push(` [${f.checkId}] ${f.severity} ${where} — ${title}`);
|
|
137
137
|
}
|
|
138
138
|
};
|
|
@@ -141,10 +141,10 @@ function renderStylish(findings: AuditFinding[], scanned: string[], notes: strin
|
|
|
141
141
|
return lines.join("\n");
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
function renderSarif(findings: AuditFinding[]): string {
|
|
144
|
+
function renderSarif(findings: AuditFinding[], catalog: Record<string, RuleMeta> = RULE_CATALOG): string {
|
|
145
145
|
const ruleIds = [...new Set(findings.map((f) => f.checkId))].sort();
|
|
146
146
|
const rules = ruleIds.map((id) => {
|
|
147
|
-
const m =
|
|
147
|
+
const m = catalog[id];
|
|
148
148
|
return {
|
|
149
149
|
id,
|
|
150
150
|
name: m?.title ?? id,
|
|
@@ -255,7 +255,12 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
|
|
|
255
255
|
const msg = err instanceof Error ? err.message : String(err);
|
|
256
256
|
return { success: false, output: "", findings: [], scanned, exitCode: 1, error: msg };
|
|
257
257
|
}
|
|
258
|
-
|
|
258
|
+
// Resolve the audit catalog once, aggregating the audited lexicons' own
|
|
259
|
+
// metadata over core's static catalog (#687). The lexicons are already loaded
|
|
260
|
+
// by `auditFiles` above, so this is cheap.
|
|
261
|
+
const catalog = await resolveAuditCatalog([...new Set(inputs.map((i) => i.lexicon))]);
|
|
262
|
+
|
|
263
|
+
if (tier === "merge-worthy") findings = findings.filter((f) => isMergeWorthy(f, catalog));
|
|
259
264
|
const notes = coverageNotes(inputs);
|
|
260
265
|
|
|
261
266
|
// Diff-bearing renderers (markdown, html) need action SHAs / image digests
|
|
@@ -299,25 +304,25 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
|
|
|
299
304
|
switch (format) {
|
|
300
305
|
case "json": {
|
|
301
306
|
const snapshot = await buildSnapshot(options, scanned, isUrl);
|
|
302
|
-
output = JSON.stringify(buildReportJson(findings, { snapshot, toolVersion: options.toolVersion }), null, 2);
|
|
307
|
+
output = JSON.stringify(buildReportJson(findings, { snapshot, toolVersion: options.toolVersion, catalog }), null, 2);
|
|
303
308
|
break;
|
|
304
309
|
}
|
|
305
310
|
case "sarif":
|
|
306
|
-
output = renderSarif(findings);
|
|
311
|
+
output = renderSarif(findings, catalog);
|
|
307
312
|
break;
|
|
308
313
|
case "markdown":
|
|
309
|
-
output = renderMarkdown(findings, { target: options.path, files, resolveSha, resolveDigest, notes });
|
|
314
|
+
output = renderMarkdown(findings, { target: options.path, files, resolveSha, resolveDigest, notes, catalog });
|
|
310
315
|
break;
|
|
311
316
|
case "html": {
|
|
312
317
|
const snapshot = await buildSnapshot(options, scanned, isUrl);
|
|
313
|
-
output = renderHtml(findings, { files, resolveSha, resolveDigest, notes, snapshot, theme: options.theme, template: options.template });
|
|
318
|
+
output = renderHtml(findings, { files, resolveSha, resolveDigest, notes, snapshot, theme: options.theme, template: options.template, catalog });
|
|
314
319
|
break;
|
|
315
320
|
}
|
|
316
321
|
default:
|
|
317
|
-
output = renderStylish(findings, scanned, notes);
|
|
322
|
+
output = renderStylish(findings, scanned, notes, catalog);
|
|
318
323
|
}
|
|
319
324
|
|
|
320
|
-
const exitCode = exitCodeFor(findings, failOn);
|
|
325
|
+
const exitCode = exitCodeFor(findings, failOn, catalog);
|
|
321
326
|
if (options.output) {
|
|
322
327
|
try {
|
|
323
328
|
writeFileSync(options.output, output);
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant lint` end-to-end integration for the COMP* composition checks
|
|
3
|
+
* (#562, epic #551) — confirms `lintCommand` itself (not just
|
|
4
|
+
* `runComponentChecks` in isolation, see
|
|
5
|
+
* ../../lint/rules/comp/comp.test.ts) merges COMP* diagnostics into its
|
|
6
|
+
* output, gates the build at error severity the same way COR/EVL rules do,
|
|
7
|
+
* honors config severity overrides (including "off"), and honors the
|
|
8
|
+
* file-level `chant-disable` directive form.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { describe, test, expect, beforeEach, afterEach } from "vitest";
|
|
12
|
+
import { lintCommand, type LintOptions } from "./lint";
|
|
13
|
+
import { mkdir, rm, writeFile } from "node:fs/promises";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { tmpdir } from "node:os";
|
|
16
|
+
|
|
17
|
+
const COMPONENT_MODULE_SPECIFIER = JSON.stringify(
|
|
18
|
+
new URL("../../components/component.ts", import.meta.url).pathname,
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
function componentSource(body: string): string {
|
|
22
|
+
return `import type { Component } from ${COMPONENT_MODULE_SPECIFIER};\nimport { phase } from ${COMPONENT_MODULE_SPECIFIER};\n\n${body}\n`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
describe("chant lint: COMP* composition checks (#562)", () => {
|
|
26
|
+
let testDir: string;
|
|
27
|
+
|
|
28
|
+
beforeEach(async () => {
|
|
29
|
+
testDir = join(tmpdir(), `chant-comp-lint-test-${Date.now()}-${Math.random()}`);
|
|
30
|
+
await mkdir(testDir, { recursive: true });
|
|
31
|
+
process.env.NO_COLOR = "1";
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(async () => {
|
|
35
|
+
await rm(testDir, { recursive: true, force: true });
|
|
36
|
+
delete process.env.NO_COLOR;
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("a clean component (no *.component.ts issues) lints with no COMP diagnostics", async () => {
|
|
40
|
+
await writeFile(
|
|
41
|
+
join(testDir, "orders-table.component.ts"),
|
|
42
|
+
componentSource(
|
|
43
|
+
`export const ordersTable: Component = {\n` +
|
|
44
|
+
` name: "orders-table",\n` +
|
|
45
|
+
` archetype: "infra",\n` +
|
|
46
|
+
` dependsOn: [],\n` +
|
|
47
|
+
` deploy: [phase("Apply", [{ kind: "cfn-deploy", template: "archive:orders-table.template.json" }])],\n` +
|
|
48
|
+
`};\n`,
|
|
49
|
+
),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
53
|
+
expect(result.diagnostics.filter((d) => d.ruleId.startsWith("COMP"))).toHaveLength(0);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("a raw shell step with no reason fails the lint at error severity (COMP006), gating the build like a COR* error", async () => {
|
|
57
|
+
await writeFile(
|
|
58
|
+
join(testDir, "legacy.component.ts"),
|
|
59
|
+
componentSource(
|
|
60
|
+
`export const legacyTool: Component = {\n` +
|
|
61
|
+
` name: "legacy-tool",\n` +
|
|
62
|
+
` archetype: "infra",\n` +
|
|
63
|
+
` dependsOn: [],\n` +
|
|
64
|
+
` deploy: [phase("Apply", [{ kind: "shell", cmd: "./deploy.sh" }])],\n` +
|
|
65
|
+
`};\n`,
|
|
66
|
+
),
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
70
|
+
expect(result.success).toBe(false);
|
|
71
|
+
const hit = result.diagnostics.find((d) => d.ruleId === "COMP006");
|
|
72
|
+
expect(hit).toBeDefined();
|
|
73
|
+
expect(hit!.severity).toBe("error");
|
|
74
|
+
expect(result.errorCount).toBeGreaterThan(0);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test("a chant-disable COMP006 file-level directive suppresses the diagnostic", async () => {
|
|
78
|
+
await writeFile(
|
|
79
|
+
join(testDir, "legacy.component.ts"),
|
|
80
|
+
`// chant-disable COMP006 -- vendor CLI, tracked in TICKET-123\n` +
|
|
81
|
+
componentSource(
|
|
82
|
+
`export const legacyTool: Component = {\n` +
|
|
83
|
+
` name: "legacy-tool",\n` +
|
|
84
|
+
` archetype: "infra",\n` +
|
|
85
|
+
` dependsOn: [],\n` +
|
|
86
|
+
` deploy: [phase("Apply", [{ kind: "shell", cmd: "./deploy.sh" }])],\n` +
|
|
87
|
+
`};\n`,
|
|
88
|
+
),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
92
|
+
expect(result.diagnostics.some((d) => d.ruleId === "COMP006")).toBe(false);
|
|
93
|
+
expect(result.success).toBe(true);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("a bare chant-disable (no rule ids) suppresses every COMP diagnostic for that file", async () => {
|
|
97
|
+
await writeFile(
|
|
98
|
+
join(testDir, "legacy.component.ts"),
|
|
99
|
+
`// chant-disable\n` +
|
|
100
|
+
componentSource(
|
|
101
|
+
`export const legacyTool: Component = {\n` +
|
|
102
|
+
` name: "legacy-tool",\n` +
|
|
103
|
+
` archetype: "infra",\n` +
|
|
104
|
+
` dependsOn: [],\n` +
|
|
105
|
+
` deploy: [phase("Apply", [{ kind: "shell", cmd: "./deploy.sh" }])],\n` +
|
|
106
|
+
`};\n`,
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
111
|
+
expect(result.diagnostics.filter((d) => d.ruleId.startsWith("COMP"))).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("chant.config.ts can turn a COMP rule off entirely", async () => {
|
|
115
|
+
await writeFile(
|
|
116
|
+
join(testDir, "legacy.component.ts"),
|
|
117
|
+
componentSource(
|
|
118
|
+
`export const legacyTool: Component = {\n` +
|
|
119
|
+
` name: "legacy-tool",\n` +
|
|
120
|
+
` archetype: "infra",\n` +
|
|
121
|
+
` dependsOn: [],\n` +
|
|
122
|
+
` deploy: [phase("Apply", [{ kind: "shell", cmd: "./deploy.sh" }])],\n` +
|
|
123
|
+
`};\n`,
|
|
124
|
+
),
|
|
125
|
+
);
|
|
126
|
+
await writeFile(
|
|
127
|
+
join(testDir, "chant.config.json"),
|
|
128
|
+
JSON.stringify({ rules: { COMP006: "off" } }),
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
132
|
+
expect(result.diagnostics.some((d) => d.ruleId === "COMP006")).toBe(false);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("chant.config.ts can downgrade a COMP rule to warning, so it no longer fails the build", async () => {
|
|
136
|
+
await writeFile(
|
|
137
|
+
join(testDir, "legacy.component.ts"),
|
|
138
|
+
componentSource(
|
|
139
|
+
`export const legacyTool: Component = {\n` +
|
|
140
|
+
` name: "legacy-tool",\n` +
|
|
141
|
+
` archetype: "infra",\n` +
|
|
142
|
+
` dependsOn: [],\n` +
|
|
143
|
+
` deploy: [phase("Apply", [{ kind: "shell", cmd: "./deploy.sh" }])],\n` +
|
|
144
|
+
`};\n`,
|
|
145
|
+
),
|
|
146
|
+
);
|
|
147
|
+
await writeFile(
|
|
148
|
+
join(testDir, "chant.config.json"),
|
|
149
|
+
JSON.stringify({ rules: { COMP006: "warning" } }),
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
const result = await lintCommand({ path: testDir, format: "stylish" } satisfies LintOptions);
|
|
153
|
+
const hit = result.diagnostics.find((d) => d.ruleId === "COMP006");
|
|
154
|
+
expect(hit).toBeDefined();
|
|
155
|
+
expect(hit!.severity).toBe("warning");
|
|
156
|
+
expect(result.success).toBe(true);
|
|
157
|
+
});
|
|
158
|
+
});
|