TestSubmoduleRepositoryRejectsEscapingName covers the storage-layer defence against submodule name path traversal. Constructing a Submodule with `Name = ".."` programmatically (bypassing the .gitmodules parser) must not result in `Repository()` opening a storer rooted in the parent's `.git/` directo
(c *C)
| 586 | // storer rooted in the parent's `.git/` directory, and must leave the |
| 587 | // parent's HEAD reference untouched. |
| 588 | func (s *SubmoduleSuite) TestSubmoduleRepositoryRejectsEscapingName(c *C) { |
| 589 | dotfs := memfs.New() |
| 590 | wtfs := memfs.New() |
| 591 | // Use filesystem.NewStorage rather than memory.NewStorage for the |
| 592 | // parent because only the filesystem-backed ModuleStorer exercises |
| 593 | // the dotgit defence; the in-memory implementation maps names to |
| 594 | // storage units directly without traversing a path. |
| 595 | storer := filesystem.NewStorage(dotfs, cache.NewObjectLRUDefault()) |
| 596 | r, err := Init(storer, wtfs) |
| 597 | c.Assert(err, IsNil) |
| 598 | |
| 599 | wt, err := r.Worktree() |
| 600 | c.Assert(err, IsNil) |
| 601 | |
| 602 | headBefore, err := storer.Reference(plumbing.HEAD) |
| 603 | c.Assert(err, IsNil) |
| 604 | |
| 605 | sm := &Submodule{ |
| 606 | initialized: true, |
| 607 | c: &config.Submodule{ |
| 608 | Name: "..", |
| 609 | Path: "deps/x", |
| 610 | URL: "https://example.com/", |
| 611 | }, |
| 612 | w: wt, |
| 613 | } |
| 614 | |
| 615 | repo, err := sm.Repository() |
| 616 | c.Assert(err, NotNil) |
| 617 | c.Assert(errors.Is(err, dotgit.ErrModuleNameEscape), Equals, true) |
| 618 | c.Assert(repo, IsNil) |
| 619 | |
| 620 | headAfter, err := storer.Reference(plumbing.HEAD) |
| 621 | c.Assert(err, IsNil) |
| 622 | c.Assert(headBefore.Target(), Equals, headAfter.Target(), |
| 623 | Commentf("parent HEAD must not be overwritten")) |
| 624 | } |
nothing calls this directly
no test coverage detected