oxedyne/daimond/dev/build-wasm.sh
7.1 KiB, 1 run
created by r2519314175:13, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | #!/bin/bash |
| 2 | # build-wasm.sh -- build the browser bundle so that the bytes are the same |
| 3 | # wherever it is built. |
| 4 | # |
| 5 | # This is THE build command for Daimond's wasm. Use it rather than calling |
| 6 | # wasm-pack directly, and use it for a rebuild you intend to compare against the |
| 7 | # published bundle: a plain `wasm-pack build` does NOT produce the sealed bytes. |
| 8 | # |
| 9 | # Why it exists. Rust bakes the path of every source file into the binary -- |
| 10 | # `file!()` is expanded by the `err!` and panic macros throughout fe2o3, and the |
| 11 | # expansion is the path as rustc saw it. Built plainly, the wasm therefore |
| 12 | # carries the absolute paths of the machine that built it, somewhere under |
| 13 | # `/home/<whoever>/.cargo/git/checkouts/...`. Two people building byte-identical |
| 14 | # source get different wasm, and the difference is only their home directory. |
| 15 | # |
| 16 | # That quietly voided the whole verifiability claim. "Rebuild it and compare the |
| 17 | # hash" is addressed to a stranger, and no stranger could ever have matched it; |
| 18 | # it only ever succeeded for someone rebuilding on the machine that sealed it, |
| 19 | # which is not evidence of anything. It also meant every visitor was served the |
| 20 | # author's directory layout inside the wasm. |
| 21 | # |
| 22 | # The fix is to remap those prefixes to fixed stand-ins before they are baked |
| 23 | # in. Cargo's own `trim-paths` profile option would do this, but it is still |
| 24 | # nightly-only in Cargo 1.90 (the pinned toolchain), so the equivalent is done |
| 25 | # here with the stable `--remap-path-prefix` flag. Each builder maps THEIR |
| 26 | # paths to the SAME stand-ins, so the output stops depending on where they keep |
| 27 | # their files. |
| 28 | # |
| 29 | # bash dev/build-wasm.sh # the sealed build |
| 30 | # bash dev/build-wasm.sh --dev # anything else is passed to wasm-pack |
| 31 | set -e |
| 32 | cd "$(dirname "$0")/.." |
| 33 | ROOT=$(pwd -P) |
| 34 | |
| 35 | # Where cargo unpacks dependency sources. Everything under it becomes /cargo. |
| 36 | CARGO_DIR=$(cd "${CARGO_HOME:-$HOME/.cargo}" && pwd -P) |
| 37 | |
| 38 | # The two prefixes that vary from machine to machine. rustc already remaps its |
| 39 | # own standard library to /rustc/<hash>, so those two are the whole story. |
| 40 | export RUSTFLAGS="--remap-path-prefix=$CARGO_DIR=/cargo --remap-path-prefix=$ROOT=/build ${RUSTFLAGS:-}" |
| 41 | |
| 42 | wasm-pack build --target web --out-dir www/pkg "$@" |
| 43 | |
| 44 | # ── Say what it was built from ────────────────────────────────────────── |
| 45 | # |
| 46 | # `dev/staleguard.mjs` is what decides whether a verifier is measuring THIS |
| 47 | # tree's engine, and with nothing to go on it can only compare clocks. An mtime |
| 48 | # answers a different question from the one being asked -- "was the bundle |
| 49 | # written after the source was?" rather than "was it built FROM this source?" -- |
| 50 | # and the two part company whenever files are rewritten without being changed. A |
| 51 | # `git stash` and its `pop` restore byte-identical sources with new timestamps, |
| 52 | # and every wasm-guarded verifier then refuses a bundle that is in fact this |
| 53 | # source's. That cost a lane a rebuild it did not need on 2026-08-12. |
| 54 | # |
| 55 | # So the bundle now carries `www/pkg/source.json`: a SHA-256 per engine source |
| 56 | # file, plus one over the wasm itself. Two properties keep it from becoming a |
| 57 | # second thing to go stale. The guard REHASHES the tree in front of it rather |
| 58 | # than believing the note, so an edit made afterwards is caught exactly as it |
| 59 | # always was; and the note names the bundle it is about, so a bundle rebuilt by |
| 60 | # any other means stops matching and the clock takes over. It can only ever |
| 61 | # prevent a false refusal. It can never launder a stale bundle. |
| 62 | # |
| 63 | # It does NOT make rebuilds rare. A comment added to a Rust file moves that |
| 64 | # file's hash just as a changed fence does, and nothing short of compiling can |
| 65 | # tell those apart. What stops costing a build is source that never changed. |
| 66 | # |
| 67 | # The other half of this lives in `verify/lib.mjs`: `pkg/source.json` is in |
| 68 | # EXCLUDE, so the note never enters a sealed manifest. It records where and when |
| 69 | # a build happened, both of which differ for every honest rebuild, and sealing it |
| 70 | # would make "clone it, build it, compare the hash" false for every reader. |
| 71 | # Neither half is any use alone. `dev/repro-check.sh` proves the pair. |
| 72 | # |
| 73 | # Not fatal when it cannot be written -- an older mirror has no staleguard to |
| 74 | # call, and the bundle above is built and good either way. What is lost is a |
| 75 | # shortcut. Said out loud rather than swallowed, because a build that quietly |
| 76 | # stopped certifying would look exactly like one that never started. |
| 77 | # |
| 78 | # `2>&1 >/dev/null` keeps the REASON: the hash on stdout is noise here, and the |
| 79 | # reason is on stderr, and a failure reported without one is a second thing to |
| 80 | # go and find out. |
| 81 | if WHY=$(node dev/staleguard.mjs certify www/pkg "$ROOT" dev/build-wasm.sh 2>&1 >/dev/null); then |
| 82 | echo |
| 83 | echo "build-wasm: certified — www/pkg/source.json records the source this was built from," |
| 84 | echo " so a verifier compares content rather than timestamps." |
| 85 | else |
| 86 | echo |
| 87 | echo "build-wasm: NOT CERTIFIED — no source record could be written beside the bundle, so" |
| 88 | echo " verifiers fall back to comparing mtimes. The bundle itself is built and fine." |
| 89 | echo "${WHY:- (no reason given)}" | sed 's/^/ /' |
| 90 | fi |
| 91 | |
| 92 | # ── Say which kind of bundle this is ──────────────────────────────────── |
| 93 | # |
| 94 | # The two prefixes above are the whole story ONLY in the mirror, where |
| 95 | # `Cargo.toml` pins fe2o3 by git revision so its sources come from under |
| 96 | # $CARGO_DIR. The DEV tree links fe2o3 by path, at ~/usr/code/rust/fe2o3, which is |
| 97 | # outside both remapped prefixes -- so every `err!` and every panic in fe2o3 |
| 98 | # bakes this machine's home directory into the bundle, and a build made here can |
| 99 | # never be reproduced by a stranger. |
| 100 | # |
| 101 | # That is fine for testing and fatal for sealing, and the difference is invisible |
| 102 | # unless somebody thinks to look. It was NOT looked at for two releases: seq 66 |
| 103 | # and 67 were sealed from a dev build, so for three days the transparency log |
| 104 | # named a bundle nobody outside this machine could produce. The check costs |
| 105 | # nothing, so it runs every time rather than being remembered. |
| 106 | # |
| 107 | # It greps for THIS BUILDER'S home directory, not for `/home/` generally. The |
| 108 | # broader pattern also matches `/home/you/project/src/main.rs`, which is a |
| 109 | # deliberate literal in `src/tools.rs` -- the file tools' own description, telling |
| 110 | # a model that an absolute path is refused rather than followed. A correct, |
| 111 | # reproducible mirror build therefore reported "DEV BUILD - 1 line" and would have |
| 112 | # been withheld from a release for a documentation example. A check that cries |
| 113 | # wolf on a good build gets ignored on a bad one, which is the failure this check |
| 114 | # exists to prevent. |
| 115 | BAKED=$(grep -ac "$HOME" www/pkg/oxedyne_daimond_bg.wasm || true) |
| 116 | echo |
| 117 | if [ "$BAKED" -eq 0 ]; then |
| 118 | echo "build-wasm: REPRODUCIBLE — no home directory in the bundle. Safe to seal." |
| 119 | else |
| 120 | echo "build-wasm: DEV BUILD — $BAKED line(s) of this machine's home directory are in" |
| 121 | echo " the bundle, because fe2o3 is linked by PATH here and only the mirror pins it" |
| 122 | echo " by revision. Fine to test with. DO NOT SEAL IT: build in the mirror instead," |
| 123 | echo " per \"Deploying\" in ~/usr/SYSTEM.md, and let repro-check.sh confirm it." |
| 124 | fi |