name: release-exact on: workflow_dispatch: inputs: source_sha: description: Full current-main commit to build required: true type: string channel: description: Isolated exact channel required: true type: choice options: [somechan, somepreview] release_version: description: Counted channel version, for example 0.1.0-somechan.1 required: true type: string standalone_version: description: Independently versioned Standalone runtime required: true default: 0.1.0 type: string permissions: actions: read contents: read concurrency: group: release-exact-${{ inputs.channel }} cancel-in-progress: false jobs: plan: name: Plan release-neutral Terminal scenes if: github.ref == 'refs/heads/main' runs-on: ubuntu-24.04 outputs: run: ${{ steps.convergence.outputs.run }} shell_matrix: ${{ steps.topology.outputs.shell_matrix }} steps: - name: Validate immutable inputs env: SOURCE_SHA: ${{ inputs.source_sha }} DISPATCH_SHA: ${{ github.sha }} CHANNEL: ${{ inputs.channel }} RELEASE_VERSION: ${{ inputs.release_version }} run: | set -euo pipefail [[ "$SOURCE_SHA" =~ ^[0-9a-f]{40}$ ]] test "$SOURCE_SHA" = "$DISPATCH_SHA" [[ "$CHANNEL" == "somechan" || "$CHANNEL" == "somepreview" ]] [[ "$RELEASE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+-${CHANNEL}\.[0-9]+$ ]] - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} fetch-depth: 0 persist-credentials: false - name: Verify checkout identity env: SOURCE_SHA: ${{ inputs.source_sha }} run: | set -euo pipefail test "$(git rev-parse HEAD)" = "$SOURCE_SHA" git merge-base --is-ancestor "$SOURCE_SHA" origin/main - name: Verify exact release transition algebra run: python3 .github/scripts/release.py --self-check - name: Resolve Shell topology id: topology run: | python3 - <<'PY' import json, os topology = [ {"shell": "terminal", "target": "darwin-arm64", "workload": "terminal_scene_darwin_arm64", "runner_class": "terminal_darwin_arm64", "runs_on": "macos-15"}, ] root = os.path.join(os.environ["RUNNER_TEMP"], "exact-plan") os.makedirs(root, exist_ok=True) with open(os.path.join(root, "topology.json"), "w") as destination: json.dump(topology, destination, sort_keys=True, separators=(",", ":")) destination.write("\n") with open(os.environ["GITHUB_OUTPUT"], "a") as output: output.write("shell_matrix=" + json.dumps({"include": topology}, separators=(",", ":")) + "\n") PY - name: Resolve reusable scene results id: convergence env: OD_WORKLOAD_RESULTS_BASE_URL: ${{ secrets.OD_WORKLOAD_RESULTS_BASE_URL }} run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/exact-plan" python3 - <<'PY' import json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"], "exact-plan") topology = json.loads(root.joinpath("topology.json").read_text()) root.joinpath("scope.json").write_text(json.dumps({"enabled": {item["workload"]: True for item in topology}}, sort_keys=True) + "\n") root.joinpath("runners.json").write_text(json.dumps({item["runner_class"]: [item["runs_on"]] for item in topology}, sort_keys=True) + "\n") PY RUNNER_PLAN=$(python3 -c 'import json,sys; print(json.dumps(json.load(open(sys.argv[1])),separators=(",",":")))' "$RUNNER_TEMP/exact-plan/runners.json") python3 .github/scripts/convergence.py \ --config .github/config/convergence-exact.json \ github-output \ --workflow release-exact \ --scope-plan "$RUNNER_TEMP/exact-plan/scope.json" \ --runner-plan-json "$RUNNER_PLAN" \ --mode enforce \ --pending "$RUNNER_TEMP/exact-plan/pending.json" - uses: actions/upload-artifact@v4 with: name: exact-convergence-plan-${{ github.run_id }}-${{ github.run_attempt }} path: ${{ runner.temp }}/exact-plan/pending.json if-no-files-found: error retention-days: 1 scene: name: Terminal scene (${{ matrix.target }}) needs: [plan] strategy: fail-fast: false matrix: ${{ fromJSON(needs.plan.outputs.shell_matrix) }} runs-on: ${{ matrix.runs_on }} timeout-minutes: 35 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/download-artifact@v8 with: name: exact-convergence-plan-${{ github.run_id }}-${{ github.run_attempt }} path: ${{ runner.temp }}/exact-plan - name: Restore converged scene if: ${{ !fromJSON(needs.plan.outputs.run)[matrix.workload] }} env: WORKLOAD: ${{ matrix.workload }} shell: bash run: | set -euo pipefail python3 - <<'PY' import hashlib, json, os, urllib.request, zipfile from pathlib import Path, PurePosixPath root = Path(os.environ["RUNNER_TEMP"]) workload = json.loads((root / "exact-plan" / "pending.json").read_text())["workloads"][os.environ["WORKLOAD"]] result = workload.get("result") if not workload.get("resultHit") or not result: raise SystemExit("convergence planner omitted a required scene without a result") product = result["products"]["scene"] archive = root / "exact-scene-cache.zip" urllib.request.urlretrieve(product["source"], archive) if hashlib.sha256(archive.read_bytes()).hexdigest() != product["data"]["sha256"]: raise SystemExit("converged scene product digest mismatch") destination = root / "exact-scene" destination.mkdir(parents=True) with zipfile.ZipFile(archive) as source: for entry in source.infolist(): path = PurePosixPath(entry.filename.rstrip("/")) if not entry.filename or entry.filename.startswith(("/", "\\")) or "\\" in entry.filename or ".." in path.parts: raise SystemExit(f"unsafe converged scene entry: {entry.filename!r}") source.extractall(destination) PY - uses: pnpm/action-setup@v5 if: ${{ fromJSON(needs.plan.outputs.run)[matrix.workload] }} with: version: 10.33.2 - uses: actions/setup-node@v6 if: ${{ fromJSON(needs.plan.outputs.run)[matrix.workload] }} with: node-version: 24.18.0 cache: pnpm - name: Build release-neutral scene inputs if: ${{ fromJSON(needs.plan.outputs.run)[matrix.workload] }} env: TARGET: ${{ matrix.target }} shell: bash run: | set -euo pipefail pnpm install --frozen-lockfile pnpm --filter @open-design/platform build pnpm --filter @open-design/sidecar build pnpm --filter @open-design/standalone build pnpm --filter @open-design/closure build mkdir -p "$RUNNER_TEMP/exact-node" python3 - <<'PY' import hashlib, json, os, urllib.request from pathlib import Path lock = json.loads(Path("shells/terminal/node-lock.json").read_text()) value = lock["targets"][os.environ["TARGET"]] destination = Path(os.environ["RUNNER_TEMP"], "exact-node", value["archive"]) urllib.request.urlretrieve(value["url"], destination) if hashlib.sha256(destination.read_bytes()).hexdigest() != value["sha256"]: raise SystemExit("official Node archive digest mismatch") request = { "schemaVersion": 1, "operation": "terminal.scene.build", "target": os.environ["TARGET"], "shellVersion": Path("shells/terminal/version").read_text().strip(), "node": {"version": lock["version"], "archiveFile": str(destination), "archiveSha256": value["sha256"]}, "closureArtifactFile": str(Path("apps/closure/dist/index.mjs").resolve()), "standaloneDirectory": str(Path("packages/standalone/dist").resolve()), "sidecarDirectory": str(Path("packages/sidecar/dist").resolve()), "platformDirectory": str(Path("packages/platform/dist").resolve()), "sceneDirectory": str(Path(os.environ["RUNNER_TEMP"], "exact-scene")), } Path(os.environ["RUNNER_TEMP"], "exact-scene-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY - name: Build Darwin Terminal scene if: ${{ fromJSON(needs.plan.outputs.run)[matrix.workload] && startsWith(matrix.target, 'darwin-') }} shell: bash run: sh shells/terminal/sh/scene.sh --request "$RUNNER_TEMP/exact-scene-request.json" --receipt "$RUNNER_TEMP/exact-scene-receipt.json" - name: Verify scene and prepare convergence product env: ARTIFACT_NAME: exact-terminal-scene-${{ matrix.target }}-${{ inputs.source_sha }} TARGET: ${{ matrix.target }} WORKLOAD: ${{ matrix.workload }} shell: bash run: | set -euo pipefail python3 - <<'PY' import json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) scene = json.loads((root / "exact-scene" / "scene.json").read_text()) if scene.get("target") != os.environ["TARGET"] or not isinstance(scene.get("shellBuildHash"), str): raise SystemExit("restored or built Terminal scene identity mismatch") encoded = json.dumps(scene, sort_keys=True) for release_field in ("somechan", "somepreview", "publishedAt", "artifactBaseUrl", "signatures"): if release_field in encoded: raise SystemExit(f"Terminal scene contains release-owned field: {release_field}") pending = json.loads((root / "exact-plan" / "pending.json").read_text())["workloads"][os.environ["WORKLOAD"]] if pending["run"]: destination = root / "convergence-products" / os.environ["WORKLOAD"] destination.mkdir(parents=True) manifest = { "workload": os.environ["WORKLOAD"], "digest": pending["digest"], "executionClass": pending["executionClass"], "products": {"scene": {"type": "job", "source": os.environ["ARTIFACT_NAME"], "data": {"target": os.environ["TARGET"]}}}, } (destination / "product-manifest.json").write_text(json.dumps(manifest, indent=2, sort_keys=True) + "\n") PY - uses: actions/upload-artifact@v4 with: name: exact-terminal-scene-${{ matrix.target }}-${{ inputs.source_sha }} path: ${{ runner.temp }}/exact-scene if-no-files-found: error retention-days: 1 - uses: actions/upload-artifact@v4 if: ${{ fromJSON(needs.plan.outputs.run)[matrix.workload] }} with: name: exact-convergence-manifest-${{ matrix.workload }}-${{ github.run_id }} path: ${{ runner.temp }}/convergence-products if-no-files-found: error retention-days: 1 prepare: name: Prepare signed exact content needs: [plan, scene] runs-on: ubuntu-24.04 environment: standalone-exact-release timeout-minutes: 10 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/setup-node@v6 with: node-version: 24.18.0 - uses: actions/download-artifact@v8 with: pattern: exact-terminal-scene-*-${{ inputs.source_sha }} path: ${{ runner.temp }}/scenes - name: Read previous content floor when available env: CHANNEL: ${{ inputs.channel }} PUBLIC_ORIGIN: ${{ secrets.EXACT_RELEASE_PUBLIC_ORIGIN }} run: | python3 - <<'PY' import json, os, urllib.error, urllib.request from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) try: with urllib.request.urlopen(f"{os.environ['PUBLIC_ORIGIN'].rstrip('/')}/{os.environ['CHANNEL']}/latest/channel-head.json", timeout=10) as response: head = json.load(response)["head"] with urllib.request.urlopen(head["lanes"]["content"]["url"], timeout=10) as response: (root / "previous-content-metadata.json").write_bytes(response.read()) except (KeyError, OSError, urllib.error.URLError, json.JSONDecodeError): pass PY - name: Compose and sign content metadata env: CHANNEL: ${{ inputs.channel }} RELEASE_VERSION: ${{ inputs.release_version }} SOURCE_SHA: ${{ inputs.source_sha }} STANDALONE_VERSION: ${{ inputs.standalone_version }} PUBLIC_ORIGIN: ${{ secrets.EXACT_RELEASE_PUBLIC_ORIGIN }} OD_EXACT_SIGNING_KEY_ID: ${{ secrets.EXACT_SIGNING_KEY_ID }} OD_EXACT_ED25519_PRIVATE_KEY: ${{ secrets.EXACT_ED25519_PRIVATE_KEY }} OD_EXACT_SIGNING_KEY_ID_NEXT: ${{ secrets.EXACT_SIGNING_KEY_ID_NEXT }} OD_EXACT_ED25519_PRIVATE_KEY_NEXT: ${{ secrets.EXACT_ED25519_PRIVATE_KEY_NEXT }} SHELL_MATRIX: ${{ needs.plan.outputs.shell_matrix }} run: | set -euo pipefail python3 - <<'PY' import hashlib, json, os, subprocess from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) topology = json.loads(os.environ["SHELL_MATRIX"])["include"] scenes = [] for item in topology: if item["shell"] != "terminal": raise SystemExit("release-exact currently has no adapter for this Shell") target = item["target"] directory = root / "scenes" / f"exact-terminal-scene-{target}-{os.environ['SOURCE_SHA']}" manifest = directory / "scene.json" scenes.append({"target": target, "sceneDirectory": str(directory), "sceneManifestSha256": hashlib.sha256(manifest.read_bytes()).hexdigest()}) published_at = subprocess.check_output(['git', 'show', '--no-patch', '--format=%cI', os.environ['SOURCE_SHA']], text=True).strip() request = { "schemaVersion": 1, "operation": "exact.prepare", "channel": os.environ["CHANNEL"], "releaseVersion": os.environ["RELEASE_VERSION"], "sourceCommit": os.environ["SOURCE_SHA"], "publishedAt": published_at, "standaloneVersion": os.environ["STANDALONE_VERSION"], "artifactBaseUrl": f"{os.environ['PUBLIC_ORIGIN'].rstrip('/')}/{os.environ['CHANNEL']}/{os.environ['RELEASE_VERSION']}", "closureArtifactFile": str(root / "scenes" / f"exact-terminal-scene-darwin-arm64-{os.environ['SOURCE_SHA']}" / "seed" / "closure.mjs"), "standaloneArtifactFile": str(root / "scenes" / f"exact-terminal-scene-darwin-arm64-{os.environ['SOURCE_SHA']}" / "runtime" / "standalone" / "index.mjs"), "shells": [{"type": "terminal", "version": Path("shells/terminal/version").read_text().strip(), "scenes": scenes}], "outputDirectory": str(root / "exact-prepare"), } previous = root / "previous-content-metadata.json" if previous.is_file(): request["previousContentMetadataFile"] = str(previous) (root / "exact-prepare-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY python3 .github/scripts/pack.py --request "$RUNNER_TEMP/exact-prepare-request.json" --receipt "$RUNNER_TEMP/exact-prepare/prepare-receipt.json" - uses: actions/upload-artifact@v4 with: name: exact-prepared-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/exact-prepare if-no-files-found: error retention-days: 1 distribution: name: Terminal distribution (${{ matrix.target }}) needs: [plan, prepare] strategy: fail-fast: false matrix: ${{ fromJSON(needs.plan.outputs.shell_matrix) }} runs-on: ${{ matrix.runs_on }} timeout-minutes: 15 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/download-artifact@v8 with: name: exact-terminal-scene-${{ matrix.target }}-${{ inputs.source_sha }} path: ${{ runner.temp }}/scene - uses: actions/download-artifact@v8 with: name: exact-prepared-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/prepared - name: Write native distribution request env: CHANNEL: ${{ inputs.channel }} RELEASE_VERSION: ${{ inputs.release_version }} SOURCE_SHA: ${{ inputs.source_sha }} TARGET: ${{ matrix.target }} shell: bash run: | python3 - <<'PY' import hashlib, json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) prepared = json.loads((root / "prepared" / "prepare-receipt.json").read_text()) scene = root / "scene" request = { "schemaVersion": 1, "operation": "terminal.distribution.build", "target": os.environ["TARGET"], "sceneDirectory": str(scene), "sceneManifestSha256": hashlib.sha256((scene / "scene.json").read_bytes()).hexdigest(), "releaseDocumentsDirectory": str(root / "prepared" / "documents"), "trustFile": str(root / "prepared" / "trust" / "keys.json"), "release": {"channel": os.environ["CHANNEL"], "releaseVersion": os.environ["RELEASE_VERSION"], "sourceCommit": os.environ["SOURCE_SHA"], "publishedAt": prepared["publishedAt"], "artifactBaseUrl": prepared["artifactBaseUrl"]}, "outputDirectory": str(root / "distribution"), } (root / "distribution-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY - name: Build Darwin distribution if: ${{ startsWith(matrix.target, 'darwin-') }} shell: bash run: sh shells/terminal/sh/distribution.sh --request "$RUNNER_TEMP/distribution-request.json" --receipt "$RUNNER_TEMP/distribution/distribution-receipt.json" - uses: actions/upload-artifact@v4 with: name: exact-distribution-${{ matrix.target }}-${{ inputs.release_version }} path: ${{ runner.temp }}/distribution if-no-files-found: error retention-days: 1 publish: name: Finalize and publish exact channel needs: [plan, distribution] runs-on: ubuntu-24.04 environment: standalone-exact-release timeout-minutes: 15 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/setup-node@v6 with: node-version: 24.18.0 - uses: actions/download-artifact@v8 with: name: exact-prepared-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/prepared - uses: actions/download-artifact@v8 with: pattern: exact-distribution-*-${{ inputs.release_version }} path: ${{ runner.temp }}/distributions - name: Finalize signed Shell sidecar and channel head env: RELEASE_VERSION: ${{ inputs.release_version }} SHELL_MATRIX: ${{ needs.plan.outputs.shell_matrix }} OD_EXACT_SIGNING_KEY_ID: ${{ secrets.EXACT_SIGNING_KEY_ID }} OD_EXACT_ED25519_PRIVATE_KEY: ${{ secrets.EXACT_ED25519_PRIVATE_KEY }} OD_EXACT_SIGNING_KEY_ID_NEXT: ${{ secrets.EXACT_SIGNING_KEY_ID_NEXT }} OD_EXACT_ED25519_PRIVATE_KEY_NEXT: ${{ secrets.EXACT_ED25519_PRIVATE_KEY_NEXT }} run: | set -euo pipefail python3 - <<'PY' import json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) prepared = json.loads((root / "prepared" / "prepare-receipt.json").read_text()) shells = {shell["type"]: shell for shell in prepared["shells"]} contributions = [] for item in json.loads(os.environ["SHELL_MATRIX"])["include"]: shell_type, target = item["shell"], item["target"] if shell_type != "terminal": raise SystemExit("release-exact currently has no distribution adapter for this Shell") directory = root / "distributions" / f"exact-distribution-{target}-{os.environ['RELEASE_VERSION']}" receipt = json.loads((directory / "distribution-receipt.json").read_text()) receipt["archive"]["file"] = str(directory / Path(receipt["archive"]["file"]).name) scene = next(scene for scene in shells[shell_type]["scenes"] if scene["target"] == target) contribution = { "schemaVersion": 1, "operation": "shell.distribution.contribute", "shell": {"type": shell_type, "version": shells[shell_type]["version"], "buildHash": scene["shellBuildHash"]}, "target": target, "artifact": receipt["archive"], "updater": {"protocol": "standalone-shell-updater-v3", "handler": "sidecar-v1", "interaction": "restart-and-install"}, } contribution_file = directory / "shell-contribution.json" contribution_file.write_text(json.dumps(contribution, sort_keys=True, separators=(",", ":")) + "\n") contributions.append({"receipt": str(contribution_file)}) request = { "schemaVersion": 1, "operation": "exact.finalize", "prepareReceipt": str(root / "prepared" / "prepare-receipt.json"), "contentMetadataFile": str(root / "prepared" / "documents" / "content-metadata.json"), "closureArtifactFile": str(next((root / "prepared" / "artifacts").glob("closure-*.mjs"))), "standaloneArtifactFile": str(next((root / "prepared" / "artifacts").glob("standalone-launcher-*.mjs"))), "contributions": contributions, "outputDirectory": str(root / "exact-final"), } (root / "exact-finalize-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY python3 .github/scripts/pack.py --request "$RUNNER_TEMP/exact-finalize-request.json" --receipt "$RUNNER_TEMP/exact-final/pack-receipt.json" - name: Publish immutable release objects env: OD_EXACT_RELEASE_TOKEN: ${{ secrets.EXACT_RELEASE_TOKEN }} STORAGE_ENDPOINT: ${{ secrets.EXACT_RELEASE_ENDPOINT }} STORAGE_BUCKET: ${{ secrets.EXACT_RELEASE_BUCKET }} run: | set -euo pipefail python3 - <<'PY' import json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) request = {"schemaVersion": 1, "operation": "exact.publish", "packReceipt": str(root / "exact-final" / "pack-receipt.json"), "endpointUrl": os.environ["STORAGE_ENDPOINT"], "bucket": os.environ["STORAGE_BUCKET"]} (root / "exact-publish-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY python3 .github/scripts/release.py --request "$RUNNER_TEMP/exact-publish-request.json" --receipt "$RUNNER_TEMP/exact-final/publish-receipt.json" - uses: actions/upload-artifact@v4 with: name: exact-published-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/exact-final if-no-files-found: error retention-days: 1 - uses: actions/download-artifact@v8 with: name: exact-convergence-plan-${{ github.run_id }}-${{ github.run_attempt }} path: ${{ runner.temp }}/exact-plan - uses: actions/download-artifact@v8 continue-on-error: true with: pattern: exact-convergence-manifest-*-${{ github.run_id }} path: ${{ runner.temp }}/convergence-products merge-multiple: true - name: Create reusable scene handoff id: convergence_handoff continue-on-error: true run: >- python3 .github/scripts/convergence.py --config .github/config/convergence-exact.json handoff --pending "$RUNNER_TEMP/exact-plan/pending.json" --products-root "$RUNNER_TEMP/convergence-products" --handoff-root "$RUNNER_TEMP/handoff-convergence-exact-scenes" --id exact-scenes - name: Upload reusable scene handoff if: ${{ steps.convergence_handoff.outputs.name != '' }} continue-on-error: true uses: actions/upload-artifact@v4 with: name: ${{ steps.convergence_handoff.outputs.name }} path: ${{ steps.convergence_handoff.outputs.path }} if-no-files-found: error retention-days: 1 - name: Upload exact release evidence if: always() uses: actions/upload-artifact@v4 with: name: exact-${{ inputs.channel }}-${{ inputs.release_version }}-receipts path: | ${{ runner.temp }}/exact-final/*.json ${{ runner.temp }}/exact-final/documents/*.json ${{ runner.temp }}/exact-finalize-request.json ${{ runner.temp }}/exact-publish-request.json if-no-files-found: error retention-days: 30 acceptance: name: Public installed acceptance (${{ matrix.shell }}/${{ matrix.target }}) needs: [plan, publish] strategy: fail-fast: false matrix: ${{ fromJSON(needs.plan.outputs.shell_matrix) }} runs-on: ${{ matrix.runs_on }} timeout-minutes: 15 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/download-artifact@v8 with: name: exact-published-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/published - name: Download accepted public artifact env: SHELL_TYPE: ${{ matrix.shell }} TARGET: ${{ matrix.target }} shell: bash run: | set -euo pipefail python3 - <<'PY' import hashlib, json, os, urllib.request from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) published = json.loads((root / "published" / "publish-receipt.json").read_text()) required = next(item for item in published["requiredAcceptances"] if item["shell"]["type"] == os.environ["SHELL_TYPE"] and item["target"] == os.environ["TARGET"]) archive = root / "public-shell-archive" urllib.request.urlretrieve(required["artifact"]["url"], archive) body = archive.read_bytes() if hashlib.sha256(body).hexdigest() != required["artifact"]["sha256"] or len(body) != required["artifact"]["size"]: raise SystemExit("public Shell artifact binding mismatch") (root / "required-acceptance.json").write_text(json.dumps(required, sort_keys=True, separators=(",", ":")) + "\n") PY - name: Install and exercise Darwin Shell lifecycle if: ${{ startsWith(matrix.target, 'darwin-') }} shell: bash run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/extracted" tar -xzf "$RUNNER_TEMP/public-shell-archive" -C "$RUNNER_TEMP/extracted" sh "$RUNNER_TEMP/extracted/nexu-terminal/sh/install.sh" \ --source "$RUNNER_TEMP/extracted/nexu-terminal" \ --root "$RUNNER_TEMP/installed-shell" \ --channel "${{ inputs.channel }}" \ --namespace exact-public-acceptance > "$RUNNER_TEMP/installed-proof.json" run_terminal() { operation=$1 shift sh "$RUNNER_TEMP/installed-shell/sh/terminal.sh" \ --root "$RUNNER_TEMP/installed-shell" \ --store-root "$RUNNER_TEMP/acceptance-store" \ --channel "${{ inputs.channel }}" \ --namespace exact-public-acceptance \ --operation "$operation" \ --result "$RUNNER_TEMP/runtime-$operation.json" \ "$@" } run_terminal start --attachment-id public-acceptance run_terminal status run_terminal stop - name: Bind installed acceptance credential env: SHELL_TYPE: ${{ matrix.shell }} TARGET: ${{ matrix.target }} shell: bash run: | set -euo pipefail python3 .github/scripts/release/installed_acceptance.py \ --root "$RUNNER_TEMP" \ --installed-root "$RUNNER_TEMP/installed-shell" \ --shell-type "$SHELL_TYPE" \ --target "$TARGET" - uses: actions/upload-artifact@v4 with: name: exact-acceptance-${{ matrix.shell }}-${{ matrix.target }}-${{ inputs.release_version }} path: ${{ runner.temp }}/acceptance if-no-files-found: error retention-days: 30 activate: name: Activate accepted exact channel needs: [acceptance] runs-on: ubuntu-24.04 environment: standalone-exact-release timeout-minutes: 10 steps: - uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.source_sha }} persist-credentials: false - uses: actions/download-artifact@v8 with: name: exact-published-${{ inputs.channel }}-${{ inputs.release_version }} path: ${{ runner.temp }}/published - uses: actions/download-artifact@v8 with: pattern: exact-acceptance-*-${{ inputs.release_version }} path: ${{ runner.temp }}/acceptances merge-multiple: true - name: Activate latest channel head after acceptance env: OD_EXACT_RELEASE_TOKEN: ${{ secrets.EXACT_RELEASE_TOKEN }} run: | set -euo pipefail python3 - <<'PY' import json, os from pathlib import Path root = Path(os.environ["RUNNER_TEMP"]) receipt = json.loads((root / "published" / "publish-receipt.json").read_text()) receipt["channelHead"]["file"] = str(root / "published" / "documents" / "channel-head.json") relocated = root / "published" / "relocated-publish-receipt.json" relocated.write_text(json.dumps(receipt, sort_keys=True, separators=(",", ":")) + "\n") credentials = sorted(str(path) for path in (root / "acceptances").glob("*.json")) request = {"schemaVersion": 1, "operation": "exact.activate", "publishReceipt": str(relocated), "acceptanceCredentials": credentials} (root / "activate-request.json").write_text(json.dumps(request, sort_keys=True, separators=(",", ":")) + "\n") PY python3 .github/scripts/release.py --request "$RUNNER_TEMP/activate-request.json" --receipt "$RUNNER_TEMP/activate-receipt.json" - uses: actions/upload-artifact@v4 with: name: exact-activation-${{ inputs.channel }}-${{ inputs.release_version }} path: | ${{ runner.temp }}/activate-request.json ${{ runner.temp }}/activate-receipt.json if-no-files-found: error retention-days: 30