@vorionsys/basis 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +22 -0
- package/AMOY-MIGRATION.md +188 -0
- package/DEPLOY-AMOY.md +368 -0
- package/DEPLOY-NOW.md +216 -0
- package/DEPLOYMENT.md +239 -0
- package/GET-WALLET.md +286 -0
- package/QUICK-WALLET-SETUP.md +268 -0
- package/README.md +195 -0
- package/artifacts/@openzeppelin/contracts/access/AccessControl.sol/AccessControl.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/access/AccessControl.sol/AccessControl.json +236 -0
- package/artifacts/@openzeppelin/contracts/access/IAccessControl.sol/IAccessControl.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/access/IAccessControl.sol/IAccessControl.json +204 -0
- package/artifacts/@openzeppelin/contracts/interfaces/IERC4906.sol/IERC4906.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/interfaces/IERC4906.sol/IERC4906.json +328 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.json +113 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.json +97 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.json +114 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.json +444 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721.sol/IERC721.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721.sol/IERC721.json +296 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.json +45 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol/ERC721Enumerable.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol/ERC721Enumerable.json +521 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol/ERC721URIStorage.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol/ERC721URIStorage.json +476 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol/IERC721Enumerable.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol/IERC721Enumerable.json +352 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol/IERC721Metadata.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol/IERC721Metadata.json +341 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol/ERC721Utils.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol/ERC721Utils.json +10 -0
- package/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.json +10 -0
- package/artifacts/@openzeppelin/contracts/utils/Panic.sol/Panic.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/Panic.sol/Panic.json +10 -0
- package/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.json +37 -0
- package/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.json +30 -0
- package/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.json +30 -0
- package/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.json +10 -0
- package/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.json +65 -0
- package/artifacts/@openzeppelin/contracts/utils/math/SignedMath.sol/SignedMath.dbg.json +4 -0
- package/artifacts/@openzeppelin/contracts/utils/math/SignedMath.sol/SignedMath.json +10 -0
- package/artifacts/build-info/357d1bba4062d461f497f221490811a3.json +1 -0
- package/artifacts/contracts/AgentCard.sol/AgentCard.dbg.json +4 -0
- package/artifacts/contracts/AgentCard.sol/AgentCard.json +1430 -0
- package/build_errors.txt +0 -0
- package/build_output.txt +0 -0
- package/cache/solidity-files-cache.json +885 -0
- package/contracts/AgentCard.sol +478 -0
- package/contracts/deploy/01-deploy-agentcard.ts +66 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/kya/accountability.d.ts.map +1 -0
- package/dist/kya/accountability.js +100 -0
- package/dist/kya/authorization.d.ts.map +1 -0
- package/dist/kya/authorization.js +258 -0
- package/dist/kya/behavior.d.ts.map +1 -0
- package/dist/kya/behavior.js +142 -0
- package/dist/kya/identity.d.ts.map +1 -0
- package/dist/kya/identity.js +187 -0
- package/dist/kya/index.d.ts.map +1 -0
- package/dist/kya/index.js +99 -0
- package/dist/kya/types.d.ts.map +1 -0
- package/dist/kya/types.js +5 -0
- package/dist/trust-1000-agents.test.d.ts.map +1 -0
- package/dist/trust-1000-agents.test.js +608 -0
- package/dist/trust-capabilities.d.ts.map +1 -0
- package/dist/trust-capabilities.js +478 -0
- package/dist/trust-factors.d.ts.map +1 -0
- package/dist/trust-factors.js +588 -0
- package/dist/trust-factors.test.d.ts.map +1 -0
- package/dist/trust-factors.test.js +179 -0
- package/dist/validation-gate.d.ts.map +1 -0
- package/dist/validation-gate.js +468 -0
- package/dist/validation-gate.test.d.ts.map +1 -0
- package/dist/validation-gate.test.js +419 -0
- package/hardhat.config.ts +55 -0
- package/package.json +57 -0
- package/scripts/certify-agent.ts +91 -0
- package/scripts/deploy-agentcard.ts +63 -0
- package/scripts/mint-agentcard.ts +87 -0
- package/specs/adversarial-sandbox-test-suite.md +1055 -0
- package/specs/kya-framework.md +910 -0
- package/specs/trust-factors-v2.md +437 -0
- package/src/index.ts +14 -0
- package/src/kya/accountability.ts +132 -0
- package/src/kya/authorization.ts +325 -0
- package/src/kya/behavior.ts +169 -0
- package/src/kya/identity.ts +224 -0
- package/src/kya/index.ts +125 -0
- package/src/kya/types.ts +242 -0
- package/src/trust-1000-agents.test.ts +745 -0
- package/src/trust-capabilities.ts +517 -0
- package/src/trust-factors.test.ts +241 -0
- package/src/trust-factors.ts +666 -0
- package/src/validation-gate.test.ts +531 -0
- package/src/validation-gate.ts +665 -0
- package/test-kya-simple.ts +258 -0
- package/test-kya.ts +245 -0
- package/tsconfig.json +14 -0
- package/typechain-types/@openzeppelin/contracts/access/AccessControl.ts +324 -0
- package/typechain-types/@openzeppelin/contracts/access/IAccessControl.ts +292 -0
- package/typechain-types/@openzeppelin/contracts/access/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts/index.ts +11 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/IERC4906.ts +462 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.ts +69 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.ts +69 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.ts +69 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts/interfaces/index.ts +6 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/ERC721.ts +420 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721.ts +393 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721Receiver.ts +110 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.ts +470 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.ts +489 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.ts +443 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.ts +420 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/index.ts +7 -0
- package/typechain-types/@openzeppelin/contracts/token/ERC721/index.ts +8 -0
- package/typechain-types/@openzeppelin/contracts/token/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts/utils/Strings.ts +69 -0
- package/typechain-types/@openzeppelin/contracts/utils/index.ts +8 -0
- package/typechain-types/@openzeppelin/contracts/utils/introspection/ERC165.ts +94 -0
- package/typechain-types/@openzeppelin/contracts/utils/introspection/IERC165.ts +94 -0
- package/typechain-types/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
- package/typechain-types/@openzeppelin/contracts/utils/math/SafeCast.ts +69 -0
- package/typechain-types/@openzeppelin/contracts/utils/math/index.ts +4 -0
- package/typechain-types/@openzeppelin/index.ts +5 -0
- package/typechain-types/common.ts +131 -0
- package/typechain-types/contracts/AgentCard.ts +1415 -0
- package/typechain-types/contracts/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/AccessControl__factory.ts +250 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/IAccessControl__factory.ts +218 -0
- package/typechain-types/factories/@openzeppelin/contracts/access/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/index.ts +7 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/IERC4906__factory.ts +339 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory.ts +127 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory.ts +111 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory.ts +128 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
- package/typechain-types/factories/@openzeppelin/contracts/interfaces/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/ERC721__factory.ts +455 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721Receiver__factory.ts +59 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721__factory.ts +307 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable__factory.ts +535 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage__factory.ts +490 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable__factory.ts +366 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata__factory.ts +355 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/index.ts +7 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/index.ts +7 -0
- package/typechain-types/factories/@openzeppelin/contracts/token/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/Strings__factory.ts +90 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/index.ts +6 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/ERC165__factory.ts +41 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/IERC165__factory.ts +41 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/math/SafeCast__factory.ts +118 -0
- package/typechain-types/factories/@openzeppelin/contracts/utils/math/index.ts +4 -0
- package/typechain-types/factories/@openzeppelin/index.ts +4 -0
- package/typechain-types/factories/contracts/AgentCard__factory.ts +1480 -0
- package/typechain-types/factories/contracts/index.ts +4 -0
- package/typechain-types/factories/index.ts +5 -0
- package/typechain-types/index.ts +44 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust Factors Test Suite
|
|
3
|
+
*
|
|
4
|
+
* Tests 100 simulated agents through the trust scoring system
|
|
5
|
+
* to validate tier placement is correct.
|
|
6
|
+
*/
|
|
7
|
+
import { TrustTier, TIER_THRESHOLDS, getTrustTierFromScore, getTierName, calculateTrustScore, } from './trust-factors';
|
|
8
|
+
// All 23 factor codes
|
|
9
|
+
const ALL_FACTOR_CODES = [
|
|
10
|
+
'CT-COMP', 'CT-REL', 'CT-OBS', 'CT-TRANS', 'CT-ACCT', 'CT-SAFE',
|
|
11
|
+
'CT-SEC', 'CT-PRIV', 'CT-ID', 'OP-HUMAN', 'OP-ALIGN', 'OP-STEW',
|
|
12
|
+
'SF-HUM', 'SF-ADAPT', 'SF-LEARN', 'LC-UNCERT', 'LC-HANDOFF',
|
|
13
|
+
'LC-EMPHUM', 'LC-CAUSAL', 'LC-PATIENT', 'LC-EMP', 'LC-MORAL', 'LC-TRACK'
|
|
14
|
+
];
|
|
15
|
+
// Generate agent with scores targeting a specific score range
|
|
16
|
+
function generateAgentForScoreRange(agentId, targetTier) {
|
|
17
|
+
const tierRange = TIER_THRESHOLDS[targetTier];
|
|
18
|
+
// Target the middle of the tier's score range
|
|
19
|
+
const targetScore = (tierRange.min + tierRange.max) / 2 / 1000; // Convert to 0-1 scale
|
|
20
|
+
// Generate uniform scores around the target
|
|
21
|
+
const factorScores = ALL_FACTOR_CODES.map(code => {
|
|
22
|
+
// Add some variance but stay near target
|
|
23
|
+
const variance = (Math.random() - 0.5) * 0.1;
|
|
24
|
+
const score = Math.min(1.0, Math.max(0, targetScore + variance));
|
|
25
|
+
return {
|
|
26
|
+
code: code,
|
|
27
|
+
score,
|
|
28
|
+
timestamp: new Date(),
|
|
29
|
+
source: 'measured',
|
|
30
|
+
confidence: 0.9,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
id: agentId,
|
|
35
|
+
targetTier,
|
|
36
|
+
factorScores,
|
|
37
|
+
expectedScoreRange: tierRange,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Generate edge case agent at boundary of tier
|
|
41
|
+
function generateBoundaryAgent(agentId, targetTier, position) {
|
|
42
|
+
const tierRange = TIER_THRESHOLDS[targetTier];
|
|
43
|
+
// Target specific boundary score
|
|
44
|
+
const targetScore = position === 'low'
|
|
45
|
+
? (tierRange.min + 10) / 1000 // Just inside lower bound
|
|
46
|
+
: (tierRange.max - 10) / 1000; // Just inside upper bound
|
|
47
|
+
const factorScores = ALL_FACTOR_CODES.map(code => {
|
|
48
|
+
// Very small variance to stay near boundary
|
|
49
|
+
const variance = (Math.random() - 0.5) * 0.02;
|
|
50
|
+
const score = Math.min(1.0, Math.max(0, targetScore + variance));
|
|
51
|
+
return {
|
|
52
|
+
code: code,
|
|
53
|
+
score,
|
|
54
|
+
timestamp: new Date(),
|
|
55
|
+
source: 'measured',
|
|
56
|
+
confidence: 0.9,
|
|
57
|
+
};
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
id: agentId,
|
|
61
|
+
targetTier,
|
|
62
|
+
factorScores,
|
|
63
|
+
expectedScoreRange: tierRange,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function runTests() {
|
|
67
|
+
console.log('='.repeat(80));
|
|
68
|
+
console.log('BASIS TRUST FACTORS TEST SUITE');
|
|
69
|
+
console.log('Testing 100 agents across all trust tiers');
|
|
70
|
+
console.log('='.repeat(80));
|
|
71
|
+
console.log('');
|
|
72
|
+
// Print tier thresholds
|
|
73
|
+
console.log('TIER THRESHOLDS:');
|
|
74
|
+
console.log('-'.repeat(50));
|
|
75
|
+
Object.entries(TIER_THRESHOLDS).forEach(([tier, range]) => {
|
|
76
|
+
const tierNum = parseInt(tier);
|
|
77
|
+
console.log(` T${tierNum} ${getTierName(tierNum)}: ${range.min} - ${range.max}`);
|
|
78
|
+
});
|
|
79
|
+
console.log('');
|
|
80
|
+
const results = [];
|
|
81
|
+
let agentCounter = 0;
|
|
82
|
+
// Generate 100 test agents distributed across tiers
|
|
83
|
+
// T0: 12 agents, T1-T6: 13 agents each, T7: 10 agents
|
|
84
|
+
const tiersToTest = [
|
|
85
|
+
{ tier: TrustTier.T0_SANDBOX, count: 12 },
|
|
86
|
+
{ tier: TrustTier.T1_OBSERVED, count: 13 },
|
|
87
|
+
{ tier: TrustTier.T2_PROVISIONAL, count: 13 },
|
|
88
|
+
{ tier: TrustTier.T3_VERIFIED, count: 13 },
|
|
89
|
+
{ tier: TrustTier.T4_OPERATIONAL, count: 13 },
|
|
90
|
+
{ tier: TrustTier.T5_TRUSTED, count: 13 },
|
|
91
|
+
{ tier: TrustTier.T6_CERTIFIED, count: 13 },
|
|
92
|
+
{ tier: TrustTier.T7_AUTONOMOUS, count: 10 },
|
|
93
|
+
];
|
|
94
|
+
for (const { tier, count } of tiersToTest) {
|
|
95
|
+
console.log(`\nTesting T${tier} ${getTierName(tier)} (${count} agents):`);
|
|
96
|
+
console.log('-'.repeat(60));
|
|
97
|
+
for (let i = 0; i < count; i++) {
|
|
98
|
+
agentCounter++;
|
|
99
|
+
const agentId = `AGENT-${agentCounter.toString().padStart(3, '0')}`;
|
|
100
|
+
// Mix of regular and boundary agents
|
|
101
|
+
const agent = i < 2
|
|
102
|
+
? generateBoundaryAgent(agentId, tier, i === 0 ? 'low' : 'high')
|
|
103
|
+
: generateAgentForScoreRange(agentId, tier);
|
|
104
|
+
// Calculate trust score
|
|
105
|
+
const evaluation = calculateTrustScore(agent.factorScores, tier);
|
|
106
|
+
const actualTier = getTrustTierFromScore(evaluation.totalScore);
|
|
107
|
+
const passed = evaluation.totalScore >= agent.expectedScoreRange.min &&
|
|
108
|
+
evaluation.totalScore <= agent.expectedScoreRange.max;
|
|
109
|
+
const result = {
|
|
110
|
+
agentId,
|
|
111
|
+
targetTier: `T${tier} ${getTierName(tier)}`,
|
|
112
|
+
actualTier: `T${actualTier} ${getTierName(actualTier)}`,
|
|
113
|
+
score: evaluation.totalScore,
|
|
114
|
+
expectedRange: `${agent.expectedScoreRange.min}-${agent.expectedScoreRange.max}`,
|
|
115
|
+
passed,
|
|
116
|
+
compliant: evaluation.compliant,
|
|
117
|
+
criticalFailures: evaluation.belowThreshold.length,
|
|
118
|
+
};
|
|
119
|
+
results.push(result);
|
|
120
|
+
// Print result
|
|
121
|
+
const status = passed ? '✓' : '✗';
|
|
122
|
+
const complianceStatus = evaluation.compliant ? 'COMPLIANT' : `FAILED(${evaluation.belowThreshold.length})`;
|
|
123
|
+
console.log(` ${status} ${agentId}: Score=${evaluation.totalScore.toString().padStart(4)} ` +
|
|
124
|
+
`Target=${result.targetTier.padEnd(15)} Actual=${result.actualTier.padEnd(15)} ` +
|
|
125
|
+
`[${complianceStatus}]`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Summary
|
|
129
|
+
console.log('\n' + '='.repeat(80));
|
|
130
|
+
console.log('TEST SUMMARY');
|
|
131
|
+
console.log('='.repeat(80));
|
|
132
|
+
const passed = results.filter(r => r.passed).length;
|
|
133
|
+
const failed = results.filter(r => !r.passed).length;
|
|
134
|
+
const compliant = results.filter(r => r.compliant).length;
|
|
135
|
+
console.log(`\nTotal Agents Tested: ${results.length}`);
|
|
136
|
+
console.log(`Passed (in expected range): ${passed} (${((passed / results.length) * 100).toFixed(1)}%)`);
|
|
137
|
+
console.log(`Failed (outside range): ${failed} (${((failed / results.length) * 100).toFixed(1)}%)`);
|
|
138
|
+
console.log(`Compliant (met all critical factors): ${compliant} (${((compliant / results.length) * 100).toFixed(1)}%)`);
|
|
139
|
+
// Distribution by tier
|
|
140
|
+
console.log('\nDISTRIBUTION BY ACTUAL TIER:');
|
|
141
|
+
console.log('-'.repeat(40));
|
|
142
|
+
for (let t = 0; t <= 7; t++) {
|
|
143
|
+
const inTier = results.filter(r => r.actualTier.startsWith(`T${t}`)).length;
|
|
144
|
+
const bar = '█'.repeat(Math.round(inTier / 2));
|
|
145
|
+
console.log(` T${t} ${getTierName(t).padEnd(12)}: ${inTier.toString().padStart(3)} ${bar}`);
|
|
146
|
+
}
|
|
147
|
+
// Score distribution
|
|
148
|
+
console.log('\nSCORE DISTRIBUTION:');
|
|
149
|
+
console.log('-'.repeat(40));
|
|
150
|
+
const scoreRanges = [
|
|
151
|
+
{ label: '0-199', min: 0, max: 199 },
|
|
152
|
+
{ label: '200-349', min: 200, max: 349 },
|
|
153
|
+
{ label: '350-499', min: 350, max: 499 },
|
|
154
|
+
{ label: '500-649', min: 500, max: 649 },
|
|
155
|
+
{ label: '650-799', min: 650, max: 799 },
|
|
156
|
+
{ label: '800-875', min: 800, max: 875 },
|
|
157
|
+
{ label: '876-949', min: 876, max: 949 },
|
|
158
|
+
{ label: '950-1000', min: 950, max: 1000 },
|
|
159
|
+
];
|
|
160
|
+
for (const range of scoreRanges) {
|
|
161
|
+
const count = results.filter(r => r.score >= range.min && r.score <= range.max).length;
|
|
162
|
+
const bar = '█'.repeat(Math.round(count / 2));
|
|
163
|
+
console.log(` ${range.label.padEnd(10)}: ${count.toString().padStart(3)} ${bar}`);
|
|
164
|
+
}
|
|
165
|
+
// Failed agents detail
|
|
166
|
+
if (failed > 0) {
|
|
167
|
+
console.log('\nFAILED AGENTS:');
|
|
168
|
+
console.log('-'.repeat(60));
|
|
169
|
+
results.filter(r => !r.passed).forEach(r => {
|
|
170
|
+
console.log(` ${r.agentId}: Score=${r.score} Expected=${r.expectedRange} Got=${r.actualTier}`);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
console.log('\n' + '='.repeat(80));
|
|
174
|
+
console.log(failed === 0 ? 'ALL TESTS PASSED!' : `${failed} TESTS FAILED`);
|
|
175
|
+
console.log('='.repeat(80));
|
|
176
|
+
}
|
|
177
|
+
// Run tests
|
|
178
|
+
runTests();
|
|
179
|
+
//# sourceMappingURL=trust-factors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-gate.d.ts","sourceRoot":"","sources":["../src/validation-gate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BASIS Validation Gate
|
|
3
|
+
*
|
|
4
|
+
* Central validation gate that verifies agent manifests before execution.
|
|
5
|
+
* Combines CAR parsing, schema validation, and capability matching.
|
|
6
|
+
*
|
|
7
|
+
* This gate returns PASS/REJECT decisions for the Kaizen pipeline.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
import { TrustTier, TIER_THRESHOLDS } from './trust-factors';
|
|
11
|
+
import { hasCapability } from './trust-capabilities';
|
|
12
|
+
// =============================================================================
|
|
13
|
+
// VALIDATION GATE TYPES
|
|
14
|
+
// =============================================================================
|
|
15
|
+
/**
|
|
16
|
+
* Gate decision - determines whether agent can proceed
|
|
17
|
+
*/
|
|
18
|
+
export var GateDecision;
|
|
19
|
+
(function (GateDecision) {
|
|
20
|
+
/** Agent passes validation, proceed to Layer 2 */
|
|
21
|
+
GateDecision["PASS"] = "PASS";
|
|
22
|
+
/** Agent fails validation, block execution */
|
|
23
|
+
GateDecision["REJECT"] = "REJECT";
|
|
24
|
+
/** Agent requires human review before proceeding */
|
|
25
|
+
GateDecision["ESCALATE"] = "ESCALATE";
|
|
26
|
+
})(GateDecision || (GateDecision = {}));
|
|
27
|
+
/**
|
|
28
|
+
* Validation error severity levels
|
|
29
|
+
*/
|
|
30
|
+
export var ValidationSeverity;
|
|
31
|
+
(function (ValidationSeverity) {
|
|
32
|
+
/** Informational - does not affect decision */
|
|
33
|
+
ValidationSeverity["INFO"] = "info";
|
|
34
|
+
/** Warning - may affect future decisions */
|
|
35
|
+
ValidationSeverity["WARNING"] = "warning";
|
|
36
|
+
/** Error - causes rejection */
|
|
37
|
+
ValidationSeverity["ERROR"] = "error";
|
|
38
|
+
/** Critical - immediate rejection with logging */
|
|
39
|
+
ValidationSeverity["CRITICAL"] = "critical";
|
|
40
|
+
})(ValidationSeverity || (ValidationSeverity = {}));
|
|
41
|
+
// =============================================================================
|
|
42
|
+
// ZOD SCHEMAS
|
|
43
|
+
// =============================================================================
|
|
44
|
+
export const validationIssueSchema = z.object({
|
|
45
|
+
code: z.string(),
|
|
46
|
+
message: z.string(),
|
|
47
|
+
severity: z.nativeEnum(ValidationSeverity),
|
|
48
|
+
path: z.string().optional(),
|
|
49
|
+
expected: z.string().optional(),
|
|
50
|
+
actual: z.string().optional(),
|
|
51
|
+
});
|
|
52
|
+
export const agentManifestSchema = z.object({
|
|
53
|
+
agentId: z.string().min(1),
|
|
54
|
+
organization: z.string().optional(),
|
|
55
|
+
agentClass: z.string().optional(),
|
|
56
|
+
domains: z.array(z.string()).optional(),
|
|
57
|
+
capabilityLevel: z.number().int().min(0).max(7).optional(),
|
|
58
|
+
version: z.string().optional(),
|
|
59
|
+
trustScore: z.number().min(0).max(1000).optional(),
|
|
60
|
+
requestedCapabilities: z.array(z.string()).optional(),
|
|
61
|
+
metadata: z.record(z.unknown()).optional(),
|
|
62
|
+
});
|
|
63
|
+
export const registeredProfileSchema = z.object({
|
|
64
|
+
agentId: z.string(),
|
|
65
|
+
organization: z.string(),
|
|
66
|
+
agentClass: z.string(),
|
|
67
|
+
approvedDomains: z.array(z.string()),
|
|
68
|
+
maxCapabilityLevel: z.number().int().min(0).max(7),
|
|
69
|
+
approvedCapabilities: z.array(z.string()),
|
|
70
|
+
trustScore: z.number().min(0).max(1000),
|
|
71
|
+
registeredAt: z.date(),
|
|
72
|
+
lastVerifiedAt: z.date().optional(),
|
|
73
|
+
});
|
|
74
|
+
export const validationGateResultSchema = z.object({
|
|
75
|
+
decision: z.nativeEnum(GateDecision),
|
|
76
|
+
valid: z.boolean(),
|
|
77
|
+
agentId: z.string(),
|
|
78
|
+
trustTier: z.nativeEnum(TrustTier).optional(),
|
|
79
|
+
trustScore: z.number().optional(),
|
|
80
|
+
issues: z.array(validationIssueSchema),
|
|
81
|
+
errors: z.array(validationIssueSchema),
|
|
82
|
+
warnings: z.array(validationIssueSchema),
|
|
83
|
+
validatedAt: z.date(),
|
|
84
|
+
durationMs: z.number(),
|
|
85
|
+
allowedCapabilities: z.array(z.string()).optional(),
|
|
86
|
+
deniedCapabilities: z.array(z.string()).optional(),
|
|
87
|
+
recommendations: z.array(z.string()).optional(),
|
|
88
|
+
});
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// HELPER FUNCTIONS
|
|
91
|
+
// =============================================================================
|
|
92
|
+
/**
|
|
93
|
+
* Convert trust score to trust tier
|
|
94
|
+
*/
|
|
95
|
+
export function scoreToTier(score) {
|
|
96
|
+
// Iterate through tiers in reverse order (highest first)
|
|
97
|
+
const tiers = [
|
|
98
|
+
TrustTier.T7_AUTONOMOUS,
|
|
99
|
+
TrustTier.T6_CERTIFIED,
|
|
100
|
+
TrustTier.T5_TRUSTED,
|
|
101
|
+
TrustTier.T4_OPERATIONAL,
|
|
102
|
+
TrustTier.T3_VERIFIED,
|
|
103
|
+
TrustTier.T2_PROVISIONAL,
|
|
104
|
+
TrustTier.T1_OBSERVED,
|
|
105
|
+
TrustTier.T0_SANDBOX,
|
|
106
|
+
];
|
|
107
|
+
for (const tier of tiers) {
|
|
108
|
+
const thresholds = TIER_THRESHOLDS[tier];
|
|
109
|
+
if (score >= thresholds.min && score <= thresholds.max) {
|
|
110
|
+
return tier;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return TrustTier.T0_SANDBOX;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Validate CAR string format
|
|
117
|
+
*/
|
|
118
|
+
function validateCARFormat(agentId) {
|
|
119
|
+
const issues = [];
|
|
120
|
+
// Handle undefined/empty agentId
|
|
121
|
+
if (!agentId) {
|
|
122
|
+
issues.push({
|
|
123
|
+
code: 'MISSING_AGENT_ID',
|
|
124
|
+
message: 'Agent ID is required',
|
|
125
|
+
severity: ValidationSeverity.ERROR,
|
|
126
|
+
path: 'agentId',
|
|
127
|
+
});
|
|
128
|
+
return issues;
|
|
129
|
+
}
|
|
130
|
+
// Basic CAR format: registry.org.class:DOMAINS-Ln@version
|
|
131
|
+
const carRegex = /^([a-z0-9]+)\.([a-z0-9-]+)\.([a-z0-9-]+):([A-Z]+)-L([0-7])@(\d+\.\d+\.\d+)(?:#[a-z0-9,_-]+)?$/;
|
|
132
|
+
if (!carRegex.test(agentId)) {
|
|
133
|
+
// Check if it looks like a legacy format or just an ID
|
|
134
|
+
if (agentId.includes(':') && agentId.includes('@')) {
|
|
135
|
+
issues.push({
|
|
136
|
+
code: 'INVALID_CAR_FORMAT',
|
|
137
|
+
message: 'CAR string format is invalid',
|
|
138
|
+
severity: ValidationSeverity.ERROR,
|
|
139
|
+
path: 'agentId',
|
|
140
|
+
expected: 'registry.org.class:DOMAINS-Ln@x.y.z',
|
|
141
|
+
actual: agentId,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
else if (!agentId.includes('.')) {
|
|
145
|
+
// Simple ID format - acceptable but noted
|
|
146
|
+
issues.push({
|
|
147
|
+
code: 'SIMPLE_ID_FORMAT',
|
|
148
|
+
message: 'Agent uses simple ID format instead of full CAR string',
|
|
149
|
+
severity: ValidationSeverity.INFO,
|
|
150
|
+
path: 'agentId',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return issues;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Validate manifest against registered profile
|
|
158
|
+
*/
|
|
159
|
+
function validateAgainstProfile(manifest, profile) {
|
|
160
|
+
const issues = [];
|
|
161
|
+
// Check organization match
|
|
162
|
+
if (manifest.organization && manifest.organization !== profile.organization) {
|
|
163
|
+
issues.push({
|
|
164
|
+
code: 'ORG_MISMATCH',
|
|
165
|
+
message: 'Organization does not match registered profile',
|
|
166
|
+
severity: ValidationSeverity.ERROR,
|
|
167
|
+
path: 'organization',
|
|
168
|
+
expected: profile.organization,
|
|
169
|
+
actual: manifest.organization,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
// Check agent class match
|
|
173
|
+
if (manifest.agentClass && manifest.agentClass !== profile.agentClass) {
|
|
174
|
+
issues.push({
|
|
175
|
+
code: 'CLASS_MISMATCH',
|
|
176
|
+
message: 'Agent class does not match registered profile',
|
|
177
|
+
severity: ValidationSeverity.ERROR,
|
|
178
|
+
path: 'agentClass',
|
|
179
|
+
expected: profile.agentClass,
|
|
180
|
+
actual: manifest.agentClass,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
// Check capability level
|
|
184
|
+
if (manifest.capabilityLevel !== undefined) {
|
|
185
|
+
if (manifest.capabilityLevel > profile.maxCapabilityLevel) {
|
|
186
|
+
issues.push({
|
|
187
|
+
code: 'CAPABILITY_LEVEL_EXCEEDED',
|
|
188
|
+
message: 'Claimed capability level exceeds registered maximum',
|
|
189
|
+
severity: ValidationSeverity.ERROR,
|
|
190
|
+
path: 'capabilityLevel',
|
|
191
|
+
expected: `<= ${profile.maxCapabilityLevel}`,
|
|
192
|
+
actual: String(manifest.capabilityLevel),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// Check domains
|
|
197
|
+
if (manifest.domains) {
|
|
198
|
+
const unauthorizedDomains = manifest.domains.filter((d) => !profile.approvedDomains.includes(d));
|
|
199
|
+
if (unauthorizedDomains.length > 0) {
|
|
200
|
+
issues.push({
|
|
201
|
+
code: 'UNAUTHORIZED_DOMAINS',
|
|
202
|
+
message: `Agent claims unauthorized domains: ${unauthorizedDomains.join(', ')}`,
|
|
203
|
+
severity: ValidationSeverity.ERROR,
|
|
204
|
+
path: 'domains',
|
|
205
|
+
expected: profile.approvedDomains.join(', '),
|
|
206
|
+
actual: manifest.domains.join(', '),
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Check requested capabilities
|
|
211
|
+
if (manifest.requestedCapabilities) {
|
|
212
|
+
const unauthorizedCaps = manifest.requestedCapabilities.filter((c) => !profile.approvedCapabilities.includes(c));
|
|
213
|
+
if (unauthorizedCaps.length > 0) {
|
|
214
|
+
issues.push({
|
|
215
|
+
code: 'UNAUTHORIZED_CAPABILITIES',
|
|
216
|
+
message: `Agent requests unauthorized capabilities: ${unauthorizedCaps.join(', ')}`,
|
|
217
|
+
severity: ValidationSeverity.WARNING,
|
|
218
|
+
path: 'requestedCapabilities',
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return issues;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Validate trust tier requirements
|
|
226
|
+
*/
|
|
227
|
+
function validateTrustTier(manifest, minimumTier) {
|
|
228
|
+
const issues = [];
|
|
229
|
+
if (manifest.trustScore === undefined) {
|
|
230
|
+
issues.push({
|
|
231
|
+
code: 'MISSING_TRUST_SCORE',
|
|
232
|
+
message: 'Agent manifest does not include trust score',
|
|
233
|
+
severity: ValidationSeverity.WARNING,
|
|
234
|
+
path: 'trustScore',
|
|
235
|
+
});
|
|
236
|
+
return issues;
|
|
237
|
+
}
|
|
238
|
+
const agentTier = scoreToTier(manifest.trustScore);
|
|
239
|
+
if (minimumTier !== undefined) {
|
|
240
|
+
// Compare numeric tier values directly (TrustTier is a numeric enum 0-7)
|
|
241
|
+
if (agentTier < minimumTier) {
|
|
242
|
+
issues.push({
|
|
243
|
+
code: 'INSUFFICIENT_TRUST_TIER',
|
|
244
|
+
message: `Agent trust tier T${agentTier} is below minimum required T${minimumTier}`,
|
|
245
|
+
severity: ValidationSeverity.ERROR,
|
|
246
|
+
path: 'trustScore',
|
|
247
|
+
expected: `>= T${minimumTier}`,
|
|
248
|
+
actual: `T${agentTier}`,
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return issues;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Validate requested capabilities against trust tier
|
|
256
|
+
*/
|
|
257
|
+
function validateCapabilitiesAgainstTier(manifest) {
|
|
258
|
+
const issues = [];
|
|
259
|
+
const allowed = [];
|
|
260
|
+
const denied = [];
|
|
261
|
+
if (!manifest.requestedCapabilities || manifest.requestedCapabilities.length === 0) {
|
|
262
|
+
return { issues, allowed, denied };
|
|
263
|
+
}
|
|
264
|
+
const trustScore = manifest.trustScore ?? 0;
|
|
265
|
+
const agentTier = scoreToTier(trustScore);
|
|
266
|
+
for (const capability of manifest.requestedCapabilities) {
|
|
267
|
+
if (hasCapability(agentTier, capability)) {
|
|
268
|
+
allowed.push(capability);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
denied.push(capability);
|
|
272
|
+
issues.push({
|
|
273
|
+
code: 'CAPABILITY_TIER_INSUFFICIENT',
|
|
274
|
+
message: `Capability ${capability} requires higher trust tier than ${agentTier}`,
|
|
275
|
+
severity: ValidationSeverity.WARNING,
|
|
276
|
+
path: 'requestedCapabilities',
|
|
277
|
+
actual: capability,
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return { issues, allowed, denied };
|
|
282
|
+
}
|
|
283
|
+
// =============================================================================
|
|
284
|
+
// MAIN VALIDATION GATE
|
|
285
|
+
// =============================================================================
|
|
286
|
+
/**
|
|
287
|
+
* BASIS Validation Gate
|
|
288
|
+
*
|
|
289
|
+
* Validates an agent manifest and returns a PASS/REJECT/ESCALATE decision.
|
|
290
|
+
*
|
|
291
|
+
* @param manifest - Agent manifest to validate
|
|
292
|
+
* @param profile - Optional registered profile for comparison
|
|
293
|
+
* @param options - Validation options
|
|
294
|
+
* @returns Validation result with decision
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* const result = validateAgent({
|
|
299
|
+
* agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
|
|
300
|
+
* trustScore: 450,
|
|
301
|
+
* requestedCapabilities: ['CAP-DB-READ', 'CAP-WRITE-APPROVED'],
|
|
302
|
+
* });
|
|
303
|
+
*
|
|
304
|
+
* if (result.decision === GateDecision.PASS) {
|
|
305
|
+
* // Proceed to Layer 2 (INTENT)
|
|
306
|
+
* } else if (result.decision === GateDecision.REJECT) {
|
|
307
|
+
* // Block execution, log reasons
|
|
308
|
+
* console.log('Rejected:', result.errors);
|
|
309
|
+
* }
|
|
310
|
+
* ```
|
|
311
|
+
*/
|
|
312
|
+
export function validateAgent(manifest, profile, options = {}) {
|
|
313
|
+
const startTime = Date.now();
|
|
314
|
+
const issues = [];
|
|
315
|
+
// 1. Validate manifest schema
|
|
316
|
+
const schemaResult = agentManifestSchema.safeParse(manifest);
|
|
317
|
+
if (!schemaResult.success) {
|
|
318
|
+
for (const error of schemaResult.error.errors) {
|
|
319
|
+
issues.push({
|
|
320
|
+
code: 'SCHEMA_VALIDATION_FAILED',
|
|
321
|
+
message: error.message,
|
|
322
|
+
severity: ValidationSeverity.ERROR,
|
|
323
|
+
path: error.path.join('.'),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// 2. Validate CAR format (handles undefined agentId)
|
|
328
|
+
const carIssues = validateCARFormat(manifest.agentId);
|
|
329
|
+
issues.push(...carIssues);
|
|
330
|
+
// If agentId is missing, short-circuit with early rejection
|
|
331
|
+
if (carIssues.some(i => i.code === 'MISSING_AGENT_ID')) {
|
|
332
|
+
return {
|
|
333
|
+
decision: GateDecision.REJECT,
|
|
334
|
+
valid: false,
|
|
335
|
+
agentId: manifest.agentId ?? 'unknown',
|
|
336
|
+
issues,
|
|
337
|
+
errors: issues.filter(i => i.severity === ValidationSeverity.ERROR || i.severity === ValidationSeverity.CRITICAL),
|
|
338
|
+
warnings: issues.filter(i => i.severity === ValidationSeverity.WARNING),
|
|
339
|
+
validatedAt: new Date(),
|
|
340
|
+
durationMs: Date.now() - startTime,
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
// 3. Validate against registered profile
|
|
344
|
+
if (profile) {
|
|
345
|
+
issues.push(...validateAgainstProfile(manifest, profile));
|
|
346
|
+
}
|
|
347
|
+
else if (options.requireRegisteredProfile) {
|
|
348
|
+
issues.push({
|
|
349
|
+
code: 'PROFILE_NOT_FOUND',
|
|
350
|
+
message: 'Agent must have a registered profile',
|
|
351
|
+
severity: ValidationSeverity.ERROR,
|
|
352
|
+
path: 'agentId',
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
// 4. Validate trust tier requirements
|
|
356
|
+
issues.push(...validateTrustTier(manifest, options.minimumTrustTier));
|
|
357
|
+
// 5. Validate required domains
|
|
358
|
+
if (options.requiredDomains && options.requiredDomains.length > 0) {
|
|
359
|
+
const agentDomains = manifest.domains || [];
|
|
360
|
+
const missingDomains = options.requiredDomains.filter((d) => !agentDomains.includes(d));
|
|
361
|
+
if (missingDomains.length > 0) {
|
|
362
|
+
issues.push({
|
|
363
|
+
code: 'MISSING_REQUIRED_DOMAINS',
|
|
364
|
+
message: `Agent missing required domains: ${missingDomains.join(', ')}`,
|
|
365
|
+
severity: ValidationSeverity.ERROR,
|
|
366
|
+
path: 'domains',
|
|
367
|
+
expected: options.requiredDomains.join(', '),
|
|
368
|
+
actual: agentDomains.join(', ') || 'none',
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
// 6. Validate capabilities against trust tier
|
|
373
|
+
const capValidation = validateCapabilitiesAgainstTier(manifest);
|
|
374
|
+
issues.push(...capValidation.issues);
|
|
375
|
+
// 7. Run custom validators
|
|
376
|
+
if (options.customValidators) {
|
|
377
|
+
for (const validator of options.customValidators) {
|
|
378
|
+
try {
|
|
379
|
+
issues.push(...validator(manifest, profile));
|
|
380
|
+
}
|
|
381
|
+
catch (e) {
|
|
382
|
+
issues.push({
|
|
383
|
+
code: 'CUSTOM_VALIDATOR_ERROR',
|
|
384
|
+
message: `Custom validator failed: ${e instanceof Error ? e.message : String(e)}`,
|
|
385
|
+
severity: ValidationSeverity.WARNING,
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// Separate errors and warnings
|
|
391
|
+
const errors = issues.filter((i) => i.severity === ValidationSeverity.ERROR || i.severity === ValidationSeverity.CRITICAL);
|
|
392
|
+
const warnings = issues.filter((i) => i.severity === ValidationSeverity.WARNING);
|
|
393
|
+
// Determine decision
|
|
394
|
+
let decision;
|
|
395
|
+
let valid;
|
|
396
|
+
const hasCritical = issues.some((i) => i.severity === ValidationSeverity.CRITICAL);
|
|
397
|
+
const hasErrors = errors.length > 0;
|
|
398
|
+
const hasWarnings = warnings.length > 0;
|
|
399
|
+
if (hasCritical || hasErrors) {
|
|
400
|
+
decision = GateDecision.REJECT;
|
|
401
|
+
valid = false;
|
|
402
|
+
}
|
|
403
|
+
else if (options.strict && hasWarnings) {
|
|
404
|
+
decision = GateDecision.REJECT;
|
|
405
|
+
valid = false;
|
|
406
|
+
}
|
|
407
|
+
else if (!options.strict && hasWarnings && capValidation.denied.length > 0) {
|
|
408
|
+
// Agent wants capabilities they can't have - escalate for review
|
|
409
|
+
decision = options.allowCapabilityEscalation ? GateDecision.ESCALATE : GateDecision.REJECT;
|
|
410
|
+
valid = decision === GateDecision.ESCALATE;
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
decision = GateDecision.PASS;
|
|
414
|
+
valid = true;
|
|
415
|
+
}
|
|
416
|
+
// Build recommendations
|
|
417
|
+
const recommendations = [];
|
|
418
|
+
if (capValidation.denied.length > 0) {
|
|
419
|
+
recommendations.push(`Increase trust score to access denied capabilities: ${capValidation.denied.join(', ')}`);
|
|
420
|
+
}
|
|
421
|
+
if (!profile && !options.requireRegisteredProfile) {
|
|
422
|
+
recommendations.push('Consider registering agent profile for enhanced validation');
|
|
423
|
+
}
|
|
424
|
+
// Calculate trust tier
|
|
425
|
+
const trustTier = manifest.trustScore !== undefined ? scoreToTier(manifest.trustScore) : undefined;
|
|
426
|
+
return {
|
|
427
|
+
decision,
|
|
428
|
+
valid,
|
|
429
|
+
agentId: manifest.agentId,
|
|
430
|
+
trustTier,
|
|
431
|
+
trustScore: manifest.trustScore,
|
|
432
|
+
issues,
|
|
433
|
+
errors,
|
|
434
|
+
warnings,
|
|
435
|
+
validatedAt: new Date(),
|
|
436
|
+
durationMs: Date.now() - startTime,
|
|
437
|
+
allowedCapabilities: capValidation.allowed.length > 0 ? capValidation.allowed : undefined,
|
|
438
|
+
deniedCapabilities: capValidation.denied.length > 0 ? capValidation.denied : undefined,
|
|
439
|
+
recommendations: recommendations.length > 0 ? recommendations : undefined,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
/**
|
|
443
|
+
* Quick validation check - returns boolean
|
|
444
|
+
*/
|
|
445
|
+
export function isValidAgent(manifest, profile, options) {
|
|
446
|
+
return validateAgent(manifest, profile, options).valid;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Create a validation gate with preset options
|
|
450
|
+
*/
|
|
451
|
+
export function createValidationGate(defaultOptions) {
|
|
452
|
+
return {
|
|
453
|
+
validate: (manifest, profile, options) => validateAgent(manifest, profile, { ...defaultOptions, ...options }),
|
|
454
|
+
isValid: (manifest, profile, options) => isValidAgent(manifest, profile, { ...defaultOptions, ...options }),
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Strict validation gate - treats warnings as errors
|
|
459
|
+
*/
|
|
460
|
+
export const strictValidationGate = createValidationGate({ strict: true });
|
|
461
|
+
/**
|
|
462
|
+
* Production validation gate - requires registered profile
|
|
463
|
+
*/
|
|
464
|
+
export const productionValidationGate = createValidationGate({
|
|
465
|
+
requireRegisteredProfile: true,
|
|
466
|
+
minimumTrustTier: TrustTier.T2_PROVISIONAL,
|
|
467
|
+
});
|
|
468
|
+
//# sourceMappingURL=validation-gate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation-gate.test.d.ts","sourceRoot":"","sources":["../src/validation-gate.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|