Skip to content

fix(scan): report a failed ignored-but-tracked file listing - #864

Open
kevin9327 wants to merge 1 commit into
openai:mainfrom
kevin9327:fix/inventory-ignored-tracked-listing
Open

kevin9327 wants to merge 1 commit into
openai:mainfrom
kevin9327:fix/inventory-ignored-tracked-listing

Conversation

@kevin9327

Copy link
Copy Markdown
Contributor

Summary

generate_in_scope_files builds the shared scan inventory from ripgrep, then adds the files that Git tracks but .gitignore excludes — ripgrep honours ignore rules, so without that step every committed-but-ignored file (vendored dependencies, checked-in build output, generated clients) would be missing from the audit. plugins/codex-security/tests/test_generate_in_scope_files.py::test_inventory_keeps_ignored_tracked_files_without_ignored_untracked_files pins that guarantee.

That git ls-files call sent its stderr to DEVNULL and treated both a spawn failure and any non-zero exit status as "this repository has no ignored-but-tracked files". So when the Git listing fails for a reason unrelated to the file set, the inventory is silently written short, the command exits 0, and the scan proceeds over a smaller file list while reporting normal success. Nothing on stdout, stderr, or in the artifact records that anything was dropped.

The branch is only entered when repository/.git exists, so the code has already concluded it is looking at a Git repository. Real triggers that leave the index intact while git ls-files fails: a repository format extension the local Git does not support (fatal: unknown repository extension found: ...), detected dubious ownership in repository at ... on a checkout owned by another user, or a linked worktree whose gitdir target is gone.

The ripgrep call ten lines above already handles the identical two failure modes correctly — raise InventoryError on OSError, and raise InventoryError with the captured stderr on an unexpected exit status. This change makes the Git call match its sibling.

Changes

  • plugins/codex-security/scripts/generate_in_scope_files.py: capture git ls-files stderr instead of discarding it; raise InventoryError on a spawn failure and on a non-zero exit status, including Git's own message in the error. The success path is unchanged apart from losing one level of indentation.
  • plugins/codex-security/tests/test_generate_in_scope_files.py: regression test that a failing ignored-but-tracked listing exits 2 and writes no inventory.

Testing

Reproduced through the plugin's own inventory command before and after the change, on Windows. Fixture: a repository with vendor/ in .gitignore and vendor/lib.py committed with git add --force; git ls-files broken with an unsupported repository extension.

Before, on unmodified main:

$ python plugins/codex-security/scripts/generate_in_scope_files.py --repo <fixture> --scope . --out inv.txt
Recorded 2 in-scope files.
exit=0
$ cat inv.txt
./.gitignore
./app.py

./vendor/lib.py is gone, the command succeeded, and nothing said so. The same fixture with a healthy .git/config records 3 files including ./vendor/lib.py.

New test against unmodified main:

$ python -m pytest plugins/codex-security/tests/test_generate_in_scope_files.py -q -k ignored
.F
>       assert result.returncode == 2, result.stdout
E       AssertionError: Recorded 10 in-scope files.
E         assert 0 == 2
1 failed, 1 passed, 23 deselected

After the change, same command and fixture:

$ python plugins/codex-security/scripts/generate_in_scope_files.py --repo <fixture> --scope . --out inv.txt
generate_in_scope_files: git ls-files exited with status 128: fatal: unknown repository extension found:
        exampleunsupported
exit=2

Still accepted, confirmed after the change:

  • healthy Git repository, same fixture: Recorded 3 in-scope files. including ./vendor/lib.py
  • directory with no .git: Recorded 1 in-scope files.

Checks run:

  • python -m pytest plugins/codex-security/tests/test_generate_in_scope_files.py -q — 21 passed, 4 skipped. The 4 skips are host-capability gates on this machine (2 need symlink creation privilege, 2 need executable script shims that Windows cannot launch); they skip on main as well.
  • python -m ruff check --config plugins/codex-security/pyproject.toml plugins/codex-security — All checks passed!
  • python -m ruff format --check --config plugins/codex-security/pyproject.toml plugins/codex-security — 137 files already formatted
  • tsc -p sdk/typescript/tsconfig.ci.json (build:ci) — clean
  • node .github/scripts/check_plugin_source_compatibility.mjs — Plugin source compatibility checks passed.
  • node --test .github/scripts/test_check_plugin_source_compatibility.mjs — 8 pass, 0 fail, 1 skipped

Risk and rollout

No public CLI surface changes: no new command, flag, environment variable, or default. The only behaviour change is that an inventory which previously succeeded with a silently truncated file list now fails with exit status 2 and Git's own diagnostic, which is the same contract the ripgrep step in this function already has.

This turns one previously tolerated situation into a failure: .git exists but Git cannot list the index. That is deliberate — for a security scan, a partial inventory reported as a complete one is worse than a stop with an actionable message, and the message points straight at the fix (add safe.directory, upgrade Git, repair the worktree). A repository with no .git entry is untouched, and a healthy repository behaves exactly as before.

Public disclosure review

  • No customer, partner, prospect, or user identities, data, or identifying details are included.
  • No credentials, personal data, private source, scan findings, or nonpublic links or tickets are included.
  • I reviewed the branch name, title, description, commits, changes, comments, logs, screenshots, attachments, and links for public disclosure.

`generate_in_scope_files` adds files that Git tracks but `.gitignore`
excludes, because ripgrep omits them. That `git ls-files` call sent its
stderr to `DEVNULL` and treated both a spawn failure and any non-zero
exit as "no such files", so a repository whose Git listing fails still
produced an inventory and reported success with those files missing.

Raise `InventoryError` with the captured Git message instead, matching
the ripgrep call a few lines above, which already fails the inventory on
a spawn error or an unexpected exit status.
@chatgpt-codex-connector

Copy link
Copy Markdown

Note

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions github-actions Bot added the bug Something isn't working label Sep 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant