Doctor: expose config audit scrub findings#84450
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 12:26 PM ET / 16:26 UTC. Summary PR surface: Source +74, Tests +72. Total +146 across 5 files. Reproducibility: yes. for the changed behavior: seed Review metrics: 2 noteworthy metrics.
Stored data model Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Merge only after maintainer acceptance of the opt-in lint/security boundary, preserving broad-lint compatibility and the existing legacy scrub path as the real mutation path. Do we have a high-confidence way to reproduce the issue? Yes for the changed behavior: seed Is this the best way to solve the issue? Yes, this is the best observed implementation shape: it reuses the authoritative scrubber in dry-run mode, keeps real mutation in the legacy Doctor path, and keeps the warning out of broad lint by default. The remaining question is maintainer acceptance of the opt-in security/compatibility boundary, not a code defect. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 3217165be770. Label changesLabel justifications:
Evidence reviewedPR surface: Source +74, Tests +72. Total +146 across 5 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
|
ClawSweeper PR egg 🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat. Where did the egg go?
|
9b583fd to
4e84dd1
Compare
4e84dd1 to
b1ee397
Compare
c6afcfd to
828c1c8
Compare
828c1c8 to
72612ac
Compare
acd6c33 to
e7ccfb6
Compare
|
@clawsweeper re-review Updated the #84450 PR body for current head |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Rebased #84450 onto current Validation after rebase:
@clawsweeper please re-review current head. |
|
🦞👀 I queued a lightweight read-only assist pass. It will post a separate answer comment and will not edit the durable ClawSweeper review comment or trigger close, merge, repair, label, or branch changes. Request: please re-review current head. |
|
ClawSweeper assist: Current head is Evidence:
Suggested next action: Comment Source: #84450 (comment) |
|
@clawsweeper review Refreshed #84450 after #84340 merged and pushed current head Change made:
Validation at current head:
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
galiniliev
left a comment
There was a problem hiding this comment.
This adds a structured doctor lint check for historical config-audit argv scrub work while leaving normal doctor/doctor --fix on the existing legacy scrub path. That matters because the audit log can contain pre-redactor argv/execArgv secrets at rest, but broad lint should not start failing operators by default.
LOC: +193/-10 (9 files)
By: Gio Della-Libera (@giodl73-repo, acct 2025-09-30) | OpenClaw: 185 PRs, 14 issues, 134 commits/12mo | GitHub: 6339 commits, 219 PRs, 29 issues, 17 reviews/12mo
No blocking findings.
Affected surface: core doctor lint/health contribution plumbing and config-audit scrub preview/reporting: src/commands/doctor-config-audit-scrub.ts, src/config/io.audit.ts, src/flows/doctor-health-contributions.ts, src/flows/doctor-lint-flow.ts.
Behavior: explicit doctor --lint --only core/doctor/config-audit-scrub reports historical pre-redactor audit argv residue; broad doctor --lint skips the check by default; doctor --fix remains owned by maybeScrubConfigAuditLog.
Provenance: carried forward by config-audit scrub repair from commit 432b949 / #80777; this PR does not change the redactor or the on-disk rewrite algorithm, only exposes the existing dry-run result as structured health/lint output.
Best-fix verdict: best. The check is declared on the existing ordered doctor contribution, reuses scrubConfigAuditLog(... dryRun: true) and resolveConfigAuditLogPath, and does not create a second repair path for the sensitive rewrite.
Alternatives considered: make the check default-enabled in broad lint (rejected because it turns historical sensitive residue into a new broad lint failure); move the rewrite into structured repair (rejected because runConfigAuditScrubHealth already owns the real doctor/--fix append-race guarded cleanup); duplicate detection outside io.audit (rejected because it would drift from the authoritative redactor).
Code read: src/config/io.audit.ts, src/config/io.audit.test.ts, src/commands/doctor-config-audit-scrub.ts, src/commands/doctor-config-audit-scrub.test.ts, src/flows/doctor-health-contributions.ts, src/flows/doctor-health-contributions.test.ts, src/flows/doctor-lint-flow.ts, src/flows/doctor-lint-flow.test.ts, src/flows/doctor-repair-flow.ts, src/flows/health-check-adapter.ts, src/flows/health-check-runner-types.ts, src/commands/doctor-lint.ts.
Validation: On merge ref 332f3ad: OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs src/commands/doctor-config-audit-scrub.test.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-lint-flow.test.ts --reporter=dot passed 56 tests across 2 shards; pnpm exec oxfmt --check ... passed; pnpm exec oxlint ... passed; git diff --check origin/main...origin/pr/84450 passed.
Remaining uncertainty: I did not run full pnpm check or live Gateway concurrent append proof; the append-race behavior is unchanged here and covered by existing focused tests in src/config/io.audit.test.ts.
|
@clawsweeper review Refreshed #84450 after #84366 merged and pushed current head Change made:
Validation at current head:
|
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Merged via squash.
|
Summary
config-audit.jsonlargv/execArgvrecords through the current redactor.maybeScrubConfigAuditLogpath authoritative for real normaldoctor/doctor --fixbehavior, including the append-race abort guard.doctor --lintcompatible by makingcore/doctor/config-audit-scrubopt-in; operators can still run it explicitly with--only core/doctor/config-audit-scrub.defaultEnabledas internal runner selection metadata, not part of the publicHealthCheckSDK contract.This is intentionally the config-audit scrub slice from the doctor repair stack. It does not change config audit logging, redaction behavior for new records, or gateway runtime behavior.
Stack
Rebased onto current
mainafter #84366 merged. Current branch head is commitef2283d04fb61da1b9429e73b7c9a034b3dbb1dc(fix(doctor): remove duplicate lint default guard).The refreshed diff now relies on the merged internal default-selection runner metadata from #84366 and is limited to the config-audit scrub slice. The latest head also removes the behavior-neutral duplicate default-disabled lint filter flagged during final maintainer review.
Real behavior proof
Behavior or issue addressed:
Historical
config-audit.jsonlrecords that still contain pre-redactorargv/execArgvvalues are surfaced by structured doctor lint when explicitly selected, scrubbed bydoctor --fix, and then disappear from the same lint check after the rewrite. The rewrite keeps the audit log mode at0600and preserves already-redacted records. Broaddoctor --lintskips this compatibility-sensitive historical residue check by default.Real environment tested:
WSL2 Ubuntu 24.04 source checkout with isolated temporary
OPENCLAW_STATE_DIR,OPENCLAW_CONFIG_PATH, andHOME; syntheticconfig-audit.jsonlcontaining one historical unredacted record plus one already-safe record. Tokens in the proof summary below are redacted.Evidence after fix:
The first explicit lint reported exactly the structured config-audit scrub finding:
{ "lintBeforeStatus": 1, "lintBeforeOk": false, "lintBeforeChecksRun": 1, "lintBeforeChecksSkipped": 22, "lintBeforeFindings": [ { "checkId": "core/doctor/config-audit-scrub", "severity": "warning", "message": "1 entry in config-audit.jsonl still contain pre-redactor argv values.", "fixHint": "Run `openclaw doctor --fix` to rewrite argv/execArgv fields through the current redactor.", "pathBasename": "config-audit.jsonl" } ] }The fix pass and after-lint evidence from the same isolated state:
{ "fixOutputNeedles": { "scrubbedOneEntry": true, "rotateCredentials": true, "doctorComplete": true }, "lintAfterStatus": 0, "lintAfterOk": true, "lintAfterChecksRun": 1, "lintAfterFindings": [], "auditModeOctal": "0o600", "recordCountAfterFix": 3, "plaintextNeedlesRemain": { "slackToken": false, "openaiKey": false, "githubToken": false } }Observed result after fix:
The explicit lint failed with the expected
core/doctor/config-audit-scrubwarning.doctor --fix --yes --non-interactivescrubbed one historical config-audit entry and printed the rotate-credentials warning. The second explicit lint passed with no findings. The audit log stayed0600, and the token-shapedargvandexecArgvplaintext needles were gone after the rewrite. The current head keeps this historical residue check out of broad default lint while leaving the explicit--onlypath and fix behavior available.What was not tested:
No live Gateway was writing concurrently to the audit log during this proof; the existing append-race abort path remains covered by focused tests. Maintainer acceptance is still needed for the compatibility/security-boundary choice that historical config-audit residue is warning-level when explicitly selected, but skipped by default.
Validation
Current head
ef2283d04fb61da1b9429e73b7c9a034b3dbb1dc:OPENCLAW_VITEST_MAX_WORKERS=1 node scripts/run-vitest.mjs run src/commands/doctor-config-audit-scrub.test.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-lint-flow.test.ts --reporter=dot- 56 tests passed across 2 shardsnode_modules\.bin\oxlint.CMD src/commands/doctor-config-audit-scrub.test.ts src/commands/doctor-config-audit-scrub.ts src/config/io.audit.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-health-contributions.ts src/flows/doctor-lint-flow.test.ts src/flows/doctor-lint-flow.ts- passednode_modules\.bin\oxfmt.CMD --check src/commands/doctor-config-audit-scrub.test.ts src/commands/doctor-config-audit-scrub.ts src/config/io.audit.ts src/flows/doctor-health-contributions.test.ts src/flows/doctor-health-contributions.ts src/flows/doctor-lint-flow.test.ts src/flows/doctor-lint-flow.ts- passednode node_modules\@typescript\native-preview\bin\tsgo.js -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts\tsgo-cache\core.tsbuildinfo --declaration false --singleThreaded --checkers 1- passednode node_modules\@typescript\native-preview\bin\tsgo.js -p test\tsconfig\tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts\tsgo-cache\test-src.tsbuildinfo --declaration false --singleThreaded --checkers 1- passednode scripts/plugin-sdk-surface-report.mjs --check- passedgit diff --check origin/main...HEAD- passed