Remediate all lint findings under the canonical golangci-lint config

Fix every finding surfaced by the canonical .golangci.yml with
golangci-lint v2.12.2 (refs #61), behavior-preserving throughout:

- err113: dynamic errors replaced with package-level sentinels and %w
  wrapping; direct comparisons converted to errors.Is
- goprintffuncname: printf-style helpers renamed with an f suffix
  (ui.Writer message methods, cli.ReportErrorf, database.Fatalf,
  vaultik stdoutf) and all call sites updated
- revive: stuttering type names renamed (blob.Handler, blob.WithReader,
  blob.ChunkPosition, storage.URL, storage.Info), doc comments added,
  unused parameters blanked, package comments added
- contextcheck/noctx: ctx threaded through blob.Packer
  (AddChunk/Flush/FinalizeBlob/PackChunks) and scanner call sites;
  context-aware exec and sql variants used
- funlen/cyclop/gocognit/nestif/dupl: oversized or duplicated
  functions split into focused helpers across production and test code
- paralleltest/tparallel/thelper/usetesting/testpackage: tests
  parallelized where safe (global log.Initialize kept in the serial
  phase), helpers marked, t.TempDir adopted, external test packages
  where only exported API is used
- gosec: integer conversions clamped or justified, header timeouts
  added, remaining findings suppressed with per-site justifications
- mnd/goconst/lll/wsl_v5/nlreturn/noinlineerr/errcheck and other
  mechanical findings fixed directly

Remove the deprecated log.LogOptions alias (callers migrated to
log.Options). make check is green.
This commit is contained in:
2026-08-07 18:51:21 +00:00
parent 6cf9211407
commit 7ae470e530
121 changed files with 8344 additions and 5406 deletions

View File

@@ -1,3 +1,4 @@
//nolint:testpackage // inspects the unexported database connection
package database
import (
@@ -11,8 +12,13 @@ import (
"sneak.berlin/go/vaultik/internal/types"
)
// errTxIntentionalRollback forces a transaction rollback in tests.
var errTxIntentionalRollback = errors.New("intentional rollback")
// TestFileRepositoryUUIDGeneration tests that files get unique UUIDs
func TestFileRepositoryUUIDGeneration(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -22,7 +28,7 @@ func TestFileRepositoryUUIDGeneration(t *testing.T) {
// Create multiple files
files := []*File{
{
Path: "/file1.txt",
Path: internalTestFile1,
MTime: time.Now().Truncate(time.Second),
Size: 1024,
Mode: 0644,
@@ -30,7 +36,7 @@ func TestFileRepositoryUUIDGeneration(t *testing.T) {
GID: 1000,
},
{
Path: "/file2.txt",
Path: internalTestFile2,
MTime: time.Now().Truncate(time.Second),
Size: 2048,
Mode: 0644,
@@ -63,6 +69,8 @@ func TestFileRepositoryUUIDGeneration(t *testing.T) {
// TestFileRepositoryGetByID tests retrieving files by UUID
func TestFileRepositoryGetByID(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -71,7 +79,7 @@ func TestFileRepositoryGetByID(t *testing.T) {
// Create a file
file := &File{
Path: "/test.txt",
Path: internalTestFilePath,
MTime: time.Now().Truncate(time.Second),
Size: 1024,
Mode: 0644,
@@ -98,8 +106,9 @@ func TestFileRepositoryGetByID(t *testing.T) {
t.Errorf("Path mismatch: expected %s, got %s", file.Path, retrieved.Path)
}
// Test non-existent ID
nonExistentID := types.NewFileID() // Generate a new UUID that won't exist in the database
// Test non-existent ID: generate a new UUID that won't exist in the
// database.
nonExistentID := types.NewFileID()
nonExistent, err := repo.GetByID(ctx, nonExistentID)
if err != nil {
@@ -113,6 +122,8 @@ func TestFileRepositoryGetByID(t *testing.T) {
// TestOrphanedFileCleanup tests the cleanup of orphaned files
func TestOrphanedFileCleanup(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -149,8 +160,8 @@ func TestOrphanedFileCleanup(t *testing.T) {
// Create a snapshot and reference only file2
snapshot := &Snapshot{
ID: "test-snapshot",
Hostname: "test-host",
ID: internalTestSnapshotID,
Hostname: internalTestHost,
StartedAt: time.Now(),
}
@@ -160,10 +171,7 @@ func TestOrphanedFileCleanup(t *testing.T) {
}
// Add file2 to snapshot
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot.ID.String(), file2.ID)
if err != nil {
t.Fatalf("failed to add file to snapshot: %v", err)
}
mustAddFileToSnapshot(t, repos, snapshot.ID.String(), file2.ID)
// Run orphaned cleanup
err = repos.Files.DeleteOrphaned(ctx)
@@ -194,6 +202,8 @@ func TestOrphanedFileCleanup(t *testing.T) {
// TestOrphanedChunkCleanup tests the cleanup of orphaned chunks
func TestOrphanedChunkCleanup(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -222,7 +232,7 @@ func TestOrphanedChunkCleanup(t *testing.T) {
// Create a file and reference only chunk2
file := &File{
Path: "/test.txt",
Path: internalTestFilePath,
MTime: time.Now().Truncate(time.Second),
Size: 1024,
Mode: 0644,
@@ -276,6 +286,8 @@ func TestOrphanedChunkCleanup(t *testing.T) {
// TestOrphanedBlobCleanup tests the cleanup of orphaned blobs
func TestOrphanedBlobCleanup(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -306,8 +318,8 @@ func TestOrphanedBlobCleanup(t *testing.T) {
// Create a snapshot and reference only blob2
snapshot := &Snapshot{
ID: "test-snapshot",
Hostname: "test-host",
ID: internalTestSnapshotID,
Hostname: internalTestHost,
StartedAt: time.Now(),
}
@@ -351,6 +363,8 @@ func TestOrphanedBlobCleanup(t *testing.T) {
// TestFileChunkRepositoryWithUUIDs tests file-chunk relationships with UUIDs
func TestFileChunkRepositoryWithUUIDs(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -359,7 +373,7 @@ func TestFileChunkRepositoryWithUUIDs(t *testing.T) {
// Create a file
file := &File{
Path: "/test.txt",
Path: internalTestFilePath,
MTime: time.Now().Truncate(time.Second),
Size: 3072,
Mode: 0644,
@@ -367,10 +381,7 @@ func TestFileChunkRepositoryWithUUIDs(t *testing.T) {
GID: 1000,
}
err := repos.Files.Create(ctx, nil, file)
if err != nil {
t.Fatalf("failed to create file: %v", err)
}
mustCreateFileRow(t, repos, file)
// Create chunks
chunks := []types.ChunkHash{"chunk1", "chunk2", "chunk3"}
@@ -380,7 +391,7 @@ func TestFileChunkRepositoryWithUUIDs(t *testing.T) {
Size: 1024,
}
err = repos.Chunks.Create(ctx, nil, chunk)
err := repos.Chunks.Create(ctx, nil, chunk)
if err != nil {
t.Fatalf("failed to create chunk: %v", err)
}
@@ -426,6 +437,8 @@ func TestFileChunkRepositoryWithUUIDs(t *testing.T) {
// TestChunkFileRepositoryWithUUIDs tests chunk-file relationships with UUIDs
func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -434,7 +447,7 @@ func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
// Create files
file1 := &File{
Path: "/file1.txt",
Path: internalTestFile1,
MTime: time.Now().Truncate(time.Second),
Size: 1024,
Mode: 0644,
@@ -442,7 +455,7 @@ func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
GID: 1000,
}
file2 := &File{
Path: "/file2.txt",
Path: internalTestFile2,
MTime: time.Now().Truncate(time.Second),
Size: 1024,
Mode: 0644,
@@ -450,15 +463,8 @@ func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
GID: 1000,
}
err := repos.Files.Create(ctx, nil, file1)
if err != nil {
t.Fatalf("failed to create file1: %v", err)
}
err = repos.Files.Create(ctx, nil, file2)
if err != nil {
t.Fatalf("failed to create file2: %v", err)
}
mustCreateFileRow(t, repos, file1)
mustCreateFileRow(t, repos, file2)
// Create a chunk that appears in both files (deduplication)
chunk := &Chunk{
@@ -466,7 +472,7 @@ func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
Size: 1024,
}
err = repos.Chunks.Create(ctx, nil, chunk)
err := repos.Chunks.Create(ctx, nil, chunk)
if err != nil {
t.Fatalf("failed to create chunk: %v", err)
}
@@ -518,6 +524,8 @@ func TestChunkFileRepositoryWithUUIDs(t *testing.T) {
// TestSnapshotRepositoryExtendedFields tests snapshot with version and git revision
func TestSnapshotRepositoryExtendedFields(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -527,7 +535,7 @@ func TestSnapshotRepositoryExtendedFields(t *testing.T) {
// Create snapshot with extended fields
snapshot := &Snapshot{
ID: "test-20250722-120000Z",
Hostname: "test-host",
Hostname: internalTestHost,
VaultikVersion: "0.0.1",
VaultikGitRevision: "abc123def456",
StartedAt: time.Now(),
@@ -555,35 +563,39 @@ func TestSnapshotRepositoryExtendedFields(t *testing.T) {
}
if retrieved.VaultikVersion != snapshot.VaultikVersion {
t.Errorf("version mismatch: expected %s, got %s", snapshot.VaultikVersion, retrieved.VaultikVersion)
t.Errorf("version mismatch: expected %s, got %s",
snapshot.VaultikVersion, retrieved.VaultikVersion)
}
if retrieved.VaultikGitRevision != snapshot.VaultikGitRevision {
t.Errorf("git revision mismatch: expected %s, got %s", snapshot.VaultikGitRevision, retrieved.VaultikGitRevision)
t.Errorf("git revision mismatch: expected %s, got %s",
snapshot.VaultikGitRevision, retrieved.VaultikGitRevision)
}
if retrieved.CompressionLevel != snapshot.CompressionLevel {
t.Errorf("compression level mismatch: expected %d, got %d", snapshot.CompressionLevel, retrieved.CompressionLevel)
t.Errorf("compression level mismatch: expected %d, got %d",
snapshot.CompressionLevel, retrieved.CompressionLevel)
}
if retrieved.BlobUncompressedSize != snapshot.BlobUncompressedSize {
t.Errorf("uncompressed size mismatch: expected %d, got %d", snapshot.BlobUncompressedSize, retrieved.BlobUncompressedSize)
t.Errorf("uncompressed size mismatch: expected %d, got %d",
snapshot.BlobUncompressedSize, retrieved.BlobUncompressedSize)
}
if retrieved.UploadDurationMs != snapshot.UploadDurationMs {
t.Errorf("upload duration mismatch: expected %d, got %d", snapshot.UploadDurationMs, retrieved.UploadDurationMs)
t.Errorf("upload duration mismatch: expected %d, got %d",
snapshot.UploadDurationMs, retrieved.UploadDurationMs)
}
}
// TestComplexOrphanedDataScenario tests a complex scenario with multiple relationships
func TestComplexOrphanedDataScenario(t *testing.T) {
db, cleanup := setupTestDB(t)
defer cleanup()
// createOrphanScenarioFixtures creates two snapshots and three files for
// the orphaned-data cleanup scenario.
func createOrphanScenarioFixtures(
ctx context.Context, t *testing.T, repos *Repositories,
) (*Snapshot, *Snapshot, []*File) {
t.Helper()
ctx := context.Background()
repos := NewRepositories(db)
// Create snapshots
snapshot1 := &Snapshot{
ID: "snapshot1",
Hostname: "host1",
@@ -623,34 +635,33 @@ func TestComplexOrphanedDataScenario(t *testing.T) {
}
}
return snapshot1, snapshot2, files
}
func TestComplexOrphanedDataScenario(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
repos := NewRepositories(db)
snapshot1, snapshot2, files := createOrphanScenarioFixtures(ctx, t, repos)
// Add files to snapshots
// Snapshot1: file0, file1
// Snapshot2: file1, file2
// file0: only in snapshot1
// file1: in both snapshots
// file2: only in snapshot2
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot1.ID.String(), files[0].ID)
if err != nil {
t.Fatal(err)
}
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot1.ID.String(), files[1].ID)
if err != nil {
t.Fatal(err)
}
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot2.ID.String(), files[1].ID)
if err != nil {
t.Fatal(err)
}
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot2.ID.String(), files[2].ID)
if err != nil {
t.Fatal(err)
}
mustAddFileToSnapshot(t, repos, snapshot1.ID.String(), files[0].ID)
mustAddFileToSnapshot(t, repos, snapshot1.ID.String(), files[1].ID)
mustAddFileToSnapshot(t, repos, snapshot2.ID.String(), files[1].ID)
mustAddFileToSnapshot(t, repos, snapshot2.ID.String(), files[2].ID)
// Delete snapshot1
err = repos.Snapshots.DeleteSnapshotFiles(ctx, snapshot1.ID.String())
err := repos.Snapshots.DeleteSnapshotFiles(ctx, snapshot1.ID.String())
if err != nil {
t.Fatal(err)
}
@@ -700,6 +711,8 @@ func TestComplexOrphanedDataScenario(t *testing.T) {
// TestCascadeDelete tests that cascade deletes work properly
func TestCascadeDelete(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -774,6 +787,8 @@ func TestCascadeDelete(t *testing.T) {
// TestTransactionIsolation tests that transactions properly isolate changes
func TestTransactionIsolation(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
@@ -802,7 +817,7 @@ func TestTransactionIsolation(t *testing.T) {
// For now, we'll just test that rollback works
// Return an error to trigger rollback
return errors.New("intentional rollback")
return errTxIntentionalRollback
})
if err == nil {
t.Fatal("expected error from transaction")
@@ -819,32 +834,15 @@ func TestTransactionIsolation(t *testing.T) {
}
}
// TestConcurrentOrphanedCleanup tests that concurrent cleanup operations don't interfere
func TestConcurrentOrphanedCleanup(t *testing.T) {
db, cleanup := setupTestDB(t)
defer cleanup()
// TestConcurrentOrphanedCleanup tests that concurrent cleanup operations
// don't interfere.
// createConcurrentCleanupFiles creates 20 files and associates the
// even-numbered ones with the snapshot, leaving the rest orphaned.
func createConcurrentCleanupFiles(
ctx context.Context, t *testing.T, repos *Repositories, snapshotID string,
) {
t.Helper()
ctx := context.Background()
repos := NewRepositories(db)
// Set a 5-second busy timeout to handle concurrent operations
if _, err := db.conn.Exec("PRAGMA busy_timeout = 5000"); err != nil {
t.Fatalf("failed to set busy timeout: %v", err)
}
// Create a snapshot
snapshot := &Snapshot{
ID: "concurrent-test",
Hostname: "test-host",
StartedAt: time.Now(),
}
err := repos.Snapshots.Create(ctx, nil, snapshot)
if err != nil {
t.Fatal(err)
}
// Create many files, some orphaned
for i := range 20 {
file := &File{
Path: types.FilePath(fmt.Sprintf("/concurrent-%d.txt", i)),
@@ -855,19 +853,49 @@ func TestConcurrentOrphanedCleanup(t *testing.T) {
GID: 1000,
}
err = repos.Files.Create(ctx, nil, file)
err := repos.Files.Create(ctx, nil, file)
if err != nil {
t.Fatal(err)
}
// Add even-numbered files to snapshot
if i%2 == 0 {
err = repos.Snapshots.AddFileByID(ctx, nil, snapshot.ID.String(), file.ID)
err = repos.Snapshots.AddFileByID(ctx, nil, snapshotID, file.ID)
if err != nil {
t.Fatal(err)
}
}
}
}
func TestConcurrentOrphanedCleanup(t *testing.T) {
t.Parallel()
db, cleanup := setupTestDB(t)
defer cleanup()
ctx := context.Background()
repos := NewRepositories(db)
// Set a 5-second busy timeout to handle concurrent operations
_, err := db.conn.ExecContext(ctx, "PRAGMA busy_timeout = 5000")
if err != nil {
t.Fatalf("failed to set busy timeout: %v", err)
}
// Create a snapshot
snapshot := &Snapshot{
ID: "concurrent-test",
Hostname: internalTestHost,
StartedAt: time.Now(),
}
err = repos.Snapshots.Create(ctx, nil, snapshot)
if err != nil {
t.Fatal(err)
}
createConcurrentCleanupFiles(ctx, t, repos, snapshot.ID.String())
// Run multiple cleanup operations concurrently
// Note: SQLite has limited support for concurrent writes, so we expect some to fail