mirror of
https://github.com/morluto/rea.git
synced 2026-11-12 01:41:21 +00:00
fix(capture): retain safe caller path selections (#9626)
* fix(cli)!: retain repeated WASM input paths BREAKING CHANGE: caller_input_paths values may now be ordered arrays of strings as well as strings. Clients must accept both forms. * fix(capture): retain safe caller path selections * fix(evidence): retain auxiliary selections in direct summaries * test(wasm): separate SDK schema and acquired-input coverage
This commit is contained in:
1 parent
dda2d40295
commit
bf271ba3fb
10 files changed
+326
-130
No files matched your search
@@ -10,7 +10,11 @@ import {
|
||||
AnalysisOutputError,
|
||||
} from "../domain/analysisErrorCore.js";
|
||||
import { createAnalysisProfile } from "../domain/analysisProfile.js";
|
||||
import { createEvidence, type Evidence } from "../domain/evidence.js";
|
||||
import {
|
||||
createEvidence,
|
||||
withEvidenceCallerInputPath,
|
||||
type Evidence,
|
||||
} from "../domain/evidence.js";
|
||||
import { analysisInputErrorFromIssues } from "../domain/inputIssueProjection.js";
|
||||
import { jsonObjectSchema } from "../domain/jsonValue.js";
|
||||
import { err, ok, type Result } from "../domain/result.js";
|
||||
@@ -39,6 +43,7 @@ export class WebNetworkCaptureService {
|
||||
async inspect(
|
||||
rawInput: unknown,
|
||||
options?: ExecutionOptions,
|
||||
callerPaths?: { readonly capture: string; readonly descriptor?: string },
|
||||
): Promise<Result<Evidence, AnalysisError>> {
|
||||
if (options?.signal?.aborted)
|
||||
return err(
|
||||
@@ -87,7 +92,11 @@ export class WebNetworkCaptureService {
|
||||
);
|
||||
let partialFailure: AnalysisError | undefined;
|
||||
if (partial.success) {
|
||||
const projected = this.#projectCapture(input, partial.data);
|
||||
const projected = this.#projectCapture(
|
||||
input,
|
||||
partial.data,
|
||||
callerPaths,
|
||||
);
|
||||
if (projected.ok) loaded.error.partialObservation = projected.value;
|
||||
else partialFailure = projected.error;
|
||||
} else if (isCapturePartialCandidate(loaded.error.partialObservation)) {
|
||||
@@ -128,7 +137,7 @@ export class WebNetworkCaptureService {
|
||||
"Capture adapter returned malformed historical evidence.",
|
||||
),
|
||||
);
|
||||
const projected = this.#projectCapture(input, report.data);
|
||||
const projected = this.#projectCapture(input, report.data, callerPaths);
|
||||
if (!projected.ok) return failure(projected.error);
|
||||
return completeProviderEvidence(projected.value, options?.signal);
|
||||
}
|
||||
@@ -136,6 +145,7 @@ export class WebNetworkCaptureService {
|
||||
#projectCapture(
|
||||
input: InspectWebNetworkCaptureInput,
|
||||
value: WebNetworkCapture,
|
||||
callerPaths?: { readonly capture: string; readonly descriptor?: string },
|
||||
): Result<Evidence, AnalysisError> {
|
||||
const artifactSha256 = value.artifact.sha256;
|
||||
if (artifactSha256 === null)
|
||||
@@ -160,6 +170,8 @@ export class WebNetworkCaptureService {
|
||||
const safeValue = excludeCaptureCoordinates(value, input.sensitive_values);
|
||||
const redactText = (text: string): string =>
|
||||
redactExplicitText(text, input.sensitive_values);
|
||||
const isSensitive = (text: string): boolean =>
|
||||
input.sensitive_values.some((literal) => text.includes(literal));
|
||||
const selected =
|
||||
input.record_ordinals ?? value.records.map(({ ordinal }) => ordinal);
|
||||
const records = [];
|
||||
@@ -189,16 +201,8 @@ export class WebNetworkCaptureService {
|
||||
limitations: record.limitations.map(redactText),
|
||||
});
|
||||
}
|
||||
const safePath = input.sensitive_values.some((literal) =>
|
||||
input.capture_path.includes(literal),
|
||||
)
|
||||
? ""
|
||||
: input.capture_path;
|
||||
const safeSha256 = input.sensitive_values.some((literal) =>
|
||||
artifactSha256.includes(literal),
|
||||
)
|
||||
? null
|
||||
: artifactSha256;
|
||||
const safePath = isSensitive(input.capture_path) ? "" : input.capture_path;
|
||||
const safeSha256 = isSensitive(artifactSha256) ? null : artifactSha256;
|
||||
const subjectUnavailableReason = redactText(
|
||||
"The explicitly sensitive artifact digest is excluded; its cryptographic identity is unknown in this Evidence.",
|
||||
);
|
||||
@@ -212,11 +216,7 @@ export class WebNetworkCaptureService {
|
||||
].map(redactText);
|
||||
const parameters = jsonObjectSchema.parse({
|
||||
capture_path: safePath,
|
||||
...(input.sensitive_values.some((literal) =>
|
||||
input.format.includes(literal),
|
||||
)
|
||||
? {}
|
||||
: { format: input.format }),
|
||||
...(isSensitive(input.format) ? {} : { format: input.format }),
|
||||
record_ordinals: selected,
|
||||
...(input.protobuf === undefined
|
||||
? {}
|
||||
@@ -247,48 +247,60 @@ export class WebNetworkCaptureService {
|
||||
? {}
|
||||
: { capture_timeout_ms: input.capture_timeout_ms }),
|
||||
});
|
||||
return ok(
|
||||
createEvidence(
|
||||
safeSha256 === null
|
||||
? undefined
|
||||
: {
|
||||
path: safePath,
|
||||
sha256: safeSha256,
|
||||
format: "file",
|
||||
},
|
||||
value.decoder,
|
||||
{
|
||||
operation: OPERATION,
|
||||
parameters,
|
||||
result: {
|
||||
...safeValue,
|
||||
artifact: {
|
||||
...value.artifact,
|
||||
path: safePath,
|
||||
sha256: safeSha256,
|
||||
},
|
||||
records,
|
||||
limitations:
|
||||
safeSha256 === null
|
||||
? [...limitations, subjectUnavailableReason]
|
||||
: limitations,
|
||||
const evidence = createEvidence(
|
||||
safeSha256 === null
|
||||
? undefined
|
||||
: {
|
||||
path: safePath,
|
||||
sha256: safeSha256,
|
||||
format: "file",
|
||||
},
|
||||
...(safeValue.format !== "qlog"
|
||||
? {}
|
||||
: {
|
||||
analysisProfile: createAnalysisProfile(value.decoder, {
|
||||
qlog_profile: safeValue.qlog.profile,
|
||||
clock: safeValue.qlog.clock,
|
||||
scope: safeValue.qlog.scope,
|
||||
}),
|
||||
}),
|
||||
confidence: "observed",
|
||||
authority: "historical-reference",
|
||||
limitations,
|
||||
...(safeSha256 === null ? { subjectUnavailableReason } : {}),
|
||||
locations:
|
||||
safePath === "" ? [] : [{ kind: "artifact-path", path: safePath }],
|
||||
value.decoder,
|
||||
{
|
||||
operation: OPERATION,
|
||||
parameters,
|
||||
result: {
|
||||
...safeValue,
|
||||
artifact: {
|
||||
...value.artifact,
|
||||
path: safePath,
|
||||
sha256: safeSha256,
|
||||
},
|
||||
records,
|
||||
limitations:
|
||||
safeSha256 === null
|
||||
? [...limitations, subjectUnavailableReason]
|
||||
: limitations,
|
||||
},
|
||||
...(safeValue.format !== "qlog"
|
||||
? {}
|
||||
: {
|
||||
analysisProfile: createAnalysisProfile(value.decoder, {
|
||||
qlog_profile: safeValue.qlog.profile,
|
||||
clock: safeValue.qlog.clock,
|
||||
scope: safeValue.qlog.scope,
|
||||
}),
|
||||
}),
|
||||
confidence: "observed",
|
||||
authority: "historical-reference",
|
||||
limitations,
|
||||
...(safeSha256 === null ? { subjectUnavailableReason } : {}),
|
||||
locations:
|
||||
safePath === "" ? [] : [{ kind: "artifact-path", path: safePath }],
|
||||
},
|
||||
);
|
||||
if (callerPaths === undefined) return ok(evidence);
|
||||
const safeCallerPath = (path: string | undefined) =>
|
||||
path === undefined || isSensitive(path) ? undefined : path;
|
||||
const callerPath = safeCallerPath(callerPaths.capture);
|
||||
const descriptor = safeCallerPath(callerPaths.descriptor);
|
||||
return ok(
|
||||
withEvidenceCallerInputPath(
|
||||
evidence,
|
||||
callerPath,
|
||||
descriptor === undefined
|
||||
? undefined
|
||||
: { descriptor_set_path: descriptor },
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user