Skip to content

Commit 28ce628

Browse files
authored
Merge pull request #22 from dcplatforms/arch-alignment-zero-trust-12602369407265400519
Architectural Alignment: Zero Trust & Mandate Enforcement
2 parents 3151015 + 26491c4 commit 28ce628

4 files changed

Lines changed: 99 additions & 4 deletions

File tree

scripts/ocp-cli.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ program.command('x402:settle')
154154
return;
155155
}
156156
} else if (process.env.STRICT_MANDATE_MODE === 'true') {
157-
console.error(`Error: Mandate required for x402 settlement in STRICT_MANDATE_MODE.`);
157+
console.error(`Zero Trust Validation Failed: Mandate required for x402 settlement in STRICT_MANDATE_MODE.`);
158158
return;
159159
}
160160

src/services/a2aService.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
const MandateService = require("./mandate");
99
const logger = require("../utils/logger");
10+
const MandateService = require("./mandate");
1011

1112
class A2AService {
1213
constructor(walletService, db, config = {}) {
@@ -67,10 +68,22 @@ class A2AService {
6768
);
6869
}
6970

70-
// 2. Policy Checks (Sender)
71+
// 2. Zero Trust Mandate Validation
72+
if (mandate) {
73+
await this.mandateService.verifyMandate(mandate, {
74+
amount,
75+
recipient: toAgentId,
76+
});
77+
} else if (this.strictMandateMode) {
78+
throw new Error(
79+
"Zero Trust Validation Failed: Mandate required for A2A transfer in strict mode",
80+
);
81+
}
82+
83+
// 3. Policy Checks (Sender)
7184
await this._validateAgentPolicy(fromAgent, toAgentId, amount);
7285

73-
// 3. Execute Wallet Transfer
86+
// 4. Execute Wallet Transfer
7487
const transferResult = await this.walletService.transfer({
7588
fromWalletId: fromAgent.walletId,
7689
toWalletId: toAgent.walletId,
@@ -136,6 +149,15 @@ class A2AService {
136149
*/
137150
_handleError(method, error) {
138151
logger.error(`A2AService.${method} error:`, error);
152+
153+
// Normalize Zero Trust errors
154+
if (
155+
error.message &&
156+
error.message.includes("Zero Trust Validation Failed:")
157+
) {
158+
return error;
159+
}
160+
139161
return error instanceof Error ? error : new Error(error);
140162
}
141163
}

src/services/tokenization.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,14 @@ class TokenizationService {
382382
_handleError(method, error) {
383383
logger.error(`TokenizationService.${method} error:`, error);
384384

385+
// Normalize Zero Trust errors
386+
if (
387+
error.message &&
388+
error.message.includes("Zero Trust Validation Failed:")
389+
) {
390+
return error;
391+
}
392+
385393
if (error.response) {
386394
const { status, data } = error.response;
387395
return new Error(
@@ -393,7 +401,7 @@ class TokenizationService {
393401
return new Error("Tokenization service unavailable");
394402
}
395403

396-
return error;
404+
return error instanceof Error ? error : new Error(error);
397405
}
398406
}
399407

tests/unit/mandate_context.spec.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
const MandateService = require("../../src/services/mandate");
2+
const jwt = require("jsonwebtoken");
3+
4+
describe("MandateService - Context Validation", () => {
5+
let mandateService;
6+
const signingKey = "test-secret";
7+
8+
beforeEach(() => {
9+
mandateService = new MandateService({ signingKey });
10+
});
11+
12+
it("should validate amount against intent mandate budget", async () => {
13+
const mandate = await mandateService.issueIntentMandate({
14+
userDid: "did:key:user",
15+
agentDid: "did:key:agent",
16+
maxBudget: 100,
17+
});
18+
19+
// Valid amount
20+
await expect(
21+
mandateService.verifyMandate(mandate, { amount: 50 }),
22+
).resolves.toBeDefined();
23+
24+
// Invalid amount
25+
await expect(
26+
mandateService.verifyMandate(mandate, { amount: 150 }),
27+
).rejects.toThrow(
28+
"Zero Trust Validation Failed: Amount 150 exceeds mandate budget of 100",
29+
);
30+
});
31+
32+
it("should validate recipient against allowed_merchants whitelist", async () => {
33+
const mandate = await mandateService.issueIntentMandate({
34+
userDid: "did:key:user",
35+
agentDid: "did:key:agent",
36+
maxBudget: 100,
37+
allowedMerchants: ["did:key:merchant-1"],
38+
});
39+
40+
// Authorized merchant
41+
await expect(
42+
mandateService.verifyMandate(mandate, { recipient: "did:key:merchant-1" }),
43+
).resolves.toBeDefined();
44+
45+
// Unauthorized merchant
46+
await expect(
47+
mandateService.verifyMandate(mandate, { recipient: "did:key:merchant-2" }),
48+
).rejects.toThrow(
49+
"Zero Trust Validation Failed: Merchant did:key:merchant-2 not authorized by mandate",
50+
);
51+
});
52+
53+
it("should handle expired tokens with correct prefix", async () => {
54+
const mandate = jwt.sign(
55+
{
56+
exp: Math.floor(Date.now() / 1000) - 60,
57+
},
58+
signingKey,
59+
);
60+
61+
await expect(mandateService.verifyMandate(mandate)).rejects.toThrow(
62+
"Zero Trust Validation Failed: Mandate has expired",
63+
);
64+
});
65+
});

0 commit comments

Comments
 (0)