Command Log Classifier
Summarize command outcomes and redact the specified token pattern from captured output.
Implement classify_command_log(events), a helper that summarizes shell commands from an agent run.
Requirements
- Each event is a dictionary with
cmd,exit_code, and optionalstdout/stderr(missing streams are empty). - Return a dictionary with
status,total,failed,first_failure_cmd, andredacted_logs. statusis"passed"when no command failed, otherwise"failed".- A command fails when
exit_code != 0. - Output on
stderrdoesn't make a zero-exit command fail; warnings still appear inredacted_logs. first_failure_cmdis the first failing command, orNone.redacted_logsis a list of strings built fromstdoutthenstderrfor each event in order.- Split each stream with newline rules equivalent to
str.splitlines(); emit one entry per resulting line (including blank internal lines). - Each entry uses the format
"{stream}: {line}"(for example"stdout: one","stderr: err [REDACTED]"). Empty or missing streams contribute no entries. - Redact secret tokens matching the regex
sk-[A-Za-z0-9_-]+by replacing each match with[REDACTED](token-level replace, not whole-line wipe).
Assume well-formed input: cmd is a string, exit_code is an integer, and present output streams are strings. Input validation isn't required. Empty input is passed with zero counts, no first failure, and no logs. Negative exit codes count as failures too.
The redaction rule applies only to stdout/stderr entries. first_failure_cmd is copied unchanged, and other secret formats remain unchanged. This exercise's narrow regex doesn't establish that arbitrary output is safe to publish. Matching is case-sensitive and can occur anywhere in a line; sk- alone doesn't match because the suffix needs at least one allowed character.
The supplied event order and stdout-before-stderr order define the result. Separate captured streams don't reveal their original chronological interleaving.
Example
events = [
{"cmd": "pytest", "exit_code": 1, "stdout": "", "stderr": "failed"},
{"cmd": "print", "exit_code": 0, "stdout": "sk-live", "stderr": "err sk-test_2"},
]
summary = classify_command_log(events)
assert summary["status"] == "failed"
assert summary["total"] == 2
assert summary["failed"] == 1
assert summary["first_failure_cmd"] == "pytest"
assert summary["redacted_logs"] == [
"stderr: failed",
"stdout: [REDACTED]",
"stderr: err [REDACTED]",
]Line separators are removed, internal blank lines remain, and a terminal separator doesn't create an extra trailing entry. For example, stdout "one\r\n\r\ntwo\n" produces "stdout: one", "stdout: ", "stdout: two". A stream containing just "\n" produces one blank entry; an empty stream produces none.
Constraints
- Preserve log line order.
- Leave inputs untouched.