Files
mhoennigandClaude Fable 5 e4bfeacf5a 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>
2026-09-01 07:01:21 +02:00

41 lines
915 B
Go

package cli
import (
"errors"
"flag"
"fmt"
"io"
"werkdock/internal/store"
)
func loadCmd(args []string) int {
fs := flag.NewFlagSet("load", flag.ContinueOnError)
fs.SetOutput(io.Discard)
var input, name string
fs.StringVar(&input, "i", "", "rootfs archive to import")
fs.StringVar(&input, "input", "", "rootfs archive to import")
fs.StringVar(&name, "name", "", "image name (default: derived from the archive file name)")
if err := fs.Parse(args); err != nil {
return fail(err)
}
if input == "" {
return fail(errors.New("load needs -i ARCHIVE"))
}
if len(fs.Args()) != 0 {
return fail(fmt.Errorf("unexpected argument %q", fs.Args()[0]))
}
if name == "" {
name = store.ImageNameFromArchive(input)
}
st, err := store.Default()
if err != nil {
return fail(err)
}
if err := st.Load(input, name); err != nil {
return fail(err)
}
fmt.Printf("Loaded image: %s\n", name)
return 0
}