A devbox is a machine that runs dejima, and this repository set one up without installing anything dejima needs. Bootstrap finished on a host with no container runtime at all. It now installs docker.io and docker-cli from Debian, compose by whichever route the release offers, and python3, jq and git - dejima's own stated prerequisites, the first two for its host-side credential proxy and its installer. The compose ladder is the sister repository's, unchanged in substance: distribution package, then backports, then Docker's own apt repository last and said out loud, because it is a third-party source on a machine whose value is a small, known surface. bin/dejima-devbox-clone then puts dejima's source at ~/dejima, and stops there. It does not run dejima's install.sh: that step writes into ~/.claude, ~/.local/bin and ~/.config/dejima, and what it does there is dejima's to define and to change. A copy of another project's setup contract kept here would go stale with nothing to notice. What is worth doing on this side is the ordering - source has to arrive over a network that is about to be locked down, so the clone happens before the addressing step and before the node rules go on. An existing directory is never modified. A checkout somebody has been working in is not this program's to pull into, and a directory that is not a checkout is more likely to be theirs than to be a mistake. Two smaller things follow from the same change: The account. dejima runs as a person, not as root, so bootstrap asks which one, adds it to the docker group and records it. The docker group is root on this VM in one command - docs/threat-model.md already treats that as a grant rather than a lapse, and the blast radius there is written assuming it. The audit's radius report was inventorying the wrong home. It runs as root, from the timer or under sudo, where HOME is root's - and root's home on a devbox holds nothing, so the report read "none found" on a box whose credentials sat one directory over. It now resolves the recorded account, falling back to $HOME so a host set up before this reports what it always did. Tested: 98 tests pass. test/clone.bats clones over file:// from a fixture repository, so it needs no network: the clone, DEJIMA_DIR, an existing checkout left alone with its uncommitted work intact, a non-checkout directory refused, an empty one accepted, a bad URL failing loudly, and that nothing is written into the account it clones for. test/audit.bats covers the home resolution. test/units.bats now checks that every program in bin/ is executable, which dejima-devbox-clone was not.
8.2 KiB
Devbox Hardener
Bounds what a compromised development VM can reach on your network, and tells you what that bound actually is.
Early development. Not ready to be depended on. Nothing here has been through outside review, an external audit, or adversarial testing by anyone but the person who wrote it. Every security property this describes is a claim awaiting scrutiny, not one that has survived it. Do not put this anywhere that being wrong about it would matter.
One maintainer, no support. Nothing about this is promised: not a reply, not a fix, not a release. SECURITY.md has the detail, and is where to report a vulnerability rather than in a public issue.
One person's work per devbox. A condition of the tool rather than an observation about how devboxes get used: the blast radius here is stated in terms of what is on the box, so a machine holding several people's work is out of spec and the reasoning in docs/threat-model.md does not hold for it. If you need separation between people, use a devbox each.
What a devbox is, and why it is a different problem
A devbox is a long-lived VM that runs dejima sessions. It differs from a CI runner in one way that drives everything else: it holds uncommitted work, so it cannot be rolled back on a schedule.
That matters because rollback is the entire containment story of its sister project, dejima-ci-hardener. A runner is built to be lost. Anything that gets into one has until the next nightly rebuild, and nothing on it was worth keeping anyway. Take that away and what is left has to come from somewhere else: the hypervisor boundary, and knowing precisely what sits inside it.
What it does not claim
It does not prevent root on the devbox. Nothing here tries to.
What it does is make root on the devbox reach less, and make that reach something you can check rather than assume. The honest version of what each layer grants is docs/threat-model.md, including the blast radius by layer and the options that were rejected, with reasons.
Container escape is deliberately deprioritised. An escape gains root, which is more than the container has, and root on this VM is already a row in that table, bounded by the same hypervisor firewall however it was reached. So patching is what is left worth doing, and separating escape from root inside the guest is not.
Two halves
| proxmox/README.md | The node side: create the VM, apply the firewall. The primary control. Everything is done in the web console. |
| docs/building-a-devbox.md | The guest side: install, bootstrap, verify. The same on any hypervisor. |
Do the node side first, through the end of its §3.
The split is deliberate. Nothing guest-side knows it is on Proxmox, so another hypervisor can be added later without touching a single step on the other page.
Use
sudo ./bin/dejima-devbox-bootstrap # once, in the guest
cd ~/dejima && ./install.sh # dejima's own step, as your own account
sudo dejima-devbox-audit # both halves
sudo dejima-devbox-audit reach # containment only, what the timer runs
sudo dejima-devbox-audit radius # what root here would get
Bootstrap installs what dejima needs from the host - Docker with the compose
v2 plugin, python3, jq - and clones dejima to ~/dejima. It stops there.
Installing dejima is dejima's step: install.sh writes into your ~/.claude,
~/.local/bin and ~/.config/dejima, and what it does there is that project's
to define and to change. A copy of that contract kept here would go stale
without anything noticing.
The audit needs root. The config is 0640 root, and the radius report stats
files in the home of the account that runs dejima, which it reads from the
config rather than from $HOME - under sudo and under the timer that is
root's, whose home on a devbox holds nothing.
How it fails
The firewall is on the hypervisor, so the guest cannot verify it by reading it. That is what makes it worth having and what makes checking it awkward. The audit tests behaviour instead, by probing the default gateway: already in the routing table so it reveals nothing, guaranteed alive where an arbitrary address is not, and inside the ranges the firewall drops.
A timeout has two causes, and telling them apart is the whole design:
PASS |
Nothing answered and the network demonstrably works |
FAIL |
Something answered. Rules missing, or an exception above them |
INDETERMINATE |
Nothing answered, including things that should. Not a pass. |
A check that reports success when it does not know is worse than no check, because it gets believed.
A rule that REJECTs rather than DROPs reports FAIL even though it is
working. bash's /dev/tcp cannot tell a rejection from a live host
refusing. That is the safe direction to be wrong in, and it is why the template
specifies DROP.
Nothing is stored about what this VM must not reach. Such a list would be a map of valuable targets, kept on the machine this project assumes will be owned. The audit derives its targets from the routing table and its controls from your forge, so there is nothing to type and nothing to leak.
Tests
bats test/
test/devbox.bats asserts against a real devbox and skips everywhere else. It
is gated on DEJIMA_DEVBOX=1 rather than on detecting a devbox, because a
detector that guesses wrong skips silently, and a suite that passes by asserting
nothing is worse than one that fails.
Further reading
| docs/ | Index of everything below |
| docs/threat-model.md | What each layer grants, why escape is deprioritised, what was rejected |
| docs/reference.md | The three verdicts, the three addressing modes, the one config key |
| SECURITY.md | What this claims, and where to report a vulnerability |
| dejima-ci-hardener | The sister project, for hosts that can be rolled back |
License
GPL-3.0-or-later. See LICENSE.
The dejima wordmark and logo are not code and are not covered by that licence. They are trademarks; who holds them and what may be done with them is stated once for the organisation, at dejima's ATTRIBUTION.md.
