Menu
AkurAI-Build
publicLatest change 1c2159692a31765cd66ed709791ba11468054873 - Initial commit: bunfork v0.1.0 source tree by Olafur Bui
## Verdict
The smallest coherent product after `bunfork-static-v1` and the native Rust MPA split is:
> A Linux-first Rust server with one CLI, serving either immutable static artifacts or explicitly registered Rust MPA applications, with optional SQLCipher/vector services.
It is not a Bun/Deno runtime, framework compiler, adapter, SSR emulator, or Node-compatible server. This matches reports 01–08 and the existing boundary in [README.md](/home/olafurbui/bunfork/README.md:3).
### Product shape
Keep three explicit modes:
- Static artifact host: byte-preserving `bunfork-static-v1`.
- Native Rust MPA: Rust route table, loaders, actions, cookies, redirects, layouts, and MiniJinja rendering, as proposed in [07-fullstack-contract.md](/home/olafurbui/bunfork/docs/adversarial/07-fullstack-contract.md:20).
- Optional data service: SQLCipher/vector API enabled only when requested.
Static serving must not require a database, migration, database key, or API token. That is the central current contradiction: [src/main.rs](/home/olafurbui/bunfork/src/main.rs:205) unconditionally loads all three before [src/server.rs](/home/olafurbui/bunfork/src/server.rs:153) can serve anything.
Preserve the default listener `0.0.0.0:3100` from [src/main.rs](/home/olafurbui/bunfork/src/main.rs:20), [README.md](/home/olafurbui/bunfork/README.md:19), and [deploy/bunfork.service](/home/olafurbui/bunfork/deploy/bunfork.service:8).
## CLI
Use a small, explicit command set:
```text
bunfork keygen [--out PATH]
bunfork build --run PROGRAM --arg ARG... [--cwd DIR]
--output DIR --manifest PATH
bunfork admit --artifact DIR --manifest PATH [--json]
bunfork doctor [--json] [--strict]
bunfork readiness [--json]
bunfork dev --static DIR --manifest PATH
bunfork serve --static DIR --manifest PATH
bunfork serve --app BIN_OR_CRATE
bunfork serve --static DIR --manifest PATH --app BIN_OR_CRATE
bunfork test [--static DIR --manifest PATH] [--app APP]
bunfork deploy --artifact DIR --manifest PATH [--out DIR] [--force]
bunfork migrate
bunfork backup [--out PATH]
bunfork restore BACKUP --yes
bunfork vector put|search|delete ...
```
`start` may remain a visible alias for `serve`; `dev` must mean reload/revalidation only, never HMR. The current `test` and `deploy` behavior—Cargo tests plus helper smoke tests and a Cargo rebuild—is not application testing ([src/main.rs](/home/olafurbui/bunfork/src/main.rs:296), [src/main.rs](/home/olafurbui/bunfork/src/main.rs:331)).
`build` should execute an explicit argv vector, never shell expansion, and use a reduced environment. This incorporates the strongest point from [06-frontend-protocol.md](/home/olafurbui/bunfork/docs/adversarial/06-frontend-protocol.md:8) and addresses inherited-secret exposure in [08-data-deploy-security.md](/home/olafurbui/bunfork/docs/adversarial/08-data-deploy-security.md:36).
No auto-detection of Vite, SvelteKit, Next, Nuxt, package scripts, or directory conventions.
## Configuration
Use one optional, strict TOML or JSON config file, explicitly selected with `--config`; do not search implicitly.
Configuration precedence:
```text
CLI > config file > narrowly scoped environment variables > defaults
```
Environment variables should cover only operational globals such as:
```text
BUNFORK_ADDRESS=0.0.0.0:3100
BUNFORK_LOG=info
BUNFORK_CONFIG=/path/config.toml
```
Secrets must come from explicit files or dedicated secret environment variables. Never place database keys, API tokens, or arbitrary inherited environment values in application templates or static artifacts.
Reject unknown configuration keys, duplicate fields, invalid paths, relative paths where absolute paths are required, and mode-inappropriate options. Static mode must reject database/vector options unless an explicit composition mode is selected.
The static manifest should be the frozen schema from reports 03–06:
```json
{
"format": "bunfork-static-v1",
"root": ".",
"mode": "mpa",
"base": "/",
"fallback": null,
"trailing_slash": "directory",
"precompressed": true,
"immutable": true,
"files": {}
}
```
`files` must be complete, sorted, digest-bound, and include byte lengths. Reject symlinks, hard links, devices, hidden path segments, extra files, changed bytes, and malformed manifests before binding.
## Doctor and readiness
`doctor` is offline validation; `readiness` is process/service state.
JSON output should be stable and machine-readable:
```json
{
"ok": false,
"checks": [
{
"id": "artifact.manifest",
"status": "fail",
"message": "sha256 mismatch",
"path": "assets/app.js"
}
]
}
```
Recommended check IDs:
- `config.parse`
- `paths.permissions`
- `artifact.manifest`
- `artifact.files`
- `artifact.routes`
- `artifact.fallback`
- `templates.compile`
- `database.exists`
- `database.key`
- `database.schema`
- `secrets.distinct`
- `service.listener`
- `service.shutdown`
`readiness` should report `ok`, bound address, mode, manifest digest, application identity, database status, and migration version. Never emit secrets, tokens, database keys, or full authorization headers.
Exit codes:
```text
0 success / ready
1 validation or test failure
2 usage/configuration error
3 admission or artifact-integrity failure
4 dependency/tool/build failure
5 database/migration/backup/restore failure
6 operational bind/service failure
64 CLI usage error
70 unexpected internal error
```
Use the same codes for human and JSON modes.
## Operations and deploy
Delete the current descriptive ownership model. [src/main.rs](/home/olafurbui/bunfork/src/main.rs:401) accepts forgeable metadata and can still replace dangerous direct-child paths. `--force` must only replace a directory containing a verified, digest-complete Bunfork manifest. Independently refuse `.git`, `src`, `data`, `target`, `backups`, and any configured live-data path.
Deployment should:
1. Admit and validate the artifact.
2. Stage in a newly created sibling directory.
3. Hash and fsync files and directories.
4. Atomically rename the staged release.
5. Retain exactly one verified previous release.
6. Remove stale PID-named releases after successful promotion.
Backup and restore need descriptor-based, no-follow operations. The current validate-then-reopen sequence remains TOCTOU-prone ([src/db.rs](/home/olafurbui/bunfork/src/db.rs:410)). Apply the same hard-link rejection to migration paths, and compare decoded secret bytes rather than strings; uppercase/lowercase equivalents currently bypass separation ([src/main.rs](/home/olafurbui/bunfork/src/main.rs:216), [src/db.rs](/home/olafurbui/bunfork/src/db.rs:1071)).
Classify malformed vectors, dimensions, IDs, limits, body sizes, and budget exhaustion as stable 4xx responses, not 500s ([src/server.rs](/home/olafurbui/bunfork/src/server.rs:313)).
## Logging
Default to concise structured logs:
- `INFO`: startup, mode, address, manifest digest, migration state, shutdown.
- `WARN`: rejected requests, fallback use, degraded checks.
- `ERROR`: internal failures with a correlation/request ID.
Never log request bodies, bearer tokens, secrets, database paths when sensitive, or full query strings by default. Support human logs and JSON logs via `BUNFORK_LOG_FORMAT=json`.
## systemd
The unit currently disagrees with README paths: [deploy/bunfork.service](/home/olafurbui/bunfork/deploy/bunfork.service:7) uses `%h/.local/lib/bunfork`, while [README.md](/home/olafurbui/bunfork/README.md:91) instructs running from `dist`.
Choose one installed layout and document it. Add:
```ini
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=%h/.local/share/bunfork
ReadOnlyPaths=%h/.local/lib/bunfork
CapabilityBoundingSet=
RestrictAddressFamilies=AF_INET AF_INET6
UMask=0077
```
For static-only mode, make the artifact read-only and grant no database write path. Keep `0.0.0.0:3100`; TLS remains the responsibility of a trusted reverse proxy.
## Test matrix
Minimum release matrix:
- CLI parsing, precedence, unknown-key rejection, malformed config.
- `doctor` and `readiness` human/JSON output and exit codes.
- Reproducible manifests from identical trees.
- Mutation, added/removed file, symlink, hard link, hidden file, device, traversal, malformed URL.
- Static MPA/SPA routing, base paths, trailing slash, `GET`, `HEAD`, `405`, 404, fallback exclusion, MIME, ETag, cache, gzip/Brotli, CSP.
- Official static outputs: SvelteKit adapter-static, Next `output: export`, Vite, Nuxt `generate`.
- Negative admission: `.next/server`, standalone, Nitro, adapter-node, API/server routes, SSR artifacts.
- Native MPA: concurrent escaping/isolation, query/body limits, loaders, actions, `303`, `422`, CSRF, cookies, auth, layouts, 404/500.
- Data: migrations, exact schema, wrong/equivalent-case keys, malformed vectors, backup no-overwrite, restore races, shutdown during writes.
- Browser: JavaScript enabled and disabled, deep-link reloads, console errors, asset loading, form progressive enhancement.
- Clean-machine artifact execution from arbitrary working directory.
- systemd start, readiness, SIGTERM, in-flight request completion, restart behavior.
## Delete-or-merge
Delete:
- Claims of framework/source/build compatibility.
- The current `bunfork-deployment-v1` metadata manifest.
- Unconditional database startup for page/static serving.
- `dev` language implying HMR.
- Cargo-based application `deploy` semantics.
Merge:
- `serve` and `start` as one command.
- `admit` and `doctor` around the same validator, with different output/purpose.
- Static and MPA routing behind one server process, but keep their artifacts and contracts separate.
- Backup/restore/migrate under one explicit data-service configuration namespace.
This is the smallest product that is coherent, testable, secure, and still meaningfully preserves the project’s `0.0.0.0:3100+` and encrypted-data goals.