mirror of
https://github.com/morluto/rea
synced 2026-10-25 22:08:11 -04:00
fix(pcap): share capture host admission with discovery
This commit is contained in:
@@ -30,6 +30,8 @@ Evidence. Capture
|
||||
inspection requires Linux with util-linux prlimit or Windows with owned Job
|
||||
Objects. macOS capture inspection returns a capability gap because the new
|
||||
native memory boundary is unverified; its version probes remain available.
|
||||
`binary_session` advertises those operations separately: unsupported capture
|
||||
hosts do not disable the client probe or remove either tool from the catalog.
|
||||
A selected tool directory or unreadable tool is a configuration capability
|
||||
refusal naming its selected path, before any capture bytes are opened.
|
||||
Tools and installed libraries/plugins are caller-trusted. An empty private
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { pcapCaptureHostSupported } from "../domain/pcap/pcapAnalysis.js";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import {
|
||||
@@ -815,3 +816,30 @@ describe("host-restricted integrations", () => {
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it.each(["darwin", "linux", "win32"])(
|
||||
"distinguishes pcap capture host support from its target-free client probe on %s",
|
||||
(platform) => {
|
||||
const tools = buildCapabilityInventory(
|
||||
{ open: false, capabilities: [] },
|
||||
{
|
||||
processCaptureEnabled: true,
|
||||
hostUnsupported: { pcapCapture: !pcapCaptureHostSupported(platform) },
|
||||
},
|
||||
);
|
||||
expect(
|
||||
tools.find(({ name }) => name === "inspect_pcap_client"),
|
||||
).toMatchObject({ available: true, reason: "available" });
|
||||
expect(
|
||||
tools.find(({ name }) => name === "inspect_pcap_capture"),
|
||||
).toMatchObject(
|
||||
platform === "darwin"
|
||||
? {
|
||||
available: false,
|
||||
reason: "unsupported_host",
|
||||
remediation: expect.stringContaining("native memory bound"),
|
||||
}
|
||||
: { available: true, reason: "available" },
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { PCAP_CAPTURE_UNSUPPORTED_HOST_REASON } from "../domain/pcap/pcapAnalysis.js";
|
||||
import { DEFAULT_CALL_RELATIONSHIP_DIRECTION } from "../contracts/enhancedInputs.js";
|
||||
import { FIRMWARE_TOOL_REQUIREMENTS } from "../contracts/firmware/firmwareToolRequirements.js";
|
||||
import { CALL_RELATIONSHIP_TRAVERSALS } from "./CallRelationshipTraversal.js";
|
||||
@@ -56,6 +57,7 @@ type ProviderDescriptor = ProviderCapability;
|
||||
/** Optional integrations whose verified hosts exclude some platforms. */
|
||||
export const HOST_RESTRICTED_FEATURES = [
|
||||
"packetCapture",
|
||||
"pcapCapture",
|
||||
"signalRecording",
|
||||
"evmInterface",
|
||||
"binaryLayout",
|
||||
@@ -602,6 +604,13 @@ const workflowAvailabilityFor = ({
|
||||
remediation: "Run process capture on a supported Linux or macOS host.",
|
||||
};
|
||||
if (kind === "application") return { reason: "available", remediation: null };
|
||||
if (name === "inspect_pcap_capture")
|
||||
return hostRestrictedAvailability(
|
||||
policy,
|
||||
"pcapCapture",
|
||||
true,
|
||||
PCAP_CAPTURE_UNSUPPORTED_HOST_REASON,
|
||||
);
|
||||
if (kind === "pcap-provider" || kind === "flutter-provider")
|
||||
return { reason: "available", remediation: null };
|
||||
const electron = electronProviderAvailability(name, kind, policy);
|
||||
|
||||
@@ -2,6 +2,12 @@ import { z } from "zod";
|
||||
import { localPathStringSchema } from "../localPath.js";
|
||||
import { digestSchema } from "../digests.js";
|
||||
|
||||
/** Summary capture admission and discovery share this native-bound host profile. */
|
||||
export const pcapCaptureHostSupported = (platform: string): boolean =>
|
||||
platform === "linux" || platform === "win32";
|
||||
export const PCAP_CAPTURE_UNSUPPORTED_HOST_REASON =
|
||||
"Packet summaries require an enforceable native memory bound: Linux with util-linux prlimit, or Windows with owned Job Objects. This host's capture boundary remains unsupported.";
|
||||
|
||||
/**
|
||||
* Caller intent for packet-capture analysis through caller-supplied tshark
|
||||
* and capinfos. REA never installs Wireshark or its tools.
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
pcapCaptureHostSupported,
|
||||
PCAP_CAPTURE_UNSUPPORTED_HOST_REASON,
|
||||
} from "../domain/pcap/pcapAnalysis.js";
|
||||
import { access, realpath } from "node:fs/promises";
|
||||
import { constants } from "node:fs";
|
||||
import { isAbsolute } from "node:path";
|
||||
@@ -32,9 +36,8 @@ export const preparePcapNativeBound = async (
|
||||
],
|
||||
};
|
||||
}
|
||||
if (process.platform !== "linux") {
|
||||
const reason =
|
||||
"Packet summaries require an enforceable native memory bound: Linux with util-linux prlimit, or Windows with owned Job Objects. This host's capture boundary remains unsupported.";
|
||||
if (!pcapCaptureHostSupported(process.platform)) {
|
||||
const reason = PCAP_CAPTURE_UNSUPPORTED_HOST_REASON;
|
||||
throw new AnalysisCapabilityUnavailableError(
|
||||
"pcap",
|
||||
"inspect_pcap_capture",
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "../application/AnalysisProvider.js";
|
||||
import {
|
||||
pcapResultSchemas,
|
||||
pcapCaptureHostSupported,
|
||||
type PcapRequest,
|
||||
type PcapOperation,
|
||||
} from "../domain/pcap/pcapAnalysis.js";
|
||||
@@ -505,7 +506,7 @@ export class PcapProvider {
|
||||
): Promise<ProviderAvailability> {
|
||||
try {
|
||||
const { client } = await this.client("inspect_pcap_client", signal);
|
||||
if (process.platform !== "linux" && process.platform !== "win32")
|
||||
if (!pcapCaptureHostSupported(process.platform))
|
||||
return {
|
||||
status: "unavailable",
|
||||
code: "unsupported_host",
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { pcapCaptureHostSupported } from "../domain/pcap/pcapAnalysis.js";
|
||||
import { createGpuCodeObjectsService } from "../composition/gpu.js";
|
||||
import { registerGpuCodeObjectsTools } from "./registerGpuCodeObjectsTools.js";
|
||||
import type { PacketCaptureService } from "../application/captures/PacketCaptureService.js";
|
||||
@@ -276,6 +277,7 @@ const installSessionToolAvailability = (
|
||||
// Each provider owns its verified host; discovery and execution share it.
|
||||
const verifiedHost = {
|
||||
packetCapture: tsharkHostSupported(platform),
|
||||
pcapCapture: pcapCaptureHostSupported(platform),
|
||||
signalRecording: sigrokHostSupported(platform),
|
||||
evmInterface: evmHostSupported(platform, arch),
|
||||
pwntools: pwntoolsHostSupported(platform, arch),
|
||||
@@ -291,6 +293,10 @@ const installSessionToolAvailability = (
|
||||
const basePolicy = sessionAvailabilityPolicy(options.availabilityPolicy, {
|
||||
optionalProviderLoadFailures: options.optionalProviderLoadFailures,
|
||||
hostUnsupported: {
|
||||
pcapCapture: outsideVerifiedHost(
|
||||
options.pcapAnalysis,
|
||||
verifiedHost.pcapCapture,
|
||||
),
|
||||
packetCapture: outsideVerifiedHost(
|
||||
options.packetCapture,
|
||||
verifiedHost.packetCapture,
|
||||
|
||||
@@ -18,6 +18,7 @@ const linux = process.platform === "linux";
|
||||
|
||||
const packetCaptureAvailability = async (
|
||||
environment: Readonly<Record<string, string | undefined>>,
|
||||
name = "inspect_packet_capture",
|
||||
): Promise<Record<string, unknown> | undefined> => {
|
||||
const session = createTestBinarySession(() => {
|
||||
throw new Error("binary analysis must not start during status discovery");
|
||||
@@ -44,7 +45,7 @@ const packetCaptureAvailability = async (
|
||||
.object({ result: sessionProvider })
|
||||
.parse(response.structuredContent).result;
|
||||
return expandToolAvailability(parsed.tool_availability).find(
|
||||
({ name }) => name === "inspect_packet_capture",
|
||||
(tool) => tool.name === name,
|
||||
);
|
||||
} finally {
|
||||
await Promise.allSettled([client.close(), server.close(), session.close()]);
|
||||
@@ -106,3 +107,20 @@ it("reports packet tools unavailable when no absolute PATH entry holds TShark",
|
||||
reason: linux ? "provider_missing" : "unsupported_host",
|
||||
});
|
||||
});
|
||||
|
||||
it("advertises pcap capture host support separately from the always available client probe", async () => {
|
||||
expect(
|
||||
await packetCaptureAvailability({}, "inspect_pcap_client"),
|
||||
).toMatchObject({ available: true, reason: "available" });
|
||||
expect(
|
||||
await packetCaptureAvailability({}, "inspect_pcap_capture"),
|
||||
).toMatchObject(
|
||||
process.platform === "linux" || process.platform === "win32"
|
||||
? { available: true, reason: "available" }
|
||||
: {
|
||||
available: false,
|
||||
reason: "unsupported_host",
|
||||
remediation: expect.stringContaining("native memory bound"),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user