Address gosec security warnings (bd-102)
- Enable gosec linter in .golangci.yml - Tighten file permissions: 0755→0750 for directories, 0644→0600 for configs - Git hooks remain 0700 (executable, user-only access) - Add #nosec comments for safe cases with justifications: - G204: Safe subprocess launches (git show, bd daemon) - G304: File inclusions with controlled paths - G201: SQL formatting with controlled column names - G115: Integer conversions with controlled values All gosec warnings resolved (20→0). All tests passing. Amp-Thread-ID: https://ampcode.com/threads/T-d7166b9e-cbbe-4c7b-9e48-3df36b20f0d0 Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -79,7 +79,7 @@ func AutoImportIfNewer(ctx context.Context, store storage.Storage, dbPath string
|
||||
return nil
|
||||
}
|
||||
|
||||
jsonlData, err := os.ReadFile(jsonlPath)
|
||||
jsonlData, err := os.ReadFile(jsonlPath) // #nosec G304 - controlled path from config
|
||||
if err != nil {
|
||||
notify.Debugf("auto-import skipped, JSONL not readable: %v", err)
|
||||
return nil
|
||||
|
||||
@@ -30,7 +30,7 @@ func ConfigPath(beadsDir string) string {
|
||||
func Load(beadsDir string) (*Config, error) {
|
||||
configPath := ConfigPath(beadsDir)
|
||||
|
||||
data, err := os.ReadFile(configPath)
|
||||
data, err := os.ReadFile(configPath) // #nosec G304 - controlled path from config
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -54,7 +54,7 @@ func (c *Config) Save(beadsDir string) error {
|
||||
return fmt.Errorf("marshaling config: %w", err)
|
||||
}
|
||||
|
||||
if err := os.WriteFile(configPath, data, 0644); err != nil {
|
||||
if err := os.WriteFile(configPath, data, 0600); err != nil {
|
||||
return fmt.Errorf("writing config: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ func (s *Server) ensureSocketDir() error {
|
||||
return err
|
||||
}
|
||||
// Best-effort tighten permissions if directory already existed
|
||||
_ = os.Chmod(dir, 0700)
|
||||
_ = os.Chmod(dir, 0700) // #nosec G302 - 0700 is secure (user-only access)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -354,6 +354,7 @@ func (s *Server) checkMemoryPressure() {
|
||||
}
|
||||
|
||||
allocMB := m.Alloc / 1024 / 1024
|
||||
// #nosec G115 - safe conversion of positive value
|
||||
if allocMB > uint64(thresholdMB) {
|
||||
fmt.Fprintf(os.Stderr, "Warning: High memory usage detected (%d MB), triggering aggressive cache eviction\n", allocMB)
|
||||
s.aggressiveEviction()
|
||||
|
||||
@@ -58,6 +58,7 @@ func (s *SQLiteStorage) GetEvents(ctx context.Context, issueID string, limit int
|
||||
args = append(args, limit)
|
||||
}
|
||||
|
||||
// #nosec G201 - safe SQL with controlled formatting
|
||||
query := fmt.Sprintf(`
|
||||
SELECT id, issue_id, event_type, actor, old_value, new_value, comment, created_at
|
||||
FROM events
|
||||
|
||||
@@ -56,6 +56,7 @@ func (s *SQLiteStorage) GetReadyWork(ctx context.Context, filter types.WorkFilte
|
||||
// 1. Find issues directly blocked by 'blocks' dependencies
|
||||
// 2. Recursively propagate blockage to all descendants via 'parent-child' links
|
||||
// 3. Exclude all blocked issues (both direct and transitive) from ready work
|
||||
// #nosec G201 - safe SQL with controlled formatting
|
||||
query := fmt.Sprintf(`
|
||||
WITH RECURSIVE
|
||||
-- Step 1: Find issues blocked directly by dependencies
|
||||
|
||||
@@ -37,7 +37,7 @@ func New(path string) (*SQLiteStorage, error) {
|
||||
// Ensure directory exists (skip for memory databases)
|
||||
if !strings.Contains(dbPath, ":memory:") {
|
||||
dir := filepath.Dir(dbPath)
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
if err := os.MkdirAll(dir, 0o750); err != nil {
|
||||
return nil, fmt.Errorf("failed to create directory: %w", err)
|
||||
}
|
||||
}
|
||||
@@ -1223,7 +1223,7 @@ func (s *SQLiteStorage) UpdateIssue(ctx context.Context, id string, updates map[
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
// Update issue
|
||||
query := fmt.Sprintf("UPDATE issues SET %s WHERE id = ?", strings.Join(setClauses, ", "))
|
||||
query := fmt.Sprintf("UPDATE issues SET %s WHERE id = ?", strings.Join(setClauses, ", ")) // #nosec G201 - safe SQL with controlled column names
|
||||
_, err = tx.ExecContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update issue: %w", err)
|
||||
@@ -1840,6 +1840,7 @@ func (s *SQLiteStorage) SearchIssues(ctx context.Context, query string, filter t
|
||||
args = append(args, filter.Limit)
|
||||
}
|
||||
|
||||
// #nosec G201 - safe SQL with controlled formatting
|
||||
querySQL := fmt.Sprintf(`
|
||||
SELECT id, title, description, design, acceptance_criteria, notes,
|
||||
status, priority, issue_type, assignee, estimated_minutes,
|
||||
|
||||
@@ -20,7 +20,7 @@ func ShouldSkipDatabase(beadsDir string) (skip bool, holder string, err error) {
|
||||
lockPath := filepath.Join(beadsDir, ".exclusive-lock")
|
||||
|
||||
// Check if lock file exists
|
||||
data, err := os.ReadFile(lockPath)
|
||||
data, err := os.ReadFile(lockPath) // #nosec G304 - controlled path from config
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
// No lock file, proceed with database
|
||||
|
||||
Reference in New Issue
Block a user