// Command keyproxy resolves opaque mpk- refs to key material at the // wire. v0 backends: file (0600 env files) and env (process env); // bitwarden and vault ship as explicit not-implemented stubs until // phase 3. Material is memory-only: never persisted, never logged. package main import ( "context" "flag" "fmt" "os" "os/signal" "syscall" "git.knownelement.com/ukrrs/mopac-keyproxy/internal/backend" "git.knownelement.com/ukrrs/mopac-keyproxy/internal/config" "git.knownelement.com/ukrrs/mopac-keyproxy/internal/server" ) const usage = `keyproxy: resolve mpk- placeholder refs to key material Usage: keyproxy serve [-config PATH] [-listen ADDR] run the resolve HTTP hop keyproxy get REF [-config PATH] resolve one ref to stdout keyproxy help print this usage Backends (v0): file (0600 env files), env (process env); bitwarden and vault are explicit not-implemented stubs until phase 3. Material is memory-only: never persisted, never logged. Exit codes: 0 ok, 1 usage/config error, 2 resolution failure. ` func main() { os.Exit(run(os.Args[1:])) } func run(args []string) int { if len(args) == 0 { fmt.Fprint(os.Stderr, usage) return 1 } switch args[0] { case "help", "-h", "--help": fmt.Print(usage) return 0 case "serve": return cmdServe(args[1:]) case "get": return cmdGet(args[1:]) default: fmt.Fprintf(os.Stderr, "keyproxy: unknown command %q\n\n%s", args[0], usage) return 1 } } // newRegistry wires every backend behind one interface; phase-3 // connectors replace the stubs in this single place. func newRegistry() *backend.Registry { return backend.NewRegistry( backend.NewFile(), backend.NewEnv(), backend.NewBitwarden(), backend.NewVault(), ) } func loadConfig(path string) (*config.Config, error) { if path == "" { path = os.Getenv("KEYPROXY_CONFIG") } if path == "" { path = "keyproxy.toml" } return config.Load(path) } func cmdServe(args []string) int { fs := flag.NewFlagSet("serve", flag.ContinueOnError) configPath := fs.String("config", "", "config file (default $KEYPROXY_CONFIG, then ./keyproxy.toml)") listen := fs.String("listen", "", "bind address (overrides config listen)") if err := fs.Parse(args); err != nil { return 1 } cfg, err := loadConfig(*configPath) if err != nil { fmt.Fprintf(os.Stderr, "keyproxy: %v\n", err) return 1 } if *listen != "" { cfg.Listen = *listen } srv, err := server.New(cfg, newRegistry(), os.Stdout) if err != nil { fmt.Fprintf(os.Stderr, "keyproxy: %v\n", err) return 1 } ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() if err := srv.ListenAndServe(ctx); err != nil { fmt.Fprintf(os.Stderr, "keyproxy: %v\n", err) return 1 } return 0 } func cmdGet(args []string) int { fs := flag.NewFlagSet("get", flag.ContinueOnError) configPath := fs.String("config", "", "config file (default $KEYPROXY_CONFIG, then ./keyproxy.toml)") if err := fs.Parse(args); err != nil { return 1 } if fs.NArg() != 1 { fmt.Fprintln(os.Stderr, "keyproxy get: exactly one ref required (mpk-)") return 1 } name := fs.Arg(0) cfg, err := loadConfig(*configPath) if err != nil { fmt.Fprintf(os.Stderr, "keyproxy: %v\n", err) return 1 } ref, ok := cfg.Refs[name] if !ok { fmt.Fprintf(os.Stderr, "keyproxy: ref %s: unknown_ref\n", name) return 2 } b, ok := newRegistry().Get(ref.Backend) if !ok { fmt.Fprintf(os.Stderr, "keyproxy: ref %s: backend %s not registered\n", name, ref.Backend) return 2 } value, err := b.Resolve(context.Background(), ref) if err != nil { fmt.Fprintf(os.Stderr, "keyproxy: %v\n", backend.AsResolveError(err, ref, ref.Backend)) return 2 } // No trailing newline: exec-style plumbing ($(keyproxy get mpk-x)) // wants the bare value. fmt.Print(value) return 0 }