runRunnerGuardOnDirectory runs the runner-guard taint analysis scanner on a directory containing workflows using the Docker image.
(workflowDir string, verbose bool, strict bool)
| 38 | // runRunnerGuardOnDirectory runs the runner-guard taint analysis scanner on a directory |
| 39 | // containing workflows using the Docker image. |
| 40 | func runRunnerGuardOnDirectory(workflowDir string, verbose bool, strict bool) error { |
| 41 | runnerGuardLog.Printf("Running runner-guard taint analysis on directory: %s", workflowDir) |
| 42 | |
| 43 | // Find git root to get the absolute path for Docker volume mount |
| 44 | gitRoot, err := gitutil.FindGitRoot() |
| 45 | if err != nil { |
| 46 | return fmt.Errorf("failed to find git root: %w", err) |
| 47 | } |
| 48 | |
| 49 | // Validate gitRoot is an absolute path (security: ensure trusted path from git) |
| 50 | if !filepath.IsAbs(gitRoot) { |
| 51 | return fmt.Errorf("git root is not an absolute path: %s", gitRoot) |
| 52 | } |
| 53 | |
| 54 | // Determine the scan path: use workflowDir relative to gitRoot when possible, |
| 55 | // so the scan is scoped to the compiled workflows directory. |
| 56 | scanPath := "." |
| 57 | if workflowDir != "" { |
| 58 | relDir, relErr := filepath.Rel(gitRoot, workflowDir) |
| 59 | if relErr == nil && relDir != ".." && !strings.HasPrefix(relDir, ".."+string(filepath.Separator)) { |
| 60 | scanPath = relDir |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | // Build the Docker command |
| 65 | // docker run --rm -v "$gitRoot:/workdir" -w /workdir ghcr.io/vigilant-llc/runner-guard:latest scan <path> --format json |
| 66 | // #nosec G204 -- gitRoot comes from git rev-parse (trusted source) and is validated as absolute path. |
| 67 | // exec.Command with separate args (not shell execution) prevents command injection. |
| 68 | cmd := exec.Command( |
| 69 | "docker", |
| 70 | "run", |
| 71 | "--rm", |
| 72 | "-v", gitRoot+":/workdir", |
| 73 | "-w", "/workdir", |
| 74 | RunnerGuardImage, |
| 75 | "scan", |
| 76 | scanPath, |
| 77 | "--format", "json", |
| 78 | ) |
| 79 | |
| 80 | // Always show that runner-guard is running (regular verbosity) |
| 81 | fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("Running runner-guard taint analysis scanner")) |
| 82 | |
| 83 | // In verbose mode, also show the command that users can run directly |
| 84 | if verbose { |
| 85 | dockerCmd := fmt.Sprintf("docker run --rm -v \"%s:/workdir\" -w /workdir %s scan %s --format json", |
| 86 | gitRoot, RunnerGuardImage, scanPath) |
| 87 | fmt.Fprintf(os.Stderr, "%s\n", console.FormatInfoMessage("Run runner-guard directly: "+dockerCmd)) |
| 88 | } |
| 89 | |
| 90 | // Capture output |
| 91 | var stdout, stderr bytes.Buffer |
| 92 | cmd.Stdout = &stdout |
| 93 | cmd.Stderr = &stderr |
| 94 | |
| 95 | // Run the command |
| 96 | err = cmd.Run() |
| 97 |
no test coverage detected