Add registry-backed module package releases
This commit is contained in:
@@ -8,6 +8,9 @@ WEBUI_DIR="${1:-$CORE_ROOT/webui}"
|
||||
WORK_ROOT="$(mktemp -d "${TMPDIR:-/tmp}/govoplan-webui-release-deps.XXXXXXXX")"
|
||||
GOVOPLAN_DEPS="$WORK_ROOT/govoplan-webui-deps.tsv"
|
||||
export GOVOPLAN_DEPS
|
||||
PACKAGE_LOCK="${GOVOPLAN_WEBUI_PACKAGE_LOCK:-}"
|
||||
PACKAGE_DIR="${GOVOPLAN_WEBUI_PACKAGE_DIR:-}"
|
||||
PYTHON_BIN="${PYTHON:-python3}"
|
||||
|
||||
trap 'rm -rf "$WORK_ROOT"' EXIT
|
||||
|
||||
@@ -55,9 +58,69 @@ rm -f package-lock.json
|
||||
npm cache clean --force
|
||||
retry npm install --prefer-online
|
||||
|
||||
if [[ -n "$PACKAGE_LOCK" || -n "$PACKAGE_DIR" ]]; then
|
||||
[[ -n "$PACKAGE_LOCK" && -n "$PACKAGE_DIR" ]] || {
|
||||
echo "GOVOPLAN_WEBUI_PACKAGE_LOCK and GOVOPLAN_WEBUI_PACKAGE_DIR must be set together" >&2
|
||||
exit 1
|
||||
}
|
||||
"$PYTHON_BIN" - "$PACKAGE_LOCK" "$PACKAGE_DIR" "$GOVOPLAN_DEPS" <<'PY'
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
lock_path = Path(sys.argv[1]).resolve()
|
||||
package_dir = Path(sys.argv[2]).resolve()
|
||||
output = Path(sys.argv[3])
|
||||
lock = json.loads(lock_path.read_text(encoding="utf-8"))
|
||||
if lock.get("schema_version") != "1" or not isinstance(lock.get("webui"), list):
|
||||
raise SystemExit("WebUI package lock is malformed")
|
||||
unsigned = dict(lock)
|
||||
expected_lock_hash = unsigned.pop("lock_sha256", None)
|
||||
actual_lock_hash = hashlib.sha256(
|
||||
json.dumps(unsigned, sort_keys=True, separators=(",", ":")).encode("utf-8")
|
||||
).hexdigest()
|
||||
if expected_lock_hash != actual_lock_hash:
|
||||
raise SystemExit("WebUI package lock hash does not match its contents")
|
||||
rows = {}
|
||||
for item in lock["webui"]:
|
||||
if not isinstance(item, dict) or not isinstance(item.get("name"), str):
|
||||
raise SystemExit("WebUI package lock contains a malformed artifact")
|
||||
if item["name"] in rows:
|
||||
raise SystemExit(f"WebUI package lock contains duplicate artifact {item['name']}")
|
||||
rows[item["name"]] = item
|
||||
requested = []
|
||||
for line in output.read_text(encoding="utf-8").splitlines():
|
||||
if not line:
|
||||
continue
|
||||
name, _source_ref = line.split("\t", 1)
|
||||
row = rows.get(name)
|
||||
if not isinstance(row, dict):
|
||||
raise SystemExit(f"WebUI package lock has no artifact for {name}")
|
||||
filename = row.get("filename")
|
||||
if not isinstance(filename, str) or Path(filename).name != filename:
|
||||
raise SystemExit(f"WebUI package lock has an invalid filename for {name}")
|
||||
artifact = package_dir / filename
|
||||
if artifact.is_symlink() or not artifact.is_file():
|
||||
raise SystemExit(f"WebUI package artifact is missing for {name}")
|
||||
encoded = artifact.read_bytes()
|
||||
if len(encoded) != row.get("size") or hashlib.sha256(encoded).hexdigest() != row.get("sha256"):
|
||||
raise SystemExit(f"WebUI package artifact hash does not match for {name}")
|
||||
requested.append(f"{name}\tfile:{artifact}")
|
||||
output.write_text("\n".join(requested) + "\n", encoding="utf-8")
|
||||
PY
|
||||
fi
|
||||
|
||||
module_paths=()
|
||||
while IFS=$'\t' read -r package_name spec; do
|
||||
[[ -n "${package_name:-}" ]] || continue
|
||||
if [[ "$spec" == file:* ]]; then
|
||||
echo "Installing $package_name from verified package artifact"
|
||||
module_paths+=("$spec")
|
||||
continue
|
||||
fi
|
||||
git_url="${spec%%#*}"
|
||||
git_ref="${spec#*#}"
|
||||
if [[ "$git_url" == "$spec" || -z "$git_ref" ]]; then
|
||||
|
||||
Reference in New Issue
Block a user