fix(messagescan): guard inspects scan-helper call arguments
What this does
Hardens the internal/messagescan guard so it catches a registry-supplied value rendered into a failure message through redact.ScanContent alone.
Problem
isRegistryExpr classified an *ast.CallExpr by the call's own selector name. Only the string(x) conversion recursed into the call's arguments. So redact.ScanContent(herr.ContentType) was judged on ScanContent — not a registry selector — and read as clean; the argument herr.ContentType was never inspected.
The consequence: a bare-scan render site that interpolates a registry value through ScanContent on its own passes the guard. !283 closed every such site in pkg/conformance/{oci,maven,npm}, and the guard is what should stop the next one — but it could not see it. TestCase.Message is public API that a library consumer reads directly, so this is defence in depth.
Reported by @mkhalifa3 in !283 (merged) (note_3829912751).
Fix
Look through a scan-helper call to its arguments, the same way the walk already looks through a string() conversion. A new explicit scanHelpers list names redact's lower-level passes — ScanContent and RedactURLUserinfo — each of which returns a string derived from its argument but is not the message scrub, so a registry value handed to one directly still renders unscrubbed. The list is explicit for the same reason scrubWrappers is: a pass that renders its argument belongs there deliberately, because a call the walk cannot classify reads as clean.
The exclusion the issue calls for is preserved: a call that renders its own result rather than an argument (len(resp.Body) is an int, not the body) is not a scan helper, so it is judged on its own selector name and its arguments are not walked.
Blast radius: none
Running the hardened guard against the tree is green — !283 already routed every bare-scan render site in the three modules through scrubForMessage, so no render site needed changing in this MR. This is guard-logic only; no production code changes.
Testing
go test ./internal/messagescan/...passes.- Added
TestIsRegistryExpr, a table test pinning the classifier: a registry value insideScanContent/RedactURLUserinfo/string()is caught;scrubForMessage(...),len(resp.Body), and a non-registry selector are not. - Manually injected a temporary
fmt.Sprintf(..., redact.ScanContent( herr.ContentType))into the maven module and confirmed the guard fails on it, then thatlen(resp.Body)leaves it green.
Closes #81 (closed)