mirror of
https://github.com/SikongJueluo/pi-extensions.git
synced 2026-10-05 11:52:55 +08:00
feat(ai-judge): review sink with telemetry health and fail-closed truth table
- add review.ts sink adapter with session-start review-log toggle detection and a privacy key denylist enforced before delegation - add judge.ts enforce truth table: allow requires mode, host contract, telemetry health, cohort qualification, owner approval, activation, judgment result, allow verdict, review acknowledgement, and current generation — each independently forces defer with a distinct reason - route the authorizer callback through the sink and the v0.1 production gate state, which is structurally unreachable and therefore fail-closed
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
evaluateEnforceAuthority,
|
||||
v01ProductionGateState,
|
||||
type EnforceGateState,
|
||||
} from "../src/judge";
|
||||
|
||||
const ALL_OPEN: EnforceGateState = {
|
||||
hostContractPresent: true,
|
||||
telemetryHealth: "healthy",
|
||||
cohortQualified: true,
|
||||
ownerApprovalRecorded: true,
|
||||
activationRecorded: true,
|
||||
resultKind: "judgment",
|
||||
verdict: "allow",
|
||||
reviewAcknowledged: true,
|
||||
generationCurrent: true,
|
||||
mode: "enforce",
|
||||
};
|
||||
|
||||
describe("evaluateEnforceAuthority — every gate independently forces defer", () => {
|
||||
it("allows only when every gate holds", () => {
|
||||
expect(evaluateEnforceAuthority(ALL_OPEN)).toEqual({ kind: "allow" });
|
||||
});
|
||||
|
||||
const cases: ReadonlyArray<{
|
||||
name: string;
|
||||
patch: Partial<EnforceGateState>;
|
||||
expectedReason: string;
|
||||
}> = [
|
||||
{ name: "shadow mode", patch: { mode: "shadow" }, expectedReason: "mode_shadow" },
|
||||
{ name: "host contract absent", patch: { hostContractPresent: false }, expectedReason: "host_contract_absent" },
|
||||
{ name: "telemetry disabled", patch: { telemetryHealth: "disabled" }, expectedReason: "telemetry_disabled" },
|
||||
{ name: "telemetry write failed", patch: { telemetryHealth: "write_failed" }, expectedReason: "telemetry_write_failed" },
|
||||
{ name: "telemetry integrity anomaly", patch: { telemetryHealth: "integrity_anomaly" }, expectedReason: "telemetry_integrity_anomaly" },
|
||||
{ name: "cohort not qualified", patch: { cohortQualified: false }, expectedReason: "cohort_not_qualified" },
|
||||
{ name: "owner approval absent", patch: { ownerApprovalRecorded: false }, expectedReason: "owner_approval_absent" },
|
||||
{ name: "activation absent", patch: { activationRecorded: false }, expectedReason: "activation_absent" },
|
||||
{ name: "preflight result", patch: { resultKind: "preflight_defer" }, expectedReason: "result_preflight_defer" },
|
||||
{ name: "infrastructure result", patch: { resultKind: "infrastructure_failure" }, expectedReason: "result_infrastructure_failure" },
|
||||
{ name: "semantic deny verdict", patch: { verdict: "deny" }, expectedReason: "verdict_deny" },
|
||||
{ name: "semantic defer verdict", patch: { verdict: "defer" }, expectedReason: "verdict_defer" },
|
||||
{ name: "review unacknowledged", patch: { reviewAcknowledged: false }, expectedReason: "review_unacknowledged" },
|
||||
{ name: "stale generation", patch: { generationCurrent: false }, expectedReason: "generation_stale" },
|
||||
];
|
||||
|
||||
for (const { name, patch, expectedReason } of cases) {
|
||||
it(`${name} defers with a distinct reason`, () => {
|
||||
const state: EnforceGateState = { ...ALL_OPEN, ...patch };
|
||||
expect(evaluateEnforceAuthority(state)).toEqual({
|
||||
kind: "defer",
|
||||
blockedBy: expectedReason,
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe("evaluateEnforceAuthority — v0.1 production state", () => {
|
||||
it("never grants authority for any mode or telemetry state in v0.1", () => {
|
||||
const modes = ["shadow", "enforce"] as const;
|
||||
const healths = ["healthy", "disabled", "write_failed", "integrity_anomaly"] as const;
|
||||
for (const mode of modes) {
|
||||
for (const health of healths) {
|
||||
const outcome = evaluateEnforceAuthority(
|
||||
v01ProductionGateState(mode, health),
|
||||
);
|
||||
expect(outcome.kind).toBe("defer");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("blocks v0.1 enforce on the cohort gate", () => {
|
||||
const outcome = evaluateEnforceAuthority(
|
||||
v01ProductionGateState("enforce", "healthy"),
|
||||
);
|
||||
expect(outcome).toEqual({ kind: "defer", blockedBy: "cohort_not_qualified" });
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { createReviewSink, type ReviewSinkDeps } from "../src/review";
|
||||
import type { AuthorizerLog } from "@gotgenes/pi-permission-system";
|
||||
|
||||
function fakeLog(): AuthorizerLog & {
|
||||
reviews: Array<{ event: string; details: Record<string, unknown> }>;
|
||||
debugs: Array<{ event: string; details?: Record<string, unknown> }>;
|
||||
} {
|
||||
const reviews: Array<{ event: string; details: Record<string, unknown> }> = [];
|
||||
const debugs: Array<{ event: string; details?: Record<string, unknown> }> = [];
|
||||
return {
|
||||
reviews,
|
||||
debugs,
|
||||
review: (event, details = {}) => reviews.push({ event, details }),
|
||||
debug: (event, details) => debugs.push({ event, details }),
|
||||
};
|
||||
}
|
||||
|
||||
describe("createReviewSink — telemetry health", () => {
|
||||
it("marks the runtime disabled when the review log toggle is off", () => {
|
||||
const log = fakeLog();
|
||||
const deps: ReviewSinkDeps = { log, reviewLogEnabled: false };
|
||||
const sink = createReviewSink(deps);
|
||||
expect(sink.health()).toBe("disabled");
|
||||
});
|
||||
|
||||
it("reports healthy when the toggle is on", () => {
|
||||
const sink = createReviewSink({ log: fakeLog(), reviewLogEnabled: true });
|
||||
expect(sink.health()).toBe("healthy");
|
||||
});
|
||||
});
|
||||
|
||||
describe("createReviewSink — privacy denylist at the sink", () => {
|
||||
it("strips keys matching forbidden patterns before delegation", () => {
|
||||
const log = fakeLog();
|
||||
const sink = createReviewSink({ log, reviewLogEnabled: true });
|
||||
sink.review("ai_bash_judge.result", {
|
||||
requestId: "req-1",
|
||||
apiToken: "leak",
|
||||
sshKey: "leak",
|
||||
secrets: "leak",
|
||||
password: "leak",
|
||||
credentials: "leak",
|
||||
outputUsage: 10,
|
||||
});
|
||||
expect(log.reviews).toEqual([
|
||||
{
|
||||
event: "ai_bash_judge.result",
|
||||
details: { requestId: "req-1", outputUsage: 10 },
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("passes metadata-only events through unchanged", () => {
|
||||
const log = fakeLog();
|
||||
const sink = createReviewSink({ log, reviewLogEnabled: true });
|
||||
sink.review("ai_bash_judge.result", {
|
||||
schemaVersion: 1,
|
||||
requestId: "req-1",
|
||||
judgeRuntimeId: "abc",
|
||||
mode: "shadow",
|
||||
resultKind: "judgment",
|
||||
});
|
||||
expect(log.reviews[0]?.details).toEqual({
|
||||
schemaVersion: 1,
|
||||
requestId: "req-1",
|
||||
judgeRuntimeId: "abc",
|
||||
mode: "shadow",
|
||||
resultKind: "judgment",
|
||||
});
|
||||
});
|
||||
|
||||
it("delegates debug writes without stripping", () => {
|
||||
const log = fakeLog();
|
||||
const sink = createReviewSink({ log, reviewLogEnabled: true });
|
||||
sink.debug("ai_bash_judge.exception");
|
||||
expect(log.debugs).toEqual([{ event: "ai_bash_judge.exception" }]);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user