@intentius/chant-lexicon-terraform 0.124.52 → 0.124.55
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/README.md +14 -10
- package/dist/__fixtures__/pr-loop/estate.component.d.ts +7 -0
- package/dist/__fixtures__/pr-loop/estate.component.d.ts.map +1 -0
- package/dist/__fixtures__/pr-loop/estate.component.js +7 -0
- package/dist/__fixtures__/report/generate.d.ts +26 -0
- package/dist/__fixtures__/report/generate.d.ts.map +1 -0
- package/dist/__fixtures__/report/generate.js +58 -0
- package/dist/applied-state.d.ts +27 -0
- package/dist/applied-state.d.ts.map +1 -0
- package/dist/applied-state.js +44 -0
- package/dist/backend-config.d.ts +53 -0
- package/dist/backend-config.d.ts.map +1 -0
- package/dist/backend-config.js +136 -0
- package/dist/behaviour/kinds.d.ts.map +1 -1
- package/dist/behaviour/kinds.js +4 -0
- package/dist/behaviour/predict.d.ts.map +1 -1
- package/dist/behaviour/predict.js +6 -2
- package/dist/behaviour/reference-catalog.d.ts +16 -5
- package/dist/behaviour/reference-catalog.d.ts.map +1 -1
- package/dist/behaviour/reference-catalog.js +16 -5
- package/dist/behaviour/request.d.ts.map +1 -1
- package/dist/behaviour/request.js +3 -2
- package/dist/changed-roots.d.ts +6 -4
- package/dist/changed-roots.d.ts.map +1 -1
- package/dist/changed-roots.js +14 -18
- package/dist/ci-setup.d.ts +11 -0
- package/dist/ci-setup.d.ts.map +1 -0
- package/dist/ci-setup.js +41 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/components/capability-plugin.d.ts +105 -9
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/capability-plugin.js +357 -36
- package/dist/components/compose-group.d.ts +145 -0
- package/dist/components/compose-group.d.ts.map +1 -0
- package/dist/components/compose-group.js +407 -0
- package/dist/components/placeholder-preview.d.ts +78 -0
- package/dist/components/placeholder-preview.d.ts.map +1 -0
- package/dist/components/placeholder-preview.js +254 -0
- package/dist/components/release-inputs.d.ts +29 -0
- package/dist/components/release-inputs.d.ts.map +1 -0
- package/dist/components/release-inputs.js +57 -0
- package/dist/components/trace-facts.d.ts +16 -0
- package/dist/components/trace-facts.d.ts.map +1 -0
- package/dist/components/trace-facts.js +19 -0
- package/dist/compose/apply-events.d.ts +46 -0
- package/dist/compose/apply-events.d.ts.map +1 -0
- package/dist/compose/apply-events.js +77 -0
- package/dist/compose/estate.d.ts +194 -0
- package/dist/compose/estate.d.ts.map +1 -0
- package/dist/compose/estate.js +363 -0
- package/dist/compose/hcl.d.ts +99 -0
- package/dist/compose/hcl.d.ts.map +1 -0
- package/dist/compose/hcl.js +302 -0
- package/dist/compose/module-address.d.ts +24 -0
- package/dist/compose/module-address.d.ts.map +1 -0
- package/dist/compose/module-address.js +43 -0
- package/dist/compose/root.d.ts +127 -0
- package/dist/compose/root.d.ts.map +1 -0
- package/dist/compose/root.js +586 -0
- package/dist/compose/run.d.ts +183 -0
- package/dist/compose/run.d.ts.map +1 -0
- package/dist/compose/run.js +447 -0
- package/dist/compose/slice.d.ts +102 -0
- package/dist/compose/slice.d.ts.map +1 -0
- package/dist/compose/slice.js +249 -0
- package/dist/compose/state-address.d.ts +28 -0
- package/dist/compose/state-address.d.ts.map +1 -0
- package/dist/compose/state-address.js +154 -0
- package/dist/compose/state-merge.d.ts +52 -0
- package/dist/compose/state-merge.d.ts.map +1 -0
- package/dist/compose/state-merge.js +135 -0
- package/dist/compose.d.ts +179 -0
- package/dist/compose.d.ts.map +1 -0
- package/dist/compose.js +482 -0
- package/dist/composites/terraform-apply-op.d.ts.map +1 -1
- package/dist/composites/terraform-apply-op.js +7 -3
- package/dist/cone.d.ts +53 -0
- package/dist/cone.d.ts.map +1 -0
- package/dist/cone.js +119 -0
- package/dist/config.d.ts +59 -13
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +43 -9
- package/dist/cost-hold.d.ts +27 -0
- package/dist/cost-hold.d.ts.map +1 -0
- package/dist/cost-hold.js +21 -0
- package/dist/describe-resources.d.ts +74 -12
- package/dist/describe-resources.d.ts.map +1 -1
- package/dist/describe-resources.js +374 -66
- package/dist/drift-read.d.ts +33 -0
- package/dist/drift-read.d.ts.map +1 -0
- package/dist/drift-read.js +243 -0
- package/dist/drift-record.d.ts +147 -0
- package/dist/drift-record.d.ts.map +1 -0
- package/dist/drift-record.js +383 -0
- package/dist/drift-rows.d.ts +61 -0
- package/dist/drift-rows.d.ts.map +1 -0
- package/dist/drift-rows.js +108 -0
- package/dist/exit-codes.d.ts +55 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +48 -0
- package/dist/hcl/edges.d.ts.map +1 -1
- package/dist/hcl/edges.js +24 -1
- package/dist/hcl/files.d.ts +61 -0
- package/dist/hcl/files.d.ts.map +1 -0
- package/dist/hcl/files.js +221 -0
- package/dist/hcl/instances.d.ts +82 -0
- package/dist/hcl/instances.d.ts.map +1 -0
- package/dist/hcl/instances.js +390 -0
- package/dist/hcl/parse.d.ts +81 -9
- package/dist/hcl/parse.d.ts.map +1 -1
- package/dist/hcl/parse.js +114 -16
- package/dist/hcl/roots.d.ts.map +1 -1
- package/dist/hcl/roots.js +5 -0
- package/dist/hcl/suppressions.d.ts.map +1 -1
- package/dist/hcl/suppressions.js +8 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -2
- package/dist/integrity.json +8 -5
- package/dist/lint/audit-catalog.d.ts.map +1 -1
- package/dist/lint/audit-catalog.js +27 -3
- package/dist/lint/audit-lineage.d.ts +14 -2
- package/dist/lint/audit-lineage.d.ts.map +1 -1
- package/dist/lint/post-synth/index.d.ts.map +1 -1
- package/dist/lint/post-synth/index.js +4 -0
- package/dist/lint/post-synth/record-store.d.ts +54 -0
- package/dist/lint/post-synth/record-store.d.ts.map +1 -0
- package/dist/lint/post-synth/record-store.js +104 -0
- package/dist/lint/post-synth/tf001.d.ts +2 -2
- package/dist/lint/post-synth/tf001.js +2 -2
- package/dist/lint/post-synth/tf024.d.ts +35 -11
- package/dist/lint/post-synth/tf024.d.ts.map +1 -1
- package/dist/lint/post-synth/tf024.js +92 -20
- package/dist/lint/post-synth/tf046.d.ts +64 -0
- package/dist/lint/post-synth/tf046.d.ts.map +1 -0
- package/dist/lint/post-synth/tf046.js +175 -0
- package/dist/lint/post-synth/tf047.d.ts +36 -0
- package/dist/lint/post-synth/tf047.d.ts.map +1 -0
- package/dist/lint/post-synth/tf047.js +94 -0
- package/dist/live-plan-reasons.d.ts +21 -0
- package/dist/live-plan-reasons.d.ts.map +1 -0
- package/dist/live-plan-reasons.js +47 -0
- package/dist/lock-rows.d.ts +36 -0
- package/dist/lock-rows.d.ts.map +1 -0
- package/dist/lock-rows.js +60 -0
- package/dist/lock-timeout.d.ts +22 -0
- package/dist/lock-timeout.d.ts.map +1 -0
- package/dist/lock-timeout.js +32 -0
- package/dist/lsp/option-keys.d.ts.map +1 -1
- package/dist/lsp/option-keys.js +2 -0
- package/dist/manifest.json +1 -1
- package/dist/module-catalog/index.d.ts +69 -0
- package/dist/module-catalog/index.d.ts.map +1 -0
- package/dist/module-catalog/index.js +110 -0
- package/dist/module-catalog/refresh-cli.d.ts +4 -0
- package/dist/module-catalog/refresh-cli.d.ts.map +1 -0
- package/dist/module-catalog/refresh-cli.js +64 -0
- package/dist/module-catalog/static-tier.d.ts +6 -0
- package/dist/module-catalog/static-tier.d.ts.map +1 -0
- package/dist/module-catalog/static-tier.js +1650 -0
- package/dist/module-catalog/types.d.ts +65 -0
- package/dist/module-catalog/types.d.ts.map +1 -0
- package/dist/module-catalog/types.js +33 -0
- package/dist/okf/index.md +3 -1
- package/dist/okf/rules/TF024.md +2 -2
- package/dist/okf/rules/TF046.md +11 -0
- package/dist/okf/rules/TF047.md +11 -0
- package/dist/op/activities/index.d.ts +6 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +5 -1
- package/dist/op/activities/live-detect.d.ts +4 -3
- package/dist/op/activities/live-detect.d.ts.map +1 -1
- package/dist/op/activities/live-detect.js +57 -32
- package/dist/op/activities/pin-rollout.d.ts +2 -0
- package/dist/op/activities/pin-rollout.d.ts.map +1 -1
- package/dist/op/activities/pin-rollout.js +1 -0
- package/dist/op/activities/terraform.d.ts +182 -5
- package/dist/op/activities/terraform.d.ts.map +1 -1
- package/dist/op/activities/terraform.js +224 -24
- package/dist/op/activity-contracts.d.ts +27 -0
- package/dist/op/activity-contracts.d.ts.map +1 -1
- package/dist/op/activity-contracts.js +19 -1
- package/dist/op/builders.d.ts +7 -1
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -0
- package/dist/pin/consumers.d.ts +35 -0
- package/dist/pin/consumers.d.ts.map +1 -0
- package/dist/pin/consumers.js +70 -0
- package/dist/pin/edit.d.ts.map +1 -1
- package/dist/pin/edit.js +35 -0
- package/dist/pin/rollout.d.ts +2 -0
- package/dist/pin/rollout.d.ts.map +1 -1
- package/dist/pin/rollout.js +14 -11
- package/dist/plan-shape.d.ts +30 -0
- package/dist/plan-shape.d.ts.map +1 -0
- package/dist/plan-shape.js +125 -0
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +37 -18
- package/dist/registry/address.d.ts +63 -0
- package/dist/registry/address.d.ts.map +1 -0
- package/dist/registry/address.js +65 -0
- package/dist/registry/catalog-read.d.ts +14 -0
- package/dist/registry/catalog-read.d.ts.map +1 -0
- package/dist/registry/catalog-read.js +58 -0
- package/dist/registry/deprecated.d.ts +37 -0
- package/dist/registry/deprecated.d.ts.map +1 -0
- package/dist/registry/deprecated.js +43 -0
- package/dist/registry/docs.d.ts +96 -0
- package/dist/registry/docs.d.ts.map +1 -0
- package/dist/registry/docs.js +210 -0
- package/dist/registry/edge/edge.d.ts +46 -0
- package/dist/registry/edge/edge.d.ts.map +1 -0
- package/dist/registry/edge/edge.js +194 -0
- package/dist/registry/edge/index.d.ts +11 -0
- package/dist/registry/edge/index.d.ts.map +1 -0
- package/dist/registry/edge/index.js +10 -0
- package/dist/registry/edge/lambda-edge.d.ts +76 -0
- package/dist/registry/edge/lambda-edge.d.ts.map +1 -0
- package/dist/registry/edge/lambda-edge.js +95 -0
- package/dist/registry/edge/sigv4-web.d.ts +33 -0
- package/dist/registry/edge/sigv4-web.d.ts.map +1 -0
- package/dist/registry/edge/sigv4-web.js +56 -0
- package/dist/registry/edge/token-source.d.ts +73 -0
- package/dist/registry/edge/token-source.d.ts.map +1 -0
- package/dist/registry/edge/token-source.js +115 -0
- package/dist/registry/edge/worker.d.ts +45 -0
- package/dist/registry/edge/worker.d.ts.map +1 -0
- package/dist/registry/edge/worker.js +26 -0
- package/dist/registry/handler.d.ts +25 -0
- package/dist/registry/handler.d.ts.map +1 -0
- package/dist/registry/handler.js +75 -0
- package/dist/registry/headers-file.d.ts +21 -0
- package/dist/registry/headers-file.d.ts.map +1 -0
- package/dist/registry/headers-file.js +57 -0
- package/dist/registry/index.d.ts +31 -0
- package/dist/registry/index.d.ts.map +1 -0
- package/dist/registry/index.js +30 -0
- package/dist/registry/mirror-paths.d.ts +9 -0
- package/dist/registry/mirror-paths.d.ts.map +1 -0
- package/dist/registry/mirror-paths.js +8 -0
- package/dist/registry/mirror.d.ts +130 -0
- package/dist/registry/mirror.d.ts.map +1 -0
- package/dist/registry/mirror.js +319 -0
- package/dist/registry/proxies.d.ts +73 -0
- package/dist/registry/proxies.d.ts.map +1 -0
- package/dist/registry/proxies.js +111 -0
- package/dist/registry/reader.d.ts +57 -0
- package/dist/registry/reader.d.ts.map +1 -0
- package/dist/registry/reader.js +198 -0
- package/dist/registry/semver.d.ts +16 -0
- package/dist/registry/semver.d.ts.map +1 -0
- package/dist/registry/semver.js +24 -0
- package/dist/registry/serve.d.ts +24 -0
- package/dist/registry/serve.d.ts.map +1 -0
- package/dist/registry/serve.js +64 -0
- package/dist/registry/source-forms.d.ts +79 -0
- package/dist/registry/source-forms.d.ts.map +1 -0
- package/dist/registry/source-forms.js +202 -0
- package/dist/registry/targets/artifactory.d.ts +28 -0
- package/dist/registry/targets/artifactory.d.ts.map +1 -0
- package/dist/registry/targets/artifactory.js +206 -0
- package/dist/registry/targets/fake-artifactory.d.ts +30 -0
- package/dist/registry/targets/fake-artifactory.d.ts.map +1 -0
- package/dist/registry/targets/fake-artifactory.js +142 -0
- package/dist/registry/targets/fake-gitlab.d.ts +39 -0
- package/dist/registry/targets/fake-gitlab.d.ts.map +1 -0
- package/dist/registry/targets/fake-gitlab.js +136 -0
- package/dist/registry/targets/fake-hcp.d.ts +50 -0
- package/dist/registry/targets/fake-hcp.d.ts.map +1 -0
- package/dist/registry/targets/fake-hcp.js +202 -0
- package/dist/registry/targets/fake-http.d.ts +31 -0
- package/dist/registry/targets/fake-http.d.ts.map +1 -0
- package/dist/registry/targets/fake-http.js +87 -0
- package/dist/registry/targets/fake-nexus.d.ts +27 -0
- package/dist/registry/targets/fake-nexus.d.ts.map +1 -0
- package/dist/registry/targets/fake-nexus.js +137 -0
- package/dist/registry/targets/gitlab.d.ts +53 -0
- package/dist/registry/targets/gitlab.d.ts.map +1 -0
- package/dist/registry/targets/gitlab.js +187 -0
- package/dist/registry/targets/hcp.d.ts +29 -0
- package/dist/registry/targets/hcp.d.ts.map +1 -0
- package/dist/registry/targets/hcp.js +310 -0
- package/dist/registry/targets/hosted.d.ts +62 -0
- package/dist/registry/targets/hosted.d.ts.map +1 -0
- package/dist/registry/targets/hosted.js +74 -0
- package/dist/registry/targets/index.d.ts +18 -0
- package/dist/registry/targets/index.d.ts.map +1 -0
- package/dist/registry/targets/index.js +17 -0
- package/dist/registry/targets/module-target.d.ts +68 -0
- package/dist/registry/targets/module-target.d.ts.map +1 -0
- package/dist/registry/targets/module-target.js +63 -0
- package/dist/registry/targets/nexus.d.ts +43 -0
- package/dist/registry/targets/nexus.d.ts.map +1 -0
- package/dist/registry/targets/nexus.js +250 -0
- package/dist/registry/targets/zip.d.ts +55 -0
- package/dist/registry/targets/zip.d.ts.map +1 -0
- package/dist/registry/targets/zip.js +278 -0
- package/dist/registry/writer.d.ts +101 -0
- package/dist/registry/writer.d.ts.map +1 -0
- package/dist/registry/writer.js +109 -0
- package/dist/report.d.ts +15 -6
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +28 -55
- package/dist/rules/record-store.ts +122 -0
- package/dist/rules/tf001.ts +2 -2
- package/dist/rules/tf024.ts +105 -22
- package/dist/rules/tf046.ts +204 -0
- package/dist/rules/tf047.ts +114 -0
- package/dist/skills/chant-terraform.md +1 -1
- package/dist/state/azure-blob.d.ts +9 -0
- package/dist/state/azure-blob.d.ts.map +1 -0
- package/dist/state/azure-blob.js +8 -0
- package/dist/state/backend.d.ts +158 -0
- package/dist/state/backend.d.ts.map +1 -0
- package/dist/state/backend.js +406 -0
- package/dist/state/exec.d.ts +39 -0
- package/dist/state/exec.d.ts.map +1 -0
- package/dist/state/exec.js +80 -0
- package/dist/state/gcs.d.ts +8 -0
- package/dist/state/gcs.d.ts.map +1 -0
- package/dist/state/gcs.js +7 -0
- package/dist/state/index.d.ts +15 -0
- package/dist/state/index.d.ts.map +1 -0
- package/dist/state/index.js +14 -0
- package/dist/state/locks.d.ts +105 -0
- package/dist/state/locks.d.ts.map +1 -0
- package/dist/state/locks.js +130 -0
- package/dist/state/object-store.d.ts +8 -0
- package/dist/state/object-store.d.ts.map +1 -0
- package/dist/state/object-store.js +7 -0
- package/dist/state/root-states.d.ts +131 -0
- package/dist/state/root-states.d.ts.map +1 -0
- package/dist/state/root-states.js +241 -0
- package/dist/state/s3.d.ts +21 -0
- package/dist/state/s3.d.ts.map +1 -0
- package/dist/state/s3.js +19 -0
- package/dist/state/store.d.ts +51 -0
- package/dist/state/store.d.ts.map +1 -0
- package/dist/state/store.js +185 -0
- package/dist/state-ops.d.ts +255 -0
- package/dist/state-ops.d.ts.map +1 -0
- package/dist/state-ops.js +305 -0
- package/dist/state-reads.d.ts +57 -0
- package/dist/state-reads.d.ts.map +1 -0
- package/dist/state-reads.js +104 -0
- package/dist/terragrunt/affected.d.ts.map +1 -1
- package/dist/terragrunt/affected.js +2 -1
- package/dist/used-sources.d.ts +54 -0
- package/dist/used-sources.d.ts.map +1 -0
- package/dist/used-sources.js +157 -0
- package/package.json +24 -4
- package/src/__fixtures__/ACCEPTANCE.md +69 -7
- package/src/__fixtures__/compose/apply-failed-in-app.jsonl +12 -0
- package/src/__fixtures__/compose/state-app.json +66 -0
- package/src/__fixtures__/compose/state-edge.json +40 -0
- package/src/__fixtures__/compose/state-net.json +58 -0
- package/src/__fixtures__/compose/three-app.plan.json +184 -0
- package/src/__fixtures__/compose/three-composed.plan.json +509 -0
- package/src/__fixtures__/compose/three-edge.plan.json +144 -0
- package/src/__fixtures__/compose/three-net.plan.json +174 -0
- package/src/__fixtures__/compose/unknown-composed.plan.json +228 -0
- package/src/__fixtures__/compose/working-after-apply.json +145 -0
- package/src/__fixtures__/config-blocks/app/main.tf +61 -0
- package/src/__fixtures__/config-blocks/app/modules/network/main.tf +4 -0
- package/src/__fixtures__/config-blocks/app-json/main.tf.json +39 -0
- package/src/__fixtures__/config-files/shadow/main.tf +3 -0
- package/src/__fixtures__/config-files/shadow/main.tofu +3 -0
- package/src/__fixtures__/config-files/shadow/other.tf +3 -0
- package/src/__fixtures__/config-files/tf/main.tf +11 -0
- package/src/__fixtures__/config-files/tf-json/main.tf.json +18 -0
- package/src/__fixtures__/config-files/tofu/main.tofu +11 -0
- package/src/__fixtures__/config-files/tofu-json/main.tofu.json +18 -0
- package/src/__fixtures__/config-files/tofu-only/main.tofu +3 -0
- package/src/__fixtures__/drift-record/README.md +16 -0
- package/src/__fixtures__/drift-record/live-plan-sections.json +27 -0
- package/src/__fixtures__/drift-rows/live-root-plan.json +70 -0
- package/src/__fixtures__/drift-rows/refresh-plan.json +61 -0
- package/src/__fixtures__/instance-forms/app/main.tf +110 -0
- package/src/__fixtures__/instance-forms/app/modules/svc/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/main.tf +52 -0
- package/src/__fixtures__/instance-vars/app/modules/app/main.tf +12 -0
- package/src/__fixtures__/instance-vars/app/modules/edge/main.tf +3 -0
- package/src/__fixtures__/instance-vars/app/terraform.tfvars +1 -0
- package/src/__fixtures__/live-module-keyed/live-graph.json +259 -0
- package/src/__fixtures__/live-module-keyed/live-plan.json +87 -0
- package/src/__fixtures__/live-module-keyed/root/estate.chdf.hcl +1 -0
- package/src/__fixtures__/live-module-keyed/root/main.tf +21 -0
- package/src/__fixtures__/live-module-keyed/root/modules/app/main.tf +17 -0
- package/src/__fixtures__/live-module-keyed/root/modules/edge/main.tf +7 -0
- package/src/__fixtures__/live-module-keyed/root/versions.tf +30 -0
- package/src/__fixtures__/live-module-keyed/show-state.json +146 -0
- package/src/__fixtures__/pr-loop/README.md +50 -0
- package/src/__fixtures__/pr-loop/chant.config.json +13 -0
- package/src/__fixtures__/pr-loop/estate.component.ts +10 -0
- package/src/__fixtures__/pr-loop/roots/a/main.tf +11 -0
- package/src/__fixtures__/pr-loop/roots/app/main.tf +19 -0
- package/src/__fixtures__/pr-loop/roots/b/main.tf +7 -0
- package/src/__fixtures__/pr-loop/roots/dns/main.tf +3 -0
- package/src/__fixtures__/pr-loop/roots/net/main.tf +7 -0
- package/src/__fixtures__/report/applied.show.json +51 -0
- package/src/__fixtures__/report/generate.ts +63 -0
- package/src/__fixtures__/report/plan.show.json +200 -0
- package/src/__fixtures__/report/tf-apply/change-set.json +170 -0
- package/src/__fixtures__/report/tf-apply/report.json +338 -0
- package/src/__fixtures__/report/tf-plan/change-set.json +170 -0
- package/src/__fixtures__/report/tf-plan/report.json +320 -0
- package/src/__fixtures__/three-cloud-azure.graph.json +290 -0
- package/src/__fixtures__/used-sources/root/extra.tofu +1 -0
- package/src/__fixtures__/used-sources/root/main.tf +31 -0
- package/src/__fixtures__/used-sources/root/modules/net/main.tf +14 -0
- package/src/__fixtures__/used-sources/root/modules/net/versions.tf.json +7 -0
- package/src/__fixtures__/used-sources/unit/terragrunt.hcl +3 -0
- package/src/applied-state.ts +52 -0
- package/src/backend-config.test.ts +105 -0
- package/src/backend-config.ts +133 -0
- package/src/behaviour/kinds.ts +4 -0
- package/src/behaviour/predict.ts +5 -2
- package/src/behaviour/reference-catalog.plugin.test.ts +65 -0
- package/src/behaviour/reference-catalog.ts +16 -5
- package/src/behaviour/request.ts +3 -2
- package/src/change-set-instances.test.ts +98 -0
- package/src/changed-roots.ts +14 -16
- package/src/ci-setup.ts +42 -0
- package/src/commands.ts +4 -3
- package/src/components/capability-plugin.test.ts +198 -19
- package/src/components/capability-plugin.ts +383 -35
- package/src/components/change-set-graph.e2e.test.ts +11 -5
- package/src/components/compose-group.test.ts +486 -0
- package/src/components/compose-group.ts +489 -0
- package/src/components/demo-composed-roots.e2e.test.ts +440 -0
- package/src/components/member-outputs.test.ts +76 -0
- package/src/components/placeholder-preview.test.ts +147 -0
- package/src/components/placeholder-preview.ts +257 -0
- package/src/components/pr-loop-compose.tofu.e2e.test.ts +363 -0
- package/src/components/pr-loop.tofu.test.ts +113 -57
- package/src/components/release-inputs.ts +69 -0
- package/src/components/trace-facts.test.ts +21 -0
- package/src/components/trace-facts.ts +27 -0
- package/src/compose/apply-events.test.ts +62 -0
- package/src/compose/apply-events.ts +100 -0
- package/src/compose/estate.choudoufu.e2e.test.ts +112 -0
- package/src/compose/estate.test.ts +421 -0
- package/src/compose/estate.ts +443 -0
- package/src/compose/hcl.ts +311 -0
- package/src/compose/module-address.ts +49 -0
- package/src/compose/root.test.ts +416 -0
- package/src/compose/root.ts +592 -0
- package/src/compose/run.test.ts +440 -0
- package/src/compose/run.tofu.test.ts +176 -0
- package/src/compose/run.ts +527 -0
- package/src/compose/slice.test.ts +184 -0
- package/src/compose/slice.ts +290 -0
- package/src/compose/state-address.ts +157 -0
- package/src/compose/state-merge.test.ts +131 -0
- package/src/compose/state-merge.ts +148 -0
- package/src/compose.test.ts +248 -0
- package/src/compose.ts +627 -0
- package/src/composites/terraform-apply-op.test.ts +9 -0
- package/src/composites/terraform-apply-op.ts +7 -3
- package/src/cone.ts +138 -0
- package/src/config-file-listers.test.ts +265 -0
- package/src/config.ts +44 -9
- package/src/cost-hold.ts +29 -0
- package/src/describe-resources.engine-facts.test.ts +411 -0
- package/src/describe-resources.live-module-keyed.test.ts +290 -0
- package/src/describe-resources.ts +416 -70
- package/src/drift-read.ts +284 -0
- package/src/drift-record.test.ts +223 -0
- package/src/drift-record.ts +455 -0
- package/src/drift-rows.test.ts +135 -0
- package/src/drift-rows.ts +137 -0
- package/src/exit-codes.test.ts +23 -0
- package/src/exit-codes.ts +59 -0
- package/src/hcl/config-blocks.test.ts +174 -0
- package/src/hcl/edges.ts +21 -1
- package/src/hcl/files.ts +234 -0
- package/src/hcl/instance-forms.test.ts +94 -0
- package/src/hcl/instances.test.ts +137 -0
- package/src/hcl/instances.ts +422 -0
- package/src/hcl/parse.test.ts +139 -1
- package/src/hcl/parse.ts +149 -16
- package/src/hcl/roots.ts +6 -0
- package/src/hcl/suppressions.ts +8 -2
- package/src/index.ts +79 -0
- package/src/lint/audit-catalog.ts +29 -3
- package/src/lint/audit-lineage.ts +14 -2
- package/src/lint/post-synth/fixtures/TF024/live-with-record-store/main.tf +18 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF024/sidecar-with-backend/main.tf +10 -0
- package/src/lint/post-synth/fixtures/TF046/azurerm-no-resource-group/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/backend-config-only/main.tf +14 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/backend.tf +7 -0
- package/src/lint/post-synth/fixtures/TF046/derived-s3/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-local/main.tf +16 -0
- package/src/lint/post-synth/fixtures/TF046/explicit-s3-beside-local-backend/main.tf +15 -0
- package/src/lint/post-synth/fixtures/TF046/implied-local/main.tf +9 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/estate.chdf.hcl +1 -0
- package/src/lint/post-synth/fixtures/TF046/sidecar-implied/main.tf +5 -0
- package/src/lint/post-synth/fixtures/TF047/clear/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/refused/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-module/main.tf +12 -0
- package/src/lint/post-synth/fixtures/TF047/unknown-version/main.tf +12 -0
- package/src/lint/post-synth/index.ts +4 -0
- package/src/lint/post-synth/record-store.ts +122 -0
- package/src/lint/post-synth/tf001.ts +2 -2
- package/src/lint/post-synth/tf024.test.ts +26 -5
- package/src/lint/post-synth/tf024.ts +105 -22
- package/src/lint/post-synth/tf046.test.ts +137 -0
- package/src/lint/post-synth/tf046.ts +204 -0
- package/src/lint/post-synth/tf047.test.ts +56 -0
- package/src/lint/post-synth/tf047.ts +114 -0
- package/src/live-plan-reasons.ts +54 -0
- package/src/lock-rows.test.ts +70 -0
- package/src/lock-rows.ts +82 -0
- package/src/lock-timeout.ts +34 -0
- package/src/lsp/completions.test.ts +1 -1
- package/src/lsp/option-keys.ts +2 -0
- package/src/module-catalog/index.test.ts +93 -0
- package/src/module-catalog/index.ts +159 -0
- package/src/module-catalog/refresh-cli.ts +68 -0
- package/src/module-catalog/static-tier.ts +1659 -0
- package/src/module-catalog/types.ts +88 -0
- package/src/op/activities/choudoufu-plan-set-op.test.ts +111 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/live-detect.ts +55 -26
- package/src/op/activities/pin-rollout.ts +3 -0
- package/src/op/activities/registry.test.ts +2 -1
- package/src/op/activities/terraform.test.ts +55 -0
- package/src/op/activities/terraform.ts +312 -27
- package/src/op/activity-contracts.test.ts +1 -0
- package/src/op/activity-contracts.ts +24 -1
- package/src/op/builders.ts +14 -0
- package/src/op-wave-step.test.ts +109 -0
- package/src/pin/__fixtures__/consumers/live/dev/main.tf +4 -0
- package/src/pin/__fixtures__/consumers/live/prod/main.tf +21 -0
- package/src/pin/__fixtures__/consumers/units/vpc/terragrunt.hcl +7 -0
- package/src/pin/bundle.test.ts +2 -0
- package/src/pin/consumers.test.ts +57 -0
- package/src/pin/consumers.ts +95 -0
- package/src/pin/edit.ts +30 -0
- package/src/pin/rollout.ts +16 -11
- package/src/plan-shape.test.ts +148 -0
- package/src/plan-shape.ts +128 -0
- package/src/plugin.ts +39 -19
- package/src/registry/__fixtures__/docs/documented/.terraform-docs.yml +3 -0
- package/src/registry/__fixtures__/docs/documented/README.md +1 -0
- package/src/registry/__fixtures__/docs/documented/main.tf +8 -0
- package/src/registry/__fixtures__/docs/json/main.tf.json +14 -0
- package/src/registry/__fixtures__/docs/vpc/README.md +3 -0
- package/src/registry/__fixtures__/docs/vpc/examples/complete/main.tf +5 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/README.md +1 -0
- package/src/registry/__fixtures__/docs/vpc/examples/simple/main.tf +4 -0
- package/src/registry/__fixtures__/docs/vpc/main.tf +14 -0
- package/src/registry/__fixtures__/docs/vpc/outputs.tf +9 -0
- package/src/registry/__fixtures__/docs/vpc/variables.tf +16 -0
- package/src/registry/__fixtures__/proxied-root/main.tf +12 -0
- package/src/registry/address.ts +100 -0
- package/src/registry/catalog-read.ts +56 -0
- package/src/registry/deprecated.test.ts +139 -0
- package/src/registry/deprecated.ts +76 -0
- package/src/registry/docs.test.ts +140 -0
- package/src/registry/docs.ts +299 -0
- package/src/registry/edge/bundle.test.ts +50 -0
- package/src/registry/edge/edge.test.ts +176 -0
- package/src/registry/edge/edge.ts +211 -0
- package/src/registry/edge/index.ts +10 -0
- package/src/registry/edge/lambda-edge.ts +127 -0
- package/src/registry/edge/sigv4-web.ts +79 -0
- package/src/registry/edge/token-source.test.ts +258 -0
- package/src/registry/edge/token-source.ts +169 -0
- package/src/registry/edge/worker.ts +61 -0
- package/src/registry/handler.ts +89 -0
- package/src/registry/headers-file.ts +61 -0
- package/src/registry/index.ts +31 -0
- package/src/registry/mirror-paths.ts +10 -0
- package/src/registry/mirror.test.ts +198 -0
- package/src/registry/mirror.ts +395 -0
- package/src/registry/proxies.test.ts +153 -0
- package/src/registry/proxies.ts +132 -0
- package/src/registry/reader.ts +225 -0
- package/src/registry/registry.test.ts +262 -0
- package/src/registry/semver.ts +34 -0
- package/src/registry/serve.ts +82 -0
- package/src/registry/source-forms.test.ts +87 -0
- package/src/registry/source-forms.ts +216 -0
- package/src/registry/targets/artifactory.test.ts +248 -0
- package/src/registry/targets/artifactory.ts +257 -0
- package/src/registry/targets/fake-artifactory.ts +158 -0
- package/src/registry/targets/fake-gitlab.ts +161 -0
- package/src/registry/targets/fake-hcp.ts +233 -0
- package/src/registry/targets/fake-http.ts +97 -0
- package/src/registry/targets/fake-nexus.ts +152 -0
- package/src/registry/targets/gitlab.test.ts +208 -0
- package/src/registry/targets/gitlab.ts +223 -0
- package/src/registry/targets/hcp.test.ts +230 -0
- package/src/registry/targets/hcp.ts +360 -0
- package/src/registry/targets/hosted.ts +117 -0
- package/src/registry/targets/index.ts +17 -0
- package/src/registry/targets/module-target.ts +131 -0
- package/src/registry/targets/nexus.test.ts +220 -0
- package/src/registry/targets/nexus.ts +314 -0
- package/src/registry/targets/zip.test.ts +65 -0
- package/src/registry/targets/zip.ts +287 -0
- package/src/registry/writer.ts +155 -0
- package/src/report.test.ts +82 -1
- package/src/report.ts +31 -54
- package/src/signal-only-root.test.ts +72 -0
- package/src/skills/chant-terraform.md +1 -1
- package/src/state/azure-blob.ts +8 -0
- package/src/state/backend-verdict.test.ts +187 -0
- package/src/state/backend.test.ts +127 -0
- package/src/state/backend.ts +488 -0
- package/src/state/exec.ts +111 -0
- package/src/state/gcs.ts +7 -0
- package/src/state/index.ts +15 -0
- package/src/state/locks.test.ts +84 -0
- package/src/state/locks.ts +201 -0
- package/src/state/object-store.ts +7 -0
- package/src/state/root-states-floci.e2e.test.ts +66 -0
- package/src/state/root-states.test.ts +462 -0
- package/src/state/root-states.ts +309 -0
- package/src/state/s3.ts +21 -0
- package/src/state/store.ts +225 -0
- package/src/state-ops.test.ts +182 -0
- package/src/state-ops.ts +462 -0
- package/src/state-reads.ts +116 -0
- package/src/terragrunt/affected.ts +2 -1
- package/src/used-sources.test.ts +75 -0
- package/src/used-sources.ts +204 -0
- package/src/workspace-kinds.test.ts +4 -17
- package/workspace-kinds.json +1 -24
- package/dist/workspace-member.d.ts +0 -30
- package/dist/workspace-member.d.ts.map +0 -1
- package/dist/workspace-member.js +0 -91
- package/schemas/pulumi.schema.json +0 -34
- package/src/testdata/pulumi-member/Pulumi.yaml +0 -2
- package/src/testdata/pulumi-member/stack-export.json +0 -53
- package/src/testdata/pulumi-unexported/Pulumi.yaml +0 -2
- package/src/workspace-member.test.ts +0 -89
- package/src/workspace-member.ts +0 -126
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the Artifactory and Nexus module targets share (chant#4605): basic
|
|
3
|
+
* `user:token` write credentials (terragucci#1299 ruling B), a binary GET of
|
|
4
|
+
* an uploaded archive, and the wait for a version to be listed after its
|
|
5
|
+
* upload, since both hosts index an upload after the PUT answers.
|
|
6
|
+
*/
|
|
7
|
+
import { readCredential } from "@intentius/chant/lifecycle/publish-credentials";
|
|
8
|
+
import { answerError, contentDigest } from "./module-target.js";
|
|
9
|
+
import { heldContentOf } from "./zip.js";
|
|
10
|
+
/** The basic credential the environment holds, added to the redactor, or null when either half is missing. */
|
|
11
|
+
export function readBasicCredential(ctx, names) {
|
|
12
|
+
const token = readCredential(ctx.env, [names.tokenEnv], ctx.redactor);
|
|
13
|
+
const user = names.user ?? ctx.env[names.userEnv];
|
|
14
|
+
if (!token || !user)
|
|
15
|
+
return null;
|
|
16
|
+
const encoded = Buffer.from(`${user}:${token.value}`, "utf-8").toString("base64");
|
|
17
|
+
ctx.redactor.add(encoded);
|
|
18
|
+
return { user, token, header: `Basic ${encoded}` };
|
|
19
|
+
}
|
|
20
|
+
/** The basic credential, or the refusal naming both variables. */
|
|
21
|
+
export function needBasicCredential(ctx, names, host, fix) {
|
|
22
|
+
const c = readBasicCredential(ctx, names);
|
|
23
|
+
if (c)
|
|
24
|
+
return c;
|
|
25
|
+
const missing = [...(ctx.env[names.tokenEnv] ? [] : [names.tokenEnv]), ...(names.user || ctx.env[names.userEnv] ? [] : [names.userEnv])];
|
|
26
|
+
throw answerError(ctx, "publish-credentials-missing", `no ${host} credentials: set ${missing.join(" and ")}`, fix);
|
|
27
|
+
}
|
|
28
|
+
/** The global fetch, in the reader's shape. */
|
|
29
|
+
export const defaultRegistryFetch = (url, init) => fetch(url, init);
|
|
30
|
+
/** A GET of bytes, with its status. A network failure is a `publish-read-failed`. */
|
|
31
|
+
export async function getBytes(ctx, fetchFn, url, authorization) {
|
|
32
|
+
let res;
|
|
33
|
+
try {
|
|
34
|
+
res = await fetchFn(url, { method: "GET", redirect: "follow", ...(authorization ? { headers: { Authorization: authorization } } : {}) });
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
throw answerError(ctx, "publish-read-failed", `GET ${url}: ${e.message}`);
|
|
38
|
+
}
|
|
39
|
+
return { status: res.status, bytes: new Uint8Array(await res.arrayBuffer()) };
|
|
40
|
+
}
|
|
41
|
+
export const HOSTED_LIST_WAIT_MS = 30000;
|
|
42
|
+
export const HOSTED_POLL_MS = 2000;
|
|
43
|
+
/** Reads `list` until it holds `version` or the wait is over; true when it was listed. */
|
|
44
|
+
export async function waitListed(list, version, wait) {
|
|
45
|
+
const start = wait.now();
|
|
46
|
+
for (;;) {
|
|
47
|
+
if ((await list()).includes(version))
|
|
48
|
+
return true;
|
|
49
|
+
if (wait.now() - start >= wait.waitMs)
|
|
50
|
+
return false;
|
|
51
|
+
await wait.sleep(wait.pollMs);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** The refusal for a 401 or 403 on an upload, naming the variables, never their values. */
|
|
55
|
+
export function writeRefused(ctx, host, status, what, credential, names, fix) {
|
|
56
|
+
const userFrom = names.user ? "the declaration's user" : names.userEnv;
|
|
57
|
+
return answerError(ctx, "publish-credentials-refused", `${host} answered ${status} to the upload of ${what}: it refused the user in ${userFrom} with the token in ${credential.token.from}`, fix);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The content of the archive a download location holds, as the CLIs would
|
|
61
|
+
* fetch it: the registry's credential goes along only to the registry's own
|
|
62
|
+
* host and only when the location has no query (a signed URL carries its own
|
|
63
|
+
* grant). Refuses a location that answers other than 2xx.
|
|
64
|
+
*/
|
|
65
|
+
export async function locationContent(ctx, fetchFn, location, registryHost, authorization) {
|
|
66
|
+
const u = new URL(location);
|
|
67
|
+
const auth = !u.search && u.host.toLowerCase() === registryHost.toLowerCase() ? authorization : undefined;
|
|
68
|
+
const { status, bytes } = await getBytes(ctx, fetchFn, location, auth);
|
|
69
|
+
if (status < 200 || status > 299)
|
|
70
|
+
throw answerError(ctx, "publish-read-failed", `${location.split("?")[0]} answered ${status} to the download a consumer would make`);
|
|
71
|
+
return heldContentOf(bytes, contentDigest);
|
|
72
|
+
}
|
|
73
|
+
/** The refusal for a download that holds other content than the version staged. */
|
|
74
|
+
export const revealMismatch = (ctx, where, version, got, want) => answerError(ctx, "publish-reveal-mismatch", `${where} ${version} downloads as ${got}, and this publish staged ${want}`, "Check which archive the repository holds for the version; a published version never changes.");
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module targets: publishing a module version to a hosted registry on chant
|
|
3
|
+
* core's publish-target contract (chant#4602): GitLab (chant#4603), HCP
|
|
4
|
+
* Terraform or Terraform Enterprise (chant#4604), and Artifactory and Nexus
|
|
5
|
+
* (chant#4605), which take the zip of the attested archive (./zip). The
|
|
6
|
+
* fakes the tests drive them with are at `registry/targets/fake-<host>`,
|
|
7
|
+
* with `fake-http` holding a module tarball builder, outside this index, so
|
|
8
|
+
* a product's tests can reach them without shipping them in its own code
|
|
9
|
+
* paths.
|
|
10
|
+
*/
|
|
11
|
+
export * from "./module-target.js";
|
|
12
|
+
export * from "./gitlab.js";
|
|
13
|
+
export * from "./hcp.js";
|
|
14
|
+
export * from "./zip.js";
|
|
15
|
+
export * from "./hosted.js";
|
|
16
|
+
export * from "./artifactory.js";
|
|
17
|
+
export * from "./nexus.js";
|
|
18
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/registry/targets/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,iBAAiB,CAAC;AAChC,cAAc,UAAU,CAAC;AACzB,cAAc,OAAO,CAAC;AACtB,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,SAAS,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module targets: publishing a module version to a hosted registry on chant
|
|
3
|
+
* core's publish-target contract (chant#4602): GitLab (chant#4603), HCP
|
|
4
|
+
* Terraform or Terraform Enterprise (chant#4604), and Artifactory and Nexus
|
|
5
|
+
* (chant#4605), which take the zip of the attested archive (./zip). The
|
|
6
|
+
* fakes the tests drive them with are at `registry/targets/fake-<host>`,
|
|
7
|
+
* with `fake-http` holding a module tarball builder, outside this index, so
|
|
8
|
+
* a product's tests can reach them without shipping them in its own code
|
|
9
|
+
* paths.
|
|
10
|
+
*/
|
|
11
|
+
export * from "./module-target.js";
|
|
12
|
+
export * from "./gitlab.js";
|
|
13
|
+
export * from "./hcp.js";
|
|
14
|
+
export * from "./zip.js";
|
|
15
|
+
export * from "./hosted.js";
|
|
16
|
+
export * from "./artifactory.js";
|
|
17
|
+
export * from "./nexus.js";
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { PublishTargetError, type PublishContextBase, type PublishDeps, type PublishFetch, type PublishTarget } from "@intentius/chant/lifecycle/release-publish";
|
|
2
|
+
import type { RegistryFetch } from "../reader.js";
|
|
3
|
+
/** A module in a hosted registry, without the host: `<namespace>/<name>/<system>`. */
|
|
4
|
+
export interface ModuleAddress {
|
|
5
|
+
namespace: string;
|
|
6
|
+
name: string;
|
|
7
|
+
system: string;
|
|
8
|
+
}
|
|
9
|
+
/** What a module target is given to plan and to publish: one version of one module. */
|
|
10
|
+
export interface ModuleVersionContext extends PublishContextBase {
|
|
11
|
+
/** The module. A host that fixes the namespace itself (GitLab's top-level group, HCP's organization) uses its own. */
|
|
12
|
+
address: ModuleAddress;
|
|
13
|
+
/** The version, semver without a leading `v`. */
|
|
14
|
+
version: string;
|
|
15
|
+
/** The gzip tarball the bucket registry serves and the attestation signs, with the module at its root. */
|
|
16
|
+
archive: Uint8Array;
|
|
17
|
+
/** The commit the version was built from. */
|
|
18
|
+
revision: string;
|
|
19
|
+
/** The content digest, `sha256:<hex>` of the uncompressed archive, as the bucket registry's release.json keeps it. */
|
|
20
|
+
content: string;
|
|
21
|
+
}
|
|
22
|
+
/** The content a version a host holds carries. */
|
|
23
|
+
export interface HeldVersion {
|
|
24
|
+
/** `sha256:<hex>` of its uncompressed archive. */
|
|
25
|
+
content: string;
|
|
26
|
+
/** The revision the host keeps for it, when it keeps one. */
|
|
27
|
+
revision?: string;
|
|
28
|
+
/**
|
|
29
|
+
* The host's status for a version it has not finished taking in, such as
|
|
30
|
+
* HCP's `pending` before its archive is parsed (chant#4604). Absent for a
|
|
31
|
+
* version consumers can install; `content` is empty while it is set.
|
|
32
|
+
*/
|
|
33
|
+
status?: string;
|
|
34
|
+
}
|
|
35
|
+
/** The reads a module target answers beside the contract. They read, and change nothing. */
|
|
36
|
+
export interface ModuleTargetReads {
|
|
37
|
+
/** Every version the host lists for the module, oldest first; none when it has no such module. */
|
|
38
|
+
versions(address: ModuleAddress, ctx: Pick<PublishContextBase, "env" | "redactor">): Promise<string[]>;
|
|
39
|
+
/** The content of a version the host holds, or undefined when it holds no such version. */
|
|
40
|
+
held(address: ModuleAddress, version: string, ctx: Pick<PublishContextBase, "env" | "redactor">): Promise<HeldVersion | undefined>;
|
|
41
|
+
}
|
|
42
|
+
/** A target that publishes a module version: the publish-target contract over {@link ModuleVersionContext}, plus its reads. */
|
|
43
|
+
export type ModulePublishTarget<K extends string = string> = PublishTarget<ModuleVersionContext, K> & ModuleTargetReads;
|
|
44
|
+
/** What a module target's factory is given: core's publish deps, plus the fetch the registry reader uses. */
|
|
45
|
+
export interface ModuleTargetDeps extends PublishDeps {
|
|
46
|
+
/**
|
|
47
|
+
* The fetch the registry-protocol reads go through. Default: the global
|
|
48
|
+
* `fetch`. A test passes its fake for both this and `fetch`.
|
|
49
|
+
*/
|
|
50
|
+
registryFetch?: RegistryFetch;
|
|
51
|
+
}
|
|
52
|
+
/** `sha256:<hex>` of the bytes. */
|
|
53
|
+
export declare const contentDigest: (bytes: Uint8Array) => string;
|
|
54
|
+
/** The content digest of a gzip archive: the digest of its uncompressed bytes. */
|
|
55
|
+
export declare function archiveContent(archive: Uint8Array): string;
|
|
56
|
+
/**
|
|
57
|
+
* The checks every module target's `plan` makes before it reads its host: the
|
|
58
|
+
* address and version are ones a registry can carry, and the archive holds
|
|
59
|
+
* the content the context names.
|
|
60
|
+
*/
|
|
61
|
+
export declare function checkModuleVersion(ctx: ModuleVersionContext): void;
|
|
62
|
+
/** The refusal for a version a host holds with other content. */
|
|
63
|
+
export declare function versionHeldError(where: string, ctx: ModuleVersionContext, held: HeldVersion): PublishTargetError;
|
|
64
|
+
/** The error message for a host's answer, with every credential masked. */
|
|
65
|
+
export declare const answerError: (ctx: Pick<PublishContextBase, "redactor">, code: string, message: string, fix?: string) => PublishTargetError;
|
|
66
|
+
/** The global fetch, in the contract's shape. */
|
|
67
|
+
export declare const defaultPublishFetch: PublishFetch;
|
|
68
|
+
//# sourceMappingURL=module-target.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-target.d.ts","sourceRoot":"","sources":["../../../src/registry/targets/module-target.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAGlK,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAE/C,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,uFAAuF;AACvF,MAAM,WAAW,oBAAqB,SAAQ,kBAAkB;IAC9D,sHAAsH;IACtH,OAAO,EAAE,aAAa,CAAC;IACvB,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,0GAA0G;IAC1G,OAAO,EAAE,UAAU,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,sHAAsH;IACtH,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,kDAAkD;AAClD,MAAM,WAAW,WAAW;IAC1B,kDAAkD;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,4FAA4F;AAC5F,MAAM,WAAW,iBAAiB;IAChC,kGAAkG;IAClG,QAAQ,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACvG,2FAA2F;IAC3F,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,CAAC,kBAAkB,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;CACpI;AAED,+HAA+H;AAC/H,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,IAAI,aAAa,CAAC,oBAAoB,EAAE,CAAC,CAAC,GAAG,iBAAiB,CAAC;AAExH,6GAA6G;AAC7G,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;OAGG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,mCAAmC;AACnC,eAAO,MAAM,aAAa,UAAW,UAAU,KAAG,MAAsE,CAAC;AAEzH,kFAAkF;AAClF,wBAAgB,cAAc,CAAC,OAAO,EAAE,UAAU,GAAG,MAAM,CAM1D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,oBAAoB,GAAG,IAAI,CAelE;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,oBAAoB,EAAE,IAAI,EAAE,WAAW,GAAG,kBAAkB,CAMhH;AAED,2EAA2E;AAC3E,eAAO,MAAM,WAAW,QAAS,IAAI,CAAC,kBAAkB,EAAE,UAAU,CAAC,QAAQ,MAAM,WAAW,MAAM,QAAQ,MAAM,KAAG,kBACC,CAAC;AAEvH,iDAAiD;AACjD,eAAO,MAAM,mBAAmB,EAAE,YAA6D,CAAC"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publishing a module version to a hosted module registry (chant#4603,
|
|
3
|
+
* terragucci#1290 bundle C). A module target is chant core's publish-target
|
|
4
|
+
* contract (`PublishTarget` in core's lifecycle/release-publish.ts, chant#4047)
|
|
5
|
+
* over a module-version context in place of a cut release (chant#4602): the
|
|
6
|
+
* same `plan`, `stage` and `reveal`, the same `PublishTargetError`, the
|
|
7
|
+
* injected `fetch`, `sleep` and `now`, and core's credential reading and
|
|
8
|
+
* masking. Two reads sit beside the contract: `versions`, the versions the
|
|
9
|
+
* host lists, and `held`, the content a version the host holds carries, so a
|
|
10
|
+
* product's publish can tell a version that is already out from one holding
|
|
11
|
+
* other content.
|
|
12
|
+
*
|
|
13
|
+
* Every target uploads the archive the bucket registry serves and the
|
|
14
|
+
* attestation signs, unchanged (terragucci#1290 ruling B), so one digest
|
|
15
|
+
* holds across all of them. A host that renders a README shows the module's
|
|
16
|
+
* own.
|
|
17
|
+
*
|
|
18
|
+
* Products (terragucci's `modules.publish`) make the targets and hold the
|
|
19
|
+
* words; the protocol and the host calls live here.
|
|
20
|
+
*/
|
|
21
|
+
import { gunzipSync } from "node:zlib";
|
|
22
|
+
import { createHash } from "node:crypto";
|
|
23
|
+
import { PublishTargetError } from "@intentius/chant/lifecycle/release-publish";
|
|
24
|
+
import { REGISTRY_NAME, REGISTRY_SYSTEM } from "../address.js";
|
|
25
|
+
import { parseSemver } from "../semver.js";
|
|
26
|
+
/** `sha256:<hex>` of the bytes. */
|
|
27
|
+
export const contentDigest = (bytes) => `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
|
|
28
|
+
/** The content digest of a gzip archive: the digest of its uncompressed bytes. */
|
|
29
|
+
export function archiveContent(archive) {
|
|
30
|
+
try {
|
|
31
|
+
return contentDigest(gunzipSync(archive));
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
throw new PublishTargetError("publish-archive-invalid", "the module archive is not a gzip tarball", "Publish the .tar.gz the bucket registry serves.");
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* The checks every module target's `plan` makes before it reads its host: the
|
|
39
|
+
* address and version are ones a registry can carry, and the archive holds
|
|
40
|
+
* the content the context names.
|
|
41
|
+
*/
|
|
42
|
+
export function checkModuleVersion(ctx) {
|
|
43
|
+
const { namespace, name, system } = ctx.address;
|
|
44
|
+
if (!REGISTRY_NAME.test(namespace) || !REGISTRY_NAME.test(name)) {
|
|
45
|
+
throw new PublishTargetError("publish-config-invalid", `${namespace}/${name}: a registry namespace and module name are letters, digits, - and _`);
|
|
46
|
+
}
|
|
47
|
+
if (!REGISTRY_SYSTEM.test(system))
|
|
48
|
+
throw new PublishTargetError("publish-config-invalid", `${system}: a registry module's system is lower-case letters and digits`);
|
|
49
|
+
if (!parseSemver(ctx.version))
|
|
50
|
+
throw new PublishTargetError("publish-config-invalid", `${ctx.version} is not a semver version`);
|
|
51
|
+
const got = archiveContent(ctx.archive);
|
|
52
|
+
if (got !== ctx.content) {
|
|
53
|
+
throw new PublishTargetError("publish-artifact-digest-mismatch", `the archive for ${namespace}/${name}/${system} ${ctx.version} holds ${got}, and the release names ${ctx.content}`, "Publish the archive the release was built with.");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The refusal for a version a host holds with other content. */
|
|
57
|
+
export function versionHeldError(where, ctx, held) {
|
|
58
|
+
return new PublishTargetError("publish-version-held", `${where} already holds ${ctx.version} with content ${held.content}, and this publish has ${ctx.content}`, "A published version never changes: raise the version, or check why the module's content moved.");
|
|
59
|
+
}
|
|
60
|
+
/** The error message for a host's answer, with every credential masked. */
|
|
61
|
+
export const answerError = (ctx, code, message, fix) => new PublishTargetError(code, ctx.redactor.redact(message), fix === undefined ? undefined : ctx.redactor.redact(fix));
|
|
62
|
+
/** The global fetch, in the contract's shape. */
|
|
63
|
+
export const defaultPublishFetch = (url, init) => fetch(url, init);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ModuleAddress, type ModulePublishTarget, type ModuleTargetDeps } from "./module-target.js";
|
|
2
|
+
/** How a Nexus module target is declared. */
|
|
3
|
+
export interface NexusModuleTargetOptions {
|
|
4
|
+
/** The Nexus base, such as `https://nexus.example.com`. */
|
|
5
|
+
url: string;
|
|
6
|
+
/** The hosted Terraform repository's name. */
|
|
7
|
+
repo: string;
|
|
8
|
+
/**
|
|
9
|
+
* The label of the consumers' CLI `host` block, which their sources start
|
|
10
|
+
* with. Default: the repository's name, lower-cased. It must be a valid host name.
|
|
11
|
+
*/
|
|
12
|
+
host?: string;
|
|
13
|
+
/** The variable the token (a user token's pass code, or the password) is read from. Default `NEXUS_TOKEN`. */
|
|
14
|
+
tokenEnv?: string;
|
|
15
|
+
/** The variable the user name (a user token's name code, or the user) is read from. Default `NEXUS_USER`. */
|
|
16
|
+
userEnv?: string;
|
|
17
|
+
/** The user name, in place of `userEnv`. */
|
|
18
|
+
user?: string;
|
|
19
|
+
/** How long `reveal` waits for Nexus to list the version. Default 30s. */
|
|
20
|
+
waitMs?: number;
|
|
21
|
+
/** How often it asks while it waits. Default 2s. */
|
|
22
|
+
pollMs?: number;
|
|
23
|
+
}
|
|
24
|
+
export declare const NEXUS_TOKEN_ENV = "NEXUS_TOKEN";
|
|
25
|
+
export declare const NEXUS_USER_ENV = "NEXUS_USER";
|
|
26
|
+
/** The first Nexus release with hosted Terraform repositories. */
|
|
27
|
+
export declare const NEXUS_HOSTED_FLOOR = "3.89.0";
|
|
28
|
+
/** The first Nexus release with the bearer token call and the archive and cache fixes the research names. */
|
|
29
|
+
export declare const NEXUS_BEARER_FLOOR = "3.95.0";
|
|
30
|
+
/** The Nexus base, without a trailing slash. */
|
|
31
|
+
export declare function nexusBase(url: string): string;
|
|
32
|
+
/** The repository's modules.v1 URL, ending in `/`. */
|
|
33
|
+
export declare const nexusModulesUrl: (base: string, repo: string) => string;
|
|
34
|
+
/** The upload path of one version's zip. */
|
|
35
|
+
export declare function nexusUploadUrl(base: string, repo: string, a: ModuleAddress, version: string): string;
|
|
36
|
+
/** The label of the consumers' `host` block. */
|
|
37
|
+
export declare function nexusHostLabel(o: Pick<NexusModuleTargetOptions, "repo" | "host">): string;
|
|
38
|
+
/** The source consumers write for a module in the repository: `<host label>/<namespace>/<name>/<system>`. */
|
|
39
|
+
export declare const nexusSource: (label: string, a: ModuleAddress) => string;
|
|
40
|
+
/** The CLI configuration block a consumer adds so its sources reach the repository. */
|
|
41
|
+
export declare function nexusHostBlock(o: Pick<NexusModuleTargetOptions, "url" | "repo" | "host">): string;
|
|
42
|
+
export declare function nexusModuleTarget(options: NexusModuleTargetOptions, deps?: ModuleTargetDeps): ModulePublishTarget<"nexus">;
|
|
43
|
+
//# sourceMappingURL=nexus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"nexus.d.ts","sourceRoot":"","sources":["../../../src/registry/targets/nexus.ts"],"names":[],"mappings":"AA+CA,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;AAiBzB,6CAA6C;AAC7C,MAAM,WAAW,wBAAwB;IACvC,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8GAA8G;IAC9G,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6GAA6G;IAC7G,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAC7C,eAAO,MAAM,cAAc,eAAe,CAAC;AAC3C,kEAAkE;AAClE,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAC3C,6GAA6G;AAC7G,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAI3C,gDAAgD;AAChD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAO7C;AAED,sDAAsD;AACtD,eAAO,MAAM,eAAe,SAAU,MAAM,QAAQ,MAAM,KAAG,MAAsE,CAAC;AAEpI,4CAA4C;AAC5C,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpG;AAED,gDAAgD;AAChD,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAMzF;AAED,6GAA6G;AAC7G,eAAO,MAAM,WAAW,UAAW,MAAM,KAAK,aAAa,KAAG,MAAyD,CAAC;AAExH,uFAAuF;AACvF,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC,GAAG,MAAM,CAEjG;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,EAAE,IAAI,GAAE,gBAAqB,GAAG,mBAAmB,CAAC,OAAO,CAAC,CA0K9H"}
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Sonatype Nexus Repository hosted Terraform repository as a module target
|
|
3
|
+
* (chant#4605), from the research on terragucci#1299 and its ruling.
|
|
4
|
+
*
|
|
5
|
+
* Nexus has a Terraform format from 3.88 and hosted Terraform repositories
|
|
6
|
+
* from 3.89, which is this target's floor. The one write is the documented
|
|
7
|
+
* module upload (help.sonatype.com, CLI usage and options):
|
|
8
|
+
*
|
|
9
|
+
* PUT <url>/repository/<repo>/v1/modules/<namespace>/<name>/<system>/<version>/<name>-<version>.zip
|
|
10
|
+
*
|
|
11
|
+
* with `Content-Type: application/zip`, basic `user:token` credentials
|
|
12
|
+
* (ruling B) and the zip of the attested archive as the body (ruling A,
|
|
13
|
+
* ./zip.ts). The user is `NEXUS_USER` (or the declaration's `user` or
|
|
14
|
+
* `userEnv`) and the token `NEXUS_TOKEN` (or `tokenEnv`), a user token's
|
|
15
|
+
* pass code or the user's password.
|
|
16
|
+
*
|
|
17
|
+
* Nexus has no single registry host to discover from: a consumer declares a
|
|
18
|
+
* CLI `host "<name>"` block mapping `modules.v1` to the repository's
|
|
19
|
+
* `<url>/repository/<repo>/v1/modules/`, and writes
|
|
20
|
+
* `<name>/<namespace>/<name>/<system>`. `nexusHostBlock` gives that block.
|
|
21
|
+
* `versions` and `reveal` read the module the same way, with the block held
|
|
22
|
+
* in memory as the reader's `services` map (ruling C), so no CLI config file
|
|
23
|
+
* is written. The reads send `TF_TOKEN_<nexus host>` when it is set, else the
|
|
24
|
+
* bearer token Nexus 3.95 and later issue at `<repo>/v1/api/token` for the
|
|
25
|
+
* basic credentials, else the basic credentials themselves, which Nexus
|
|
26
|
+
* takes as header authentication before 3.95. Nexus before 3.95 kept a "not
|
|
27
|
+
* found" answer in its cache, so `reveal` waits for the version to be
|
|
28
|
+
* listed, up to `waitMs` (default 30s).
|
|
29
|
+
*
|
|
30
|
+
* `held` GETs the uploaded zip at its path. A chant zip names the attested
|
|
31
|
+
* content in its archive comment, so the same content comes back `present`
|
|
32
|
+
* with nothing sent and other content is refused.
|
|
33
|
+
*
|
|
34
|
+
* Not confirmed by the docs (terragucci#1299): Sonatype's page on creating a
|
|
35
|
+
* Terraform repository says GPG signing is mandatory for hosted repositories
|
|
36
|
+
* and also that it is optional for modules, so what a module upload does on
|
|
37
|
+
* a repository with no signing key is unknown; whether a second upload of a
|
|
38
|
+
* version is refused; whether a hosted repository serves
|
|
39
|
+
* `/.well-known/terraform.json` (this target never asks for it); and the
|
|
40
|
+
* answer shape of the 3.95 token call (this reads a JSON `token` field, else
|
|
41
|
+
* the body as text). Nexus shows no deprecation for a module version, so the
|
|
42
|
+
* bucket catalog carries it.
|
|
43
|
+
*/
|
|
44
|
+
import { PublishTargetError } from "@intentius/chant/lifecycle/release-publish";
|
|
45
|
+
import { terraformCredential } from "@intentius/chant/terraform/credentials";
|
|
46
|
+
import { createHash } from "node:crypto";
|
|
47
|
+
import { RegistryError, registryLocation, registryVersions } from "../reader.js";
|
|
48
|
+
import { answerError, checkModuleVersion, contentDigest, defaultPublishFetch, versionHeldError, } from "./module-target.js";
|
|
49
|
+
import { HOSTED_LIST_WAIT_MS, HOSTED_POLL_MS, defaultRegistryFetch, getBytes, locationContent, needBasicCredential, readBasicCredential, revealMismatch, waitListed, writeRefused, } from "./hosted.js";
|
|
50
|
+
import { heldContentOf, moduleZip } from "./zip.js";
|
|
51
|
+
export const NEXUS_TOKEN_ENV = "NEXUS_TOKEN";
|
|
52
|
+
export const NEXUS_USER_ENV = "NEXUS_USER";
|
|
53
|
+
/** The first Nexus release with hosted Terraform repositories. */
|
|
54
|
+
export const NEXUS_HOSTED_FLOOR = "3.89.0";
|
|
55
|
+
/** The first Nexus release with the bearer token call and the archive and cache fixes the research names. */
|
|
56
|
+
export const NEXUS_BEARER_FLOOR = "3.95.0";
|
|
57
|
+
const HOST_LABEL = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)*$/;
|
|
58
|
+
/** The Nexus base, without a trailing slash. */
|
|
59
|
+
export function nexusBase(url) {
|
|
60
|
+
try {
|
|
61
|
+
const u = new URL(url);
|
|
62
|
+
return `${u.origin}${u.pathname.replace(/\/+$/, "")}`;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new PublishTargetError("publish-config-invalid", `${url} is not a URL`, "Set url to the Nexus base, such as https://nexus.example.com.");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** The repository's modules.v1 URL, ending in `/`. */
|
|
69
|
+
export const nexusModulesUrl = (base, repo) => `${base}/repository/${encodeURIComponent(repo)}/v1/modules/`;
|
|
70
|
+
/** The upload path of one version's zip. */
|
|
71
|
+
export function nexusUploadUrl(base, repo, a, version) {
|
|
72
|
+
const seg = [a.namespace, a.name, a.system, version].map(encodeURIComponent).join("/");
|
|
73
|
+
return `${nexusModulesUrl(base, repo)}${seg}/${encodeURIComponent(`${a.name}-${version}.zip`)}`;
|
|
74
|
+
}
|
|
75
|
+
/** The label of the consumers' `host` block. */
|
|
76
|
+
export function nexusHostLabel(o) {
|
|
77
|
+
const label = (o.host ?? o.repo).toLowerCase();
|
|
78
|
+
if (!HOST_LABEL.test(label)) {
|
|
79
|
+
throw new PublishTargetError("publish-config-invalid", `${JSON.stringify(label)} is not a host name a CLI host block can carry`, "Set the declaration's host to a name of letters, digits and -, such as the repository's name without _.");
|
|
80
|
+
}
|
|
81
|
+
return label;
|
|
82
|
+
}
|
|
83
|
+
/** The source consumers write for a module in the repository: `<host label>/<namespace>/<name>/<system>`. */
|
|
84
|
+
export const nexusSource = (label, a) => `${label}/${a.namespace}/${a.name}/${a.system}`;
|
|
85
|
+
/** The CLI configuration block a consumer adds so its sources reach the repository. */
|
|
86
|
+
export function nexusHostBlock(o) {
|
|
87
|
+
return `host "${nexusHostLabel(o)}" {\n services = {\n "modules.v1" = "${nexusModulesUrl(nexusBase(o.url), o.repo)}"\n }\n}\n`;
|
|
88
|
+
}
|
|
89
|
+
export function nexusModuleTarget(options, deps = {}) {
|
|
90
|
+
const put = deps.fetch ?? defaultPublishFetch;
|
|
91
|
+
const get = deps.registryFetch ?? defaultRegistryFetch;
|
|
92
|
+
const names = { tokenEnv: options.tokenEnv ?? NEXUS_TOKEN_ENV, userEnv: options.userEnv ?? NEXUS_USER_ENV, ...(options.user ? { user: options.user } : {}) };
|
|
93
|
+
const wait = {
|
|
94
|
+
waitMs: options.waitMs ?? HOSTED_LIST_WAIT_MS,
|
|
95
|
+
pollMs: options.pollMs ?? HOSTED_POLL_MS,
|
|
96
|
+
sleep: deps.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms))),
|
|
97
|
+
now: deps.now ?? Date.now,
|
|
98
|
+
};
|
|
99
|
+
const key = `nexus:${createHash("sha256")
|
|
100
|
+
.update(JSON.stringify({ url: options.url, repo: options.repo, host: options.host ?? null, tokenEnv: names.tokenEnv, userEnv: names.userEnv, user: options.user ?? null }))
|
|
101
|
+
.digest("hex")
|
|
102
|
+
.slice(0, 16)}`;
|
|
103
|
+
const where = () => {
|
|
104
|
+
const base = nexusBase(options.url);
|
|
105
|
+
const label = nexusHostLabel(options);
|
|
106
|
+
return { base, label, nexusHost: new URL(base).host.toLowerCase(), modules: nexusModulesUrl(base, options.repo) };
|
|
107
|
+
};
|
|
108
|
+
const fix = `Use a user token, or a user, that may add and edit components in the repository ${options.repo}.`;
|
|
109
|
+
const needCredential = (ctx) => needBasicCredential(ctx, names, "Nexus", fix);
|
|
110
|
+
/** The bearer token from Nexus 3.95's token call, per credential; null when the call is not there. */
|
|
111
|
+
const issued = new Map();
|
|
112
|
+
const issuedToken = async (ctx, basic) => {
|
|
113
|
+
if (issued.has(basic.header))
|
|
114
|
+
return issued.get(basic.header);
|
|
115
|
+
const { base } = where();
|
|
116
|
+
const url = `${base}/repository/${encodeURIComponent(options.repo)}/v1/api/token`;
|
|
117
|
+
const { status, bytes } = await getBytes(ctx, get, url, basic.header);
|
|
118
|
+
let token = null;
|
|
119
|
+
if (status >= 200 && status <= 299) {
|
|
120
|
+
const text = Buffer.from(bytes).toString("utf-8").trim();
|
|
121
|
+
try {
|
|
122
|
+
const doc = JSON.parse(text);
|
|
123
|
+
token = typeof doc.token === "string" && doc.token ? doc.token : null;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
token = text || null;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
ctx.redactor.add(token);
|
|
130
|
+
issued.set(basic.header, token);
|
|
131
|
+
return token;
|
|
132
|
+
};
|
|
133
|
+
/** How the reads authenticate: the CLIs' token for the Nexus host, else the issued bearer token, else basic. */
|
|
134
|
+
const readAuth = async (ctx) => {
|
|
135
|
+
const { nexusHost } = where();
|
|
136
|
+
const cli = terraformCredential(nexusHost, { env: ctx.env })?.token;
|
|
137
|
+
if (cli) {
|
|
138
|
+
ctx.redactor.add(cli);
|
|
139
|
+
return `Bearer ${cli}`;
|
|
140
|
+
}
|
|
141
|
+
const basic = readBasicCredential(ctx, names);
|
|
142
|
+
if (!basic)
|
|
143
|
+
return undefined;
|
|
144
|
+
const bearer = await issuedToken(ctx, basic);
|
|
145
|
+
return bearer ? `Bearer ${bearer}` : basic.header;
|
|
146
|
+
};
|
|
147
|
+
const readOptions = async (ctx) => {
|
|
148
|
+
const { label, modules } = where();
|
|
149
|
+
const authorization = await readAuth(ctx);
|
|
150
|
+
return { services: { [label]: modules }, token: false, fetch: get, ...(authorization ? { authorization } : {}) };
|
|
151
|
+
};
|
|
152
|
+
const read = async (ctx, run) => {
|
|
153
|
+
try {
|
|
154
|
+
return await run();
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
if (e instanceof RegistryError)
|
|
158
|
+
throw answerError(ctx, "publish-read-failed", e.message);
|
|
159
|
+
throw e;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const versions = async (address, ctx) => {
|
|
163
|
+
const o = await readOptions(ctx);
|
|
164
|
+
return read(ctx, () => registryVersions(nexusSource(where().label, address), o));
|
|
165
|
+
};
|
|
166
|
+
const held = async (address, version, ctx) => {
|
|
167
|
+
const { base } = where();
|
|
168
|
+
const url = nexusUploadUrl(base, options.repo, address, version);
|
|
169
|
+
const { status, bytes } = await getBytes(ctx, get, url, await readAuth(ctx));
|
|
170
|
+
if (status === 404)
|
|
171
|
+
return undefined;
|
|
172
|
+
if (status === 401 || status === 403) {
|
|
173
|
+
throw answerError(ctx, "publish-credentials-refused", `Nexus answered ${status} to a read of ${url}`, `Set ${names.userEnv} and ${names.tokenEnv} to a user with read access to ${options.repo}.`);
|
|
174
|
+
}
|
|
175
|
+
if (status < 200 || status > 299)
|
|
176
|
+
throw answerError(ctx, "publish-read-failed", `Nexus answered ${status} to a read of ${url}`);
|
|
177
|
+
return heldContentOf(bytes, contentDigest);
|
|
178
|
+
};
|
|
179
|
+
const item = (ctx, present) => {
|
|
180
|
+
const { label } = where();
|
|
181
|
+
const a = ctx.address;
|
|
182
|
+
return { name: `${a.namespace}/${a.name}/${a.system} ${ctx.version}`, destination: nexusSource(label, a), digest: ctx.content, ...(present ? { present: true } : {}) };
|
|
183
|
+
};
|
|
184
|
+
return {
|
|
185
|
+
kind: "nexus",
|
|
186
|
+
name: "Nexus Terraform repository",
|
|
187
|
+
destination: `${options.url} ${options.repo}`,
|
|
188
|
+
credentialEnv: [names.tokenEnv, ...(options.user ? [] : [names.userEnv])],
|
|
189
|
+
key,
|
|
190
|
+
versions,
|
|
191
|
+
held,
|
|
192
|
+
async plan(ctx) {
|
|
193
|
+
checkModuleVersion(ctx);
|
|
194
|
+
where();
|
|
195
|
+
needCredential(ctx);
|
|
196
|
+
return [item(ctx)];
|
|
197
|
+
},
|
|
198
|
+
async stage(ctx) {
|
|
199
|
+
checkModuleVersion(ctx);
|
|
200
|
+
const credential = needCredential(ctx);
|
|
201
|
+
const { base, label } = where();
|
|
202
|
+
const source = nexusSource(label, ctx.address);
|
|
203
|
+
const staged = (present) => ({ target: "nexus", destination: source, items: [item(ctx, present)], state: { repo: options.repo, url: base, version: ctx.version } });
|
|
204
|
+
const before = await held(ctx.address, ctx.version, ctx);
|
|
205
|
+
if (before) {
|
|
206
|
+
if (before.content !== ctx.content)
|
|
207
|
+
throw versionHeldError(source, ctx, before);
|
|
208
|
+
ctx.log(`${source} ${ctx.version} is already in ${options.repo} with this content; nothing sent`);
|
|
209
|
+
return staged(true);
|
|
210
|
+
}
|
|
211
|
+
const zip = moduleZip(ctx.archive, ctx.content, ctx.revision);
|
|
212
|
+
const url = nexusUploadUrl(base, options.repo, ctx.address, ctx.version);
|
|
213
|
+
let res;
|
|
214
|
+
try {
|
|
215
|
+
res = await put(url, { method: "PUT", headers: { authorization: credential.header, "content-type": "application/zip" }, body: zip });
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
throw answerError(ctx, "publish-upload-failed", `PUT ${url}: ${e.message}`);
|
|
219
|
+
}
|
|
220
|
+
const text = await res.text().catch(() => "");
|
|
221
|
+
if (res.ok) {
|
|
222
|
+
ctx.log(`uploaded ${source} ${ctx.version} to ${options.repo}`);
|
|
223
|
+
return staged(false);
|
|
224
|
+
}
|
|
225
|
+
if (res.status === 400 || res.status === 403 || res.status === 409) {
|
|
226
|
+
// A deployment policy that refuses a redeploy, or another run uploading first: judge what the repository holds.
|
|
227
|
+
const now = await held(ctx.address, ctx.version, ctx).catch(() => undefined);
|
|
228
|
+
if (now && now.content === ctx.content)
|
|
229
|
+
return staged(true);
|
|
230
|
+
if (now)
|
|
231
|
+
throw versionHeldError(source, ctx, now);
|
|
232
|
+
}
|
|
233
|
+
if (res.status === 401 || res.status === 403)
|
|
234
|
+
throw writeRefused(ctx, "Nexus", res.status, `${source} ${ctx.version}`, credential, names, fix);
|
|
235
|
+
throw answerError(ctx, "publish-upload-failed", `Nexus answered ${res.status} to the upload of ${source} ${ctx.version}: ${text.slice(0, 300)}`, `Hosted Terraform repositories need Nexus ${NEXUS_HOSTED_FLOOR} or later; check that ${options.repo} is a hosted Terraform repository with a signing key.`);
|
|
236
|
+
},
|
|
237
|
+
async reveal(ctx, staged) {
|
|
238
|
+
const listed = await waitListed(() => versions(ctx.address, ctx), ctx.version, wait);
|
|
239
|
+
if (!listed) {
|
|
240
|
+
throw answerError(ctx, "publish-reveal-missing", `${staged.destination} lists no ${ctx.version} ${Math.round(wait.waitMs / 1000)}s after the upload`, `Nexus before ${NEXUS_BEARER_FLOOR} can keep an earlier "not found" in its cache; run the publish again once it has expired.`);
|
|
241
|
+
}
|
|
242
|
+
const o = await readOptions(ctx);
|
|
243
|
+
const location = await read(ctx, () => registryLocation(staged.destination, ctx.version, o));
|
|
244
|
+
const got = await locationContent(ctx, get, location, where().nexusHost, o.authorization);
|
|
245
|
+
if (got.content !== ctx.content)
|
|
246
|
+
throw revealMismatch(ctx, staged.destination, ctx.version, got.content, ctx.content);
|
|
247
|
+
return { target: staged.target, destination: staged.destination, items: staged.items };
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** One entry of a module tarball. */
|
|
2
|
+
export interface ModuleArchiveEntry {
|
|
3
|
+
path: string;
|
|
4
|
+
type: "file" | "dir";
|
|
5
|
+
mode: number;
|
|
6
|
+
/** Seconds since the epoch. */
|
|
7
|
+
mtime: number;
|
|
8
|
+
data: Buffer;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* The entries of a module's gzip tarball (ustar, pax and GNU long names), with
|
|
12
|
+
* `./` cut from each path. A link or a device in the archive is refused: a
|
|
13
|
+
* zip of the module could not carry it as the tarball does.
|
|
14
|
+
*/
|
|
15
|
+
export declare function moduleArchiveEntries(archive: Uint8Array): ModuleArchiveEntry[];
|
|
16
|
+
/** The CRC-32 a zip entry carries. */
|
|
17
|
+
export declare function crc32(data: Uint8Array): number;
|
|
18
|
+
/** The archive comment that names the attested archive a zip was made from. */
|
|
19
|
+
export declare const ZIP_COMMENT_PREFIX = "chant-module";
|
|
20
|
+
export declare const moduleZipComment: (content: string, revision?: string) => string;
|
|
21
|
+
/** The content and revision a zip's archive comment names, when it is one {@link moduleZipComment} wrote. */
|
|
22
|
+
export declare function readModuleZipComment(comment: string): {
|
|
23
|
+
content: string;
|
|
24
|
+
revision?: string;
|
|
25
|
+
} | undefined;
|
|
26
|
+
/** A zip of the given entries, with `comment` as its archive comment. Files are deflated. */
|
|
27
|
+
export declare function zipOf(entries: readonly ModuleArchiveEntry[], comment?: string): Buffer;
|
|
28
|
+
/**
|
|
29
|
+
* The zip a hosted target uploads for an attested archive: its entries,
|
|
30
|
+
* repacked, with the content digest and revision in the archive comment.
|
|
31
|
+
*/
|
|
32
|
+
export declare function moduleZip(archive: Uint8Array, content: string, revision?: string): Buffer;
|
|
33
|
+
/** A zip read back: its archive comment and its entries' paths, modes and bytes. */
|
|
34
|
+
export interface ReadZip {
|
|
35
|
+
comment: string;
|
|
36
|
+
entries: {
|
|
37
|
+
path: string;
|
|
38
|
+
dir: boolean;
|
|
39
|
+
mode: number;
|
|
40
|
+
data: Buffer;
|
|
41
|
+
}[];
|
|
42
|
+
}
|
|
43
|
+
/** Reads a zip's central directory and entries. Throws on bytes that are not a zip. */
|
|
44
|
+
export declare function readZip(bytes: Uint8Array): ReadZip;
|
|
45
|
+
/**
|
|
46
|
+
* The content a module archive a host gave back carries, as `held` reports
|
|
47
|
+
* it: the attested digest a chant zip's comment names; for a gzip tarball,
|
|
48
|
+
* the digest of its uncompressed bytes, as the bucket registry keeps it; for
|
|
49
|
+
* any other bytes, their own digest.
|
|
50
|
+
*/
|
|
51
|
+
export declare function heldContentOf(bytes: Uint8Array, digest: (b: Uint8Array) => string): {
|
|
52
|
+
content: string;
|
|
53
|
+
revision?: string;
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=zip.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"zip.d.ts","sourceRoot":"","sources":["../../../src/registry/targets/zip.ts"],"names":[],"mappings":"AAqBA,qCAAqC;AACrC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AA2BD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,UAAU,GAAG,kBAAkB,EAAE,CAwC9E;AAYD,sCAAsC;AACtC,wBAAgB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAI9C;AAWD,+EAA+E;AAC/E,eAAO,MAAM,kBAAkB,iBAAiB,CAAC;AAEjD,eAAO,MAAM,gBAAgB,YAAa,MAAM,aAAa,MAAM,KAAG,MAA8F,CAAC;AAErK,6GAA6G;AAC7G,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAMxG;AAED,6FAA6F;AAC7F,wBAAgB,KAAK,CAAC,OAAO,EAAE,SAAS,kBAAkB,EAAE,EAAE,OAAO,SAAK,GAAG,MAAM,CA+DlF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzF;AAED,oFAAoF;AACpF,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CACvE;AAED,uFAAuF;AACvF,wBAAgB,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAmClD;AAKD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC,EAAE,UAAU,KAAK,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAgB1H"}
|