fix(installer): ship all app build contexts and refresh GitWorkshop dependencies
This commit is contained in:
@@ -16,9 +16,11 @@ lookup relays from the defaults. It does not replace GitWorkshop's NIP-34,
|
||||
GRASP, repository browser, issue, pull-request, or review interfaces.
|
||||
|
||||
The separate dependency patch refreshes the npm lockfile and moves `fflate` to
|
||||
0.8.3, `react-router-dom` to 7.18.3, and Vitest to 5.0.0. The resulting clean
|
||||
install reports zero npm advisories; its type-check, 152 unit tests, and
|
||||
Archipelago subpath production build pass. Keeping this mechanical security
|
||||
0.8.3, `react-router-dom` to 7.18.3, and Vitest to 5.0.0. On 2026-09-30 the lockfile was refreshed again for `brace-expansion`
|
||||
1.1.21/5.0.12, `fast-uri` 3.1.8 and `ip-address` 10.7.2 after fresh node
|
||||
installs failed the retained dependency audit. The resulting clean install
|
||||
reports zero npm advisories; its type-check, 152 unit tests, and Archipelago
|
||||
subpath production build pass. The complete image also builds on the X250. Keeping this mechanical security
|
||||
update separate makes both the upstream integration and future dependency
|
||||
refreshes auditable.
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/package-lock.json b/package-lock.json
|
||||
index 20631bb..0933917 100644
|
||||
index 20631bb..86b6f86 100644
|
||||
--- a/package-lock.json
|
||||
+++ b/package-lock.json
|
||||
@@ -63,7 +63,7 @@
|
||||
@@ -495,9 +495,9 @@ index 20631bb..0933917 100644
|
||||
- "version": "5.0.7",
|
||||
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
|
||||
- "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
|
||||
+ "version": "5.0.9",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
|
||||
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
|
||||
+ "version": "5.0.12",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -678,9 +678,9 @@ index 20631bb..0933917 100644
|
||||
- "version": "1.1.15",
|
||||
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz",
|
||||
- "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==",
|
||||
+ "version": "1.1.18",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz",
|
||||
+ "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==",
|
||||
+ "version": "1.1.21",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz",
|
||||
+ "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -833,9 +833,9 @@ index 20631bb..0933917 100644
|
||||
- "version": "3.1.3",
|
||||
- "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz",
|
||||
- "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==",
|
||||
+ "version": "3.1.7",
|
||||
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.7.tgz",
|
||||
+ "integrity": "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg==",
|
||||
+ "version": "3.1.8",
|
||||
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz",
|
||||
+ "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -859,9 +859,9 @@ index 20631bb..0933917 100644
|
||||
- "version": "5.0.7",
|
||||
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.7.tgz",
|
||||
- "integrity": "sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==",
|
||||
+ "version": "5.0.9",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz",
|
||||
+ "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==",
|
||||
+ "version": "5.0.12",
|
||||
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz",
|
||||
+ "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -893,9 +893,9 @@ index 20631bb..0933917 100644
|
||||
- "version": "10.2.0",
|
||||
- "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz",
|
||||
- "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==",
|
||||
+ "version": "10.7.0",
|
||||
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz",
|
||||
+ "integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==",
|
||||
+ "version": "10.7.2",
|
||||
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz",
|
||||
+ "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
@@ -1445,4 +1445,3 @@ index bd7190c..6aa5a6f 100644
|
||||
import { vi } from "vitest";
|
||||
|
||||
// Mock window.matchMedia
|
||||
|
||||
|
||||
@@ -2607,21 +2607,14 @@ if [ -f "$SCRIPT_DIR/../../scripts/image-versions.sh" ]; then
|
||||
echo " ✅ Bundled image-versions.sh"
|
||||
fi
|
||||
|
||||
# Bundle docker UI source files for building custom UIs on first boot
|
||||
# Always bundle — these are tiny HTML/CSS files, not container images
|
||||
if true; then
|
||||
DOCKER_UI_DIR="$SCRIPT_DIR/../../docker"
|
||||
if [ -d "$DOCKER_UI_DIR" ]; then
|
||||
echo " Bundling docker UI source files..."
|
||||
mkdir -p "$ARCH_DIR/docker"
|
||||
for ui_dir in bitcoin-ui lnd-ui electrs-ui; do
|
||||
if [ -d "$DOCKER_UI_DIR/$ui_dir" ]; then
|
||||
cp -r "$DOCKER_UI_DIR/$ui_dir" "$ARCH_DIR/docker/"
|
||||
echo " ✅ Bundled $ui_dir source"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
# Build-source apps need their complete contexts even on unbundled ISOs.
|
||||
# Keep this identical to the OTA runtime payload; a per-app allowlist silently
|
||||
# omitted GitWorkshop, FIPS and Cuprate and made fresh installs fail at 70%.
|
||||
DOCKER_UI_DIR="$SCRIPT_DIR/../../docker"
|
||||
[ -d "$DOCKER_UI_DIR" ] || { echo "Missing docker build sources" >&2; exit 1; }
|
||||
mkdir -p "$ARCH_DIR/docker"
|
||||
cp -a "$DOCKER_UI_DIR/." "$ARCH_DIR/docker/"
|
||||
python3 "$SCRIPT_DIR/../../scripts/check-app-build-contexts.py" "$ARCH_DIR"
|
||||
|
||||
if [ "$UNBUNDLED" = "1" ]; then
|
||||
echo " ✅ Unbundled build ready (Tor setup included, no container images)"
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate build-source apps against an OTA/ISO runtime payload before shipping."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
|
||||
|
||||
def check(root: Path) -> int:
|
||||
root = root.resolve()
|
||||
manifests = sorted((root / 'apps').glob('*/manifest.y*ml'))
|
||||
if not manifests:
|
||||
raise ValueError(f'No app manifests in {root / "apps"}')
|
||||
count = 0
|
||||
for manifest in manifests:
|
||||
app = yaml.safe_load(manifest.read_text())['app']
|
||||
build = app.get('container', {}).get('build')
|
||||
if not build:
|
||||
continue
|
||||
context = Path(build['context'])
|
||||
if context.is_absolute():
|
||||
context = root / context.relative_to('/opt/archipelago')
|
||||
else:
|
||||
context = manifest.parent / context
|
||||
context = context.resolve()
|
||||
if not context.is_relative_to(root) or not context.is_dir():
|
||||
raise ValueError(f'{app["id"]}: missing or out-of-payload build context: {context}')
|
||||
dockerfile = (context / build.get('dockerfile', 'Dockerfile')).resolve()
|
||||
if not dockerfile.is_relative_to(context) or not dockerfile.is_file():
|
||||
raise ValueError(f'{app["id"]}: missing or out-of-context Dockerfile: {dockerfile}')
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
count = check(Path(sys.argv[1] if len(sys.argv) > 1 else '.'))
|
||||
except (ValueError, KeyError, OSError, yaml.YAMLError) as error:
|
||||
sys.exit(f'Invalid app build payload: {error}')
|
||||
print(f'Validated {count} app build contexts and Dockerfiles.')
|
||||
@@ -101,6 +101,7 @@ if [ -z "$FRONTEND_ARCHIVE" ]; then
|
||||
cp -r "$PROJECT_ROOT/$runtime_path" "$RUNTIME_DIR/$runtime_path"
|
||||
fi
|
||||
done
|
||||
python3 "$PROJECT_ROOT/scripts/check-app-build-contexts.py" "$RUNTIME_DIR"
|
||||
# KEEP IN SYNC with the `for unit in [...]` array in
|
||||
# core/archipelago/src/bootstrap.rs (run_runtime_assets). A unit that
|
||||
# bootstrap installs but this list does not ship simply never reaches a
|
||||
|
||||
@@ -64,6 +64,13 @@ for f in live/vmlinuz live/initrd.img live/filesystem.squashfs \
|
||||
fi
|
||||
done
|
||||
|
||||
# Verify the mounted artifact carries every manifest-declared build source.
|
||||
if python3 "$REPO/scripts/check-app-build-contexts.py" "$MNT/archipelago"; then
|
||||
ok "app build contexts and Dockerfiles"
|
||||
else
|
||||
bad "incomplete app build payload"
|
||||
fi
|
||||
|
||||
# ── GRUB must boot the live system ───────────────────────────────────
|
||||
if grep -q "boot=live" "$MNT/boot/grub/grub.cfg" 2>/dev/null; then
|
||||
ok "grub.cfg has boot=live"
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Exercise release payload checks with complete, incomplete and escaping contexts."""
|
||||
import importlib.util
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
REPO = Path(__file__).resolve().parents[2]
|
||||
spec = importlib.util.spec_from_file_location('contexts', REPO / 'scripts/check-app-build-contexts.py')
|
||||
contexts = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(contexts)
|
||||
|
||||
|
||||
class BuildPayloadTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.temp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.temp.cleanup)
|
||||
self.root = Path(self.temp.name)
|
||||
shutil.copytree(REPO / 'apps', self.root / 'apps')
|
||||
shutil.copytree(REPO / 'docker', self.root / 'docker')
|
||||
|
||||
def test_complete_payload(self):
|
||||
self.assertGreaterEqual(contexts.check(self.root), 6)
|
||||
|
||||
def test_iso_old_allowlist_rejected(self):
|
||||
shutil.rmtree(self.root / 'docker/archipelago-source')
|
||||
with self.assertRaisesRegex(ValueError, 'archipelago-source.*missing'):
|
||||
contexts.check(self.root)
|
||||
|
||||
def test_missing_dockerfile_rejected(self):
|
||||
(self.root / 'docker/archipelago-source/Dockerfile').unlink()
|
||||
with self.assertRaisesRegex(ValueError, 'archipelago-source.*Dockerfile'):
|
||||
contexts.check(self.root)
|
||||
|
||||
def test_context_symlink_cannot_escape_payload(self):
|
||||
target = self.root / 'docker/archipelago-source'
|
||||
shutil.rmtree(target)
|
||||
target.symlink_to(REPO / 'docker/archipelago-source', target_is_directory=True)
|
||||
with self.assertRaisesRegex(ValueError, 'out-of-payload'):
|
||||
contexts.check(self.root)
|
||||
|
||||
def test_empty_payload_rejected(self):
|
||||
shutil.rmtree(self.root / 'apps')
|
||||
with self.assertRaisesRegex(ValueError, 'No app manifests'):
|
||||
contexts.check(self.root)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -71,6 +71,7 @@ summary() {
|
||||
# ── Stage 1: static ──────────────────────────────────────────────────
|
||||
stage "git-diff-check" git diff --check
|
||||
stage "cargo-fmt" timeout 240 cargo fmt --manifest-path core/Cargo.toml --all --check
|
||||
stage "app-build-contexts" python3 tests/regression/app-build-contexts.py
|
||||
stage "manifest-shell" python3 scripts/check-manifest-shell.py
|
||||
stage "doctor-ports" bash tests/regression/container-doctor-ports.sh
|
||||
stage "bitcoin-pruning" python3 tests/regression/bitcoin-prune-entrypoint.py
|
||||
|
||||
Reference in New Issue
Block a user