Files
reverse-engineering-anything/src/application/ownedProcessAvailability.ts
T
Rishikesh Gowda K K 891371e738 fix(objdump): reflect observed launch failure in discovery availability (#9051)
* fix(objdump): reflect observed launch failure in discovery availability

Distinguish a statically registered standalone command from an executable
whose launch has failed in the active server session. Discovery leaves
unprobed commands optimistically available, reports an observed launch
failure as provider_unavailable with the command remediation, keeps the
tool callable for retries, and clears the failure after a subsequent
successful launch.

Fixes #8826.

* test(reverse): verify overlapping command launch dispatch ordering

* test(reverse): unblock gated test workers before awaiting service closure

* test(reverse): bound lifecycle acknowledgement and join launched workers

* fix(reverse): distinguish host capacity exhaustion from command launch failures

* fix(reverse): preserve host capacity across Linux process ownership preparation

* fix(reverse): exclude process ownership admission failures from command launch state

* fix(reverse): preserve Darwin process ownership preparation error across command launch

* fix(reverse): disambiguate cleanup declaration in provider observation

* fix(reverse): preserve command deadline timeout during Darwin ownership preparation

* fix(reverse): isolate Darwin baseline ps errors and provide platform-aware admission guidance

* fix(reverse): rely on typed baseline admission failures and use owning repair formatter in tests

* test(reverse): use owning formatters for process ownership remediation assertions

* fix(reverse): restrict Linux ownership prerequisite remediation to missing ps and preserve system error codes

* fix(reverse): retain typed process ownership prerequisite with preserved error codes

* fix(reverse): remove unvalidated error label fallbacks and keep admission tags out of system_code

* fix(reverse): keep Windows native runner failures out of command-launch state

* fix(process): preserve current_process_unreported refusal in Linux provider readiness

* fix(process): distinguish no-code ps failure from missing ps and cover rizin launch failure

* fix(windows): classify process_spawn host-control rejections as RuntimeControlUnavailableError
2026-11-09 17:39:34 +08:00

107 lines
3.7 KiB
TypeScript

import { AnalysisCapabilityUnavailableError } from "../domain/analysisErrorCore.js";
import { ProviderAdapterError } from "../domain/providerAdapterError.js";
import { jsonValueSchema } from "../domain/jsonValue.js";
import { DarwinProcessOwnershipInspectionError } from "../process/DarwinProcessRunTokenReader.js";
import { OwnedCommandFailure } from "../process/OwnedCommand.js";
import {
LINUX_PROCESS_OWNERSHIP_REMEDIATION,
LinuxOwnedProcessPrerequisiteError,
} from "../process/ProcessOwnershipObservation.js";
import type { ProviderAvailability } from "./AnalysisProvider.js";
const DARWIN_REMEDIATION =
"Check the selected Xcode or Command Line Tools and Swift compiler configuration, then restart REA and retry.";
// Provider adapters re-attribute capability errors and keep the original as cause.
const prerequisiteRefusal = (
cause: unknown,
): LinuxOwnedProcessPrerequisiteError | undefined => {
if (
!(cause instanceof AnalysisCapabilityUnavailableError) ||
cause.cleanupIncomplete
)
return undefined;
for (
let current: unknown = cause;
current instanceof AnalysisCapabilityUnavailableError;
current = current.cause
)
if (current instanceof LinuxOwnedProcessPrerequisiteError) return current;
return undefined;
};
// Recognize only failures attributed to owned-process preparation. Cancellation
// and failed cleanup remain errors so their owner and completion are not lost.
const darwinPrerequisiteRefusal = (
cause: unknown,
): DarwinProcessOwnershipInspectionError | undefined => {
let current = cause;
while (current instanceof ProviderAdapterError) {
if (
current.cleanupIncomplete ||
current.diagnostics?.stage !== "ownership_preparation"
)
return undefined;
current = current.cause;
}
if (current instanceof OwnedCommandFailure) {
if (
current.reason !== "process" ||
current.cleanupOwner !== undefined ||
current.cleanupFailure !== null ||
current.cleanupResult !== undefined ||
current.cancellation !== undefined
)
return undefined;
current = current.preparationFailure;
}
return current instanceof DarwinProcessOwnershipInspectionError &&
current.cleanupFailure === undefined &&
current.cleanupOwner === undefined &&
current.cancellation === undefined
? current
: undefined;
};
/** A host prerequisite gap is the probed provider's unavailability, not a probe failure. */
export const ownedProcessPrerequisiteAvailability = (
cause: unknown,
): ProviderAvailability | undefined => {
const refusal = prerequisiteRefusal(cause);
if (refusal !== undefined) {
const remediation =
refusal.remediationAction ?? LINUX_PROCESS_OWNERSHIP_REMEDIATION;
return {
status: "unavailable",
code: "runtime_unavailable",
reason: `${refusal.reason}. ${remediation}`,
remediation,
diagnostics: {
stage: "ownership_preparation",
prerequisite_provider_id: refusal.providerId,
prerequisite_operation: refusal.operation,
...(refusal.diagnostics?.admission_code === undefined
? {}
: { admission_code: refusal.diagnostics.admission_code }),
...(refusal.diagnostics?.system_code === undefined
? {}
: { system_code: refusal.diagnostics.system_code }),
},
};
}
const darwin = darwinPrerequisiteRefusal(cause);
if (darwin === undefined) return undefined;
return {
status: "unavailable",
code: "runtime_unavailable",
reason: `${darwin.message}. ${DARWIN_REMEDIATION}`,
remediation: DARWIN_REMEDIATION,
diagnostics: {
stage: "ownership_preparation",
...(darwin.compilerOutcome === undefined
? {}
: { compiler_outcome: jsonValueSchema.parse(darwin.compilerOutcome) }),
},
};
};