The workflow asks for the confined tier on the grounds that bats over shell and markdown needs neither a Docker socket nor the host's network namespace, and that taking a privilege for no reason is what this repository is about. But runs-on: is a request. Which runner answers it depends on which runners carry the label, and nothing in a job's log says whether the socket was mounted in. Without this file, 'we run confined' is a claim in a comment, and it would keep reading as true on a runner that grants everything. The sister project has a file like this and it is doing a different job. There the runner is the product, and its failures name the program that should have configured it differently. This repository configures no runner and cannot fix one. What it checks is that the job got no more than it asked for, and its failures say so and point at dejima-ci-hardener rather than pretending otherwise. Seven assertions: no Docker socket, not in the host network namespace, not masquerading as a devbox, and four on the allowlist this repository actually depends on for bats to install at all. The off-list probe is a public resolver rather than a documentation address on purpose, because an address that never answers would satisfy every negative check on a runner with no network, which is the exact failure this file exists to detect. DEJIMA_CI_TIER is declared by the workflow rather than sniffed, so landing on the wrong runner fails rather than quietly selecting a different set of assertions. The checkout is bare, which is the property worth having: the assertions come from main, and a branch that could edit the file asserting it was not handed a Docker socket could assert anything it liked. There is no bootstrapping problem despite appearances, and the comment says so, because it looks real enough to be re-introduced by anyone who reasons about it briefly. Under pull_request_target the workflow is read from main too, so this job cannot run on the pull request that introduces it, and by the time it first fires main has both the job and the file.
Devbox Hardener
Bounds what a compromised development VM can reach on your network, and tells you what that bound actually is.
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.
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, and the reasoning is written down rather than assumed: an escape would land in an account holding less than the session already had, so patching is the proportionate response.
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
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
All of these need root. The config is 0640 root, and the radius report stats
files in root's own home.
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.
