diff options
| author | Madeline Kalil <mkalil@google.com> | 2026-03-31 13:34:41 -0400 |
|---|---|---|
| committer | Madeline Kalil <mkalil@google.com> | 2026-04-08 07:19:42 -0700 |
| commit | 5c3cacb5982231e5d4acd75f6c4cf1bb8f7ba411 (patch) | |
| tree | 3641b80eb19d692f8823f213e3a8e3562361c6c0 | |
| parent | f1e456b85e628969cdc65e0fec050038e653d1a0 (diff) | |
| download | go-x-pkgsite-5c3cacb5982231e5d4acd75f6c4cf1bb8f7ba411.tar.xz | |
internal/postgres: allow matching exact prefix with exact:
Currently, the package exclusion process is case insensitive, because certain hosts such as GitHub are case insensitive.
The only way to exclude a case sensitive version without also excluding all case insensitive matches is to add the prefix to caseSensitiveExcludedPaths in internal/frontend/details.go.
This CL implements a new approach to excluding case sensitive paths: it enables specifying an "exact:" prefix in excluded.txt that will force matching the pattern exactly, instead of with case insensitivity.
For golang/go#77822
Change-Id: I123ad2e13ff6673084006c6d51377308d95230ce
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/761521
kokoro-CI: kokoro <noreply+kokoro@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Ethan Lee <ethanalee@google.com>
| -rw-r--r-- | internal/frontend/details.go | 2 | ||||
| -rw-r--r-- | internal/postgres/excluded.go | 26 | ||||
| -rw-r--r-- | internal/postgres/excluded_test.go | 13 |
3 files changed, 29 insertions, 12 deletions
diff --git a/internal/frontend/details.go b/internal/frontend/details.go index 27b40f05..f1438de4 100644 --- a/internal/frontend/details.go +++ b/internal/frontend/details.go @@ -103,6 +103,8 @@ func checkExcluded(ctx context.Context, ds internal.DataSource, fullPath, versio // Paths to exclude if they match exactly. // These are very rare, so it's simpler to hardcode them rather than use the DB. +// TODO(mkalil): Remove once go.dev/cl/761521, which provides an alternative +// implementation for case sensitive exclusions, is merged. var caseSensitiveExcludedPaths = map[string]bool{ "github.com/ibm/sarama": true, // https://go.dev/issue/71342 "github.com/burntsushi/toml": true, // https://go.dev/issue/68357 diff --git a/internal/postgres/excluded.go b/internal/postgres/excluded.go index 176b9c7e..6225c6b3 100644 --- a/internal/postgres/excluded.go +++ b/internal/postgres/excluded.go @@ -31,22 +31,28 @@ func (db *DB) IsExcluded(ctx context.Context, path, version string) bool { func excludes(pattern, path, version string) bool { // Certain hosts (such as GitHub) are case insensitive. - // Therefore, we err on the side of insensitive exclusions. + // By default, we err on the side of insensitive exclusions. + // If the pattern starts with "exact:", we match exactly (case sensitive). + isExact := strings.HasPrefix(pattern, "exact:") + if isExact { + pattern = pattern[len("exact:"):] + } - // Patterns with "@" must match the full path (case insensitively). mod, ver, found := strings.Cut(pattern, "@") if found { + if isExact { + return mod == path && ver == version + } return strings.EqualFold(mod, path) && ver == version } - // Patterns without "@" can match the full path or be a componentwise prefix - // (case insensitively). - if strings.EqualFold(pattern, path) { - return true - } - if !strings.HasSuffix(pattern, "/") { - pattern += "/" + + pattern = strings.TrimSuffix(pattern, "/") + + if isExact { + return pattern == path || strings.HasPrefix(path, pattern+"/") } - return strings.HasPrefix(strings.ToLower(path), strings.ToLower(pattern)) + return strings.EqualFold(pattern, path) || + strings.HasPrefix(strings.ToLower(path), strings.ToLower(pattern)+"/") } // InsertExcludedPattern inserts pattern into the excluded_prefixes table. diff --git a/internal/postgres/excluded_test.go b/internal/postgres/excluded_test.go index 13206a85..e8050aee 100644 --- a/internal/postgres/excluded_test.go +++ b/internal/postgres/excluded_test.go @@ -15,7 +15,7 @@ func TestIsExcluded(t *testing.T) { defer release() ctx := context.Background() - for _, pat := range []string{"bad", "badslash/", "baddy@v1.2.3", "github.com/bad"} { + for _, pat := range []string{"bad", "badslash/", "baddy@v1.2.3", "github.com/bad", "exact:github.com/CASE/go", "exact:github.com/PACKAGE@v1.0.0"} { if err := testDB.InsertExcludedPattern(ctx, pat, "someone", "because"); err != nil { t.Fatal(err) } @@ -31,7 +31,7 @@ func TestIsExcluded(t *testing.T) { {"badness", "", false}, {"bad/ness", "", true}, {"bad.com/foo", "", false}, - {"badslash", "", false}, + {"badslash", "", true}, {"badslash/more", "", true}, {"badslash/more", "v1.2.3", true}, {"baddys", "v1.2.3", false}, @@ -48,6 +48,15 @@ func TestIsExcluded(t *testing.T) { {"github.com/bad/repo", "", true}, {"github.com/bad/Repo", "", true}, {"github.com/Bad/repo", "", true}, + + // tests for exact: prefix + {"github.com/CASE/go", "", true}, + {"github.com/case/go", "", false}, + {"github.com/CASE/go/sub", "", true}, + {"github.com/case/go/sub", "", false}, + {"github.com/PACKAGE", "v1.0.0", true}, + {"github.com/package", "v1.0.0", false}, + {"github.com/PACKAGE", "v1.0.1", false}, } { got := testDB.IsExcluded(ctx, test.path, test.version) if got != test.want { |
