-
Notifications
You must be signed in to change notification settings - Fork 0
Align OCP SDK with OCI Architect Mandate and Zero Trust Pillars #21
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
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 |
|---|---|---|
|
|
@@ -331,53 +331,20 @@ class TokenizationService { | |
| async signWithToken(tokenId, dataToSign, mandate, context = {}) { | ||
| // Zero Trust Validation: Verify mandate BEFORE entering try/catch simulation block | ||
| if (mandate) { | ||
| let decodedMandate; | ||
| try { | ||
| decodedMandate = await this.mandateService.verifyMandate(mandate); | ||
| // Normalize context for MandateService (merchant -> recipient) | ||
| const validationContext = { | ||
| ...context, | ||
| recipient: context.recipient || context.merchant, | ||
| }; | ||
| await this.mandateService.verifyMandate(mandate, validationContext); | ||
| } catch (error) { | ||
| if (error.message?.includes("jwt expired")) { | ||
| throw new Error("Zero Trust Validation Failed: Mandate has expired"); | ||
| } | ||
| if (error.message?.includes("Zero Trust Validation Failed:")) { | ||
| throw error; | ||
| } | ||
| throw new Error(`Zero Trust Validation Failed: ${error.message || error}`); | ||
| } | ||
|
|
||
| // Validate budget if context amount is provided | ||
| if (context.amount) { | ||
|
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. Expired mandate message changedMedium Severity The Reviewed by Cursor Bugbot for commit f223810. Configure here. |
||
| // Check Intent Mandate budget | ||
| if ( | ||
| decodedMandate.max_budget && | ||
| context.amount > decodedMandate.max_budget.value | ||
| ) { | ||
| throw new Error( | ||
| `Zero Trust Validation Failed: Amount ${context.amount} exceeds mandate budget of ${decodedMandate.max_budget.value}`, | ||
| ); | ||
| } | ||
| // Check Cart Mandate total price | ||
| if ( | ||
| decodedMandate.total_price && | ||
| context.amount !== decodedMandate.total_price | ||
| ) { | ||
| throw new Error( | ||
| `Zero Trust Validation Failed: Amount ${context.amount} does not match cart mandate total of ${decodedMandate.total_price}`, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // Validate merchant if context merchant is provided | ||
| if (context.merchant && decodedMandate.allowed_merchants?.length > 0) { | ||
| if (!decodedMandate.allowed_merchants.includes(context.merchant)) { | ||
| throw new Error( | ||
| `Zero Trust Validation Failed: Merchant ${context.merchant} not authorized by mandate`, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // Validate expiration | ||
| if (decodedMandate.exp < Math.floor(Date.now() / 1000)) { | ||
| throw new Error("Zero Trust Validation Failed: Mandate has expired"); | ||
| throw new Error( | ||
| `Zero Trust Validation Failed: ${error.message || error}`, | ||
| ); | ||
| } | ||
| } else if (this.strictMandateMode) { | ||
| throw new Error( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| const MandateService = require('../../src/services/mandate'); | ||
| const A2AService = require('../../src/services/a2aService'); | ||
|
|
||
| describe('A2AService Zero Trust Validation', () => { | ||
| let a2aService; | ||
| let mandateService; | ||
| let mockWalletService; | ||
| let mockDb; | ||
|
|
||
| beforeEach(() => { | ||
| mockWalletService = { | ||
| transfer: jest.fn().mockResolvedValue({ transferId: 'tx_123' }) | ||
| }; | ||
| mockDb = { | ||
| findAgentById: jest.fn().mockImplementation((id) => ({ | ||
| id, | ||
| name: `Agent ${id}`, | ||
| status: 'active', | ||
| walletId: `wallet_${id}`, | ||
| config: { limits: { perTransaction: 1000 } } | ||
| })) | ||
| }; | ||
| mandateService = new MandateService({ signingKey: 'test-secret' }); | ||
| a2aService = new A2AService(mockWalletService, mockDb, { | ||
| mandateConfig: { signingKey: 'test-secret' }, | ||
| strictMandateMode: true | ||
| }); | ||
| }); | ||
|
|
||
| it('should fail if mandate is missing in strict mode', async () => { | ||
| await expect(a2aService.executeTransfer({ | ||
| fromAgentId: 'agent1', | ||
| toAgentId: 'agent2', | ||
| amount: 100 | ||
| })).rejects.toThrow('Zero Trust Validation Failed: Mandate required for A2A transfer in strict mode'); | ||
| }); | ||
|
|
||
| it('should fail if mandate budget is exceeded', async () => { | ||
| const mandate = await mandateService.issueIntentMandate({ | ||
| userDid: 'did:user:1', | ||
| agentDid: 'did:agent:1', | ||
| maxBudget: 50 | ||
| }); | ||
|
|
||
| await expect(a2aService.executeTransfer({ | ||
| fromAgentId: 'agent1', | ||
| toAgentId: 'agent2', | ||
| amount: 100, | ||
| mandate | ||
| })).rejects.toThrow('Zero Trust Validation Failed: Amount 100 exceeds mandate budget of 50'); | ||
| }); | ||
|
|
||
| it('should fail if recipient is not authorized by mandate', async () => { | ||
| const mandate = await mandateService.issueIntentMandate({ | ||
| userDid: 'did:user:1', | ||
| agentDid: 'did:agent:1', | ||
| maxBudget: 200, | ||
| allowedMerchants: ['agent2'] | ||
| }); | ||
|
|
||
| await expect(a2aService.executeTransfer({ | ||
| fromAgentId: 'agent1', | ||
| toAgentId: 'agent3', | ||
| amount: 100, | ||
| mandate | ||
| })).rejects.toThrow('Zero Trust Validation Failed: Merchant agent3 not authorized by mandate'); | ||
|
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. A2A tests lack implementationHigh Severity The Reviewed by Cursor Bugbot for commit f223810. Configure here. |
||
| }); | ||
|
|
||
| it('should succeed with valid mandate', async () => { | ||
| const mandate = await mandateService.issueIntentMandate({ | ||
| userDid: 'did:user:1', | ||
| agentDid: 'did:agent:1', | ||
| maxBudget: 200, | ||
| allowedMerchants: ['agent2'] | ||
| }); | ||
|
|
||
| const result = await a2aService.executeTransfer({ | ||
| fromAgentId: 'agent1', | ||
| toAgentId: 'agent2', | ||
| amount: 100, | ||
| mandate | ||
| }); | ||
|
|
||
| expect(result.success).toBe(true); | ||
| expect(mockWalletService.transfer).toHaveBeenCalled(); | ||
| }); | ||
| }); | ||


There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Merchant error says Recipient
Medium Severity
The
mandateService.verifyMandatefunction now reports unauthorized counterparties as "Recipient ... not authorized by mandate". This change in error message phrasing from "Merchant" breaks existing tests and expectations.Additional Locations (1)
tests/unit/a2a_zerotrust.spec.js#L52-L66Reviewed by Cursor Bugbot for commit f223810. Configure here.