Skip to content

fix(security): resolve tool paths absolutely, close digest evidence gaps - #56

Merged
2233admin merged 6 commits into
mainfrom
fix/path-resolution-digest-hardening
Jul 27, 2026
Merged

fix(security): resolve tool paths absolutely, close digest evidence gaps#56
2233admin merged 6 commits into
mainfrom
fix/path-resolution-digest-hardening

Conversation

@2233admin

Copy link
Copy Markdown
Owner

Summary

Fixes three self-audit findings in one PR:

  • security-004 (info/low-confidence): Command::new("rg")/Command::new("git") were launched by bare program name while the child's current_dir() was set to the repo under analysis — a scanned repo that plants its own rg.exe/git.exe could win Windows's PATH search. Added crates/code-intel-cli/src/tool_path.rs, a shared absolute-path resolver that reuses doctor_adapter.rs's existing tool-inventory candidate/PATH-scan logic (no new resolution logic written). Routed every production call site through it: hardened_git.rs (the single choke point for all git invocations — covers snapshot.rs, sentrux_analysis.rs, sentrux_gate.rs, audit_report/cli.rs transitively), sentrux_analysis.rs, snapshot.rs, capability_inventory.rs. doctor_adapter.rs::tool_available() now delegates to the same resolver so presence-checking and launch-time resolution can never drift apart. Mirrored the same fix in tools/sentrux-shim/sentrux-shim.ps1's rg/git invocations.

  • supply-chain-008 (low): 4 of 14 orchestration/integrations.json capability entries (doctor.envelope.compat, repository.snapshot.compat, advisory.workflow-recommend.compat, inventory.rg.compat) declared toolchainDigests with no toolchainDigestEvidence.inputs, making them unverifiable/non-drift-checkable. Added toolchainDigestEvidence.inputs to each, mapping to the actual source file(s) each capability key implements (traced through code, not guessed from the entrypoint field — e.g. inventory.rg's entrypoint string says run-code-intel.ps1 but its actual implementation is capability_inventory.rs::inventory()). Recomputed toolchainDigests via sha256 over those inputs.

  • supply-chain-009 (info): tools/sentrux-shim/sentrux-shim.ps1 fabricated a local Pro-tier license for third-party sentrux and auto-activated it on every bootstrapped machine, opt-out only, with no license justification anywhere in the tree. Searched README.md and install-code-intel-pipeline.ps1 for any genuine upstream license evidence — found none. Per the task's explicit instruction not to fabricate a justification that can't be substantiated, chose option (b): flipped auto-activation from opt-out to opt-in via SENTRUX_AUTO_PRO (only fires when explicitly set to "1"/"true", default off).

Why the diff is bigger than the 3 findings alone

tool_path.rs changed the byte content of doctor_adapter.rs, capability_inventory.rs, and snapshot.rs, which moved their sha256 digests. That shift cascades three layers deep, all required to keep cargo test -p code-intel green (an explicit gate for this change):

  1. Registryorchestration/integrations.json digests corrected (the supply-chain-008 fix itself).
  2. Test fixturescrates/code-intel-cli/tests/artifact_ref.rs and tests/capability_exec.rs hardcode inventory.rg/advisory.workflow-recommend request digests that capability.rs's cohere() validates against the registry; these were pinned to the pre-fix values and had to move with the registry.
  3. Provenance recordsorchestration/internalization/{git,rg,ast-grep,sentrux}.json independently embed sha256 of the same source/conformance files, live-recomputed and asserted by internalization_record.rs/ast_grep_internalization.rs; and run-code-intel.ps1 hardcodes the same advisory.workflow-recommend.compat request fixture as the Rust tests. All updated to the corrected values — value-only corrections, no logic changes, same "critical fix" character as the sentrux-shim.ps1 edit under AGENTS.md's carve-out.

Every one of these files was pulled in by an actual test failure that was root-caused, not by scope creep. All 35 toolchainDigestEvidence.inputs slots across the registry and all 84 operationTrace entries in the internalization records were independently re-verified against live file content after the fact.

Out of scope, deliberately: README.md/install-code-intel-pipeline.ps1 still describe the old default-Pro-activation behavior post supply-chain-009's opt-in flip. Flagged as a separate follow-up rather than folded in here, to keep this PR's diff limited to what the three findings and the test gate actually require.

Test plan

  • cargo build -p code-intel — 0 errors
  • cargo test -p code-intel — 2025 passed, 44 suites, 0 failed
  • pwsh -NoProfile -Command "[scriptblock]::Create(...)" on both edited .ps1 files — parses cleanly
  • orchestration/integrations.json and all touched orchestration/internalization/*.json — valid JSON
  • All 4 corrected toolchainDigestEvidence entries + the 4 other entries whose digest values shifted — independently re-verified as correct (not just plausible-looking hex)

Addresses security-004 from #33, supply-chain-008/009 from #35.

security-004: rg/git launched via Command::new(bare-name) with current_dir()
set to the repo under analysis, letting a scanned repo's own rg.exe/git.exe
win the Windows PATH search. Add crates/code-intel-cli/src/tool_path.rs,
a shared absolute-path resolver reusing doctor_adapter.rs's existing
tool-inventory candidate/PATH-scan logic, and route every production
Command::new("rg")/Command::new("git") call site through it
(hardened_git.rs, sentrux_analysis.rs, snapshot.rs, capability_inventory.rs).
doctor_adapter.rs's tool_available() now delegates to the same resolver so
presence-checking and launch-time resolution can't drift apart. Mirrored the
same fix in tools/sentrux-shim/sentrux-shim.ps1's rg/git invocations.

supply-chain-008: 4 of 14 orchestration/integrations.json capability entries
(doctor.envelope.compat, repository.snapshot.compat,
advisory.workflow-recommend.compat, inventory.rg.compat) declared
toolchainDigests with no toolchainDigestEvidence.inputs, so they could not be
drift-checked. Added evidence.inputs mapping each entry to the actual source
file(s) implementing it, and recomputed toolchainDigests via sha256 over
those inputs. Because tool_path.rs changed the byte content of
doctor_adapter.rs, capability_inventory.rs, and snapshot.rs, their digests
moved; that shift cascades through crates/code-intel-cli/tests/artifact_ref.rs
and tests/capability_exec.rs (hardcoded request fixtures validated against
the registry by capability.rs's cohere()), through
orchestration/internalization/{git,rg,ast-grep,sentrux}.json (provenance
records whose sha256 fields are live-recomputed and asserted by
internalization_record.rs/ast_grep_internalization.rs), and through
run-code-intel.ps1 (a hardcoded advisory.workflow-recommend.compat request
fixture). All of these were updated to keep cargo test -p code-intel green;
none of them are logic changes, only digest-value corrections.

supply-chain-009: tools/sentrux-shim/sentrux-shim.ps1 auto-activated a
fabricated local Pro-tier license for third-party sentrux on every
bootstrapped machine, opt-out only, with no upstream license evidence
anywhere in the tree to justify it. No genuine provenance could be found, so
auto-activation is now opt-in: it only fires when SENTRUX_AUTO_PRO is
explicitly set to an affirmative value ("1"/"true"), default off.

Addresses security-004 from #33, supply-chain-008/009 from #35.
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@2233admin, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 28 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ad8d6736-8631-49e1-9899-37f9c62459b1

📥 Commits

Reviewing files that changed from the base of the PR and between 4b60712 and 472e9c3.

📒 Files selected for processing (2)
  • orchestration/integrations.json
  • orchestration/internalization/sentrux.json
📝 Walkthrough

Walkthrough

The change adds shared absolute-path resolution for rg and git, updates command consumers and related digests, and changes local Pro activation to require explicit opt-in through SENTRUX_AUTO_PRO.

Changes

Absolute Tool Resolution

Layer / File(s) Summary
Shared tool path resolver
crates/code-intel-cli/src/tool_path.rs
Adds platform-aware lookup and absolute-path resolution for external tools, with unit tests for resolution behavior.
Resolved tool command adoption
crates/code-intel-cli/src/*.rs
Updates inventory, snapshot, analysis, doctor, and hardened Git command paths to use the shared resolver.
Digest and provenance synchronization
crates/code-intel-cli/tests/*, orchestration/**/*.json, run-code-intel.ps1, .sentrux/*
Updates implementation digests, toolchain evidence, internalization hashes, workflow fixtures, and analysis baseline metadata.

Explicit Pro Activation

Layer / File(s) Summary
Opt-in Pro activation flow
tools/sentrux-shim/sentrux-shim.ps1, install-code-intel-pipeline.ps1, check-code-intel-tools.ps1, README.md
Requires affirmative SENTRUX_AUTO_PRO values for automatic activation and documents free-by-default versus opt-in Pro behavior.

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

Sequence Diagram(s)

sequenceDiagram
  participant CapabilityAdapters
  participant tool_path
  participant ExternalTools
  CapabilityAdapters->>tool_path: resolve("rg") or resolve("git")
  tool_path->>tool_path: locate executable outside current directory
  tool_path-->>CapabilityAdapters: absolute executable path
  CapabilityAdapters->>ExternalTools: launch command with resolved path
Loading

Possibly related issues

Possibly related PRs

Poem

A bunny hops where tool paths gleam,
rg and git now chase one dream.
Pro waits for a yes, not chance,
Free by default, then joins the dance.
Hashes align in a tidy row—
Hop, hop, ship the change! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main changes: absolute tool-path resolution and digest evidence updates.
Description check ✅ Passed The description is clearly related to the changeset and describes the hardening and digest updates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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.

supply-chain-009 flipped SENTRUX_AUTO_PRO from opt-out to opt-in in
this branch; README.md and the install-plan text still described
auto-activation as the default. Update both to the opt-in reality.

@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: 2

🧹 Nitpick comments (1)
install-code-intel-pipeline.ps1 (1)

846-846: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use named parameters for Add-InstallPlan.

This changed call has many positional arguments, making future parameter additions easy to misbind. Named arguments also resolve the reported PSScriptAnalyzer warning.

🤖 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 `@install-code-intel-pipeline.ps1` at line 846, Update the Add-InstallPlan
invocation for "sentrux-shim" to pass every argument using its declared
parameter names instead of positional ordering. Preserve the existing values and
ordering semantics while eliminating positional binding and the associated
PSScriptAnalyzer warning.

Source: Linters/SAST tools

🤖 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 `@crates/code-intel-cli/src/tool_path.rs`:
- Around line 42-57: Update executable discovery in the prefix and PATH search
branches of the tool-path lookup function to canonicalize each matching
candidate with std::fs::canonicalize before returning it, ensuring relative or
empty PATH entries produce absolute paths. Add focused cargo test coverage for
relative and empty PATH components, plus the relevant integration-contract
checks.

In `@tools/sentrux-shim/sentrux-shim.ps1`:
- Around line 108-112: Retain the opt-in activation logic in sentrux-shim.ps1 at
lines 108-112. In install-code-intel-pipeline.ps1, update the installer health
checks at lines 490-493 and 903 to accept free/inactive status when
SENTRUX_AUTO_PRO is unset, while requiring Pro status only when the environment
variable is explicitly affirmative.

---

Nitpick comments:
In `@install-code-intel-pipeline.ps1`:
- Line 846: Update the Add-InstallPlan invocation for "sentrux-shim" to pass
every argument using its declared parameter names instead of positional
ordering. Preserve the existing values and ordering semantics while eliminating
positional binding and the associated PSScriptAnalyzer warning.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3b313e48-1462-4359-a058-2f508db04b18

📥 Commits

Reviewing files that changed from the base of the PR and between b73c16a and 5d0fe98.

📒 Files selected for processing (17)
  • README.md
  • crates/code-intel-cli/src/capability_inventory.rs
  • crates/code-intel-cli/src/doctor_adapter.rs
  • crates/code-intel-cli/src/hardened_git.rs
  • crates/code-intel-cli/src/sentrux_analysis.rs
  • crates/code-intel-cli/src/snapshot.rs
  • crates/code-intel-cli/src/tool_path.rs
  • crates/code-intel-cli/tests/artifact_ref.rs
  • crates/code-intel-cli/tests/capability_exec.rs
  • install-code-intel-pipeline.ps1
  • orchestration/integrations.json
  • orchestration/internalization/ast-grep.json
  • orchestration/internalization/git.json
  • orchestration/internalization/rg.json
  • orchestration/internalization/sentrux.json
  • run-code-intel.ps1
  • tools/sentrux-shim/sentrux-shim.ps1

Comment on lines +42 to +57
if let Some(prefix) = prefix {
if let Some(found) = names
.iter()
.map(|candidate| prefix.join(candidate))
.find(|full| full.is_file())
{
return Some(found);
}
}
let path = env::var_os("PATH")?;
env::split_paths(&path).find_map(|dir| {
names
.iter()
.map(|candidate| dir.join(candidate))
.find(|full| full.is_file())
})

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 | 🔴 Critical | ⚡ Quick win

Canonicalize located executables before returning them.

A relative or empty PATH component (for example .) makes dir.join(candidate) relative. Downstream Command::new calls then apply the scanned repository as current_dir, allowing a planted rg/git there to execute. Return std::fs::canonicalize(full) for found candidates and add a regression test for relative/empty PATH entries.

Proposed fix
+use std::fs;
 use std::env;
 
+fn existing_absolute(path: PathBuf) -> Option<PathBuf> {
+    if !path.is_file() {
+        return None;
+    }
+    fs::canonicalize(path).ok()
+}
+
 pub(crate) fn locate(name: &str, prefix: Option<&Path>) -> Option<PathBuf> {
     let names = candidates(name);
     if let Some(prefix) = prefix {
-        if let Some(found) = names
+        if let Some(found) = names
             .iter()
             .map(|candidate| prefix.join(candidate))
-            .find(|full| full.is_file())
+            .find_map(existing_absolute)
         {
             return Some(found);
         }
     }
     let path = env::var_os("PATH")?;
     env::split_paths(&path).find_map(|dir| {
         names
             .iter()
             .map(|candidate| dir.join(candidate))
-            .find(|full| full.is_file())
+            .find_map(existing_absolute)
     })
 }

As per coding guidelines, “Rust changes require focused cargo test coverage plus the relevant integration-contract checks.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if let Some(prefix) = prefix {
if let Some(found) = names
.iter()
.map(|candidate| prefix.join(candidate))
.find(|full| full.is_file())
{
return Some(found);
}
}
let path = env::var_os("PATH")?;
env::split_paths(&path).find_map(|dir| {
names
.iter()
.map(|candidate| dir.join(candidate))
.find(|full| full.is_file())
})
use std::fs;
fn existing_absolute(path: PathBuf) -> Option<PathBuf> {
if !path.is_file() {
return None;
}
fs::canonicalize(path).ok()
}
if let Some(prefix) = prefix {
if let Some(found) = names
.iter()
.map(|candidate| prefix.join(candidate))
.find_map(existing_absolute)
{
return Some(found);
}
}
let path = env::var_os("PATH")?;
env::split_paths(&path).find_map(|dir| {
names
.iter()
.map(|candidate| dir.join(candidate))
.find_map(existing_absolute)
})
🤖 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 `@crates/code-intel-cli/src/tool_path.rs` around lines 42 - 57, Update
executable discovery in the prefix and PATH search branches of the tool-path
lookup function to canonicalize each matching candidate with
std::fs::canonicalize before returning it, ensuring relative or empty PATH
entries produce absolute paths. Add focused cargo test coverage for relative and
empty PATH components, plus the relevant integration-contract checks.

Source: Coding guidelines

Comment thread tools/sentrux-shim/sentrux-shim.ps1
The shared tool_path resolver (security-004) adds one module imported by
six call sites, moving coupling 45.13 -> 45.33 and quality 3968 -> 3967.
This is the fix's intrinsic structural cost — the same documented
re-baseline procedure used for the ast-grep internalization suite
(45.07 -> 45.13). Cycles and god files unchanged. Gate and full
self-scan verified green locally after the re-baseline.
Flipping Pro auto-activation to opt-in left three health checks still
requiring Tier: pro unconditionally, so a default install now failed its
own installer verification, the tool:sentrux-pro required check, and
check-code-intel-tools' missing-list (CI Install portable pipeline step
red on all four runners). The expected tier now follows the opt-in: pro
when SENTRUX_AUTO_PRO is affirmative, pro-or-free otherwise, mirroring
the shim's own truthiness set.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
install-code-intel-pipeline.ps1 (1)

850-850: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the SENTRUX_AUTO_PRO guidance PowerShell-appropriate. SENTRUX_AUTO_PRO=1 is valid CMD/POSIX syntax, not PowerShell syntax; either update these hints to $Env:SENTRUX_AUTO_PRO='1' for PowerShell users or explicitly say it applies to CMD/cmd.exe.

🤖 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 `@install-code-intel-pipeline.ps1` at line 850, Update the SENTRUX_AUTO_PRO
guidance in the Add-InstallPlan entry and the related guidance at
install-code-intel-pipeline.ps1 lines 907-910 to use PowerShell syntax
($Env:SENTRUX_AUTO_PRO='1') or explicitly identify the existing syntax as
CMD/cmd.exe syntax; keep the opt-in behavior unchanged.
🤖 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.

Outside diff comments:
In `@install-code-intel-pipeline.ps1`:
- Line 850: Update the SENTRUX_AUTO_PRO guidance in the Add-InstallPlan entry
and the related guidance at install-code-intel-pipeline.ps1 lines 907-910 to use
PowerShell syntax ($Env:SENTRUX_AUTO_PRO='1') or explicitly identify the
existing syntax as CMD/cmd.exe syntax; keep the opt-in behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 44ff834c-6df9-4ee9-95bb-81f2e36514f6

📥 Commits

Reviewing files that changed from the base of the PR and between 7d6d271 and 4b60712.

📒 Files selected for processing (2)
  • check-code-intel-tools.ps1
  • install-code-intel-pipeline.ps1

…olution

Resolving the sentrux.json conflict with a whole-file --theirs take kept
main's post-#45 sentrux_gate.rs digest but discarded this branch's own
re-pin for the edited sentrux_analysis.rs, failing
internalization_record.rs ticket_r03 on every platform. Recomputed and
swept all 35 internalization records for stale digests (only this one).
Full suite green locally: 44 suites, 2082 passed, 0 failed.
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.

1 participant