Fix gosec security warnings (bd-57)
- Changed file permissions from 0644 → 0600 for JSONL exports and config files - Changed directory permissions from 0755 → 0750 in all test code - Updated .golangci.yml with proper exclusions for false positives - Reduced gosec warnings from 102 to 22 (all remaining are acceptable) Closes bd-57 Amp-Thread-ID: https://ampcode.com/threads/T-f754d957-9e42-4e74-861e-57235c7e6436 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -43,8 +43,16 @@ issues:
|
|||||||
exclude:
|
exclude:
|
||||||
- "var-naming: avoid meaningless package names"
|
- "var-naming: avoid meaningless package names"
|
||||||
- "exported.*SQLiteStorage.*stutters"
|
- "exported.*SQLiteStorage.*stutters"
|
||||||
- "G201: SQL string formatting"
|
- "G201: SQL string formatting" # Safe: SQL is constructed from constants
|
||||||
- "G301: Expect directory permissions"
|
- "G204: Subprocess launched" # Safe: git/bd commands from trusted sources
|
||||||
- "G204: Subprocess launched"
|
- "G115: integer overflow conversion" # Safe: controlled conversions
|
||||||
- "G115: integer overflow conversion"
|
exclude-rules:
|
||||||
- "G304.*file inclusion via variable"
|
# G304: File inclusion via variable in tests is safe (test data)
|
||||||
|
- path: _test\.go
|
||||||
|
linters:
|
||||||
|
- gosec
|
||||||
|
text: "G304.*file inclusion via variable"
|
||||||
|
# G302/G306: Directory permissions 0700/0750 are acceptable
|
||||||
|
- linters:
|
||||||
|
- gosec
|
||||||
|
text: "G302.*0700|G301.*0750"
|
||||||
|
|||||||
@@ -30,28 +30,28 @@ func TestFindAllDatabases(t *testing.T) {
|
|||||||
|
|
||||||
// Root .beads
|
// Root .beads
|
||||||
rootBeads := filepath.Join(tmpDir, ".beads")
|
rootBeads := filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(rootBeads, 0755); err != nil {
|
if err := os.MkdirAll(rootBeads, 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
rootDB := filepath.Join(rootBeads, "test.db")
|
rootDB := filepath.Join(rootBeads, "test.db")
|
||||||
if err := os.WriteFile(rootDB, []byte("fake db"), 0644); err != nil {
|
if err := os.WriteFile(rootDB, []byte("fake db"), 0600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Project1 .beads
|
// Project1 .beads
|
||||||
project1Dir := filepath.Join(tmpDir, "project1")
|
project1Dir := filepath.Join(tmpDir, "project1")
|
||||||
project1Beads := filepath.Join(project1Dir, ".beads")
|
project1Beads := filepath.Join(project1Dir, ".beads")
|
||||||
if err := os.MkdirAll(project1Beads, 0755); err != nil {
|
if err := os.MkdirAll(project1Beads, 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
project1DB := filepath.Join(project1Beads, "project1.db")
|
project1DB := filepath.Join(project1Beads, "project1.db")
|
||||||
if err := os.WriteFile(project1DB, []byte("fake db"), 0644); err != nil {
|
if err := os.WriteFile(project1DB, []byte("fake db"), 0600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subdir for working directory
|
// Subdir for working directory
|
||||||
subdir := filepath.Join(project1Dir, "subdir")
|
subdir := filepath.Join(project1Dir, "subdir")
|
||||||
if err := os.MkdirAll(subdir, 0755); err != nil {
|
if err := os.MkdirAll(subdir, 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,11 +107,11 @@ func TestFindAllDatabases_Single(t *testing.T) {
|
|||||||
|
|
||||||
// Create .beads directory with database
|
// Create .beads directory with database
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(beadsDir, 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
dbPath := filepath.Join(beadsDir, "test.db")
|
dbPath := filepath.Join(beadsDir, "test.db")
|
||||||
if err := os.WriteFile(dbPath, []byte("fake db"), 0644); err != nil {
|
if err := os.WriteFile(dbPath, []byte("fake db"), 0600); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ func TestFindDatabasePathInTree(t *testing.T) {
|
|||||||
|
|
||||||
// Create .beads directory with a database file
|
// Create .beads directory with a database file
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
err = os.MkdirAll(beadsDir, 0o755)
|
err = os.MkdirAll(beadsDir, 0o750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create .beads dir: %v", err)
|
t.Fatalf("Failed to create .beads dir: %v", err)
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func TestFindDatabasePathInTree(t *testing.T) {
|
|||||||
|
|
||||||
// Create a subdirectory and change to it
|
// Create a subdirectory and change to it
|
||||||
subDir := filepath.Join(tmpDir, "sub", "nested")
|
subDir := filepath.Join(tmpDir, "sub", "nested")
|
||||||
err = os.MkdirAll(subDir, 0o755)
|
err = os.MkdirAll(subDir, 0o750)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to create subdirectory: %v", err)
|
t.Fatalf("Failed to create subdirectory: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ func TestGetSocketPath(t *testing.T) {
|
|||||||
localSocket := filepath.Join(beadsDir, "bd.sock")
|
localSocket := filepath.Join(beadsDir, "bd.sock")
|
||||||
|
|
||||||
// Create local socket file
|
// Create local socket file
|
||||||
if err := os.WriteFile(localSocket, []byte{}, 0644); err != nil {
|
if err := os.WriteFile(localSocket, []byte{}, 0600); err != nil {
|
||||||
t.Fatalf("Failed to create socket file: %v", err)
|
t.Fatalf("Failed to create socket file: %v", err)
|
||||||
}
|
}
|
||||||
defer os.Remove(localSocket)
|
defer os.Remove(localSocket)
|
||||||
@@ -201,7 +201,7 @@ func TestGetSocketPath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
globalSocket := filepath.Join(globalBeadsDir, "bd.sock")
|
globalSocket := filepath.Join(globalBeadsDir, "bd.sock")
|
||||||
|
|
||||||
if err := os.WriteFile(globalSocket, []byte{}, 0644); err != nil {
|
if err := os.WriteFile(globalSocket, []byte{}, 0600); err != nil {
|
||||||
t.Fatalf("Failed to create fake global socket file: %v", err)
|
t.Fatalf("Failed to create fake global socket file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ func TestBackwardCompatibilityWithOldDaemon(t *testing.T) {
|
|||||||
// Simulate old daemon: PID file exists but no lock file
|
// Simulate old daemon: PID file exists but no lock file
|
||||||
pidFile := filepath.Join(beadsDir, "daemon.pid")
|
pidFile := filepath.Join(beadsDir, "daemon.pid")
|
||||||
currentPID := os.Getpid()
|
currentPID := os.Getpid()
|
||||||
if err := os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", currentPID)), 0644); err != nil {
|
if err := os.WriteFile(pidFile, []byte(fmt.Sprintf("%d", currentPID)), 0600); err != nil {
|
||||||
t.Fatalf("Failed to write PID file: %v", err)
|
t.Fatalf("Failed to write PID file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ func TestIsDaemonRunning_StalePIDFile(t *testing.T) {
|
|||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
pidFile := filepath.Join(tmpDir, "test.pid")
|
pidFile := filepath.Join(tmpDir, "test.pid")
|
||||||
|
|
||||||
if err := os.WriteFile(pidFile, []byte("99999"), 0644); err != nil {
|
if err := os.WriteFile(pidFile, []byte("99999"), 0600); err != nil {
|
||||||
t.Fatalf("Failed to write PID file: %v", err)
|
t.Fatalf("Failed to write PID file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +212,7 @@ func TestDaemonPIDFileManagement(t *testing.T) {
|
|||||||
pidFile := filepath.Join(tmpDir, "daemon.pid")
|
pidFile := filepath.Join(tmpDir, "daemon.pid")
|
||||||
|
|
||||||
testPID := 12345
|
testPID := 12345
|
||||||
if err := os.WriteFile(pidFile, []byte(strconv.Itoa(testPID)), 0644); err != nil {
|
if err := os.WriteFile(pidFile, []byte(strconv.Itoa(testPID)), 0600); err != nil {
|
||||||
t.Fatalf("Failed to write PID file: %v", err)
|
t.Fatalf("Failed to write PID file: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,7 +612,7 @@ func (s *mockDaemonServer) WaitReady(timeout time.Duration) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *mockDaemonServer) Start(ctx context.Context) error {
|
func (s *mockDaemonServer) Start(ctx context.Context) error {
|
||||||
if err := os.MkdirAll(filepath.Dir(s.socketPath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(s.socketPath), 0750); err != nil {
|
||||||
return fmt.Errorf("failed to create socket directory: %w", err)
|
return fmt.Errorf("failed to create socket directory: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -194,8 +194,8 @@ Output to stdout by default, or use -o flag for file output.`,
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set appropriate file permissions (0644: rw-r--r--)
|
// Set appropriate file permissions (0600: rw-------)
|
||||||
if err := os.Chmod(finalPath, 0644); err != nil {
|
if err := os.Chmod(finalPath, 0600); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ bd.db
|
|||||||
# Keep JSONL exports (source of truth for git)
|
# Keep JSONL exports (source of truth for git)
|
||||||
!*.jsonl
|
!*.jsonl
|
||||||
`
|
`
|
||||||
if err := os.WriteFile(gitignorePath, []byte(gitignoreContent), 0644); err != nil {
|
if err := os.WriteFile(gitignorePath, []byte(gitignoreContent), 0600); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Warning: failed to create .gitignore: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Warning: failed to create .gitignore: %v\n", err)
|
||||||
// Non-fatal - continue anyway
|
// Non-fatal - continue anyway
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -351,8 +351,8 @@ func exportToJSONL(ctx context.Context, jsonlPath string) error {
|
|||||||
return fmt.Errorf("failed to replace JSONL file: %w", err)
|
return fmt.Errorf("failed to replace JSONL file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set appropriate file permissions (0644: rw-r--r--)
|
// Set appropriate file permissions (0600: rw-------)
|
||||||
if err := os.Chmod(jsonlPath, 0644); err != nil {
|
if err := os.Chmod(jsonlPath, 0600); err != nil {
|
||||||
// Non-fatal warning
|
// Non-fatal warning
|
||||||
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
|
fmt.Fprintf(os.Stderr, "Warning: failed to set file permissions: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ flush-debounce: 15s
|
|||||||
|
|
||||||
// Create .beads directory
|
// Create .beads directory
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(beadsDir, 0750); err != nil {
|
||||||
t.Fatalf("failed to create .beads directory: %v", err)
|
t.Fatalf("failed to create .beads directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,7 +159,7 @@ func TestConfigPrecedence(t *testing.T) {
|
|||||||
// Create a config file with json: false
|
// Create a config file with json: false
|
||||||
configContent := `json: false`
|
configContent := `json: false`
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(beadsDir, 0750); err != nil {
|
||||||
t.Fatalf("failed to create .beads directory: %v", err)
|
t.Fatalf("failed to create .beads directory: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func dialTestConn(t *testing.T, socketPath string) net.Conn {
|
|||||||
func TestConnectionLimits(t *testing.T) {
|
func TestConnectionLimits(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
||||||
if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(dbPath), 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +150,7 @@ func TestConnectionLimits(t *testing.T) {
|
|||||||
func TestRequestTimeout(t *testing.T) {
|
func TestRequestTimeout(t *testing.T) {
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
||||||
if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(dbPath), 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +207,7 @@ func TestMemoryPressureDetection(t *testing.T) {
|
|||||||
|
|
||||||
tmpDir := t.TempDir()
|
tmpDir := t.TempDir()
|
||||||
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
dbPath := filepath.Join(tmpDir, ".beads", "test.db")
|
||||||
if err := os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
|
if err := os.MkdirAll(filepath.Dir(dbPath), 0750); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func setupTestServer(t *testing.T) (*Server, *Client, func()) {
|
|||||||
|
|
||||||
// Create .beads subdirectory so findDatabaseForCwd finds THIS database, not project's
|
// Create .beads subdirectory so findDatabaseForCwd finds THIS database, not project's
|
||||||
beadsDir := filepath.Join(tmpDir, ".beads")
|
beadsDir := filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(beadsDir, 0750); err != nil {
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
t.Fatalf("Failed to create .beads dir: %v", err)
|
t.Fatalf("Failed to create .beads dir: %v", err)
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ func setupTestServerIsolated(t *testing.T) (tmpDir, beadsDir, dbPath, socketPath
|
|||||||
|
|
||||||
// Create .beads subdirectory so findDatabaseForCwd finds THIS database, not project's
|
// Create .beads subdirectory so findDatabaseForCwd finds THIS database, not project's
|
||||||
beadsDir = filepath.Join(tmpDir, ".beads")
|
beadsDir = filepath.Join(tmpDir, ".beads")
|
||||||
if err := os.MkdirAll(beadsDir, 0755); err != nil {
|
if err := os.MkdirAll(beadsDir, 0750); err != nil {
|
||||||
os.RemoveAll(tmpDir)
|
os.RemoveAll(tmpDir)
|
||||||
t.Fatalf("Failed to create .beads dir: %v", err)
|
t.Fatalf("Failed to create .beads dir: %v", err)
|
||||||
}
|
}
|
||||||
@@ -424,7 +424,7 @@ func TestDatabaseHandshake(t *testing.T) {
|
|||||||
|
|
||||||
// Setup first daemon (db1)
|
// Setup first daemon (db1)
|
||||||
beadsDir1 := filepath.Join(tmpDir1, ".beads")
|
beadsDir1 := filepath.Join(tmpDir1, ".beads")
|
||||||
os.MkdirAll(beadsDir1, 0755)
|
os.MkdirAll(beadsDir1, 0750)
|
||||||
dbPath1 := filepath.Join(beadsDir1, "db1.db")
|
dbPath1 := filepath.Join(beadsDir1, "db1.db")
|
||||||
socketPath1 := filepath.Join(beadsDir1, "bd.sock")
|
socketPath1 := filepath.Join(beadsDir1, "bd.sock")
|
||||||
store1, err := sqlitestorage.New(dbPath1)
|
store1, err := sqlitestorage.New(dbPath1)
|
||||||
@@ -442,7 +442,7 @@ func TestDatabaseHandshake(t *testing.T) {
|
|||||||
|
|
||||||
// Setup second daemon (db2)
|
// Setup second daemon (db2)
|
||||||
beadsDir2 := filepath.Join(tmpDir2, ".beads")
|
beadsDir2 := filepath.Join(tmpDir2, ".beads")
|
||||||
os.MkdirAll(beadsDir2, 0755)
|
os.MkdirAll(beadsDir2, 0750)
|
||||||
dbPath2 := filepath.Join(beadsDir2, "db2.db")
|
dbPath2 := filepath.Join(beadsDir2, "db2.db")
|
||||||
socketPath2 := filepath.Join(beadsDir2, "bd.sock")
|
socketPath2 := filepath.Join(beadsDir2, "bd.sock")
|
||||||
store2, err := sqlitestorage.New(dbPath2)
|
store2, err := sqlitestorage.New(dbPath2)
|
||||||
|
|||||||
Reference in New Issue
Block a user