Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/config/profiles_v3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func TestProfileConfig_LegacyRoundTrip(t *testing.T) {

out, err := json.Marshal(p)
require.NoError(t, err)
require.JSONEq(t, src, string(out))
require.Equal(t, src, string(out))
}

// TestProfileConfig_V3FieldsParse pins that every v3 field round-trips and
Expand Down
7 changes: 5 additions & 2 deletions internal/profile/glob.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@ type globMatcher struct {
// compileGlob compiles a "server:tool" rule pattern into an anchored
// matcher. The pattern is assumed already validated (config.ValidateProfiles,
// FR-004) — an unparsable pattern here would be a validator bug, not a
// runtime condition, so this never errors.
// runtime condition, so this never errors. The (?s) flag makes '*' (".*")
// match embedded newlines too: a tool identity is upstream-controlled text,
// and without it a deny pattern like "github:delete*" would silently fail
// open on "github:delete\nrepo".
func compileGlob(pattern string) *globMatcher {
return &globMatcher{pattern: pattern, re: regexp.MustCompile("^" + globToRegexp(pattern) + "$")}
return &globMatcher{pattern: pattern, re: regexp.MustCompile("(?s)^" + globToRegexp(pattern) + "$")}
}

// globToRegexp renders pattern as an anchor-free regexp fragment: '*'
Expand Down
5 changes: 4 additions & 1 deletion internal/profile/glob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ func TestGlobMatcher(t *testing.T) {
{"anchored: no partial prefix match", "github:list", "github:list_issues", false},
{"anchored: no partial suffix match", "github:issues", "github:list_issues", false},
{"case-sensitive", "github:List_Issues", "github:list_issues", false},
{"tool name containing a slash", "filesystem:read_text_file", "filesystem:read_text_file", true},
{"underscored tool name, exact", "filesystem:read_text_file", "filesystem:read_text_file", true},
{"tool name containing a slash, exact", "ns:sub/erase", "ns:sub/erase", true},
{"tool name containing a slash, glob", "ns:sub/*", "ns:sub/erase", true},
{"tool name containing double underscore (direct-surface alias shape)", "github:list__issues", "github:list__issues", true},
{"tool identity with an embedded colon (namespaced raw name)", "a:ns:erase", "a:ns:erase", true},
{"tool identity with an embedded colon, mismatch", "a:ns:erase", "a:ns:wipe", false},
{"literal dot is not a regex any-char wildcard", "github:v1.0-sync", "github:v1.0-sync", true},
{"literal dot near-miss: dot must match exactly, not any char", "github:v1.0-sync", "github:v1x0-sync", false},
{"star matches an embedded newline (deny rules must not fail open)", "github:delete*", "github:delete\nrepo", true},
{"leading star matches across a newline", "github:*repo", "github:delete\nrepo", true},
{"literal hyphen", "github:v1.0-sync", "github:v1.0_sync", false},
}
for _, tc := range cases {
Expand Down
7 changes: 5 additions & 2 deletions internal/server/profiles_v3_node_fixture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,11 @@ var wantNodeFixtureTools = map[string]wantNodeFixtureTool{

// nodeFixtureFileTools is which tools each per-server file must contain, in
// order (matches enforcementMatrixProfiles' upstream registration order in
// profiles_v3_fixture_test.go, so the two fixtures never drift apart on
// content even though they are read by different runtimes).
// profiles_v3_fixture_test.go). Only the tool names and their order are kept
// in step across the two fixtures; per-tool descriptions and annotation
// shapes intentionally differ (the JSON files use description==name and a
// single hint, the in-process fixture uses descriptive text and sets both
// readOnlyHint and destructiveHint).
var nodeFixtureFileTools = map[string][]string{
"github": {"list_issues", "create_issue", "delete_repo", "search_code", "get_secret_scanning_alert"},
"notion": {"update_page"},
Expand Down
Loading