Skip to content

fix(sieve): resolve case-exact file probes and deduplicate contents (fixes #645) - #658

Open
i-am-paradox wants to merge 1 commit into
darnitdevorg:mainfrom
i-am-paradox:fix/645-case-insensitive-file-probes
Open

i-am-paradox wants to merge 1 commit into
darnitdevorg:mainfrom
i-am-paradox:fix/645-case-insensitive-file-probes

Conversation

@i-am-paradox

Copy link
Copy Markdown
Contributor

Summary

Fixes #645.

On case-insensitive filesystems (such as macOS APFS and Windows NTFS), os.path.exists() and open() match lowercase file probes against uppercase files in the repository. As reported in #645, this causes sieve handlers to:

  1. Match candidate probes that don't match the repository's actual case (e.g., matching lowercase docs/architecture.md when only docs/ARCHITECTURE.md exists).
  2. Read duplicate file contents in llm_eval_handler and llm_extract_handler when files_to_include or files specify both case variants (such as README.md and readme.md).
  3. Cite paths in audit evidence that do not exist under exact case in the repository.

Key Changes

  1. Case-exact Directory Entry Validation:

    • Added resolve_case_exact_path(path, root=None) in darnit.core.utils to traverse each path component and verify it exists verbatim in the actual directory entries (os.listdir), ensuring exact-case matching across all platforms.
    • Cached directory entries via _dir_entries(dir_path) keyed by st_mtime_ns, ensuring zero subprocess overhead while automatically invalidating if remediation or user edits write files to disk.
    • Added get_file_identity(full_path) returning (st.st_dev, st.st_ino) for physical file deduplication across paths, symlinks, or aliases.
  2. Sieve Handler Updates:

    • file_exists_handler: verifies exact case for globs, max_depth walks, and direct path lookups.
    • _resolve_regex_files & _regex_exclude_evidence: ensures exact case matches and deduplicates candidate files by physical file identity.
    • llm_eval_handler & llm_extract_handler: enforces case-exact paths and deduplicates opened files before adding them to file_contents.
  3. Config & Baseline Alignment:

    • discover_files: verifies case-exact paths before returning mapped references.
    • openssf-baseline.toml: updated OSPS-SA-01.01 and OSPS-SA-02.01 to probe docs/ARCHITECTURE.md and docs/API.md (and .rst variants) while strictly adhering to the 5-file cap for files_to_include.
  4. Testing:

    • Added unit tests in tests/darnit/core/test_utils.py for resolve_case_exact_path and get_file_identity.
    • Added regression tests in tests/darnit/sieve/test_builtin_handlers.py for file_exists_handler, regex_handler, depth-limited walks, and llm_eval_handler case rejection & deduplication.
    • Added tests in tests/darnit/config/test_discovery.py verifying case-mismatched files are not discovered.
    • Ran complete test suites: tests/darnit (3,660 passed), tests/darnit_baseline (1,093 passed), and ruff check (all clean).

@Marc-cn Marc-cn left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, the approach is the one #645 asks for and the core of it reads right: case-exact traversal against os.listdir, the listing cache keyed by directory mtime, dedup by (st_dev, st_ino). 160 tests pass here.

Two things before merge:

  1. Please drop the unrelated reformatting. In core/utils.py about 60 of the 169 changed lines are untouched code rewritten by a formatter (quotes, joined argument lists, split f-strings), and sieve/builtin_handlers.py has the same. The project isn't formatted with ruff format, and these hunks hide the real change and conflict with every other PR touching those files.
  2. The TOML change isn't only about case: to stay at 5 entries, files_to_include drops docs/design.md (OSPS-SA-01.01) and swagger.json (OSPS-SA-02.01), so the LLM step stops reading those. @mlieberman85, that's a content call for you; if those files should stay, the uppercase variants could go into discover/files only.

Note for Mike: this edits discover_files in config/discovery.py, which #630's notes mark for removal after #622.

@i-am-paradox

Copy link
Copy Markdown
Contributor Author

Thanks @Marc-cn! Addressed both points in 0c37b6c:

  1. Dropped unrelated reformatting: Reverted untouched code formatting across core/utils.py, sieve/builtin_handlers.py, and config/discovery.py back to original repository style, eliminating all formatting churn.
  2. Preserved baseline files_to_include: Restored docs/design.md in OSPS-SA-01.01 and swagger.json in OSPS-SA-02.01 in files_to_include (leaving files_to_include identical to upstream main). The uppercase variants remain in discover and files (pattern).

All 160 tests in test_utils.py, test_discovery.py, and test_builtin_handlers.py pass cleanly.

…ixes darnitdevorg#645)

On case-insensitive filesystems (such as macOS APFS and Windows NTFS),
os.path.exists() and open() match lowercase file probes against uppercase
files in the repository. As reported in darnitdevorg#645, this causes sieve handlers to:
1. Match candidate probes that don't match the repository's actual case.
2. Read duplicate file contents in llm_eval_handler and llm_extract_handler
   when files_to_include or files specify both case variants.
3. Cite paths in audit evidence that do not exist under exact case in the repo.

Changes:
- Added resolve_case_exact_path(path, root=None) in darnit.core.utils.
- Cached directory entries via _dir_entries(dir_path) keyed by st_mtime_ns.
- Added get_file_identity(full_path) returning (st_dev, st_ino) for physical file deduplication.
- file_exists_handler: verifies exact case for globs, max_depth walks, and direct path lookups while preserving repository containment.
- _resolve_regex_files & _regex_exclude_evidence: ensures exact case matches and deduplicates by physical file identity.
- llm_eval_handler & llm_extract_handler: enforces case-exact paths and deduplicates opened files before adding to file_contents.
- discover_files: verifies case-exact paths before returning mapped references.
- openssf-baseline.toml: added docs/ARCHITECTURE.md and docs/API.md variants to discover and files.
- Unit and regression tests covering case-exact path validation, deduplication, and case-mismatched rejection.

Fixes darnitdevorg#645

Signed-off-by: Paradox <159635503+i-am-paradox@users.noreply.github.com>
@i-am-paradox
i-am-paradox force-pushed the fix/645-case-insensitive-file-probes branch from 0c37b6c to c91e235 Compare October 25, 2026 23:10
@Marc-cn

Marc-cn commented Oct 26, 2026

Copy link
Copy Markdown
Collaborator

Both of my points are addressed: the formatting churn is gone and files_to_include matches main. The case-exact walk only filters candidates, the reads still go through the #635 containment, so the two compose.

@mlieberman85: the uppercase variants added to the Baseline discover/files lists, and whether a 400-line change for case-insensitive filesystems is wanted given darnit mostly runs in Linux containers. The dedup of contents is the part I'd keep regardless.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

On a case-insensitive filesystem, file probes duplicate evidence and cite paths that are not in the repository

2 participants