From faf55fe6a43ef77e88894cfdc3244131651caabd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:53:19 +0000 Subject: [PATCH 1/2] Initial plan From d58cd06589c0847cf5387a99add3076642cdf4c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 18 Aug 2026 04:55:31 +0000 Subject: [PATCH 2/2] Extract shared splitTagScope helper in difc violations formatting Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- internal/difc/format_functions_test.go | 55 ++++++++++++++++++++++++++ internal/difc/violations.go | 30 +++++++++----- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/internal/difc/format_functions_test.go b/internal/difc/format_functions_test.go index cf38b133d..aa2eaaa17 100644 --- a/internal/difc/format_functions_test.go +++ b/internal/difc/format_functions_test.go @@ -177,3 +177,58 @@ func TestFormatSecrecyLevel(t *testing.T) { }) } } + +// TestSplitTagScope tests the shared tag/scope splitting helper. +func TestSplitTagScope(t *testing.T) { + tests := []struct { + name string + tag Tag + wantBase string + wantScope string + }{ + { + name: "tag without scope", + tag: "public", + wantBase: "public", + wantScope: "", + }, + { + name: "tag with scope", + tag: "approved:all", + wantBase: "approved", + wantScope: "all", + }, + { + name: "scope containing colons is preserved", + tag: "private:org/repo:extra", + wantBase: "private", + wantScope: "org/repo:extra", + }, + { + name: "empty scope suffix", + tag: "private:", + wantBase: "private", + wantScope: "", + }, + { + name: "leading colon is not split", + tag: ":all", + wantBase: ":all", + wantScope: "", + }, + { + name: "empty tag", + tag: "", + wantBase: "", + wantScope: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + base, scope := splitTagScope(tt.tag) + assert.Equal(t, tt.wantBase, base) + assert.Equal(t, tt.wantScope, scope) + }) + } +} diff --git a/internal/difc/violations.go b/internal/difc/violations.go index f53334c27..e8a135a4e 100644 --- a/internal/difc/violations.go +++ b/internal/difc/violations.go @@ -120,6 +120,17 @@ func FormatViolationError(result *EvaluationResult, agentSecrecy *SecrecyLabel, return errors.New(msg.String()) } +// splitTagScope splits a tag into its base level and optional scope suffix +// (e.g., "approved:all" → ("approved", "all"), "public" → ("public", "")). +// A tag whose only colon is at the start (e.g., ":all") is returned unsplit. +func splitTagScope(tag Tag) (base, scope string) { + s := string(tag) + if idx := strings.Index(s, ":"); idx > 0 { + return s[:idx], s[idx+1:] + } + return s, "" +} + // formatIntegrityLevel converts a list of integrity tags into a human-readable // integrity level description (e.g., `"approved"` instead of "[unapproved:all approved:all]"). func formatIntegrityLevel(tags []Tag) string { @@ -129,11 +140,7 @@ func formatIntegrityLevel(tags []Tag) string { // Find the highest integrity level mentioned in the tags highest := "" for _, tag := range tags { - s := string(tag) - // Strip scope suffix (e.g., "approved:all" → "approved") - if idx := strings.Index(s, ":"); idx > 0 { - s = s[:idx] - } + s, _ := splitTagScope(tag) switch s { case "merged": logViolations.Printf("formatIntegrityLevel: resolved to \"merged\" from tags=%v", tags) @@ -164,15 +171,18 @@ func formatSecrecyLevel(tags []Tag) string { hasPrivate := false for _, tag := range tags { - s := string(tag) - if strings.HasPrefix(s, "private:") { - scope := strings.TrimPrefix(s, "private:") - if scope != "" && len(scope) > len(bestScope) { + base, scope := splitTagScope(tag) + if base != "private" { + continue + } + if scope != "" { + if len(scope) > len(bestScope) { bestScope = scope } continue } - if s == "private" { + // No scope suffix at all (as opposed to an empty "private:" scope) + if string(tag) == "private" { hasPrivate = true } }