Skip to content

Commit a2daa46

Browse files
committed
feat: include dirs
1 parent 0556135 commit a2daa46

File tree

3 files changed

+76
-9
lines changed

3 files changed

+76
-9
lines changed

nix/packages/cis-audit/scanner/cmd/cis-generate-spec/main.go

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var (
2424
includePorts bool
2525
includeProcess bool
2626
shallowDirs []string
27+
shallowDepth int
2728
strict bool
2829
verbose bool
2930
debug bool
@@ -52,8 +53,11 @@ Examples:
5253
# Enable verbose logging to stderr
5354
cis-generate-spec --verbose --log-format json
5455
55-
# Scan directories without recursing into subdirectories
56+
# Scan directories without recursing into subdirectories (depth 1 = top level only)
5657
cis-generate-spec --shallow-dirs /nix/store --shallow-dirs /data/pgdata
58+
59+
# Scan shallow dirs including immediate subdirectories (depth 2)
60+
cis-generate-spec --shallow-dirs /nix/store --shallow-depth 2
5761
`,
5862
Args: cobra.MaximumNArgs(1),
5963
Version: version,
@@ -66,7 +70,8 @@ func init() {
6670
rootCmd.Flags().BoolVar(&includeDynamic, "include-dynamic", false, "Include dynamic kernel parameters")
6771
rootCmd.Flags().BoolVar(&includePorts, "include-ports", false, "Include listening ports")
6872
rootCmd.Flags().BoolVar(&includeProcess, "include-processes", false, "Include running processes")
69-
rootCmd.Flags().StringArrayVar(&shallowDirs, "shallow-dirs", nil, "Directories to scan without recursion (can be specified multiple times)")
73+
rootCmd.Flags().StringArrayVar(&shallowDirs, "shallow-dirs", nil, "Directories to scan with limited depth (can be specified multiple times)")
74+
rootCmd.Flags().IntVar(&shallowDepth, "shallow-depth", 1, "How deep to scan in shallow dirs (1=top level only, 2=include immediate subdirs)")
7075
rootCmd.Flags().BoolVar(&strict, "strict", false, "Fail on any access errors (default: skip and warn)")
7176
rootCmd.Flags().BoolVar(&verbose, "verbose", false, "Enable structured logging to stderr")
7277
rootCmd.Flags().BoolVar(&debug, "debug", false, "Enable debug logging (implies --verbose)")
@@ -92,6 +97,7 @@ func run(cmd *cobra.Command, args []string) error {
9297
IncludePorts: includePorts,
9398
IncludeProcesses: includeProcess,
9499
ShallowDirs: shallowDirs,
100+
ShallowDepth: shallowDepth,
95101
}
96102
cfg, err := config.Load(configFile, cliOpts)
97103
if err != nil {

nix/packages/cis-audit/scanner/internal/config/loader.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,16 @@ type Config struct {
1818
// Paths to exclude from scanning (glob patterns supported)
1919
Paths []string `yaml:"paths,omitempty"`
2020

21-
// ShallowDirs are directories to scan at top level only (no recursion)
22-
// Files directly in these directories are scanned, but subdirectories are skipped
21+
// ShallowDirs are directories to scan with limited recursion depth
22+
// Files up to ShallowDepth levels deep are scanned, deeper subdirectories are skipped
2323
ShallowDirs []string `yaml:"shallowDirs,omitempty"`
2424

25+
// ShallowDepth controls how many levels deep to scan in shallow directories
26+
// 1 = only files directly in the shallow dir (default)
27+
// 2 = files in shallow dir + immediate subdirectories
28+
// 3 = files in shallow dir + 2 levels of subdirectories, etc.
29+
ShallowDepth int `yaml:"shallowDepth,omitempty"`
30+
2531
// Kernel parameters to exclude from scanning
2632
KernelParams []string `yaml:"kernelParams,omitempty"`
2733

@@ -49,6 +55,9 @@ type CLIOptions struct {
4955

5056
// ShallowDirs adds directories to scan without recursion (from CLI)
5157
ShallowDirs []string
58+
59+
// ShallowDepth controls recursion depth in shallow directories (from CLI)
60+
ShallowDepth int
5261
}
5362

5463
// Load reads configuration from defaults, optional config file, and CLI options.
@@ -95,6 +104,16 @@ func Load(configPath string, opts CLIOptions) (*Config, error) {
95104
cfg.ShallowDirs = append(cfg.ShallowDirs, opts.ShallowDirs...)
96105
}
97106

107+
// Set shallow depth from CLI (overrides config file and defaults)
108+
if opts.ShallowDepth > 0 {
109+
cfg.ShallowDepth = opts.ShallowDepth
110+
}
111+
112+
// Default shallow depth to 1 if not set
113+
if cfg.ShallowDepth == 0 {
114+
cfg.ShallowDepth = 1
115+
}
116+
98117
return &cfg, nil
99118
}
100119

@@ -124,6 +143,11 @@ func merge(base, file Config) Config {
124143
result.KernelParams = append(result.KernelParams, file.KernelParams...)
125144
result.DisabledScanners = append(result.DisabledScanners, file.DisabledScanners...)
126145

146+
// ShallowDepth from file overrides base if set
147+
if file.ShallowDepth > 0 {
148+
result.ShallowDepth = file.ShallowDepth
149+
}
150+
127151
return result
128152
}
129153

nix/packages/cis-audit/scanner/internal/scanners/files.go

Lines changed: 42 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,28 @@ func (s *FileScanner) Scan(ctx context.Context, opts ScanOptions) (ScanStats, er
7373
return nil
7474
}
7575

76-
// Handle shallow directories - scan top level only, skip subdirectories
76+
// Handle shallow directories - limit recursion depth
7777
if d != nil && d.IsDir() {
7878
depth := cfg.GetShallowDirDepth(path)
79-
if depth > 1 {
80-
// This is a subdirectory inside a shallow dir - skip it
81-
opts.Logger.Debug("Skipping subdirectory in shallow dir", "path", path, "depth", depth)
82-
return filepath.SkipDir
79+
if depth >= 0 {
80+
if depth == 0 && cfg.ShallowDepth == 0 {
81+
// Depth 0 means capture this directory entry but don't recurse into it
82+
info, err := d.Info()
83+
if err == nil {
84+
dirSpec := s.buildDirSpec(path, info)
85+
if err := writer.Add(dirSpec); err != nil {
86+
return fmt.Errorf("failed to write dir spec: %w", err)
87+
}
88+
s.stats.FilesScanned++
89+
}
90+
opts.Logger.Debug("Captured shallow dir, skipping contents", "path", path)
91+
return filepath.SkipDir
92+
}
93+
if depth >= cfg.ShallowDepth {
94+
// This directory is at or beyond the configured shallow depth - skip it
95+
opts.Logger.Debug("Skipping directory beyond shallow depth", "path", path, "depth", depth, "max_depth", cfg.ShallowDepth)
96+
return filepath.SkipDir
97+
}
8398
}
8499
}
85100

@@ -142,6 +157,28 @@ func (s *FileScanner) buildFileSpec(path string, info fs.FileInfo) spec.FileSpec
142157
}
143158
}
144159

160+
// buildDirSpec creates a GOSS file spec for a directory
161+
func (s *FileScanner) buildDirSpec(path string, info fs.FileInfo) spec.FileSpec {
162+
// Extract Unix permissions and ownership
163+
sys := info.Sys().(*syscall.Stat_t)
164+
165+
// Mode with leading zero (GOSS format: "0755" not "755")
166+
mode := fmt.Sprintf("0%o", info.Mode().Perm())
167+
168+
// Get username/groupname from UID/GID
169+
owner := getUsername(sys.Uid)
170+
group := getGroupname(sys.Gid)
171+
172+
return spec.FileSpec{
173+
Path: path,
174+
Exists: true,
175+
Mode: mode,
176+
Owner: owner,
177+
Group: group,
178+
Filetype: "directory",
179+
}
180+
}
181+
145182
// handleError processes errors based on strict mode
146183
func (s *FileScanner) handleError(err error, path string, opts ScanOptions) error {
147184
// Permission denied is common and expected

0 commit comments

Comments
 (0)