1.0 quality polish — code review, tests, bug fixes, documentation #32
@ -70,6 +70,8 @@ type Checker struct {
|
|||||||
fs afero.Fs
|
fs afero.Fs
|
||||||
// manifestPaths is a set of paths in the manifest for quick lookup
|
// manifestPaths is a set of paths in the manifest for quick lookup
|
||||||
manifestPaths map[RelFilePath]struct{}
|
manifestPaths map[RelFilePath]struct{}
|
||||||
|
// manifestRelPath is the relative path of the manifest file from basePath (for exclusion)
|
||||||
|
manifestRelPath RelFilePath
|
||||||
// signature info from the manifest
|
// signature info from the manifest
|
||||||
signature []byte
|
signature []byte
|
||||||
signer []byte
|
signer []byte
|
||||||
@ -100,14 +102,25 @@ func NewChecker(manifestPath string, basePath string, fs afero.Fs) (*Checker, er
|
|||||||
manifestPaths[RelFilePath(f.Path)] = struct{}{}
|
manifestPaths[RelFilePath(f.Path)] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compute manifest's relative path from basePath for exclusion in FindExtraFiles
|
||||||
|
absManifest, err := filepath.Abs(manifestPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
manifestRel, err := filepath.Rel(abs, absManifest)
|
||||||
|
if err != nil {
|
||||||
|
manifestRel = ""
|
||||||
|
}
|
||||||
|
|
||||||
return &Checker{
|
return &Checker{
|
||||||
basePath: AbsFilePath(abs),
|
basePath: AbsFilePath(abs),
|
||||||
files: files,
|
files: files,
|
||||||
fs: fs,
|
fs: fs,
|
||||||
manifestPaths: manifestPaths,
|
manifestPaths: manifestPaths,
|
||||||
signature: m.pbOuter.Signature,
|
manifestRelPath: RelFilePath(manifestRel),
|
||||||
signer: m.pbOuter.Signer,
|
signature: m.pbOuter.Signature,
|
||||||
signingPubKey: m.pbOuter.SigningPubKey,
|
signer: m.pbOuter.Signer,
|
||||||
|
signingPubKey: m.pbOuter.SigningPubKey,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,14 +322,13 @@ func (c *Checker) FindExtraFiles(ctx context.Context, results chan<- Result) err
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip manifest files
|
relPath := RelFilePath(rel)
|
||||||
base := filepath.Base(rel)
|
|
||||||
if base == "index.mf" || base == ".index.mf" {
|
// Skip the manifest file itself
|
||||||
|
if relPath == c.manifestRelPath {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
relPath := RelFilePath(rel)
|
|
||||||
|
|
||||||
// Check if path is in manifest
|
// Check if path is in manifest
|
||||||
if _, exists := c.manifestPaths[relPath]; !exists {
|
if _, exists := c.manifestPaths[relPath]; !exists {
|
||||||
if results != nil {
|
if results != nil {
|
||||||
|
|||||||
@ -452,6 +452,61 @@ func TestCheckMissingFileDetectedWithoutFallback(t *testing.T) {
|
|||||||
assert.Equal(t, 0, statusCounts[StatusError], "no files should be ERROR")
|
assert.Equal(t, 0, statusCounts[StatusError], "no files should be ERROR")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestFindExtraFilesSkipsDotfiles(t *testing.T) {
|
||||||
|
// Regression test for #16: FindExtraFiles should not report dotfiles
|
||||||
|
// or the manifest file itself as extra files.
|
||||||
|
fs := afero.NewMemMapFs()
|
||||||
|
files := map[string][]byte{
|
||||||
|
"file1.txt": []byte("in manifest"),
|
||||||
|
}
|
||||||
|
createTestManifest(t, fs, "/data/.index.mf", files)
|
||||||
|
createFilesOnDisk(t, fs, "/data", files)
|
||||||
|
|
||||||
|
// Add dotfiles and manifest file on disk
|
||||||
|
require.NoError(t, afero.WriteFile(fs, "/data/.hidden", []byte("dotfile"), 0o644))
|
||||||
|
require.NoError(t, fs.MkdirAll("/data/.git", 0o755))
|
||||||
|
require.NoError(t, afero.WriteFile(fs, "/data/.git/config", []byte("git config"), 0o644))
|
||||||
|
|
||||||
|
chk, err := NewChecker("/data/.index.mf", "/data", fs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
results := make(chan Result, 10)
|
||||||
|
err = chk.FindExtraFiles(context.Background(), results)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var extras []Result
|
||||||
|
for r := range results {
|
||||||
|
extras = append(extras, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should report NO extra files — dotfiles and manifest should be skipped
|
||||||
|
assert.Empty(t, extras, "FindExtraFiles should not report dotfiles or manifest file as extra; got: %v", extras)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindExtraFilesSkipsManifestFile(t *testing.T) {
|
||||||
|
// The manifest file itself should never be reported as extra
|
||||||
|
fs := afero.NewMemMapFs()
|
||||||
|
files := map[string][]byte{
|
||||||
|
"file1.txt": []byte("content"),
|
||||||
|
}
|
||||||
|
createTestManifest(t, fs, "/data/index.mf", files)
|
||||||
|
createFilesOnDisk(t, fs, "/data", files)
|
||||||
|
|
||||||
|
chk, err := NewChecker("/data/index.mf", "/data", fs)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
results := make(chan Result, 10)
|
||||||
|
err = chk.FindExtraFiles(context.Background(), results)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var extras []Result
|
||||||
|
for r := range results {
|
||||||
|
extras = append(extras, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Empty(t, extras, "manifest file should not be reported as extra; got: %v", extras)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckEmptyManifest(t *testing.T) {
|
func TestCheckEmptyManifest(t *testing.T) {
|
||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
// Create manifest with no files
|
// Create manifest with no files
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user