@agoric/xsnap 0.14.3-dev-dcc80f2.0.dcc80f2 → 0.14.3-dev-4b83f24.0.4b83f24
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/README.md +33 -0
- package/package.json +8 -18
- package/scripts/use-github-release-binary.sh +160 -0
- package/src/install-prebuilt.js +358 -0
- package/src/prebuilt-manifest-sha256.js +3 -0
- package/src/xsnap.js +41 -18
- package/build.env +0 -4
- package/moddable/modules/data/base64/base64.js +0 -28
- package/moddable/modules/data/base64/manifest.json +0 -11
- package/moddable/modules/data/base64/modBase64.c +0 -188
- package/moddable/modules/data/binaryMessage/BinaryMessage.js +0 -106
- package/moddable/modules/data/crc/crc.c +0 -205
- package/moddable/modules/data/crc/crc.js +0 -36
- package/moddable/modules/data/crc/manifest.json +0 -8
- package/moddable/modules/data/hex/hex.js +0 -28
- package/moddable/modules/data/hex/manifest.json +0 -11
- package/moddable/modules/data/hex/modHex.c +0 -139
- package/moddable/modules/data/logical/logical.js +0 -32
- package/moddable/modules/data/logical/modLogical.c +0 -98
- package/moddable/modules/data/qrcode/manifest.json +0 -9
- package/moddable/modules/data/qrcode/qrcode.c +0 -93
- package/moddable/modules/data/qrcode/qrcode.js +0 -23
- package/moddable/modules/data/qrcode/qrcodegen.c +0 -1025
- package/moddable/modules/data/qrcode/qrcodegen.h +0 -267
- package/moddable/modules/data/text/decoder/manifest.json +0 -8
- package/moddable/modules/data/text/decoder/textdecoder.c +0 -480
- package/moddable/modules/data/text/decoder/textdecoder.js +0 -27
- package/moddable/modules/data/text/encoder/manifest.json +0 -8
- package/moddable/modules/data/text/encoder/textencoder.c +0 -232
- package/moddable/modules/data/text/encoder/textencoder.js +0 -24
- package/moddable/modules/data/tinyint/tinyint.c +0 -150
- package/moddable/modules/data/tinyint/tinyint.js +0 -53
- package/moddable/modules/data/url/manifest.json +0 -17
- package/moddable/modules/data/url/url.c +0 -1959
- package/moddable/modules/data/url/url.js +0 -210
- package/moddable/modules/data/wavreader/manifest.json +0 -8
- package/moddable/modules/data/wavreader/wavreader.js +0 -128
- package/moddable/modules/data/zlib/deflate.c +0 -161
- package/moddable/modules/data/zlib/deflate.js +0 -63
- package/moddable/modules/data/zlib/inflate.c +0 -145
- package/moddable/modules/data/zlib/inflate.js +0 -66
- package/moddable/modules/data/zlib/manifest_deflate.json +0 -9
- package/moddable/modules/data/zlib/manifest_inflate.json +0 -9
- package/moddable/modules/data/zlib/miniz.c +0 -4924
- package/moddable/xs/includes/xs.d.ts +0 -73
- package/moddable/xs/includes/xs.h +0 -1533
- package/moddable/xs/includes/xsmc.h +0 -206
- package/moddable/xs/makefiles/lin/makefile +0 -33
- package/moddable/xs/makefiles/lin/xsc.mk +0 -118
- package/moddable/xs/makefiles/lin/xsid.mk +0 -90
- package/moddable/xs/makefiles/lin/xsl.mk +0 -168
- package/moddable/xs/makefiles/lin/xst.mk +0 -201
- package/moddable/xs/makefiles/mac/makefile +0 -33
- package/moddable/xs/makefiles/mac/xsc.mk +0 -130
- package/moddable/xs/makefiles/mac/xsid.mk +0 -102
- package/moddable/xs/makefiles/mac/xsl.mk +0 -177
- package/moddable/xs/makefiles/mac/xst.mk +0 -203
- package/moddable/xs/makefiles/mac/xst_no_asan.txt +0 -52
- package/moddable/xs/makefiles/win/build.bat +0 -26
- package/moddable/xs/makefiles/win/xsc.mak +0 -142
- package/moddable/xs/makefiles/win/xsid.mak +0 -113
- package/moddable/xs/makefiles/win/xsl.mak +0 -186
- package/moddable/xs/makefiles/win/xst.mak +0 -195
- package/moddable/xs/platforms/lin_xs.h +0 -99
- package/moddable/xs/platforms/mac_xs.h +0 -97
- package/moddable/xs/platforms/wasm_xs.h +0 -79
- package/moddable/xs/platforms/win_xs.h +0 -104
- package/moddable/xs/platforms/xsHost.h +0 -63
- package/moddable/xs/platforms/xsPlatform.h +0 -618
- package/moddable/xs/sources/xsAPI.c +0 -2555
- package/moddable/xs/sources/xsAll.c +0 -294
- package/moddable/xs/sources/xsAll.h +0 -2741
- package/moddable/xs/sources/xsArguments.c +0 -222
- package/moddable/xs/sources/xsArray.c +0 -2657
- package/moddable/xs/sources/xsAtomics.c +0 -844
- package/moddable/xs/sources/xsBigInt.c +0 -1859
- package/moddable/xs/sources/xsBoolean.c +0 -109
- package/moddable/xs/sources/xsCode.c +0 -4493
- package/moddable/xs/sources/xsCommon.c +0 -1710
- package/moddable/xs/sources/xsCommon.h +0 -1142
- package/moddable/xs/sources/xsDataView.c +0 -2890
- package/moddable/xs/sources/xsDate.c +0 -1541
- package/moddable/xs/sources/xsDebug.c +0 -2710
- package/moddable/xs/sources/xsDefaults.c +0 -134
- package/moddable/xs/sources/xsError.c +0 -353
- package/moddable/xs/sources/xsFunction.c +0 -776
- package/moddable/xs/sources/xsGenerator.c +0 -865
- package/moddable/xs/sources/xsGlobal.c +0 -839
- package/moddable/xs/sources/xsJSON.c +0 -1091
- package/moddable/xs/sources/xsLexical.c +0 -1969
- package/moddable/xs/sources/xsLockdown.c +0 -933
- package/moddable/xs/sources/xsMapSet.c +0 -1649
- package/moddable/xs/sources/xsMarshall.c +0 -1020
- package/moddable/xs/sources/xsMath.c +0 -624
- package/moddable/xs/sources/xsMemory.c +0 -1941
- package/moddable/xs/sources/xsModule.c +0 -3101
- package/moddable/xs/sources/xsNumber.c +0 -560
- package/moddable/xs/sources/xsObject.c +0 -1102
- package/moddable/xs/sources/xsPlatforms.c +0 -480
- package/moddable/xs/sources/xsProfile.c +0 -577
- package/moddable/xs/sources/xsPromise.c +0 -1199
- package/moddable/xs/sources/xsProperty.c +0 -636
- package/moddable/xs/sources/xsProxy.c +0 -1014
- package/moddable/xs/sources/xsRegExp.c +0 -1168
- package/moddable/xs/sources/xsRun.c +0 -4889
- package/moddable/xs/sources/xsScope.c +0 -1293
- package/moddable/xs/sources/xsScript.c +0 -288
- package/moddable/xs/sources/xsScript.h +0 -1186
- package/moddable/xs/sources/xsSnapshot.c +0 -2161
- package/moddable/xs/sources/xsSnapshot.h +0 -51
- package/moddable/xs/sources/xsSourceMap.c +0 -218
- package/moddable/xs/sources/xsString.c +0 -3332
- package/moddable/xs/sources/xsSymbol.c +0 -503
- package/moddable/xs/sources/xsSyntaxical.c +0 -4193
- package/moddable/xs/sources/xsTree.c +0 -1893
- package/moddable/xs/sources/xsType.c +0 -1488
- package/moddable/xs/sources/xsdtoa.c +0 -6672
- package/moddable/xs/sources/xsmc.c +0 -340
- package/moddable/xs/sources/xsre.c +0 -7578
- package/src/build.js +0 -481
- package/xsnap-native/xsnap/makefiles/lin/makefile +0 -10
- package/xsnap-native/xsnap/makefiles/lin/xsnap-worker.mk +0 -156
- package/xsnap-native/xsnap/makefiles/lin/xsnap.mk +0 -144
- package/xsnap-native/xsnap/makefiles/mac/makefile +0 -10
- package/xsnap-native/xsnap/makefiles/mac/xsnap-worker.mk +0 -165
- package/xsnap-native/xsnap/makefiles/mac/xsnap.mk +0 -153
- package/xsnap-native/xsnap/sources/xsnap-worker.c +0 -1024
- package/xsnap-native/xsnap/sources/xsnap.c +0 -717
- package/xsnap-native/xsnap/sources/xsnap.h +0 -142
- package/xsnap-native/xsnap/sources/xsnapPlatform.c +0 -1501
- package/xsnap-native/xsnap/sources/xsnapPlatform.h +0 -105
package/README.md
CHANGED
|
@@ -18,6 +18,39 @@ await fs.writeFile('bootstrap.xss', worker.makeSnapshotStream());
|
|
|
18
18
|
await worker.close();
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Using CI-built binaries from `xsnap-worker-binaries`
|
|
22
|
+
|
|
23
|
+
Before npm platform packages are wired, CI can consume binaries from GitHub
|
|
24
|
+
releases in `Agoric/xsnap-worker-binaries`.
|
|
25
|
+
|
|
26
|
+
From `packages/xsnap/`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
./scripts/use-github-release-binary.sh 0.0.0-dev /tmp/xsnap-release-assets
|
|
30
|
+
source /tmp/xsnap-release-assets/xsnap-binary.env
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This sets:
|
|
34
|
+
|
|
35
|
+
- `XSNAP_WORKER` for release mode
|
|
36
|
+
- `XSNAP_WORKER_DEBUG` for debug mode
|
|
37
|
+
|
|
38
|
+
The script verifies SHA256 digests against the release manifest before writing
|
|
39
|
+
the env file.
|
|
40
|
+
|
|
41
|
+
## Package install behavior
|
|
42
|
+
|
|
43
|
+
`@agoric/xsnap` postinstall now installs prebuilt binaries from GitHub releases
|
|
44
|
+
instead of compiling native sources locally.
|
|
45
|
+
|
|
46
|
+
Optional environment overrides:
|
|
47
|
+
|
|
48
|
+
- `XSNAP_BINARY_VERSION` (default: package version)
|
|
49
|
+
- `XSNAP_BINARY_REPO` (default: `Agoric/xsnap-worker-binaries`)
|
|
50
|
+
- `XSNAP_BINARY_BASE_URL` (advanced override)
|
|
51
|
+
- `XSNAP_BINARY_MANIFEST_SHA256` (required trust anchor for unpinned versions)
|
|
52
|
+
- `XSNAP_CACHE_DIR` (advanced override for cached downloads)
|
|
53
|
+
|
|
21
54
|
Some time later, possibly on a different computer…
|
|
22
55
|
|
|
23
56
|
```js
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/xsnap",
|
|
3
|
-
"version": "0.14.3-dev-
|
|
3
|
+
"version": "0.14.3-dev-4b83f24.0.4b83f24",
|
|
4
4
|
"description": "Snapshotting VM worker based on Moddable's XS Javascript engine",
|
|
5
5
|
"author": "Agoric",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -12,12 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
14
|
"repl": "node src/xsrepl.js",
|
|
15
|
-
"
|
|
16
|
-
"build
|
|
17
|
-
"build:from-env": "{ cat build.env; echo node src/build.js; } | xargs env",
|
|
18
|
-
"build": "yarn build:bin && yarn build:env",
|
|
15
|
+
"install:prebuilt": "node src/install-prebuilt.js",
|
|
16
|
+
"build": "yarn install:prebuilt",
|
|
19
17
|
"check-version": "/bin/sh -c 'if test \"${npm_package_version}\" != \"$(./scripts/get_xsnap_version.sh)\"; then echo \"xsnap version mismatch; expected '${npm_package_version}'\"; exit 1; fi'",
|
|
20
|
-
"postinstall": "npm run
|
|
18
|
+
"postinstall": "npm run install:prebuilt",
|
|
21
19
|
"clean": "rm -rf xsnap-native/xsnap/build",
|
|
22
20
|
"lint": "yarn run -T run-s --continue-on-error 'lint:*'",
|
|
23
21
|
"lint:eslint": "yarn run -T eslint 'src/**/*.js' 'test/**/*.js' api.js",
|
|
@@ -28,8 +26,8 @@
|
|
|
28
26
|
"test:xs": "exit 0"
|
|
29
27
|
},
|
|
30
28
|
"dependencies": {
|
|
31
|
-
"@agoric/internal": "0.3.3-dev-
|
|
32
|
-
"@agoric/xsnap-lockdown": "0.14.1-dev-
|
|
29
|
+
"@agoric/internal": "0.3.3-dev-4b83f24.0.4b83f24",
|
|
30
|
+
"@agoric/xsnap-lockdown": "0.14.1-dev-4b83f24.0.4b83f24",
|
|
33
31
|
"@endo/bundle-source": "^4.1.2",
|
|
34
32
|
"@endo/errors": "^1.2.13",
|
|
35
33
|
"@endo/eventual-send": "^1.3.4",
|
|
@@ -51,16 +49,8 @@
|
|
|
51
49
|
"files": [
|
|
52
50
|
"LICENSE*",
|
|
53
51
|
"api.js",
|
|
54
|
-
"build.env",
|
|
55
|
-
"moddable/modules/data/**",
|
|
56
|
-
"moddable/xs/includes/**",
|
|
57
|
-
"moddable/xs/makefiles/**",
|
|
58
|
-
"moddable/xs/sources/**",
|
|
59
|
-
"moddable/xs/platforms/*.h",
|
|
60
52
|
"scripts/**",
|
|
61
|
-
"src/**"
|
|
62
|
-
"xsnap-native/xsnap/makefiles/**",
|
|
63
|
-
"xsnap-native/xsnap/sources/**"
|
|
53
|
+
"src/**"
|
|
64
54
|
],
|
|
65
55
|
"publishConfig": {
|
|
66
56
|
"access": "public"
|
|
@@ -80,5 +70,5 @@
|
|
|
80
70
|
"engines": {
|
|
81
71
|
"node": "^20.9 || ^22.11"
|
|
82
72
|
},
|
|
83
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "4b83f243d627e8214b1b33338566dff420259339"
|
|
84
74
|
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
version="${1:-}"
|
|
6
|
+
out_dir="${2:-}"
|
|
7
|
+
repo="${XSNAP_BINARY_REPO:-Agoric/xsnap-worker-binaries}"
|
|
8
|
+
|
|
9
|
+
if [[ -z "$version" || -z "$out_dir" ]]; then
|
|
10
|
+
echo "Usage: $0 <version> <output-dir>" >&2
|
|
11
|
+
echo "Environment:" >&2
|
|
12
|
+
echo " XSNAP_BINARY_REPO (default: Agoric/xsnap-worker-binaries)" >&2
|
|
13
|
+
echo " XSNAP_ENV_FILE (default: <output-dir>/xsnap-binary.env)" >&2
|
|
14
|
+
exit 1
|
|
15
|
+
fi
|
|
16
|
+
|
|
17
|
+
mkdir -p "$out_dir"
|
|
18
|
+
tag="v$version"
|
|
19
|
+
tarball="xsnap-worker-binaries-$version.tar.gz"
|
|
20
|
+
manifest_name="xsnap-worker-manifest-$version.json"
|
|
21
|
+
env_file="${XSNAP_ENV_FILE:-$out_dir/xsnap-binary.env}"
|
|
22
|
+
|
|
23
|
+
case "$(uname -s)" in
|
|
24
|
+
Linux) os="linux" ;;
|
|
25
|
+
Darwin) os="darwin" ;;
|
|
26
|
+
*)
|
|
27
|
+
echo "Unsupported host OS: $(uname -s)" >&2
|
|
28
|
+
exit 1
|
|
29
|
+
;;
|
|
30
|
+
esac
|
|
31
|
+
|
|
32
|
+
case "$(uname -m)" in
|
|
33
|
+
x86_64|amd64) arch="x64" ;;
|
|
34
|
+
arm64|aarch64) arch="arm64" ;;
|
|
35
|
+
*)
|
|
36
|
+
echo "Unsupported host architecture: $(uname -m)" >&2
|
|
37
|
+
exit 1
|
|
38
|
+
;;
|
|
39
|
+
esac
|
|
40
|
+
|
|
41
|
+
target="$os-$arch"
|
|
42
|
+
|
|
43
|
+
gh release download "$tag" \
|
|
44
|
+
--repo "$repo" \
|
|
45
|
+
--pattern "$tarball" \
|
|
46
|
+
--pattern "$manifest_name" \
|
|
47
|
+
--dir "$out_dir"
|
|
48
|
+
|
|
49
|
+
release_entry="dist/$target/release/xsnap-worker"
|
|
50
|
+
debug_entry="dist/$target/debug/xsnap-worker"
|
|
51
|
+
found_release=false
|
|
52
|
+
found_debug=false
|
|
53
|
+
|
|
54
|
+
mapfile -t tar_entries < <(tar -tvzf "$out_dir/$tarball")
|
|
55
|
+
for line in "${tar_entries[@]}"; do
|
|
56
|
+
[[ -n "$line" ]] || continue
|
|
57
|
+
type="${line:0:1}"
|
|
58
|
+
entry="${line##* }"
|
|
59
|
+
entry="${entry%/}"
|
|
60
|
+
if [[ -z "$entry" || "$entry" = /* || "$entry" == *'\'* ]]; then
|
|
61
|
+
echo "Refusing to extract unsafe archive path: $entry" >&2
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
IFS='/' read -r -a parts <<<"$entry"
|
|
65
|
+
for part in "${parts[@]}"; do
|
|
66
|
+
if [[ "$part" == ".." ]]; then
|
|
67
|
+
echo "Refusing to extract archive path traversal: $entry" >&2
|
|
68
|
+
exit 1
|
|
69
|
+
fi
|
|
70
|
+
done
|
|
71
|
+
allowed=false
|
|
72
|
+
for expected in "${expected_entries[@]}"; do
|
|
73
|
+
if [[ "$entry" == "$expected" ]]; then
|
|
74
|
+
allowed=true
|
|
75
|
+
break
|
|
76
|
+
fi
|
|
77
|
+
done
|
|
78
|
+
if [[ "$allowed" != true ]]; then
|
|
79
|
+
echo "Refusing to extract unexpected archive path: $entry" >&2
|
|
80
|
+
exit 1
|
|
81
|
+
fi
|
|
82
|
+
if [[ "$type" != "-" && "$type" != "d" ]]; then
|
|
83
|
+
echo "Refusing to extract non-regular archive entry: $entry" >&2
|
|
84
|
+
exit 1
|
|
85
|
+
fi
|
|
86
|
+
|
|
87
|
+
if [[ "$entry" == "$release_entry" ]]; then
|
|
88
|
+
found_release=true
|
|
89
|
+
fi
|
|
90
|
+
if [[ "$entry" == "$debug_entry" ]]; then
|
|
91
|
+
found_debug=true
|
|
92
|
+
fi
|
|
93
|
+
done
|
|
94
|
+
|
|
95
|
+
if [[ "$found_release" != true || "$found_debug" != true ]]; then
|
|
96
|
+
echo "Missing binaries for target $target in release bundle" >&2
|
|
97
|
+
exit 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
tar -xzf "$out_dir/$tarball" -C "$out_dir" "$release_entry" "$debug_entry"
|
|
101
|
+
|
|
102
|
+
release_bin="$out_dir/dist/$target/release/xsnap-worker"
|
|
103
|
+
debug_bin="$out_dir/dist/$target/debug/xsnap-worker"
|
|
104
|
+
|
|
105
|
+
if [[ ! -f "$release_bin" || ! -f "$debug_bin" ]]; then
|
|
106
|
+
echo "Missing binaries for target $target in release bundle" >&2
|
|
107
|
+
exit 1
|
|
108
|
+
fi
|
|
109
|
+
|
|
110
|
+
chmod +x "$release_bin" "$debug_bin"
|
|
111
|
+
|
|
112
|
+
manifest_path="$out_dir/$manifest_name"
|
|
113
|
+
|
|
114
|
+
release_expected="$(
|
|
115
|
+
node -e '
|
|
116
|
+
const fs = require("fs");
|
|
117
|
+
const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
118
|
+
const target = process.argv[2];
|
|
119
|
+
process.stdout.write(manifest.targets[target].release.sha256);
|
|
120
|
+
' "$manifest_path" "$target"
|
|
121
|
+
)"
|
|
122
|
+
|
|
123
|
+
debug_expected="$(
|
|
124
|
+
node -e '
|
|
125
|
+
const fs = require("fs");
|
|
126
|
+
const manifest = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
|
|
127
|
+
const target = process.argv[2];
|
|
128
|
+
process.stdout.write(manifest.targets[target].debug.sha256);
|
|
129
|
+
' "$manifest_path" "$target"
|
|
130
|
+
)"
|
|
131
|
+
|
|
132
|
+
sha256_file() {
|
|
133
|
+
local path="$1"
|
|
134
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
135
|
+
sha256sum "$path" | awk '{print $1}'
|
|
136
|
+
else
|
|
137
|
+
shasum -a 256 "$path" | awk '{print $1}'
|
|
138
|
+
fi
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
release_actual="$(sha256_file "$release_bin")"
|
|
142
|
+
debug_actual="$(sha256_file "$debug_bin")"
|
|
143
|
+
|
|
144
|
+
if [[ "$release_expected" != "$release_actual" ]]; then
|
|
145
|
+
echo "Release binary hash mismatch for $target" >&2
|
|
146
|
+
exit 1
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
if [[ "$debug_expected" != "$debug_actual" ]]; then
|
|
150
|
+
echo "Debug binary hash mismatch for $target" >&2
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
cat >"$env_file" <<EOF
|
|
155
|
+
XSNAP_WORKER=$release_bin
|
|
156
|
+
XSNAP_WORKER_DEBUG=$debug_bin
|
|
157
|
+
EOF
|
|
158
|
+
|
|
159
|
+
echo "Prepared xsnap binaries for $target"
|
|
160
|
+
echo "Env file: $env_file"
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-env node */
|
|
3
|
+
|
|
4
|
+
import { createHash } from 'crypto';
|
|
5
|
+
import fsTop from 'fs';
|
|
6
|
+
import osTop from 'os';
|
|
7
|
+
import pathTop from 'path';
|
|
8
|
+
import { fileURLToPath } from 'url';
|
|
9
|
+
import * as childProcess from 'child_process';
|
|
10
|
+
import { manifestHashes } from './prebuilt-manifest-sha256.js';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @import {promises as fsPromises} from 'fs';
|
|
14
|
+
* @import {spawn} from 'child_process';
|
|
15
|
+
* @import {ReadStream} from 'fs';
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** @param {string} path */
|
|
19
|
+
const asset = path => fileURLToPath(new URL(path, import.meta.url));
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {string} osType
|
|
23
|
+
* @param {string} arch
|
|
24
|
+
*/
|
|
25
|
+
export const mapOsArchToTarget = (osType, arch) => {
|
|
26
|
+
const osName = {
|
|
27
|
+
Linux: 'linux',
|
|
28
|
+
Darwin: 'darwin',
|
|
29
|
+
}[osType];
|
|
30
|
+
if (!osName) {
|
|
31
|
+
throw Error(`Unsupported OS for prebuilt xsnap: ${osType}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const archName = {
|
|
35
|
+
x64: 'x64',
|
|
36
|
+
arm64: 'arm64',
|
|
37
|
+
amd64: 'x64',
|
|
38
|
+
aarch64: 'arm64',
|
|
39
|
+
}[arch];
|
|
40
|
+
if (!archName) {
|
|
41
|
+
throw Error(`Unsupported architecture for prebuilt xsnap: ${arch}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return `${osName}-${archName}`;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/** @param {string} target */
|
|
48
|
+
export const targetToBuildPlatform = target => {
|
|
49
|
+
if (target.startsWith('linux-')) {
|
|
50
|
+
return 'lin';
|
|
51
|
+
}
|
|
52
|
+
if (target.startsWith('darwin-')) {
|
|
53
|
+
return 'mac';
|
|
54
|
+
}
|
|
55
|
+
throw Error(`Unsupported target for build platform mapping: ${target}`);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {string} command
|
|
60
|
+
* @param {string[]} args
|
|
61
|
+
* @param {{ cwd?: string }} [opts]
|
|
62
|
+
*/
|
|
63
|
+
const run = (command, args, opts = {}) =>
|
|
64
|
+
new Promise((resolve, reject) => {
|
|
65
|
+
const child = childProcess.spawn(command, args, {
|
|
66
|
+
cwd: opts.cwd || '.',
|
|
67
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
68
|
+
});
|
|
69
|
+
child.once('error', reject);
|
|
70
|
+
child.once('exit', code => {
|
|
71
|
+
if (code === 0) {
|
|
72
|
+
resolve(undefined);
|
|
73
|
+
} else {
|
|
74
|
+
reject(Error(`${command} exited with code ${code}`));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string} command
|
|
81
|
+
* @param {string[]} args
|
|
82
|
+
* @param {{ cwd?: string }} [opts]
|
|
83
|
+
* @returns {Promise<string>}
|
|
84
|
+
*/
|
|
85
|
+
const capture = (command, args, opts = {}) =>
|
|
86
|
+
new Promise((resolve, reject) => {
|
|
87
|
+
const child = childProcess.spawn(command, args, {
|
|
88
|
+
cwd: opts.cwd || '.',
|
|
89
|
+
stdio: ['ignore', 'pipe', 'inherit'],
|
|
90
|
+
});
|
|
91
|
+
let stdout = '';
|
|
92
|
+
child.stdout.setEncoding('utf8');
|
|
93
|
+
child.stdout.on('data', chunk => {
|
|
94
|
+
stdout += chunk;
|
|
95
|
+
});
|
|
96
|
+
child.once('error', reject);
|
|
97
|
+
child.once('exit', code => {
|
|
98
|
+
if (code === 0) {
|
|
99
|
+
resolve(stdout);
|
|
100
|
+
} else {
|
|
101
|
+
reject(Error(`${command} exited with code ${code}`));
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} url
|
|
108
|
+
* @param {string} destPath
|
|
109
|
+
*/
|
|
110
|
+
const downloadFile = async (url, destPath) => {
|
|
111
|
+
const res = await fetch(url);
|
|
112
|
+
if (!res.ok) {
|
|
113
|
+
throw Error(`Download failed for ${url}: HTTP ${res.status}`);
|
|
114
|
+
}
|
|
115
|
+
if (!res.body) {
|
|
116
|
+
throw Error(`Download failed for ${url}: missing response body`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
await fsTop.promises.mkdir(pathTop.dirname(destPath), { recursive: true });
|
|
120
|
+
await fsTop.promises.writeFile(
|
|
121
|
+
destPath,
|
|
122
|
+
Buffer.from(await res.arrayBuffer()),
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {string} path
|
|
128
|
+
* @returns {Promise<string>}
|
|
129
|
+
*/
|
|
130
|
+
const sha256File = async path => {
|
|
131
|
+
const hash = createHash('sha256');
|
|
132
|
+
await new Promise((resolve, reject) => {
|
|
133
|
+
const stream = fsTop.createReadStream(path);
|
|
134
|
+
stream.once('error', reject);
|
|
135
|
+
stream.on('data', chunk => hash.update(chunk));
|
|
136
|
+
stream.once('end', resolve);
|
|
137
|
+
});
|
|
138
|
+
return hash.digest('hex');
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* @param {string} manifestPath
|
|
143
|
+
* @param {string} target
|
|
144
|
+
* @returns {Promise<{ release: string, debug: string }>}
|
|
145
|
+
*/
|
|
146
|
+
const readExpectedHashes = async (manifestPath, target) => {
|
|
147
|
+
const text = await fsTop.promises.readFile(manifestPath, 'utf8');
|
|
148
|
+
const manifest = JSON.parse(text);
|
|
149
|
+
const entry = manifest?.targets?.[target];
|
|
150
|
+
if (!entry?.release?.sha256 || !entry?.debug?.sha256) {
|
|
151
|
+
throw Error(`Manifest missing hashes for target ${target}`);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
release: entry.release.sha256,
|
|
155
|
+
debug: entry.debug.sha256,
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
const getDefaultCacheRoot = () => {
|
|
160
|
+
if (process.platform === 'darwin') {
|
|
161
|
+
return pathTop.join(osTop.homedir(), 'Library', 'Caches', 'agoric-sdk');
|
|
162
|
+
}
|
|
163
|
+
return pathTop.join(
|
|
164
|
+
process.env.XDG_CACHE_HOME || pathTop.join(osTop.homedir(), '.cache'),
|
|
165
|
+
'agoric-sdk',
|
|
166
|
+
);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/** @param {string} entry */
|
|
170
|
+
const isSafeTarEntry = entry =>
|
|
171
|
+
entry !== '' &&
|
|
172
|
+
!pathTop.isAbsolute(entry) &&
|
|
173
|
+
!entry.split('/').includes('..') &&
|
|
174
|
+
!entry.includes('\\');
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param {string} tarballPath
|
|
178
|
+
* @param {string[]} expectedFiles
|
|
179
|
+
*/
|
|
180
|
+
const validateTarball = async (tarballPath, expectedFiles) => {
|
|
181
|
+
const remaining = new Set(expectedFiles);
|
|
182
|
+
const listing = await capture('tar', ['-tvzf', tarballPath]);
|
|
183
|
+
for (const line of listing.split('\n')) {
|
|
184
|
+
if (!line) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const type = line[0];
|
|
188
|
+
const rawEntry = line.split(/\s+/).at(-1) || '';
|
|
189
|
+
const entry = rawEntry.replace(/\/$/, '');
|
|
190
|
+
if (!isSafeTarEntry(entry)) {
|
|
191
|
+
throw Error(`Refusing to extract unsafe archive path: ${rawEntry}`);
|
|
192
|
+
}
|
|
193
|
+
if (type !== 'd' && type !== '-') {
|
|
194
|
+
throw Error(`Refusing to extract non-regular archive entry: ${rawEntry}`);
|
|
195
|
+
}
|
|
196
|
+
remaining.delete(entry);
|
|
197
|
+
}
|
|
198
|
+
if (remaining.size > 0) {
|
|
199
|
+
throw Error(
|
|
200
|
+
`Archive missing expected xsnap binaries: ${Array.from(remaining).join(', ')}`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* @param {string} version
|
|
207
|
+
* @param {NodeJS.ProcessEnv} env
|
|
208
|
+
*/
|
|
209
|
+
const getExpectedManifestHash = (version, env) => {
|
|
210
|
+
const expected = env.XSNAP_BINARY_MANIFEST_SHA256 || manifestHashes[version];
|
|
211
|
+
if (!expected) {
|
|
212
|
+
throw Error(
|
|
213
|
+
`Missing trusted manifest hash for xsnap binary version ${version}; set XSNAP_BINARY_MANIFEST_SHA256 for explicit overrides`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
return expected;
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const main = async () => {
|
|
220
|
+
const env = process.env;
|
|
221
|
+
if (env.XSNAP_WORKER) {
|
|
222
|
+
console.log('XSNAP_WORKER is set; skipping prebuilt binary install');
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const version = env.XSNAP_BINARY_VERSION || env.npm_package_version;
|
|
227
|
+
if (!version) {
|
|
228
|
+
throw Error(
|
|
229
|
+
'Missing XSNAP_BINARY_VERSION and npm_package_version; cannot resolve prebuilt release',
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const repo = env.XSNAP_BINARY_REPO || 'Agoric/xsnap-worker-binaries';
|
|
234
|
+
const base =
|
|
235
|
+
env.XSNAP_BINARY_BASE_URL ||
|
|
236
|
+
`https://github.com/${repo}/releases/download/v${version}`;
|
|
237
|
+
|
|
238
|
+
const target = mapOsArchToTarget(osTop.type(), osTop.arch());
|
|
239
|
+
const platform = targetToBuildPlatform(target);
|
|
240
|
+
|
|
241
|
+
const tarballName = `xsnap-worker-binaries-${version}.tar.gz`;
|
|
242
|
+
const manifestName = `xsnap-worker-manifest-${version}.json`;
|
|
243
|
+
|
|
244
|
+
const cacheRoot = pathTop.join(
|
|
245
|
+
env.XSNAP_CACHE_DIR || getDefaultCacheRoot(),
|
|
246
|
+
'xsnap',
|
|
247
|
+
'prebuilt',
|
|
248
|
+
version,
|
|
249
|
+
);
|
|
250
|
+
const tarballPath = pathTop.join(cacheRoot, tarballName);
|
|
251
|
+
const manifestPath = pathTop.join(cacheRoot, manifestName);
|
|
252
|
+
const extractRoot = pathTop.join(cacheRoot, 'bundle');
|
|
253
|
+
const expectedManifestHash = getExpectedManifestHash(version, env);
|
|
254
|
+
|
|
255
|
+
const releaseSrc = pathTop.join(
|
|
256
|
+
extractRoot,
|
|
257
|
+
`dist/${target}/release/xsnap-worker`,
|
|
258
|
+
);
|
|
259
|
+
const debugSrc = pathTop.join(
|
|
260
|
+
extractRoot,
|
|
261
|
+
`dist/${target}/debug/xsnap-worker`,
|
|
262
|
+
);
|
|
263
|
+
const expectedArchiveFiles = [
|
|
264
|
+
`dist/${target}/release/xsnap-worker`,
|
|
265
|
+
`dist/${target}/debug/xsnap-worker`,
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
await fsTop.promises.mkdir(cacheRoot, { recursive: true });
|
|
269
|
+
|
|
270
|
+
const releaseDest = asset(
|
|
271
|
+
`../xsnap-native/xsnap/build/bin/${platform}/release/xsnap-worker`,
|
|
272
|
+
);
|
|
273
|
+
const debugDest = asset(
|
|
274
|
+
`../xsnap-native/xsnap/build/bin/${platform}/debug/xsnap-worker`,
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const [manifestAvailable, releaseAvailable, debugAvailable] =
|
|
278
|
+
await Promise.allSettled([
|
|
279
|
+
sha256File(manifestPath),
|
|
280
|
+
sha256File(releaseDest),
|
|
281
|
+
sha256File(debugDest),
|
|
282
|
+
]);
|
|
283
|
+
if (
|
|
284
|
+
manifestAvailable.status === 'fulfilled' &&
|
|
285
|
+
manifestAvailable.value === expectedManifestHash &&
|
|
286
|
+
releaseAvailable.status === 'fulfilled' &&
|
|
287
|
+
debugAvailable.status === 'fulfilled'
|
|
288
|
+
) {
|
|
289
|
+
const { release: releaseExpected, debug: debugExpected } =
|
|
290
|
+
await readExpectedHashes(manifestPath, target);
|
|
291
|
+
if (
|
|
292
|
+
releaseAvailable.value === releaseExpected &&
|
|
293
|
+
debugAvailable.value === debugExpected
|
|
294
|
+
) {
|
|
295
|
+
console.log(
|
|
296
|
+
`Using cached prebuilt xsnap binaries for ${target} (${version})`,
|
|
297
|
+
);
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
await downloadFile(`${base}/${manifestName}`, manifestPath);
|
|
303
|
+
const manifestHash = await sha256File(manifestPath);
|
|
304
|
+
if (manifestHash !== expectedManifestHash) {
|
|
305
|
+
throw Error(`Manifest hash mismatch for xsnap binary version ${version}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
await downloadFile(`${base}/${tarballName}`, tarballPath);
|
|
309
|
+
await validateTarball(tarballPath, expectedArchiveFiles);
|
|
310
|
+
|
|
311
|
+
await fsTop.promises.rm(extractRoot, { recursive: true, force: true });
|
|
312
|
+
await fsTop.promises.mkdir(extractRoot, { recursive: true });
|
|
313
|
+
await run('tar', [
|
|
314
|
+
'-xzf',
|
|
315
|
+
tarballPath,
|
|
316
|
+
'-C',
|
|
317
|
+
extractRoot,
|
|
318
|
+
...expectedArchiveFiles,
|
|
319
|
+
]);
|
|
320
|
+
|
|
321
|
+
const [
|
|
322
|
+
{ release: releaseExpected, debug: debugExpected },
|
|
323
|
+
releaseActual,
|
|
324
|
+
debugActual,
|
|
325
|
+
] = await Promise.all([
|
|
326
|
+
readExpectedHashes(manifestPath, target),
|
|
327
|
+
sha256File(releaseSrc),
|
|
328
|
+
sha256File(debugSrc),
|
|
329
|
+
]);
|
|
330
|
+
|
|
331
|
+
if (releaseExpected !== releaseActual) {
|
|
332
|
+
throw Error(`Release binary hash mismatch for ${target}`);
|
|
333
|
+
}
|
|
334
|
+
if (debugExpected !== debugActual) {
|
|
335
|
+
throw Error(`Debug binary hash mismatch for ${target}`);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
await fsTop.promises.mkdir(pathTop.dirname(releaseDest), { recursive: true });
|
|
339
|
+
await fsTop.promises.mkdir(pathTop.dirname(debugDest), { recursive: true });
|
|
340
|
+
await fsTop.promises.copyFile(releaseSrc, releaseDest);
|
|
341
|
+
await fsTop.promises.copyFile(debugSrc, debugDest);
|
|
342
|
+
await fsTop.promises.chmod(releaseDest, 0o755);
|
|
343
|
+
await fsTop.promises.chmod(debugDest, 0o755);
|
|
344
|
+
|
|
345
|
+
console.log(`Installed prebuilt xsnap binaries for ${target} (${version})`);
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
const isMain =
|
|
349
|
+
process.argv[1] &&
|
|
350
|
+
pathTop.resolve(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
351
|
+
|
|
352
|
+
if (isMain) {
|
|
353
|
+
main().catch(err => {
|
|
354
|
+
console.error('Failed to install prebuilt xsnap binaries');
|
|
355
|
+
console.error(err);
|
|
356
|
+
process.exit(1);
|
|
357
|
+
});
|
|
358
|
+
}
|
package/src/xsnap.js
CHANGED
|
@@ -44,6 +44,46 @@ const { freeze } = Object;
|
|
|
44
44
|
|
|
45
45
|
const noop = freeze(() => {});
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the xsnap worker binary path.
|
|
49
|
+
*
|
|
50
|
+
* `XSNAP_WORKER` may override both modes.
|
|
51
|
+
* `XSNAP_WORKER_DEBUG` overrides debug mode only.
|
|
52
|
+
*
|
|
53
|
+
* @param {{
|
|
54
|
+
* os: string,
|
|
55
|
+
* debug: boolean,
|
|
56
|
+
* env: Record<string, string | undefined>,
|
|
57
|
+
* }} options
|
|
58
|
+
*/
|
|
59
|
+
export function resolveXsnapWorkerPath({ os, debug, env }) {
|
|
60
|
+
const platform = {
|
|
61
|
+
Linux: 'lin',
|
|
62
|
+
Darwin: 'mac',
|
|
63
|
+
// Windows_NT: 'win', // One can dream.
|
|
64
|
+
}[os];
|
|
65
|
+
|
|
66
|
+
if (platform === undefined) {
|
|
67
|
+
throw Error(`xsnap does not support platform ${os}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (debug && env.XSNAP_WORKER_DEBUG) {
|
|
71
|
+
return env.XSNAP_WORKER_DEBUG;
|
|
72
|
+
}
|
|
73
|
+
if (env.XSNAP_WORKER) {
|
|
74
|
+
return env.XSNAP_WORKER;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return fileURLToPath(
|
|
78
|
+
new URL(
|
|
79
|
+
`../xsnap-native/xsnap/build/bin/${platform}/${
|
|
80
|
+
debug ? 'debug' : 'release'
|
|
81
|
+
}/xsnap-worker`,
|
|
82
|
+
import.meta.url,
|
|
83
|
+
),
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
47
87
|
/**
|
|
48
88
|
* @param {Uint8Array} arg
|
|
49
89
|
* @returns {Uint8Array}
|
|
@@ -169,24 +209,7 @@ export async function xsnap(options) {
|
|
|
169
209
|
env = process.env,
|
|
170
210
|
} = options;
|
|
171
211
|
|
|
172
|
-
|
|
173
|
-
Linux: 'lin',
|
|
174
|
-
Darwin: 'mac',
|
|
175
|
-
// Windows_NT: 'win', // One can dream.
|
|
176
|
-
}[os];
|
|
177
|
-
|
|
178
|
-
if (platform === undefined) {
|
|
179
|
-
throw Error(`xsnap does not support platform ${os}`);
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
let bin = fileURLToPath(
|
|
183
|
-
new URL(
|
|
184
|
-
`../xsnap-native/xsnap/build/bin/${platform}/${
|
|
185
|
-
debug ? 'debug' : 'release'
|
|
186
|
-
}/xsnap-worker`,
|
|
187
|
-
import.meta.url,
|
|
188
|
-
),
|
|
189
|
-
);
|
|
212
|
+
let bin = resolveXsnapWorkerPath({ os, debug, env });
|
|
190
213
|
|
|
191
214
|
/** @type {PromiseKit<void>} */
|
|
192
215
|
const vatExit = makePromiseKit();
|
package/build.env
DELETED