updates
ober
2ad4299b390f1fcb2bfcf452873bb5840035d641
--- a/data/features.sexp +++ b/data/features.sexp @@ -905,4 +905,60 @@ ("use_case" . "Reviewing a workspace containing many related Jerboa and Chez repositories without manually running inventory, rg exclusions, and per-repo MCP scans.") + ("votes" . 0)) + (("description" + . + "jerboa_verify can fail with an internal string-ref exception on large or malformed files and include a huge source dump instead of a filename, line, column, and nearest form. It should catch verifier/parser internal exceptions, trim source excerpts, and return structured diagnostics with location and phase.") + ("estimated_token_reduction" + . + "~10000 tokens per failed verification") + ("example_scenario" + . + "Verifying src/std/nrepl.ss and src/jerboa-yaml.ss returned a string-ref out-of-range exception plus the entire file contents, making it hard to distinguish verifier bugs from real source errors.") + ("id" . "verify-actionable-syntax-errors") + ("impact" . "high") + ("tags" "verify" "syntax" "diagnostics" "tooling" "parser") + ("title" + . + "Make jerboa_verify report actionable parse errors") + ("use_case" + . + "Reviewing modified Jerboa source files before deciding whether changes are healthy.") + ("votes" . 0)) + (("description" + . + "Add a tool that scans a Jerboa workspace containing many jerboa*/chez* repos and reports branch, origin, last commit, dirty tracked files, untracked artifacts, stale generated lib files, available make targets, and known health findings in one compact table.") + ("estimated_token_reduction" + . + "~3000 tokens per workspace review") + ("example_scenario" + . + "Reviewing ~/mine/jerboa* and ~/mine/chez* required several shell loops to separate clean repos, source edits, generated build artifacts, and non-git planning directories.") + ("id" . "workspace-repo-status-summary") + ("impact" . "medium") + ("tags" "workspace" "git" "status" "jerbuild" "multi-repo") + ("title" . "Summarize Jerboa workspace repo status") + ("use_case" + . + "Strategic reviews of the Jerboa stack across sibling repositories.") + ("votes" . 0)) + (("description" + . + "Improve jerboa_security_scan so it distinguishes Chez/Jerboa idioms from generic vulnerability patterns: call-with-output-file with an explicit 'replace policy, bytevector u8* FFI calls versus foreign-alloc pointers, intentional REPL/eval handlers behind auth gates, and Scheme do-loop bounds that are already nonnegative by construction.") + ("estimated_token_reduction" + . + "~1500 tokens per scanned file with noisy findings") + ("example_scenario" + . + "Scanning src/std/nrepl.ss and src/jerboa-yaml.ss reported call-with-output-file overwrite and do-loop issues that were either already using 'replace or guarded by fx> checks, while the truly useful signal was the nREPL eval surface and FFI/import health.") + ("id" . "security-scan-context-aware-scheme") + ("impact" . "medium") + ("tags" "security-scan" "false-positive" "scheme" "ffi" + "diagnostics") + ("title" + . + "Reduce context-insensitive Scheme security scan false positives") + ("use_case" + . + "Security reviewing Jerboa source without spending most of the time triaging scanner noise.") ("votes" . 0))) --- a/docs/index.md +++ b/docs/index.md @@ -60,6 +60,7 @@ New here? Start with [quickstart.md](quickstart.md), then [tutorial.md](tutorial ## Security & Hardening +- [unification.md](unification.md) - security-first guide for unifying the Jerboa ecosystem into a full stack - [security-reference.md](security-reference.md) — consolidated reference for all security modules; includes the patterns / threat-model checklist - [safety-guide.md](safety-guide.md) — practical guide to writing secure Jerboa applications - [capability.md](capability.md) — object-capability model library new file mode 100644 --- /dev/null +++ b/docs/unification.md @@ -0,0 +1,910 @@ +# Jerboa Unification Guide + +Living document - last revised 2026-05-28. Concrete, security first, no stubs. + +This guide explains how to grow Jerboa from a set of related repositories and +libraries into a coherent full stack for secure software. It is the operating +plan beneath [Philosophy.md](Philosophy.md): the philosophy says why the stack +exists; this document says how to unify the pieces without losing the security +properties that make the stack worth building. + +The goal is not to clone npm, Node, POSIX shell, C libraries, Emacs Lisp, or a +typical cloud platform in Scheme syntax. The goal is a full system where one +common language, one build model, one authority model, and one provenance model +cover the normal path from local development to production deployment. + +--- + +## North Star + +Build a full software stack where the common case can be written in Jerboa +source files, built by Jerboa tooling, packaged with verified provenance, +run with explicit authority, audited through structured events, and deployed as +hardened artifacts. + +The stack should make the secure path the easiest path: + +- Application code is Jerboa `.ss`, not ad hoc shell, generated `.sls`, or + unreviewed glue. +- Effects are explicit capabilities, not ambient process power. +- Third-party code is minimized, signed, locked, and sandboxed. +- Native code is small, audited, and treated as part of the trusted base. +- Hostile input goes through bounded parsers, fuzzed surfaces, and structured + data APIs. +- AI-generated code runs inside authority and resource boundaries by default. + +If a subsystem cannot state its authority, provenance, TCB impact, and failure +mode, it is not ready to be a default part of the stack. + +--- + +## The Unification Claim + +Jerboa becomes a full stack by making every layer obey the same contract: + +1. **One language boundary.** User-facing code is `.ss`; generated `.sls` is an + internal build artifact. +2. **One authority boundary.** Filesystem, network, process, environment, + secrets, eval, devices, and signing are all capabilities. +3. **One build boundary.** `jerbuild` is the normal compiler, packager, + artifact generator, and source-of-truth checker. +4. **One provenance boundary.** Packages and build outputs are content-addressed, + locked, reproducible, and signed. +5. **One native boundary.** Rust is the preferred native core; C is an audited + shim of last resort; handwritten FFI is minimized and ideally generated. +6. **One data boundary.** Tools exchange structured records, bytevectors, typed + values, and events, not parseable terminal text. +7. **One operations boundary.** Running systems emit security-relevant audit + events and health metrics in a common format. + +This is the difference between "many Scheme projects" and a secure system. + +--- + +## What We Are Unifying + +The current ecosystem naturally falls into layers. Keep those layers explicit. + +| Layer | Role | Examples | +|-------|------|----------| +| Language and stdlib | Core language, reader, macros, data, concurrency, security modules | `jerboa`, `lib/std/*` | +| Build and packaging | Transpile, binary build, lock files, reproducible artifacts, package metadata | `jerbuild`, `docs/packages.md` | +| Native core | Fast parsers, crypto, compression, regex, OS integration | `jerboa-native-rs`, selected `chez-*` shims | +| Data and services | HTTP edge, databases, DNS, cloud clients, actors, RPC | `jerboa-edge`, `jerboa-db`, `jerboa-dns`, `jerboa-aws` | +| Developer surface | Shell, editor, browser, code agent, LSP, syntax tooling | `jerboa-shell`, `jerboa-emacs`, `jerboa-browser`, `jerboa-code`, `jerboa-ts-mode` | +| Security tooling | Signing, PGP, secret handling, malware/intel scanning, packet analysis, repo safety | `jerboa-yubikey`, `jerboa-pgp`, `jerboa-virus`, `jerboa-secmon`, `jerboa-wafter`, `jerboa-gitsafe` | +| Language tooling | YAML, awk/sed replacements, parsers, static analysis, search | `jerboa-yaml`, `jerboa-awk`, `jerboa-sed`, `jerboa-treesitter`, `jerboa-semgrep` | + +Unification does not mean merging every repository into one tree. It means every +repository follows the same contract and can be composed without reintroducing +ambient authority, text glue, or untracked provenance. + +--- + +## Security Invariants + +These invariants are non-negotiable. New code can be incomplete, but it must not +pretend to satisfy these if it does not. + +### 1. Ambient authority is never the default + +No package, plugin, build step, test, code agent, editor extension, shell +script, or server handler should inherit the host process's full filesystem, +network, process, environment, secret, or signing authority. + +The default shape is: + +```scheme +(def root (make-root-capability)) +(def app-fs (attenuate-fs root read-only: #t paths: '("/srv/app/config/"))) +(def app-net (attenuate-net root allow: '("api.example.com") deny-all-others: #t)) +``` + +Exact APIs may differ by module while the capability system is unified. The +important property is stable: authority is passed, attenuated, checked, and +revoked. It is not discovered from ambient process state. + +### 2. Install never executes package code + +Package installation must not run arbitrary package code. Build behavior is +declarative and sandboxed. A package may declare how it builds; it may not get a +shell escape hatch during install. + +Allowed: + +```scheme +(build + (entry "src/main.ss") + (outputs ("bin/my-tool")) + (requires ("cc" "rust"))) +``` + +Rejected: + +```scheme +(postinstall "curl https://example.com/install.sh | sh") +``` + +### 3. Provenance is a runtime dependency, not a release nicety + +Every artifact that crosses a trust boundary should have: + +- content hash +- source revision +- dependency lock +- build recipe hash +- builder identity +- signature +- TCB summary + +YubiKey-backed signing should become the normal root for high-trust releases. + +### 4. FFI is the unsafe block + +Pure Jerboa code is memory safe. The FFI boundary is where memory unsafety, +calling convention bugs, lifetime bugs, and parser bugs enter the system. + +Rules: + +- Prefer pure Jerboa when throughput allows. +- Prefer pure Rust crates for hostile byte parsing and crypto. +- Use wasm isolation for dangerous parsers when throughput permits. +- Keep C shims tiny and boring. +- Generate FFI bindings and ownership wrappers where practical. +- Every native handle has explicit ownership and close/free behavior. +- Every raw pointer crossing has a size, lifetime, and nullability contract. + +### 5. Structured data beats text composition + +Jerboa tools should pass records, lists, maps, bytevectors, events, and protocol +objects. They should not parse `ls`, `ps`, `git`, or shell output unless they +are specifically compatibility tools. + +This is how the stack avoids the normal shell/Node failure mode: stringly typed +composition, quoting bugs, accidental eval, and command injection. + +### 6. Secrets are capabilities, not strings + +API keys, signing keys, SSH agent access, PGP keys, YubiKey sessions, and local +model tokens are signing or access oracles. Access to the oracle is authority. + +The system should prefer: + +- encrypted local stores +- hardware-backed keys +- scoped unlocks +- per-command grants +- non-exportable signing APIs +- audit events for secret use + +It should reject: + +- secrets in command-line arguments +- broad ambient env access +- globally discoverable agent sockets +- editor extensions inheriting secret reach + +### 7. AI code is untrusted code + +AI-generated code is useful, but it should never be special-cased as trusted. +The right default is: + +- generated code runs with explicit capabilities +- agents receive a workspace view, not the user's whole machine +- build and test commands run in scoped sandboxes +- network access is denied unless granted +- local credentials are unavailable unless granted +- security scans and fuzzing run before promotion + +--- + +## The System Contract + +This section is a proposed contract. It is not all implemented today. It is the +shape new work should converge on. + +Every package, app, tool, and service should be describable by one manifest. +The existing package manager document covers semver, dependency resolution, and +lock files. The unification step is adding authority, provenance, and build +contracts to that model. + +Example shape: + +```scheme +(system + (name secure-notes) + (version "0.1.0") + (kind app) + (language jerboa) + + (source + (entry "src/main.ss") + (generated "lib/") + (tests "tests/")) + + (dependencies + (jerboa-db "^0.1.0" registry) + (jerboa-yaml "^0.1.0" registry)) + + (capabilities + (filesystem + (read "/srv/secure-notes/config/") + (write "/srv/secure-notes/data/") + (deny "/home" "/etc" "/tmp")) + (network + (listen "127.0.0.1" 8080) + (connect "api.example.com" 443)) + (environment + (read "JERBOA_ENV") + (deny "*")) + (process + (spawn none)) + (secrets + (read "secure-notes/db-key"))) + + (build + (mode static-binary) + (reproducible #t) + (native rust-only) + (install-code none)) + + (provenance + (content-addressed #t) + (lock-file "jerboa.lock") + (signing yubikey) + (sbom #t))) +``` + +The manifest should be readable by humans, tooling, CI, package resolution, +security scans, editors, and code agents. + +--- + +## Full Stack Reference Architecture + +A secure Jerboa application should look like this: + +```text +request + | + v +edge listener + | + +-- parse bounded protocol input + +-- authenticate and rate-limit + +-- taint external data + | + v +handler + | + +-- validate typed request + +-- use attenuated capabilities + +-- call structured services, not shell commands + | + v +domain logic + | + +-- pure functions where possible + +-- STM/actors/fibers for concurrency + +-- explicit effects at boundaries + | + v +storage / external APIs / jobs + | + +-- parameterized DB calls + +-- network allowlists + +-- sandboxed background work + +-- audit events + | + v +response +``` + +Recommended layers: + +| Layer | Responsibility | Security requirement | +|-------|----------------|----------------------| +| Entry | Parse config, create root authority, derive app caps | Root cap never leaks | +| Edge | HTTP/TLS/WebSocket/RPC boundary | Bounded parser, auth, rate limit, request taint | +| Router | Map request to handler | No dynamic eval, no string-dispatch surprises | +| Handler | Application workflow | Only receives required caps | +| Domain | Pure business logic | No I/O imports by default | +| Data | DB, files, cache, queues | Parameterized APIs, cap checks, audit | +| Jobs | Background work and AI tools | Sandbox, timeout, memory limits, output limits | +| Native | Rust/C/wasm boundary | Ownership contracts, fuzzing, TCB entry | +| Build | Artifact production | Reproducible, signed, locked | +| Ops | Runtime monitoring | Audit chain, metrics, crash reports | + +--- + +## Repository Policy + +Every `jerboa-*` and `chez-*` repository should converge on these rules. + +### Source layout + +```text +repo/ + README.md + AGENTS.md + Makefile + src/ + project-name.ss + lib/ + project-name.sls # generated; ignored or regenerated deterministically + tests/ + test.ss + docs/ + optional.md + native/ + optional-rust-or-c/ + .jerboa-system # proposed manifest +``` + +Rules: + +- Human-authored Jerboa code lives in `src/*.ss`. +- Generated `.sls`, `.wpo`, `.so`, `.dylib`, `.o`, boot files, and binary + outputs are either ignored or deliberately tracked with a clear reason. +- `make build`, `make test`, `make clean`, and any release target behave + consistently. +- Builds do not mutate sibling repos. +- Cross-builds use vendored or copied dependencies, not `git checkout --` in + another working tree. +- Repo health is checkable without tribal knowledge. + +### Definition of done for a subsystem + +A subsystem is unified enough to depend on when it has: + +- `.ss` source as the maintained form +- a deterministic `jerbuild` path +- a test target that works from a clean checkout +- documented capabilities +- a package/system manifest +- a security note describing hostile inputs and trusted base +- fuzz tests for parsers or binary protocols +- no raw shell construction for untrusted paths or arguments +- no broad `(chezscheme)` or FFI exposure outside low-level layers +- a clean generated-artifact policy +- reproducible build metadata +- signed release artifacts for distribution + +--- + +## Package and Registry Roadmap + +The package manager should grow in this order. + +### Phase 1: Local manifest discipline + +Add package/system metadata to every repo: + +- name +- version +- source entries +- dependencies +- build outputs +- test command +- generated artifact policy +- capability declaration +- native code declaration + +Acceptance check: a workspace scanner can summarize every repo without custom +logic. + +### Phase 2: Lock files and content addressing + +Extend lock files to include: + +- package name and version +- source hash +- resolved dependency hashes +- build recipe hash +- native dependency hashes +- generated artifact hashes + +Acceptance check: a clean build can prove whether a local artifact matches its +declared source and recipe. + +### Phase 3: No-install-code enforcement + +Package install resolves, verifies, and unpacks. It does not execute package +code. Build execution, when needed, happens under the declared build sandbox. + +Acceptance check: a malicious package cannot run arbitrary code merely because +it was added as a dependency. + +### Phase 4: Signing and namespace trust + +Introduce signed package indexes and artifacts: + +- hardware-backed signing for high-trust packages +- namespace ownership +- revocation metadata +- reproducible build attestations +- transparent logs for published artifacts + +Acceptance check: package resolution rejects unsigned or incorrectly signed +artifacts by default. + +### Phase 5: Capability-aware dependency resolution + +Dependency resolution should expose authority cost: + +- this dependency needs filesystem read +- this dependency wants network connect +- this dependency includes native code +- this dependency spawns processes +- this dependency requests secrets + +Acceptance check: adding a dependency that broadens authority is visible in the +diff and can be denied by policy. + +--- + +## Capability Unification + +The stack needs one mental model for authority even if multiple modules +currently expose related APIs. + +Required domains: + +| Domain | Examples | Default | +|--------|----------|---------| +| Filesystem | read, write, execute, temp dirs, embeds | deny | +| Network | listen, connect, DNS, raw sockets | deny | +| Process | spawn, signal, ptrace, shell | deny | +| Environment | read vars, write vars | deny | +| Secrets | decrypt, sign, token read, hardware key access | deny | +| Eval | module allowlists, timeouts, memory/output caps | deny | +| Native | load shared object, FFI call, device access | deny | +| Package | install, build, publish, sign | deny | + +Patterns: + +- Create broad authority only at process start. +- Immediately attenuate to subsystem-specific capabilities. +- Pass caps through constructors, not global parameters, where practical. +- Use scoped parameters only for ergonomic boundaries that cannot be passed + explicitly. +- Record authority grants in audit logs. +- Treat capability leakage as a bug even when the leaked cap is valid. + +Example handler shape: + +```scheme +(defstruct app-context + (config-cap data-cap api-cap audit-cap secret-cap)) + +(def (handle-save-note ctx req) + (let* ([note (validate-note req)] + [data-cap (app-context-data-cap ctx)] + [audit-cap (app-context-audit-cap ctx)]) + (audit-log! audit-cap 'note/save-started note.id) + (cap-file-write data-cap (note-path note.id) (serialize-note note)) + (audit-log! audit-cap 'note/save-completed note.id) + (ok note.id))) +``` + +The point is not this exact API. The point is that the handler cannot write +outside `data-cap`, cannot phone home unless given a net cap, and cannot read +secrets unless given a secret cap. + +--- + +## Native Boundary Roadmap + +The native layer should converge on one of three patterns. + +### Pattern A: Pure Jerboa + +Use when: + +- the input format is simple enough +- throughput is acceptable +- correctness and auditability matter more than peak speed + +Examples: many text formats, protocol framing, config formats, glue logic. + +### Pattern B: Rust native core + +Use when: + +- parsing hostile bytes at high speed +- crypto, compression, regex, TLS, or hash-heavy workloads +- mature pure-Rust crates exist + +Requirements: + +- no hidden bundled C or C++ without review +- panic containment +- explicit error channel +- bytevector length passed with pointer +- fuzz harnesses at the Rust and Jerboa boundary +- ownership wrapper in Jerboa + +### Pattern C: C shim + +Use when: + +- system APIs require C ABI access +- a mature C library is unavoidable +- the shim can be tiny and stable + +Requirements: + +- no parser logic in the shim unless unavoidable +- no unchecked casts from caller-provided offsets +- no variadic FFI from Jerboa +- no returned raw pointers without a free function +- no string ownership ambiguity +- null checks on every allocation and lookup +- one high-level safe wrapper per unsafe function family + +Long-term goal: generated FFI wrappers with ownership, size, nullability, +thread-safety, and finalizer warnings. + +--- + +## Developer Environment as a Security Boundary + +The development environment is part of the product. Shells, editors, browsers, +LSP servers, and coding agents have access to source, secrets, build outputs, +SSH keys, package registries, and deployment credentials. + +Unification goals: + +- `jsh` is the structured command environment, not just a POSIX shell clone. +- `jerboa-code` runs model tools through capability-scoped execution contexts. +- `jerboa-emacs` and browser extensions do not inherit full editor/browser + authority by default. +- LSP/nREPL/debug surfaces require local auth and have clear eval boundaries. +- repo scanners, gitsafe, virus/intel scanners, and package provenance checks + run before code is promoted. + +Recommended local workflow: + +```text +edit .ss source + -> jerbuild check + -> unit tests + -> capability manifest check + -> security scan + -> fuzz/smoke tests for changed parsers + -> reproducible build + -> signed artifact +``` + +AI tools should operate inside this same workflow, not outside it. + +--- + +## Secure Full Stack Blueprint + +This is the target shape for a production Jerboa service. + +### 1. App entry + +Responsibilities: + +- parse config +- create root authority +- derive capabilities +- initialize audit logging +- initialize metrics +- start edge listener +- install signal handlers +- drop unused authority + +### 2. Edge + +Responsibilities: + +- TLS termination or verified local proxy boundary +- request parsing with size/depth/time limits +- authentication +- rate limiting +- request tainting +- routing +- response safety + +### 3. Domain + +Responsibilities: + +- pure logic +- typed records +- result-returning functions +- explicit errors +- no direct filesystem/network/process imports + +### 4. Data + +Responsibilities: + +- parameterized queries +- schema migrations under build/deploy authority only +- transaction boundaries +- audit events for sensitive reads/writes +- backup/restore capabilities separated from normal app caps + +### 5. Background jobs + +Responsibilities: + +- sandboxed execution +- bounded memory, time, and output +- explicit network and filesystem caps +- no access to request secrets unless granted +- structured job results + +### 6. Observability + +Responsibilities: + +- append-only audit chain for security decisions +- metrics for denied capabilities, auth failures, parse failures, resource + limits, and native errors +- crash reports without secret leakage +- deterministic error references for user-visible failures + +### 7. Release + +Responsibilities: + +- clean checkout build +- lock file verification +- artifact hash +- SBOM +- hardening flags +- signature +- deployment policy check + +--- + +## Migration Plan + +### Step 0: Record truth + +For every repo: + +- purpose +- maintained source form +- build command +- test command +- generated outputs +- native code +- security-sensitive inputs +- package dependencies +- dirty artifact policy + +Do not normalize by deleting functionality. Normalize by making state visible. + +### Step 1: Standardize source and build layout + +Move maintained Jerboa source to `src/*.ss`. Generate `.sls` into `lib/` with +`jerbuild`. Make `make build`, `make test`, and `make clean` consistent. + +Acceptance check: a fresh clone can build and test without manual path folklore. + +### Step 2: Add capability manifests + +Start with coarse declarations: + +- filesystem read/write paths +- network connect/listen hosts +- process spawn policy +- environment variables +- secret names +- native libraries + +Then refine them until tests can run under those caps. + +Acceptance check: capability diffs are visible in code review. + +### Step 3: Remove ambient build mutation + +Sibling build scripts must not patch, delete, or checkout files in the main +Jerboa repo. Use copied build inputs, vendored snapshots, or declared workspace +dependencies. + +Acceptance check: a cross-build cannot discard uncommitted source in another +checkout. + +### Step 4: Gate eval and agent surfaces + +Local eval is still code execution. REPL, nREPL, LSP, editor, browser, and AI +agent eval paths need auth, capabilities, and resource limits. + +Acceptance check: an arbitrary same-user local process cannot connect to an eval +surface and run code without the required grant. + +### Step 5: Make package provenance enforceable + +Extend package metadata and lock files until install can verify source, recipe, +artifact, and signer. + +Acceptance check: install fails closed on missing signatures, hash mismatches, +or undeclared build behavior. + +### Step 6: Consolidate native dependencies + +Inventory every `foreign-procedure`, C shim, Rust crate, bundled C dependency, +and dynamic loader path. Move common native capabilities into the Rust native +core where this reduces TCB complexity. + +Acceptance check: the TCB inventory is generated and reviewed. + +### Step 7: Ship a reference secure service + +Build one complete service that uses the full contract: + +- Jerboa edge +- auth +- DB +- YAML/JSON config +- audit log +- capability manifest +- sandboxed job +- reproducible binary +- signed artifact +- deployment notes + +Acceptance check: it is easier to start from this service than to assemble a +Node/Python/Rust stack with equivalent safety. + +--- + +## Promotion Gates + +Use these gates to decide whether a subsystem can move from experiment to core. + +### Experimental + +- code exists +- README explains purpose +- build may be local/manual +- security model may be notes only + +### Usable + +- `make build` works +- `make test` works +- generated artifacts are controlled +- main hostile inputs are documented +- basic security scan passes or findings are triaged + +### Stack-ready + +- package/system manifest exists +- capabilities are declared +- tests run under least authority or documented approximation +- native boundary is audited +- fuzzing exists for parsers/protocols +- build is reproducible enough to hash + +### Default + +- signed artifacts +- no install-time code +- complete lock metadata +- audit and metrics integration +- cross-platform behavior documented +- security review completed +- failure modes are fail-closed + +--- + +## What To Build Next + +The highest leverage work is not another isolated application. It is the glue +that makes every application inherit the same guarantees. + +1. **Workspace health tool.** Summarize all `jerboa*` and `chez*` repos: + branch, dirty source, generated artifacts, build target, test target, + manifest, native code, security findings. +2. **System manifest MVP.** Extend package metadata with capabilities, build + outputs, generated artifact policy, and native boundary declarations. +3. **Capability test runner.** Run tests with the declared caps and report + undeclared authority use. +4. **Generated FFI wrapper format.** Describe native functions with ownership + and size metadata, then generate safe Jerboa wrappers. +5. **Signed package prototype.** Use content hashes and YubiKey signatures for a + small first-party registry. +6. **Secure service template.** A real app that wires edge, db, auth, audit, + config, jobs, hardening, and signing. +7. **Agent sandbox.** Make `jerboa-code` and editor integrations use the same + capability runner as packages and tests. +8. **TCB report generator.** Produce a per-artifact list of Chez, Jerboa, Rust, + C, wasm, kernel, and host assumptions. + +--- + +## Anti-Patterns + +Do not normalize the stack by accepting these: + +- "It is local only, so auth is unnecessary." +- "It is signed, so it can have ambient authority." +- "It is memory safe, so authority does not matter." +- "It is generated by AI, so we will review it later." +- "It is just a build script, so shell injection is fine." +- "It is only a plugin, so it can inherit editor secrets." +- "It is a parser, so a crash is acceptable." +- "It is a C library everyone uses, so it is outside our TCB." +- "It is too much work to declare capabilities." +- "The package manager can add security after adoption." + +These are exactly how secure rewrites become insecure ecosystems. + +--- + +## Review Checklist + +Before merging a subsystem into the unified stack, ask: + +1. What authority does it need? +2. Where is that authority declared? +3. Can it attenuate authority before passing it onward? +4. What happens if the config, network, file, package, or user input is hostile? +5. What native code is trusted? +6. What parsers handle attacker-controlled bytes? +7. What runs during install? +8. What runs during build? +9. What is signed? +10. What is content-addressed? +11. What can an AI-generated dependency do if compromised? +12. What audit event proves the sensitive action happened? +13. What is the smallest test that proves authority is denied by default? +14. What breaks on Linux, macOS, FreeBSD, static binaries, or unsupported + kernels? +15. What is aspirational versus implemented today? + +If the answers are unclear, the subsystem is not unified yet. + +--- + +## Open Tensions + +These are real design pressures. + +1. **Ergonomics vs. explicit authority.** If capabilities are tedious, + developers will route around them. Tooling must make authority declaration + easier than ambient access. +2. **Package reach vs. package trust.** A secure ecosystem grows slower than a + no-rules ecosystem. The answer is first-party depth, curated imports, and + strong package UX, not weaker defaults. +3. **Pure Jerboa vs. native performance.** Pure Jerboa is easier to audit; Rust + can be necessary for hostile byte throughput. The boundary must be explicit. +4. **In-process integration vs. isolation.** Editors, shells, browsers, and + agents want deep integration. Security wants fault and authority isolation. +5. **Cross-platform hardening vs. honest degradation.** Linux has Landlock and + seccomp. Other platforms differ. Unsupported hardening must fail visibly or + degrade with explicit policy, not silently. +6. **AI acceleration vs. AI attack surface.** AI can generate tests, ports, and + fuzzers quickly. It can also generate plausible insecure glue. The stack must + harness it inside the same constraints as untrusted code. + +--- + +## Summary + +Jerboa becomes a full stack when every layer shares the same security contract: +least authority, structured data, small trusted base, reproducible build, +verified provenance, and explicit native boundaries. + +The way forward is not one large rewrite. It is a sequence of unifying contracts: + +- source layout +- build targets +- manifests +- capabilities +- lock files +- signatures +- FFI ownership +- audit events +- reference services + +Once those contracts are boring and automatic, the stack can grow quickly +without inheriting the failure modes of npm, shell glue, or C-based systems. --- a/jerbuild.ss +++ b/jerbuild.ss @@ -678,7 +678,25 @@ ;; jsh/util re-exports and overrides several chezscheme identifiers ((jsh util) . (string-downcase string-upcase file-directory? file-regular?)) ;; std/datetime exports make-date and make-time (chezscheme also has them) - ((std datetime) . (make-date make-time)))) + ((std datetime) . (make-date make-time)) + ;; (jerboa prelude) re-exports (jerboa core) + (jerboa runtime) and adds + ;; richer overrides. Listed so an explicit `(import (jerboa prelude))` + ;; (which suppresses auto-injection of core/runtime) still gets the + ;; correct (except (chezscheme) ...) clause. The final exclusions are + ;; filtered by `chez-export?`, so names not actually in chezscheme are + ;; dropped before emission — no harm in being inclusive here. + ((jerboa prelude) . (make-hash-table hash-table? sort sort! printf fprintf format + path-extension path-absolute? + with-input-from-string with-output-to-string