@mannyc1/ts-release 0.0.6 → 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 -87
- package/CHANGELOG.md +115 -0
- package/LICENSE +21 -0
- package/README.md +272 -540
- package/SPEC.md +206 -305
- 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 +61 -154
- 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 -59
- package/templates/bun-cli-github/README.md +12 -0
- package/templates/bun-cli-github/release.config.json +51 -0
- 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/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 -36
- package/dist/domain/artifact.d.ts.map +0 -1
- package/dist/domain/artifact.js +0 -29
- package/dist/domain/artifact.js.map +0 -1
- package/dist/domain/evidence.d.ts +0 -108
- package/dist/domain/evidence.d.ts.map +0 -1
- package/dist/domain/evidence.js +0 -96
- package/dist/domain/evidence.js.map +0 -1
- package/dist/domain/operation.d.ts +0 -153
- package/dist/domain/operation.d.ts.map +0 -1
- package/dist/domain/operation.js +0 -320
- package/dist/domain/operation.js.map +0 -1
- package/dist/domain/release.d.ts +0 -141
- package/dist/domain/release.d.ts.map +0 -1
- package/dist/domain/release.js +0 -127
- package/dist/domain/release.js.map +0 -1
- package/dist/domain/remote-state.d.ts +0 -85
- package/dist/domain/remote-state.d.ts.map +0 -1
- package/dist/domain/remote-state.js +0 -77
- package/dist/domain/remote-state.js.map +0 -1
- package/dist/domain/status.d.ts +0 -43
- package/dist/domain/status.d.ts.map +0 -1
- package/dist/domain/status.js +0 -51
- package/dist/domain/status.js.map +0 -1
- package/dist/domain/target.d.ts +0 -135
- package/dist/domain/target.d.ts.map +0 -1
- package/dist/domain/target.js +0 -137
- 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/workflow-phases.d.ts +0 -3
- package/dist/internal/workflow-phases.d.ts.map +0 -1
- package/dist/internal/workflow-phases.js +0 -2
- package/dist/internal/workflow-phases.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 -84
- 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 -81
- package/dist/planner/errors.d.ts.map +0 -1
- package/dist/planner/errors.js +0 -70
- package/dist/planner/errors.js.map +0 -1
- package/dist/planner/evidence-recorder.d.ts +0 -26
- package/dist/planner/evidence-recorder.d.ts.map +0 -1
- package/dist/planner/evidence-recorder.js +0 -330
- 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 -159
- package/dist/planner/executor.js.map +0 -1
- package/dist/planner/normalize-release.d.ts +0 -16
- package/dist/planner/normalize-release.d.ts.map +0 -1
- package/dist/planner/normalize-release.js +0 -218
- 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 -261
- package/dist/planner/reconcile.js.map +0 -1
- package/dist/planner/release-eligibility.d.ts +0 -39
- package/dist/planner/release-eligibility.d.ts.map +0 -1
- package/dist/planner/release-eligibility.js +0 -578
- package/dist/planner/release-eligibility.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 -238
- package/dist/planner/render-plan.js.map +0 -1
- package/dist/planner/status.d.ts +0 -40
- package/dist/planner/status.d.ts.map +0 -1
- package/dist/planner/status.js +0 -313
- package/dist/planner/status.js.map +0 -1
- package/dist/targets/adapter-helpers.d.ts +0 -64
- package/dist/targets/adapter-helpers.d.ts.map +0 -1
- package/dist/targets/adapter-helpers.js +0 -124
- 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 -125
- 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 -97
- 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 -118
- 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 -103
- 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 -78
- 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 -252
- package/dist/workflows/config.d.ts.map +0 -1
- package/dist/workflows/config.js +0 -465
- 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 -527
- package/dist/workflows/diagnostics.js.map +0 -1
- package/dist/workflows/evidence.d.ts +0 -26
- package/dist/workflows/evidence.d.ts.map +0 -1
- package/dist/workflows/evidence.js +0 -44
- package/dist/workflows/evidence.js.map +0 -1
- package/dist/workflows/index.d.ts +0 -7
- package/dist/workflows/index.d.ts.map +0 -1
- package/dist/workflows/index.js +0 -6
- 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 -441
- 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,644 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { CredentialRequest as CredentialRequestSchema } from "../model/authority.js";
|
|
3
|
+
import { digestEquals, formatGitHubSha256, formatSha256Hex, parseGitHubSha256, sha256Digest } from "../model/digest.js";
|
|
4
|
+
import { NonEmptyName } from "../model/primitives.js";
|
|
5
|
+
import { ReleaseSubjectError } from "./coordinator.js";
|
|
6
|
+
import { AbsenceBasis, Applied, AuthoritativelyAbsent, Conflict, CreateAuthorizationProof, Difference, InconclusiveObservation, MutationPrecondition, NeedsMutation, OutcomeUnknown, PresentDifferent, PresentEquivalent, ProviderAlreadyEquivalent, ProviderAuthorizedCreate, ProviderBlocked, ProviderMutationFact, SafeReason, VisibilityBasis, VisibilityPending } from "./report.js";
|
|
7
|
+
import { makeRecoveryCapabilityProfile } from "./recovery.js";
|
|
8
|
+
const githubApiVersion = "2022-11-28";
|
|
9
|
+
const githubJsonHeaders = {
|
|
10
|
+
accept: "application/vnd.github+json",
|
|
11
|
+
"x-github-api-version": githubApiVersion
|
|
12
|
+
};
|
|
13
|
+
const gitObjectSha = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/u;
|
|
14
|
+
const maximumTagDepth = 32;
|
|
15
|
+
const maximumAssetPages = 1_000;
|
|
16
|
+
/**
|
|
17
|
+
* Timing values are policy bounds, not measured provider facts. They remain
|
|
18
|
+
* ASSUMED/UNVERIFIED until an explicitly authorized live run records evidence.
|
|
19
|
+
*/
|
|
20
|
+
export const githubRecoveryCapabilityProfile = makeRecoveryCapabilityProfile({
|
|
21
|
+
observation: "exact",
|
|
22
|
+
authoritativeAbsence: "provider-specific",
|
|
23
|
+
createAuthorization: "authenticated-namespace-and-unique-coordinate",
|
|
24
|
+
replay: "coordinate-unique",
|
|
25
|
+
identifierReuse: "reusable",
|
|
26
|
+
correction: [],
|
|
27
|
+
exposure: "persistent-to-consumers",
|
|
28
|
+
historyRequirement: "optional-evidence",
|
|
29
|
+
readConvergence: {
|
|
30
|
+
contract: {
|
|
31
|
+
_tag: "assumed",
|
|
32
|
+
basis: "ASSUMED/UNVERIFIED: no authorized live mutation evidence establishes GitHub read-convergence timing."
|
|
33
|
+
},
|
|
34
|
+
observationRetry: {
|
|
35
|
+
maxAttempts: 5,
|
|
36
|
+
backoff: { baseMs: 1_000, factor: 2, capMs: 15_000 },
|
|
37
|
+
totalBudgetMs: 60_000
|
|
38
|
+
},
|
|
39
|
+
retryEligible: "VisibilityPending | Inconclusive",
|
|
40
|
+
exhaustion: "UncertainSubject with full trace"
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const asObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value)
|
|
44
|
+
? value
|
|
45
|
+
: undefined;
|
|
46
|
+
const asString = (value) => typeof value === "string" ? value : undefined;
|
|
47
|
+
const asNonEmptyString = (value) => typeof value === "string" && value.length > 0 ? value : undefined;
|
|
48
|
+
const asBoolean = (value) => typeof value === "boolean" ? value : undefined;
|
|
49
|
+
const asNonNegativeSize = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
50
|
+
const asPositiveId = (value) => typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : undefined;
|
|
51
|
+
const parseJson = (body) => {
|
|
52
|
+
try {
|
|
53
|
+
const text = typeof body === "string"
|
|
54
|
+
? body
|
|
55
|
+
: new TextDecoder("utf-8", { fatal: true }).decode(body);
|
|
56
|
+
return JSON.parse(text);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const responseHeader = (response, name) => {
|
|
63
|
+
const lower = name.toLowerCase();
|
|
64
|
+
return Object.entries(response.headers).find(([candidate]) => candidate.toLowerCase() === lower)?.[1];
|
|
65
|
+
};
|
|
66
|
+
const repositoryFacts = (value) => {
|
|
67
|
+
const object = asObject(value);
|
|
68
|
+
const fullName = asNonEmptyString(object?.full_name);
|
|
69
|
+
return fullName === undefined ? undefined : { fullName };
|
|
70
|
+
};
|
|
71
|
+
const gitObjectFacts = (value) => {
|
|
72
|
+
const object = asObject(value);
|
|
73
|
+
const type = object?.type;
|
|
74
|
+
const sha = asString(object?.sha);
|
|
75
|
+
return (type !== "commit" && type !== "tag") || sha === undefined || !gitObjectSha.test(sha)
|
|
76
|
+
? undefined
|
|
77
|
+
: { type, sha };
|
|
78
|
+
};
|
|
79
|
+
const parseRef = (value, expectedRef) => {
|
|
80
|
+
const object = asObject(value);
|
|
81
|
+
return object?.ref !== expectedRef ? undefined : gitObjectFacts(object.object);
|
|
82
|
+
};
|
|
83
|
+
const parseTagObject = (value, expectedSha) => {
|
|
84
|
+
const object = asObject(value);
|
|
85
|
+
return object?.sha !== expectedSha ? undefined : gitObjectFacts(object.object);
|
|
86
|
+
};
|
|
87
|
+
const releaseFacts = (value) => {
|
|
88
|
+
const object = asObject(value);
|
|
89
|
+
const id = asPositiveId(object?.id);
|
|
90
|
+
const tag = asNonEmptyString(object?.tag_name);
|
|
91
|
+
const title = asString(object?.name);
|
|
92
|
+
const body = object?.body === null ? "" : asString(object?.body);
|
|
93
|
+
const draft = asBoolean(object?.draft);
|
|
94
|
+
const prerelease = asBoolean(object?.prerelease);
|
|
95
|
+
const uploadUrl = asNonEmptyString(object?.upload_url);
|
|
96
|
+
return id === undefined || tag === undefined || title === undefined || body === undefined ||
|
|
97
|
+
draft === undefined || prerelease === undefined || uploadUrl === undefined
|
|
98
|
+
? undefined
|
|
99
|
+
: { id, tag, title, body, draft, prerelease, uploadUrl };
|
|
100
|
+
};
|
|
101
|
+
const releaseAssetApiUrl = (publication, value) => {
|
|
102
|
+
if (typeof value !== "string")
|
|
103
|
+
return undefined;
|
|
104
|
+
const prefix = `${publication.authority.audience}/releases/assets/`;
|
|
105
|
+
const id = value.startsWith(prefix) ? value.slice(prefix.length) : "";
|
|
106
|
+
return /^[1-9][0-9]*$/u.test(id) ? value : undefined;
|
|
107
|
+
};
|
|
108
|
+
const releaseAssetDigest = (asset) => {
|
|
109
|
+
if (!Object.hasOwn(asset, "digest") || asset.digest === null)
|
|
110
|
+
return { _tag: "Missing" };
|
|
111
|
+
try {
|
|
112
|
+
return { _tag: "Present", value: parseGitHubSha256(asset.digest) };
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
return { _tag: "Malformed" };
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
const releaseAssetFacts = (publication, value) => {
|
|
119
|
+
const object = asObject(value);
|
|
120
|
+
if (object === undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
const name = asNonEmptyString(object.name);
|
|
123
|
+
const size = asNonNegativeSize(object.size);
|
|
124
|
+
const mediaType = asNonEmptyString(object.content_type);
|
|
125
|
+
const apiUrl = releaseAssetApiUrl(publication, object.url);
|
|
126
|
+
if (name === undefined || size === undefined || mediaType === undefined ||
|
|
127
|
+
object.state !== "uploaded" || apiUrl === undefined)
|
|
128
|
+
return undefined;
|
|
129
|
+
return {
|
|
130
|
+
name,
|
|
131
|
+
size,
|
|
132
|
+
mediaType,
|
|
133
|
+
state: "uploaded",
|
|
134
|
+
digest: releaseAssetDigest(object),
|
|
135
|
+
apiUrl
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
const observationRequests = (publication) => {
|
|
139
|
+
const make = (strategy) => CredentialRequestSchema.make({
|
|
140
|
+
subject: publication.authority.subject,
|
|
141
|
+
provider: publication.authority.provider,
|
|
142
|
+
audience: publication.authority.audience,
|
|
143
|
+
purpose: "observe",
|
|
144
|
+
strategy
|
|
145
|
+
});
|
|
146
|
+
const first = publication.authority.observationStrategies[0];
|
|
147
|
+
return [make(first), ...publication.authority.observationStrategies.slice(1).map(make)];
|
|
148
|
+
};
|
|
149
|
+
const mutationRequest = (publication) => CredentialRequestSchema.make({
|
|
150
|
+
subject: publication.authority.subject,
|
|
151
|
+
provider: publication.authority.provider,
|
|
152
|
+
audience: publication.authority.audience,
|
|
153
|
+
purpose: "publish",
|
|
154
|
+
strategy: publication.authority.publishStrategy
|
|
155
|
+
});
|
|
156
|
+
const valueFingerprint = (origin, value) => SafeReason.make(`${origin} value sha256-${formatSha256Hex(sha256Digest(new TextEncoder().encode(value)))}`);
|
|
157
|
+
const textDifference = (field, expected, observed) => Difference.make({
|
|
158
|
+
field: NonEmptyName.make(field),
|
|
159
|
+
expected: valueFingerprint("prepared", expected),
|
|
160
|
+
observed: valueFingerprint("provider", observed)
|
|
161
|
+
});
|
|
162
|
+
const scalarDifference = (field, expected, observed) => Difference.make({
|
|
163
|
+
field: NonEmptyName.make(field),
|
|
164
|
+
expected: SafeReason.make(String(expected)),
|
|
165
|
+
observed: SafeReason.make(String(observed))
|
|
166
|
+
});
|
|
167
|
+
const inconclusive = (publication, reason) => InconclusiveObservation.make({
|
|
168
|
+
subject: publication.authority.subject,
|
|
169
|
+
reason: SafeReason.make(reason)
|
|
170
|
+
});
|
|
171
|
+
const pending = (publication, detail) => VisibilityPending.make({
|
|
172
|
+
subject: publication.authority.subject,
|
|
173
|
+
expectation: SafeReason.make("The accepted GitHub mutation is expected to become exactly observable."),
|
|
174
|
+
basis: VisibilityBasis.make({
|
|
175
|
+
kind: NonEmptyName.make("github-read-convergence"),
|
|
176
|
+
detail: SafeReason.make(detail)
|
|
177
|
+
})
|
|
178
|
+
});
|
|
179
|
+
const absent = (publication, kind, detail) => AuthoritativelyAbsent.make({
|
|
180
|
+
subject: publication.authority.subject,
|
|
181
|
+
basis: AbsenceBasis.make({
|
|
182
|
+
kind: NonEmptyName.make(kind),
|
|
183
|
+
detail: SafeReason.make(detail)
|
|
184
|
+
})
|
|
185
|
+
});
|
|
186
|
+
const observationFailure = (publication, reason, commitment = "unknown") => new ReleaseSubjectError({
|
|
187
|
+
subject: publication.authority.subject,
|
|
188
|
+
phase: "observe",
|
|
189
|
+
commitment,
|
|
190
|
+
reason: SafeReason.make(reason)
|
|
191
|
+
});
|
|
192
|
+
const mapObservationError = (publication, error) => observationFailure(publication, "GitHub observation could not be completed by the host HTTP boundary.", error._tag === "CredentialPlatformError" ? error.commitment ?? "before-dispatch" : "before-dispatch");
|
|
193
|
+
const get = (publication, http, grant, url, accept = "application/vnd.github+json") => http.execute({
|
|
194
|
+
subject: publication.authority.subject,
|
|
195
|
+
method: "GET",
|
|
196
|
+
url,
|
|
197
|
+
headers: { accept, "x-github-api-version": githubApiVersion }
|
|
198
|
+
}, grant).pipe(Effect.mapError((error) => mapObservationError(publication, error)));
|
|
199
|
+
const releaseUrl = (publication) => `${publication.authority.audience}/releases/tags/${encodeURIComponent(publication.tag)}`;
|
|
200
|
+
const refUrl = (publication) => `${publication.authority.audience}/git/ref/tags/${encodeURIComponent(publication.tag)}`;
|
|
201
|
+
const tagObjectUrl = (publication, sha) => `${publication.authority.audience}/git/tags/${sha}`;
|
|
202
|
+
const assetsPageUrl = (publication, releaseId, page) => `${publication.authority.audience}/releases/${releaseId}/assets?per_page=100&page=${page}`;
|
|
203
|
+
const linkNextUrl = (value) => {
|
|
204
|
+
if (value === undefined)
|
|
205
|
+
return { malformed: false };
|
|
206
|
+
const matches = [...value.matchAll(/<([^>]+)>\s*;\s*rel="next"/gu)];
|
|
207
|
+
if (matches.length > 1 || (/rel="next"/u.test(value) && matches.length !== 1))
|
|
208
|
+
return { malformed: true };
|
|
209
|
+
const url = matches[0]?.[1];
|
|
210
|
+
return url === undefined ? { malformed: false } : { malformed: false, url };
|
|
211
|
+
};
|
|
212
|
+
const listAllAssets = Effect.fn("GitHubReleaseSubject.listAllAssets")(function* (publication, http, grant, releaseId) {
|
|
213
|
+
const assets = [];
|
|
214
|
+
let page = 1;
|
|
215
|
+
while (page <= maximumAssetPages) {
|
|
216
|
+
const expectedUrl = assetsPageUrl(publication, releaseId, page);
|
|
217
|
+
const response = yield* get(publication, http, grant, expectedUrl);
|
|
218
|
+
if (response.status !== 200) {
|
|
219
|
+
return { _tag: "Inconclusive", reason: `GitHub asset enumeration returned HTTP ${response.status}.` };
|
|
220
|
+
}
|
|
221
|
+
const raw = parseJson(response.body);
|
|
222
|
+
if (!Array.isArray(raw)) {
|
|
223
|
+
return { _tag: "Inconclusive", reason: "A GitHub asset page was malformed." };
|
|
224
|
+
}
|
|
225
|
+
const parsed = raw.map((value) => releaseAssetFacts(publication, value));
|
|
226
|
+
if (parsed.some((value) => value === undefined)) {
|
|
227
|
+
return {
|
|
228
|
+
_tag: "Inconclusive",
|
|
229
|
+
reason: "A GitHub asset page omitted or malformed an exact asset identity fact."
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
assets.push(...parsed);
|
|
233
|
+
const next = linkNextUrl(responseHeader(response, "link"));
|
|
234
|
+
if (next.malformed) {
|
|
235
|
+
return { _tag: "Inconclusive", reason: "GitHub asset pagination metadata was malformed." };
|
|
236
|
+
}
|
|
237
|
+
const computedNext = assetsPageUrl(publication, releaseId, page + 1);
|
|
238
|
+
if (next.url !== undefined && next.url !== computedNext) {
|
|
239
|
+
return {
|
|
240
|
+
_tag: "Inconclusive",
|
|
241
|
+
reason: "GitHub asset pagination left the exact prepared repository scope or skipped a page."
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
if (next.url === undefined && raw.length < 100) {
|
|
245
|
+
return { _tag: "Complete", assets };
|
|
246
|
+
}
|
|
247
|
+
page += 1;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
_tag: "Inconclusive",
|
|
251
|
+
reason: "GitHub asset pagination exceeded the bounded full-enumeration limit."
|
|
252
|
+
};
|
|
253
|
+
});
|
|
254
|
+
const compareReleaseMetadata = (publication, facts) => {
|
|
255
|
+
const differences = [];
|
|
256
|
+
if (facts.tag !== publication.tag.toString()) {
|
|
257
|
+
differences.push(textDifference("release.tag", publication.tag.toString(), facts.tag));
|
|
258
|
+
}
|
|
259
|
+
if (facts.title !== publication.title.toString()) {
|
|
260
|
+
differences.push(textDifference("release.title", publication.title.toString(), facts.title));
|
|
261
|
+
}
|
|
262
|
+
const expectedBody = publication.body ?? "";
|
|
263
|
+
if (facts.body !== expectedBody)
|
|
264
|
+
differences.push(textDifference("release.body", expectedBody, facts.body));
|
|
265
|
+
if (facts.draft !== publication.draft) {
|
|
266
|
+
differences.push(scalarDifference("release.draft", publication.draft, facts.draft));
|
|
267
|
+
}
|
|
268
|
+
if (facts.prerelease !== publication.prerelease) {
|
|
269
|
+
differences.push(scalarDifference("release.prerelease", publication.prerelease, facts.prerelease));
|
|
270
|
+
}
|
|
271
|
+
return differences;
|
|
272
|
+
};
|
|
273
|
+
const validateUploadUrl = (publication, releaseId, value) => value ===
|
|
274
|
+
`https://uploads.github.com/repos/${publication.repository}/releases/${releaseId}/assets{?name,label}`;
|
|
275
|
+
const presentDifferent = (publication, differences) => PresentDifferent.make({
|
|
276
|
+
subject: publication.authority.subject,
|
|
277
|
+
differences: differences
|
|
278
|
+
});
|
|
279
|
+
const decideFor = (publication, observation, plan) => {
|
|
280
|
+
switch (observation._tag) {
|
|
281
|
+
case "PresentEquivalent":
|
|
282
|
+
return ProviderAlreadyEquivalent.make({ subject: publication.authority.subject });
|
|
283
|
+
case "PresentDifferent":
|
|
284
|
+
return Conflict.make({ subject: publication.authority.subject, differences: observation.differences });
|
|
285
|
+
case "AuthoritativelyAbsent":
|
|
286
|
+
if (plan?._tag === "CreateRelease" && plan.tagAbsent) {
|
|
287
|
+
return ProviderAuthorizedCreate.make({
|
|
288
|
+
subject: publication.authority.subject,
|
|
289
|
+
proof: CreateAuthorizationProof.make({
|
|
290
|
+
kind: NonEmptyName.make("github-authenticated-repository-and-unique-tag")
|
|
291
|
+
})
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
if (plan?._tag === "CreateRelease") {
|
|
295
|
+
return NeedsMutation.make({
|
|
296
|
+
subject: publication.authority.subject,
|
|
297
|
+
precondition: MutationPrecondition.make({
|
|
298
|
+
kind: NonEmptyName.make("github-release-absent-at-exact-tag")
|
|
299
|
+
})
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
if (plan?._tag === "UploadAssets") {
|
|
303
|
+
return NeedsMutation.make({
|
|
304
|
+
subject: publication.authority.subject,
|
|
305
|
+
precondition: MutationPrecondition.make({
|
|
306
|
+
kind: NonEmptyName.make("github-intended-assets-authoritatively-absent")
|
|
307
|
+
})
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
return ProviderBlocked.make({
|
|
311
|
+
subject: publication.authority.subject,
|
|
312
|
+
reason: SafeReason.make("GitHub absence carried no exact mutation plan.")
|
|
313
|
+
});
|
|
314
|
+
case "VisibilityPending":
|
|
315
|
+
case "Inconclusive":
|
|
316
|
+
return ProviderBlocked.make({
|
|
317
|
+
subject: publication.authority.subject,
|
|
318
|
+
reason: SafeReason.make("GitHub publication truth is not yet conclusive enough to mutate.")
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
};
|
|
322
|
+
const mutationFailure = (publication, reason, commitment = "before-dispatch") => new ReleaseSubjectError({
|
|
323
|
+
subject: publication.authority.subject,
|
|
324
|
+
phase: "mutate",
|
|
325
|
+
commitment,
|
|
326
|
+
reason: SafeReason.make(reason)
|
|
327
|
+
});
|
|
328
|
+
const unknownAttempt = (publication, reason) => OutcomeUnknown.make({
|
|
329
|
+
subject: publication.authority.subject,
|
|
330
|
+
reason: SafeReason.make(reason)
|
|
331
|
+
});
|
|
332
|
+
const appliedAttempt = (publication) => Applied.make({
|
|
333
|
+
subject: publication.authority.subject,
|
|
334
|
+
fact: ProviderMutationFact.make({
|
|
335
|
+
subject: publication.authority.subject,
|
|
336
|
+
detail: SafeReason.make("GitHub accepted the release mutation and every planned asset upload.")
|
|
337
|
+
})
|
|
338
|
+
});
|
|
339
|
+
const executeMutation = (mutationHttp, operation, request, grant) => mutationHttp.execute(operation, request, grant).pipe(Effect.map((response) => ({ _tag: "Response", response })), Effect.catch((error) => Effect.succeed({ _tag: "Failure", error })));
|
|
340
|
+
const uploadRequest = (publication, uploadUrl, index, bytes) => {
|
|
341
|
+
const asset = publication.assets[index];
|
|
342
|
+
const template = "{?name,label}";
|
|
343
|
+
const expanded = `${uploadUrl.slice(0, -template.length)}?name=${encodeURIComponent(asset.name)}`;
|
|
344
|
+
return {
|
|
345
|
+
method: "POST",
|
|
346
|
+
url: expanded,
|
|
347
|
+
headers: {
|
|
348
|
+
...githubJsonHeaders,
|
|
349
|
+
"content-type": asset.mediaType,
|
|
350
|
+
"content-length": String(bytes.length)
|
|
351
|
+
},
|
|
352
|
+
body: bytes
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
/**
|
|
356
|
+
* The exact tag ref and recursively peeled commit are established before the
|
|
357
|
+
* release endpoint can contribute any equality or absence fact. Release
|
|
358
|
+
* target_commitish is intentionally ignored: GitHub does not make it a stable
|
|
359
|
+
* equality fact for a release whose tag already exists.
|
|
360
|
+
*/
|
|
361
|
+
export const makeGithubSubjects = (bundle, publication, http, mutationHttp) => {
|
|
362
|
+
let mutationPlan;
|
|
363
|
+
const observe = Effect.fn("GitHubReleaseSubject.observe")(function* (grant, context) {
|
|
364
|
+
mutationPlan = undefined;
|
|
365
|
+
const mutationMayStillBecomeVisible = context.phase === "post-mutation" &&
|
|
366
|
+
context.attempt._tag !== "RejectedBeforeDispatch" &&
|
|
367
|
+
context.attempt._tag !== "RejectedByProvider";
|
|
368
|
+
if (grant._tag === "WorkloadIdentity") {
|
|
369
|
+
return yield* observationFailure(publication, "Workload identity cannot authorize GitHub release observation.", "before-dispatch");
|
|
370
|
+
}
|
|
371
|
+
const targetCommit = publication.targetCommit.toString();
|
|
372
|
+
if (!gitObjectSha.test(targetCommit)) {
|
|
373
|
+
return inconclusive(publication, "The prepared GitHub target commit is not a canonical full Git object identifier.");
|
|
374
|
+
}
|
|
375
|
+
const intendedNames = publication.assets.map((asset) => asset.name);
|
|
376
|
+
if (new Set(intendedNames).size !== intendedNames.length) {
|
|
377
|
+
return inconclusive(publication, "The prepared GitHub release repeats an asset name and cannot define an exact set.");
|
|
378
|
+
}
|
|
379
|
+
if (publication.assets.some((asset) => bundle.blobs.get(asset.artifactId.toString()) === undefined)) {
|
|
380
|
+
return inconclusive(publication, "The prepared GitHub release is missing exact bytes for an intended asset.");
|
|
381
|
+
}
|
|
382
|
+
const repositoryResponse = yield* get(publication, http, grant, publication.authority.audience);
|
|
383
|
+
if (repositoryResponse.status !== 200) {
|
|
384
|
+
return inconclusive(publication, `GitHub repository visibility returned HTTP ${repositoryResponse.status}.`);
|
|
385
|
+
}
|
|
386
|
+
const repository = repositoryFacts(parseJson(repositoryResponse.body));
|
|
387
|
+
if (repository === undefined || repository.fullName !== publication.repository) {
|
|
388
|
+
return inconclusive(publication, "GitHub repository visibility did not establish the exact prepared repository coordinate.");
|
|
389
|
+
}
|
|
390
|
+
const referenceResponse = yield* get(publication, http, grant, refUrl(publication));
|
|
391
|
+
if (referenceResponse.status === 404) {
|
|
392
|
+
if (grant._tag === "AnonymousAccess") {
|
|
393
|
+
return inconclusive(publication, "Anonymous GitHub tag absence cannot authorize creation in the prepared namespace.");
|
|
394
|
+
}
|
|
395
|
+
const danglingRelease = yield* get(publication, http, grant, releaseUrl(publication));
|
|
396
|
+
if (danglingRelease.status === 200) {
|
|
397
|
+
return presentDifferent(publication, [scalarDifference("tag.exists", true, false)]);
|
|
398
|
+
}
|
|
399
|
+
if (danglingRelease.status !== 404) {
|
|
400
|
+
return inconclusive(publication, `GitHub release observation returned HTTP ${danglingRelease.status}.`);
|
|
401
|
+
}
|
|
402
|
+
if (mutationMayStillBecomeVisible) {
|
|
403
|
+
return pending(publication, "The exact GitHub tag and release are not visible after the accepted mutation.");
|
|
404
|
+
}
|
|
405
|
+
mutationPlan = { _tag: "CreateRelease", tagAbsent: true };
|
|
406
|
+
return absent(publication, "github-authenticated-tag-and-release-absent", "Authenticated exact-repository reads found neither the prepared tag nor its release coordinate.");
|
|
407
|
+
}
|
|
408
|
+
if (referenceResponse.status !== 200) {
|
|
409
|
+
return inconclusive(publication, `GitHub tag-ref observation returned HTTP ${referenceResponse.status}.`);
|
|
410
|
+
}
|
|
411
|
+
let object = parseRef(parseJson(referenceResponse.body), `refs/tags/${publication.tag}`);
|
|
412
|
+
if (object === undefined) {
|
|
413
|
+
return inconclusive(publication, "The GitHub tag-ref response was malformed or named a different ref.");
|
|
414
|
+
}
|
|
415
|
+
const visited = new Set();
|
|
416
|
+
for (let depth = 0; object.type === "tag"; depth += 1) {
|
|
417
|
+
if (depth >= maximumTagDepth || visited.has(object.sha)) {
|
|
418
|
+
return inconclusive(publication, "The GitHub annotated-tag chain was cyclic or exceeded its bounded peel depth.");
|
|
419
|
+
}
|
|
420
|
+
visited.add(object.sha);
|
|
421
|
+
const tagResponse = yield* get(publication, http, grant, tagObjectUrl(publication, object.sha));
|
|
422
|
+
if (tagResponse.status !== 200) {
|
|
423
|
+
return inconclusive(publication, `GitHub annotated-tag observation returned HTTP ${tagResponse.status}.`);
|
|
424
|
+
}
|
|
425
|
+
const peeled = parseTagObject(parseJson(tagResponse.body), object.sha);
|
|
426
|
+
if (peeled === undefined) {
|
|
427
|
+
return inconclusive(publication, "A GitHub annotated-tag object was malformed or changed identity while peeling.");
|
|
428
|
+
}
|
|
429
|
+
object = peeled;
|
|
430
|
+
}
|
|
431
|
+
if (object.sha !== targetCommit) {
|
|
432
|
+
return presentDifferent(publication, [textDifference("tag.commit", targetCommit, object.sha)]);
|
|
433
|
+
}
|
|
434
|
+
const releaseResponse = yield* get(publication, http, grant, releaseUrl(publication));
|
|
435
|
+
if (releaseResponse.status === 404) {
|
|
436
|
+
if (grant._tag === "AnonymousAccess") {
|
|
437
|
+
return inconclusive(publication, "Anonymous GitHub release absence may hide a draft release and is not authoritative.");
|
|
438
|
+
}
|
|
439
|
+
if (mutationMayStillBecomeVisible) {
|
|
440
|
+
return pending(publication, "The exact GitHub release is not yet visible after the accepted mutation.");
|
|
441
|
+
}
|
|
442
|
+
mutationPlan = { _tag: "CreateRelease", tagAbsent: false };
|
|
443
|
+
return absent(publication, "github-authenticated-release-absent", "Authenticated exact-repository reads found the prepared tag but no release at that tag.");
|
|
444
|
+
}
|
|
445
|
+
if (releaseResponse.status !== 200) {
|
|
446
|
+
return inconclusive(publication, `GitHub release observation returned HTTP ${releaseResponse.status}.`);
|
|
447
|
+
}
|
|
448
|
+
const release = releaseFacts(parseJson(releaseResponse.body));
|
|
449
|
+
if (release === undefined || !validateUploadUrl(publication, release.id, release.uploadUrl)) {
|
|
450
|
+
return inconclusive(publication, "The GitHub release response omitted identity facts or carried an invalid repository-scoped upload template.");
|
|
451
|
+
}
|
|
452
|
+
const releaseDifferences = compareReleaseMetadata(publication, release);
|
|
453
|
+
if (releaseDifferences.length > 0)
|
|
454
|
+
return presentDifferent(publication, releaseDifferences);
|
|
455
|
+
const listed = yield* listAllAssets(publication, http, grant, release.id);
|
|
456
|
+
if (listed._tag === "Inconclusive")
|
|
457
|
+
return inconclusive(publication, listed.reason);
|
|
458
|
+
const assetsByName = new Map();
|
|
459
|
+
for (const asset of listed.assets) {
|
|
460
|
+
const candidates = assetsByName.get(asset.name) ?? [];
|
|
461
|
+
candidates.push(asset);
|
|
462
|
+
assetsByName.set(asset.name, candidates);
|
|
463
|
+
}
|
|
464
|
+
const differences = [];
|
|
465
|
+
for (const [name, candidates] of assetsByName) {
|
|
466
|
+
if (!intendedNames.includes(name)) {
|
|
467
|
+
differences.push(textDifference("assets.extra-name", "no undeclared asset", name));
|
|
468
|
+
}
|
|
469
|
+
if (candidates.length > 1) {
|
|
470
|
+
differences.push(scalarDifference(`asset.${name}.count`, 1, candidates.length));
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
const missingIndexes = [];
|
|
474
|
+
const downloads = [];
|
|
475
|
+
for (const [index, intended] of publication.assets.entries()) {
|
|
476
|
+
const candidates = assetsByName.get(intended.name) ?? [];
|
|
477
|
+
if (candidates.length === 0) {
|
|
478
|
+
missingIndexes.push(index);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (candidates.length !== 1)
|
|
482
|
+
continue;
|
|
483
|
+
const observed = candidates[0];
|
|
484
|
+
const bytes = bundle.blobs.get(intended.artifactId.toString());
|
|
485
|
+
if (observed.size !== bytes.length) {
|
|
486
|
+
differences.push(scalarDifference(`asset.${intended.name}.size`, bytes.length, observed.size));
|
|
487
|
+
}
|
|
488
|
+
if (observed.mediaType !== intended.mediaType) {
|
|
489
|
+
differences.push(textDifference(`asset.${intended.name}.mediaType`, intended.mediaType, observed.mediaType));
|
|
490
|
+
}
|
|
491
|
+
const expected = sha256Digest(bytes);
|
|
492
|
+
if (observed.digest._tag === "Malformed") {
|
|
493
|
+
return inconclusive(publication, "A GitHub asset carried a malformed canonical sha256 digest.");
|
|
494
|
+
}
|
|
495
|
+
if (observed.digest._tag === "Missing") {
|
|
496
|
+
downloads.push({ index, facts: observed, expected });
|
|
497
|
+
}
|
|
498
|
+
else if (!digestEquals(observed.digest.value, expected)) {
|
|
499
|
+
differences.push(textDifference(`asset.${intended.name}.digest`, formatGitHubSha256(expected), formatGitHubSha256(observed.digest.value)));
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
if (differences.length > 0)
|
|
503
|
+
return presentDifferent(publication, differences);
|
|
504
|
+
for (const download of downloads) {
|
|
505
|
+
const response = yield* get(publication, http, grant, download.facts.apiUrl, "application/octet-stream").pipe(Effect.map((result) => ({ _tag: "Response", result })), Effect.catch(() => Effect.succeed({ _tag: "Unavailable" })));
|
|
506
|
+
if (response._tag === "Unavailable" || response.result.status !== 200) {
|
|
507
|
+
return inconclusive(publication, "GitHub asset bytes could not be downloaded for exact sha256 observation.");
|
|
508
|
+
}
|
|
509
|
+
const bytes = typeof response.result.body === "string"
|
|
510
|
+
? new TextEncoder().encode(response.result.body)
|
|
511
|
+
: response.result.body;
|
|
512
|
+
const digest = sha256Digest(bytes);
|
|
513
|
+
if (!digestEquals(digest, download.expected)) {
|
|
514
|
+
return presentDifferent(publication, [textDifference(`asset.${publication.assets[download.index].name}.digest`, formatGitHubSha256(download.expected), formatGitHubSha256(digest))]);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
if (missingIndexes.length > 0) {
|
|
518
|
+
if (mutationMayStillBecomeVisible) {
|
|
519
|
+
return pending(publication, "One or more intended GitHub assets are not yet visible after the accepted mutation.");
|
|
520
|
+
}
|
|
521
|
+
mutationPlan = {
|
|
522
|
+
_tag: "UploadAssets",
|
|
523
|
+
releaseId: release.id,
|
|
524
|
+
uploadUrl: release.uploadUrl,
|
|
525
|
+
assetIndexes: missingIndexes
|
|
526
|
+
};
|
|
527
|
+
return absent(publication, "github-intended-assets-absent", "A full paginated release-asset enumeration proved at least one intended asset name absent.");
|
|
528
|
+
}
|
|
529
|
+
return PresentEquivalent.make({ subject: publication.authority.subject });
|
|
530
|
+
});
|
|
531
|
+
const mutate = Effect.fn("GitHubReleaseSubject.mutate")(function* (decision, grant) {
|
|
532
|
+
if (grant._tag !== "ScopedSecret") {
|
|
533
|
+
return yield* mutationFailure(publication, "GitHub release mutation requires an opaque scoped-secret grant.", "before-dispatch");
|
|
534
|
+
}
|
|
535
|
+
const plan = mutationPlan;
|
|
536
|
+
if (decision.subject !== publication.authority.subject || plan === undefined) {
|
|
537
|
+
return yield* mutationFailure(publication, "The GitHub mutation decision has no matching exact observation plan.");
|
|
538
|
+
}
|
|
539
|
+
const expectedDecision = plan._tag === "CreateRelease" && plan.tagAbsent
|
|
540
|
+
? decision._tag === "ProviderAuthorizedCreate" &&
|
|
541
|
+
decision.proof.kind === "github-authenticated-repository-and-unique-tag"
|
|
542
|
+
: plan._tag === "CreateRelease"
|
|
543
|
+
? decision._tag === "NeedsMutation" && decision.precondition.kind === "github-release-absent-at-exact-tag"
|
|
544
|
+
: decision._tag === "NeedsMutation" &&
|
|
545
|
+
decision.precondition.kind === "github-intended-assets-authoritatively-absent";
|
|
546
|
+
if (!expectedDecision) {
|
|
547
|
+
return yield* mutationFailure(publication, "The GitHub mutation decision does not match its observed precondition.");
|
|
548
|
+
}
|
|
549
|
+
const indexes = plan._tag === "CreateRelease"
|
|
550
|
+
? publication.assets.map((_, index) => index)
|
|
551
|
+
: [...plan.assetIndexes];
|
|
552
|
+
const bytesByIndex = new Map();
|
|
553
|
+
for (const index of indexes) {
|
|
554
|
+
const asset = publication.assets[index];
|
|
555
|
+
const bytes = asset === undefined ? undefined : bundle.blobs.get(asset.artifactId.toString());
|
|
556
|
+
if (asset === undefined || bytes === undefined) {
|
|
557
|
+
return yield* mutationFailure(publication, "An intended GitHub asset is unavailable before dispatch.");
|
|
558
|
+
}
|
|
559
|
+
bytesByIndex.set(index, bytes);
|
|
560
|
+
}
|
|
561
|
+
if (plan._tag === "UploadAssets" && !validateUploadUrl(publication, plan.releaseId, plan.uploadUrl)) {
|
|
562
|
+
return yield* mutationFailure(publication, "The observed GitHub upload template failed validation before dispatch.");
|
|
563
|
+
}
|
|
564
|
+
const operation = {
|
|
565
|
+
_tag: "PublishOperation",
|
|
566
|
+
subject: publication.authority.subject,
|
|
567
|
+
provider: publication.authority.provider,
|
|
568
|
+
audience: publication.authority.audience,
|
|
569
|
+
purpose: "publish",
|
|
570
|
+
decision
|
|
571
|
+
};
|
|
572
|
+
let acceptedWrites = 0;
|
|
573
|
+
const dispatch = Effect.fn("GitHubReleaseSubject.dispatch")(function* (request) {
|
|
574
|
+
const exchange = yield* executeMutation(mutationHttp, operation, request, grant);
|
|
575
|
+
if (exchange._tag === "Failure") {
|
|
576
|
+
if (acceptedWrites > 0 || exchange.error.commitment === "unknown") {
|
|
577
|
+
return { _tag: "Attempt", attempt: unknownAttempt(publication, "GitHub transport outcome became unknown after mutation dispatch.") };
|
|
578
|
+
}
|
|
579
|
+
return yield* mutationFailure(publication, "The authorized GitHub HTTP boundary rejected mutation before dispatch.", "before-dispatch");
|
|
580
|
+
}
|
|
581
|
+
if (exchange.response.status === 201) {
|
|
582
|
+
acceptedWrites += 1;
|
|
583
|
+
return { _tag: "Accepted", response: exchange.response };
|
|
584
|
+
}
|
|
585
|
+
return { _tag: "Attempt", attempt: unknownAttempt(publication, `GitHub returned conservative mutation status ${exchange.response.status}; exact outcome requires reobservation.`) };
|
|
586
|
+
});
|
|
587
|
+
let uploadUrl;
|
|
588
|
+
if (plan._tag === "CreateRelease") {
|
|
589
|
+
const body = JSON.stringify({
|
|
590
|
+
tag_name: publication.tag.toString(),
|
|
591
|
+
target_commitish: publication.targetCommit.toString(),
|
|
592
|
+
name: publication.title.toString(),
|
|
593
|
+
body: publication.body ?? "",
|
|
594
|
+
draft: publication.draft,
|
|
595
|
+
prerelease: publication.prerelease
|
|
596
|
+
});
|
|
597
|
+
const created = yield* dispatch({
|
|
598
|
+
method: "POST",
|
|
599
|
+
url: `${publication.authority.audience}/releases`,
|
|
600
|
+
headers: {
|
|
601
|
+
...githubJsonHeaders,
|
|
602
|
+
"content-type": "application/json",
|
|
603
|
+
"content-length": String(new TextEncoder().encode(body).length)
|
|
604
|
+
},
|
|
605
|
+
body
|
|
606
|
+
});
|
|
607
|
+
if (created._tag === "Attempt")
|
|
608
|
+
return created.attempt;
|
|
609
|
+
const facts = releaseFacts(parseJson(created.response.body));
|
|
610
|
+
if (facts === undefined || !validateUploadUrl(publication, facts.id, facts.uploadUrl) ||
|
|
611
|
+
compareReleaseMetadata(publication, facts).length > 0) {
|
|
612
|
+
return unknownAttempt(publication, "GitHub accepted release creation but its response did not establish the exact release identity and repository-scoped upload template.");
|
|
613
|
+
}
|
|
614
|
+
uploadUrl = facts.uploadUrl;
|
|
615
|
+
}
|
|
616
|
+
else {
|
|
617
|
+
uploadUrl = plan.uploadUrl;
|
|
618
|
+
}
|
|
619
|
+
for (const index of indexes) {
|
|
620
|
+
const bytes = bytesByIndex.get(index);
|
|
621
|
+
const uploaded = yield* dispatch(uploadRequest(publication, uploadUrl, index, bytes));
|
|
622
|
+
if (uploaded._tag === "Attempt")
|
|
623
|
+
return uploaded.attempt;
|
|
624
|
+
const intended = publication.assets[index];
|
|
625
|
+
const facts = releaseAssetFacts(publication, parseJson(uploaded.response.body));
|
|
626
|
+
if (facts === undefined || facts.name !== intended.name || facts.size !== bytes.length ||
|
|
627
|
+
facts.mediaType !== intended.mediaType || facts.digest._tag === "Malformed" ||
|
|
628
|
+
(facts.digest._tag === "Present" && !digestEquals(facts.digest.value, sha256Digest(bytes)))) {
|
|
629
|
+
return unknownAttempt(publication, "GitHub accepted an asset upload but its response did not establish the exact uploaded asset identity.");
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
return appliedAttempt(publication);
|
|
633
|
+
});
|
|
634
|
+
return [{
|
|
635
|
+
id: publication.authority.subject,
|
|
636
|
+
recovery: githubRecoveryCapabilityProfile,
|
|
637
|
+
observationRequests: observationRequests(publication),
|
|
638
|
+
mutationRequest: mutationRequest(publication),
|
|
639
|
+
observe,
|
|
640
|
+
decide: (observation) => decideFor(publication, observation, mutationPlan),
|
|
641
|
+
mutate
|
|
642
|
+
}];
|
|
643
|
+
};
|
|
644
|
+
//# sourceMappingURL=github.js.map
|