Skip to content

Deep Scan fails on Windows because generated in-scope inventory uses backslash-separated paths #302

Description

@SAYUTIM

Summary

A repository-wide Deep Security Scan on Windows terminates during deterministic setup, before discovery, because line 1 of the generated in_scope_files.txt is rejected as an unsafe repository-relative path.

The original staged inventory was removed by normal failed-setup cleanup before it could be inspected. A bounded reproduction using the same installed plugin helper and validator produces the identical error: ripgrep emits a Windows-native backslash-separated row, while the downstream Deep Scan validator requires POSIX-style repository-relative paths.

Environment

  • Windows 11 Home 25H2, build 26200.8875, x64
  • Codex Desktop 26.803.5235.0
  • Codex Security plugin 0.1.18
  • Bundled Python helper 3.12.13
  • ripgrep 15.2.0
  • Scan mode: repository-wide Deep Security Scan
  • Public target: woodpecker-ci/woodpecker at e1c0b37db93cdaf183042fa82890638d713f4ecb
  • Target worktree: clean
  • Workspace permissions: managed profile

The failure manifest records deterministic setup as incomplete and terminally failed, with zero discoveries, zero dispatched workers, and zero worker executions.

Steps to reproduce

On Windows, create a disposable Git repository containing one nested file:

nested/example.txt

Run the helper bundled with Codex Security plugin 0.1.18:

<python> -I -B <plugin-root>/scripts/generate_in_scope_files.py --repo <temporary-repository> --scope . --out <temporary-output>

The helper exits successfully but writes:

.\nested\example.txt

Passing that row through the bundled MCP runtime's actual parseInScopePaths / validateRepositoryPath logic reproduces the failure before any discovery worker starts.

The original product failure occurred while starting a repository-wide Deep Security Scan against woodpecker-ci/woodpecker at e1c0b37db93cdaf183042fa82890638d713f4ecb.

Actual behavior

in_scope_files.txt:1 must be a safe repository-relative path.

Discovery does not start, and the logical scan becomes terminally failed during deterministic setup.

Expected behavior

Codex Security should generate and consume one canonical repository-relative inventory representation on Windows, then begin discovery successfully.

Evidence

Affected plugin 0.1.18, disposable one-file repository:

generator exit: 0
first row: .\nested\example.txt
drive-letter prefix: no
absolute path: no
traversal: no
leading/trailing whitespace: no
control characters: no
validator result: rejected
validator exit: 2
validator error: in_scope_files.txt:1 must be a safe repository-relative path.

Tested correction using ripgrep's output-separator option:

rg --files --hidden --glob '!.git/**' --path-separator / -- .
ripgrep exit: 0
first row: ./nested/example.txt
same validator result: accepted
same validator exit: 0

Current public main at 0facad0b2bda57d845ae22f8b87584ddd716ffba produces the same .\nested\example.txt row and the same validator rejection. The latest public package release, @openai/codex-security@0.1.7 (bundled plugin 0.1.15), has Git blobs identical to current main for both the generator and bundled MCP runtime, so it is affected as well.

Root cause analysis

The affected 0.1.18 generator invokes ripgrep as:

rg --files --hidden --glob !.git/** -- .

Current main adds --no-ignore but likewise does not set the output path separator. See generate_in_scope_files.py on current main.

ripgrep 15.2.0 documents that printed paths default to the platform separator: / on Unix and \ on Windows. The generator preserves and sorts ripgrep's raw output bytes.

The bundled MCP runtime strips repeated leading ./ prefixes and then rejects empty paths, NULs, backslashes, leading /, drive-letter prefixes, dot/traversal components, and empty path components. Therefore the generator emits .\nested\example.txt on Windows, the parser does not remove its .\ prefix, and validation rejects the backslashes.

This is a generator/consumer contract mismatch in deterministic Deep Scan setup, not a target-repository problem.

Suggested correction

The tested minimal correction is to make the generator invoke ripgrep with --path-separator /. In the disposable Windows repository this changed the row to ./nested/example.txt, which the existing parser normalized and the same validator accepted.

This is preferable to an unconditional string replacement: POSIX permits literal backslash and colon characters in filenames, and related inventory work explicitly preserves those names. A correction should change separator rendering without rewriting filename characters.

Please add a native Windows regression that runs the real generator and the Deep Scan setup validator on at least one nested path. It should verify that the generated inventory:

  • is repository-relative;
  • uses the canonical separator expected by downstream validation;
  • has no drive-letter prefix;
  • has no traversal;
  • remains compatible with legitimate filenames on supported platforms; and
  • works through Deep Scan deterministic setup, not only Standard Scan.

The current generator test checks only that an ignored tracked filename appears as a substring, so it does not detect a leading .\ or Windows separators: runtime.test.ts.

Related work

  • PR #267 merged the shared generate_in_scope_files.py helper and unified Deep Scan with Standard Scan phases. It introduced the affected Deep Scan generator path but did not force canonical separators or assert them on native Windows. It is the relevant causal change, not a fix.
  • PR #88 is open authoritative-inventory work for Standard Scan. It does not modify generate_in_scope_files.py, does not exercise this Deep Scan setup path, and does not fix the observed failure. Its POSIX filename-preservation requirements are relevant to choosing a safe correction.
  • PR #85 addressed case-insensitive native Windows scan/artifact path containment. It does not address separators inside repository-relative inventory rows.
  • Issue #283 reports a different Windows Deep Scan failure involving locale-dependent subprocess decoding after workers emit output. This setup-time inventory validation failure is not a duplicate.

No open or closed issue, comment, PR, or open PR file list found an exact report or pending fix for this failure.

Privacy

  • The failure occurred before discovery.
  • No private source, credentials, findings, or complete scan artifacts are included.
  • The complete inventory and coordinator manifest are not included.
  • Local absolute paths and usernames were redacted.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions