Skip to main content

Module logging

Module logging 

Source
Expand description

A command-logging ProcessRunner decorator and its argv redaction.

LoggingRunner wraps any real ProcessRunner (the default JobRunner, a ManagedClient’s inner runner, a test double) and reports every command it runs — program, argv, working directory, exit code, and duration — to a CommandObserver. Because it sits on the single seam every wrapper spawns through, coverage is complete by construction: it observes all of vcs-git / vcs-jj / the forge wrappers without any per-call-site instrumentation, and it can’t drift out of date when a new operation is added.

§Why this is a security boundary

Logging argv is delicate: the value slots can carry a PR/issue body, a commit message, a clone URL, or — in principle — a secret. This module never emits a value verbatim. redact_args applies a fail-closed policy before anything reaches an observer:

  • The value after a sensitive flag (--token, --password, --secret, --authorization, …) is replaced with <redacted>, as is the value of a --flag=value form of one.
  • A value that contains a secret shape (a ghp_/github_pat_/glpat-/… token prefix, or an x-access-token: embed) is replaced with <redacted>.
  • A URL with userinfo (scheme://user@host/… or scheme://user:pass@host/…) keeps its host/path but masks the userinfo (scheme://<redacted>@host/…). The conventional non-secret ssh://git@host/… form remains visible.
  • Any long free-text value (a PR/issue body, a commit message) is truncated to MAX_VALUE_LEN characters plus a length marker.

This is defence in depth on top of the workspace’s existing “the token never rides in argv” contract (forge tokens travel in GH_TOKEN/GITLAB_TOKEN environment, git’s secret via credential.helper) — the decorator never logs the environment at all, so the token-carrying channel is out of scope for the log by construction, and the argv redaction guards the residual risk.

The default StderrObserver writes a one-line summary to stderr, never stdout — so a JSON-RPC transport sharing the process’s stdout (the vcs-mcp server) stays a clean transport. Supply your own CommandObserver to route the same structured record into tracing, a file, or a test buffer instead.

Structs§

CommandRecord
A display-safe, already-redacted record of one command a LoggingRunner ran, handed to a CommandObserver. Every field is safe to print: args has been through redact_args, and status carries no captured process output.
LoggingRunner
A ProcessRunner decorator that reports every command it runs to a CommandObserver, then forwards the real runner’s result unchanged.
StderrObserver
The default CommandObserver: writes one line per command to stderr (never stdout, so a stdout JSON-RPC transport stays clean), prefixed with a short tag. Format: `<tag>: <program> <args…> (cwd: <dir>) -> <status> in <dur>`.

Enums§

CommandStatus
How an observed command finished. Carries no captured stdout/stderr — only a coarse, allocation-free category — so an observer can never leak process output (which could echo user text) into a log.

Constants§

MAX_VALUE_LEN
The longest a single free-text argv value is rendered before it is truncated with a …(<n> chars) marker. Normal argv (subcommands, flags, refs, paths, revsets) sits well under this, so it only ever clips genuinely large values — a PR/issue body, a long commit message — keeping the log both readable and free of bulk user text. The exact number is not load-bearing.

Traits§

CommandObserver
A sink for the command records a LoggingRunner produces. Implement it to route the (already-redacted) CommandRecord into tracing, a file, a metrics counter, or a test buffer; the built-in StderrObserver writes a one-line summary to stderr.

Functions§

redact_args
Redact a command’s argv for display: mask secret-bearing values, mask the userinfo of a URL, and truncate long free text — see the module docs for the full policy. Returns one display string per input argument, in order. The policy is fail-closed: when in doubt it masks.
redact_value
Redact one free-text value without sequence-aware flag handling or truncation.