Skip to content

feat: enforce gitignore protection across bash tool and indexer#39

Merged
A-Souhei merged 2 commits intomainfrom
feat/gitignore-enforcement
Mar 13, 2026
Merged

feat: enforce gitignore protection across bash tool and indexer#39
A-Souhei merged 2 commits intomainfrom
feat/gitignore-enforcement

Conversation

@A-Souhei
Copy link
Owner

Summary

Closes the known gap where gitignored files could still be read by bash commands other than cat, and removes the Faker-based content substitution from the indexer in favour of simply skipping gitignored files.

Changes

bash.ts

  • Expanded the path-resolution loop condition from a hardcoded 9-command list to also include all FILE_READ_CMDS (head, tail, grep, sed, awk, less, more, sort, uniq, wc, strings, xxd, od, base64, python, python3, node, perl, ruby) — these now all trigger the gitignore check
  • Added FILE_FLAG_CMDS (grep, awk, sed) + skipNext pattern so that -f <file> flag-value arguments (e.g. grep -f .env pattern) are also resolved and gitignore-checked; compound flags like -fn handled via regex /^-[a-zA-Z]*f/
  • Removed tee from FILE_READ_CMDStee is a write command (reads stdin, not files by path); its gitignore check was a no-op
  • let commandTextconst commandText (style guide)

indexer/index.ts

  • indexFile() now returns null immediately for gitignored files instead of calling Faker.fakeContent() and embedding fake data
  • Removed import { Faker }, indexedPath, is_gitignored payload field, and RETURN 4 → RETURN 3 in Redis backend
  • Indexer.search() simplified — no longer needs a ternary to redact real paths for gitignored results

test/tool/bash.test.ts

  • Added gitignore-blocking tests for head, tail, grep, sed
  • Extracted setupGitignore(dir) helper to eliminate 5× duplicated boilerplate
  • Added -c user.email=test@test.com -c user.name=Test to git setup calls (prevents silent CI failures without a global git config)
  • Removed .quiet() from git setup commands so failures surface

Known limitations (documented, not fixed — architectural)

  • Variable expansion (cat $SECRET) bypasses static analysis — tree-sitter filters expansion nodes
  • Symlinks to out-of-tree sensitive files bypass isGitignored
  • Mutation commands (rm .env, mv .env /tmp) are not gitignore-checked
  • Inline interpreter execution (python -c "...", node -e "...") bypasses the check

- Expand bash.ts path-resolution loop to cover all FILE_READ_CMDS
  (head, tail, grep, sed, awk, less, more, etc.) so gitignored files
  are blocked across the board, not just for cat
- Add FILE_FLAG_CMDS + skipNext pattern to catch grep/awk/sed -f <file>
  flag-value args that previously bypassed the gitignore check
- Remove tee from FILE_READ_CMDS (write command, not a read command)
- Fix let → const for commandText (style)
- Indexer: skip gitignored files entirely instead of faking content;
  remove Faker import, is_gitignored payload field, and related code
- Tests: add head/tail/grep/sed gitignore-blocking tests; extract
  setupGitignore helper; add git identity to prevent CI failures
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enforces gitignore protection by expanding the bash tool's file-read command list and gitignore check, and simplifies the indexer to skip gitignored files entirely instead of faking their content. It also renames the index CLI command to indexer.

Changes:

  • Expanded bash tool gitignore checks to cover ~20 file-reading commands and added FILE_FLAG_CMDS handling for -f flag arguments
  • Simplified indexer to return null for gitignored files instead of using Faker.fakeContent()
  • Renamed CLI command from index to indexer and added corresponding tests

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/opencode/src/tool/bash.ts Added FILE_READ_CMDS/FILE_FLAG_CMDS sets and gitignore check for file-reading commands
packages/opencode/src/indexer/index.ts Skip gitignored files entirely instead of faking content; removed Faker import and is_gitignored field
packages/opencode/test/tool/bash.test.ts Added gitignore-blocking tests for head/tail/grep/sed with shared setupGitignore helper
packages/opencode/src/cli/cmd/indexer.ts Renamed IndexCommand to IndexerCommand, command index to indexer
packages/opencode/src/index.ts Updated import/usage to IndexerCommand
Makefile Added indexer to CLI command list

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +146 to +151
let skipNext = false
for (const arg of command.slice(1)) {
if (arg.startsWith("-") || (command[0] === "chmod" && arg.startsWith("+"))) continue
if (skipNext) {
skipNext = false
} else if (arg.startsWith("-") || (command[0] === "chmod" && arg.startsWith("+"))) {
if (FILE_FLAG_CMDS.has(command[0]) && /^-[a-zA-Z]*f/.test(arg)) skipNext = true
@@ -740,19 +737,14 @@ export namespace Indexer {
if (!stat.isFile()) return null
if (stat.size > maxFileSizeBytes()) return null

- bash.ts: remove no-op skipNext/FILE_FLAG_CMDS — file args after -f
  already fall through to gitignore check as regular positional args
- indexer/index.ts: restore mtime-based early return so incremental
  indexing still skips unchanged files (was accidentally removed with
  the Faker cleanup)
@A-Souhei A-Souhei merged commit fcdd589 into main Mar 13, 2026
1 check passed
@A-Souhei A-Souhei deleted the feat/gitignore-enforcement branch March 13, 2026 10:37
A-Souhei added a commit that referenced this pull request Mar 13, 2026
Gitignored files now return -stat.mtimeMs instead of null so callers
store a sentinel in the mtime cache. This prevents re-running the
gitignore check on every startup for every gitignored file (fixing the
re-index-from-zero regression introduced in PR #39), while ensuring
the mtime early-return never fires for gitignored files — so
un-gitignoring a file without touching its mtime still triggers a
proper re-index on the next run.

No file content is read and no vectors are stored for gitignored files;
the gitignore safety property from PR #39 is fully preserved.
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