@mannyc1/ts-release 0.0.7 → 0.2.2
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/ARCHITECTURE.md +124 -92
- package/CHANGELOG.md +115 -0
- package/LICENSE +21 -0
- package/README.md +278 -324
- package/SPEC.md +206 -310
- package/apps/release-ts/README.md +32 -0
- package/apps/release-ts/src/cli/command.ts +164 -0
- package/apps/release-ts/src/cli/commands.ts +351 -0
- package/apps/release-ts/src/cli/main.ts +43 -0
- package/apps/release-ts/src/cli/node-main.ts +49 -0
- package/apps/ts-release-agents/LICENSE +21 -0
- package/apps/ts-release-agents/README.md +21 -0
- package/apps/ts-release-agents/evals/cases.json +11 -0
- package/apps/ts-release-agents/manifests/claude.json +5 -0
- package/apps/ts-release-agents/manifests/codex.json +5 -0
- package/apps/ts-release-agents/package.json +11 -0
- package/apps/ts-release-agents/skills/release/SKILL.md +48 -0
- package/apps/ts-release-agents/skills/release/references/configuration.md +18 -0
- package/apps/ts-release-agents/skills/release/references/recovery.md +10 -0
- package/apps/ts-release-agents/skills/release/references/staged-workflow.md +12 -0
- package/apps/ts-release-agents/skills/release/references/target-selection.md +13 -0
- package/apps/ts-release-agents/skills/release/references/verification.md +14 -0
- package/apps/ts-release-agents/src/build.ts +105 -0
- package/apps/ts-release-agents/src/check.ts +117 -0
- package/apps/ts-release-agents/src/install.ts +121 -0
- package/apps/ts-release-agents/test/contract.test.ts +56 -0
- package/apps/ts-release-agents/tsconfig.json +5 -0
- package/dist/api/api.d.ts +15 -0
- package/dist/api/api.d.ts.map +1 -0
- package/dist/api/api.js +244 -0
- package/dist/api/api.js.map +1 -0
- package/dist/api/errors.d.ts +39 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +32 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/input.d.ts +10 -0
- package/dist/api/input.d.ts.map +1 -0
- package/dist/api/input.js +73 -0
- package/dist/api/input.js.map +1 -0
- package/dist/api/runtime.d.ts +18 -0
- package/dist/api/runtime.d.ts.map +1 -0
- package/dist/api/runtime.js +7 -0
- package/dist/api/runtime.js.map +1 -0
- package/dist/api/types.d.ts +76 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +17 -0
- package/dist/api/types.js.map +1 -0
- package/dist/bin/ts-release.js +39239 -0
- package/dist/capabilities/bun-targets.d.ts +3 -0
- package/dist/capabilities/bun-targets.d.ts.map +1 -0
- package/dist/capabilities/bun-targets.js +3 -0
- package/dist/capabilities/bun-targets.js.map +1 -0
- package/dist/capabilities/field-ownership.d.ts +17 -0
- package/dist/capabilities/field-ownership.d.ts.map +1 -0
- package/dist/capabilities/field-ownership.js +40 -0
- package/dist/capabilities/field-ownership.js.map +1 -0
- package/dist/capabilities/module.d.ts +91 -0
- package/dist/capabilities/module.d.ts.map +1 -0
- package/dist/capabilities/module.js +2 -0
- package/dist/capabilities/module.js.map +1 -0
- package/dist/capabilities/registry.d.ts +829 -0
- package/dist/capabilities/registry.d.ts.map +1 -0
- package/dist/capabilities/registry.js +291 -0
- package/dist/capabilities/registry.js.map +1 -0
- package/dist/config/config.d.ts +6 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +42 -0
- package/dist/config/config.js.map +1 -0
- package/dist/correction/coordinator.d.ts +248 -0
- package/dist/correction/coordinator.d.ts.map +1 -0
- package/dist/correction/coordinator.js +274 -0
- package/dist/correction/coordinator.js.map +1 -0
- package/dist/correction/index.d.ts +3 -0
- package/dist/correction/index.d.ts.map +1 -0
- package/dist/correction/index.js +3 -0
- package/dist/correction/index.js.map +1 -0
- package/dist/correction/intent.d.ts +111 -0
- package/dist/correction/intent.d.ts.map +1 -0
- package/dist/correction/intent.js +146 -0
- package/dist/correction/intent.js.map +1 -0
- package/dist/drivers/archive.d.ts +8 -0
- package/dist/drivers/archive.d.ts.map +1 -0
- package/dist/drivers/archive.js +101 -0
- package/dist/drivers/archive.js.map +1 -0
- package/dist/drivers/contain.d.ts +6 -0
- package/dist/drivers/contain.d.ts.map +1 -0
- package/dist/drivers/contain.js +17 -0
- package/dist/drivers/contain.js.map +1 -0
- package/dist/drivers/environment.d.ts +4 -0
- package/dist/drivers/environment.d.ts.map +1 -0
- package/dist/drivers/environment.js +18 -0
- package/dist/drivers/environment.js.map +1 -0
- package/dist/drivers/errors.d.ts +9 -0
- package/dist/drivers/errors.d.ts.map +1 -0
- package/dist/drivers/errors.js +6 -0
- package/dist/drivers/errors.js.map +1 -0
- package/dist/drivers/glob.d.ts +2 -0
- package/dist/drivers/glob.d.ts.map +1 -0
- package/dist/drivers/glob.js +162 -0
- package/dist/drivers/glob.js.map +1 -0
- package/dist/drivers/process.d.ts +48 -0
- package/dist/drivers/process.d.ts.map +1 -0
- package/dist/drivers/process.js +257 -0
- package/dist/drivers/process.js.map +1 -0
- package/dist/drivers/redact.d.ts +4 -0
- package/dist/drivers/redact.d.ts.map +1 -0
- package/dist/drivers/redact.js +24 -0
- package/dist/drivers/redact.js.map +1 -0
- package/dist/drivers/seccomp-helper-source.d.ts +7 -0
- package/dist/drivers/seccomp-helper-source.d.ts.map +1 -0
- package/dist/drivers/seccomp-helper-source.js +121 -0
- package/dist/drivers/seccomp-helper-source.js.map +1 -0
- package/dist/drivers/utils.d.ts +4 -0
- package/dist/drivers/utils.d.ts.map +1 -0
- package/dist/drivers/utils.js +5 -0
- package/dist/drivers/utils.js.map +1 -0
- package/dist/drivers/workspace.d.ts +6 -0
- package/dist/drivers/workspace.d.ts.map +1 -0
- package/dist/drivers/workspace.js +49 -0
- package/dist/drivers/workspace.js.map +1 -0
- package/dist/extensions/provider-adapter.d.ts +48 -0
- package/dist/extensions/provider-adapter.d.ts.map +1 -0
- package/dist/extensions/provider-adapter.js +64 -0
- package/dist/extensions/provider-adapter.js.map +1 -0
- package/dist/host.d.ts +33 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +20 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +19 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/model/artifact-collection.d.ts +84 -0
- package/dist/model/artifact-collection.d.ts.map +1 -0
- package/dist/model/artifact-collection.js +185 -0
- package/dist/model/artifact-collection.js.map +1 -0
- package/dist/model/authority.d.ts +89 -0
- package/dist/model/authority.d.ts.map +1 -0
- package/dist/model/authority.js +80 -0
- package/dist/model/authority.js.map +1 -0
- package/dist/model/bun-targets.d.ts +34 -0
- package/dist/model/bun-targets.d.ts.map +1 -0
- package/dist/model/bun-targets.js +17 -0
- package/dist/model/bun-targets.js.map +1 -0
- package/dist/model/canonical.d.ts +8 -0
- package/dist/model/canonical.d.ts.map +1 -0
- package/dist/model/canonical.js +205 -0
- package/dist/model/canonical.js.map +1 -0
- package/dist/model/catalog.d.ts +76 -0
- package/dist/model/catalog.d.ts.map +1 -0
- package/dist/model/catalog.js +174 -0
- package/dist/model/catalog.js.map +1 -0
- package/dist/model/digest.d.ts +53 -0
- package/dist/model/digest.d.ts.map +1 -0
- package/dist/model/digest.js +127 -0
- package/dist/model/digest.js.map +1 -0
- package/dist/model/errors.d.ts +14 -0
- package/dist/model/errors.d.ts.map +1 -0
- package/dist/model/errors.js +8 -0
- package/dist/model/errors.js.map +1 -0
- package/dist/model/primitives.d.ts +19 -0
- package/dist/model/primitives.d.ts.map +1 -0
- package/dist/model/primitives.js +18 -0
- package/dist/model/primitives.js.map +1 -0
- package/dist/model/pypi.d.ts +12 -0
- package/dist/model/pypi.d.ts.map +1 -0
- package/dist/model/pypi.js +20 -0
- package/dist/model/pypi.js.map +1 -0
- package/dist/model/python-distribution.d.ts +33 -0
- package/dist/model/python-distribution.d.ts.map +1 -0
- package/dist/model/python-distribution.js +367 -0
- package/dist/model/python-distribution.js.map +1 -0
- package/dist/model/secret-patterns.d.ts +2 -0
- package/dist/model/secret-patterns.d.ts.map +1 -0
- package/dist/model/secret-patterns.js +12 -0
- package/dist/model/secret-patterns.js.map +1 -0
- package/dist/platform/bun.d.ts +7 -0
- package/dist/platform/bun.d.ts.map +1 -0
- package/dist/platform/bun.js +15 -0
- package/dist/platform/bun.js.map +1 -0
- package/dist/platform/credentials.d.ts +32 -0
- package/dist/platform/credentials.d.ts.map +1 -0
- package/dist/platform/credentials.js +772 -0
- package/dist/platform/credentials.js.map +1 -0
- package/dist/platform/host-support.d.ts +2 -0
- package/dist/platform/host-support.d.ts.map +1 -0
- package/dist/platform/host-support.js +4 -0
- package/dist/platform/host-support.js.map +1 -0
- package/dist/platform/node.d.ts +7 -0
- package/dist/platform/node.d.ts.map +1 -0
- package/dist/platform/node.js +15 -0
- package/dist/platform/node.js.map +1 -0
- package/dist/platform/release-runtime.d.ts +11 -0
- package/dist/platform/release-runtime.d.ts.map +1 -0
- package/dist/platform/release-runtime.js +34 -0
- package/dist/platform/release-runtime.js.map +1 -0
- package/dist/platform/services.d.ts +15 -0
- package/dist/platform/services.d.ts.map +1 -0
- package/dist/platform/services.js +30 -0
- package/dist/platform/services.js.map +1 -0
- package/dist/platform/source-observer.d.ts +5 -0
- package/dist/platform/source-observer.d.ts.map +1 -0
- package/dist/platform/source-observer.js +159 -0
- package/dist/platform/source-observer.js.map +1 -0
- package/dist/provider-sdk.d.ts +14 -0
- package/dist/provider-sdk.d.ts.map +1 -0
- package/dist/provider-sdk.js +10 -0
- package/dist/provider-sdk.js.map +1 -0
- package/dist/publication/adapter.d.ts +212 -0
- package/dist/publication/adapter.d.ts.map +1 -0
- package/dist/publication/adapter.js +83 -0
- package/dist/publication/adapter.js.map +1 -0
- package/dist/publication/authority.d.ts +137 -0
- package/dist/publication/authority.d.ts.map +1 -0
- package/dist/publication/authority.js +233 -0
- package/dist/publication/authority.js.map +1 -0
- package/dist/publication/catalog-git.d.ts +37 -0
- package/dist/publication/catalog-git.d.ts.map +1 -0
- package/dist/publication/catalog-git.js +451 -0
- package/dist/publication/catalog-git.js.map +1 -0
- package/dist/publication/claim.d.ts +39 -0
- package/dist/publication/claim.d.ts.map +1 -0
- package/dist/publication/claim.js +31 -0
- package/dist/publication/claim.js.map +1 -0
- package/dist/publication/coordinator.d.ts +246 -0
- package/dist/publication/coordinator.d.ts.map +1 -0
- package/dist/publication/coordinator.js +370 -0
- package/dist/publication/coordinator.js.map +1 -0
- package/dist/publication/github.d.ts +36 -0
- package/dist/publication/github.d.ts.map +1 -0
- package/dist/publication/github.js +644 -0
- package/dist/publication/github.js.map +1 -0
- package/dist/publication/http.d.ts +69 -0
- package/dist/publication/http.d.ts.map +1 -0
- package/dist/publication/http.js +29 -0
- package/dist/publication/http.js.map +1 -0
- package/dist/publication/index.d.ts +5 -0
- package/dist/publication/index.d.ts.map +1 -0
- package/dist/publication/index.js +5 -0
- package/dist/publication/index.js.map +1 -0
- package/dist/publication/npm.d.ts +40 -0
- package/dist/publication/npm.d.ts.map +1 -0
- package/dist/publication/npm.js +359 -0
- package/dist/publication/npm.js.map +1 -0
- package/dist/publication/profiles.d.ts +136 -0
- package/dist/publication/profiles.d.ts.map +1 -0
- package/dist/publication/profiles.js +90 -0
- package/dist/publication/profiles.js.map +1 -0
- package/dist/publication/publisher.d.ts +82 -0
- package/dist/publication/publisher.d.ts.map +1 -0
- package/dist/publication/publisher.js +53 -0
- package/dist/publication/publisher.js.map +1 -0
- package/dist/publication/pypi.d.ts +45 -0
- package/dist/publication/pypi.d.ts.map +1 -0
- package/dist/publication/pypi.js +369 -0
- package/dist/publication/pypi.js.map +1 -0
- package/dist/publication/recovery.d.ts +663 -0
- package/dist/publication/recovery.d.ts.map +1 -0
- package/dist/publication/recovery.js +252 -0
- package/dist/publication/recovery.js.map +1 -0
- package/dist/publication/report.d.ts +1061 -0
- package/dist/publication/report.d.ts.map +1 -0
- package/dist/publication/report.js +441 -0
- package/dist/publication/report.js.map +1 -0
- package/dist/recipes/config.d.ts +296 -0
- package/dist/recipes/config.d.ts.map +1 -0
- package/dist/recipes/config.js +325 -0
- package/dist/recipes/config.js.map +1 -0
- package/dist/release/capabilities.d.ts +12 -0
- package/dist/release/capabilities.d.ts.map +1 -0
- package/dist/release/capabilities.js +395 -0
- package/dist/release/capabilities.js.map +1 -0
- package/dist/release/compiler.d.ts +5 -0
- package/dist/release/compiler.d.ts.map +1 -0
- package/dist/release/compiler.js +19 -0
- package/dist/release/compiler.js.map +1 -0
- package/dist/release/config.d.ts +5 -0
- package/dist/release/config.d.ts.map +1 -0
- package/dist/release/config.js +10 -0
- package/dist/release/config.js.map +1 -0
- package/dist/release/context.d.ts +96 -0
- package/dist/release/context.d.ts.map +1 -0
- package/dist/release/context.js +168 -0
- package/dist/release/context.js.map +1 -0
- package/dist/release/graph.d.ts +271 -0
- package/dist/release/graph.d.ts.map +1 -0
- package/dist/release/graph.js +766 -0
- package/dist/release/graph.js.map +1 -0
- package/dist/release/inspect.d.ts +88 -0
- package/dist/release/inspect.d.ts.map +1 -0
- package/dist/release/inspect.js +75 -0
- package/dist/release/inspect.js.map +1 -0
- package/dist/release/prepare.d.ts +24 -0
- package/dist/release/prepare.d.ts.map +1 -0
- package/dist/release/prepare.js +1116 -0
- package/dist/release/prepare.js.map +1 -0
- package/dist/release/prepared-ref.d.ts +60 -0
- package/dist/release/prepared-ref.d.ts.map +1 -0
- package/dist/release/prepared-ref.js +131 -0
- package/dist/release/prepared-ref.js.map +1 -0
- package/dist/release/prepared-store.d.ts +90 -0
- package/dist/release/prepared-store.d.ts.map +1 -0
- package/dist/release/prepared-store.js +337 -0
- package/dist/release/prepared-store.js.map +1 -0
- package/dist/release/prepared.d.ts +172 -0
- package/dist/release/prepared.d.ts.map +1 -0
- package/dist/release/prepared.js +268 -0
- package/dist/release/prepared.js.map +1 -0
- package/dist/release/staging.d.ts +31 -0
- package/dist/release/staging.d.ts.map +1 -0
- package/dist/release/staging.js +218 -0
- package/dist/release/staging.js.map +1 -0
- package/dist/resolve/authored.d.ts +53 -0
- package/dist/resolve/authored.d.ts.map +1 -0
- package/dist/resolve/authored.js +55 -0
- package/dist/resolve/authored.js.map +1 -0
- package/dist/resolve/encode.d.ts +3 -0
- package/dist/resolve/encode.d.ts.map +1 -0
- package/dist/resolve/encode.js +21 -0
- package/dist/resolve/encode.js.map +1 -0
- package/dist/resolve/errors.d.ts +7 -0
- package/dist/resolve/errors.d.ts.map +1 -0
- package/dist/resolve/errors.js +17 -0
- package/dist/resolve/errors.js.map +1 -0
- package/dist/resolve/facts.d.ts +12 -0
- package/dist/resolve/facts.d.ts.map +1 -0
- package/dist/resolve/facts.js +18 -0
- package/dist/resolve/facts.js.map +1 -0
- package/dist/resolve/resolve.d.ts +10 -0
- package/dist/resolve/resolve.d.ts.map +1 -0
- package/dist/resolve/resolve.js +242 -0
- package/dist/resolve/resolve.js.map +1 -0
- package/dist/store.d.ts +11 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +9 -0
- package/dist/store.js.map +1 -0
- package/examples/README.md +20 -30
- package/examples/github-release/release.config.json +11 -18
- package/examples/homebrew-tap/README.md +11 -0
- package/examples/homebrew-tap/release.config.json +40 -28
- package/examples/multi-target/release.config.json +28 -53
- package/examples/npm-first-publish/release.config.json +23 -25
- package/examples/npm-only/release.config.json +22 -30
- package/examples/portable-cli/README.md +17 -0
- package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-arm64 +1 -0
- package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-x64 +1 -0
- package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-arm64 +1 -0
- package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-x64 +1 -0
- package/examples/portable-cli/artifacts/portable-example-0.1.0-windows-x64.exe +1 -0
- package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_10_15_x86_64.whl +1 -0
- package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_11_0_arm64.whl +1 -0
- package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_aarch64.whl +1 -0
- package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_x86_64.whl +1 -0
- package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-win_amd64.whl +1 -0
- package/examples/portable-cli/package.json +9 -0
- package/examples/portable-cli/release.config.json +53 -0
- package/examples/portable-cli/src/cli.ts +3 -0
- package/examples/pypi-registry/README.md +8 -0
- package/examples/scoop-bucket/README.md +10 -0
- package/examples/scoop-bucket/release.config.json +40 -30
- package/package.json +60 -156
- package/src/api/api.ts +365 -0
- package/src/api/errors.ts +36 -0
- package/src/api/input.ts +92 -0
- package/src/api/runtime.ts +14 -0
- package/src/api/types.ts +103 -0
- package/src/capabilities/bun-targets.ts +2 -0
- package/src/capabilities/field-ownership.ts +60 -0
- package/src/capabilities/module.ts +158 -0
- package/src/capabilities/registry.ts +333 -0
- package/src/config/config.ts +48 -0
- package/src/correction/coordinator.ts +336 -0
- package/src/correction/index.ts +2 -0
- package/src/correction/intent.ts +172 -0
- package/src/drivers/archive.ts +102 -0
- package/src/drivers/contain.ts +20 -0
- package/src/drivers/environment.ts +28 -0
- package/src/drivers/errors.ts +6 -0
- package/src/drivers/glob.ts +137 -0
- package/src/drivers/process.ts +340 -0
- package/src/drivers/redact.ts +31 -0
- package/src/drivers/seccomp-helper-source.ts +121 -0
- package/src/drivers/utils.ts +10 -0
- package/src/drivers/workspace.ts +40 -0
- package/src/extensions/provider-adapter.ts +99 -0
- package/src/host.ts +140 -0
- package/src/index.ts +64 -0
- package/src/model/artifact-collection.ts +237 -0
- package/src/model/authority.ts +116 -0
- package/src/model/bun-targets.ts +34 -0
- package/src/model/canonical.ts +205 -0
- package/src/model/catalog.ts +220 -0
- package/src/model/digest.ts +172 -0
- package/src/model/errors.ts +6 -0
- package/src/model/primitives.ts +37 -0
- package/src/model/pypi.ts +30 -0
- package/src/model/python-distribution.ts +360 -0
- package/src/model/secret-patterns.ts +11 -0
- package/src/platform/bun.ts +38 -0
- package/src/platform/credentials.ts +1083 -0
- package/src/platform/host-support.ts +4 -0
- package/src/platform/node.ts +38 -0
- package/src/platform/release-runtime.ts +47 -0
- package/src/platform/services.ts +57 -0
- package/src/platform/source-observer.ts +193 -0
- package/src/provider-sdk.ts +48 -0
- package/src/publication/adapter.ts +132 -0
- package/src/publication/authority.ts +397 -0
- package/src/publication/catalog-git.ts +603 -0
- package/src/publication/claim.ts +51 -0
- package/src/publication/coordinator.ts +578 -0
- package/src/publication/github.ts +954 -0
- package/src/publication/http.ts +101 -0
- package/src/publication/index.ts +4 -0
- package/src/publication/npm.ts +525 -0
- package/src/publication/profiles.ts +94 -0
- package/src/publication/publisher.ts +130 -0
- package/src/publication/pypi.ts +463 -0
- package/src/publication/recovery.ts +349 -0
- package/src/publication/report.ts +628 -0
- package/src/recipes/config.ts +395 -0
- package/src/release/capabilities.ts +459 -0
- package/src/release/compiler.ts +28 -0
- package/src/release/config.ts +12 -0
- package/src/release/context.ts +223 -0
- package/src/release/graph.ts +866 -0
- package/src/release/inspect.ts +83 -0
- package/src/release/prepare.ts +1331 -0
- package/src/release/prepared-ref.ts +193 -0
- package/src/release/prepared-store.ts +377 -0
- package/src/release/prepared.ts +299 -0
- package/src/release/staging.ts +257 -0
- package/src/resolve/authored.ts +64 -0
- package/src/resolve/encode.ts +22 -0
- package/src/resolve/errors.ts +15 -0
- package/src/resolve/facts.ts +18 -0
- package/src/resolve/resolve.ts +328 -0
- package/src/store.ts +28 -0
- package/templates/README.md +55 -72
- package/templates/bun-cli-github/README.md +7 -9
- package/templates/bun-cli-github/release.config.json +35 -73
- package/templates/github-actions/release.yml +57 -0
- package/templates/github-actions/reviewed-release.yml +80 -0
- package/templates/multi-target-homebrew/README.md +10 -0
- package/templates/multi-target-homebrew/release.config.json +43 -60
- package/templates/multi-target-scoop/README.md +10 -0
- package/templates/multi-target-scoop/release.config.json +43 -62
- package/templates/npm-github/release.config.json +25 -38
- package/templates/npm-github/reviewed-release.config.json +37 -0
- package/templates/npm-only/README.md +10 -0
- package/templates/npm-only/release.config.json +15 -30
- package/templates/portable-cli/README.md +13 -0
- package/templates/portable-cli/release.config.json +53 -0
- package/dist/artifacts/adapter.d.ts +0 -39
- package/dist/artifacts/adapter.d.ts.map +0 -1
- package/dist/artifacts/adapter.js +0 -23
- package/dist/artifacts/adapter.js.map +0 -1
- package/dist/artifacts/registry.d.ts +0 -21
- package/dist/artifacts/registry.d.ts.map +0 -1
- package/dist/artifacts/registry.js +0 -21
- package/dist/artifacts/registry.js.map +0 -1
- package/dist/config/errors.d.ts +0 -24
- package/dist/config/errors.d.ts.map +0 -1
- package/dist/config/errors.js +0 -19
- package/dist/config/errors.js.map +0 -1
- package/dist/config/load.d.ts +0 -9
- package/dist/config/load.d.ts.map +0 -1
- package/dist/config/load.js +0 -29
- package/dist/config/load.js.map +0 -1
- package/dist/config/schema.d.ts +0 -12
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/config/schema.js +0 -19
- package/dist/config/schema.js.map +0 -1
- package/dist/domain/artifact.d.ts +0 -118
- package/dist/domain/artifact.d.ts.map +0 -1
- package/dist/domain/artifact.js +0 -197
- package/dist/domain/artifact.js.map +0 -1
- package/dist/domain/evidence.d.ts +0 -59
- package/dist/domain/evidence.d.ts.map +0 -1
- package/dist/domain/evidence.js +0 -51
- package/dist/domain/evidence.js.map +0 -1
- package/dist/domain/operation.d.ts +0 -143
- package/dist/domain/operation.d.ts.map +0 -1
- package/dist/domain/operation.js +0 -198
- package/dist/domain/operation.js.map +0 -1
- package/dist/domain/release.d.ts +0 -93
- package/dist/domain/release.d.ts.map +0 -1
- package/dist/domain/release.js +0 -82
- package/dist/domain/release.js.map +0 -1
- package/dist/domain/remote-state.d.ts +0 -58
- package/dist/domain/remote-state.d.ts.map +0 -1
- package/dist/domain/remote-state.js +0 -55
- package/dist/domain/remote-state.js.map +0 -1
- package/dist/domain/target.d.ts +0 -148
- package/dist/domain/target.d.ts.map +0 -1
- package/dist/domain/target.js +0 -151
- package/dist/domain/target.js.map +0 -1
- package/dist/host/host.d.ts +0 -32
- package/dist/host/host.d.ts.map +0 -1
- package/dist/host/host.js +0 -24
- package/dist/host/host.js.map +0 -1
- package/dist/host/http-live.d.ts +0 -6
- package/dist/host/http-live.d.ts.map +0 -1
- package/dist/host/http-live.js +0 -86
- package/dist/host/http-live.js.map +0 -1
- package/dist/host/http.d.ts +0 -43
- package/dist/host/http.d.ts.map +0 -1
- package/dist/host/http.js +0 -59
- package/dist/host/http.js.map +0 -1
- package/dist/host/platform.d.ts +0 -10
- package/dist/host/platform.d.ts.map +0 -1
- package/dist/host/platform.js +0 -114
- package/dist/host/platform.js.map +0 -1
- package/dist/host/test.d.ts +0 -23
- package/dist/host/test.d.ts.map +0 -1
- package/dist/host/test.js +0 -222
- package/dist/host/test.js.map +0 -1
- package/dist/internal/workspace-path.d.ts +0 -15
- package/dist/internal/workspace-path.d.ts.map +0 -1
- package/dist/internal/workspace-path.js +0 -36
- package/dist/internal/workspace-path.js.map +0 -1
- package/dist/planner/artifact-inventory.d.ts +0 -9
- package/dist/planner/artifact-inventory.d.ts.map +0 -1
- package/dist/planner/artifact-inventory.js +0 -86
- package/dist/planner/artifact-inventory.js.map +0 -1
- package/dist/planner/create-release-plan.d.ts +0 -5
- package/dist/planner/create-release-plan.d.ts.map +0 -1
- package/dist/planner/create-release-plan.js +0 -25
- package/dist/planner/create-release-plan.js.map +0 -1
- package/dist/planner/errors.d.ts +0 -67
- package/dist/planner/errors.d.ts.map +0 -1
- package/dist/planner/errors.js +0 -58
- package/dist/planner/errors.js.map +0 -1
- package/dist/planner/evidence-recorder.d.ts +0 -28
- package/dist/planner/evidence-recorder.d.ts.map +0 -1
- package/dist/planner/evidence-recorder.js +0 -362
- package/dist/planner/evidence-recorder.js.map +0 -1
- package/dist/planner/executor.d.ts +0 -58
- package/dist/planner/executor.d.ts.map +0 -1
- package/dist/planner/executor.js +0 -147
- package/dist/planner/executor.js.map +0 -1
- package/dist/planner/normalize-release.d.ts +0 -19
- package/dist/planner/normalize-release.d.ts.map +0 -1
- package/dist/planner/normalize-release.js +0 -342
- package/dist/planner/normalize-release.js.map +0 -1
- package/dist/planner/reconcile.d.ts +0 -17
- package/dist/planner/reconcile.d.ts.map +0 -1
- package/dist/planner/reconcile.js +0 -259
- package/dist/planner/reconcile.js.map +0 -1
- package/dist/planner/render-plan.d.ts +0 -15
- package/dist/planner/render-plan.d.ts.map +0 -1
- package/dist/planner/render-plan.js +0 -231
- package/dist/planner/render-plan.js.map +0 -1
- package/dist/targets/adapter-helpers.d.ts +0 -79
- package/dist/targets/adapter-helpers.d.ts.map +0 -1
- package/dist/targets/adapter-helpers.js +0 -194
- package/dist/targets/adapter-helpers.js.map +0 -1
- package/dist/targets/adapter.d.ts +0 -17
- package/dist/targets/adapter.d.ts.map +0 -1
- package/dist/targets/adapter.js +0 -2
- package/dist/targets/adapter.js.map +0 -1
- package/dist/targets/github-release.d.ts +0 -25
- package/dist/targets/github-release.d.ts.map +0 -1
- package/dist/targets/github-release.js +0 -82
- package/dist/targets/github-release.js.map +0 -1
- package/dist/targets/github.d.ts +0 -11
- package/dist/targets/github.d.ts.map +0 -1
- package/dist/targets/github.js +0 -117
- package/dist/targets/github.js.map +0 -1
- package/dist/targets/homebrew.d.ts +0 -11
- package/dist/targets/homebrew.d.ts.map +0 -1
- package/dist/targets/homebrew.js +0 -210
- package/dist/targets/homebrew.js.map +0 -1
- package/dist/targets/live.d.ts +0 -5
- package/dist/targets/live.d.ts.map +0 -1
- package/dist/targets/live.js +0 -50
- package/dist/targets/live.js.map +0 -1
- package/dist/targets/npm.d.ts +0 -10
- package/dist/targets/npm.d.ts.map +0 -1
- package/dist/targets/npm.js +0 -112
- package/dist/targets/npm.js.map +0 -1
- package/dist/targets/pypi.d.ts +0 -11
- package/dist/targets/pypi.d.ts.map +0 -1
- package/dist/targets/pypi.js +0 -141
- package/dist/targets/pypi.js.map +0 -1
- package/dist/targets/registry.d.ts +0 -25
- package/dist/targets/registry.d.ts.map +0 -1
- package/dist/targets/registry.js +0 -34
- package/dist/targets/registry.js.map +0 -1
- package/dist/targets/scoop.d.ts +0 -11
- package/dist/targets/scoop.d.ts.map +0 -1
- package/dist/targets/scoop.js +0 -88
- package/dist/targets/scoop.js.map +0 -1
- package/dist/types/effect-internal.d.ts +0 -5
- package/dist/types/effect-internal.d.ts.map +0 -1
- package/dist/types/effect-internal.js +0 -2
- package/dist/types/effect-internal.js.map +0 -1
- package/dist/workflows/config.d.ts +0 -202
- package/dist/workflows/config.d.ts.map +0 -1
- package/dist/workflows/config.js +0 -420
- package/dist/workflows/config.js.map +0 -1
- package/dist/workflows/diagnostics.d.ts +0 -62
- package/dist/workflows/diagnostics.d.ts.map +0 -1
- package/dist/workflows/diagnostics.js +0 -530
- package/dist/workflows/diagnostics.js.map +0 -1
- package/dist/workflows/distribution.d.ts +0 -25
- package/dist/workflows/distribution.d.ts.map +0 -1
- package/dist/workflows/distribution.js +0 -24
- package/dist/workflows/distribution.js.map +0 -1
- package/dist/workflows/evidence.d.ts +0 -17
- package/dist/workflows/evidence.d.ts.map +0 -1
- package/dist/workflows/evidence.js +0 -32
- package/dist/workflows/evidence.js.map +0 -1
- package/dist/workflows/index.d.ts +0 -8
- package/dist/workflows/index.d.ts.map +0 -1
- package/dist/workflows/index.js +0 -7
- package/dist/workflows/index.js.map +0 -1
- package/dist/workflows/init.d.ts +0 -84
- package/dist/workflows/init.d.ts.map +0 -1
- package/dist/workflows/init.js +0 -487
- package/dist/workflows/init.js.map +0 -1
- package/dist/workflows/live.d.ts +0 -9
- package/dist/workflows/live.d.ts.map +0 -1
- package/dist/workflows/live.js +0 -7
- package/dist/workflows/live.js.map +0 -1
- package/dist/workflows/options.d.ts +0 -30
- package/dist/workflows/options.d.ts.map +0 -1
- package/dist/workflows/options.js +0 -16
- package/dist/workflows/options.js.map +0 -1
- package/examples/non-strict-skips/artifacts/release-example-skips-0.1.0.tgz +0 -1
- package/examples/non-strict-skips/release.config.json +0 -31
- package/examples/pypi-registry/release.config.json +0 -31
- package/templates/github-actions/plan-and-approved-execute.yml +0 -58
- package/templates/github-actions/plan-only.yml +0 -33
- package/templates/github-actions/trusted-publishing.yml +0 -61
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import * as Schema from "effect/Schema"
|
|
3
|
+
import { Sha256Hex } from "../model/digest.js"
|
|
4
|
+
|
|
5
|
+
const referenceSegmentPattern = /^[A-Za-z0-9._~-]{1,255}$/u
|
|
6
|
+
const positiveDecimalPattern = /^[1-9][0-9]*$/u
|
|
7
|
+
|
|
8
|
+
/** The lowercase hexadecimal payload of a SHA-256 digest. */
|
|
9
|
+
export const PreparedReleaseSha256 = Sha256Hex
|
|
10
|
+
export type PreparedReleaseSha256 = Sha256Hex
|
|
11
|
+
|
|
12
|
+
const GitHubReferenceSegment = Schema.String.check(
|
|
13
|
+
Schema.makeFilter((value: string) =>
|
|
14
|
+
referenceSegmentPattern.test(value) && value !== "." && value !== ".."
|
|
15
|
+
? undefined
|
|
16
|
+
: "GitHub prepared-reference segments must be nonempty URI-unreserved tokens.")
|
|
17
|
+
).pipe(Schema.brand("GitHubPreparedReferenceSegment"))
|
|
18
|
+
|
|
19
|
+
const GitHubRunCoordinate = Schema.String.check(
|
|
20
|
+
Schema.makeFilter((value: string) =>
|
|
21
|
+
positiveDecimalPattern.test(value)
|
|
22
|
+
? undefined
|
|
23
|
+
: "GitHub run coordinates must be canonical positive decimal strings.")
|
|
24
|
+
).pipe(Schema.brand("GitHubPreparedReferenceRunCoordinate"))
|
|
25
|
+
|
|
26
|
+
/** A complete bundle in the configured/default local content-addressed store. */
|
|
27
|
+
export class LocalCompletePreparedReleaseRef
|
|
28
|
+
extends Schema.TaggedClass<LocalCompletePreparedReleaseRef>()("LocalCompletePreparedReleaseRef", {
|
|
29
|
+
kind: Schema.Literal("complete"),
|
|
30
|
+
scheme: Schema.Literal("local"),
|
|
31
|
+
digest: PreparedReleaseSha256
|
|
32
|
+
}) {}
|
|
33
|
+
|
|
34
|
+
/** A complete bundle in a durable GitHub Actions artifact store. */
|
|
35
|
+
export class GitHubActionsCompletePreparedReleaseRef
|
|
36
|
+
extends Schema.TaggedClass<GitHubActionsCompletePreparedReleaseRef>()("GitHubActionsCompletePreparedReleaseRef", {
|
|
37
|
+
kind: Schema.Literal("complete"),
|
|
38
|
+
scheme: Schema.Literal("gha"),
|
|
39
|
+
owner: GitHubReferenceSegment,
|
|
40
|
+
repository: GitHubReferenceSegment,
|
|
41
|
+
runId: GitHubRunCoordinate,
|
|
42
|
+
attempt: GitHubRunCoordinate,
|
|
43
|
+
artifactName: GitHubReferenceSegment,
|
|
44
|
+
digest: PreparedReleaseSha256
|
|
45
|
+
}) {}
|
|
46
|
+
|
|
47
|
+
/** Every complete prepared-release reference accepted by the kernel. */
|
|
48
|
+
export const CompletePreparedReleaseRef = Schema.Union([
|
|
49
|
+
LocalCompletePreparedReleaseRef,
|
|
50
|
+
GitHubActionsCompletePreparedReleaseRef
|
|
51
|
+
])
|
|
52
|
+
export type CompletePreparedReleaseRef = typeof CompletePreparedReleaseRef.Type
|
|
53
|
+
|
|
54
|
+
export class PreparedReleaseRefMalformedError
|
|
55
|
+
extends Schema.TaggedErrorClass<PreparedReleaseRefMalformedError>()("PreparedReleaseRefMalformedError", {
|
|
56
|
+
reason: Schema.String
|
|
57
|
+
}) {}
|
|
58
|
+
|
|
59
|
+
export class PreparedReleaseRefUnknownSchemeError
|
|
60
|
+
extends Schema.TaggedErrorClass<PreparedReleaseRefUnknownSchemeError>()("PreparedReleaseRefUnknownSchemeError", {
|
|
61
|
+
scheme: Schema.String
|
|
62
|
+
}) {}
|
|
63
|
+
|
|
64
|
+
export const PreparedReleaseRefCodecError = Schema.Union([
|
|
65
|
+
PreparedReleaseRefMalformedError,
|
|
66
|
+
PreparedReleaseRefUnknownSchemeError
|
|
67
|
+
])
|
|
68
|
+
export type PreparedReleaseRefCodecError = typeof PreparedReleaseRefCodecError.Type
|
|
69
|
+
|
|
70
|
+
export interface GitHubActionsCompletePreparedReleaseRefInput {
|
|
71
|
+
readonly owner: string
|
|
72
|
+
readonly repository: string
|
|
73
|
+
readonly runId: string
|
|
74
|
+
readonly attempt: string
|
|
75
|
+
readonly artifactName: string
|
|
76
|
+
readonly digest: string
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const malformed = (reason: string): PreparedReleaseRefMalformedError =>
|
|
80
|
+
PreparedReleaseRefMalformedError.make({ reason })
|
|
81
|
+
|
|
82
|
+
const validateDigest = (digest: string): Effect.Effect<PreparedReleaseSha256, PreparedReleaseRefMalformedError> =>
|
|
83
|
+
Schema.is(Sha256Hex)(digest)
|
|
84
|
+
? Effect.succeed(digest)
|
|
85
|
+
: Effect.fail(malformed("The digest must contain exactly 64 lowercase hexadecimal characters."))
|
|
86
|
+
|
|
87
|
+
const validateSegment = (
|
|
88
|
+
value: string,
|
|
89
|
+
field: string
|
|
90
|
+
): Effect.Effect<typeof GitHubReferenceSegment.Type, PreparedReleaseRefMalformedError> =>
|
|
91
|
+
referenceSegmentPattern.test(value) && value !== "." && value !== ".."
|
|
92
|
+
? Effect.succeed(GitHubReferenceSegment.make(value))
|
|
93
|
+
: Effect.fail(malformed(`${field} must be a nonempty URI-unreserved token.`))
|
|
94
|
+
|
|
95
|
+
const validateRunCoordinate = (
|
|
96
|
+
value: string,
|
|
97
|
+
field: string
|
|
98
|
+
): Effect.Effect<typeof GitHubRunCoordinate.Type, PreparedReleaseRefMalformedError> =>
|
|
99
|
+
positiveDecimalPattern.test(value)
|
|
100
|
+
? Effect.succeed(GitHubRunCoordinate.make(value))
|
|
101
|
+
: Effect.fail(malformed(`${field} must be a canonical positive decimal string.`))
|
|
102
|
+
|
|
103
|
+
export const makeLocalCompletePreparedReleaseRef = Effect.fn("makeLocalCompletePreparedReleaseRef")(
|
|
104
|
+
function*(digest: string) {
|
|
105
|
+
return LocalCompletePreparedReleaseRef.make({
|
|
106
|
+
kind: "complete",
|
|
107
|
+
scheme: "local",
|
|
108
|
+
digest: yield* validateDigest(digest)
|
|
109
|
+
})
|
|
110
|
+
}
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
export const makeGitHubActionsCompletePreparedReleaseRef = Effect.fn(
|
|
114
|
+
"makeGitHubActionsCompletePreparedReleaseRef"
|
|
115
|
+
)(function*(input: GitHubActionsCompletePreparedReleaseRefInput) {
|
|
116
|
+
return GitHubActionsCompletePreparedReleaseRef.make({
|
|
117
|
+
kind: "complete",
|
|
118
|
+
scheme: "gha",
|
|
119
|
+
owner: yield* validateSegment(input.owner, "owner"),
|
|
120
|
+
repository: yield* validateSegment(input.repository, "repository"),
|
|
121
|
+
runId: yield* validateRunCoordinate(input.runId, "runId"),
|
|
122
|
+
attempt: yield* validateRunCoordinate(input.attempt, "attempt"),
|
|
123
|
+
artifactName: yield* validateSegment(input.artifactName, "artifactName"),
|
|
124
|
+
digest: yield* validateDigest(input.digest)
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
|
|
128
|
+
export const isLocalCompletePreparedReleaseRef = (
|
|
129
|
+
value: unknown
|
|
130
|
+
): value is LocalCompletePreparedReleaseRef => Schema.is(LocalCompletePreparedReleaseRef)(value)
|
|
131
|
+
|
|
132
|
+
export const isGitHubActionsCompletePreparedReleaseRef = (
|
|
133
|
+
value: unknown
|
|
134
|
+
): value is GitHubActionsCompletePreparedReleaseRef => Schema.is(GitHubActionsCompletePreparedReleaseRef)(value)
|
|
135
|
+
|
|
136
|
+
/** Encode a validated complete reference to its single canonical CLI representation. */
|
|
137
|
+
export const encodeCompletePreparedReleaseRef = (reference: CompletePreparedReleaseRef): string =>
|
|
138
|
+
reference.scheme === "local"
|
|
139
|
+
? `prepared:local:sha256-${reference.digest}`
|
|
140
|
+
: `prepared:gha:${reference.owner}/${reference.repository}/runs/${reference.runId}/attempts/${reference.attempt}/artifacts/${reference.artifactName}#sha256-${reference.digest}`
|
|
141
|
+
|
|
142
|
+
const githubActionsPayloadPattern =
|
|
143
|
+
/^([A-Za-z0-9._~-]{1,255})\/([A-Za-z0-9._~-]{1,255})\/runs\/([1-9][0-9]*)\/attempts\/([1-9][0-9]*)\/artifacts\/([A-Za-z0-9._~-]{1,255})#sha256-([a-f0-9]{64})$/u
|
|
144
|
+
|
|
145
|
+
/** Decode only the canonical `prepared:local:` and `prepared:gha:` grammars. */
|
|
146
|
+
export const decodeCompletePreparedReleaseRef = Effect.fn("decodeCompletePreparedReleaseRef")(
|
|
147
|
+
function*(input: unknown) {
|
|
148
|
+
if (typeof input !== "string") {
|
|
149
|
+
return yield* malformed("A prepared reference must be a string.")
|
|
150
|
+
}
|
|
151
|
+
if (!input.startsWith("prepared:")) {
|
|
152
|
+
return yield* malformed("A prepared reference must start with 'prepared:'.")
|
|
153
|
+
}
|
|
154
|
+
const schemeEnd = input.indexOf(":", "prepared:".length)
|
|
155
|
+
if (schemeEnd < 0) {
|
|
156
|
+
return yield* malformed("A prepared reference must include a scheme and payload.")
|
|
157
|
+
}
|
|
158
|
+
const scheme = input.slice("prepared:".length, schemeEnd)
|
|
159
|
+
const payload = input.slice(schemeEnd + 1)
|
|
160
|
+
if (scheme !== "local" && scheme !== "gha") {
|
|
161
|
+
if (scheme.length === 0) {
|
|
162
|
+
return yield* malformed("A prepared reference scheme must be nonempty.")
|
|
163
|
+
}
|
|
164
|
+
return yield* PreparedReleaseRefUnknownSchemeError.make({ scheme })
|
|
165
|
+
}
|
|
166
|
+
if (scheme === "local") {
|
|
167
|
+
const match = /^sha256-([a-f0-9]{64})$/u.exec(payload)
|
|
168
|
+
if (match === null) {
|
|
169
|
+
return yield* malformed("A local reference payload must be 'sha256-' followed by 64 lowercase hexadecimal characters.")
|
|
170
|
+
}
|
|
171
|
+
return yield* makeLocalCompletePreparedReleaseRef(match[1]!)
|
|
172
|
+
}
|
|
173
|
+
const match = githubActionsPayloadPattern.exec(payload)
|
|
174
|
+
if (match === null || match[1] === "." || match[1] === ".." || match[2] === "." || match[2] === ".." ||
|
|
175
|
+
match[5] === "." || match[5] === "..") {
|
|
176
|
+
return yield* malformed(
|
|
177
|
+
"A GitHub Actions reference must contain canonical owner, repository, run, attempt, artifact, and SHA-256 coordinates."
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
const reference = yield* makeGitHubActionsCompletePreparedReleaseRef({
|
|
181
|
+
owner: match[1]!,
|
|
182
|
+
repository: match[2]!,
|
|
183
|
+
runId: match[3]!,
|
|
184
|
+
attempt: match[4]!,
|
|
185
|
+
artifactName: match[5]!,
|
|
186
|
+
digest: match[6]!
|
|
187
|
+
})
|
|
188
|
+
if (encodeCompletePreparedReleaseRef(reference) !== input) {
|
|
189
|
+
return yield* malformed("The prepared reference is not in canonical form.")
|
|
190
|
+
}
|
|
191
|
+
return reference
|
|
192
|
+
}
|
|
193
|
+
)
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import * as Context from "effect/Context"
|
|
3
|
+
import * as Schema from "effect/Schema"
|
|
4
|
+
import { constants, existsSync, lstatSync, mkdirSync, openSync, readdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, chmodSync, closeSync, fsyncSync } from "node:fs"
|
|
5
|
+
import { randomUUID } from "node:crypto"
|
|
6
|
+
import { basename, dirname, join } from "node:path"
|
|
7
|
+
import { secureRead, secureWrite } from "../drivers/workspace.js"
|
|
8
|
+
import { digestEquals, sha256Digest, Sha256Hex } from "../model/digest.js"
|
|
9
|
+
import { PreparedArtifact, PreparedReleaseV2, decodePreparedRelease, encodePreparedRelease } from "./prepared.js"
|
|
10
|
+
import { CompletePreparedReleaseRef, makeLocalCompletePreparedReleaseRef } from "./prepared-ref.js"
|
|
11
|
+
|
|
12
|
+
export class PreparedStoreError
|
|
13
|
+
extends Schema.TaggedErrorClass<PreparedStoreError>()("PreparedStoreError", { reason: Schema.String }) {}
|
|
14
|
+
|
|
15
|
+
export class PreparedStoreProvenanceError
|
|
16
|
+
extends Schema.TaggedErrorClass<PreparedStoreProvenanceError>()("PreparedStoreProvenanceError", {
|
|
17
|
+
scheme: Schema.Literals(["local", "gha"]),
|
|
18
|
+
reason: Schema.String
|
|
19
|
+
}) {}
|
|
20
|
+
|
|
21
|
+
export class LocalPreparedStoreProvenance
|
|
22
|
+
extends Schema.TaggedClass<LocalPreparedStoreProvenance>()("LocalPreparedStoreProvenance", {
|
|
23
|
+
scheme: Schema.Literal("local"),
|
|
24
|
+
filesystemRoot: Schema.NonEmptyString,
|
|
25
|
+
operatorBoundary: Schema.NonEmptyString
|
|
26
|
+
}) {}
|
|
27
|
+
|
|
28
|
+
export class GitHubActionsPreparedStoreProvenance
|
|
29
|
+
extends Schema.TaggedClass<GitHubActionsPreparedStoreProvenance>()("GitHubActionsPreparedStoreProvenance", {
|
|
30
|
+
scheme: Schema.Literal("gha"),
|
|
31
|
+
repository: Schema.NonEmptyString,
|
|
32
|
+
workflowRef: Schema.NonEmptyString,
|
|
33
|
+
workflowSha: Schema.NonEmptyString,
|
|
34
|
+
runId: Schema.NonEmptyString,
|
|
35
|
+
attempt: Schema.NonEmptyString,
|
|
36
|
+
candidateCommit: Schema.NonEmptyString,
|
|
37
|
+
artifactName: Schema.NonEmptyString,
|
|
38
|
+
artifactDigest: Schema.NonEmptyString,
|
|
39
|
+
allowedWriter: Schema.Literal("repository-workflow")
|
|
40
|
+
}) {}
|
|
41
|
+
|
|
42
|
+
export const PreparedStoreProvenance = Schema.Union([
|
|
43
|
+
LocalPreparedStoreProvenance,
|
|
44
|
+
GitHubActionsPreparedStoreProvenance
|
|
45
|
+
])
|
|
46
|
+
export type PreparedStoreProvenance = typeof PreparedStoreProvenance.Type
|
|
47
|
+
|
|
48
|
+
const canonicalPathEquals = (left: string, right: string): boolean => {
|
|
49
|
+
try { return realpathSync(left) === realpathSync(right) } catch { return false }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* GitHub artifact lookup is name-based and may span every rerun attempt in a
|
|
54
|
+
* workflow run. Bind the attempt as well as the content digest so an older
|
|
55
|
+
* prepared reference cannot be shadowed by a newer rerun's duplicate name.
|
|
56
|
+
*/
|
|
57
|
+
export const githubActionsPreparedArtifactName = (attempt: string, digest: string): string =>
|
|
58
|
+
`ts-release-prepared-${attempt}-${digest}`
|
|
59
|
+
|
|
60
|
+
export const verifyPreparedStoreProvenance = Effect.fn("verifyPreparedStoreProvenance")(function*(input: {
|
|
61
|
+
readonly reference: CompletePreparedReleaseRef
|
|
62
|
+
readonly bundle: PreparedBundle
|
|
63
|
+
readonly evidence: PreparedStoreProvenance
|
|
64
|
+
}) {
|
|
65
|
+
if (input.reference.kind !== "complete" || input.bundle.manifest.kind !== "complete") {
|
|
66
|
+
return yield* new PreparedStoreProvenanceError({
|
|
67
|
+
scheme: input.reference.scheme,
|
|
68
|
+
reason: "Prepared store provenance verifies only complete references and bundles."
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
const digest = sha256Digest(encodePreparedRelease(input.bundle.manifest)).hex
|
|
72
|
+
if (digest !== input.reference.digest.toString()) {
|
|
73
|
+
return yield* new PreparedStoreProvenanceError({
|
|
74
|
+
scheme: input.reference.scheme,
|
|
75
|
+
reason: "Prepared reference digest does not match canonical complete-bundle contents."
|
|
76
|
+
})
|
|
77
|
+
}
|
|
78
|
+
if (input.reference.scheme === "local") {
|
|
79
|
+
if (input.evidence.scheme !== "local" || input.evidence.filesystemRoot.trim().length === 0 ||
|
|
80
|
+
input.evidence.operatorBoundary.trim().length === 0 ||
|
|
81
|
+
!canonicalPathEquals(input.evidence.filesystemRoot, dirname(input.bundle.directory))) {
|
|
82
|
+
return yield* new PreparedStoreProvenanceError({
|
|
83
|
+
scheme: "local",
|
|
84
|
+
reason: "Local prepared bytes require an explicit filesystem/operator trust boundary."
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
return input.evidence
|
|
88
|
+
}
|
|
89
|
+
if (input.evidence.scheme !== "gha") {
|
|
90
|
+
return yield* new PreparedStoreProvenanceError({
|
|
91
|
+
scheme: "gha",
|
|
92
|
+
reason: "Local evidence cannot be promoted into GitHub Actions trust by copying bytes or a digest."
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
const coordinate = `${input.reference.owner}/${input.reference.repository}`
|
|
96
|
+
const mismatches = [
|
|
97
|
+
input.evidence.repository !== coordinate ? "repository" : undefined,
|
|
98
|
+
input.evidence.runId !== input.reference.runId.toString() ? "runId" : undefined,
|
|
99
|
+
input.evidence.attempt !== input.reference.attempt.toString() ? "attempt" : undefined,
|
|
100
|
+
input.evidence.candidateCommit !== input.bundle.manifest.source.commit.toString() ? "candidateCommit" : undefined,
|
|
101
|
+
input.evidence.artifactName !== input.reference.artifactName.toString() ? "artifactName" : undefined,
|
|
102
|
+
input.evidence.artifactDigest !== input.reference.digest.toString() ? "artifactDigest" : undefined,
|
|
103
|
+
!input.evidence.workflowRef.startsWith(`${coordinate}/.github/workflows/`) ||
|
|
104
|
+
!input.evidence.workflowRef.includes("@refs/") ? "workflowRef" : undefined,
|
|
105
|
+
!/^[a-f0-9]{40}(?:[a-f0-9]{24})?$/u.test(input.evidence.workflowSha) ? "workflowSha" : undefined,
|
|
106
|
+
input.reference.artifactName.toString() !== githubActionsPreparedArtifactName(
|
|
107
|
+
input.reference.attempt.toString(),
|
|
108
|
+
input.reference.digest.toString()
|
|
109
|
+
) ? "immutableArtifactName" : undefined
|
|
110
|
+
].filter((field): field is string => field !== undefined)
|
|
111
|
+
if (mismatches.length > 0) {
|
|
112
|
+
return yield* new PreparedStoreProvenanceError({
|
|
113
|
+
scheme: "gha",
|
|
114
|
+
reason: `Hosted prepared-store provenance mismatched ${mismatches.join(", ")}.`
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
return input.evidence
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The bytes are already durable and verified, but the host failed to expose
|
|
122
|
+
* their recovery reference before publication could continue. This is a
|
|
123
|
+
* post-commit abort, never a preparation failure.
|
|
124
|
+
*/
|
|
125
|
+
export class PreparedCommitHandoffError
|
|
126
|
+
extends Schema.TaggedErrorClass<PreparedCommitHandoffError>()("PreparedCommitHandoffError", {
|
|
127
|
+
prepared: CompletePreparedReleaseRef,
|
|
128
|
+
reason: Schema.String
|
|
129
|
+
}) {}
|
|
130
|
+
|
|
131
|
+
export const PreparedStoreFaultPoint = Schema.Literals([
|
|
132
|
+
"before-blob-write",
|
|
133
|
+
"after-blob-write",
|
|
134
|
+
"before-manifest-write",
|
|
135
|
+
"after-manifest-write",
|
|
136
|
+
"before-blob-directory-fsync",
|
|
137
|
+
"after-blob-directory-fsync",
|
|
138
|
+
"before-bundle-directory-fsync",
|
|
139
|
+
"after-bundle-directory-fsync",
|
|
140
|
+
"before-promotion",
|
|
141
|
+
"after-promotion",
|
|
142
|
+
"before-store-fsync",
|
|
143
|
+
"after-store-fsync",
|
|
144
|
+
"before-cleanup",
|
|
145
|
+
"after-cleanup"
|
|
146
|
+
])
|
|
147
|
+
export type PreparedStoreFaultPoint = typeof PreparedStoreFaultPoint.Type
|
|
148
|
+
|
|
149
|
+
/** Host-only fault seam used to prove the atomic store protocol. */
|
|
150
|
+
export interface PreparedStoreOptions {
|
|
151
|
+
readonly onFaultPoint?: (point: PreparedStoreFaultPoint) => void
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const equal = (left: Uint8Array, right: Uint8Array): boolean => left.length === right.length && left.every((byte, index) => byte === right[index])
|
|
155
|
+
const fail = (reason: string): never => { throw PreparedStoreError.make({ reason }) }
|
|
156
|
+
const causeReason = (cause: unknown): string =>
|
|
157
|
+
typeof cause === "object" && cause !== null && "reason" in cause && typeof cause.reason === "string"
|
|
158
|
+
? cause.reason
|
|
159
|
+
: cause instanceof Error
|
|
160
|
+
? cause.message
|
|
161
|
+
: String(cause)
|
|
162
|
+
const canonicalDirectory = (directory: string): string => {
|
|
163
|
+
if (!existsSync(directory)) mkdirSync(directory, { recursive: true, mode: 0o700 })
|
|
164
|
+
const real = realpathSync(directory)
|
|
165
|
+
if (real !== directory) fail("Prepared store root must not be a symlink.")
|
|
166
|
+
return real
|
|
167
|
+
}
|
|
168
|
+
const syncDirectory = (directory: string): void => {
|
|
169
|
+
const descriptor = openSync(directory, constants.O_RDONLY)
|
|
170
|
+
try { fsyncSync(descriptor) } finally { closeSync(descriptor) }
|
|
171
|
+
}
|
|
172
|
+
const artifactsById = (manifest: PreparedReleaseV2): Map<string, PreparedArtifact> => {
|
|
173
|
+
if (manifest.kind !== "complete") fail("Prepared store accepts only a kind:'complete' publication bundle.")
|
|
174
|
+
const result = new Map<string, PreparedArtifact>()
|
|
175
|
+
for (const artifact of manifest.artifacts) {
|
|
176
|
+
const id = artifact.id.toString()
|
|
177
|
+
if (result.has(id)) fail(`Prepared manifest repeats artifact ${id}.`)
|
|
178
|
+
if (!digestEquals(artifact.digest, artifact.blob)) {
|
|
179
|
+
fail(`Prepared artifact ${id} does not carry a canonical SHA-256 blob reference.`)
|
|
180
|
+
}
|
|
181
|
+
result.set(id, artifact)
|
|
182
|
+
}
|
|
183
|
+
return result
|
|
184
|
+
}
|
|
185
|
+
const validatePublications = (manifest: PreparedReleaseV2, artifacts: Map<string, PreparedArtifact>): void => {
|
|
186
|
+
const ids = new Set<string>()
|
|
187
|
+
for (const publication of manifest.publications) {
|
|
188
|
+
if (ids.has(publication.id.toString())) fail(`Prepared manifest repeats publication ${publication.id}.`)
|
|
189
|
+
ids.add(publication.id.toString())
|
|
190
|
+
const references = publication._tag === "PreparedNpmPublication"
|
|
191
|
+
? [publication.artifactId]
|
|
192
|
+
: publication._tag === "PreparedPyPiPublication"
|
|
193
|
+
? publication.files.map((file) => file.artifactId)
|
|
194
|
+
: publication._tag === "PreparedGitHubPublication"
|
|
195
|
+
? publication.assets.map((asset) => asset.artifactId)
|
|
196
|
+
: [publication.targetArtifactId, publication.stateArtifactId]
|
|
197
|
+
for (const id of references) if (!artifacts.has(id.toString())) fail(`Publication ${publication.id} references missing artifact ${id}.`)
|
|
198
|
+
if (publication._tag === "PreparedPyPiPublication") for (const file of publication.files) {
|
|
199
|
+
const artifact = artifacts.get(file.artifactId.toString())!
|
|
200
|
+
if (artifact.size !== file.size || !digestEquals(artifact.digest, file.sha256) ||
|
|
201
|
+
artifact.mediaType !== file.mediaType || artifact.path.toString().split("/").at(-1) !== file.filename.toString()) {
|
|
202
|
+
fail(`PyPI publication ${publication.id} file ${file.filename} disagrees with its prepared artifact.`)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (publication._tag === "PreparedGitHubPublication" && publication.body !== undefined && publication.body.length === 0) {
|
|
206
|
+
fail(`GitHub publication ${publication.id} carries an empty body.`)
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export interface PreparedBundle {
|
|
212
|
+
readonly directory: string
|
|
213
|
+
readonly manifest: PreparedReleaseV2
|
|
214
|
+
readonly blobs: ReadonlyMap<string, Uint8Array>
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export interface CommittedPreparedRelease {
|
|
218
|
+
readonly ref: CompletePreparedReleaseRef
|
|
219
|
+
readonly bundle: PreparedBundle
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const readBundle = (directory: string): PreparedBundle => {
|
|
223
|
+
const real = realpathSync(directory)
|
|
224
|
+
if (real !== directory || lstatSync(directory).isSymbolicLink()) fail("Prepared bundle directory must not be a symlink.")
|
|
225
|
+
const bytes = secureRead(directory, "prepared-release.json").bytes
|
|
226
|
+
const manifest = decodePreparedRelease(bytes)
|
|
227
|
+
if (manifest.kind !== "complete") fail("Prepared store refuses every unknown or partial bundle kind.")
|
|
228
|
+
const manifestDigest = sha256Digest(bytes).hex
|
|
229
|
+
if (basename(directory) !== manifestDigest) fail("Prepared bundle directory does not match its manifest digest.")
|
|
230
|
+
const entries = readdirSync(directory, { withFileTypes: true })
|
|
231
|
+
if (entries.some((entry) => entry.name !== "prepared-release.json" && entry.name !== "blobs")) fail("Prepared bundle contains an unexpected top-level entry.")
|
|
232
|
+
const blobDirectory = join(directory, "blobs")
|
|
233
|
+
if (!existsSync(blobDirectory) || lstatSync(blobDirectory).isSymbolicLink() || !statSync(blobDirectory).isDirectory()) fail("Prepared bundle is missing its real blobs directory.")
|
|
234
|
+
const artifacts = artifactsById(manifest)
|
|
235
|
+
validatePublications(manifest, artifacts)
|
|
236
|
+
const expectedBlobs = new Set([...artifacts.values()].map((artifact) => artifact.blob.hex))
|
|
237
|
+
const actualBlobs = new Set(readdirSync(blobDirectory, { withFileTypes: true }).map((entry) => {
|
|
238
|
+
if (!entry.isFile() || !Schema.is(Sha256Hex)(entry.name)) fail(`Prepared blob entry ${entry.name} is invalid.`)
|
|
239
|
+
return entry.name
|
|
240
|
+
}))
|
|
241
|
+
if (actualBlobs.size !== expectedBlobs.size || [...expectedBlobs].some((blob) => !actualBlobs.has(blob))) fail("Prepared bundle blob set does not match its manifest.")
|
|
242
|
+
const blobs = new Map<string, Uint8Array>()
|
|
243
|
+
for (const artifact of artifacts.values()) {
|
|
244
|
+
const blob = secureRead(directory, `blobs/${artifact.blob.hex}`).bytes
|
|
245
|
+
if (blob.length !== artifact.size || !digestEquals(sha256Digest(blob), artifact.digest)) fail(`Prepared blob ${artifact.id} failed size or digest verification.`)
|
|
246
|
+
blobs.set(artifact.id.toString(), new Uint8Array(blob))
|
|
247
|
+
}
|
|
248
|
+
return { directory: real, manifest, blobs }
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const atomicWrite = (directory: string, target: string, bytes: Uint8Array): void => {
|
|
252
|
+
const temporary = `${target}.${randomUUID()}.tmp`
|
|
253
|
+
secureWrite(directory, temporary, bytes)
|
|
254
|
+
renameSync(join(directory, temporary), join(directory, target))
|
|
255
|
+
chmodSync(join(directory, target), 0o400)
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
const writeBundle = (
|
|
259
|
+
storeDirectory: string,
|
|
260
|
+
manifest: PreparedReleaseV2,
|
|
261
|
+
blobs: ReadonlyMap<string, Uint8Array>,
|
|
262
|
+
options: PreparedStoreOptions = {}
|
|
263
|
+
): PreparedBundle => {
|
|
264
|
+
const fault = options.onFaultPoint ?? (() => undefined)
|
|
265
|
+
const store = canonicalDirectory(storeDirectory)
|
|
266
|
+
const manifestBytes = encodePreparedRelease(manifest)
|
|
267
|
+
if (manifest.kind !== "complete") fail("Prepared store commits only a kind:'complete' publication bundle.")
|
|
268
|
+
const manifestDigest = sha256Digest(manifestBytes).hex
|
|
269
|
+
const artifacts = artifactsById(manifest)
|
|
270
|
+
validatePublications(manifest, artifacts)
|
|
271
|
+
for (const artifact of artifacts.values()) {
|
|
272
|
+
const bytes = blobs.get(artifact.id.toString()) ?? fail(`No prepared bytes supplied for artifact ${artifact.id}.`)
|
|
273
|
+
if (bytes.length !== artifact.size || !digestEquals(sha256Digest(bytes), artifact.digest) || !digestEquals(artifact.blob, artifact.digest)) fail(`Prepared bytes do not match artifact ${artifact.id}.`)
|
|
274
|
+
}
|
|
275
|
+
const finalDirectory = join(store, manifestDigest)
|
|
276
|
+
if (existsSync(finalDirectory)) {
|
|
277
|
+
const existing = readBundle(finalDirectory)
|
|
278
|
+
if (!equal(secureRead(finalDirectory, "prepared-release.json").bytes, manifestBytes)) fail("Existing prepared bundle has a different manifest.")
|
|
279
|
+
return existing
|
|
280
|
+
}
|
|
281
|
+
const temporary = join(store, `.${manifestDigest}.${randomUUID()}.tmp`)
|
|
282
|
+
mkdirSync(join(temporary, "blobs"), { recursive: true, mode: 0o700 })
|
|
283
|
+
let promoted = false
|
|
284
|
+
try {
|
|
285
|
+
for (const artifact of artifacts.values()) {
|
|
286
|
+
fault("before-blob-write")
|
|
287
|
+
atomicWrite(join(temporary, "blobs"), artifact.blob.hex, blobs.get(artifact.id.toString())!)
|
|
288
|
+
fault("after-blob-write")
|
|
289
|
+
}
|
|
290
|
+
fault("before-manifest-write")
|
|
291
|
+
atomicWrite(temporary, "prepared-release.json", manifestBytes)
|
|
292
|
+
fault("after-manifest-write")
|
|
293
|
+
fault("before-blob-directory-fsync")
|
|
294
|
+
syncDirectory(join(temporary, "blobs"))
|
|
295
|
+
fault("after-blob-directory-fsync")
|
|
296
|
+
fault("before-bundle-directory-fsync")
|
|
297
|
+
syncDirectory(temporary)
|
|
298
|
+
fault("after-bundle-directory-fsync")
|
|
299
|
+
fault("before-promotion")
|
|
300
|
+
renameSync(temporary, finalDirectory)
|
|
301
|
+
promoted = true
|
|
302
|
+
fault("after-promotion")
|
|
303
|
+
fault("before-store-fsync")
|
|
304
|
+
syncDirectory(store)
|
|
305
|
+
fault("after-store-fsync")
|
|
306
|
+
} catch (cause) {
|
|
307
|
+
let cleanupFailure: unknown
|
|
308
|
+
if (existsSync(temporary)) {
|
|
309
|
+
try {
|
|
310
|
+
fault("before-cleanup")
|
|
311
|
+
rmSync(temporary, { recursive: true, force: true })
|
|
312
|
+
fault("after-cleanup")
|
|
313
|
+
} catch (cleanupCause) {
|
|
314
|
+
cleanupFailure = cleanupCause
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
if (!promoted && existsSync(finalDirectory)) {
|
|
318
|
+
const existing = readBundle(finalDirectory)
|
|
319
|
+
if (!equal(secureRead(finalDirectory, "prepared-release.json").bytes, manifestBytes)) {
|
|
320
|
+
fail("Concurrent prepared-store promotion produced a different manifest.")
|
|
321
|
+
}
|
|
322
|
+
return existing
|
|
323
|
+
}
|
|
324
|
+
if (cleanupFailure !== undefined) {
|
|
325
|
+
throw PreparedStoreError.make({
|
|
326
|
+
reason: `Prepared-store cleanup failed after ${cause instanceof Error ? cause.message : String(cause)}: ${cleanupFailure instanceof Error ? cleanupFailure.message : String(cleanupFailure)}`
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
if (cause instanceof PreparedStoreError) throw cause
|
|
330
|
+
throw PreparedStoreError.make({ reason: cause instanceof Error ? cause.message : String(cause) })
|
|
331
|
+
}
|
|
332
|
+
return readBundle(finalDirectory)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export const storePreparedRelease = Effect.fn("storePreparedRelease")((
|
|
336
|
+
storeDirectory: string,
|
|
337
|
+
manifest: PreparedReleaseV2,
|
|
338
|
+
blobs: ReadonlyMap<string, Uint8Array>,
|
|
339
|
+
options?: PreparedStoreOptions
|
|
340
|
+
) => Effect.try({ try: () => writeBundle(storeDirectory, manifest, blobs, options), catch: (cause) =>
|
|
341
|
+
cause instanceof PreparedStoreError ? cause : PreparedStoreError.make({ reason: causeReason(cause) })
|
|
342
|
+
}))
|
|
343
|
+
|
|
344
|
+
export const loadPreparedRelease = Effect.fn("loadPreparedRelease")((directory: string) => Effect.try({
|
|
345
|
+
try: () => readBundle(directory),
|
|
346
|
+
catch: (cause) => cause instanceof PreparedStoreError ? cause : PreparedStoreError.make({ reason: causeReason(cause) })
|
|
347
|
+
}))
|
|
348
|
+
|
|
349
|
+
/** The durable store boundary used by coordinators and host projections. */
|
|
350
|
+
export interface PreparedReleaseStoreShape {
|
|
351
|
+
readonly commit: (
|
|
352
|
+
manifest: PreparedReleaseV2,
|
|
353
|
+
blobs: ReadonlyMap<string, Uint8Array>
|
|
354
|
+
) => Effect.Effect<CommittedPreparedRelease, PreparedStoreError | PreparedCommitHandoffError>
|
|
355
|
+
readonly load: (reference: CompletePreparedReleaseRef) => Effect.Effect<PreparedBundle, PreparedStoreError>
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export class PreparedReleaseStore
|
|
359
|
+
extends Context.Service<PreparedReleaseStore, PreparedReleaseStoreShape>()("ts-release/PreparedReleaseStore") {}
|
|
360
|
+
|
|
361
|
+
/** A local store resolves digest-only references against one explicit root. */
|
|
362
|
+
export const makeLocalPreparedReleaseStore = (
|
|
363
|
+
storeDirectory: string,
|
|
364
|
+
options?: PreparedStoreOptions
|
|
365
|
+
): PreparedReleaseStoreShape => ({
|
|
366
|
+
commit: (manifest, blobs) => storePreparedRelease(storeDirectory, manifest, blobs, options).pipe(
|
|
367
|
+
Effect.flatMap((bundle) => makeLocalCompletePreparedReleaseRef(basename(bundle.directory)).pipe(
|
|
368
|
+
Effect.map((ref) => ({ ref, bundle })),
|
|
369
|
+
Effect.mapError((cause) => PreparedStoreError.make({ reason: cause.reason }))
|
|
370
|
+
))
|
|
371
|
+
),
|
|
372
|
+
load: (reference) => reference.scheme === "local"
|
|
373
|
+
? loadPreparedRelease(join(storeDirectory, reference.digest))
|
|
374
|
+
: Effect.fail(PreparedStoreError.make({
|
|
375
|
+
reason: "A GitHub Actions prepared reference is not loadable by the local store; rerun the failed workflow publish job or dispatch its recovery workflow."
|
|
376
|
+
}))
|
|
377
|
+
})
|