// Package main is the sorcery CLI — the unified entry point for the Coven. // // This is the real CLI. Every subcommand wires together the actual pkg/* // implementations: config.Default() builds the runtime paths, state.Open // opens the bbolt DB, grimoire.IndexAll walks the spell tree, cast.Pipeline // runs the forge, warding.Ward guards the result, web.Server serves the UI. // // Drop-in usage in an existing Source Mage chroot: // // sudo install -m 755 sorcery /usr/local/sbin/sorcery-go // sudo sorcery-go init // sudo sorcery-go cast busybox --static --default // sorcery-go gaze install busybox package main import ( "context" "flag" "fmt" "os" "os/signal" "syscall" "time" "dcos.net/sorcery-go/pkg/config" "dcos.net/sorcery-go/pkg/eventbus" "dcos.net/sorcery-go/pkg/grimoire" "dcos.net/sorcery-go/pkg/state" "dcos.net/sorcery-go/pkg/tomb" ) // Version is set at build time via -ldflags. var Version = "dev" func main() { if len(os.Args) < 2 { usage() os.Exit(1) } cmd := os.Args[1] args := os.Args[2:] switch cmd { case "init": cmdInit(args) case "cast": cmdCast(args) case "reanimate": cmdReanimate(args) case "dispel": cmdDispel(args) case "coven": cmdCoven(args) case "tomb": cmdTomb(args) case "ward": cmdWard(args) case "legal": cmdLegal(args) case "web": cmdWeb(args) case "gaze": cmdGaze(args) case "version", "--version", "-v": fmt.Printf("sorcery %s (Coven Edition)\n", Version) case "help", "--help", "-h": usage() default: fmt.Fprintf(os.Stderr, "unknown command: %s\n", cmd) usage() os.Exit(2) } } func usage() { fmt.Print(`sorcery — Sovereign Coven CLI Usage: sorcery init Initialise state DB and Tomb sorcery cast [--target arch] [--static] [-r] [-d] [-m arches] sorcery reanimate --sanctum [--runtime ] sorcery dispel sorcery coven spawn|destroy|list|status [--runtime ] sorcery coven join sorcery coven pulse sorcery tomb list|verify|purge|inspect sorcery ward status|banish|reinforce|watch|thaw sorcery legal audit|sbom|set-posture sorcery web --port 8080 sorcery gaze install|tablet|depends|essence|whereis|sbom sorcery version Flags: --target Cross-compile for arch (x86_64, aarch64) --static Produce a portable static ELF (musl) -r, --reconfigure Force ICE y/n prompts even if Tablet has answers -d, --default Accept all defaults (HPC-friendly) -m, --matrix Build across all maintained arches simultaneously Environment: SORCERY_GO_ROOT State root (default /var/lib/sorcery-go) SORCERY_GO_GRIMOIRE Grimoire path (default /var/lib/sorcery/codex/grimoire) SORCERY_GO_RUNTIME Container runtime (lxc|podman|firecracker|baremetal|auto) SORCERY_GO_POSTURE Legal posture (strict_copyleft | corporate_lite | lawless) SORCERY_GO_PGP_KEYRING GnuPG keyring for DETAILS attestation SORCERY_GO_EBPF_ENFORCE Enable eBPF enforcing mode (true/false) SORCERY_GO_NETWORK_BRIDGE Bridge interface for containers (default br0) Runtimes: lxc System containers (lxc-tools) podman OCI containers (rootless capable) firecracker Lightweight microVMs (VM-level isolation) baremetal Direct filesystem deployment auto Auto-detect first available runtime Coven Edition · "The Ley-Lines are humming. The Tomb is secure (eBPF-enforced)." `) } // --- engine helpers --- // openEngine wires up the standard set of pkg/* objects every command needs. // Returns them all so callers can use what they want. func openEngine() (*config.Config, *state.Manager, *tomb.Tomb, *eventbus.Bus) { cfg := config.Default() if err := cfg.EnsureDirs(); err != nil { fmt.Fprintf(os.Stderr, "init: %v\n", err) os.Exit(1) } stateMgr, err := state.Open(cfg.StateDB) if err != nil { fmt.Fprintf(os.Stderr, "state: %v\n", err) os.Exit(1) } t := tomb.New(cfg.TombRoot) bus := eventbus.New() return cfg, stateMgr, t, bus } // indexGrimoire walks the configured grimoire path and returns the in-memory // spell index. Used by cast, gaze, and web. func indexGrimoire(cfg *config.Config) map[string]*grimoire.Spell { spells, err := grimoire.IndexAll(cfg.GrimoirePath) if err != nil { fmt.Fprintf(os.Stderr, "grimoire: %v (continuing with empty index)\n", err) return map[string]*grimoire.Spell{} } return spells } // installSignalHandler returns a context that's cancelled on Ctrl+C / SIGTERM. func installSignalHandler() context.Context { ctx, cancel := context.WithCancel(context.Background()) ch := make(chan os.Signal, 1) signal.Notify(ch, syscall.SIGINT, syscall.SIGTERM) go func() { <-ch fmt.Fprintln(os.Stderr, "\n⚡ Interrupt received — winding down...") cancel() }() return ctx } // --- init --- func cmdInit(args []string) { fs := flag.NewFlagSet("init", flag.ExitOnError) force := fs.Bool("force", false, "rebuild indexes even if state.db exists") _ = fs.Parse(args) cfg := config.Default() if err := cfg.EnsureDirs(); err != nil { fmt.Fprintf(os.Stderr, "init: %v\n", err) os.Exit(1) } stateMgr, err := state.Open(cfg.StateDB) if err != nil { fmt.Fprintf(os.Stderr, "state: %v\n", err) os.Exit(1) } defer stateMgr.Close() fmt.Printf("⚡ Sorcery-Go %s initialised\n", Version) fmt.Printf(" State DB: %s\n", cfg.StateDB) fmt.Printf(" Tomb: %s\n", cfg.TombRoot) fmt.Printf(" Grimoire: %s\n", cfg.GrimoirePath) fmt.Printf(" Spool: %s\n", cfg.SpoolDir) fmt.Printf(" Host arch: %s\n", cfg.HostArch) fmt.Printf(" Posture: %s\n", cfg.ActivePosture) if *force { spells := indexGrimoire(cfg) fmt.Printf(" Indexed %d spells from grimoire.\n", len(spells)) } else { fmt.Println(" (run `sorcery gaze install ` to query the grimoire)") } fmt.Println("\nNext: `sorcery cast busybox --static --default`") } // streamTaskToStdout subscribes to the bus under taskID and prints every // event to stdout. Returns when the task completes or fails. func streamTaskToStdout(bus *eventbus.Bus, taskID string) { ch, unsub := bus.Subscribe(taskID) defer unsub() defer func() { for range ch {} }() for ev := range ch { switch ev.Type { case eventbus.EventLog: fmt.Println(ev.Data) case eventbus.EventPhase: fmt.Printf("─── %s ───\n", ev.Data) case eventbus.EventProgress: fmt.Printf(" [%d/%d]\n", ev.Done, ev.Total) case eventbus.EventComplete: fmt.Printf("✓ Essence sealed: %s\n", ev.Data) return case eventbus.EventFailed: fmt.Fprintf(os.Stderr, "✗ FAILED: %s\n", ev.Data) os.Exit(1) } } } // pause briefly so the goroutine in cmdCast can subscribe before events fire. var pause = func() { time.Sleep(10 * time.Millisecond) }