feat: native linux-x64-glibc module packages and reviewed license supplements (ADR 0049, ADR 0052)
CI / verify (pull_request) Successful in 1m6s
CI / infrastructure-smoke (pull_request) Successful in 27s
CI / migration-smoke (pull_request) Successful in 1m54s
CI / image-build (pull_request) Successful in 29s
CI / deploy-smoke (same-origin) (pull_request) Successful in 43s
CI / deploy-smoke (split) (pull_request) Successful in 1m30s

Implements ADR 0049's deferred native target and ADR 0052's reviewed
license supplements. The proof case is a real module using sharp.
packageFormat stays 1, and `any` is unchanged.

Packager (@ekklesia/module-pack):
- --target linux-x64-glibc. Native or platform-specific packages, found by
  the same generic rule that refuses them in `any`, stay outside the bundle.
- Each native package's production closure is walked through its own
  dependencies, installed optionalDependencies that match the target, and
  required peers. It is copied as real files flat under node_modules/<name>,
  with no links, dev dependencies, declarations, source maps, or other
  platforms' packages. Missing or foreign-platform required dependencies,
  version conflicts, links, foreign machines, and Node.js range conflicts
  fail closed.
- runtime.nodeApi, nodeAbi, and libcVersion are read from the binaries by a
  small ELF reader: the addon's node_api_module_get_api_version_v1 and the
  newest GLIBC_ symbol version needed. No shelling out. A native target with
  no addon is refused.
- ADR 0052 supplements: package-provided material stays primary. An exact
  match on name, version, and ekklesia-content-v1 digest (sorted normalized
  paths with each file's size and SHA-256; no metadata) adds labelled
  material after the package's own. Any mismatch, a declared-licence
  conflict, or a malformed or unreviewed supplement file fails. Missing
  material with no supplement still fails.

Supplement for @img/[email protected]:
- 184 components and 143 unique texts, assembled from the exact upstream
  sources sharp-libvips v1.3.3 builds linux-x64 from: 27 C/C++ libraries,
  glib's gvdb, librsvg's Rust crates (reproduced with cargo tree), the Rust
  standard library at the rustc commit recorded in the binary, plus the
  LGPL-3.0, GPL-3.0, and MPL-2.0 texts. Each source is recorded with its
  SHA-256 in PROVENANCE.md.
- It pins digest ekklesia-content-v1:sha256:50647b0b…, which is identical
  from the installed copy and from the registry tarball.
- LGPL/MPL source-availability determinations stay open, as ADR 0052
  states. Nothing claims they are met.

Verifier (Core):
- linux-x64-glibc is accepted only on a host whose platform, arch, glibc
  family and version, and Node-API version (from Node itself) match.
- Every ELF file must be x86-64; every .node must be an ELF object.
- `any` packages now also refuse node_modules/ and ELF files.
- Contract: native metadata must state nodeApi or nodeAbi, and Linux targets
  libcVersion (ADR 0049).

Proof:
- A checked-in AGPL native fixture packs byte-identically from unrelated
  copies (8.86 MB) and verifies with Core's verifier.
- Extracted elsewhere, it runs a sharp resize and PNG round trip in an
  empty-environment process. Every resolution stays in the package, and
  only the package's addon and libvips plus host system libraries load.

Signage is untouched.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
ekklesia
2026-10-07 20:16:53 -05:00
co-authored by Claude Opus 5.5
parent f53506b3f0
commit 44d385cd7f
173 changed files with 20638 additions and 53 deletions
@@ -0,0 +1,19 @@
{
"manifestVersion": 8,
"id": "native-proof",
"name": "Native proof",
"description": "A minimal native module: its backend uses sharp, so it packages for linux-x64-glibc.",
"version": "0.1.0",
"compatibility": {
"platform": "^0.1.0",
"moduleSdk": "^0.1.0"
},
"database": {
"abi": 1
},
"capabilities": [],
"permissions": [],
"entrypoints": {
"server": "./server/index.js"
}
}
@@ -0,0 +1,12 @@
{
"name": "@ekklesia-fixtures/native-proof",
"version": "0.1.0",
"description": "The packager's native-target proof module. Not a workspace package: its tests link sharp and the Module SDK in.",
"license": "AGPL-3.0-or-later",
"private": true,
"type": "module",
"dependencies": {
"@ekklesia/module-sdk": "workspace:*",
"sharp": "0.35.4"
}
}
@@ -0,0 +1,37 @@
// The packager's native-target proof module (ADR 0049). Its backend uses sharp, a native dependency,
// so it packages only for a native target. It is plain JavaScript and needs no build step.
import { defineModuleRuntime } from "@ekklesia/module-sdk";
import sharp from "sharp";
/** A deterministic image operation: a 4×4 solid red image resized to 2×2, returned as raw pixels,
* and the same image encoded as PNG and decoded again. */
export async function proof() {
const resized = await sharp({
create: { background: { b: 0, g: 0, r: 255 }, channels: 3, height: 4, width: 4 },
})
.resize(2, 2)
.raw()
.toBuffer({ resolveWithObject: true });
const png = await sharp({
create: { background: { b: 255, g: 0, r: 0 }, channels: 3, height: 3, width: 5 },
})
.png()
.toBuffer();
const decoded = await sharp(png).metadata();
return {
pixels: [...resized.data],
png: { format: decoded.format, height: decoded.height, width: decoded.width },
resized: {
channels: resized.info.channels,
height: resized.info.height,
width: resized.info.width,
},
};
}
export default defineModuleRuntime({
database: { abi: 1 },
id: "native-proof",
version: "0.1.0",
register() {},
});