@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
package/dist/workspace/ci-run.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `chant ci run plan|apply` (#4094, epic #4101): run one pull-request job as
|
|
2
|
+
* `chant ci run plan|record|apply` (#4094, epic #4101, record #4168): run one pull-request job as
|
|
3
3
|
* a pipeline Op, the first slice of the chant runner.
|
|
4
4
|
*
|
|
5
5
|
* The job is the typed value `prLoopJobs` (../components/pr-pipeline.ts)
|
|
@@ -44,6 +44,30 @@
|
|
|
44
44
|
* With a forge client (#4097) the job also sets a commit status at its
|
|
45
45
|
* commit: `pending` when it starts, `success` or `failure` when it settles.
|
|
46
46
|
* A status the forge refuses is a warning and never fails the job.
|
|
47
|
+
*
|
|
48
|
+
* Signing is opt-in (#4156). With no runner key the record is unsigned, and
|
|
49
|
+
* a reader counts it with no signer. A key `.chant/trust.json` does not list
|
|
50
|
+
* leaves it unsigned with a note `--verbose` prints, unless the declaration
|
|
51
|
+
* sets `ci.green.signedSince`; then a run left unsigned is a warning.
|
|
52
|
+
*
|
|
53
|
+
* In place (`--in-place`, #4156) the job runs in the checkout it is started
|
|
54
|
+
* in, as a generated forge job does: no worktree, no setup phase and no
|
|
55
|
+
* commit status of its own (the forge shows the job). The steps get the
|
|
56
|
+
* job's whole environment less `CHANT_RUNNER_KEY`, since the forge job is
|
|
57
|
+
* already the boundary, and the record's `runOrigin` names the forge's run,
|
|
58
|
+
* job and attempt (`resolveCiJob`).
|
|
59
|
+
*
|
|
60
|
+
* Local (`--local`, #4161) runs the job the same way on this machine and
|
|
61
|
+
* leaves nothing outside it. It implies `--no-push` and `--no-status`, and
|
|
62
|
+
* writes nothing under a report URL, given or declared: the command gets no
|
|
63
|
+
* `--report-url`, and gets `--no-status`, so pr-plan and pr-apply post no
|
|
64
|
+
* status or note either. The record is still written to the local
|
|
65
|
+
* `chant/lifecycle`, where a reader on this machine finds it beside CI's for
|
|
66
|
+
* the same commit. It says `runOrigin: { forge: "local" }` and its events say
|
|
67
|
+
* `runtime: "local"`. `ci tick --source runs` and `ci list` never count it.
|
|
68
|
+
* A pr-apply still pushes its own release records and gate facts, as the
|
|
69
|
+
* command always does, since a local apply changes the same infrastructure
|
|
70
|
+
* a CI one does.
|
|
47
71
|
*/
|
|
48
72
|
import { execFileSync } from "node:child_process";
|
|
49
73
|
import { copyFileSync, cpSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
@@ -53,25 +77,38 @@ import { PR_APPLY_RECORD, PR_LOOP_REPORT_DIR, prLoopJobs, prLoopSetup, PR_LOOP_I
|
|
|
53
77
|
import { detectForge, ForgeEnvironmentError, forgeFromEnv, FORGE_KINDS } from "../pr-forge.js";
|
|
54
78
|
import { PR_APPLY_GATE } from "../pr-loop.js";
|
|
55
79
|
import { formatError, formatWarning } from "../cli/format.js";
|
|
56
|
-
import {
|
|
80
|
+
import { resolveCiJob } from "../lifecycle/release-ledger.js";
|
|
81
|
+
import { fetchLifecycleStatus, pushLifecycleReport } from "../lifecycle/git.js";
|
|
57
82
|
import { ACTIVITY_PROFILES } from "../op/activity-profiles.js";
|
|
58
83
|
import { shellCmd } from "../op/activities/shell.js";
|
|
59
84
|
import { OpRunFailure, runOpLocally } from "../op/local-executor.js";
|
|
60
85
|
import { redactText } from "../op/redact.js";
|
|
61
86
|
import { findWorkspaceRoot } from "../project-root.js";
|
|
62
87
|
import { parseReportUrl, reportKey } from "../pr-report-url.js";
|
|
63
|
-
import {
|
|
88
|
+
import { reportUrlOf } from "./ci-report-url.js";
|
|
89
|
+
import { ciTagSigner, RUNNER_KEY_ENV, signedRunsRequired } from "./ci-green.js";
|
|
90
|
+
import { loadRunnerKey } from "./trust/dsse.js";
|
|
64
91
|
import { ciRedactor, ciSecretsFor, CI_SECRETS_ENV, readCiSecrets } from "./ci-secrets.js";
|
|
65
92
|
import { updateCiRunIndex } from "./ci-run-index.js";
|
|
66
93
|
import { resolveMemberContext } from "./member-pipeline.js";
|
|
67
94
|
import { signOpRunRecord } from "./trust/op-run-statement.js";
|
|
68
95
|
import { gitTop } from "./tree.js";
|
|
69
96
|
import { hostRunnerKey } from "./ci-runner-key.js";
|
|
70
|
-
|
|
97
|
+
import { requireRunnerStart } from "./ci-runner-start.js";
|
|
98
|
+
import { securityGroupsAt } from "./security.js";
|
|
99
|
+
export const CI_JOB_NAMES = ["plan", "apply", "record"];
|
|
71
100
|
/** The Op each job is recorded as, which `ci.green` phases match. */
|
|
72
|
-
export const CI_JOB_OPS = { plan: "pr-plan", apply: "pr-apply" };
|
|
101
|
+
export const CI_JOB_OPS = { plan: "pr-plan", apply: "pr-apply", record: "pr-record" };
|
|
102
|
+
/** What each job's Op says it does. */
|
|
103
|
+
const CI_JOB_OVERVIEWS = {
|
|
104
|
+
plan: "Plan the members this pull request reaches",
|
|
105
|
+
apply: "Apply the plan a reviewer approved",
|
|
106
|
+
record: "Record the plan on the merged commit; nothing applies",
|
|
107
|
+
};
|
|
73
108
|
/** Where a job the chant runner ran says it ran (#4094). */
|
|
74
109
|
export const CHANT_RUNNER_ORIGIN = { forge: "chant" };
|
|
110
|
+
/** Where a job `chant ci run --local` ran says it ran (#4161): this machine, outside CI. */
|
|
111
|
+
export const CHANT_LOCAL_ORIGIN = { forge: "local" };
|
|
75
112
|
/** The runner's variables every job gets, when the runner has them. */
|
|
76
113
|
export const CI_RUN_BASE_ENV = ["PATH", "HOME", "USER", "LOGNAME", "SHELL", "LANG", "LC_ALL", "LC_CTYPE", "TMPDIR", "TZ"];
|
|
77
114
|
/**
|
|
@@ -178,7 +215,7 @@ export function ciJobOp(input) {
|
|
|
178
215
|
const op = CI_JOB_OPS[input.job.jobName];
|
|
179
216
|
return {
|
|
180
217
|
name: op,
|
|
181
|
-
overview: input.job.jobName
|
|
218
|
+
overview: CI_JOB_OVERVIEWS[input.job.jobName],
|
|
182
219
|
labels: { Env: input.env, Pipeline: "pr", Job: input.job.jobName },
|
|
183
220
|
phases,
|
|
184
221
|
};
|
|
@@ -190,6 +227,17 @@ function exitCodeOf(error) {
|
|
|
190
227
|
const m = /command exited (\d+)/.exec(error ?? "");
|
|
191
228
|
return m ? Number(m[1]) : undefined;
|
|
192
229
|
}
|
|
230
|
+
/**
|
|
231
|
+
* The code `chant ci run` exits with for a settled job: 0 when it passed,
|
|
232
|
+
* else its command's own code when that is 1 to 255, such as 3 for a moved
|
|
233
|
+
* plan or a waiting wave (#4156), else 1. The run index records the same
|
|
234
|
+
* code (#4165).
|
|
235
|
+
*/
|
|
236
|
+
export function ciJobExitCode(result) {
|
|
237
|
+
if (result.status === "ok")
|
|
238
|
+
return 0;
|
|
239
|
+
return result.exitCode && result.exitCode > 0 && result.exitCode < 256 ? result.exitCode : 1;
|
|
240
|
+
}
|
|
193
241
|
/** The first line of a step's error, for a reason. */
|
|
194
242
|
const firstLine = (text) => text.split("\n").find((l) => l.trim() !== "")?.trim() ?? text;
|
|
195
243
|
/**
|
|
@@ -249,12 +297,12 @@ export function ciJobFailure(input) {
|
|
|
249
297
|
const STATUS_DESCRIPTION = 140;
|
|
250
298
|
const cut = (text, max = STATUS_DESCRIPTION) => (text.length > max ? `${text.slice(0, max - 3)}...` : text);
|
|
251
299
|
/**
|
|
252
|
-
* A job's status context: `chant/pr-plan` for the plan, and for the apply
|
|
300
|
+
* A job's status context: `chant/pr-plan` for the plan, `chant/pr-record` for the record (#4168), and for the apply
|
|
253
301
|
* `chant/<gate>`, which is `chant/pr-apply` unless `--gate` renamed the gate.
|
|
254
302
|
* pr-plan's own status is `chant/plan` (../pr-loop.ts), a different context.
|
|
255
303
|
*/
|
|
256
304
|
export function ciStatusContext(job, gate) {
|
|
257
|
-
return job === "apply" ? `chant/${gate ?? PR_APPLY_GATE}` : `chant/${CI_JOB_OPS
|
|
305
|
+
return job === "apply" ? `chant/${gate ?? PR_APPLY_GATE}` : `chant/${CI_JOB_OPS[job]}`;
|
|
258
306
|
}
|
|
259
307
|
/**
|
|
260
308
|
* The link a job's status carries: the `--status-url` template with `{key}`
|
|
@@ -396,7 +444,9 @@ async function recordInIndex(input) {
|
|
|
396
444
|
ended: input.record.ended,
|
|
397
445
|
runId: clean(input.record.id),
|
|
398
446
|
key: clean(reportKey(pr, input.commit, input.member)),
|
|
399
|
-
runOrigin:
|
|
447
|
+
runOrigin: input.runOrigin,
|
|
448
|
+
signer: input.signer,
|
|
449
|
+
exitCode: input.exitCode,
|
|
400
450
|
};
|
|
401
451
|
await updateCiRunIndex({ target, entry, ...(input.limit ? { limit: input.limit } : {}), warn: input.warn });
|
|
402
452
|
}
|
|
@@ -413,12 +463,25 @@ export async function ciRun(req) {
|
|
|
413
463
|
if (!top)
|
|
414
464
|
throw new CiRunError("a job runs in a fresh checkout of a commit, and this directory is not in a git repository");
|
|
415
465
|
const commit = resolveJobCommit(top, req.commit ?? "HEAD");
|
|
466
|
+
if (req.inPlace && commit !== resolveJobCommit(top, "HEAD"))
|
|
467
|
+
throw new CiRunError(`--in-place runs the checkout's HEAD, and --commit names ${commit.slice(0, 12)}`);
|
|
468
|
+
if (req.local && req.inPlace)
|
|
469
|
+
throw new CiRunError("--in-place runs a forge job in the forge's checkout, and --local runs one on this machine; pass one of them");
|
|
416
470
|
const place = ciJobPlace(cwd, top);
|
|
417
|
-
const jobs = prLoopJobs(req.forge, req.env, req.loop ?? {}, place.member);
|
|
418
|
-
const
|
|
419
|
-
if (!
|
|
471
|
+
const jobs = prLoopJobs(req.forge, req.env, req.local ? localLoop(req.loop) : (req.loop ?? {}), place.member);
|
|
472
|
+
const found = jobs.find((j) => j.jobName === req.job);
|
|
473
|
+
if (!found)
|
|
420
474
|
throw new CiRunError(`the pull-request pipeline has no ${req.job} job; it has ${jobs.map((j) => j.jobName).join(" and ")}`);
|
|
421
|
-
|
|
475
|
+
if (req.wave !== undefined && (req.job !== "apply" || !req.loop?.waveGate))
|
|
476
|
+
throw new CiRunError("--wave names the one wave an apply runs, and takes --wave-gate: ci run apply --wave-gate <gate> --wave <k>");
|
|
477
|
+
// #4147: before anything runs or any secret reaches a step, the provisioner's word that this runner was started for this job.
|
|
478
|
+
// #4168: under the isolated-runners security group an apply job requires the statement too, unless it runs on this machine.
|
|
479
|
+
const isolated = !req.requireRunnerStart && !req.local && req.job === "apply" && securityGroupsAt(cwd).has("isolated-runners");
|
|
480
|
+
const started = req.requireRunnerStart || isolated ? runnerStartFor(req, { top, commit, hostEnv }) : undefined;
|
|
481
|
+
// A generated wave job's command, as prLoopWaveJobs writes it. #4161: a local job's command posts no status or note.
|
|
482
|
+
const command = `${found.command}${req.wave !== undefined ? ` --wave ${req.wave}` : ""}${req.local ? " --no-status" : ""}`;
|
|
483
|
+
const job = { ...found, command, ...(req.wave !== undefined ? { wave: req.wave } : {}) };
|
|
484
|
+
const own = ciJobEnv(job, {
|
|
422
485
|
forge: req.forge,
|
|
423
486
|
env: req.env,
|
|
424
487
|
values: { base: req.base, pr: req.pr, commit },
|
|
@@ -426,11 +489,16 @@ export async function ciRun(req) {
|
|
|
426
489
|
passEnv: req.passEnv,
|
|
427
490
|
secrets: ciSecretsFor(req.secrets, req.job),
|
|
428
491
|
});
|
|
492
|
+
// #4156: in place, the forge job's environment is the job's, less the runner key.
|
|
493
|
+
const jobEnv = req.inPlace ? { ...definedEnv(hostEnv), ...own } : own;
|
|
494
|
+
delete jobEnv[RUNNER_KEY_ENV];
|
|
429
495
|
// #4096: the secrets and the job's secret-looking variables, redacted from everything the run writes and returns.
|
|
430
|
-
|
|
496
|
+
// In place the forge's own variables come too; one whose value is short, such as a flag, is left out, so it can't blank common words.
|
|
497
|
+
const redact = ciRedactor(req.inPlace ? { ...longValues(jobEnv), ...own } : jobEnv, req.secrets);
|
|
431
498
|
try {
|
|
432
|
-
const
|
|
433
|
-
|
|
499
|
+
const ran = await runCiJob(req, { cwd, top, commit, place, job, jobEnv, ...(redact ? { redact } : {}) });
|
|
500
|
+
const result = started ? { ...ran, notes: [started, ...ran.notes] } : ran;
|
|
501
|
+
return redact ? { ...result, warnings: result.warnings.map(redact), notes: result.notes.map(redact), ...(result.pushWarning ? { pushWarning: redact(result.pushWarning) } : {}) } : result;
|
|
434
502
|
}
|
|
435
503
|
catch (err) {
|
|
436
504
|
if (redact && err instanceof Error)
|
|
@@ -438,23 +506,89 @@ export async function ciRun(req) {
|
|
|
438
506
|
throw err;
|
|
439
507
|
}
|
|
440
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* `--require-runner-start` (#4147): the runner-start statement for this
|
|
511
|
+
* forge job, checked against `.chant/trust.json` at `--base` (the commit
|
|
512
|
+
* before the change, as a push's `before` is), or at the job's commit
|
|
513
|
+
* without one. Throws {@link CiRunError} unless it verifies.
|
|
514
|
+
*/
|
|
515
|
+
function runnerStartFor(req, at) {
|
|
516
|
+
if (req.local)
|
|
517
|
+
throw new CiRunError("--require-runner-start checks a forge job's runner, and --local runs the job on this machine");
|
|
518
|
+
const base = req.base ? resolveJobCommit(at.top, req.base) : at.commit;
|
|
519
|
+
try {
|
|
520
|
+
return requireRunnerStart({ top: at.top, base, commit: at.commit, env: at.hostEnv }).reason;
|
|
521
|
+
}
|
|
522
|
+
catch (err) {
|
|
523
|
+
throw new CiRunError(message(err));
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
/** The generator's options for a `--local` job (#4161): the same, with no report URL. */
|
|
527
|
+
function localLoop(loop) {
|
|
528
|
+
const { reportUrl: _dropped, ...rest } = loop ?? {};
|
|
529
|
+
return rest;
|
|
530
|
+
}
|
|
531
|
+
/** The variables of `env` whose value is long enough to be a credential, 8 characters or more. */
|
|
532
|
+
function longValues(env) {
|
|
533
|
+
return Object.fromEntries(Object.entries(env).filter(([, value]) => value.length >= 8));
|
|
534
|
+
}
|
|
535
|
+
/** The variables of `env` that have a value. */
|
|
536
|
+
function definedEnv(env) {
|
|
537
|
+
const out = {};
|
|
538
|
+
for (const [name, value] of Object.entries(env))
|
|
539
|
+
if (value !== undefined)
|
|
540
|
+
out[name] = value;
|
|
541
|
+
return out;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Who signs the run (#4156): the runner key, checked against
|
|
545
|
+
* `.chant/trust.json` at the commit. A key that isn't an Ed25519 PEM is an
|
|
546
|
+
* error, and so is a `--key` the file does not list. A key from the
|
|
547
|
+
* environment that it does not list, and no key at all, leave the run
|
|
548
|
+
* unsigned: a warning when the declaration's `ci.green.signedSince` asks
|
|
549
|
+
* for signed runs, a note for `--verbose` otherwise.
|
|
550
|
+
*/
|
|
551
|
+
function ciRunSigner(req, at) {
|
|
552
|
+
// #4161: a local run never counts, signed or not, so nothing about its signature warns.
|
|
553
|
+
const required = req.local ? null : signedRunsRequired(at.cwd);
|
|
554
|
+
const say = (text) => (required ? { warnings: [`${text}, and ci.green.signedSince is ${required}, so it will not count`], notes: [] } : { warnings: [], notes: [text] });
|
|
555
|
+
if (req.runnerKey === undefined)
|
|
556
|
+
return say("there is no runner key, so the run's record is unsigned");
|
|
557
|
+
try {
|
|
558
|
+
loadRunnerKey(req.runnerKey);
|
|
559
|
+
}
|
|
560
|
+
catch (err) {
|
|
561
|
+
throw new CiRunError(`the runner key${req.runnerKeyFromEnv ? ` in ${RUNNER_KEY_ENV}` : ""} is not an Ed25519 private key in PEM: ${message(err)}`);
|
|
562
|
+
}
|
|
563
|
+
try {
|
|
564
|
+
return { signer: ciTagSigner(at.top, at.commit, req.runnerKey, "the runs it signed"), warnings: [], notes: [] };
|
|
565
|
+
}
|
|
566
|
+
catch (err) {
|
|
567
|
+
if (!req.runnerKeyFromEnv)
|
|
568
|
+
throw new CiRunError(`the run would not be signed: ${message(err)}`);
|
|
569
|
+
return say(`${RUNNER_KEY_ENV} is set, and the run will not be signed: ${message(err)}`);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/** Where the job runs: a fresh worktree of the commit, or with `inPlace` the checkout itself, which is left as it is. */
|
|
573
|
+
function jobCheckout(top, commit, inPlace) {
|
|
574
|
+
return inPlace ? { dir: top, remove() { } } : freshCheckout(top, commit);
|
|
575
|
+
}
|
|
441
576
|
/** {@link ciRun} once the job and its environment are known. */
|
|
442
577
|
async function runCiJob(req, at) {
|
|
443
578
|
const { cwd, top, commit, place, job, jobEnv, redact } = at;
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const checkout = freshCheckout(top, commit);
|
|
579
|
+
const local = req.local === true;
|
|
580
|
+
const status = local ? undefined : req.status;
|
|
581
|
+
const reportUrl = local ? undefined : req.loop?.reportUrl;
|
|
582
|
+
// The record is signed against .chant/trust.json at the commit the job runs, so a --key that commit does not list is refused before anything runs.
|
|
583
|
+
const signing = ciRunSigner(req, { cwd, top, commit });
|
|
584
|
+
const signer = signing.signer;
|
|
585
|
+
const early = signing.warnings;
|
|
586
|
+
const notes = signing.notes;
|
|
587
|
+
const origin = local ? CHANT_LOCAL_ORIGIN : req.inPlace ? (resolveCiJob(req.hostEnv ?? process.env)?.runOrigin ?? CHANT_RUNNER_ORIGIN) : CHANT_RUNNER_ORIGIN;
|
|
588
|
+
// In place, the job writes its record on the checkout's chant/lifecycle, which a forge checkout may not have fetched.
|
|
589
|
+
if (req.inPlace && req.push !== false)
|
|
590
|
+
await fetchLifecycleStatus({ cwd: top }).catch(() => undefined);
|
|
591
|
+
const checkout = jobCheckout(top, commit, req.inPlace);
|
|
458
592
|
try {
|
|
459
593
|
const jobDir = place.dir === "." ? checkout.dir : join(checkout.dir, place.dir);
|
|
460
594
|
const op = ciJobOp({
|
|
@@ -462,7 +596,7 @@ async function runCiJob(req, at) {
|
|
|
462
596
|
env: req.env,
|
|
463
597
|
cwd: jobDir,
|
|
464
598
|
jobEnv,
|
|
465
|
-
setup: prLoopSetup(req.image ?? PR_LOOP_IMAGE),
|
|
599
|
+
setup: req.inPlace ? [] : prLoopSetup(req.image ?? PR_LOOP_IMAGE),
|
|
466
600
|
build: [...(req.beforeScript ?? []), ...(job.build ?? [])],
|
|
467
601
|
...(req.chant ? { chant: req.chant } : {}),
|
|
468
602
|
});
|
|
@@ -474,14 +608,14 @@ async function runCiJob(req, at) {
|
|
|
474
608
|
copyFileSync(resume.host, resume.job);
|
|
475
609
|
}
|
|
476
610
|
const statusContext = ciStatusContext(req.job, req.loop?.gate);
|
|
477
|
-
const statusUrl =
|
|
478
|
-
? ciStatusUrl({ ...(
|
|
611
|
+
const statusUrl = status
|
|
612
|
+
? ciStatusUrl({ ...(status.urlTemplate ? { urlTemplate: status.urlTemplate } : {}), ...(reportUrl ? { reportUrl } : {}), ...(req.pr !== undefined ? { pr: req.pr } : {}), commit, ...(place.member ? { member: place.member } : {}) })
|
|
479
613
|
: undefined;
|
|
480
614
|
const postStatus = async (state, description) => {
|
|
481
|
-
if (!
|
|
615
|
+
if (!status)
|
|
482
616
|
return;
|
|
483
617
|
try {
|
|
484
|
-
await
|
|
618
|
+
await status.client.setCommitStatus(commit, { context: statusContext, state, description: cut(redact ? redact(description) : description), ...(statusUrl ? { targetUrl: statusUrl } : {}) });
|
|
485
619
|
}
|
|
486
620
|
catch (err) {
|
|
487
621
|
warnings.push(`could not set the ${statusContext} status: ${message(err)}`);
|
|
@@ -498,7 +632,7 @@ async function runCiJob(req, at) {
|
|
|
498
632
|
cwd: jobDir,
|
|
499
633
|
commit,
|
|
500
634
|
ledger: { cwd: jobDir },
|
|
501
|
-
runner: { kind: "pipeline", runtime: "ci", runOrigin:
|
|
635
|
+
runner: { kind: "pipeline", runtime: local ? "local" : "ci", runOrigin: origin },
|
|
502
636
|
describeFailure: (records) => ciJobFailure({ job: req.job, op, records, reportDir: join(jobDir, PR_LOOP_REPORT_DIR) }),
|
|
503
637
|
...(req.runEvents ? { runEvents: { write: req.runEvents } } : {}),
|
|
504
638
|
...(req.stepOutput ? { stepOutput: req.stepOutput } : {}),
|
|
@@ -533,28 +667,40 @@ async function runCiJob(req, at) {
|
|
|
533
667
|
let report = null;
|
|
534
668
|
if (existsSync(written)) {
|
|
535
669
|
report = resolve(cwd, req.output ?? PR_LOOP_REPORT_DIR);
|
|
536
|
-
|
|
537
|
-
if (
|
|
538
|
-
|
|
670
|
+
// In place the report is already where the forge keeps it, and stays as the command wrote it.
|
|
671
|
+
if (!(existsSync(report) && realpathSync(report) === realpathSync(written))) {
|
|
672
|
+
cpSync(written, report, { recursive: true });
|
|
673
|
+
if (redact)
|
|
674
|
+
redactTree(report, redact);
|
|
675
|
+
}
|
|
539
676
|
}
|
|
540
|
-
|
|
541
|
-
|
|
677
|
+
const failed = result.records.find((r) => r.status === "fail");
|
|
678
|
+
const exitCode = failed?.phase === req.job ? exitCodeOf(failed.error) : undefined;
|
|
679
|
+
if (reportUrl) {
|
|
680
|
+
await recordInIndex({ url: reportUrl, job: req.job, commit, member: place.member, pr: req.pr, record: result.record, runOrigin: origin, signer: result.record.statement && signer ? signer.principal : null, exitCode: ciJobExitCode({ status: result.status, ...(exitCode !== undefined ? { exitCode } : {}) }), reportDir: written, limit: req.runIndexLimit, ...(redact ? { redact } : {}), warn: (w) => warnings.push(w) });
|
|
542
681
|
}
|
|
543
|
-
|
|
682
|
+
// In place the forge job's outcome is the command's, so a record that could not be written is a warning there.
|
|
683
|
+
if (ledgerError && req.inPlace)
|
|
684
|
+
warnings.push(ledgerError);
|
|
685
|
+
else if (ledgerError)
|
|
544
686
|
throw new CiRunError(ledgerError);
|
|
545
|
-
const pushed =
|
|
546
|
-
|
|
687
|
+
const pushed = local
|
|
688
|
+
? { pushed: false }
|
|
689
|
+
: req.push === false ? { pushed: false, pushWarning: "chant/lifecycle was not pushed" } : await pushLifecycleReport({ cwd: top });
|
|
547
690
|
return {
|
|
548
691
|
op: op.name,
|
|
549
692
|
status: result.status,
|
|
550
693
|
record: result.record,
|
|
551
694
|
...(failed ? { failure: { phase: failed.phase, error: failed.error ?? "the step failed" } } : {}),
|
|
695
|
+
...(exitCode !== undefined ? { exitCode } : {}),
|
|
552
696
|
report,
|
|
553
|
-
signer: signer
|
|
697
|
+
signer: result.record.statement && signer ? signer.principal : null,
|
|
554
698
|
pushed: pushed.pushed,
|
|
555
699
|
...(pushed.pushWarning ? { pushWarning: pushed.pushWarning } : {}),
|
|
556
700
|
warnings,
|
|
701
|
+
notes,
|
|
557
702
|
checkout: checkout.dir,
|
|
703
|
+
...(local ? { local: true } : {}),
|
|
558
704
|
};
|
|
559
705
|
}
|
|
560
706
|
finally {
|
|
@@ -592,18 +738,39 @@ export function formatCiRun(r) {
|
|
|
592
738
|
lines.push(` failure: ${why.code}${why.phase ? ` in ${why.phase}` : ""}${why.exitCode !== undefined ? `, exit ${why.exitCode}` : ""}: ${why.reason}`);
|
|
593
739
|
else if (r.failure)
|
|
594
740
|
lines.push(` ${r.failure.phase}: ${r.failure.error}`);
|
|
595
|
-
lines.push(` record: ${r.record.env}/runs__${r.op}.jsonl on chant/lifecycle, ${r.signer ? `signed by ${r.signer}` : "unsigned
|
|
741
|
+
lines.push(` record: ${r.record.env}/runs__${r.op}.jsonl on chant/lifecycle, ${r.signer ? `signed by ${r.signer}` : "unsigned"}`);
|
|
596
742
|
if (r.report)
|
|
597
743
|
lines.push(` report: ${r.report}`);
|
|
598
|
-
if (
|
|
744
|
+
if (r.local)
|
|
745
|
+
lines.push(" local run: the record stays on this machine, with no push, commit status or report upload");
|
|
746
|
+
else if (!r.pushed)
|
|
599
747
|
lines.push(` ${r.pushWarning ?? "chant/lifecycle was not pushed"}`);
|
|
600
748
|
return lines.join("\n");
|
|
601
749
|
}
|
|
602
750
|
// ── The command ──────────────────────────────────────────────────────────────
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
751
|
+
/**
|
|
752
|
+
* The generator's options from `ci run`'s and `ci serve`'s flags, as `chant
|
|
753
|
+
* build --components --generate <lexicon> --pr-loop` takes them: `--gate`,
|
|
754
|
+
* `--branch`, `--events-json`, `--report-url`, `--pr-build`,
|
|
755
|
+
* `--pr-build-command`, `--wave-gate` (#4003) and `--require-review`
|
|
756
|
+
* (#4168; `--no-require-review`, the default, is still accepted).
|
|
757
|
+
*/
|
|
758
|
+
export function ciLoopOptions(args) {
|
|
759
|
+
return {
|
|
760
|
+
...(args.gate ? { gate: args.gate } : {}),
|
|
761
|
+
...(args.branch ? { branch: args.branch } : {}),
|
|
762
|
+
...(args.eventsJson ? { events: true } : {}),
|
|
763
|
+
...(args.reportUrl ? { reportUrl: args.reportUrl } : {}),
|
|
764
|
+
...(args.prBuild ? { build: true } : {}),
|
|
765
|
+
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
766
|
+
...(args.waveGate ? { waveGate: args.waveGate } : {}),
|
|
767
|
+
...(args.requireReview === true ? { requireReview: true } : {}),
|
|
768
|
+
};
|
|
769
|
+
}
|
|
770
|
+
const USAGE = "chant ci run plan|record|apply --env <env> --base <sha> [--pr <n>] [--commit <sha>] [--forge github|gitlab|forgejo] " +
|
|
771
|
+
"[--gate <name>] [--wave-gate <name>] [--wave <k>] [--branch <name>] [--events-json] [--report-url <url>] [--run-index-limit <n>] [--image <image>] [--before-script <line>]... " +
|
|
772
|
+
"[--pr-build] [--pr-build-command <line>] [--require-review] [--no-status] [--status-url <url template>] " +
|
|
773
|
+
"[--chant <command>] [--pass-env <NAME>]... [--secrets <file>] [--key <runner key.pem>] [-o <dir>] [--in-place | --local] [--no-push] [--verbose] | chant ci run --at <sha> | chant ci run --setup-key [--trust [--principal <name>]] [--state <dir>] [--branch <name>]";
|
|
607
774
|
const ENV_NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
608
775
|
/** The host's runner key in `--state`, or in ci serve's default state directory, when `--setup-key` made one there (#4099). */
|
|
609
776
|
function hostRunnerKeyAt(cwd, statePath) {
|
|
@@ -623,15 +790,40 @@ export function ciSecretsOf(flag, env = process.env) {
|
|
|
623
790
|
const file = flag ?? (env[CI_SECRETS_ENV] || undefined);
|
|
624
791
|
return file === undefined ? undefined : readCiSecrets(resolve(file));
|
|
625
792
|
}
|
|
626
|
-
/**
|
|
793
|
+
/**
|
|
794
|
+
* `chant ci run --at <sha>` (#4169): ask for every required phase to be built
|
|
795
|
+
* at a commit of the green branch. On GitHub, with a token in the
|
|
796
|
+
* environment, the workflows holding the phases start at once.
|
|
797
|
+
*/
|
|
798
|
+
async function requestBuildCommand(at) {
|
|
799
|
+
const { requestBuild } = await import("./ci-green.js");
|
|
800
|
+
const { ciForgeFromEnv } = await import("./ci-green-forge.js");
|
|
801
|
+
let forge;
|
|
802
|
+
try {
|
|
803
|
+
forge = process.env.GITHUB_REPOSITORY ? ciForgeFromEnv("github") : undefined;
|
|
804
|
+
}
|
|
805
|
+
catch {
|
|
806
|
+
forge = undefined;
|
|
807
|
+
}
|
|
808
|
+
const r = await requestBuild({ cwd: process.cwd(), at, ...(forge ? { forge } : {}) });
|
|
809
|
+
for (const w of r.warnings)
|
|
810
|
+
console.error(formatWarning({ message: w }));
|
|
811
|
+
const what = `${r.request.phases.join(", ")} at ${r.request.commit.slice(0, 12)}`;
|
|
812
|
+
console.log(`${r.existed ? `${r.request.tag} already asks for a build` : `Asked for ${what}: ${r.request.tag}`}. ` +
|
|
813
|
+
(r.dispatched.length > 0 ? `Started ${r.dispatched.join(", ")}.` : "The next ci tick starts it on GitHub, and ci serve --build-command serves it for chant runs."));
|
|
814
|
+
return 0;
|
|
815
|
+
}
|
|
816
|
+
/** `chant ci run plan|record|apply` (#4094, #4168). */
|
|
627
817
|
export async function runCiRun(ctx) {
|
|
628
818
|
const { args } = ctx;
|
|
629
819
|
try {
|
|
630
820
|
if (args.setupKey)
|
|
631
821
|
return (await import("./ci-serve.js")).runnerKeySetupCommand(ctx);
|
|
822
|
+
if (args.at !== undefined && args.extraPositional === undefined)
|
|
823
|
+
return await requestBuildCommand(args.at);
|
|
632
824
|
const job = args.extraPositional;
|
|
633
|
-
if (job !== "plan" && job !== "apply")
|
|
634
|
-
throw new CiRunError(`ci run takes the job to run, plan or apply${job ? `, not ${JSON.stringify(job)}` : ""}`);
|
|
825
|
+
if (job !== "plan" && job !== "apply" && job !== "record")
|
|
826
|
+
throw new CiRunError(`ci run takes the job to run, plan, record or apply${job ? `, not ${JSON.stringify(job)}` : ""}`);
|
|
635
827
|
if (!args.env)
|
|
636
828
|
throw new CiRunError("--env names the environment the pipeline is for, as chant build --components --generate <lexicon> --pr-loop took it: --env <env>");
|
|
637
829
|
const forge = args.forge ?? detectForge(process.env);
|
|
@@ -647,10 +839,14 @@ export async function runCiRun(ctx) {
|
|
|
647
839
|
const hostKey = fromFlag || process.env[RUNNER_KEY_ENV] ? undefined : hostRunnerKeyAt(process.cwd(), args.statePath);
|
|
648
840
|
const runnerKey = fromFlag ? readFileSync(resolve(args.key), "utf-8") : process.env[RUNNER_KEY_ENV] || hostKey?.pem;
|
|
649
841
|
const hostEnv = process.env;
|
|
650
|
-
|
|
842
|
+
// #4156: in place the forge shows the job, so ci run sets no status of its own.
|
|
843
|
+
// #4161: a local run sets no status, so it builds no client and warns about none.
|
|
844
|
+
const { status, warning } = ciStatusFromEnv({ forge: forge, hostEnv, noStatus: args.noStatus || args.ciInPlace || args.local, statusUrl: args.statusUrl });
|
|
651
845
|
if (warning)
|
|
652
846
|
console.error(formatWarning({ message: warning }));
|
|
653
847
|
const secrets = ciSecretsOf(args.ciSecrets);
|
|
848
|
+
// #4160: without --report-url, the declaration's ci.reportUrl.
|
|
849
|
+
const reportUrl = await reportUrlOf(args.reportUrl, process.cwd());
|
|
654
850
|
const result = await ciRun({
|
|
655
851
|
cwd: process.cwd(),
|
|
656
852
|
...(status ? { status } : {}),
|
|
@@ -660,14 +856,12 @@ export async function runCiRun(ctx) {
|
|
|
660
856
|
...(args.base ? { base: args.base } : {}),
|
|
661
857
|
...(args.pr !== undefined ? { pr: args.pr } : {}),
|
|
662
858
|
...(args.commit ? { commit: args.commit } : {}),
|
|
663
|
-
loop: {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
...(args.prBuildCommand ? { buildCommand: args.prBuildCommand } : {}),
|
|
670
|
-
},
|
|
859
|
+
loop: ciLoopOptions(reportUrl ? { ...args, reportUrl } : args),
|
|
860
|
+
...(args.ciInPlace ? { inPlace: true } : {}),
|
|
861
|
+
...(args.local ? { local: true } : {}),
|
|
862
|
+
...(args.noPush ? { push: false } : {}),
|
|
863
|
+
...(args.wave !== undefined ? { wave: args.wave } : {}),
|
|
864
|
+
...(args.requireRunnerStart ? { requireRunnerStart: true } : {}),
|
|
671
865
|
...(args.runIndexLimit ? { runIndexLimit: args.runIndexLimit } : {}),
|
|
672
866
|
...(args.image ? { image: args.image } : {}),
|
|
673
867
|
...(args.beforeScript?.length ? { beforeScript: args.beforeScript } : {}),
|
|
@@ -681,8 +875,12 @@ export async function runCiRun(ctx) {
|
|
|
681
875
|
});
|
|
682
876
|
for (const w of result.warnings)
|
|
683
877
|
console.error(formatWarning({ message: w }));
|
|
878
|
+
if (args.verbose)
|
|
879
|
+
for (const n of result.notes)
|
|
880
|
+
console.error(`ci run: ${n}`);
|
|
684
881
|
console.error(formatCiRun(result));
|
|
685
|
-
|
|
882
|
+
// #4156: a failed command's own exit code, such as 3 for a moved plan, is the job's, as it was before the job ran through ci run.
|
|
883
|
+
return ciJobExitCode(result);
|
|
686
884
|
}
|
|
687
885
|
catch (err) {
|
|
688
886
|
console.error(formatError({ message: `chant ci run: ${message(err)}`, hint: USAGE }));
|
|
@@ -101,9 +101,18 @@ export declare function formatRunnerKeySetup(s: RunnerKeySetup, branch: string):
|
|
|
101
101
|
/**
|
|
102
102
|
* The key `ci serve` signs with, checked before its first poll (#4099): the
|
|
103
103
|
* `--key` file, else `CHANT_RUNNER_KEY`, else the host's key in the state
|
|
104
|
-
* directory.
|
|
105
|
-
*
|
|
106
|
-
*
|
|
104
|
+
* directory. Signing is opt-in (#4156):
|
|
105
|
+
*
|
|
106
|
+
* - With no key, `ci serve` serves unsigned and says so only in `note`.
|
|
107
|
+
* - A key `.chant/trust.json` at the target's head does not list with the
|
|
108
|
+
* runner role, or a target branch it can't find to check against, leaves
|
|
109
|
+
* it serving unsigned, with one `warning`.
|
|
110
|
+
* - With `required` (the declaration's `ci.green.signedSince`) each of
|
|
111
|
+
* those refuses to start, as before #4156.
|
|
112
|
+
*
|
|
113
|
+
* A key that is not an Ed25519 private key in PEM, or a `--key` file that
|
|
114
|
+
* can't be read, refuses either way. `unsigned` (`--unsigned`) skips the
|
|
115
|
+
* key without `required` and is ignored with it.
|
|
107
116
|
*/
|
|
108
117
|
export declare function ciServeRunnerKey(req: {
|
|
109
118
|
top: string;
|
|
@@ -112,9 +121,13 @@ export declare function ciServeRunnerKey(req: {
|
|
|
112
121
|
keyFile?: string;
|
|
113
122
|
envKey?: string;
|
|
114
123
|
unsigned?: boolean;
|
|
124
|
+
/** The declaration's `ci.green.signedSince`, when it sets one: every run must then be signed. */
|
|
125
|
+
required?: string | null;
|
|
115
126
|
}): {
|
|
116
127
|
pem?: string;
|
|
117
128
|
fromFlag: boolean;
|
|
118
129
|
source: string;
|
|
130
|
+
warning?: string;
|
|
131
|
+
note?: string;
|
|
119
132
|
};
|
|
120
133
|
//# sourceMappingURL=ci-runner-key.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ci-runner-key.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-runner-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH,oDAAoD;AACpD,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAEhD,2FAA2F;AAC3F,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB;AA4BD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAGzE;AAED,yHAAyH;AACzH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAWnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAOtH;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,4HAA4H;AAC5H,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAMzI;AAED,MAAM,WAAW,mBAAmB;IAClC,mGAAmG;IACnG,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,mBAAmB,CAmChK;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,aAAa,CAAC;IACnB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED,iIAAiI;AACjI,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAQvJ;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAe9E;AAED
|
|
1
|
+
{"version":3,"file":"ci-runner-key.d.ts","sourceRoot":"","sources":["../../src/workspace/ci-runner-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAYH,oDAAoD;AACpD,eAAO,MAAM,eAAe,mBAAmB,CAAC;AAEhD,2FAA2F;AAC3F,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,8BAA8B;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,OAAO,EAAE,OAAO,CAAC;CAClB;AA4BD,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAGzE;AAED,yHAAyH;AACzH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,aAAa,CAWnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAW,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAOtH;AAED,gEAAgE;AAChE,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,4HAA4H;AAC5H,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAMzI;AAED,MAAM,WAAW,mBAAmB;IAClC,mGAAmG;IACnG,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,mDAAmD;IACnD,MAAM,EAAE,OAAO,CAAC;IAChB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,mBAAmB,CAmChK;AAED,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,aAAa,CAAC;IACnB,4FAA4F;IAC5F,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,gEAAgE;IAChE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED,iIAAiI;AACjI,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,cAAc,CAQvJ;AAED,gFAAgF;AAChF,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAe9E;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iGAAiG;IACjG,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,GAAG;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CA+BvF"}
|
|
@@ -184,18 +184,31 @@ export function formatRunnerKeySetup(s, branch) {
|
|
|
184
184
|
/**
|
|
185
185
|
* The key `ci serve` signs with, checked before its first poll (#4099): the
|
|
186
186
|
* `--key` file, else `CHANT_RUNNER_KEY`, else the host's key in the state
|
|
187
|
-
* directory.
|
|
188
|
-
*
|
|
189
|
-
*
|
|
187
|
+
* directory. Signing is opt-in (#4156):
|
|
188
|
+
*
|
|
189
|
+
* - With no key, `ci serve` serves unsigned and says so only in `note`.
|
|
190
|
+
* - A key `.chant/trust.json` at the target's head does not list with the
|
|
191
|
+
* runner role, or a target branch it can't find to check against, leaves
|
|
192
|
+
* it serving unsigned, with one `warning`.
|
|
193
|
+
* - With `required` (the declaration's `ci.green.signedSince`) each of
|
|
194
|
+
* those refuses to start, as before #4156.
|
|
195
|
+
*
|
|
196
|
+
* A key that is not an Ed25519 private key in PEM, or a `--key` file that
|
|
197
|
+
* can't be read, refuses either way. `unsigned` (`--unsigned`) skips the
|
|
198
|
+
* key without `required` and is ignored with it.
|
|
190
199
|
*/
|
|
191
200
|
export function ciServeRunnerKey(req) {
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
const required = req.required ?? null;
|
|
202
|
+
const optIn = `ci.green.signedSince is ${required}, so every run must be signed`;
|
|
203
|
+
if (req.unsigned && !required)
|
|
204
|
+
return { fromFlag: false, source: "none (--unsigned)", note: "runs are not signed (--unsigned)" };
|
|
194
205
|
const host = req.keyFile === undefined && !req.envKey ? hostRunnerKey(req.stateDir) : undefined;
|
|
195
206
|
const pem = req.keyFile !== undefined ? readFileSync(req.keyFile, "utf-8") : req.envKey || host?.pem;
|
|
196
207
|
const source = req.keyFile !== undefined ? req.keyFile : req.envKey ? "CHANT_RUNNER_KEY" : (host?.path ?? join(req.stateDir, RUNNER_KEY_FILE));
|
|
197
208
|
if (pem === undefined) {
|
|
198
|
-
|
|
209
|
+
if (!required)
|
|
210
|
+
return { fromFlag: false, source: "none", note: "runs are not signed: there is no runner key. To verify who ran a job, add one with chant ci serve --setup-key --trust" };
|
|
211
|
+
throw new CiRunError(`${optIn}, and there is no runner key: no --key, no CHANT_RUNNER_KEY and no ${source}. Make one with chant ci serve --setup-key and list it with --trust`);
|
|
199
212
|
}
|
|
200
213
|
let publicKey;
|
|
201
214
|
try {
|
|
@@ -205,12 +218,19 @@ export function ciServeRunnerKey(req) {
|
|
|
205
218
|
throw new CiRunError(`the runner key from ${source} is not an Ed25519 private key in PEM: ${message(err)}`);
|
|
206
219
|
}
|
|
207
220
|
const head = targetHead(req.top, req.branch);
|
|
208
|
-
if (!head)
|
|
209
|
-
|
|
221
|
+
if (!head) {
|
|
222
|
+
const why = `there is no branch ${req.branch} here or on origin, so the runner key can't be checked against its .chant/trust.json`;
|
|
223
|
+
if (required)
|
|
224
|
+
throw new CiRunError(`${optIn}, and ${why}; fetch it`);
|
|
225
|
+
return { fromFlag: false, source, warning: `${why}, so runs are not signed; fetch it to sign them` };
|
|
226
|
+
}
|
|
210
227
|
const listed = runnerKeyListed(req.top, head.commit, pem);
|
|
211
228
|
if (!listed.ok) {
|
|
212
|
-
|
|
213
|
-
|
|
229
|
+
const why = `the runner key from ${source} is not trusted at ${branchAt(req.branch, head.commit)}: ${listed.reason}`;
|
|
230
|
+
const fix = `List it on a branch for review with chant ci serve --setup-key --trust, or run ${trustCommand(defaultRunnerPrincipal(), publicKey)} in a checkout of ${req.branch} and merge the change.`;
|
|
231
|
+
if (required)
|
|
232
|
+
throw new CiRunError(`${optIn}, and ${why}\n ${fix}`);
|
|
233
|
+
return { fromFlag: false, source, warning: `${why}. Runs are not signed until it is. ${fix}` };
|
|
214
234
|
}
|
|
215
235
|
return { pem, fromFlag: req.keyFile !== undefined, source };
|
|
216
236
|
}
|