@intentius/chant 0.124.31 → 0.124.33
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/bin/chant +7 -2
- package/dist/ci-jobs.d.ts +4 -0
- package/dist/ci-jobs.d.ts.map +1 -1
- package/dist/ci-jobs.js +9 -2
- package/dist/cli/commands/check-lexicon-plugin.d.ts +7 -4
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +10 -7
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.js +18 -12
- package/dist/cli/commands/import.d.ts +10 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/import.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.js +4 -3
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/onboard.js +8 -4
- package/dist/cli/commands/update.d.ts.map +1 -1
- package/dist/cli/commands/update.js +2 -1
- package/dist/cli/dependencies.d.ts +18 -0
- package/dist/cli/dependencies.d.ts.map +1 -0
- package/dist/cli/dependencies.js +120 -0
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +38 -4
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.js +12 -4
- package/dist/cli/handlers/graph.d.ts.map +1 -1
- package/dist/cli/handlers/graph.js +16 -6
- package/dist/cli/handlers/lifecycle-health.d.ts +16 -0
- package/dist/cli/handlers/lifecycle-health.d.ts.map +1 -0
- package/dist/cli/handlers/lifecycle-health.js +150 -0
- package/dist/cli/handlers/lifecycle.d.ts +26 -0
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.js +1 -1
- package/dist/cli/handlers/lint.d.ts.map +1 -1
- package/dist/cli/handlers/lint.js +6 -0
- package/dist/cli/handlers/operator.d.ts +2 -2
- package/dist/cli/handlers/operator.js +3 -3
- package/dist/cli/handlers/pr.d.ts +16 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +610 -32
- package/dist/cli/handlers/promote.d.ts.map +1 -1
- package/dist/cli/handlers/promote.js +19 -2
- package/dist/cli/handlers/release.d.ts +16 -1
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +83 -11
- package/dist/cli/handlers/run.d.ts +13 -1
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/handlers/run.js +38 -15
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +121 -33
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +37 -0
- package/dist/cli/registry.d.ts +29 -6
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +6 -2
- package/dist/codegen/generate-post-synth-barrel.js +2 -2
- package/dist/codegen/lexicon-regen.d.ts +4 -0
- package/dist/codegen/lexicon-regen.d.ts.map +1 -1
- package/dist/codegen/lexicon-regen.js +1 -1
- package/dist/codegen/pinned-upgrade.js +2 -2
- package/dist/components/capability.d.ts +44 -3
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/capability.js +21 -0
- package/dist/components/changed-files.d.ts +7 -1
- package/dist/components/changed-files.d.ts.map +1 -1
- package/dist/components/changed-files.js +9 -1
- package/dist/components/deploy-inputs.d.ts +91 -0
- package/dist/components/deploy-inputs.d.ts.map +1 -0
- package/dist/components/deploy-inputs.js +184 -0
- package/dist/components/driver.d.ts +38 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/driver.js +56 -6
- package/dist/components/fan-out-record.d.ts +6 -1
- package/dist/components/fan-out-record.d.ts.map +1 -1
- package/dist/components/fan-out-record.js +24 -0
- package/dist/components/fan-out-run.d.ts +20 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-run.js +21 -1
- package/dist/components/gate-plan.d.ts +8 -0
- package/dist/components/gate-plan.d.ts.map +1 -1
- package/dist/components/gate-plan.js +6 -0
- package/dist/components/pr-pipeline.d.ts +98 -12
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +146 -23
- package/dist/components/pr-run.d.ts +128 -30
- package/dist/components/pr-run.d.ts.map +1 -1
- package/dist/components/pr-run.js +290 -70
- package/dist/components/release-compile.d.ts +37 -2
- package/dist/components/release-compile.d.ts.map +1 -1
- package/dist/components/release-compile.js +64 -8
- package/dist/components/release-promote.d.ts +17 -3
- package/dist/components/release-promote.d.ts.map +1 -1
- package/dist/components/release-promote.js +79 -18
- package/dist/components/verbs/bom-writer.d.ts +1 -1
- package/dist/components/verbs/bom-writer.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.d.ts +20 -0
- package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/lockfile-sbom-generator.js +41 -4
- package/dist/components/wave-plan.d.ts +15 -2
- package/dist/components/wave-plan.d.ts.map +1 -1
- package/dist/components/wave-plan.js +44 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +16 -6
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.js +6 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.js +8 -2
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/fold/fold.js +68 -1
- package/dist/fold/subset.d.ts +37 -0
- package/dist/fold/subset.d.ts.map +1 -1
- package/dist/fold/subset.js +88 -0
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-detail.js +32 -7
- package/dist/health.d.ts +110 -0
- package/dist/health.d.ts.map +1 -0
- package/dist/health.js +105 -0
- package/dist/health.schema.json +191 -0
- package/dist/lexicon-module.d.ts +10 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +53 -8
- package/dist/lexicon-plugin-helpers.d.ts.map +1 -1
- package/dist/lexicon-plugin-helpers.js +6 -4
- package/dist/lexicon.d.ts +29 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/affected.d.ts.map +1 -1
- package/dist/lifecycle/affected.js +7 -1
- package/dist/lifecycle/merge-record.d.ts +104 -0
- package/dist/lifecycle/merge-record.d.ts.map +1 -0
- package/dist/lifecycle/merge-record.js +102 -0
- package/dist/lifecycle/publish-attachments.d.ts +8 -5
- package/dist/lifecycle/publish-attachments.d.ts.map +1 -1
- package/dist/lifecycle/publish-attachments.js +27 -13
- package/dist/lifecycle/publish-npm.d.ts +3 -2
- package/dist/lifecycle/publish-npm.d.ts.map +1 -1
- package/dist/lifecycle/publish-npm.js +4 -3
- package/dist/lifecycle/release-at.d.ts +40 -0
- package/dist/lifecycle/release-at.d.ts.map +1 -0
- package/dist/lifecycle/release-at.js +83 -0
- package/dist/lifecycle/release-cut.d.ts.map +1 -1
- package/dist/lifecycle/release-cut.js +23 -12
- package/dist/lifecycle/release-ledger.d.ts +21 -0
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.js +24 -0
- package/dist/lifecycle/release-publish.d.ts +28 -12
- package/dist/lifecycle/release-publish.d.ts.map +1 -1
- package/dist/lifecycle/release-publish.js +29 -17
- package/dist/lifecycle/release-store.d.ts +25 -2
- package/dist/lifecycle/release-store.d.ts.map +1 -1
- package/dist/lifecycle/release-store.js +40 -13
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -0
- package/dist/lifecycle/work-dir.d.ts +45 -0
- package/dist/lifecycle/work-dir.d.ts.map +1 -0
- package/dist/lifecycle/work-dir.js +78 -0
- package/dist/lint/discover.d.ts +17 -9
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +62 -54
- package/dist/lint/rules/op/index.d.ts +2 -1
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +4 -2
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts +10 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.d.ts.map +1 -0
- package/dist/lint/rules/op/ops018-shell-image-digest.js +38 -0
- package/dist/module-source.d.ts +57 -0
- package/dist/module-source.d.ts.map +1 -0
- package/dist/module-source.js +104 -0
- package/dist/op/activities/activity-contracts.d.ts +5 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +3 -0
- package/dist/op/activities/factory.js +1 -1
- package/dist/op/activities/shell.d.ts +38 -0
- package/dist/op/activities/shell.d.ts.map +1 -1
- package/dist/op/activities/shell.js +89 -3
- package/dist/op/builders.d.ts +7 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +7 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +13 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +3 -0
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +20 -5
- package/dist/op/operator.d.ts +2 -2
- package/dist/op/operator.js +2 -2
- package/dist/op/runtime.d.ts +2 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/steward.d.ts +6 -4
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/steward.js +5 -3
- package/dist/op/work-lease-run.d.ts +20 -7
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/op/work-lease-run.js +56 -12
- package/dist/pr-forge.d.ts +10 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +39 -0
- package/dist/pr-loop.d.ts +155 -7
- package/dist/pr-loop.d.ts.map +1 -1
- package/dist/pr-loop.js +137 -11
- package/dist/pr-report-url.d.ts +4 -4
- package/dist/pr-report-url.d.ts.map +1 -1
- package/dist/pr-report-url.js +5 -5
- package/dist/runner-start.d.ts +179 -0
- package/dist/runner-start.d.ts.map +1 -0
- package/dist/runner-start.js +277 -0
- package/dist/ts-loader.d.ts +38 -4
- package/dist/ts-loader.d.ts.map +1 -1
- package/dist/ts-loader.js +190 -16
- package/dist/wave-runtime.mjs +238 -231
- package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts +34 -0
- package/dist/workspace/chant-migrations/fountain-retired-kinds.d.ts.map +1 -0
- package/dist/workspace/chant-migrations/fountain-retired-kinds.js +176 -0
- package/dist/workspace/chant-migrations.d.ts.map +1 -1
- package/dist/workspace/chant-migrations.js +2 -0
- package/dist/workspace/check.schema.json +70 -2
- package/dist/workspace/checks/boxes.d.ts +6 -6
- package/dist/workspace/checks/boxes.js +9 -9
- package/dist/workspace/checks/security.d.ts +35 -0
- package/dist/workspace/checks/security.d.ts.map +1 -0
- package/dist/workspace/checks/security.js +305 -0
- package/dist/workspace/checks.d.ts +2 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +5 -0
- package/dist/workspace/ci-builds.d.ts +163 -0
- package/dist/workspace/ci-builds.d.ts.map +1 -0
- package/dist/workspace/ci-builds.js +315 -0
- package/dist/workspace/ci-green-cli.d.ts +2 -1
- package/dist/workspace/ci-green-cli.d.ts.map +1 -1
- package/dist/workspace/ci-green-cli.js +25 -5
- package/dist/workspace/ci-green-forge.d.ts +18 -4
- package/dist/workspace/ci-green-forge.d.ts.map +1 -1
- package/dist/workspace/ci-green-forge.js +12 -0
- package/dist/workspace/ci-green-workflow.d.ts +55 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +128 -1
- package/dist/workspace/ci-green.d.ts +117 -16
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +358 -43
- package/dist/workspace/ci-last-green.schema.json +49 -0
- package/dist/workspace/ci-list.schema.json +47 -7
- package/dist/workspace/ci-report-url.d.ts +18 -0
- package/dist/workspace/ci-report-url.d.ts.map +1 -0
- package/dist/workspace/ci-report-url.js +33 -0
- package/dist/workspace/ci-run-index.d.ts +13 -1
- package/dist/workspace/ci-run-index.d.ts.map +1 -1
- package/dist/workspace/ci-run-index.js +6 -4
- package/dist/workspace/ci-run-index.schema.json +6 -4
- package/dist/workspace/ci-run.d.ts +85 -6
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +262 -64
- package/dist/workspace/ci-runner-key.d.ts +16 -3
- package/dist/workspace/ci-runner-key.d.ts.map +1 -1
- package/dist/workspace/ci-runner-key.js +30 -10
- package/dist/workspace/ci-runner-start.d.ts +77 -0
- package/dist/workspace/ci-runner-start.d.ts.map +1 -0
- package/dist/workspace/ci-runner-start.js +185 -0
- package/dist/workspace/ci-serve.d.ts +130 -11
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +323 -40
- package/dist/workspace/declaration.d.ts +25 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +14 -2
- package/dist/workspace/declaration.schema.json +30 -2
- package/dist/workspace/export.d.ts +1 -1
- package/dist/workspace/export.d.ts.map +1 -1
- package/dist/workspace/export.js +7 -3
- package/dist/workspace/ls.d.ts +8 -1
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +2 -1
- package/dist/workspace/ls.schema.json +9 -2
- package/dist/workspace/member-pipeline.d.ts +1 -0
- package/dist/workspace/member-pipeline.d.ts.map +1 -1
- package/dist/workspace/member-pipeline.js +2 -0
- package/dist/workspace/merge-record.schema.json +49 -0
- package/dist/workspace/pin-integrity.d.ts.map +1 -1
- package/dist/workspace/pin-integrity.js +3 -2
- package/dist/workspace/pr-report.schema.json +75 -8
- package/dist/workspace/reason-codes.d.ts +18 -1
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +20 -2
- package/dist/workspace/release-candidates.d.ts +129 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -0
- package/dist/workspace/release-candidates.js +233 -0
- package/dist/workspace/release-candidates.schema.json +353 -0
- package/dist/workspace/run-event.schema.json +3 -1
- package/dist/workspace/security.d.ts +40 -0
- package/dist/workspace/security.d.ts.map +1 -0
- package/dist/workspace/security.js +99 -0
- package/dist/workspace/status.schema.json +3 -1
- package/dist/workspace/write-scope.d.ts +9 -0
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/workspace/write-scope.js +11 -1
- package/package.json +8 -1
- package/src/__fixtures__/pr-loop/pr-apply-wave-waiting.note.golden.md +48 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +1 -1
- package/src/ci-jobs.ts +11 -2
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +3 -3
- package/src/cli/commands/audit.test.ts +2 -2
- package/src/cli/commands/check-lexicon-plugin.test.ts +9 -0
- package/src/cli/commands/check-lexicon-plugin.ts +11 -8
- package/src/cli/commands/check-lexicon.test.ts +1 -1
- package/src/cli/commands/check-lexicon.ts +16 -11
- package/src/cli/commands/import.ts +40 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +4 -3
- package/src/cli/commands/init-lexicon.test.ts +8 -5
- package/src/cli/commands/onboard.test.ts +45 -0
- package/src/cli/commands/onboard.ts +8 -4
- package/src/cli/commands/update.test.ts +6 -0
- package/src/cli/commands/update.ts +4 -1
- package/src/cli/compiled-cli.e2e.test.ts +76 -11
- package/src/cli/dependencies.e2e.test.ts +101 -0
- package/src/cli/dependencies.test.ts +93 -0
- package/src/cli/dependencies.ts +122 -0
- package/src/cli/handlers/build.test.ts +105 -0
- package/src/cli/handlers/build.ts +35 -4
- package/src/cli/handlers/fan-out.test.ts +73 -0
- package/src/cli/handlers/fan-out.ts +11 -4
- package/src/cli/handlers/graph.test.ts +76 -0
- package/src/cli/handlers/graph.ts +19 -12
- package/src/cli/handlers/lifecycle-health.test.ts +123 -0
- package/src/cli/handlers/lifecycle-health.ts +157 -0
- package/src/cli/handlers/lifecycle.ts +1 -1
- package/src/cli/handlers/lint.test.ts +42 -0
- package/src/cli/handlers/lint.ts +6 -0
- package/src/cli/handlers/operator.ts +3 -3
- package/src/cli/handlers/pr-deploy-inputs.test.ts +209 -0
- package/src/cli/handlers/pr-record.test.ts +201 -0
- package/src/cli/handlers/pr-waves.test.ts +449 -0
- package/src/cli/handlers/pr.test.ts +156 -0
- package/src/cli/handlers/pr.ts +648 -33
- package/src/cli/handlers/promote.test.ts +43 -1
- package/src/cli/handlers/promote.ts +19 -3
- package/src/cli/handlers/release-cut-at.e2e.test.ts +115 -0
- package/src/cli/handlers/release-publish-targets.e2e.test.ts +2 -2
- package/src/cli/handlers/release-verify.e2e.test.ts +12 -10
- package/src/cli/handlers/release.e2e.test.ts +19 -28
- package/src/cli/handlers/release.ts +81 -11
- package/src/cli/handlers/run-components-exit.test.ts +99 -0
- package/src/cli/handlers/run-signer.test.ts +79 -0
- package/src/cli/handlers/run.ts +34 -16
- package/src/cli/main.test.ts +18 -0
- package/src/cli/main.ts +120 -33
- package/src/cli/parse-args.ts +28 -0
- package/src/cli/registry.ts +35 -8
- package/src/codegen/generate-post-synth-barrel.ts +2 -2
- package/src/codegen/lexicon-regen.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -2
- package/src/codegen/post-synth-barrel-guards.test.ts +6 -11
- package/src/components/capability.ts +51 -3
- package/src/components/changed-files.test.ts +16 -1
- package/src/components/changed-files.ts +9 -1
- package/src/components/deploy-inputs.test.ts +108 -0
- package/src/components/deploy-inputs.ts +225 -0
- package/src/components/driver.test.ts +36 -1
- package/src/components/driver.ts +87 -4
- package/src/components/fan-out-record.ts +29 -1
- package/src/components/fan-out-run.test.ts +35 -0
- package/src/components/fan-out-run.ts +40 -1
- package/src/components/gate-plan.ts +9 -0
- package/src/components/pr-pipeline.test.ts +100 -0
- package/src/components/pr-pipeline.ts +184 -28
- package/src/components/pr-run.test.ts +323 -18
- package/src/components/pr-run.ts +355 -76
- package/src/components/release-compile.test.ts +34 -0
- package/src/components/release-compile.ts +89 -8
- package/src/components/release-promote.test.ts +55 -2
- package/src/components/release-promote.ts +93 -23
- package/src/components/verbs/bom-writer.ts +1 -1
- package/src/components/verbs/lockfile-sbom-generator.test.ts +36 -0
- package/src/components/verbs/lockfile-sbom-generator.ts +43 -5
- package/src/components/wave-plan.ts +48 -8
- package/src/discovery/fold-host-method.test.ts +87 -0
- package/src/discovery/fold-import.ts +15 -5
- package/src/discovery/fold-package-composite.test.ts +27 -0
- package/src/discovery/fold-specifiers.test.ts +8 -0
- package/src/discovery/sandbox/bundle.ts +6 -0
- package/src/discovery/specifier-resolve.ts +8 -2
- package/src/fold/fold.test.ts +72 -0
- package/src/fold/fold.ts +71 -0
- package/src/fold/subset.test.ts +31 -0
- package/src/fold/subset.ts +99 -0
- package/src/graph-detail.test.ts +57 -0
- package/src/graph-detail.ts +33 -7
- package/src/health.schema.json +191 -0
- package/src/health.test.ts +62 -0
- package/src/health.ts +178 -0
- package/src/lexicon-dist.e2e.test.ts +254 -0
- package/src/lexicon-module.test.ts +47 -0
- package/src/lexicon-module.ts +49 -7
- package/src/lexicon-plugin-helpers.ts +6 -4
- package/src/lexicon.ts +43 -1
- package/src/lifecycle/affected.test.ts +7 -0
- package/src/lifecycle/affected.ts +6 -1
- package/src/lifecycle/merge-record.test.ts +111 -0
- package/src/lifecycle/merge-record.ts +154 -0
- package/src/lifecycle/publish-attachments.ts +25 -13
- package/src/lifecycle/publish-npm.ts +4 -3
- package/src/lifecycle/publish-targets.test.ts +34 -4
- package/src/lifecycle/release-at.test.ts +48 -0
- package/src/lifecycle/release-at.ts +100 -0
- package/src/lifecycle/release-cut.test.ts +41 -0
- package/src/lifecycle/release-cut.ts +22 -11
- package/src/lifecycle/release-ledger.ts +34 -0
- package/src/lifecycle/release-publish.test.ts +43 -13
- package/src/lifecycle/release-publish.ts +38 -18
- package/src/lifecycle/release-store.ts +57 -13
- package/src/lifecycle/run-ledger.test.ts +13 -0
- package/src/lifecycle/run-ledger.ts +1 -0
- package/src/lifecycle/work-dir.test.ts +77 -0
- package/src/lifecycle/work-dir.ts +82 -0
- package/src/lint/discover.test.ts +46 -2
- package/src/lint/discover.ts +55 -49
- package/src/lint/rules/op/index.ts +4 -2
- package/src/lint/rules/op/ops018-shell-image-digest.test.ts +60 -0
- package/src/lint/rules/op/ops018-shell-image-digest.ts +48 -0
- package/src/module-source.test.ts +85 -0
- package/src/module-source.ts +112 -0
- package/src/op/activities/activity-contracts.ts +3 -0
- package/src/op/activities/factory.ts +1 -1
- package/src/op/activities/shell-container.e2e.test.ts +67 -0
- package/src/op/activities/shell.test.ts +44 -1
- package/src/op/activities/shell.ts +110 -3
- package/src/op/builders.ts +7 -0
- package/src/op/discover-root.test.ts +31 -2
- package/src/op/discover.ts +14 -4
- package/src/op/gate.test.ts +30 -0
- package/src/op/gate.ts +3 -0
- package/src/op/op-waves-run.ts +20 -5
- package/src/op/op-waves.test.ts +49 -0
- package/src/op/operator.ts +2 -2
- package/src/op/runtime.ts +2 -0
- package/src/op/step-console.test.ts +4 -2
- package/src/op/steward.ts +6 -4
- package/src/op/work-lease-run.test.ts +88 -2
- package/src/op/work-lease-run.ts +52 -12
- package/src/pr-forge-bundle.test.ts +2 -2
- package/src/pr-forge.test.ts +42 -0
- package/src/pr-forge.ts +40 -0
- package/src/pr-loop-bundle.test.ts +2 -1
- package/src/pr-loop.test.ts +146 -1
- package/src/pr-loop.ts +278 -17
- package/src/pr-report-url.ts +7 -7
- package/src/runner-start-bundle.test.ts +29 -0
- package/src/runner-start.test.ts +179 -0
- package/src/runner-start.ts +329 -0
- package/src/terraform/__fixtures__/advise.test.ts +21 -2
- package/src/ts-loader.test.ts +89 -1
- package/src/ts-loader.ts +180 -13
- package/src/workspace/changes.test.ts +1 -1
- package/src/workspace/chant-migrations/fountain-retired-kinds.test.ts +33 -0
- package/src/workspace/chant-migrations/fountain-retired-kinds.ts +190 -0
- package/src/workspace/chant-migrations.e2e.test.ts +5 -0
- package/src/workspace/chant-migrations.ts +2 -0
- package/src/workspace/check-contract.test.ts +3 -2
- package/src/workspace/check.schema.json +70 -2
- package/src/workspace/checks/boxes.ts +9 -9
- package/src/workspace/checks/security.test.ts +138 -0
- package/src/workspace/checks/security.ts +305 -0
- package/src/workspace/checks.ts +5 -0
- package/src/workspace/ci-builds.e2e.test.ts +208 -0
- package/src/workspace/ci-builds.test.ts +174 -0
- package/src/workspace/ci-builds.ts +385 -0
- package/src/workspace/ci-green-builds.test.ts +180 -0
- package/src/workspace/ci-green-cli.test.ts +54 -0
- package/src/workspace/ci-green-cli.ts +26 -5
- package/src/workspace/ci-green-forge.ts +30 -4
- package/src/workspace/ci-green-runs.test.ts +53 -11
- package/src/workspace/ci-green-workflow.test.ts +84 -1
- package/src/workspace/ci-green-workflow.ts +139 -2
- package/src/workspace/ci-green.test.ts +6 -3
- package/src/workspace/ci-green.ts +408 -48
- package/src/workspace/ci-last-green.schema.json +49 -0
- package/src/workspace/ci-list.schema.json +47 -7
- package/src/workspace/ci-report-url.test.ts +220 -0
- package/src/workspace/ci-report-url.ts +33 -0
- package/src/workspace/ci-run-index.schema.json +6 -4
- package/src/workspace/ci-run-index.test.ts +42 -3
- package/src/workspace/ci-run-index.ts +19 -5
- package/src/workspace/ci-run.test.ts +203 -8
- package/src/workspace/ci-run.ts +295 -63
- package/src/workspace/ci-runner-key.test.ts +55 -17
- package/src/workspace/ci-runner-key.ts +36 -11
- package/src/workspace/ci-runner-start.test.ts +151 -0
- package/src/workspace/ci-runner-start.ts +193 -0
- package/src/workspace/ci-serve-builds.test.ts +86 -0
- package/src/workspace/ci-serve.test.ts +209 -6
- package/src/workspace/ci-serve.ts +341 -42
- package/src/workspace/declaration.schema.json +30 -2
- package/src/workspace/declaration.test.ts +40 -0
- package/src/workspace/declaration.ts +40 -3
- package/src/workspace/export.ts +6 -3
- package/src/workspace/ls.schema.json +9 -2
- package/src/workspace/ls.ts +10 -4
- package/src/workspace/member-pipeline.ts +2 -1
- package/src/workspace/merge-record.schema.json +49 -0
- package/src/workspace/pin-integrity.test.ts +5 -0
- package/src/workspace/pin-integrity.ts +3 -2
- package/src/workspace/pr-report.schema.json +75 -8
- package/src/workspace/reason-codes.test.ts +2 -0
- package/src/workspace/reason-codes.ts +20 -2
- package/src/workspace/release-candidates.schema.json +353 -0
- package/src/workspace/release-candidates.test.ts +106 -0
- package/src/workspace/release-candidates.ts +315 -0
- package/src/workspace/run-event.schema.json +3 -1
- package/src/workspace/security.test.ts +70 -0
- package/src/workspace/security.ts +118 -0
- package/src/workspace/status.schema.json +3 -1
- package/src/workspace/write-scope.test.ts +29 -1
- package/src/workspace/write-scope.ts +12 -1
|
@@ -15,7 +15,14 @@
|
|
|
15
15
|
* ./promote.ts: a literal path in a deploy step's `template`, `manifest` or
|
|
16
16
|
* `values` field ({@link TEMPLATE_FIELDS}), read after the environment's build
|
|
17
17
|
* command has run. A path with the `archive:` prefix names the file after it.
|
|
18
|
-
*
|
|
18
|
+
*
|
|
19
|
+
* Since #4155 a cut also records the other local paths a deploy step names
|
|
20
|
+
* ({@link recordedInputRefs}: a Helm chart, a kustomize directory, a sync's
|
|
21
|
+
* source tree, the fields `./deploy-inputs.ts` lists). A directory is
|
|
22
|
+
* recorded file by file and named in the target's `trees`; a file that is not
|
|
23
|
+
* UTF-8 is recorded as base64. Such a path that does not exist after the
|
|
24
|
+
* build, as a chart named from a repository, is not recorded, and the
|
|
25
|
+
* promote leaves it as written.
|
|
19
26
|
*
|
|
20
27
|
* A project with no components (#4046) is compiled the way `chant build --env
|
|
21
28
|
* <env> -o <output>` builds it ({@link compileBuildOutput}): every file that
|
|
@@ -24,6 +31,7 @@
|
|
|
24
31
|
* back from disk, so a file an earlier build left behind is never recorded.
|
|
25
32
|
*/
|
|
26
33
|
import { spawn, spawnSync } from "node:child_process";
|
|
34
|
+
import { isUtf8 } from "node:buffer";
|
|
27
35
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
28
36
|
import { isAbsolute, relative, resolve } from "node:path";
|
|
29
37
|
import { loadChantConfig } from "../config.js";
|
|
@@ -36,7 +44,8 @@ import { ARCHIVE_STEP_KINDS, BUILD_STEP_KINDS, PUBLISH_STEP_KINDS } from "./prom
|
|
|
36
44
|
import { DriverRunFailure, runInterpretDriver } from "./driver.js";
|
|
37
45
|
import { memoryGateLedgerPort } from "../op/gate.js";
|
|
38
46
|
/** The deploy step fields whose literal file paths are a component's templates. */
|
|
39
|
-
export
|
|
47
|
+
export { TEMPLATE_FIELDS } from "./deploy-inputs.js";
|
|
48
|
+
import { DEPLOY_INPUT_FIELDS, directoryFiles, ignoredByGit, TEMPLATE_FIELDS, walkFiles } from "./deploy-inputs.js";
|
|
40
49
|
/** The prefix a step may write before an archive-relative template path. */
|
|
41
50
|
const ARCHIVE_PREFIX = "archive:";
|
|
42
51
|
function isGate(step) {
|
|
@@ -79,6 +88,33 @@ export function templateRefs(component) {
|
|
|
79
88
|
}
|
|
80
89
|
return out;
|
|
81
90
|
}
|
|
91
|
+
/** Every literal path a component's deploy names that a cut records: {@link templateRefs}, plus each kind's own fields in `DEPLOY_INPUT_FIELDS`. */
|
|
92
|
+
export function recordedInputRefs(component) {
|
|
93
|
+
const out = [];
|
|
94
|
+
for (const { phase, step } of stepsOf(component.deploy)) {
|
|
95
|
+
if (BUILD_STEP_KINDS.includes(step.kind) || PUBLISH_STEP_KINDS.includes(step.kind))
|
|
96
|
+
continue;
|
|
97
|
+
for (const field of recordedFields(step.kind)) {
|
|
98
|
+
const raw = step[field];
|
|
99
|
+
for (const value of Array.isArray(raw) ? raw : [raw]) {
|
|
100
|
+
if (!isLiteralPath(value))
|
|
101
|
+
continue;
|
|
102
|
+
const path = value.startsWith(ARCHIVE_PREFIX) ? value.slice(ARCHIVE_PREFIX.length) : value;
|
|
103
|
+
out.push({ component: component.name, phase, kind: step.kind, field, value, path, required: TEMPLATE_FIELDS.includes(field) });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
/** The fields of a step of `kind` whose paths a cut records and a promote points at the recorded copy. */
|
|
110
|
+
export function recordedFields(kind) {
|
|
111
|
+
return [...TEMPLATE_FIELDS, ...(DEPLOY_INPUT_FIELDS[kind] ?? [])];
|
|
112
|
+
}
|
|
113
|
+
/** A file's bytes as a template: its text when it is UTF-8, else base64. */
|
|
114
|
+
export function templateOf(component, path, file) {
|
|
115
|
+
const bytes = readFileSync(file);
|
|
116
|
+
return isUtf8(bytes) ? { component, path, content: bytes.toString("utf-8") } : { component, path, content: bytes.toString("base64"), encoding: "base64" };
|
|
117
|
+
}
|
|
82
118
|
/** A component's build-time steps ({@link BUILD_STEP_KINDS}), each as declared, in composition order. */
|
|
83
119
|
export function buildStepsOf(component) {
|
|
84
120
|
return stepsOf(component.deploy).map((s) => s.step).filter((s) => BUILD_STEP_KINDS.includes(s.kind));
|
|
@@ -122,6 +158,8 @@ export function withOnlyArchiveSteps(component) {
|
|
|
122
158
|
const deploy = component.deploy.map(keep).filter((p) => p !== undefined);
|
|
123
159
|
return deploy.length > 0 ? { name: component.name, dependsOn: [], deploy } : undefined;
|
|
124
160
|
}
|
|
161
|
+
/** The variable a cut's label reaches the build through (#4168). */
|
|
162
|
+
export const RELEASE_LABEL_ENV = "CHANT_RELEASE_LABEL";
|
|
125
163
|
/**
|
|
126
164
|
* Where a project with no components writes its build output when the cut
|
|
127
165
|
* names no `-o`. YAML, since the k8s and helm serializers write YAML whatever
|
|
@@ -185,21 +223,33 @@ export async function compileEnvironment(inputs, env) {
|
|
|
185
223
|
return compileBuildOutput(inputs, env, config);
|
|
186
224
|
const rel = (p) => (isAbsolute(p) ? relative(inputs.projectDir, p) : p);
|
|
187
225
|
const templates = [];
|
|
226
|
+
const trees = [];
|
|
188
227
|
const seen = new Set();
|
|
189
228
|
for (const { component } of components) {
|
|
190
|
-
for (const ref of
|
|
229
|
+
for (const ref of recordedInputRefs(component)) {
|
|
191
230
|
const key = `${ref.component}\u0000${ref.path}`;
|
|
192
231
|
if (seen.has(key))
|
|
193
232
|
continue;
|
|
194
233
|
seen.add(key);
|
|
195
234
|
const file = resolve(inputs.projectDir, ref.path);
|
|
196
235
|
if (!existsSync(file)) {
|
|
236
|
+
if (!ref.required)
|
|
237
|
+
continue;
|
|
197
238
|
throw new ReleaseCompileError(`component "${ref.component}": its ${ref.kind} step in phase "${ref.phase}" reads ${ref.field} "${ref.value}", ` +
|
|
198
239
|
`and no such file exists after the build for "${env}"`);
|
|
199
240
|
}
|
|
200
|
-
if (
|
|
241
|
+
if (statSync(file).isFile()) {
|
|
242
|
+
templates.push(templateOf(ref.component, ref.path, file));
|
|
201
243
|
continue;
|
|
202
|
-
|
|
244
|
+
}
|
|
245
|
+
// #4155: a directory, file by file. One git ignores is the build's output, recorded whole.
|
|
246
|
+
const files = ignoredByGit(inputs.projectDir, ref.path) ? walkFiles(inputs.projectDir, ref.path) : directoryFiles(inputs.projectDir, ref.path);
|
|
247
|
+
const dir = ref.path.replace(/\/+$/, "");
|
|
248
|
+
for (const f of files) {
|
|
249
|
+
const under = relative(resolve(inputs.projectDir, dir), resolve(inputs.projectDir, f)).split("\\").join("/");
|
|
250
|
+
templates.push(templateOf(ref.component, `${dir}/${under}`, resolve(inputs.projectDir, f)));
|
|
251
|
+
}
|
|
252
|
+
trees.push({ component: ref.component, path: dir });
|
|
203
253
|
}
|
|
204
254
|
}
|
|
205
255
|
return {
|
|
@@ -211,6 +261,7 @@ export async function compileEnvironment(inputs, env) {
|
|
|
211
261
|
buildInputs: Object.fromEntries(components.map(({ component }) => [component.name, buildInputPaths(component)])),
|
|
212
262
|
componentFiles: Object.fromEntries(components.map(({ component, file }) => [component.name, rel(file)])),
|
|
213
263
|
templates,
|
|
264
|
+
trees,
|
|
214
265
|
};
|
|
215
266
|
}
|
|
216
267
|
/**
|
|
@@ -325,10 +376,15 @@ export function ownChantCommand() {
|
|
|
325
376
|
const main = process.argv[1] ?? "";
|
|
326
377
|
return [process.execPath, ...process.execArgv, main];
|
|
327
378
|
}
|
|
328
|
-
function runChild(command, args, cwd, env) {
|
|
379
|
+
function runChild(command, args, cwd, env, releaseLabel) {
|
|
329
380
|
return new Promise((resolvePromise, reject) => {
|
|
330
381
|
const [bin, ...lead] = command;
|
|
331
|
-
const
|
|
382
|
+
const childEnv = { ...process.env, CHANT_ENV: env };
|
|
383
|
+
// A label never leaks in from the caller's shell: only the cut sets it.
|
|
384
|
+
delete childEnv[RELEASE_LABEL_ENV];
|
|
385
|
+
if (releaseLabel !== undefined)
|
|
386
|
+
childEnv[RELEASE_LABEL_ENV] = releaseLabel;
|
|
387
|
+
const child = spawn(bin, [...lead, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"], env: childEnv });
|
|
332
388
|
const out = [];
|
|
333
389
|
const err = [];
|
|
334
390
|
child.stdout.on("data", (c) => out.push(c));
|
|
@@ -361,7 +417,7 @@ export function spawnTargetCompiler(inputs, command = ownChantCommand()) {
|
|
|
361
417
|
return args;
|
|
362
418
|
};
|
|
363
419
|
const call = async (env, extra) => {
|
|
364
|
-
const run = await runChild(command, ["release", "compile", "--env", env, ...common(), ...extra, "--json"], inputs.projectDir, env);
|
|
420
|
+
const run = await runChild(command, ["release", "compile", "--env", env, ...common(), ...extra, "--json"], inputs.projectDir, env, inputs.releaseLabel);
|
|
365
421
|
if (run.code !== 0)
|
|
366
422
|
throw new ReleaseCompileError(`compiling "${env}" failed (exit ${run.code})`);
|
|
367
423
|
try {
|
|
@@ -11,9 +11,19 @@
|
|
|
11
11
|
* under `.chant/release-templates/<digest>/` in the member's directory and the
|
|
12
12
|
* step reads them from there. The path is relative and fixed by the digest,
|
|
13
13
|
* so a gate approval bound to the promote's plan still matches on a re-run.
|
|
14
|
+
*
|
|
15
|
+
* A release cut since #4155 (a target with `trees`) records every local path
|
|
16
|
+
* a deploy step names (`recordedInputRefs`), directories file by file. A
|
|
17
|
+
* promote points each of them at the recorded copy: a directory is written
|
|
18
|
+
* under `.chant/release-templates/<digest>/<name>/`, its digest taken over its
|
|
19
|
+
* files the way a gate's directory digest is (`./deploy-inputs.ts`). A path
|
|
20
|
+
* outside the template fields that the release does not record, such as a
|
|
21
|
+
* chart named from a repository, is left as written. A target cut before
|
|
22
|
+
* #4155 is pinned as it was then: template fields only, other paths read from
|
|
23
|
+
* the checkout.
|
|
14
24
|
*/
|
|
15
25
|
import type { DriverComponent } from "./driver.js";
|
|
16
|
-
import type
|
|
26
|
+
import { type Release, type ReleaseTarget } from "../lifecycle/release-store.js";
|
|
17
27
|
import type { ReleaseRecord } from "../lifecycle/release-ledger.js";
|
|
18
28
|
import type { BuildArchiveManifest } from "./verbs/build-archive.js";
|
|
19
29
|
/** Where a promote under a release writes the recorded templates, relative to the member's directory. */
|
|
@@ -22,8 +32,12 @@ export declare const RELEASE_TEMPLATES_DIR = ".chant/release-templates";
|
|
|
22
32
|
export interface PinnedTemplate {
|
|
23
33
|
/** Relative to the member's directory. */
|
|
24
34
|
path: string;
|
|
35
|
+
/** The text, or the base64 of the bytes under `encoding: "base64"`. */
|
|
25
36
|
content: string;
|
|
37
|
+
encoding?: "base64";
|
|
26
38
|
}
|
|
39
|
+
/** Reads a recorded template's stored copy by digest: its text, or its base64 under `base64`. */
|
|
40
|
+
export type TemplateReader = (digest: string, encoding?: "base64") => Promise<string | null>;
|
|
27
41
|
/** The release's target for `env`, or an error naming the environments it has. */
|
|
28
42
|
export declare function targetFor(release: Release, env: string): {
|
|
29
43
|
target: ReleaseTarget;
|
|
@@ -38,7 +52,7 @@ export declare function isImplicitRelease(release: Release): boolean;
|
|
|
38
52
|
* the promote is refused: a template the target does not record, one whose
|
|
39
53
|
* bytes are missing, or one whose bytes do not hash to the target's digest.
|
|
40
54
|
*/
|
|
41
|
-
export declare function pinReleaseTemplates(components: readonly DriverComponent[], release: Release, target: ReleaseTarget, readTemplate:
|
|
55
|
+
export declare function pinReleaseTemplates(components: readonly DriverComponent[], release: Release, target: ReleaseTarget, readTemplate: TemplateReader): Promise<{
|
|
42
56
|
components: DriverComponent[];
|
|
43
57
|
files: PinnedTemplate[];
|
|
44
58
|
} | {
|
|
@@ -53,7 +67,7 @@ export declare function pinReleaseTemplates(components: readonly DriverComponent
|
|
|
53
67
|
* member's directory; a template whose bytes are missing or don't hash to the
|
|
54
68
|
* target's digest is refused, as {@link pinReleaseTemplates} refuses one.
|
|
55
69
|
*/
|
|
56
|
-
export declare function targetFiles(release: Release, target: ReleaseTarget, readTemplate:
|
|
70
|
+
export declare function targetFiles(release: Release, target: ReleaseTarget, readTemplate: TemplateReader): Promise<{
|
|
57
71
|
files: PinnedTemplate[];
|
|
58
72
|
} | {
|
|
59
73
|
errors: string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"release-promote.d.ts","sourceRoot":"","sources":["../../src/components/release-promote.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"release-promote.d.ts","sourceRoot":"","sources":["../../src/components/release-promote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAuC,MAAM,UAAU,CAAC;AAErF,OAAO,EAAuB,KAAK,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEnG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,yGAAyG;AACzG,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,iGAAiG;AACjG,MAAM,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;AAE7F,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAMtG;AAED,sIAAsI;AACtI,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAG3D;AAUD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,SAAS,eAAe,EAAE,EACtC,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,cAAc,GAC3B,OAAO,CAAC;IAAE,UAAU,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAyD5F;AA+CD;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,aAAa,EACrB,YAAY,EAAE,cAAc,GAC3B,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAA;CAAE,GAAG;IAAE,MAAM,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CA2B7D;AAED,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI,CAMxF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,cAAc,EAAE,GAAG,IAAI,CAUzF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,aAAa,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAC,EACpE,YAAY,EAAE,CAAC,cAAc,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAC7E,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnB"}
|
|
@@ -11,11 +11,22 @@
|
|
|
11
11
|
* under `.chant/release-templates/<digest>/` in the member's directory and the
|
|
12
12
|
* step reads them from there. The path is relative and fixed by the digest,
|
|
13
13
|
* so a gate approval bound to the promote's plan still matches on a re-run.
|
|
14
|
+
*
|
|
15
|
+
* A release cut since #4155 (a target with `trees`) records every local path
|
|
16
|
+
* a deploy step names (`recordedInputRefs`), directories file by file. A
|
|
17
|
+
* promote points each of them at the recorded copy: a directory is written
|
|
18
|
+
* under `.chant/release-templates/<digest>/<name>/`, its digest taken over its
|
|
19
|
+
* files the way a gate's directory digest is (`./deploy-inputs.ts`). A path
|
|
20
|
+
* outside the template fields that the release does not record, such as a
|
|
21
|
+
* chart named from a repository, is left as written. A target cut before
|
|
22
|
+
* #4155 is pinned as it was then: template fields only, other paths read from
|
|
23
|
+
* the checkout.
|
|
14
24
|
*/
|
|
15
25
|
import { mkdirSync, readdirSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
16
26
|
import { basename, dirname, join } from "node:path";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
27
|
+
import { recordedFields, recordedInputRefs, TEMPLATE_FIELDS, templateRefs } from "./release-compile.js";
|
|
28
|
+
import { templateBytesDigest } from "../lifecycle/release-store.js";
|
|
29
|
+
import { computePlanDigest } from "../lifecycle/plan-digest.js";
|
|
19
30
|
/** Where a promote under a release writes the recorded templates, relative to the member's directory. */
|
|
20
31
|
export const RELEASE_TEMPLATES_DIR = ".chant/release-templates";
|
|
21
32
|
/** The release's target for `env`, or an error naming the environments it has. */
|
|
@@ -48,29 +59,41 @@ export async function pinReleaseTemplates(components, release, target, readTempl
|
|
|
48
59
|
const errors = [];
|
|
49
60
|
const files = [];
|
|
50
61
|
const out = [];
|
|
62
|
+
// #4155: a target with `trees` records every deploy input; one without was cut before and records template fields only.
|
|
63
|
+
const full = target.trees !== undefined;
|
|
51
64
|
for (const component of components) {
|
|
52
65
|
const replace = new Map();
|
|
53
|
-
|
|
66
|
+
const refs = full ? recordedInputRefs(component) : templateRefs(component).map((r) => ({ ...r, required: true }));
|
|
67
|
+
for (const ref of refs) {
|
|
54
68
|
if (replace.has(ref.value))
|
|
55
69
|
continue;
|
|
70
|
+
const dir = ref.path.replace(/\/+$/, "");
|
|
71
|
+
const tree = full ? target.trees.find((t) => t.component === component.name && t.path === dir) : undefined;
|
|
72
|
+
if (tree) {
|
|
73
|
+
const pinned = await pinTree(component.name, tree.path, target, readTemplate);
|
|
74
|
+
if ("errors" in pinned)
|
|
75
|
+
errors.push(...pinned.errors);
|
|
76
|
+
else {
|
|
77
|
+
files.push(...pinned.files);
|
|
78
|
+
replace.set(ref.value, pinned.path);
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
56
82
|
const recorded = target.templates.find((t) => t.component === component.name && t.path === ref.path);
|
|
57
83
|
if (!recorded) {
|
|
84
|
+
if (!ref.required)
|
|
85
|
+
continue;
|
|
58
86
|
errors.push(`component "${component.name}" reads ${ref.field} "${ref.value}", which release ${release.releaseDigest} does not record for "${target.env}"; ` +
|
|
59
87
|
`this checkout's deploy is not the one the release was compiled from (commit ${release.commit.slice(0, 12)})`);
|
|
60
88
|
continue;
|
|
61
89
|
}
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
errors.push(
|
|
65
|
-
continue;
|
|
66
|
-
}
|
|
67
|
-
const got = contentDigest(content);
|
|
68
|
-
if (got !== recorded.digest) {
|
|
69
|
-
errors.push(`component "${component.name}": template "${ref.path}" hashes to ${got}, but the release's target for "${target.env}" records ${recorded.digest}; refusing to deploy it`);
|
|
90
|
+
const read = await readChecked(component.name, ref.path, recorded, target, readTemplate);
|
|
91
|
+
if ("error" in read) {
|
|
92
|
+
errors.push(read.error);
|
|
70
93
|
continue;
|
|
71
94
|
}
|
|
72
95
|
const path = join(RELEASE_TEMPLATES_DIR, recorded.digest.replace(/:/g, "_"), basename(ref.path));
|
|
73
|
-
files.push({ path, content });
|
|
96
|
+
files.push({ path, content: read.content, ...(recorded.encoding ? { encoding: recorded.encoding } : {}) });
|
|
74
97
|
replace.set(ref.value, path);
|
|
75
98
|
}
|
|
76
99
|
const rewrite = (phase) => ({
|
|
@@ -81,7 +104,7 @@ export async function pinReleaseTemplates(components, release, target, readTempl
|
|
|
81
104
|
if (isGate(step))
|
|
82
105
|
return step;
|
|
83
106
|
const next = { ...step };
|
|
84
|
-
for (const field of TEMPLATE_FIELDS) {
|
|
107
|
+
for (const field of full ? recordedFields(step.kind) : TEMPLATE_FIELDS) {
|
|
85
108
|
const v = next[field];
|
|
86
109
|
if (typeof v === "string" && replace.has(v))
|
|
87
110
|
next[field] = replace.get(v);
|
|
@@ -95,6 +118,42 @@ export async function pinReleaseTemplates(components, release, target, readTempl
|
|
|
95
118
|
}
|
|
96
119
|
return errors.length > 0 ? { errors } : { components: out, files };
|
|
97
120
|
}
|
|
121
|
+
/** One recorded template's stored copy, checked against its digest. */
|
|
122
|
+
async function readChecked(component, path, recorded, target, readTemplate) {
|
|
123
|
+
const who = component === null ? "" : `component "${component}": `;
|
|
124
|
+
const content = await readTemplate(recorded.digest, recorded.encoding);
|
|
125
|
+
if (content === null)
|
|
126
|
+
return { error: `${who}the bytes of template "${path}" (${recorded.digest}) are not on the chant/lifecycle branch; fetch it and try again` };
|
|
127
|
+
const got = templateBytesDigest(content, recorded.encoding);
|
|
128
|
+
if (got !== recorded.digest) {
|
|
129
|
+
return { error: `${who}template "${path}" hashes to ${got}, but the release's target for "${target.env}" records ${recorded.digest}; refusing to deploy it` };
|
|
130
|
+
}
|
|
131
|
+
return { content };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* A recorded directory's files, under `.chant/release-templates/<digest>/<name>/`
|
|
135
|
+
* (#4155). The digest is taken over the files' paths from the directory and
|
|
136
|
+
* their bytes, as a gate's directory digest is, so the path names the tree.
|
|
137
|
+
*/
|
|
138
|
+
async function pinTree(component, dir, target, readTemplate) {
|
|
139
|
+
const prefix = `${dir}/`;
|
|
140
|
+
const entries = target.templates.filter((t) => t.component === component && t.path.startsWith(prefix));
|
|
141
|
+
const errors = [];
|
|
142
|
+
const read = [];
|
|
143
|
+
for (const e of entries) {
|
|
144
|
+
const got = await readChecked(component, e.path, e, target, readTemplate);
|
|
145
|
+
if ("error" in got)
|
|
146
|
+
errors.push(got.error);
|
|
147
|
+
else
|
|
148
|
+
read.push({ rel: e.path.slice(prefix.length), content: got.content, digest: e.digest, ...(e.encoding ? { encoding: e.encoding } : {}) });
|
|
149
|
+
}
|
|
150
|
+
if (errors.length > 0)
|
|
151
|
+
return { errors };
|
|
152
|
+
read.sort((a, b) => (a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0));
|
|
153
|
+
const digest = computePlanDigest("directory", read.map(({ rel, digest }) => ({ path: rel, digest })));
|
|
154
|
+
const path = join(RELEASE_TEMPLATES_DIR, digest.replace(/:/g, "_"), basename(dir));
|
|
155
|
+
return { path, files: read.map((r) => ({ path: join(path, r.rel), content: r.content, ...(r.encoding ? { encoding: r.encoding } : {}) })) };
|
|
156
|
+
}
|
|
98
157
|
/**
|
|
99
158
|
* The files a release's target records, read back by digest and checked, for
|
|
100
159
|
* `chant release export` (#4046). A project with no components has no deploy
|
|
@@ -113,12 +172,12 @@ export async function targetFiles(release, target, readTemplate) {
|
|
|
113
172
|
errors.push(`${who}template "${t.path}" is not a path inside the member's directory; refusing to write it`);
|
|
114
173
|
continue;
|
|
115
174
|
}
|
|
116
|
-
const content = await readTemplate(t.digest);
|
|
175
|
+
const content = await readTemplate(t.digest, t.encoding);
|
|
117
176
|
if (content === null) {
|
|
118
177
|
errors.push(`${who}the bytes of template "${t.path}" (${t.digest}) are not on the chant/lifecycle branch; fetch it and try again`);
|
|
119
178
|
continue;
|
|
120
179
|
}
|
|
121
|
-
const got =
|
|
180
|
+
const got = templateBytesDigest(content, t.encoding);
|
|
122
181
|
if (got !== t.digest) {
|
|
123
182
|
errors.push(`${who}template "${t.path}" hashes to ${got}, but release ${release.releaseDigest} records ${t.digest} for "${target.env}"; refusing to write it`);
|
|
124
183
|
continue;
|
|
@@ -129,7 +188,7 @@ export async function targetFiles(release, target, readTemplate) {
|
|
|
129
188
|
errors.push(`two components record different bytes at "${t.path}" for "${target.env}", so they can't both be written there`);
|
|
130
189
|
continue;
|
|
131
190
|
}
|
|
132
|
-
files.push({ path: t.path, content });
|
|
191
|
+
files.push({ path: t.path, content, ...(t.encoding ? { encoding: t.encoding } : {}) });
|
|
133
192
|
}
|
|
134
193
|
return errors.length > 0 ? { errors } : { files };
|
|
135
194
|
}
|
|
@@ -138,7 +197,7 @@ export function writePinnedTemplates(dir, files) {
|
|
|
138
197
|
for (const f of files) {
|
|
139
198
|
const full = join(dir, f.path);
|
|
140
199
|
mkdirSync(dirname(full), { recursive: true });
|
|
141
|
-
writeFileSync(full, f.content);
|
|
200
|
+
writeFileSync(full, f.encoding === "base64" ? Buffer.from(f.content, "base64") : f.content);
|
|
142
201
|
}
|
|
143
202
|
}
|
|
144
203
|
/**
|
|
@@ -148,8 +207,10 @@ export function writePinnedTemplates(dir, files) {
|
|
|
148
207
|
* again from the release.
|
|
149
208
|
*/
|
|
150
209
|
export function removePinnedTemplates(dir, files) {
|
|
210
|
+
// Each file sits under `.chant/release-templates/<digest>/`, a recorded tree's deeper; that digest directory goes.
|
|
211
|
+
const prefix = RELEASE_TEMPLATES_DIR.split("/").length;
|
|
151
212
|
for (const f of files)
|
|
152
|
-
rmSync(
|
|
213
|
+
rmSync(join(dir, ...f.path.split(/[\\/]/).slice(0, prefix + 1)), { recursive: true, force: true });
|
|
153
214
|
const root = join(dir, RELEASE_TEMPLATES_DIR);
|
|
154
215
|
try {
|
|
155
216
|
if (readdirSync(root).length === 0)
|
|
@@ -68,7 +68,7 @@ export interface BomPackage {
|
|
|
68
68
|
/** Version string, when known. Omitted for resources with no version concept (e.g. a CFN resource). */
|
|
69
69
|
version?: string;
|
|
70
70
|
/** Package manager / ecosystem this entry came from (e.g. "npm", "maven"), surfaced in SPDX's `externalRefs`/CycloneDX's `purl` when derivable. */
|
|
71
|
-
type?: "npm" | "maven" | "config" | "external-reference";
|
|
71
|
+
type?: "npm" | "maven" | "cargo" | "config" | "external-reference";
|
|
72
72
|
/** Package URL (purl), when derivable — e.g. `pkg:npm/left-pad@1.3.0`. */
|
|
73
73
|
purl?: string;
|
|
74
74
|
/** SPDX download location, when known. Defaults to `"NOASSERTION"` per the SPDX spec's requirement that every package declare one. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bom-writer.d.ts","sourceRoot":"","sources":["../../../src/components/verbs/bom-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAIrE;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,2HAA2H;IAC3H,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mJAAmJ;IACnJ,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"bom-writer.d.ts","sourceRoot":"","sources":["../../../src/components/verbs/bom-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AAEH,OAAO,EAAoB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAIrE;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB,2HAA2H;IAC3H,IAAI,EAAE,MAAM,CAAC;IACb,uGAAuG;IACvG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mJAAmJ;IACnJ,IAAI,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,OAAO,GAAG,QAAQ,GAAG,oBAAoB,CAAC;IACnE,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sIAAsI;IACtI,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,0JAA0J;IAC1J,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,iGAAiG;IACjG,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+MAA+M;IAC/M,SAAS,EAAE,MAAM,CAAC;IAClB,4DAA4D;IAC5D,QAAQ,EAAE,UAAU,EAAE,CAAC;CACxB;AAED,oGAAoG;AACpG,MAAM,WAAW,QAAQ;IACvB,yFAAyF;IACzF,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2IAA2I;IAC3I,SAAS,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,gIAAgI;IAChI,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,cAAc,EAAE,CAAC;CACjC;AAyDD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAE,MAAM,IAAuB,GAAG,MAAM,CAyErF;AAsBD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,GAAE,MAAM,IAAuB,GAAG,MAAM,CAgE1F;AAUD,+NAA+N;AAC/N,wBAAgB,QAAQ,CACtB,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,QAAQ,EACf,GAAG,CAAC,EAAE,MAAM,IAAI,GACf;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAG1D"}
|
|
@@ -55,6 +55,26 @@ export declare function parseNpmPackageLock(content: string): BomPackage[];
|
|
|
55
55
|
* inheritance chain.
|
|
56
56
|
*/
|
|
57
57
|
export declare function parsePomXml(content: string): BomPackage[];
|
|
58
|
+
/**
|
|
59
|
+
* Parse a `Cargo.lock` (version 3 or 4) into a flat `BomPackage[]`: one
|
|
60
|
+
* entry per `[[package]]` with a `source`, so the workspace's own crates,
|
|
61
|
+
* which have none, are left out as the npm parser leaves out the root.
|
|
62
|
+
* A dependency is named `name` or `name version` in the lock; only the name
|
|
63
|
+
* is kept. A small line reader, not a TOML parser: the lock is written by
|
|
64
|
+
* cargo in one fixed shape.
|
|
65
|
+
*/
|
|
66
|
+
export declare function parseCargoLock(content: string): BomPackage[];
|
|
67
|
+
/** Each lockfile kind's parser and file name. */
|
|
68
|
+
export declare const LOCKFILE_PARSERS: {
|
|
69
|
+
readonly npm: typeof parseNpmPackageLock;
|
|
70
|
+
readonly maven: typeof parsePomXml;
|
|
71
|
+
readonly cargo: typeof parseCargoLock;
|
|
72
|
+
};
|
|
73
|
+
export declare const LOCKFILE_NAMES: {
|
|
74
|
+
readonly npm: "package-lock.json";
|
|
75
|
+
readonly maven: "pom.xml";
|
|
76
|
+
readonly cargo: "Cargo.lock";
|
|
77
|
+
};
|
|
58
78
|
export interface LockfileSbomGeneratorOptions {
|
|
59
79
|
/** Where generated SBOM documents are written on disk, as a sibling of the scanned path (see `sbomOutputPath`). Default: alongside the scanned manifest, named `sbom.<format>.json`. */
|
|
60
80
|
outDir?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lockfile-sbom-generator.d.ts","sourceRoot":"","sources":["../../../src/components/verbs/lockfile-sbom-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,KAAK,EAMV,aAAa,EACd,MAAM,kBAAkB,CAAC;AAe1B;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAkCjE;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CA8BzD;AAID,MAAM,WAAW,4BAA4B;IAC3C,wLAAwL;IACxL,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAgBD,qIAAqI;AACrI,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,aAAa,CA0CrG;AAED,gMAAgM;AAChM,eAAO,MAAM,qBAAqB,EAAE,aAA6C,CAAC"}
|
|
1
|
+
{"version":3,"file":"lockfile-sbom-generator.d.ts","sourceRoot":"","sources":["../../../src/components/verbs/lockfile-sbom-generator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAIH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,KAAK,EAMV,aAAa,EACd,MAAM,kBAAkB,CAAC;AAe1B;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAkCjE;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CA8BzD;AAID;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAsB5D;AAED,iDAAiD;AACjD,eAAO,MAAM,gBAAgB;aAAK,GAAG;aAAuB,KAAK;aAAe,KAAK;CAA2B,CAAC;AACjH,eAAO,MAAM,cAAc;aAAK,GAAG,EAAE,mBAAmB;aAAE,KAAK,EAAE,SAAS;aAAE,KAAK,EAAE,YAAY;CAAW,CAAC;AAI3G,MAAM,WAAW,4BAA4B;IAC3C,wLAAwL;IACxL,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB;AAgBD,qIAAqI;AACrI,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,aAAa,CA0CrG;AAED,gMAAgM;AAChM,eAAO,MAAM,qBAAqB,EAAE,aAA6C,CAAC"}
|
|
@@ -125,9 +125,46 @@ export function parsePomXml(content) {
|
|
|
125
125
|
}
|
|
126
126
|
return packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
127
127
|
}
|
|
128
|
+
// ── Cargo.lock (Rust, #4168 decision 12) ────────────────────────────────────
|
|
129
|
+
/**
|
|
130
|
+
* Parse a `Cargo.lock` (version 3 or 4) into a flat `BomPackage[]`: one
|
|
131
|
+
* entry per `[[package]]` with a `source`, so the workspace's own crates,
|
|
132
|
+
* which have none, are left out as the npm parser leaves out the root.
|
|
133
|
+
* A dependency is named `name` or `name version` in the lock; only the name
|
|
134
|
+
* is kept. A small line reader, not a TOML parser: the lock is written by
|
|
135
|
+
* cargo in one fixed shape.
|
|
136
|
+
*/
|
|
137
|
+
export function parseCargoLock(content) {
|
|
138
|
+
const seen = new Map();
|
|
139
|
+
const blocks = content.split(/^\[\[package\]\]\s*$/m).slice(1);
|
|
140
|
+
for (const block of blocks) {
|
|
141
|
+
const body = block.split(/^\[/m)[0] ?? "";
|
|
142
|
+
const field = (key) => new RegExp(`^${key}\\s*=\\s*"([^"]*)"`, "m").exec(body)?.[1];
|
|
143
|
+
const name = field("name");
|
|
144
|
+
const version = field("version");
|
|
145
|
+
if (!name || field("source") === undefined)
|
|
146
|
+
continue;
|
|
147
|
+
const deps = /^dependencies\s*=\s*\[([\s\S]*?)\]/m.exec(body)?.[1];
|
|
148
|
+
const dependsOn = deps ? [...deps.matchAll(/"([^"\s]+)[^"]*"/g)].map((m) => m[1]) : [];
|
|
149
|
+
const key = `${name}@${version ?? ""}`;
|
|
150
|
+
if (seen.has(key))
|
|
151
|
+
continue;
|
|
152
|
+
seen.set(key, {
|
|
153
|
+
name,
|
|
154
|
+
version,
|
|
155
|
+
type: "cargo",
|
|
156
|
+
purl: version ? `pkg:cargo/${encodeURIComponent(name)}@${version}` : undefined,
|
|
157
|
+
dependsOn: dependsOn.length ? [...new Set(dependsOn)] : undefined,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return [...seen.values()].sort((a, b) => a.name.localeCompare(b.name) || (a.version ?? "").localeCompare(b.version ?? ""));
|
|
161
|
+
}
|
|
162
|
+
/** Each lockfile kind's parser and file name. */
|
|
163
|
+
export const LOCKFILE_PARSERS = { npm: parseNpmPackageLock, maven: parsePomXml, cargo: parseCargoLock };
|
|
164
|
+
export const LOCKFILE_NAMES = { npm: "package-lock.json", maven: "pom.xml", cargo: "Cargo.lock" };
|
|
128
165
|
/** Locate the first readable lockfile/manifest under `dir` this generator knows how to parse, in preference order (npm before Maven — most chant components are Node-first). Returns `undefined` if none is found. */
|
|
129
166
|
function findManifest(dir) {
|
|
130
|
-
for (const [kind, filename] of [["npm", "package-lock.json"], ["maven", "pom.xml"]]) {
|
|
167
|
+
for (const [kind, filename] of [["npm", "package-lock.json"], ["maven", "pom.xml"], ["cargo", "Cargo.lock"]]) {
|
|
131
168
|
const candidate = join(dir, filename);
|
|
132
169
|
try {
|
|
133
170
|
readFileSync(candidate, "utf-8");
|
|
@@ -160,12 +197,12 @@ export function createLockfileSbomGenerator(options = {}) {
|
|
|
160
197
|
function generateFromDir(dir, subjectName, digest, format = DEFAULT_SBOM_FORMAT) {
|
|
161
198
|
const manifest = findManifest(dir);
|
|
162
199
|
if (!manifest) {
|
|
163
|
-
throw new Error(`no supported lockfile/manifest found under "${dir}" (looked for package-lock.json, pom.xml) — ` +
|
|
200
|
+
throw new Error(`no supported lockfile/manifest found under "${dir}" (looked for package-lock.json, pom.xml, Cargo.lock) — ` +
|
|
164
201
|
`the hermetic lockfile SBOM backend requires a lockfile on disk; use the deep-scan path (#610) for images with no lockfile`);
|
|
165
202
|
}
|
|
166
203
|
const content = readFileSync(manifest.path, "utf-8");
|
|
167
|
-
const packages = manifest.kind
|
|
168
|
-
const generatorName =
|
|
204
|
+
const packages = LOCKFILE_PARSERS[manifest.kind](content);
|
|
205
|
+
const generatorName = `chant-lockfile-sbom/${LOCKFILE_NAMES[manifest.kind]}`;
|
|
169
206
|
const doc = writeBom(format, { subjectName, subjectId: digest ?? manifest.path, packages, generator: generatorName }, now);
|
|
170
207
|
const outDir = options.outDir ?? dir;
|
|
171
208
|
mkdirSync(outDir, { recursive: true });
|
|
@@ -13,30 +13,43 @@
|
|
|
13
13
|
* (`componentPlanDigest`, ./gate-plan.ts, #2574), so a wave mixing roots and
|
|
14
14
|
* other components still has one digest that moves when any of them does.
|
|
15
15
|
*
|
|
16
|
+
* The files a step without a `plan` deploys from are bound too (#4155,
|
|
17
|
+
* ./deploy-inputs.ts). A component with no plannable step folds them into its
|
|
18
|
+
* composition digest. A component with one gets a member more,
|
|
19
|
+
* `<component>#inputs`, over its other steps' files, so a `lambda-deploy`
|
|
20
|
+
* source or a Helm chart beside a `cfn-deploy` moves the wave's digest. A step
|
|
21
|
+
* whose content chant can't name is a hole on that member, so the plan note
|
|
22
|
+
* lists it as unbound.
|
|
23
|
+
*
|
|
16
24
|
* Known limit: a step input that reads an earlier step of the same
|
|
17
25
|
* component (`@Phase.field`) has no value before the component runs, so it
|
|
18
26
|
* plans as `undefined`. Cross-component wiring (`stackOutput()`,
|
|
19
27
|
* `@<component>.publish.*`) resolves.
|
|
20
28
|
*/
|
|
21
29
|
import { type DriverComponent, type DriverPhase, type DriverStep } from "./driver.js";
|
|
22
|
-
import type { CapabilityRegistry, DeployContext } from "./capability.js";
|
|
30
|
+
import type { CapabilityRegistry, DeployContext, PlannedOutputs } from "./capability.js";
|
|
23
31
|
import type { WaveMember } from "../gated-waves.js";
|
|
24
32
|
import type { ChangeSetPart } from "../change-set.js";
|
|
25
33
|
/**
|
|
26
34
|
* What planning one component produced: its members, what its steps hand to
|
|
27
35
|
* `run`, and each member's change-set part (#3183), or why it could not plan.
|
|
28
36
|
* A member whose capability returns no part gets one with no entries, so the
|
|
29
|
-
* parts always cover the members.
|
|
37
|
+
* parts always cover the members. `outputs` is what its steps' plans say the
|
|
38
|
+
* component will expose once applied (#3999), merged the way the driver
|
|
39
|
+
* merges a run's outputs; absent when no step's plan says.
|
|
30
40
|
*/
|
|
31
41
|
export type WaveComponentPlan = {
|
|
32
42
|
component: string;
|
|
33
43
|
members: WaveMember[];
|
|
34
44
|
plans: Record<string, unknown>;
|
|
35
45
|
parts: ChangeSetPart[];
|
|
46
|
+
outputs?: PlannedOutputs;
|
|
36
47
|
} | {
|
|
37
48
|
component: string;
|
|
38
49
|
error: string;
|
|
39
50
|
};
|
|
51
|
+
/** The member a planning component's other steps add (#4155): their files, under the component's name. */
|
|
52
|
+
export declare const inputsMemberName: (component: string) => string;
|
|
40
53
|
/** Every capability step in a composition, nested phases included, gates left out. */
|
|
41
54
|
export declare function capabilitySteps(phases: readonly DriverPhase[]): DriverStep[];
|
|
42
55
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wave-plan.d.ts","sourceRoot":"","sources":["../../src/components/wave-plan.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"wave-plan.d.ts","sourceRoot":"","sources":["../../src/components/wave-plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAA6C,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,MAAM,UAAU,CAAC;AAI9H,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,aAAa,EAAE,CAAC;IAAC,OAAO,CAAC,EAAE,cAAc,CAAA;CAAE,GAC9H;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAWzC,0GAA0G;AAC1G,eAAO,MAAM,gBAAgB,cAAe,MAAM,KAAG,MAA+B,CAAC;AAErF,sFAAsF;AACtF,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,EAAE,CAc5E;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,aAAa,EAClB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,aAAa,CAGf;AAED,oHAAoH;AACpH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,iBAAiB,CAAC,CAgD5B;AAUD;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,eAAe,EAC1B,QAAQ,EAAE,kBAAkB,EAC5B,GAAG,EAAE,aAAa,EAClB,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACxD,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,CAU9C;AAED;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAChD,QAAQ,EAAE,kBAAkB,EAC5B,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,aAAa,EAC3C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAC/C,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAYnC"}
|