runPoutineOnFile runs the poutine security scanner on a single .lock.yml file using Docker This is a wrapper that filters the directory scan results to a single file for backward compatibility
(lockFile string, verbose bool, strict bool)
| 170 | // runPoutineOnFile runs the poutine security scanner on a single .lock.yml file using Docker |
| 171 | // This is a wrapper that filters the directory scan results to a single file for backward compatibility |
| 172 | func runPoutineOnFile(lockFile string, verbose bool, strict bool) error { |
| 173 | poutineLog.Printf("Running poutine security scanner: file=%s, strict=%v", lockFile, strict) |
| 174 | |
| 175 | // Find git root to get the absolute path for Docker volume mount |
| 176 | gitRoot, err := gitutil.FindGitRoot() |
| 177 | if err != nil { |
| 178 | return fmt.Errorf("failed to find git root: %w", err) |
| 179 | } |
| 180 | |
| 181 | // Validate gitRoot is an absolute path (security: ensure trusted path from git) |
| 182 | if !filepath.IsAbs(gitRoot) { |
| 183 | return fmt.Errorf("git root is not an absolute path: %s", gitRoot) |
| 184 | } |
| 185 | |
| 186 | // Ensure poutine config exists with custom runner configuration |
| 187 | if err := ensurePoutineConfig(gitRoot); err != nil { |
| 188 | return fmt.Errorf("failed to ensure poutine config: %w", err) |
| 189 | } |
| 190 | |
| 191 | // Get the relative path from git root |
| 192 | relPath, err := filepath.Rel(gitRoot, lockFile) |
| 193 | if err != nil { |
| 194 | return fmt.Errorf("failed to get relative path: %w", err) |
| 195 | } |
| 196 | |
| 197 | // Build the Docker command with JSON output for easier parsing |
| 198 | // docker run --rm -v "$(pwd)":/workdir -w /workdir ghcr.io/boostsecurityio/poutine:latest analyze_local . --format json |
| 199 | // #nosec G204 -- gitRoot comes from git rev-parse (trusted source) and is validated as absolute path |
| 200 | // exec.Command with separate args (not shell execution) prevents command injection |
| 201 | cmd := exec.Command( |
| 202 | "docker", |
| 203 | "run", |
| 204 | "--rm", |
| 205 | "-v", gitRoot+":/workdir", |
| 206 | "-w", "/workdir", |
| 207 | "ghcr.io/boostsecurityio/poutine:latest", |
| 208 | "analyze_local", |
| 209 | ".", |
| 210 | "--format", "json", |
| 211 | "--quiet", // Disable progress output |
| 212 | ) |
| 213 | |
| 214 | // Always show that poutine is running (regular verbosity) |
| 215 | fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("Running poutine security scanner")) |
| 216 | |
| 217 | // In verbose mode, also show the command that users can run directly |
| 218 | if verbose { |
| 219 | dockerCmd := fmt.Sprintf("docker run --rm -v \"%s:/workdir\" -w /workdir ghcr.io/boostsecurityio/poutine:latest analyze_local . --format json --quiet", |
| 220 | gitRoot) |
| 221 | fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("Run poutine directly: "+dockerCmd)) |
| 222 | } |
| 223 | |
| 224 | // Capture output |
| 225 | var stdout, stderr bytes.Buffer |
| 226 | cmd.Stdout = &stdout |
| 227 | cmd.Stderr = &stderr |
| 228 | |
| 229 | // Run the command |
no test coverage detected