Files
PerishFireandLooper 8ab7c3d5f1 feat(standalone): establish the exact lifecycle and Terminal carrier (#7716)
* feat(standalone): add shell-neutral exact lifecycle

* feat(terminal): add native exact cold-start carrier

* test(terminal): exercise mutable exact channel heads

* feat(standalone): model synced blobs and Shell updates

* feat(terminal): exercise the complete Shell lifecycle

* feat(release): add the independent exact Terminal line

* test(exact): run the full local Terminal release line

* feat(terminal): harden exact Sidecar lifecycle

* feat(standalone): prove exact update transactions

* refactor(standalone): separate shell lifecycle dimensions

* refactor(e2e): decouple terminal exact drivers

* refactor(terminal): isolate exact sidecar fixture host

* feat(terminal): gate handoff on physical retirement

* refactor(release): gate exact activation on public acceptance

* test(terminal): formalize guarded lifecycle algebra

* fix(terminal): guard shell installer handoff

* feat(terminal): add exact bootloader handoff

* feat(terminal): integrate exact sidecar lifecycle

* refactor(exact): rename validation channels

* test(terminal): harden exact release acceptance

* fix(postinstall): build standalone dependencies first

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

* fix(ci): build the native Terminal scene

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

* test(ci): cover exact convergence handoff routing

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

* fix(exact): isolate terminal validation from main CI

* fix(terminal): complete shell update confirmation

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

* fix(exact): bind acceptance to installed manifest

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

* fix(standalone): block occupied shell installs

Generated-By: looper 0.11.2 (runner=fixer, agent=codex)

---------

Co-authored-by: Looper <looper@noreply.github.com>
2026-09-03 03:50:34 +00:00

388 lines
22 KiB
Python

#!/usr/bin/env python3
"""Compose exact content and Shell documents from generic Shell contributions."""
from __future__ import annotations
import argparse
import base64
import hashlib
import json
import os
from pathlib import Path
import re
import shutil
import subprocess
from typing import Any
DIGEST = re.compile(r"^[a-f0-9]{64}$")
IDENTIFIER = re.compile(r"^[a-z][a-z0-9-]{0,31}$")
SOURCE_COMMIT = re.compile(r"^[a-f0-9]{40}$")
TARGET = re.compile(r"^[a-z0-9]+(?:-[a-z0-9]+)*$")
VERSION = re.compile(r"^\d+\.\d+\.\d+(?:-[0-9a-z]+(?:[.-][0-9a-z]+)*)?$")
def canonical_bytes(value: Any) -> bytes:
return (json.dumps(value, ensure_ascii=False, separators=(",", ":"), sort_keys=True) + "\n").encode()
def read_json(path: Path) -> dict[str, Any]:
value = json.loads(path.read_text(encoding="utf-8"))
if not isinstance(value, dict):
raise SystemExit(f"JSON document must be an object: {path}")
return value
def write_json(path: Path, value: Any) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(canonical_bytes(value))
def described(path: Path, media_type: str | None = None) -> dict[str, Any]:
body = path.read_bytes()
value = {"file": str(path.resolve()), "sha256": hashlib.sha256(body).hexdigest(), "size": len(body)}
if media_type is not None:
value["mediaType"] = media_type
return value
def checked_description(value: dict[str, Any], label: str, override: str | None = None) -> Path:
path = Path(override or str(value.get("file", ""))).resolve()
actual = described(path)
if actual["sha256"] != value.get("sha256") or actual["size"] != value.get("size"):
raise SystemExit(f"{label} binding verification failed: {path}")
return path
def require_release(value: dict[str, Any]) -> None:
channel = str(value.get("channel", ""))
release = str(value.get("releaseVersion", ""))
if not IDENTIFIER.fullmatch(channel):
raise SystemExit("invalid release channel")
if re.fullmatch(rf"\d+\.\d+\.\d+-{re.escape(channel)}\.\d+", release) is None:
raise SystemExit("releaseVersion does not belong to channel")
if not SOURCE_COMMIT.fullmatch(str(value.get("sourceCommit", ""))):
raise SystemExit("sourceCommit must be a full lowercase SHA")
if not VERSION.fullmatch(str(value.get("standaloneVersion", ""))):
raise SystemExit("invalid standaloneVersion")
if not isinstance(value.get("publishedAt"), str) or "T" not in value["publishedAt"]:
raise SystemExit("publishedAt must be an ISO timestamp")
if not re.fullmatch(r"https?://[^\s]+", str(value.get("artifactBaseUrl", ""))):
raise SystemExit("artifactBaseUrl must use HTTP(S)")
def signing_keys() -> list[dict[str, str]]:
keys: list[dict[str, str]] = []
for suffix in ("", "_NEXT"):
key_id = os.environ.get(f"OD_EXACT_SIGNING_KEY_ID{suffix}", "")
private_key = os.environ.get(f"OD_EXACT_ED25519_PRIVATE_KEY{suffix}", "")
key_file = os.environ.get(f"OD_EXACT_ED25519_PRIVATE_KEY_FILE{suffix}", "")
if not private_key and key_file:
private_key = Path(key_file).read_text(encoding="utf-8")
if key_id or private_key:
if not re.fullmatch(r"[a-z0-9][a-z0-9._-]{0,63}", key_id) or not private_key:
raise SystemExit(f"incomplete or invalid signing key pair: {suffix or 'primary'}")
keys.append({"keyId": key_id, "privateKey": private_key})
if not keys or len({item["keyId"] for item in keys}) != len(keys):
raise SystemExit("at least one unique exact signing key is required")
return keys
CRYPTO_SCRIPT = r"""
const {createPublicKey, sign, verify} = require('node:crypto');
let source = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => source += chunk);
process.stdin.on('end', () => {
const input = JSON.parse(source);
const payload = Buffer.from(input.payload, 'base64');
const keys = input.keys.map(({keyId, privateKey}) => ({
keyId,
privateKey,
publicKey: createPublicKey(privateKey).export({type: 'spki', format: 'pem'}),
}));
const result = {
keys: keys.map(({keyId, publicKey}) => ({keyId, publicKey})),
signatures: keys.map(({keyId, privateKey}) => ({algorithm: 'Ed25519', keyId, value: sign(null, payload, privateKey).toString('base64')})),
};
if (input.verify) result.verified = input.verify.some(signature => {
const key = keys.find(candidate => candidate.keyId === signature.keyId);
return key && signature.algorithm === 'Ed25519' && verify(null, payload, key.publicKey, Buffer.from(signature.value, 'base64'));
});
process.stdout.write(JSON.stringify(result));
});
"""
def crypto(value: Any, keys: list[dict[str, str]], verify_signatures: Any = None) -> dict[str, Any]:
payload = {"payload": base64.b64encode(canonical_bytes(value)).decode(), "keys": keys,
**({"verify": verify_signatures} if verify_signatures is not None else {})}
result = subprocess.run(["node", "-e", CRYPTO_SCRIPT], input=json.dumps(payload), text=True, check=True, stdout=subprocess.PIPE)
return json.loads(result.stdout)
def signed(field: str, value: dict[str, Any], keys: list[dict[str, str]]) -> dict[str, Any]:
return {field: value, "signatures": crypto(value, keys)["signatures"]}
def semver_core(version: str) -> tuple[int, int, int]:
return tuple(map(int, version.split("-")[0].split(".")))
def previous_requirements(path: str | None, channel: str, keys: list[dict[str, str]]) -> dict[str, dict[str, str]]:
if not path:
return {}
try:
envelope = read_json(Path(path).resolve())
metadata = envelope["metadata"]
if not crypto(metadata, keys, envelope.get("signatures"))["verified"]:
return {}
if metadata.get("schemaVersion") != 4 or metadata.get("channel") != channel:
return {}
requirements = metadata["shellRequirements"]
if not isinstance(requirements, list):
return {}
return {str(item["type"]): item for item in requirements}
except (KeyError, TypeError, ValueError, OSError, subprocess.SubprocessError):
return {}
def prepare(request: dict[str, Any], receipt_path: Path) -> None:
require_release(request)
shells = request.get("shells")
legacy_terminal = shells is None and request.get("shellVersion") is not None
if legacy_terminal:
shells = [{"type": "terminal", "version": request.get("shellVersion"), "scenes": request.get("scenes")}]
if not isinstance(shells, list) or not shells:
raise SystemExit("exact.prepare requires at least one Shell")
shell_records: list[dict[str, Any]] = []
shell_types: set[str] = set()
closure_scene_digest: str | None = None
standalone_scene_digest: str | None = None
for shell in shells:
if not isinstance(shell, dict):
raise SystemExit("invalid Shell descriptor")
shell_type, shell_version, scenes = str(shell.get("type", "")), str(shell.get("version", "")), shell.get("scenes")
if not IDENTIFIER.fullmatch(shell_type) or shell_type in shell_types or not VERSION.fullmatch(shell_version):
raise SystemExit(f"invalid or duplicate Shell identity: {shell_type}")
if not isinstance(scenes, list) or not scenes:
raise SystemExit(f"{shell_type} requires at least one scene")
shell_types.add(shell_type)
scene_records: list[dict[str, Any]] = []
targets: set[str] = set()
for raw in scenes:
if not isinstance(raw, dict) or not TARGET.fullmatch(str(raw.get("target", ""))):
raise SystemExit(f"invalid {shell_type} scene target")
target = raw["target"]
if target in targets:
raise SystemExit(f"duplicate {shell_type} scene target: {target}")
targets.add(target)
directory = Path(str(raw.get("sceneDirectory", ""))).resolve()
manifest_path = directory / "scene.json"
binding = str(raw.get("sceneManifestSha256", ""))
if not DIGEST.fullmatch(binding) or hashlib.sha256(manifest_path.read_bytes()).hexdigest() != binding:
raise SystemExit(f"{shell_type} scene manifest binding failed: {target}")
manifest = read_json(manifest_path)
if manifest.get("schemaVersion") != 1 or manifest.get("target") != target or manifest.get("shellVersion") != shell_version:
raise SystemExit(f"{shell_type} scene identity mismatch: {target}")
build_hash = str(manifest.get("shellBuildHash", ""))
scene_closure_digest = str(manifest.get("closure", {}).get("sha256", ""))
scene_standalone_digest = str(manifest.get("standalone", {}).get("sha256", ""))
if not DIGEST.fullmatch(build_hash) or not DIGEST.fullmatch(scene_closure_digest) or not DIGEST.fullmatch(scene_standalone_digest):
raise SystemExit(f"{shell_type} scene lacks a valid build, Closure, or Standalone binding: {target}")
if closure_scene_digest is not None and scene_closure_digest != closure_scene_digest:
raise SystemExit("Shell scenes contain different Closure seeds")
closure_scene_digest = scene_closure_digest
if standalone_scene_digest is not None and scene_standalone_digest != standalone_scene_digest:
raise SystemExit("Shell scenes contain different Standalone launcher seeds")
standalone_scene_digest = scene_standalone_digest
scene_records.append({"target": target, "directory": str(directory), "sceneManifestSha256": binding, "shellBuildHash": build_hash})
scene_records.sort(key=lambda item: item["target"])
composite_hash = hashlib.sha256(canonical_bytes([{"target": item["target"], "shellBuildHash": item["shellBuildHash"]} for item in scene_records])).hexdigest()
shell_records.append({"type": shell_type, "version": shell_version, "buildHash": composite_hash, "scenes": scene_records})
shell_records.sort(key=lambda item: item["type"])
keys = signing_keys()
old = previous_requirements(request.get("previousContentMetadataFile"), request["channel"], keys)
for shell in shell_records:
prior = old.get(shell["type"])
shell["minimumVersion"] = shell["version"]
if (prior and prior.get("buildHash") == shell["buildHash"] and VERSION.fullmatch(str(prior.get("minVersion", "")))
and semver_core(prior["minVersion"]) <= semver_core(shell["version"])):
shell["minimumVersion"] = prior["minVersion"]
output = Path(str(request.get("outputDirectory", ""))).resolve()
artifacts, documents, trust = output / "artifacts", output / "documents", output / "trust" / "keys.json"
artifacts.mkdir(parents=True, exist_ok=True)
closure_source = Path(str(request.get("closureArtifactFile", ""))).resolve()
closure_digest = hashlib.sha256(closure_source.read_bytes()).hexdigest()
if closure_digest != closure_scene_digest:
raise SystemExit("Closure promotion input differs from Shell scenes")
closure_file = artifacts / f"closure-{closure_digest}.mjs"
shutil.copyfile(closure_source, closure_file)
closure = described(closure_file, "text/javascript")
standalone_source = Path(str(request.get("standaloneArtifactFile", ""))).resolve()
standalone_digest = hashlib.sha256(standalone_source.read_bytes()).hexdigest()
if standalone_digest != standalone_scene_digest:
raise SystemExit("Standalone launcher promotion input differs from Shell scenes")
standalone_file = artifacts / f"standalone-launcher-{standalone_digest}.mjs"
shutil.copyfile(standalone_source, standalone_file)
standalone = described(standalone_file, "text/javascript")
base = request["artifactBaseUrl"].rstrip("/")
metadata = {
"schemaVersion": 4, "channel": request["channel"], "releaseVersion": request["releaseVersion"],
"standaloneVersion": request["standaloneVersion"], "sourceCommit": request["sourceCommit"], "publishedAt": request["publishedAt"],
"blobs": {
closure["sha256"]: {"sha256": closure["sha256"], "size": closure["size"], "mediaType": "text/javascript", "sources": [{"kind": "remote", "url": f"{base}/{closure_file.name}"}]},
standalone["sha256"]: {"sha256": standalone["sha256"], "size": standalone["size"], "mediaType": "text/javascript", "sources": [{"kind": "remote", "url": f"{base}/{standalone_file.name}"}]},
},
"resources": [
{"id": "standalone-launcher", "component": "standalone.launcher", "blob": standalone["sha256"], "sync": True, "materialization": {"type": "file", "entrypoint": "launcher.mjs"}},
{"id": "closure-fixture", "component": "standalone.resource", "blob": closure["sha256"], "sync": True, "materialization": {"type": "file", "entrypoint": "fixture.mjs"}},
],
"shellRequirements": [{"type": item["type"], "minVersion": item["minimumVersion"], "buildHash": item["buildHash"]} for item in shell_records],
}
content_file = documents / "content-metadata.json"
write_json(content_file, signed("metadata", metadata, keys))
write_json(trust, {"schemaVersion": 1, "keys": crypto({}, keys)["keys"]})
receipt = {
"schemaVersion": 2, "operation": "exact.prepare", "channel": request["channel"], "releaseVersion": request["releaseVersion"],
"sourceCommit": request["sourceCommit"], "publishedAt": request["publishedAt"], "artifactBaseUrl": base,
"standaloneVersion": request["standaloneVersion"], "shells": shell_records, "closureArtifact": closure,
"standaloneArtifact": standalone,
"contentMetadata": described(content_file), "trustFile": described(trust),
}
if legacy_terminal:
terminal = shell_records[0]
receipt.update({"shellVersion": terminal["version"], "shellBuildHash": terminal["buildHash"],
"minimumShellVersion": terminal["minimumVersion"], "scenes": terminal["scenes"]})
write_json(receipt_path, receipt)
def finalize(request: dict[str, Any], receipt_path: Path) -> None:
prepared = read_json(Path(str(request.get("prepareReceipt", ""))).resolve())
if prepared.get("schemaVersion") != 2 or prepared.get("operation") != "exact.prepare":
raise SystemExit("invalid exact.prepare receipt")
contributions = request.get("contributions")
legacy_distributions = contributions is None and isinstance(request.get("distributions"), list)
if legacy_distributions:
contributions = request["distributions"]
if not isinstance(contributions, list) or not contributions:
raise SystemExit("exact.finalize requires Shell contributions")
prepared_shells = {shell["type"]: shell for shell in prepared["shells"]}
expected = {(shell["type"], scene["target"]) for shell in prepared["shells"] for scene in shell["scenes"]}
seen: set[tuple[str, str]] = set()
distributions: dict[str, list[dict[str, Any]]] = {shell_type: [] for shell_type in prepared_shells}
closure_path = checked_description(prepared["closureArtifact"], "Closure artifact", request.get("closureArtifactFile"))
standalone_path = checked_description(prepared["standaloneArtifact"], "Standalone launcher artifact", request.get("standaloneArtifactFile"))
artifacts = [
described(closure_path, prepared["closureArtifact"].get("mediaType", "application/octet-stream")),
described(standalone_path, prepared["standaloneArtifact"].get("mediaType", "application/octet-stream")),
]
for descriptor in contributions:
if not isinstance(descriptor, dict):
raise SystemExit("invalid Shell contribution descriptor")
source_receipt = read_json(Path(str(descriptor.get("receipt", ""))).resolve())
if legacy_distributions:
target = str(source_receipt.get("target", ""))
terminal = prepared_shells.get("terminal")
scene = next((value for value in terminal["scenes"] if value["target"] == target), None) if terminal else None
contribution = {"schemaVersion": 1, "operation": "shell.distribution.contribute", "target": target,
"shell": {"type": "terminal", "version": terminal["version"] if terminal else "", "buildHash": scene["shellBuildHash"] if scene else ""},
"artifact": source_receipt.get("archive", {}),
"updater": {"protocol": "standalone-shell-updater-v3", "handler": "sidecar-v1", "interaction": "restart-and-install"}}
else:
contribution = source_receipt
shell_type, target = str(contribution.get("shell", {}).get("type", "")), str(contribution.get("target", ""))
key, shell = (shell_type, target), prepared_shells.get(shell_type)
scene = next((value for value in shell["scenes"] if value["target"] == target), None) if shell else None
if contribution.get("schemaVersion") != 1 or contribution.get("operation") != "shell.distribution.contribute" or key not in expected or key in seen:
raise SystemExit(f"invalid or duplicate Shell contribution: {shell_type}/{target}")
if contribution["shell"].get("version") != shell["version"] or contribution["shell"].get("buildHash") != scene["shellBuildHash"]:
raise SystemExit(f"Shell contribution identity mismatch: {shell_type}/{target}")
seen.add(key)
archive = dict(contribution.get("artifact", {}))
path = checked_description(archive, f"{shell_type}/{target} distribution", descriptor.get("archiveFile"))
media_type = str(archive.get("mediaType", "application/octet-stream"))
artifact = described(path, media_type)
artifacts.append(artifact)
updater = contribution.get("updater")
if not isinstance(updater, dict) or updater.get("protocol") != "standalone-shell-updater-v3":
raise SystemExit(f"Shell contribution lacks updater contract: {shell_type}/{target}")
distributions[shell_type].append({"shell": {"type": shell_type, "version": shell["version"], "buildHash": scene["shellBuildHash"]},
"target": target, "artifact": {"url": f"{prepared['artifactBaseUrl']}/{path.name}", "sha256": artifact["sha256"], "size": artifact["size"], "mediaType": media_type}, "updater": updater})
if seen != expected:
raise SystemExit(f"Shell contributions do not cover prepared topology: missing {sorted(expected - seen)}")
keys = signing_keys()
output = Path(str(request.get("outputDirectory", ""))).resolve()
documents = output / "documents"
documents.mkdir(parents=True, exist_ok=True)
content_source = checked_description(prepared["contentMetadata"], "content metadata", request.get("contentMetadataFile"))
content_file = documents / "content-metadata.json"
shutil.copyfile(content_source, content_file)
content, base = described(content_file), prepared["artifactBaseUrl"]
lanes = {"content": {"releaseVersion": prepared["releaseVersion"], "url": f"{base}/{content_file.name}", "sha256": content["sha256"], "size": content["size"]}}
shell_metadata: dict[str, dict[str, Any]] = {}
required_acceptances: list[dict[str, Any]] = []
shell_files: list[Path] = []
for shell_type in sorted(distributions):
values = sorted(distributions[shell_type], key=lambda item: item["target"])
shell_document = {"schemaVersion": 1, "channel": prepared["channel"], "releaseVersion": prepared["releaseVersion"],
"sourceCommit": prepared["sourceCommit"], "publishedAt": prepared["publishedAt"], "distributions": values}
shell_file = documents / f"{shell_type}-metadata.json"
write_json(shell_file, signed("document", shell_document, keys))
shell_files.append(shell_file)
shell_description = described(shell_file)
shell_metadata[shell_type] = shell_description
lanes[shell_type] = {"releaseVersion": prepared["releaseVersion"], "url": f"{base}/{shell_file.name}", "sha256": shell_description["sha256"], "size": shell_description["size"]}
for value in values:
required_acceptances.append({"shell": value["shell"], "target": value["target"], "artifact": value["artifact"],
"shellMetadata": {"url": lanes[shell_type]["url"], "sha256": shell_description["sha256"], "size": shell_description["size"]}})
head = {"schemaVersion": 1, "channel": prepared["channel"], "publishedAt": prepared["publishedAt"], "lanes": lanes}
head_file = documents / "channel-head.json"
write_json(head_file, signed("head", head, keys))
receipt = {"schemaVersion": 2, "operation": "exact.pack", "channel": prepared["channel"],
"releaseVersion": prepared["releaseVersion"], "sourceCommit": prepared["sourceCommit"],
"shells": [{key: shell[key] for key in ("type", "version", "buildHash", "minimumVersion")} for shell in prepared["shells"]],
"artifacts": artifacts, "documents": [described(path) for path in [content_file, *shell_files, head_file]],
"contentMetadataFile": str(content_file), "shellMetadataFiles": {key: value["file"] for key, value in shell_metadata.items()},
"channelHeadFile": str(head_file), "requiredAcceptances": required_acceptances}
if "terminal" in shell_metadata:
terminal = prepared_shells["terminal"]
receipt.update({"terminalMetadataFile": shell_metadata["terminal"]["file"], "shellBuildHash": terminal["buildHash"],
"minimumShellVersion": terminal["minimumVersion"]})
write_json(receipt_path, receipt)
def legacy_pack(request: dict[str, Any], receipt_path: Path) -> None:
"""Preserve the pre-split tools harness contract during the phased migration."""
scene = Path(str(request.get("sceneDirectory", ""))).resolve()
manifest = read_json(scene / "scene.json")
if manifest.get("standaloneVersion") != request.get("standaloneVersion"):
raise SystemExit("requested standaloneVersion differs from Terminal scene")
raise SystemExit(
"legacy exact.pack can only reuse its validation contract; "
"release-exact must use exact.prepare and exact.finalize"
)
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--request", required=True, type=Path)
parser.add_argument("--receipt", required=True, type=Path)
args = parser.parse_args()
request = read_json(args.request.resolve())
if request.get("schemaVersion") != 1:
raise SystemExit("unsupported exact pack request schema")
if request.get("operation") == "exact.prepare":
prepare(request, args.receipt.resolve())
elif request.get("operation") == "exact.finalize":
finalize(request, args.receipt.resolve())
elif request.get("operation") == "exact.pack":
legacy_pack(request, args.receipt.resolve())
else:
raise SystemExit("unsupported exact pack operation")
if __name__ == "__main__":
main()