diff --git a/packages/account-core/src/index.test.ts b/packages/account-core/src/index.test.ts index c00a8e3..f62e78f 100644 --- a/packages/account-core/src/index.test.ts +++ b/packages/account-core/src/index.test.ts @@ -41,6 +41,23 @@ describe("account-core", () => { expect(result.decision).toBe("approval_required"); }); + it("treats non-finite risk scores as critical", () => { + const result = evaluateAccountPolicy({ + action: "social:profile:read", + riskScore: Number.NaN, + grant: { + id: "grant_1", + accountId: "account_1", + principal: { type: "agent", id: "marketing-agent" }, + permissions: ["social:profile:read"], + policy: [], + createdAt: new Date(0).toISOString() + } + }); + + expect(result).toMatchObject({ decision: "deny", riskScore: 1 }); + }); + it("redacts secret-like audit previews", () => { const event = createAccountAuditEvent({ provider: "gmail", diff --git a/packages/account-core/src/policy.ts b/packages/account-core/src/policy.ts index b80ed25..82a2ec3 100644 --- a/packages/account-core/src/policy.ts +++ b/packages/account-core/src/policy.ts @@ -51,7 +51,8 @@ export function scoreAccountActionRisk(input: { } export function evaluateAccountPolicy(input: LogicSrcPolicyEvaluationInput): LogicSrcPolicyEvaluationResult { - const riskScore = Math.min(1, Math.max(0, input.riskScore ?? scoreAccountActionRisk({ action: input.action }))); + const rawRiskScore = input.riskScore ?? scoreAccountActionRisk({ action: input.action }); + const riskScore = Number.isFinite(rawRiskScore) ? Math.min(1, Math.max(0, rawRiskScore)) : 1; const grantActive = input.grant && !input.grant.revokedAt && (!input.grant.expiresAt || Date.parse(input.grant.expiresAt) > Date.now()); const hasPermission = Boolean(grantActive && input.grant?.permissions.includes(input.action));