feat(membershipd): one-command bot provisioning (bot add)
Add `membershipd bot add --handle <name> --out <path> [--role] [--store]` to provision a bus identity for an automated process in a single step: mint a fresh Ed25519+X25519 identity (cs.GenerateIdentity, the same derivation worker/chat use), register its signing key in the allowlist, and write the credentials to a 0600 file. The file is the canonical identity format read by client.LoadIdentity, so a worker/clientcheck binary pointed at --out connects as the new user with no extra conversion. Shares the sqlite/kv store plumbing with `user add`. New exported pkg/client.WriteNewIdentity writes an identity in that format but refuses to overwrite an existing file (never silently clobber private keys). provisionBot ordering guarantees no half-provisioned bot: refuse an existing --out before touching the store, register (an already-registered key is a clear error, not a panic), then write credentials. Tests cover the golden path (register + 0600 file + LoadIdentity round-trip), default role, the already-registered error path (no file written), and the out-exists error path (no orphan user). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,6 +47,14 @@ func main() {
|
||||
runMigrateCLI(os.Args[2:])
|
||||
return
|
||||
}
|
||||
// `membershipd bot add ...` provisions a bus identity for an automated process
|
||||
// in one command (mint identity + register + write 0600 credentials). It shares
|
||||
// the same trusted-host model and store plumbing as the user CLI, so it is
|
||||
// dispatched here before the server flag set parses os.Args.
|
||||
if len(os.Args) > 1 && os.Args[1] == "bot" {
|
||||
runBotCLI(os.Args[2:])
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
bind = flag.String("bind", "127.0.0.1", "network interface to bind the HTTP API and the embedded NATS to; use 0.0.0.0 to accept LAN/remote peers")
|
||||
|
||||
Reference in New Issue
Block a user