Skip to content

uphold 1.1.1: one answer about a file that is not text - #10

Merged
HackingGate merged 1 commit into
mainfrom
fix/guard-reads-the-not-text-declaration
Aug 12, 2026
Merged

uphold 1.1.1: one answer about a file that is not text#10
HackingGate merged 1 commit into
mainfrom
fix/guard-reads-the-not-text-declaration

Conversation

@HackingGate

@HackingGate HackingGate commented Aug 12, 2026

Copy link
Copy Markdown
Owner

uphold scan reads .gitattributes, skips a path declared -text, and says it skipped it. The guard over the same files did not read the declaration -- it opened the bytes, failed to decode them, and refused -- so a repository that took one of the three cures the reference names got a clean tree from one seam and exit 2 from the other, on every commit touching the file. Found on a real repository with a Shift-JIS capture fixture already declared binary in .gitattributes.

The NUL test keeps its job: it is the guess about bytes nobody declared. Where the declaration itself could not be read, the refusal stands with that reason attached.

Also reorders the guard fixture builder to write its policy after git init: several fixtures carry a policy meant to be refused at load, and with this binary installed in front of git the shim reads that policy before it knows whether anything stands in front of the command.

Summary by CodeRabbit

  • New Features

    • The Unicode guard now respects .gitattributes entries that mark files as non-text, skipping those files during content checks.
    • Skipped paths are reported, and clearer diagnostics are provided when file classification is unavailable.
  • Bug Fixes

    • Unclassified files containing undecodable data are still safely refused, while explicitly marked non-text files are accepted.
  • Documentation

    • Updated installation and setup references for release v1.1.1.

`uphold scan` reads `.gitattributes`, skips a path declared `-text` and
says it skipped it -- the use its own doc comment names, a captured page
kept byte-for-byte in the encoding its venue served. The guard over the
same files did not read the declaration: it opened the bytes, failed to
decode them, and refused. So a repository that took one of the three
cures the reference names got a clean tree from one seam and exit 2 from
the other, on every commit that touched the file.

The NUL test keeps its own job, and the comment beside it is still right
about what it is for: it is the guess about bytes NOBODY declared. A
declaration is not a guess, so where there is one it answers first, and
where the declaration itself could not be read the refusal stands with
that reason attached.

The fixture builder here now writes its policy after `git init` rather
than before, because several fixtures carry a policy meant to be refused
at load -- and on a machine where this binary is installed in front of
`git`, the shim reads that policy before it knows whether anything stands
in front of the command, so the setup failed in the shape of the subject.
@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Unicode guard now reads .gitattributes to skip declared non-text paths and reports skipped files. CLI tests cover undecodable staged bytes before and after a -text declaration. Package and installation references update to 1.1.1.

Changes

Unicode guard and release update

Layer / File(s) Summary
Unicode guard .gitattributes handling
src/guard/unicode.rs
The guard normalizes paths, reads non-text declarations, skips declared paths, and reports declaration or read errors.
Unicode guard CLI validation
tests/guard_cli.rs
The fixture configures Git before policy creation. Tests verify refusal of undeclared bytes and successful skipping after a -text declaration.
Version and installation references
Cargo.toml, README.md, hooks/lefthook.yml
Package and documented installation references change from 1.1.0 to 1.1.1.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant UnicodeGuard as Unicode guard
  participant GitAttributes as .gitattributes
  participant StagedFile as staged file
  UnicodeGuard->>GitAttributes: read non-text declaration
  GitAttributes-->>UnicodeGuard: return normalized path
  UnicodeGuard->>StagedFile: inspect filename and bytes
  UnicodeGuard->>UnicodeGuard: skip declared non-text path
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title references non-text files, but the phrase "one answer" is vague and does not clearly describe the .gitattributes handling change. Use a concise title such as "uphold 1.1.1: skip files marked -text in .gitattributes".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/guard-reads-the-not-text-declaration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov-commenter

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 88.41%. Comparing base (b7839a2) to head (61f734e).

Additional details and impacted files
@@            Coverage Diff             @@
##             main      #10      +/-   ##
==========================================
+ Coverage   88.38%   88.41%   +0.03%     
==========================================
  Files          24       24              
  Lines        7162     7181      +19     
==========================================
+ Hits         6330     6349      +19     
  Misses        832      832              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/guard/unicode.rs`:
- Around line 291-293: Update src/guard/unicode.rs at lines 291-293 so
not_text_paths resolves .gitattributes from the same staged or committed tree
used by scope::blobs, rather than the working tree; preserve path normalization
and declared_not_text construction. Add regression coverage in
tests/guard_cli.rs at lines 265-279 that reproduces an unstaged .gitattributes
change suppressing scanning of a staged blob and verifies the blob is still
scanned.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 36fc8428-984d-45b2-af82-43930a9dfa86

📥 Commits

Reviewing files that changed from the base of the PR and between b7839a2 and 61f734e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • Cargo.toml
  • README.md
  • hooks/lefthook.yml
  • src/guard/unicode.rs
  • tests/guard_cli.rs

Comment thread src/guard/unicode.rs
Comment on lines +291 to +293
let (not_text, unmeasured) = not_text_paths(request.root);
let declared_not_text: BTreeSet<&str> =
not_text.iter().map(|path| normalize_rel(path)).collect();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the declaration-selection module before inspecting the implementation.
ast-grep outline src/selection.rs --items all

# Inspect whether declaration lookup uses Git's index, for example via
# `git check-attr --cached`, rather than the working tree.
rg -n -C 10 'fn not_text_paths\b|not_text_paths\(|check-attr|--cached|gitattributes' \
  src/selection.rs src/guard/unicode.rs

# Inspect the current staged-declaration test before adding the unstaged case.
sed -n '238,280p' tests/guard_cli.rs

Repository: HackingGate/uphold

Length of output: 21277


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- selection index and attribute implementation ---'
sed -n '50,180p' src/selection.rs

printf '%s\n' '--- staged blob collection and guard request construction ---'
rg -n -C 12 'fn blobs\b|blobs\(|struct Request|stage|index_bytes|from_index' src/guard src/selection.rs

printf '%s\n' '--- relevant guard tests and helpers ---'
rg -n -C 8 'a_path_declared_not_text|fn guard\b|--stage|pre-commit|captured.html' tests/guard_cli.rs tests

printf '%s\n' '--- local Git attribute semantics, without changing the repository ---'
git check-attr text -- .gitattributes 2>&1 || true
git check-attr --cached text -- .gitattributes 2>&1 || true

printf '%s\n' '--- source-level behavioral verifier ---'
python3 - <<'PY'
from pathlib import Path

selection = Path("src/selection.rs").read_text()
unicode = Path("src/guard/unicode.rs").read_text()

start = selection.index("pub(crate) fn not_text_paths")
end = selection.index("\npub(crate) struct Selection", start)
impl_text = selection[start:end]

assert 'args(["check-attr", "--stdin", "-z", "text"])' in impl_text
assert "--cached" not in impl_text
assert "current_dir(root)" in impl_text

blobs_call = unicode.index("let blobs =")
blobs_end = unicode.index(";", blobs_call)
request_call = unicode.index("not_text_paths(request.root)")
print("not_text_paths uses working-tree `git check-attr` without `--cached`.")
print("The guard resolves attributes from `request.root` independently of its staged blob collection.")
print("Conclusion:", request_call > blobs_end)
PY

Repository: HackingGate/uphold

Length of output: 50375


Resolve .gitattributes against the scanned tree.

not_text_paths uses working-tree attributes, while scope::blobs scans staged or pushed objects. An unstaged .gitattributes change can suppress scanning of a staged blob. Use the same staged or committed tree for both decisions, and add regression coverage.

📍 Affects 2 files
  • src/guard/unicode.rs#L291-L293 (this comment)
  • tests/guard_cli.rs#L265-L279
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/guard/unicode.rs` around lines 291 - 293, Update src/guard/unicode.rs at
lines 291-293 so not_text_paths resolves .gitattributes from the same staged or
committed tree used by scope::blobs, rather than the working tree; preserve path
normalization and declared_not_text construction. Add regression coverage in
tests/guard_cli.rs at lines 265-279 that reproduces an unstaged .gitattributes
change suppressing scanning of a staged blob and verifies the blob is still
scanned.

Source: Coding guidelines

@HackingGate
HackingGate merged commit e437d86 into main Aug 12, 2026
12 checks passed
@HackingGate
HackingGate deleted the fix/guard-reads-the-not-text-declaration branch August 12, 2026 15:56
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.

2 participants