From c37b79ef3a8afd05d6263bcce124cedd739ef7c2 Mon Sep 17 00:00:00 2001 From: Francesc Campoy Date: Fri, 10 Apr 2026 18:21:07 -0700 Subject: [PATCH] Improve regex error messages to surface pattern in output Wrap regexp compile errors to include the full pattern string, making it easy to identify which directive failed and audit patterns in PR reviews. Update existing tests and add new cases covering the improved error format, missing-slashes validation, and a valid-pattern regression. Add a security note to the package godoc. Closes #83 --- embedmd/embedmd.go | 8 +++++++- embedmd/embedmd_test.go | 14 ++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/embedmd/embedmd.go b/embedmd/embedmd.go index aed9eea..7195f07 100644 --- a/embedmd/embedmd.go +++ b/embedmd/embedmd.go @@ -49,6 +49,12 @@ // go, this will fail with other files like .md whose language name is markdown. // // [embedmd]:# (file.ext) +// +// Security note: embed directives, including their regular expression patterns, +// are treated as trusted input. Markdown files containing embedmd directives +// should not be sourced from untrusted contributors without careful review, as +// a crafted regular expression could match unintended content from the embedded +// file. package embedmd import ( @@ -122,7 +128,7 @@ func extract(b []byte, start, end *string) ([]byte, error) { } re, err := regexp.CompilePOSIX(s[1 : len(s)-1]) if err != nil { - return nil, err + return nil, fmt.Errorf("invalid regexp %s: %v", s, err) } loc := re.FindIndex(b) if loc == nil { diff --git a/embedmd/embedmd_test.go b/embedmd/embedmd_test.go index dba20d1..3015ab6 100644 --- a/embedmd/embedmd_test.go +++ b/embedmd/embedmd_test.go @@ -62,14 +62,24 @@ func TestExtract(t *testing.T) { start: testutil.Ptr("/func main/"), end: testutil.Ptr("/}/"), out: "func main() {\n fmt.Println(\"hello, test\")\n}"}, {name: "bad start regexp", - start: testutil.Ptr("/(/"), err: "error parsing regexp: missing closing ): `(`"}, + start: testutil.Ptr("/(/"), err: "invalid regexp /(/: error parsing regexp: missing closing ): `(`"}, {name: "bad regexp", start: testutil.Ptr("something"), err: "missing slashes (/) around \"something\""}, {name: "bad end regexp", - start: testutil.Ptr("/fmt.P/"), end: testutil.Ptr("/)/"), err: "error parsing regexp: unexpected ): `)`"}, + start: testutil.Ptr("/fmt.P/"), end: testutil.Ptr("/)/"), err: "invalid regexp /)/: error parsing regexp: unexpected ): `)`"}, {name: "start and end of line ^$", start: testutil.Ptr("/^func main/"), end: testutil.Ptr("/}$/"), out: "func main() {\n fmt.Println(\"hello, test\")\n}"}, + + // Error message quality: invalid patterns should include the pattern string. + {name: "invalid regexp shows pattern in error", + start: testutil.Ptr("/[invalid/"), err: "invalid regexp /[invalid/: error parsing regexp: missing closing ]: `[invalid`"}, + // Missing slashes should report the raw value. + {name: "missing slashes reports value", + start: testutil.Ptr("noSlashes"), err: "missing slashes (/) around \"noSlashes\""}, + // Valid pattern regression: correctly matches a simple pattern. + {name: "valid pattern still works", + start: testutil.Ptr("/fmt\\.Println/"), out: "fmt.Println"}, } for _, tt := range tc {