9.4 KiB
Checked capability and component artifacts
This is the current helper/output format, not the core package abstraction. See the architecture and current gaps. In particular, the universal artifact inventory and component-only omission of a server are implementation gaps to resolve, not requirements for arbitrary package servers.
mkCaminoArtifacts is the fresh package builder. It regenerates candidate
bindings, typechecks the entry's dependency closure, bundles declared targets,
generates a process service when requested, and emits content manifests and
receipts. It has no migration step or package-defined shell hooks.
# Inside a per-system flake output:
quixosPackages.checkedArtifacts =
{ buildContract, sourceDigest, generator, core, sharedRuntime, typescript, packageRevisionId, ... }:
helpers.mkCaminoArtifacts {
inherit pkgs buildContract sourceDigest core sharedRuntime typescript packageRevisionId;
protocol = generator;
src = ./.;
portable = {
entry = "src/portable.ts";
bindingOutput = "src/gen/qx.ts";
registryExport = "registry";
targets = [ "browser" "server" ];
};
};
buildContract is a canonical, source-free capability slice. sourceDigest
records the exact selected package source in the final installation manifest;
it does not enter the reusable compilation group. Ordinary source dependencies,
SDKs and React props companions remain explicit Nix inputs. Raw QX and resource
lock files enter through the checked contract and evaluated recipe, and are
excluded from the implementation source tree. The plan argument on the low-level
helper is a composition convenience for fixtures; it is projected before building.
Package recipes receive the contract directly and can be checked without a workspace.
Inside checkedArtifacts = context: ..., the package helpers expose
camino.packageSet { inherit nixpkgs system context; } as the usual package set
selection. It shares the workspace composition's evaluated Nixpkgs when the
source content, system, and default import arguments match. Pass ordinary Nixpkgs
arguments such as config or overlays to use a separate import. A direct
import nixpkgs { inherit system; } also works, with additional evaluation cost.
The implementation groups depend on the complete execution compiler bundle and
JavaScript build drivers by content; unrelated checker CLI and publication
metadata changes do not enter those inputs.
The handler entry exports registry = createRegistry(handlers) from the generated
bindings. One registry contains many exports. The builder always supplies a server
implementation for the generated process service. A service-only package instead
omits portable and supplies service.entry, an ordinary JavaScript process entry
using the versioned stdin/stdout protocol. Custom services own their lifecycle and
may hold external resources. This first helper supports JavaScript custom service
entries; other languages can emit the same checked artifact contract independently.
Additional portable source dependencies can be provided as a locked nodeModules directory.
The workspace supplies the exact SDK and compiler; packages cannot replace those
with their own versions. Authored source symlinks and non-bundled portable imports
other than the SDK and server Node builtins are rejected. This is build closure
checking, not a purity proof or security sandbox.
The core/Automerge bundle and Replicache bundle are built once. Browser modules import the core through a content-addressed gateway URL, independent of package identity. Each manifest covers the shared bytes it uses. The gateway retains its workspace authentication and explicit file registry; it never interprets an HTTP path as a Nix store path. Applications cannot import Replicache through the SDK.
checked-artifacts.nix evaluates a package's checkedArtifacts output without
activation. During the checked Nix build, loadCheckedArtifactWorld verifies manifest bytes, the selected
generator identity, and exact regenerated binding sources. Receipts are consistency
evidence from a trusted Nix build, not cryptographic attestations of remote builds.
The build stores the checked plan, kernel/query programs, their digests and original
compiler provenance in its immutable candidate output. Runtime loading validates
that output's identities, artifact contents and supported runtime contracts. It
does not regenerate bindings or programs with the currently running compiler.
Nix owns rebuilding and cache reuse when a toolchain input changes.
The root camino-artifact-builds check exercises actual reader/service outputs,
module and process execution, browser shared imports, rejection recovery, and
altered receipt rejection at the build boundary. The managed workspace host loads
the resulting checked candidate before activation. No adapter pretends this ABI
works in the old server dispatcher.
Component packages add components = { inherit (react) sdk runtime; entries; }.
The ordinary execution candidate checker supplies the selected React build inputs
when the package declares components. Each entry maps a component ID to
{ entry = "src/card.tsx"; export = "Card"; }. See the
React SDK for bindings and hooks. CSS is emitted as a
checked artifact; local image/font imports are inlined. The helper rejects
undeclared external assets and substituted React/client dependencies.
Component-only packages produce no backend service.
camino-component-artifacts checks bad subject/SDK/dependency/asset inputs and
proves that a component-only edit preserves a mixed package's service digest.
Run nix run .#camino-component-source-qualification from the monorepo to
materialize separate retained Git resources and compile an ordinary Nix candidate.
This is a source/build qualification harness; it does not deploy a workspace.
Restricted execution in a workspace VM
Add service.restricted = true to a checked portable package to select the pinned
workerd executor. Generated bindings and the ordinary transaction-port protocol
stay the same. All server exports must belong to one checked portable registry;
remote exports and custom process services retain their ordinary VM execution
path. The restricted build rejects Node imports and unresolved dependencies,
and supplies an explicit SDK for value codecs, identities and declared graph ports.
service = {
restricted = true;
limits = {
deadlineMs = 10000;
maxBytes = 1048576;
maxPortCalls = 1000;
maxQueued = 8;
};
};
Each invocation gets a fresh Worker in a reusable engine process. An engine runs
one active frame; the adapter has bounded concurrency and queueing. Queue wait
consumes the deadline. Overflow is an explicit
RESTRICTED_QUEUE_FULL result. Cancellation kills the engine process group and
removes its sockets before acknowledgement. All graph calls inherit the trusted
invocation identity; authored code cannot choose another frame or workspace.
Native graph grants and transaction commit remain enforced by Camino outside
the guest. Initialization and synchronous loops are subject to the same deadline.
The default root/Package Invocation wall deadline is 10 seconds. The separate root CPU allowance remains at most 4 CPU seconds; extra wall time accommodates queueing and graph-port waits. Ordinary graph database transactions and idle transactions allow 30 seconds, and ordinary client HTTP requests allow 45 seconds so server failures can be returned. Nested calls inherit the remaining root budget; explicit smaller limits still apply. Restore/activation jobs retain their separate budgets. These defaults are starting limits, not latency targets.
Direct network access, native filesystem imports, ambient clock and entropy,
parent environment credentials, and unlisted modules are denied. Explicit dates,
Intl.Segmenter, deterministic hashes and normal JavaScript computation remain
available. Host-managed HTTP bridges expose only the current frame's declared
graph ports. Authored serialization is untrusted protocol input.
The packaged runtime uses the platform's Bubblewrap/seccomp launcher. Only the engine's read-only runtime closure and private broker directory are mounted; native filesystem/process/network escape probes qualify that boundary. Systemd limits the whole package in a workspace VM. Shared authority additionally charges each engine to its own cgroup before launch. No per-isolate memory protection or Cloudflare hosted side-channel defenses are claimed. See the runtime decision for the exact boundary and residual risks. A guest user can control its VM, so authoritative graph grants and credentials must remain outside it.
Qualification commands:
nix build .#checks.x86_64-linux.camino-restricted-execution
nix build .#checks.x86_64-linux.camino-restricted-package-runners
nix build .#checks.x86_64-linux.camino-restricted-execution-vm
The first uses the actual pinned engine for frame isolation, graph ports, SDK codecs, denied ambient access, cancellation and overload. The second runs ordinary package dispatch, rollback, PostgreSQL and browser replica tests with the restricted reader fixture. The VM check adds actual cgroup allocation exhaustion, neighboring-service survival, native socket egress rejection and fresh-frame timing. VM qualification is independent of hosted rollout.