Summary
formatAnnotation in report/annotations.go emits GitHub Actions workflow commands without escaping the message or the property values (file, title). GitHub's workflow-command spec requires certain characters to be percent-encoded; without it, annotations with those characters are truncated, mis-rendered, or split into the wrong fields.
Details
The command is built as:
return fmt.Sprintf("::%s%s::%s", cmd, params, res.Message)
with params containing file=<path>, ,line=N, and ,title=<category>, all interpolated raw.
GitHub requires:
- Message data —
% → %25, \r → %0D, \n → %0A
- Property values (e.g.
file, title) — the above plus : → %3A and , → %2C
Impact
- A
res.Message containing a newline is cut off at the first \n (the runner treats the command as ending there), so multi-line messages lose everything after the first line.
- A literal
% in a message can be misinterpreted.
- A
title or file containing , prematurely ends the property and corrupts the parsed parameters; a : can break the key=value parsing.
These are most likely to surface as messages grow longer or include punctuation, paths on Windows (C:\...), or categories with commas.
Repro
A result with Message: "line one\nline two" produces:
::error file=skill/SKILL.md,line=1,title=Cat::line one
line two
GitHub parses only line one as the annotation; line two is dropped from the annotation (it appears as a normal log line).
Suggested fix
Add the two escaping helpers and apply escapeData to the message and escapeProperty to each property value:
func escapeData(s string) string {
s = strings.ReplaceAll(s, "%", "%25")
s = strings.ReplaceAll(s, "\r", "%0D")
s = strings.ReplaceAll(s, "\n", "%0A")
return s
}
func escapeProperty(s string) string {
s = escapeData(s)
s = strings.ReplaceAll(s, ":", "%3A")
s = strings.ReplaceAll(s, ",", "%2C")
return s
}
(The % replacement must run first so the other substitutions aren't double-encoded.)
Happy to send a PR if that's useful.
Summary
formatAnnotationinreport/annotations.goemits GitHub Actions workflow commands without escaping the message or the property values (file,title). GitHub's workflow-command spec requires certain characters to be percent-encoded; without it, annotations with those characters are truncated, mis-rendered, or split into the wrong fields.Details
The command is built as:
with
paramscontainingfile=<path>,,line=N, and,title=<category>, all interpolated raw.GitHub requires:
%→%25,\r→%0D,\n→%0Afile,title) — the above plus:→%3Aand,→%2CImpact
res.Messagecontaining a newline is cut off at the first\n(the runner treats the command as ending there), so multi-line messages lose everything after the first line.%in a message can be misinterpreted.titleorfilecontaining,prematurely ends the property and corrupts the parsed parameters; a:can break thekey=valueparsing.These are most likely to surface as messages grow longer or include punctuation, paths on Windows (
C:\...), or categories with commas.Repro
A result with
Message: "line one\nline two"produces:GitHub parses only
line oneas the annotation;line twois dropped from the annotation (it appears as a normal log line).Suggested fix
Add the two escaping helpers and apply
escapeDatato the message andescapePropertyto each property value:(The
%replacement must run first so the other substitutions aren't double-encoded.)Happy to send a PR if that's useful.