6
6
"os"
7
7
"os/exec"
8
8
"path/filepath"
9
+ "sync"
9
10
)
10
11
11
12
// ProcessAssureType handles the assurance process for policies of type "assure"
@@ -64,39 +65,19 @@ func executeAssure(policy Policy, rgPath string, targetDir string, filesToAssure
64
65
return fmt .Errorf ("no target directory defined" )
65
66
}
66
67
67
- // Append the file targets
68
- if len ( filesToAssure ) > 0 {
69
- codePatternAssureJSON = append ( codePatternAssureJSON , filesToAssure ... )
70
- } else if policy . FilePattern == "" {
71
- codePatternAssureJSON = append ( codePatternAssureJSON , targetDir )
68
+ matchesFound := true
69
+
70
+ // Parallel execution for large file sets
71
+ if len ( filesToAssure ) > 25 {
72
+ matchesFound , err = executeParallelAssure ( rgPath , codePatternAssureJSON , filesToAssure , writer )
72
73
} else {
73
- return fmt . Errorf ( "no files matched policy pattern" )
74
+ matchesFound , err = executeSingleAssure ( rgPath , codePatternAssureJSON , filesToAssure , targetDir , policy , writer )
74
75
}
75
76
76
- // Execute the ripgrep command for JSON output
77
- cmdJSON := exec .Command (rgPath , codePatternAssureJSON ... )
78
- cmdJSON .Stdout = writer
79
- cmdJSON .Stderr = os .Stderr
77
+ if err != nil {
80
78
81
- log .Debug ().Msgf ("Creating JSON output for assure policy %s... " , policy .ID )
82
- err = cmdJSON .Run ()
79
+ log .Error ().Err (err ).Msg ("error executing ripgrep batch" )
83
80
84
- // Check if ripgrep found any matches
85
- matchesFound := true
86
- if err != nil {
87
- if exitError , ok := err .(* exec.ExitError ); ok {
88
- // Exit code 1 in ripgrep means "no matches found"
89
- if exitError .ExitCode () == 1 {
90
- matchesFound = false
91
- err = nil // Reset error as this is the expected outcome for assure
92
- } else {
93
- log .Error ().Err (err ).Msg ("error executing ripgrep for JSON output" )
94
- return fmt .Errorf ("error executing ripgrep for JSON output: %w" , err )
95
- }
96
- } else {
97
- log .Error ().Err (err ).Msg ("error executing ripgrep for JSON output" )
98
- return fmt .Errorf ("error executing ripgrep for JSON output: %w" , err )
99
- }
100
81
}
101
82
102
83
// Patch the JSON output file
@@ -107,6 +88,7 @@ func executeAssure(policy Policy, rgPath string, targetDir string, filesToAssure
107
88
}
108
89
109
90
log .Debug ().Msgf ("JSON output for assure policy %s written to: %s " , policy .ID , jsonOutputFile )
91
+ log .Debug ().Msgf ("Scanned ~%d files for policy %s" , len (filesToAssure ), policy .ID )
110
92
111
93
// Determine the status based on whether matches were found
112
94
status := "NOT FOUND"
@@ -143,3 +125,115 @@ func executeAssure(policy Policy, rgPath string, targetDir string, filesToAssure
143
125
144
126
return nil
145
127
}
128
+
129
+ func executeParallelAssure (rgPath string , baseArgs []string , filesToScan []string , writer * bufio.Writer ) (bool , error ) {
130
+
131
+ const batchSize = 25
132
+ matched := true
133
+ var wg sync.WaitGroup
134
+ errChan := make (chan error , len (filesToScan )/ batchSize + 1 )
135
+ var mu sync.Mutex
136
+
137
+ for i := 0 ; i < len (filesToScan ); i += batchSize {
138
+ end := i + batchSize
139
+ if end > len (filesToScan ) {
140
+ end = len (filesToScan )
141
+ }
142
+ batch := filesToScan [i :end ]
143
+
144
+ // log.Debug().Msgf("RGM: %v", batch)
145
+
146
+ wg .Add (1 )
147
+ go func (batch []string ) {
148
+ defer wg .Done ()
149
+ args := append (baseArgs , batch ... )
150
+ cmd := exec .Command (rgPath , args ... )
151
+ output , err := cmd .Output ()
152
+
153
+ if err != nil {
154
+
155
+ if exitError , ok := err .(* exec.ExitError ); ok {
156
+ // Exit code 1 in ripgrep means "no matches found"
157
+ if exitError .ExitCode () == 1 {
158
+ matched = false
159
+ err = nil // Reset error as this is the expected outcome for assure
160
+ }
161
+ }
162
+
163
+ if exitError , ok := err .(* exec.ExitError ); ok && exitError .ExitCode () != 1 {
164
+ errChan <- fmt .Errorf ("error executing ripgrep: %w" , err )
165
+ return
166
+ }
167
+ }
168
+
169
+ mu .Lock ()
170
+ _ , writeErr := writer .Write (output )
171
+ if writeErr == nil {
172
+ writeErr = writer .Flush ()
173
+ }
174
+ mu .Unlock ()
175
+
176
+ if writeErr != nil {
177
+ errChan <- fmt .Errorf ("error writing output: %w" , writeErr )
178
+ }
179
+ }(batch )
180
+ }
181
+
182
+ wg .Wait ()
183
+ close (errChan )
184
+
185
+ for err := range errChan {
186
+ if err != nil {
187
+ return matched , err
188
+ }
189
+ }
190
+
191
+ return matched , nil
192
+ }
193
+
194
+ func executeSingleAssure (rgPath string , baseArgs []string , filesToScan []string , targetDir string , policy Policy , writer * bufio.Writer ) (bool , error ) {
195
+
196
+ if len (filesToScan ) > 0 {
197
+ baseArgs = append (baseArgs , filesToScan ... )
198
+ } else {
199
+ log .Error ().Str ("policy" , policy .ID ).Msgf ("no files matched policy pattern on target : %s" , targetDir )
200
+ }
201
+
202
+ matched := true
203
+
204
+ // log.Debug().Msgf("RGS: %v", baseArgs)
205
+
206
+ cmdJSON := exec .Command (rgPath , baseArgs ... )
207
+ cmdJSON .Stdout = writer
208
+ cmdJSON .Stderr = os .Stderr
209
+
210
+ log .Debug ().Msgf ("Creating JSON output for policy %s... " , policy .ID )
211
+ err := cmdJSON .Run ()
212
+ if err != nil {
213
+ if exitError , ok := err .(* exec.ExitError ); ok {
214
+
215
+ if exitError .ExitCode () == 1 {
216
+ matched = false
217
+ err = nil // Reset error as this is the expected outcome for assure
218
+ }
219
+
220
+ if exitError .ExitCode () == 2 {
221
+ log .Warn ().Msgf ("RG exited with code 2" )
222
+ log .Debug ().Msgf ("RG Error Args: %v" , baseArgs )
223
+ if len (exitError .Stderr ) > 0 {
224
+ log .Debug ().Msgf ("RG exited with code 2 stderr: %s" , string (exitError .Stderr ))
225
+ }
226
+ }
227
+ if exitError .ExitCode () != 1 {
228
+ log .Error ().Err (err ).Msg ("error executing ripgrep for JSON output" )
229
+ return matched , fmt .Errorf ("error executing ripgrep for JSON output: %w" , err )
230
+ }
231
+
232
+ } else {
233
+ log .Error ().Err (err ).Msg ("error executing ripgrep for JSON output" )
234
+ return matched , fmt .Errorf ("error executing ripgrep for JSON output: %w" , err )
235
+ }
236
+ }
237
+
238
+ return matched , nil
239
+ }
0 commit comments