Werkdock skeleton: doctor, load, run over the bwrap engine (Go)
The minimal build-capable CLI decided in RFC 0002's outcome: stdlib-only Go module, one static binary. - engine: RunSpec behind the Engine interface (RFC 0001); the Bwrap engine ports Werkator's hardened invocation — uid-0 mapping, read-only rootfs at /, proc/dev/tmp/root before the user binds so binds below them land inside, mountpoint pre-creation in the rootfs including file mountpoints, and a guard against binds escaping the rootfs. --clearenv gives docker-style clean environments (HOME/PATH set explicitly). - store: images under $WERKDOCK_HOME (default ~/.werkdock), load unpacks via the tar CLI into a tmp dir and renames atomically. - cli: docker-shaped run flags (-v/-e/-w/--rm); refused docker flags (-p, --network, --memory, --cpus, --user, -d) fail loudly with the reason; exit codes follow docker (125 CLI errors, child code through). - doctor: port of werkator-build-prerequisites.sh — userns probe with the three signals, tar/zstd, free space and group-quota headroom via testable df/quota parsers, same PASS/FAIL output. - tests: argv golden test, mountpoint and escape tests, flag refusals, store round trip, doctor parsers — plus real-sandbox integration tests that skip where bwrap or userns are unavailable. Also records in step 21: RFC 0002 levels 2/3 deferred; next goal is sandbox builds of Werkator, Werkbaum, and Werkdock itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
de79210a7b
commit
e4bfeacf5a
@@ -0,0 +1,68 @@
|
||||
// Package cli parses werkdock's docker-shaped command line (RFC 0002)
|
||||
// and dispatches to the internal packages. Exit codes follow docker:
|
||||
// 125 for werkdock's own errors, otherwise the sandboxed command's code
|
||||
// is passed through.
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Version is replaced at release time; the dev default marks unreleased
|
||||
// builds.
|
||||
var Version = "0.1.0-dev"
|
||||
|
||||
const exitCLIError = 125
|
||||
|
||||
// Main runs the CLI and returns the process exit code.
|
||||
func Main(args []string) int {
|
||||
if len(args) == 0 {
|
||||
usage(os.Stderr)
|
||||
return exitCLIError
|
||||
}
|
||||
switch args[0] {
|
||||
case "run":
|
||||
return runCmd(args[1:])
|
||||
case "load":
|
||||
return loadCmd(args[1:])
|
||||
case "doctor":
|
||||
return doctorCmd(args[1:])
|
||||
case "version", "--version":
|
||||
fmt.Printf("werkdock %s\n", Version)
|
||||
return 0
|
||||
case "help", "--help", "-h":
|
||||
usage(os.Stdout)
|
||||
return 0
|
||||
default:
|
||||
fmt.Fprintf(os.Stderr, "werkdock: unknown command %q\n\n", args[0])
|
||||
usage(os.Stderr)
|
||||
return exitCLIError
|
||||
}
|
||||
}
|
||||
|
||||
func usage(w io.Writer) {
|
||||
fmt.Fprint(w, `werkdock — a docker-like sandbox CLI over bwrap, filesystem isolation only.
|
||||
Network, uid, /proc, /dev, and /tmp come from the host by contract.
|
||||
|
||||
Usage:
|
||||
werkdock run [flags] IMAGE COMMAND [ARG...] run a command in a sandbox
|
||||
werkdock load -i ARCHIVE [--name NAME] import a rootfs archive as an image
|
||||
werkdock doctor [TARGET_DIR] check whether this host can run sandboxes
|
||||
werkdock version print the version
|
||||
|
||||
Run flags:
|
||||
-v, --volume SRC:DEST[:ro] bind mount (repeatable, applied in order)
|
||||
-e, --env KEY=VALUE set an environment variable (KEY alone copies it from the host)
|
||||
-w, --workdir DIR working directory inside the sandbox (default /)
|
||||
--rm remove the instance afterwards (currently required)
|
||||
|
||||
The store lives in $WERKDOCK_HOME (default ~/.werkdock).
|
||||
`)
|
||||
}
|
||||
|
||||
func fail(err error) int {
|
||||
fmt.Fprintf(os.Stderr, "werkdock: %v\n", err)
|
||||
return exitCLIError
|
||||
}
|
||||
Reference in New Issue
Block a user