fix: support native package verifier scratch
CI / verify (pull_request) Successful in 1m10s
CI / infrastructure-smoke (pull_request) Successful in 37s
CI / migration-smoke (pull_request) Successful in 1m54s
CI / package-release (pull_request) Successful in 36s
CI / image-build (pull_request) Successful in 52s
CI / deploy-smoke (same-origin) (pull_request) Successful in 51s
CI / deploy-smoke (split) (pull_request) Successful in 1m31s
CI / package-publication (pull_request) Successful in 51s

This commit is contained in:
ekklesia
2026-10-09 18:05:04 -05:00
parent c5a6cdaf6a
commit 4be046c8d0
12 changed files with 330 additions and 13 deletions
+4 -1
View File
@@ -701,7 +701,10 @@ Module Package v1, a deterministic `.tar.gz` with its SHA-256.
- **The verifier.** Core's `verifyModulePackage` reads the archive in memory and refuses links,
special files, and escaping paths. It checks every digest and identity, the target and runtime,
runs the platform's own module, schema, and migration validation, and loads the backend once in a
short-lived process with an empty environment. Only then does it extract anything.
short-lived process with an empty environment. Only then does it copy the package to a requested
output directory. In the hardened container invocation, `/tmp` remains `noexec`; the temporary
candidate lives on a dedicated, bounded executable tmpfs because a native addon's code must be
mapped executable to load.
- **A native package's host checks.** It is accepted only on a host whose operating system, CPU,
C library family and version, and Node-API version Node.js itself reports as compatible.
- **ELF files.** Every ELF file in it must be built for the target's machine.
+7 -1
View File
@@ -484,7 +484,13 @@ before it is installed: its digest, its archive safety (no links, special files,
escaping paths), every file's digest, and its identity and compatibility. The digest proves
integrity, not who published the package; signing is not implemented. The verifier loads the backend
in a short-lived process with an empty environment, so module code never sees a database URL or a
secret while it is being checked.
secret while it is being checked. That load executes package code: `noexec` is retained on the
general `/tmp`, but native packages require the verifier's narrow, bounded execution scratch to be
executable. The one-shot hardened verifier container—not the scratch mount—is the isolation
boundary, and it is not claimed to be a perfect sandbox. Use the supported invocation in
[`deploy/README.md`](../../deploy/README.md#installed-modules), which also keeps the root filesystem
read-only, runs as the image's non-root user, disables networking and privilege escalation, and
drops Linux capabilities.
Two production defaults are relevant but are **not** by themselves a deployment guarantee:
+4 -1
View File
@@ -318,7 +318,10 @@ require exact agreement with Core. The legacy facade has not been removed.
`node core/dist/cli/verify-module-package.js <archive> --sha256-file <archive>.sha256`, run from an
Ekklesia installation (`/opt/ekklesia` in the image), checks a package against that platform without
installing it. Pass `--extract-to <new directory>` to receive the verified module directory.
[deploy/README.md](../../deploy/README.md#installed-modules) shows the whole installation.
[deploy/README.md](../../deploy/README.md#installed-modules) shows the supported hardened container
invocation; use it rather than inventing mount flags. Backend verification executes package code.
Its container is therefore the isolation boundary: general `/tmp` remains `noexec`, while a narrow,
bounded, ephemeral verifier scratch tmpfs permits execution so native addons can load.
The repository's boundary checks (`pnpm boundaries`) prove only source modules in a workspace. An
installed package normally has no source, so the platform cannot check it the same way. Your