Repository navigation
Conversation
4344c8d to
1f043f3
Compare
f401ae9 to
355bddd
Compare
decf029 to
c68f402
Compare
02c09d0 to
3e94f2f
Compare
The installer hashes the signed release-head.json it just checked and writes that UnixFS CIDv0 into sources.json. A non-empty stamp that names different bytes exits 1. The launcher contract records that failure. Co-authored-by: Sash <SashaMIT@users.noreply.github.com>
detect_platform exits before any download when the Mac is not Apple silicon. The message names Intel Mac and the source-home path in docs/MAC.md. Help text states that there is no signed Intel download. Co-authored-by: Sash <SashaMIT@users.noreply.github.com>
c68f402 to
3e52e38
Compare
3e94f2f to
58a76ac
Compare
A frozen installer has no head CID. Filling that stamp from the verified bytes made a fresh install cache a head CID, which the update hop refuses. A matching stamp still stores the verified CID. A different stamp still stops. Co-authored-by: Sash <SashaMIT@users.noreply.github.com>
docs/MAC.md: kept the base's one Intel Mac section and quoted this branch's new installer message in it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
install.sh now stops an Intel Mac with "Intel Mac has no signed release yet. See docs/MAC.md for the source-home path." The test requires that stop in detect_platform, requires detect_platform before release-head.json in the main flow, requires MAC.md to quote the same text, and refuses the old text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
zip 9 for RUSTSEC-2026-0367/0368/0369 so cargo-audit passes. The base already merges fix/zip-9-rustsec; merging the base keeps this PR's diff against it unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
The installer stop on an Intel Mac pointed to the source-home path in docs/MAC.md. That path is a developer build, not an install path, so a first-time user had no step they could take. The team decided on a plain stop with no pointer to that build. - install.sh detect_platform now stops with "This Mac has an Intel processor. ElastOS supports Macs with Apple silicon (M1 or later). Intel Mac is not supported yet." It still exits 1 before any download. - --help says "Intel Mac is not supported yet." instead of the source-home pointer. - docs/MAC.md#intel-mac quotes the new message and says there is no other install path for an Intel Mac. - gateway-healthz-smoke-test.py requires the new text in install.sh and MAC.md, requires detect_platform before the first fetch_url, and refuses the retired texts. - install-bootstrap-test.py: test_intel_mac_stops_before_release_lookup requires exit 1, no PLATFORM output and no "source-home" in the message. New test_intel_mac_full_run_downloads_nothing runs the whole install.sh with a configured publisher, uname reporting Darwin x86_64 and curl/wget mocks that log. It requires no network call, no file in HOME, exit 1 and the message. With the die line removed, it records the curl fetch of release-head.json and fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
Brings the plain Intel Mac stop message from #398. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
Brings in the ported held-lock journal test fix (develop 5051505) so test-capsules stops flaking. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
Decision 4 is the plain stop. The installer put two sentences about the processor and Apple silicon before it. - install.sh keeps the text once, in INTEL_MAC_UNSUPPORTED. detect_platform and --help both print that variable. - docs/MAC.md#intel-mac names the variable and quotes its text. - gateway-healthz-smoke-test.py requires the variable, the die line, a single copy of the text, and none of the retired sentences. - install-bootstrap-test.py requires stderr to be exactly "Error: Intel Mac is not supported yet." from detect_platform, and from a full run that downloads nothing and writes nothing in HOME. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
A Terminal under Rosetta on an M1 or later Mac reports uname -m x86_64, so the installer told an Apple silicon Mac that it was an Intel Mac. On Darwin x86_64, detect_platform now asks the kernel. When sysctl -in sysctl.proc_translated or sysctl -in hw.optional.arm64 prints 1, the platform is aarch64-darwin. That build is arm64 only, so macOS runs it natively when the Rosetta shell starts it. Any other answer, a failed sysctl or a missing sysctl proves nothing, so the installer stops with the Intel Mac message before any download. Linux never asks sysctl. Tests (install-bootstrap-test.py, sysctl and uname faked): - test_rosetta_shell_on_apple_silicon_is_apple_silicon: four Rosetta or arm64 answers give aarch64-darwin; Linux x86_64 stays x86_64-linux. - test_intel_mac_stops_before_release_lookup: 0/0, empty, 0/empty, 2/0, a failing sysctl and a missing sysctl all stop with exit 1. - test_intel_mac_full_run_downloads_nothing: the whole installer with an Intel answer, a failing sysctl, and no sysctl on PATH runs no curl and writes nothing in HOME. - test_rosetta_shell_installs_the_apple_silicon_build_and_intel_downloads_nothing: one sandbox; the Intel answer makes no request, then the Rosetta answer fetches artifacts/elastos-aarch64-darwin and installs it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
The installer checked release-head.json, release.json and the Runtime, then read or copied them again from the temporary folder. Nothing tied those later reads to the bytes that passed. A process that could change that folder between the check and the use could: - put a head signed by its own key in place, and sources.json pinned that key as the publisher, read again from the file (d["signer_did"]); - put another Runtime in place after its SHA-256 passed. The installer ran that copy (--version, install-release) and installed it. Now: - verify_signature reads the envelope once and returns the SHA-256 of the bytes whose signature passed (VERIFIED_SHA256). - Every later read (bind_verified_head_cid, json_get, validate_release_identity) takes that SHA-256 and stops with "The release files changed on this computer after they were checked. Nothing was installed. Run the installer again." for other bytes. - sources.json pins MAINTAINER_DID, the trust root that verify_signature compared with the signer. It is not read again. - The staged Runtime copy in the install directory is checked again after the copy. That copy is the file the installer runs and hands to the writer. The writer reads each file once, checks those bytes against sources.json and installs those same bytes (update.rs install_release). Tests (install-bootstrap-test.py): - test_runtime_swapped_after_its_checksum_check_is_not_run_or_installed: a sha256sum hook swaps the download in TMPDIR after it hashes it. The swapped Runtime never runs and nothing is installed. Without the staged check, the swapped Runtime runs and is installed. - test_release_head_swapped_after_its_signature_check_is_refused: a python3 hook swaps in an attacker-signed head after its signature passes. The run stops after one request. Without the SHA-256 checks it installs. - test_publisher_pin_is_the_trust_root_not_a_second_read: the head is swapped after the last read; sources.json still pins the maintainer DID. With the old d["signer_did"] read, it pins the attacker key. - test_reads_after_the_signature_check_refuse_other_bytes: each read refuses one changed byte. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
@andersalm @SashaMIT a team question on the installer trust root (signing keys, so I am not changing it without your answer). Issue. Who uses the override today. Only repo test and demo paths: Options.
Recommendation: (a). The published installer has exactly one trust root, and test paths stamp a copy. (b) with "unstamped only" is the fallback if a smoke really needs the env var. No code changes on this until you answer. Generated by Claude Code |
|
Generated by Claude Code |
Brings in #398's fixes: the plain Intel Mac stop, Rosetta as Apple silicon, and the installer using only the bytes it checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Round 3 review: blocked (C). Removing the maintainer-key override is a team decision. |
The round-3 hook swapped a file only when its path was under TMPDIR. Apple's mktemp -d ignores TMPDIR and uses the per-user folder from confstr, so on a Mac nothing was swapped, the install succeeded and the test failed. The hook now swaps the exact path curl wrote, logs the swap, and the test asserts the swap happened before it asserts the refusal. sha256sum and shasum are both mocked. Extra cases run as Darwin with Apple's mktemp layout, a symlinked TMPDIR, and a PATH without sha256sum. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Answer to the trust-root question (comment 6233893115): (a), in 0.8.1, tracked in #434. Remove the |
The installer hashed the staged Runtime by path, then ran it by path three times. A process that replaced or rewrote that path between the hash and a run got its own program run as the installer's writer. The staged copy now sits read-only (0500) in a new 0700 folder made by mktemp -d in the checked install directory, and is opened once on fd 9. Its SHA-256 is taken from that open file. Before each run, a check refuses unless the held file is unchanged (device, inode, size, mtime, ctime, mode 0500, one link, this user) and the path still names it. Where the kernel can start an open file (Linux /proc/self/fd), the held file itself runs, so a path swapped after the last check cannot run. macOS has no way to start an open file, so there the path runs right after the check. Tests: staged swap (rename and in place) between the hash and the run is refused on the Linux and Darwin layouts; a swap after the last check runs only the checked bytes (Linux); held_runtime refuses each kind of change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Generated by Claude Code |
Brings in #398's round-4 commits: the swapped-Runtime test swaps the real download on macOS too (f8defe8), and the staged Runtime runs from one held file, not by path (112e168). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Trust-root decision (#434) is now draft #435, stacked on this PR, for 0.8.1. A stamped installer refuses a different DID from Generated by Claude Code |
Brings in #394's one-step flock ownership proof, the subordinate lane on the same proof, and a held lock with an unreadable record counting as held (4bb19dc), through #395 and #397. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
Brings in #394's one-step flock ownership proof, the subordinate lane on the same proof, and a held lock with an unreadable record counting as held (4bb19dc), through #398. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
…-root Brings in #394's one-step flock ownership proof, the subordinate lane on the same proof, and a held lock with an unreadable record counting as held (4bb19dc), through #398. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Round 4 at 32f4abf: B. Held-file exec and verified-byte binding proven; tampers caught. |
Brings in, through #397 and #395, #394's statement that the host lock proves possession, not that the holder is the gateway (13cdcad), and #395's hermetic default-command smoke test (630efc6). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
The Linux case of test_runtime_swapped_after_its_checksum_check_is_not_run_or_installed used the host's own mktemp and then required the installer's scratch folder to be under the fixture TMPDIR. GNU mktemp -d uses TMPDIR, but Apple's mktemp -d ignores it and uses the per-user temp folder, so the case failed on every Mac host (install-bootstrap-test.py:1112). The Linux case now uses mock_gnu_mktemp, as the macOS cases use mock_apple_mktemp, with a template form that GNU and BSD mktemp both accept. The test no longer depends on the host's mktemp. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Generated by Claude Code |
Brings in #398's portable swapped-Runtime test (da63c23: the Linux case mocks a GNU-like mktemp instead of using the host's), and, through #397 and #395, #394's statement that the host lock proves possession, not that the holder is the gateway (13cdcad). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
…-root Brings in #398's portable swapped-Runtime test (da63c23: the Linux case mocks a GNU-like mktemp instead of using the host's), and, through #397 and #395, #394's statement that the host lock proves possession, not that the holder is the gateway (13cdcad). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6Qn9RX7LDqrwiAfNC2F2K
|
Round 5 at da63c23: PASS (A); independent review PASS. macOS installer suite passed twice (98 pass, 5 skip); swapped-Runtime tamper fails as intended. |
Summary
Stack: #395 ← #397 (
cursor/intel-package-name-1297, this PR's base) ← #398 (this) ← #399.Head:
da63c235. Draft. Do not merge. The base (#397,8dd9e851) is merged in (29733e73, merge, not rebase); it carries the zip 9 fix from #417 socargo-auditcan pass, #394's36720070(/healthzand the gateway start prove that the gateway holds the lock from the held flock;docs/LAUNCHER_CONTRACT.md, "What proves that this gateway holds the lock") and #395's macOS smoke test fixes through3cffaad4.32f4abfdmerges #397 at56a8084f(no conflicts), which carries #394's4bb19dcf: the ownership proof is one step (each registry entry keeps a second descriptor of the locked open file, and the registry mutex is held from the lookup to the end of the probe;85f3142e); the managed-runtime subordinate lane uses the same proof as/healthz, and a Home terminal gets an inherited lock descriptor,ELASTOS_GATEWAY_HOST_LOCK_FD(eed83a72); a held lock whose record cannot be read still counts as held (4bb19dcf).9c7ebae6merges #397 ataa7bd1ce(no conflicts;docs/LAUNCHER_CONTRACT.mdandscripts/gateway-healthz-smoke-test.pyauto-merged), which carries #394's13cdcad0(the contract states that the host lock proves possession, not that the holder is the gateway) and #395's630efc6d(the default-command smoke test no longer depends on port 8090). The base merges do not change this PR's diff against #397.Round 4 commits on top of
29733e73:f8defe86test only: the swapped-Runtime test now swaps the real download on macOS too (see "Why the swap test failed on a Mac").112e168finstall.sh: the staged Runtime runs from one held file, not by path (item 5 below).Round 5 commit:
da63c235test only: the Linux case of the swapped-Runtime test no longer uses the host'smktemp(see "Round 5: the Linux case assumed GNU mktemp").What this PR does in
scripts/install.sh:detect_platformstops an Intel Mac before any download and exits 1 with exactlyIntel Mac is not supported yet.The text lives once, inINTEL_MAC_UNSUPPORTED(install.sh:327); the stop (:357) and--help(:113) print that variable.docs/MAC.md#intel-macnames the variable and quotes it.uname -mx86_64. On Darwinx86_64,mac_has_apple_silicon(install.sh:332) asks the kernel:sysctl -in sysctl.proc_translatedorsysctl -in hw.optional.arm64must print1. Then the platform isaarch64-darwin. That build is arm64 only (package-release-binaries.shrefuses a universal binary), so macOS runs it natively when the Rosetta shell starts it. Any other answer, a failedsysctlor a missingsysctlproves nothing, so the installer stops with the Intel Mac message before any download (fail closed).HEAD_CIDstamp must equal the UnixFS CIDv0 of the verifiedrelease-head.jsonbytes, or the run exits 1. An empty stamp stays empty, so a frozen installer does not cache a head CID (8e3c774f).verify_signature(install.sh:760) reads the envelope once and returns the SHA-256 of the bytes whose signature passed (HEAD_SHA256:1427,RELEASE_SHA256:1459).bind_verified_head_cid,json_get,validate_release_identity) takes that SHA-256 and stops withRELEASE_CHANGED(:161) for other bytes.sources.jsonpinsMAINTAINER_DID(:1557), the trust root thatverify_signaturecompared with the signer. Before, it readd["signer_did"]from the file again.update.rsinstall_release) reads each file once, checks those bytes against the pin, version, channel and any stamp insources.json, and installs those same bytes. It admits the candidate Runtime only if the bytes it read have the signed SHA-256 (installed_release.rsadmit_candidate).112e168f). Before, the installer hashed the staged copy by path, then ran it by path three times (--version,install-release --check,install-release). The staged Runtime is the installer's writer, so a process that replaced or rewrote that path between the hash and a run got its own program run as the writer. Now:0500) in a new0700folder made bymktemp -dinside the checked install directory (:1518).:1526).held_runtime hash(:408) takes its SHA-256 from that open file and records its identity (device, inode, size, mtime, ctime).held_runtime check(:1540,:1622,:1635) refuses withRUNTIME_CHANGED(:159) unless the held file is unchanged, is a regular file of this user with mode0500and one link, and the path still names it./proc/self/fd/9,:1533),run_held_runtime(:449) starts the held file itself, so a path swapped after the last check cannot run. macOS has no way to start an open file (nofexecve), so there the path runs right after the check. fd 9 is closed after the install (:1638).Why the swap test failed on a Mac
The round-3 hook swapped a file only when its path was under
TMPDIR. Apple'smktemp -d(no template) ignoresTMPDIR: in its implied-tmode it uses the per-user folder fromconfstr(_CS_DARWIN_USER_TEMP_DIR)(apple-oss-distributions/shell_cmdsmktemp/mktemp.c, the#ifdef __APPLE__branch inif (tflag)). GNUmktemp -dusesTMPDIR. So on a Mac nothing was swapped, the install succeeded, and the test failed onreturncode. Reproduced on Linux with a mock that behaves like Apple'smktemp -d: the round-3 hook gives exit 0 and the original Runtime installed.Now the hook swaps the exact path
curlwrote (thecurlmock logs it), once, and logs the swap (hasher, path, SHA-256 before and after). The test asserts the swap happened before it asserts the refusal, so it cannot pass or fail without a swap.sha256sumandshasum -a 256are both mocked.TMPDIRis a private0700folder the test made.Round 5: the Linux case assumed GNU mktemp
Review (round 4): "the swapped-Runtime test's Linux subcase assumes GNU mktemp, so it fails on every Mac host (
install-bootstrap-test.py:1112)". Confirmed. The Darwin cases mock Apple'smktemp(mock_apple_mktemp), but the Linux case used the host's ownmktempand then required the scratch folder to be under the fixtureTMPDIR(:1111-1112). On a Mac host thatmktempis Apple's, which ignoresTMPDIR.da63c235addsmock_gnu_mktemp(install-bootstrap-test.py:826):mktemp -dwith no template makes${TMPDIR:-/tmp}/tmp.XXXXXXXXXX; every other form goes to the hostmktempunchanged. It uses only a template ending inX, which GNU and BSDmktempboth accept. The Linux case uses it (:1117), so each of the three cases now mocksmktempand none depends on the host.Proof without a Mac: a stub
mktempfirst onPATHthat behaves like Apple's (only-d -q -t -u;--tmpdirand-prefused withillegal option; no template and no-tuses a per-user folder, notTMPDIR; a template must end inX).9c7ebae6), with the stub: the Linux case fails at the reviewer's line:32f4abfd:Ran 98 tests ... FAILED (failures=1, skipped=4), and that one subcase is the only failure, so no other test depends on GNUmktemp.da63c235): that testOKwith the stub and with the host's GNUmktemp; the whole fileRan 98 tests ... OK (skipped=4)both ways.No real Mac ran this. No CI job runs
install-bootstrap-test.pyon macOS: it runs only insource-gate(ubuntu-24.04) throughscripts/test-source-gate.sh release→release-platform-input-test.py(InstallerAdmissionTest). The macOS jobs (gateway-smoke-macos-intel,source-home-macos) do not run it. So CI on this head proves the Linux path only.Decision: Intel Mac message
Decision 4: the plain stop
Intel Mac is not supported yet., with no pointer to the developer source-home build and no sentence before it. The launcher (Elacity/elastos-launcher) has its own Intel stop text (src/main/targets/runtimeSupport.ts:4-5); this PR does not change the launcher.Tests
On
112e168f(Linux):git diff --checkclean. A realelastosELF (debug build) starts through/proc/self/fd/9withexec -aand prints its version.On
32f4abfd(the base merge):install-bootstrap-test.pyOK (skipped=4);gateway-healthz-smoke-test.pyOK (skipped=3).On
da63c235:install-bootstrap-test.py98 OK (skipped=4) with the hostmktempand with the Apple-like stub;release-platform-input-test.py164 OK andrelease-signer-test.py87 OK (both underenv -i PATH=... HOME=... python3 -I -S; in a shell with TLS proxy variables the signer refuses them, as #397 notes);gateway-healthz-smoke-test.py26 OK (3 skipped);ci-release-policy-test.py103 OK;package-release-binaries-test.py9 OK;git diff --check,public-copy-entropy-checkpass.The tamper tests:
test_runtime_swapped_after_its_checksum_check_is_not_run_or_installed: the download is rewritten right after its SHA-256 passed. Three cases: Linux withsha256sumand a GNU-likemktempmock; Darwin (unamemock,arm64) with Apple'smktemp -dlayout andTMPDIRbehind a symlink (like/tmp→/private/tmp); the same with nosha256sumonPATH, soshasumis used.test_staged_runtime_swapped_between_its_hash_and_its_run_is_refused: the staged Runtime is replaced at its path, or rewritten in place with its mode put back, right afterheld_runtime hash. Linux and Darwin layouts. Refused before anything runs.test_staged_runtime_swapped_after_its_last_check_still_runs_the_checked_bytes(Linux only, skipped where/proc/self/fdis missing): the path is replaced after the last check. The checked bytes run, the replacement never runs, and the writer refuses the replaced candidate, as Runtime's writer does.test_held_runtime_refuses_any_change_to_the_held_file_or_its_path: path renamed over, removed, made a symlink, file written in place, made writable, given a second link.Negative checks (the lines reverted, then restored):
held_runtime checkmade a no-op: the staged-swap test fails 4 of 4 (AssertionError: True is not falseonswapped-ran: the swapped Runtime ran), and the unit test fails 6 of 6 (0 != 12).HELD_RUNTIME=/proc/self/fd/9removed (path exec, as on macOS): the after-the-last-check test fails (True is not false: the swapped Runtime ran). This is the macOS window that remains.install.sh(29733e73, hash by path then run by path): the staged-swap test fails 4 of 4 (True is not false).29733e73install.sh:1469-1471) with the new download-swap test: fails 3 of 3 (True is not false), after the swap assertions passed.sys.exit(3)SHA-256 comparisons removed →test_release_head_swapped_after_its_signature_check_is_refusedexits 0; pin set back tod["signer_did"]→test_publisher_pin_is_the_trust_root_not_a_second_readfails.CI
29733e73(run 39038170012):source-gate,cargo-audit,release-upstream-pathsandgateway-smoke-macos-intelpassed; the other jobs were still queued when112e168fwas pushed. No job failed. CI runsinstall-bootstrap-test.pyon Linux only (source-gatethroughrelease-platform-input-test.py).Principles check
1stops before any download. A staged Runtime that changed after its check does not run.Gaps, not fixed here:
0700folder.mktemp -d(TMPDIR on Linux, the per-user folder on macOS). A swap there is refused, not prevented.install.sh:45,:1265-1267). The team decided this in Follow-ups from Sasha's 0.8.0 pre-release review (#375) #434 for 0.8.1; Stamped installer: no environment or flag override of the maintainer DID #435 (stacked on this PR) makes the stamped installer refuse a different DID. Unchanged here.uname, Apple'smktemp -dlayout and aPATHwithoutsha256sumon Linux, and the round-5 check used an Apple-likemktempstub on Linux. The path-exec branch that macOS takes was run on Linux only by forcing it (the second revert check): the staged-swap test passes on it, the after-the-last-check test fails as expected. Not tested on a real Rosetta Terminal or a real Intel Mac. No CI job runs this suite on macOS.No grade here is a merge approval.
Team issues to open
Signed x86_64-darwin artifact, darwin-amd64 payloads, and Home journey.docs/MAC.md#intel-mac.scripts/install-bootstrap-test.pyin a macOS job, so a host-specific assumption like this one is caught by CI.