Repository navigation
fix(session): report a missing Linux ps as provider unavailability in status - #7180
Conversation
… status On Linux without a procps-compatible ps on REA's PATH, the Apktool and JADX availability probes rethrew the owned-process prerequisite refusal, so binary_session failed as a whole and returned no provider status. Build the Linux refusal in one owner with a remediation, recognize it from the two probes, and project it as runtime_unavailable availability so the status call returns and the affected tool groups report provider_unavailable with the ps reason. Execution paths keep refusing with capability_unavailable. Fixes morluto#7164
[Medium impact] The PR appears safe to merge; no new blocking issue was found. SummaryMissing Linux
Source checks found no new actionable issues. Tests were not run during this review. Whether another PR supersedes this one could not be verified because GitHub access was unavailable. Diagram%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Linux ownership preparation] --> B[Missing or incompatible ps]
B --> C[Dedicated prerequisite error]
C --> D{Caller}
D -->|binary_session readiness| E[Report affected provider unavailable]
E --> F[Keep other provider statuses]
D -->|open_binary selection| G[Preserve execution refusal]
Reviews (3) · Last reviewed commit: "fix(session): keep the ps refusal owner ..." · Reviewed by Greptile |
…nux ps The Ghidra Java probe raised the same owned-process refusal during binary_session readiness, and the registry failed the whole status call. Project the refusal in the registry's candidate readiness step as well. Recognize the refusal by a dedicated LinuxOwnedProcessPrerequisiteError, following re-attributed capability errors through their cause, instead of matching provider and operation strings. Keep the install guidance in the availability reason only, so execution refusals keep their prior remediation action.
|
Re-ran the Linux container E2E on the final head
Full output is in the PR body. Tests: registry/apktool 98 passed, JADX/session/status boundary 35 passed, |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: daeaa31b7c
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Only binary_session projects a missing Linux ps into per-provider unavailability. open_binary shares candidate inspection, so it now rethrows the process-ownership refusal as before. The installation guide also notes that earlier configuration failures keep their own reason.
|
Want your agent to iterate on Greptile's feedback? Try greploops. |
|
Independent validation of
Merging the existing contributor PR preserves its authorship and avoids a duplicate implementation. |
Summary
Fixes #7164.
On a Linux host without a procps-compatible
pson REA'sPATH,binary_session {}failed as a whole withcapability_unavailable(operationinspect_apktool_client, "spawn ps ENOENT") and returned no provider status at all. The status call now returns. The Apktool and JADX tool groups reportavailable: false, reasonprovider_unavailable, with a remediation that names the missingps. A configured Ghidra candidate, whose readiness check runs an owned Java probe, reportsruntime_unavailablewith the same reason. Every other provider keeps its own status.Problem and expected behavior
Trigger:
rea mcpover stdio withPATHlackingps, thenbinary_session {}(thesession.mjsfrom the issue). Observed onmain1173c0a9d:isError: true, the Linux owned-process refusal escapes the availability probe and the whole discovery call fails, even though Apktool is not installed.Violated invariant:
inspectAvailabilityis a bounded host observation that answers with aProviderAvailability; the discovery call aggregates these answers and must not lose every provider's status because one optional probe met a host prerequisite it cannot satisfy.The same shape applies to the JADX probe when
REA_JADX_MCP_JARandJAVA_HOMEare configured, and to the deep-provider registry whenGHIDRA_INSTALL_DIRis set: the Ghidra Java probe raises the refusal during readiness and the registry fails the whole status call (both reproduced below). The adb probe does not launch an owned child and was not affected.Change and scope
src/process/ProcessOwnershipObservation.ts): the Linuxpreparerefusal is now a dedicatedLinuxOwnedProcessPrerequisiteError(a subclass ofAnalysisCapabilityUnavailableErrorwith the same tag, provider id, operation, reason and user message). Execution-path projections are unchanged.src/application/ownedProcessAvailability.ts):ownedProcessPrerequisiteAvailabilityrecognizes that class, following capability errors that provider adapters re-attribute while keeping the original ascause(Ghidra does this), and returns{ status: "unavailable", code: "runtime_unavailable", reason: <refusal reason + install guidance>, diagnostics: { stage: "ownership_preparation", ... } }. A refusal that carries incomplete cleanup is not projected.AnalysisProviderRegistry) when it servesbinary_session, return that availability instead of rethrowing. The registry keeps the provider's declared capabilities for the unavailable candidate. Foropen_binarythe registry rethrows the refusal, so selection keeps theprocess-ownershipowner and message. Execution paths (inspect_apktool_client,inspect_android_package, deep-provider opens, ...) still refuse withcapability_unavailable; only discovery changes.docs/installation.md"Linux owned-process prerequisite" states the discovery behavior.Not included: a generic guard that swallows any probe rejection. Only this one host-prerequisite refusal is projected; unexpected probe errors, cancellation and incomplete cleanup still fail the call as before. The macOS helper-compilation failure path (
ProviderAdapterError, stageownership_preparation) is a different failure and is unchanged.Contract and boundary impact
preparerefusal (process layer) owns the fact; the Apktool/JADX probes and the registry readiness step consume it through one projection. The string-based recognition from the first revision of this PR was removed. Session status aggregation and inventory mapping are unchanged.binary_sessionoutput gains no fields;tool_availabilitygroups for Apktool/JADX carry thepsreason asremediationon affected hosts.preparebranch is Linux-specific); tests exercise the same path on macOS/Linux through the hostpreparehook.Expected effects:
Evidence and regression coverage
src/apktool/ApktoolProvider.test.ts: the prerequisite refusal becomesruntime_unavailableavailability;inspect_apktool_clientexecution still refuses withcapability_unavailableandprovider_id: process-ownership.tests/boundary/android/jadxConfiguration.test.ts: same forinspectJadxAvailabilitywith a fake JDK and a valid engine JAR;validateJadxConfigurationstill rejects.src/application/binary/AnalysisProviderRegistry.test.ts: a candidate whose readiness rejects with a re-attributed capability error caused by the refusal becomesruntime_unavailablewhile another candidate staysavailable; explicitselectforopen_binarystill returns theprocess-ownershiprefusal.tests/boundary/mcp/sessionMcp.test.ts: a realApktoolProviderbehindcreateServerwhose hostprepareraises the refusal;binary_sessionreturns status, the Apktool group isprovider_unavailablewith thepsremediation, and the adb group staysavailable. On the base revision this call returnsisError: true.mainand the final head, six cases including Ghidra and two execution-path checks. See the table and details blocks below.ps-less Linux host was exercised; the JADX case uses a fakejavascript and the Ghidra case an empty install directory, both of which reach the owned Java probe (and so the prerequisite) first. Other deep providers whose readiness might launch an owned child are covered by the registry projection but were not individually exercised. Windows and macOS production paths are untouched.E2E on the final head (
ec57e834d) and onmain(1173c0a9d), both built in the same Linux arm64 container (node:24-bookworm, Node 24.22.1). The script startsscripts/rea.mjs mcpover stdio with onlyHOMEand the givenPATH, callsbinary_session {}, in cases 4 and 5 also runsinspect_apktool_client, and in case 6 runs onlyopen_binary {path: "/usr/bin/env", provider_id: "ghidra"}. In the output,<ps-refusal>abbreviates "Linux process ownership inspection requires a procps-compatible ps on REA's PATH before launching a child:".PATH=""(issue repro)provider_unavailablewith thepsreasonPATH=""+ JADX configuredprovider_unavailablewith thepsreasonPATH=""+GHIDRA_INSTALL_DIRruntime_unavailablewith thepsreasonPATH="", then runinspect_apktool_clientcapability_unavailableremediation.actionpsonPATH(control)PATH=""+GHIDRA_INSTALL_DIR,open_binarywithprovider_id: "ghidra"psmessagemain 1173c0a
this PR ec57e83
Boundary regressions covered:
psis missing is reported asruntime_unavailablewith thepsreason, instead of failing the whole status; other providers keep their own availability (registry test,sessionMcp.test.ts, E2E cases 1-3, control case 5).binary_sessionthrough a real MCP server insessionMcp.test.tsand the stdio E2E above; the execution refusal keeps its code, provider andremediation.action(inspect_apktool_clientcase 4,open_binarycase 6). Gap: the CLI was not run separately.Lifecycle regressions: not applicable. The refusal happens before any child starts, so no process or cleanup stage is involved.
For evidence-bearing changes:
Validation performed
npm run test:local -- src/application/binary/AnalysisProviderRegistry.test.ts src/apktool/ApktoolProvider.test.ts— 98 passed.npm run test:focused -- tests/boundary/android/jadxConfiguration.test.ts tests/boundary/mcp/sessionMcp.test.ts src/application/binary/BinarySessionStatus.test.ts— 35 passed.npm run check:fast— typecheck and lint passed.npm run docs:check— passed.main1173c0a9dand the final headec57e834d— all six cases as in the table: cases 1-3 fail as a whole on main and return status on this PR; cases 4-6 are identical.daeaa31b7returned the genericprovider_unavailable"The selected analysis provider is unavailable" without thepsreason.ec57e834dfixes that, and the new registry assertion fails without the fix.ec57e834d:npm run test:focused --registry, Apktool, JADX configuration and session MCP files — 126 passed;npm run check:fastandnpm run docs:check— passed.Compatibility, safety, and release
remediation.action; only discovery output changes.pslookup failure.Author readiness
Human owner: @chordpli
Before merge
type(scope): outcome.