diff --git a/src/services/agent.js b/src/services/agent.js index ad47bc5..25e918f 100644 --- a/src/services/agent.js +++ b/src/services/agent.js @@ -181,17 +181,11 @@ class AgentService { // Basic policy checks (more complex logic would be here) if (amount > fromAgent.policy.spendingLimit) { - throw new Error( - `Transfer amount exceeds spending limit for agent ${fromAgentId}`, - ); + throw new Error(`Zero Trust Validation Failed: Transfer amount exceeds spending limit for agent ${fromAgentId}`); } - if ( - !fromAgent.policy.authorizedCounterparties.includes(toAgentId) && - fromAgent.policy.authorizedCounterparties.length > 0 - ) { - throw new Error( - `Agent ${toAgentId} is not an authorized counterparty for ${fromAgentId}`, - ); + if (!fromAgent.policy.authorizedCounterparties.includes(toAgentId) && + fromAgent.policy.authorizedCounterparties.length > 0) { + throw new Error(`Zero Trust Validation Failed: Agent ${toAgentId} is not an authorized counterparty for ${fromAgentId}`); } // Simulate transfer success diff --git a/src/services/mandate.js b/src/services/mandate.js index dd22396..20feda1 100644 --- a/src/services/mandate.js +++ b/src/services/mandate.js @@ -67,27 +67,18 @@ class MandateService { }) { const decodedIntent = await this.verifyMandate(intentMandate); - if (decodedIntent.type !== "intent_mandate") { - throw new Error( - "Zero Trust Validation Failed: Invalid intent mandate type", - ); + if (decodedIntent.type !== 'intent_mandate') { + throw new Error('Zero Trust Validation Failed: Invalid intent mandate type'); } // Verify budget if (totalPrice > decodedIntent.max_budget.value) { - throw new Error( - "Zero Trust Validation Failed: Cart total exceeds intent mandate budget", - ); + throw new Error('Zero Trust Validation Failed: Cart total exceeds intent mandate budget'); } // Verify merchant if whitelist exists - if ( - decodedIntent.allowed_merchants.length > 0 && - !decodedIntent.allowed_merchants.includes(merchantDid) - ) { - throw new Error( - `Zero Trust Validation Failed: Merchant ${merchantDid} is not authorized by this mandate`, - ); + if (decodedIntent.allowed_merchants.length > 0 && !decodedIntent.allowed_merchants.includes(merchantDid)) { + throw new Error(`Zero Trust Validation Failed: Merchant ${merchantDid} is not authorized by this mandate`); } // Create cryptographic hash of cart @@ -120,9 +111,7 @@ class MandateService { try { return jwt.verify(token, this.signingKey, { algorithms: ["HS256"] }); } catch (error) { - throw new Error( - `Zero Trust Validation Failed: Mandate verification failed: ${error.message}`, - ); + throw new Error(`Zero Trust Validation Failed: Mandate verification failed: ${error.message}`); } } diff --git a/src/services/ucp.js b/src/services/ucp.js index 918d0b7..2b12df2 100644 --- a/src/services/ucp.js +++ b/src/services/ucp.js @@ -42,27 +42,26 @@ class UCPService { /** * Process a UCP Payload * @param {Object} payload - The raw UCP JSON payload + * @param {string} mandate - Optional signed Mandate (AP2) for Zero Trust validation */ - async processPayload(payload) { + async processPayload(payload, mandate) { try { // 1. Validate the UCP intent against schema const { error, value } = this.ucpIntentSchema.validate(payload, { stripUnknown: true, }); if (error) { - throw new Error( - `Zero Trust Validation Failed: UCP Intent validation failed: ${error.details.map((x) => x.message).join(", ")}`, - ); + throw new Error(`Zero Trust Validation Failed: UCP Intent validation failed: ${error.details.map(x => x.message).join(', ')}`); } const validatedPayload = value; const { intent } = validatedPayload; switch (intent) { - case "transfer": - case "payment": - return this._handleTransfer(validatedPayload); - case "purchase": + case 'transfer': + case 'payment': + return this._handleTransfer(validatedPayload, mandate); + case 'purchase': // Future implementation: integration with Inventory/Order services return { status: "success", @@ -85,21 +84,22 @@ class UCPService { * Handle transfer/payment intents via A2AService * @private */ - async _handleTransfer(payload) { + async _handleTransfer(payload, mandate) { const { sender, recipient, amount } = payload; if (!recipient?.agent_id) { - throw new Error("Missing recipient agent_id for transfer"); + throw new Error('Zero Trust Validation Failed: Missing recipient agent_id for transfer'); } if (!amount?.value) { - throw new Error("Missing amount value"); + throw new Error('Zero Trust Validation Failed: Missing amount value'); } return this.a2aService.executeTransfer({ fromAgentId: sender.agent_id, toAgentId: recipient.agent_id, amount: amount.value, - ucpPayload: payload, + mandate, + ucpPayload: payload }); } diff --git a/tests/unit/mandate_extra.spec.js b/tests/unit/mandate_extra.spec.js new file mode 100644 index 0000000..322c82b --- /dev/null +++ b/tests/unit/mandate_extra.spec.js @@ -0,0 +1,61 @@ +const MandateService = require('../../src/services/mandate'); +const jwt = require('jsonwebtoken'); + +describe('MandateService', () => { + let mandateService; + const signingKey = 'test-secret'; + + beforeEach(() => { + mandateService = new MandateService({ signingKey }); + }); + + describe('issueCartMandate', () => { + it('should throw error for invalid intent mandate type', async () => { + const invalidMandate = jwt.sign({ type: 'not_intent' }, signingKey); + await expect(mandateService.issueCartMandate({ + intentMandate: invalidMandate, + cartItems: [], + totalPrice: 100, + merchantDid: 'did:key:m' + })).rejects.toThrow('Zero Trust Validation Failed: Invalid intent mandate type'); + }); + + it('should throw error if cart total exceeds budget', async () => { + const intentMandate = await mandateService.issueIntentMandate({ + userDid: 'did:key:u', + agentDid: 'did:key:a', + maxBudget: 50 + }); + + await expect(mandateService.issueCartMandate({ + intentMandate, + cartItems: [], + totalPrice: 100, + merchantDid: 'did:key:m' + })).rejects.toThrow('Zero Trust Validation Failed: Cart total exceeds intent mandate budget'); + }); + + it('should throw error if merchant is not authorized', async () => { + const intentMandate = await mandateService.issueIntentMandate({ + userDid: 'did:key:u', + agentDid: 'did:key:a', + maxBudget: 500, + allowedMerchants: ['did:key:m1'] + }); + + await expect(mandateService.issueCartMandate({ + intentMandate, + cartItems: [], + totalPrice: 100, + merchantDid: 'did:key:m2' + })).rejects.toThrow('Zero Trust Validation Failed: Merchant did:key:m2 is not authorized by this mandate'); + }); + }); + + describe('verifyMandate', () => { + it('should throw error for invalid token', async () => { + await expect(mandateService.verifyMandate('invalid-token')) + .rejects.toThrow('Zero Trust Validation Failed: Mandate verification failed: jwt malformed'); + }); + }); +});