From bed51280aacb3774ae83933eaff5de8d6cff04dc Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 27 Apr 2026 21:57:01 +0200 Subject: [PATCH 1/2] Add failing test for incorrect prefix-based match --- FAIL: TestMatchAbsoluteRejectsPathWithBasePrefixOnly (0.00s) match_test.go:293: unexpected match for path outside base directory; expected nil, got file.txt FAIL FAIL github.com/boyter/gocodewalker/go-gitignore 0.287s FAIL --- go-gitignore/match_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/go-gitignore/match_test.go b/go-gitignore/match_test.go index 3ae24e0..2289c60 100644 --- a/go-gitignore/match_test.go +++ b/go-gitignore/match_test.go @@ -276,6 +276,24 @@ func TestMatchAbsolute(t *testing.T) { } } // TestMatchAbsolute() +func TestMatchAbsoluteRejectsPathWithBasePrefixOnly(t *testing.T) { + _buffer, _err := buffer("file.txt\n") + if _err != nil { + t.Fatalf("unable to create temporary .gitignore: %s", _err.Error()) + } + + _ignore := gitignore.New(_buffer, _GITBASE, nil) + if _ignore == nil { + t.Fatal("expected non-nil GitIgnore instance; nil found") + } + + _path := _GITBASE + "xfile.txt" + _match := _ignore.Absolute(_path, false) + if _match != nil { + t.Fatalf("unexpected match for path outside base directory; expected nil, got %v", _match) + } +} + func TestMatchRelative(t *testing.T) { // create a temporary .gitignore _buffer, _err := buffer(_GITMATCH) From 3cd08b4b4649a42c10d32267efe53298c5c3452f Mon Sep 17 00:00:00 2001 From: Varun Gandhi Date: Mon, 27 Apr 2026 22:09:40 +0200 Subject: [PATCH 2/2] Fix bug with incorrect handling of prefixes --- go-gitignore/gitignore.go | 20 +++++++++++++------- go-gitignore/repository.go | 9 ++------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/go-gitignore/gitignore.go b/go-gitignore/gitignore.go index e0b5df2..cce429b 100644 --- a/go-gitignore/gitignore.go +++ b/go-gitignore/gitignore.go @@ -268,18 +268,24 @@ func (i *ignore) MatchIsDir(path string, _isdir bool) Match { // the path is not located under the base directory of this GitIgnore, or // is not matched by this GitIgnore, nil is returned. func (i *ignore) Absolute(path string, isdir bool) Match { - // does the file share the same directory as this ignore file? - if !strings.HasPrefix(path, i._base) { + _rel, ok := relativeToBase(i._base, path) + if !ok { return nil } - - // extract the relative path of this file - _prefix := len(i._base) + 1 // BOYTERWASHERE - //_prefix := len(i._base) - _rel := string(path[_prefix:]) return i.Relative(_rel, isdir) } // Absolute() +func relativeToBase(base, path string) (string, bool) { + _rel, _err := filepath.Rel(base, path) + if _err != nil { + return "", false + } + if _rel == ".." || strings.HasPrefix(_rel, ".."+string(filepath.Separator)) { + return "", false + } + return _rel, true +} + // Relative attempts to match a path relative to the GitIgnore base // directory. isdir is used to indicate whether the path represents a file // or a directory. If the path is not matched by the GitIgnore, nil is diff --git a/go-gitignore/repository.go b/go-gitignore/repository.go index 1a69cdf..df56f74 100644 --- a/go-gitignore/repository.go +++ b/go-gitignore/repository.go @@ -5,7 +5,6 @@ package gitignore import ( "os" "path/filepath" - "strings" ) const File = ".gitignore" @@ -197,14 +196,10 @@ func (r *repository) Match(path string) Match { // path is not located under the base directory of this repository, or is not // matched by this repository, nil is returned. func (r *repository) Absolute(path string, isdir bool) Match { - // does the file share the same directory as this ignore file? - if !strings.HasPrefix(path, r.Base()) { + _rel, ok := relativeToBase(r.Base(), path) + if !ok { return nil } - - // extract the relative path of this file - _prefix := len(r.Base()) + 1 - _rel := string(path[_prefix:]) return r.Relative(_rel, isdir) } // Absolute()