-
Notifications
You must be signed in to change notification settings - Fork 93
M5: Cutover decision authorization + remove isTrusted #10990
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6fa8e2f
e74a7ec
aa32572
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |||||||||||||||||||||||
| import { | ||||||||||||||||||||||||
| applyCanonicalGuardianDecision, | ||||||||||||||||||||||||
| type CanonicalDecisionResult, | ||||||||||||||||||||||||
| isAuthorizedGuardianPrincipal, | ||||||||||||||||||||||||
| } from '../approvals/guardian-decision-primitive.js'; | ||||||||||||||||||||||||
| import type { ActorContext, ChannelDeliveryContext } from '../approvals/guardian-request-resolvers.js'; | ||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||
|
|
@@ -195,19 +196,26 @@ function findPendingCanonicalRequests( | |||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // For desktop/trusted actors without an externalUserId, query by | ||||||||||||||||||||||||
| // conversationId so the NL path can discover pending requests. | ||||||||||||||||||||||||
| // Actors without an externalUserId: scope by conversationId so the NL | ||||||||||||||||||||||||
| // path can discover pending requests bound to this conversation. | ||||||||||||||||||||||||
| // Include guardianPrincipalId filter when available so the guardian only | ||||||||||||||||||||||||
| // sees requests they are authorized to act on. | ||||||||||||||||||||||||
| if (conversationId) { | ||||||||||||||||||||||||
| return listCanonicalGuardianRequests({ | ||||||||||||||||||||||||
| status: 'pending', | ||||||||||||||||||||||||
| conversationId, | ||||||||||||||||||||||||
| ...(actor.guardianPrincipalId ? { guardianPrincipalId: actor.guardianPrincipalId } : {}), | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| // Trusted actors without a conversationId: return all pending requests | ||||||||||||||||||||||||
| // so desktop sessions can always discover pending guardian work. | ||||||||||||||||||||||||
| if (actor.isTrusted) { | ||||||||||||||||||||||||
| return listCanonicalGuardianRequests({ status: 'pending' }); | ||||||||||||||||||||||||
| // Actors with a guardianPrincipalId but no externalUserId or | ||||||||||||||||||||||||
| // conversationId: query by principal so desktop sessions can still | ||||||||||||||||||||||||
| // discover pending guardian work via their bound principal. | ||||||||||||||||||||||||
| if (actor.guardianPrincipalId) { | ||||||||||||||||||||||||
| return listCanonicalGuardianRequests({ | ||||||||||||||||||||||||
| status: 'pending', | ||||||||||||||||||||||||
| guardianPrincipalId: actor.guardianPrincipalId, | ||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||
| } | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| return []; | ||||||||||||||||||||||||
|
|
@@ -299,22 +307,24 @@ export async function routeGuardianReply( | |||||||||||||||||||||||
| // silently defaulting to approve_once. | ||||||||||||||||||||||||
| if (!codeResult.remainingText || codeResult.remainingText.trim().length === 0) { | ||||||||||||||||||||||||
| // Identity check: only expose request details to the assigned guardian | ||||||||||||||||||||||||
| // or trusted (desktop) actors. Mirrors the identity check in | ||||||||||||||||||||||||
| // applyCanonicalGuardianDecision to prevent leaking request details | ||||||||||||||||||||||||
| // (toolName, questionText) to unauthorized senders. | ||||||||||||||||||||||||
| // principal. Uses the shared cross-channel principal helper (same logic | ||||||||||||||||||||||||
| // as applyCanonicalGuardianDecision) to prevent leaking request details | ||||||||||||||||||||||||
| // (toolName, questionText) to unauthorized senders while allowing | ||||||||||||||||||||||||
| // cross-channel lookups (e.g. desktop guardian entering a code for a | ||||||||||||||||||||||||
| // Telegram-originated request). | ||||||||||||||||||||||||
| if ( | ||||||||||||||||||||||||
| request.guardianExternalUserId && | ||||||||||||||||||||||||
| !actor.isTrusted && | ||||||||||||||||||||||||
| actor.externalUserId !== request.guardianExternalUserId | ||||||||||||||||||||||||
| request.guardianPrincipalId && | ||||||||||||||||||||||||
| actor.guardianPrincipalId && | ||||||||||||||||||||||||
| !isAuthorizedGuardianPrincipal(actor.guardianPrincipalId, request.guardianPrincipalId) | ||||||||||||||||||||||||
|
Comment on lines
315
to
+318
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Code-only clarification identity check silently skips when actor principal is missing The code-only clarification identity gate in Comparison with old codeOld code: The old code blocked when New code: When By contrast, the decision gate in Impact: A channel actor on a legacy binding without
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||
|
noanflaherty marked this conversation as resolved.
Comment on lines
+313
to
315
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The code-only clarification guard now rejects whenever Useful? React with 👍 / 👎. |
||||||||||||||||||||||||
| log.warn( | ||||||||||||||||||||||||
| { | ||||||||||||||||||||||||
| event: 'router_code_only_identity_mismatch', | ||||||||||||||||||||||||
| event: 'router_code_only_principal_mismatch', | ||||||||||||||||||||||||
| requestId: request.id, | ||||||||||||||||||||||||
| expectedGuardian: request.guardianExternalUserId, | ||||||||||||||||||||||||
| actualActor: actor.externalUserId, | ||||||||||||||||||||||||
| expectedPrincipal: request.guardianPrincipalId, | ||||||||||||||||||||||||
| actualPrincipal: actor.guardianPrincipalId, | ||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||
| 'Code-only clarification blocked: actor identity does not match expected guardian', | ||||||||||||||||||||||||
| 'Code-only clarification blocked: actor principal does not match request or canonical principal', | ||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||
| decisionApplied: false, | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.