docker: find and hide secrets a container printed into its log (hq issue 268)
letta printed two passwords into its log for weeks and nothing noticed, and docker_logs handed them to whoever asked. docker_secrets_in_logs compares each container's recent lines with the secret-named values of its environment, the passwords in its URIs, and any URI carrying a password, and names what it found by container, module and variable - never the value. docker_logs redacts the same values before answering.
This commit is contained in:
@@ -71,8 +71,9 @@ func tools(c *Client) []stdio.Tool {
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "docker_logs",
|
||||
Description: "The last lines one container wrote, both streams merged in order, each with its timestamp (default 200, at most 2000 lines; a line is cut at 4 KiB).",
|
||||
Name: "docker_logs",
|
||||
Description: "The last lines one container wrote, both streams merged in order, each with its timestamp (default 200, at most 2000 lines; a line is cut at 4 KiB). " +
|
||||
"A secret the container was given that it printed is shown as [redacted: <name>], and so is a password inside a URI.",
|
||||
Input: map[string]any{
|
||||
"container": containerArg,
|
||||
"lines": map[string]any{"type": "integer", "description": "how many lines from the end (default 200, at most 2000)"},
|
||||
@@ -90,6 +91,27 @@ func tools(c *Client) []stdio.Tool {
|
||||
return c.Logs(ctx, ref, n, optional(args, "since"))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "docker_secrets_in_logs",
|
||||
Description: "Which containers printed a secret they were given into their own log — by container, module and the secret's name, never its value: " +
|
||||
"each one's recent lines compared with the values of its environment named like a secret and the passwords in its URIs, and any URI carrying a password. " +
|
||||
"A finding is a secret to rotate once the program stops printing it (novox/hq issue 268).",
|
||||
Input: map[string]any{
|
||||
"held": map[string]any{"type": "string", "enum": []string{"all", "mesh", "other"}, "description": "whose: the mesh's (default), every container, or the others"},
|
||||
"lines": map[string]any{"type": "integer", "description": "how many lines from the end of each log (default 5000, at most 50000)"},
|
||||
},
|
||||
Run: func(args map[string]any) (any, error) {
|
||||
n, err := bounded(args, "lines", 5000, 50000)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
held := optional(args, "held")
|
||||
if held == "" {
|
||||
held = "mesh"
|
||||
}
|
||||
return c.SecretsInLogs(ctx, held, n)
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "docker_stats",
|
||||
Description: "What the running containers use now — CPU, memory, network and disk I/O, processes — the heaviest by memory first; or one container's.",
|
||||
|
||||
Reference in New Issue
Block a user