// agent-token: the forge's read credential for each node's agent (novox/hq ADR 0365 clauses 1, 3, 4 and 5; issue // 737). A process the node's runtime launches and speaks MCP over stdio to, beside the module's other bundles. // // It serves one tool, gitea_agent_token, which the vault alone asks (ADR 0349 clause 10, issue 749): for each holder // of the provision `gitea-read` the vault names — the claude-code module on one machine — it makes that machine's // agent a forge account of its own, `agent-`, no administrator and in no team, mints it a token whose one // scope is `read:repository`, and answers the git credential lines for it, each holder's sealed to the key the vault // made for the call. Asked again, it mints again and deletes the account's token from before: that is its rotation. // // stdout is the protocol; it says what it says on stderr, and never a token or the admin's password. package main import ( "fmt" "os" stdio "git.novox.be/novox/mesh-sdk/go" ) // ToolNames are the tools this bundle serves. The module's manifest lists no `tools` (see the npm-registry bundle // for why); the README names this one, and a test holds the three together. var ToolNames = []string{ToolName} func main() { if err := stdio.Serve("", Tools(MinterFromEnv)); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } // Tools are the bundle's tools over the minter the function gives, asked per call, so a manifest that does not set // the environment is a refusal naming what is missing, not a bundle that will not start. func Tools(minter func() (*Minter, error)) []stdio.Tool { return []stdio.Tool{{ Name: ToolName, Description: "The forge's read credential for each node's agent (novox/hq ADR 0365), answered to the vault " + "alone: for each holder named, a forge account of the node's agent's own (agent-), no administrator " + "and in no team, and a token of scope read:repository minted for it anew, its git credential lines " + "sealed to seal_to. Any other caller is refused and nothing is minted.", Input: map[string]any{ "type": "object", "properties": map[string]any{ "provision": map[string]any{"type": "string", "description": "the provision, " + Provision}, "seal_to": map[string]any{"type": "string", "description": "the key made for this call, base64"}, "holders": map[string]any{ "type": "array", "description": "the provision's holders: each a consuming module on one machine", "items": map[string]any{"type": "object", "properties": map[string]any{ "node": map[string]any{"type": "string"}, "module": map[string]any{"type": "string"}, }}, }, }, "required": []string{"provision", "seal_to", "holders"}, }, Run: func(args map[string]any) (any, error) { caller := stdio.CallerOf(args) if err := fromTheVault(caller); err != nil { return nil, err } ask, err := readAsk(args) if err != nil { return nil, err } m, err := minter() if err != nil { return nil, err } return m.Answer(ask) }, }} }