chore: bump version for cleanness
This commit is contained in:
parent
014d662bd1
commit
77599ab3ee
3 changed files with 28 additions and 24 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
|
@ -5,6 +5,8 @@ which records not just what changed but what each drill run proved.
|
|||
|
||||
## Unreleased
|
||||
|
||||
## 0.6.0 — 2026-07-18
|
||||
|
||||
### Added
|
||||
|
||||
- **The restricted tier: multi-user hosts** (#74, redesigning #72) — an admin
|
||||
|
|
@ -12,7 +14,7 @@ which records not just what changed but what each drill run proved.
|
|||
hardened `boxnet`, seeing nobody else's; `box revoke <user>` takes it back
|
||||
(`--purge` deletes their world, and asserts the absence). The tier rides
|
||||
incus-user, whose defaults miss box's contract three measured ways (Debian
|
||||
13 / Incus 6.0.4): a private *unhardened* NAT bridge per user, snapshots
|
||||
13 / Incus 6.0.4): a private _unhardened_ NAT bridge per user, snapshots
|
||||
blocked, the `box-net` profile invisible — so grant is an idempotent
|
||||
convergence: project narrowed to `boxnet` **and only boxnet** (listing the
|
||||
private bridge too, the obvious fix, would keep an unhardened network one
|
||||
|
|
@ -29,7 +31,7 @@ which records not just what changed but what each drill run proved.
|
|||
`multiuser.sh --container`), so every PR proves the tier's semantics
|
||||
against a live daemon, not a mock. The VM trust boundary itself remains a
|
||||
real-hardware ritual, like the full drill.
|
||||
- **Global / root install** (#71) — run as root, box installs *once* to
|
||||
- **Global / root install** (#71) — run as root, box installs _once_ to
|
||||
`/opt/box` (world-readable) with the `box` symlink on `/usr/local/bin`, so
|
||||
every operator on a shared host runs the same tree. Per-user installs are
|
||||
unchanged (`$HOME/.local`); `BOX_HOME`/`BOX_BIN` still override. A per-user
|
||||
|
|
@ -53,7 +55,7 @@ which records not just what changed but what each drill run proved.
|
|||
restricted user; fixed for every tier, and the rehearsal + a grep-guard in
|
||||
`test/cli.sh` now hold it.
|
||||
- **`box tmux` works on every template** (#65) — `box tmux` runs
|
||||
`tmux new-session` *inside* the box, but the templates did not install tmux, so
|
||||
`tmux new-session` _inside_ the box, but the templates did not install tmux, so
|
||||
it failed with `tmux: command not found`. `tmux` is now in each template's
|
||||
cloud-init package list (`blank`/`claude`/`codex`/`grok`).
|
||||
|
||||
|
|
@ -103,11 +105,11 @@ which records not just what changed but what each drill run proved.
|
|||
It now asserts the post-install stack in-group before touching the host, and
|
||||
runs `setup-host` exactly once more — after the clean, which deliberately
|
||||
unsets `dns.mode` and so has to be converged back. `DRILL_OWNS_SETUP=1`
|
||||
hands sequencing back to the drill. Pre-setup tripwires now read *before*
|
||||
hands sequencing back to the drill. Pre-setup tripwires now read _before_
|
||||
`install.sh`, since that is what triggers setup now.
|
||||
- **`install.sh` asks, sets up the host, and no-ops on re-run** (#64) — it now
|
||||
prompts *"Install box?"*, then on a fresh host installs the tree and asks a
|
||||
second question, *"Set up this machine as a box host now?"*, running the whole
|
||||
prompts _"Install box?"_, then on a fresh host installs the tree and asks a
|
||||
second question, _"Set up this machine as a box host now?"_, running the whole
|
||||
isolation stack if you say yes (previously it only printed a warning and left
|
||||
you a command, so the install reported success and `box new` died on a host
|
||||
with no Incus). Prompts read `/dev/tty`, since under `curl | bash` the script
|
||||
|
|
|
|||
18
README.md
18
README.md
|
|
@ -8,7 +8,7 @@ destroying it loses nothing you didn't push.
|
|||
|
||||
**Strictly creds-free.** A box ships with everything installed and **no**
|
||||
credentials — no agent token, no git PAT, nothing. You authenticate
|
||||
interactively *inside* the box. The tool never stores or injects a secret. That
|
||||
interactively _inside_ the box. The tool never stores or injects a secret. That
|
||||
means there's nothing shared or committed, so it's safe for multiple operators
|
||||
out of the box.
|
||||
|
||||
|
|
@ -23,6 +23,8 @@ runbook that the box's coding agent reads and acts on — there is no `install`
|
|||
step and no host-run setup. See [docs/box-design.md](docs/box-design.md) for the
|
||||
design rationale.
|
||||
|
||||
> **0.6.0**: multi-user support.
|
||||
|
||||
> **0.5.0**: two new templates (`codex`, `grok`), `box expose` — a
|
||||
> loopback-only door to a box port, for seeing a dev server — and the host
|
||||
> lifecycle as first-class verbs: `box setup-host`, `box teardown-host`, and
|
||||
|
|
@ -52,7 +54,7 @@ rebuild the stack under your boxes. Upgrading is therefore explicit: uninstall
|
|||
what you have and install fresh. Preserve any boxes first — `box down <box>`,
|
||||
copy out anything you need (a portable `box export` is
|
||||
[#70](https://github.com/heavy-duty/box/issues/70)), then `box rm <box>`
|
||||
(which deletes the box *and* its snapshots) — then:
|
||||
(which deletes the box _and_ its snapshots) — then:
|
||||
|
||||
```sh
|
||||
rm -rf ~/.local/share/box ~/.local/bin/box # uninstall
|
||||
|
|
@ -67,7 +69,7 @@ declines the host-setup step.
|
|||
### Global vs per-user install
|
||||
|
||||
Where box lands depends on **who runs the installer**, because on a shared host
|
||||
box's tree is *executed by other users* — so it cannot hide in one user's home:
|
||||
box's tree is _executed by other users_ — so it cannot hide in one user's home:
|
||||
|
||||
- **As root → global.** The tree goes to `/opt/box` (world-readable) and the
|
||||
`box` symlink to `/usr/local/bin` (already on every login `PATH`). One
|
||||
|
|
@ -114,7 +116,7 @@ the machine — so box layers a second tier on
|
|||
[incus-user](https://linuxcontainers.org/incus/docs/main/projects/):
|
||||
|
||||
| tier | who | what they hold |
|
||||
|---|---|---|
|
||||
| -------------- | -------------------------------- | ----------------------------------------------------------------- |
|
||||
| **admin** | root, or the `incus-admin` group | everything: all boxes, the stack, `setup-host`, `expose`, `grant` |
|
||||
| **restricted** | the `incus` group | their **own** boxes only, on the same hardened network |
|
||||
| none | everyone else | no socket, nothing |
|
||||
|
|
@ -132,7 +134,7 @@ box revoke dev1 --purge # ...or end their sessions and delete everything the
|
|||
`grant` is an idempotent convergence, not a flag flip, because incus-user's
|
||||
defaults miss box's contract three ways (measured on Debian 13 / Incus 6.0.4,
|
||||
see [the plan doc](docs/plans/2026-07-18-restricted-tier.md)): it pins each
|
||||
user to a private *unhardened* NAT bridge, it blocks snapshots, and it cannot
|
||||
user to a private _unhardened_ NAT bridge, it blocks snapshots, and it cannot
|
||||
see the `box-net` profile. Granting rewires all three: the user's project is
|
||||
restricted to `boxnet` **and only boxnet** — the hardened network is not their
|
||||
default placement but the only one their certificate can express — snapshots
|
||||
|
|
@ -176,7 +178,7 @@ No coding agent is special — each is one template among several, and adding
|
|||
another is just another directory. What ships today:
|
||||
|
||||
| Template | What's in it |
|
||||
| --- | --- |
|
||||
| -------- | --------------------------------------------------------- |
|
||||
| `blank` | Bare Debian 13 — same isolation, no tooling. The default. |
|
||||
| `claude` | Claude Code, creds-free — where this project started |
|
||||
| `codex` | OpenAI Codex CLI, creds-free |
|
||||
|
|
@ -303,7 +305,7 @@ command surface is a table.
|
|||
## Isolation
|
||||
|
||||
The contract: **a box reaches the public internet and nothing else.** Not the
|
||||
host, not your LAN, not another box, not even another box's *name*. What
|
||||
host, not your LAN, not another box, not even another box's _name_. What
|
||||
enforces it, layer by layer:
|
||||
|
||||
- **Dedicated NAT bridge** `boxnet`, IPv6 off. Every rule below is
|
||||
|
|
@ -311,7 +313,7 @@ enforces it, layer by layer:
|
|||
contract, not a default.
|
||||
- **`box-isolate` ACL** — drops all egress to private space (RFC1918,
|
||||
CGNAT, link-local), with a single carve-out to the gateway so DNS works.
|
||||
- **Sibling isolation, at L2** — two boxes on one bridge are *switched*,
|
||||
- **Sibling isolation, at L2** — two boxes on one bridge are _switched_,
|
||||
never routed, so no L3 rule can separate them (learned the hard way; see
|
||||
below). `security.port_isolation` on every box NIC plus an nft
|
||||
bridge-family drop mean box A cannot exchange frames with box B at all.
|
||||
|
|
|
|||
2
VERSION
2
VERSION
|
|
@ -1 +1 @@
|
|||
0.5.0
|
||||
0.6.0
|
||||
|
|
|
|||
Loading…
Reference in a new issue