@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.
Files changed (174) hide show
  1. package/.env.example +22 -0
  2. package/AMOY-MIGRATION.md +188 -0
  3. package/DEPLOY-AMOY.md +368 -0
  4. package/DEPLOY-NOW.md +216 -0
  5. package/DEPLOYMENT.md +239 -0
  6. package/GET-WALLET.md +286 -0
  7. package/QUICK-WALLET-SETUP.md +268 -0
  8. package/README.md +195 -0
  9. package/artifacts/@openzeppelin/contracts/access/AccessControl.sol/AccessControl.dbg.json +4 -0
  10. package/artifacts/@openzeppelin/contracts/access/AccessControl.sol/AccessControl.json +236 -0
  11. package/artifacts/@openzeppelin/contracts/access/IAccessControl.sol/IAccessControl.dbg.json +4 -0
  12. package/artifacts/@openzeppelin/contracts/access/IAccessControl.sol/IAccessControl.json +204 -0
  13. package/artifacts/@openzeppelin/contracts/interfaces/IERC4906.sol/IERC4906.dbg.json +4 -0
  14. package/artifacts/@openzeppelin/contracts/interfaces/IERC4906.sol/IERC4906.json +328 -0
  15. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.dbg.json +4 -0
  16. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.json +113 -0
  17. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.dbg.json +4 -0
  18. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.json +97 -0
  19. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.dbg.json +4 -0
  20. package/artifacts/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.json +114 -0
  21. package/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.dbg.json +4 -0
  22. package/artifacts/@openzeppelin/contracts/token/ERC721/ERC721.sol/ERC721.json +444 -0
  23. package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721.sol/IERC721.dbg.json +4 -0
  24. package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721.sol/IERC721.json +296 -0
  25. package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.dbg.json +4 -0
  26. package/artifacts/@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol/IERC721Receiver.json +45 -0
  27. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol/ERC721Enumerable.dbg.json +4 -0
  28. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol/ERC721Enumerable.json +521 -0
  29. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol/ERC721URIStorage.dbg.json +4 -0
  30. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol/ERC721URIStorage.json +476 -0
  31. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol/IERC721Enumerable.dbg.json +4 -0
  32. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.sol/IERC721Enumerable.json +352 -0
  33. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol/IERC721Metadata.dbg.json +4 -0
  34. package/artifacts/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol/IERC721Metadata.json +341 -0
  35. package/artifacts/@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol/ERC721Utils.dbg.json +4 -0
  36. package/artifacts/@openzeppelin/contracts/token/ERC721/utils/ERC721Utils.sol/ERC721Utils.json +10 -0
  37. package/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.dbg.json +4 -0
  38. package/artifacts/@openzeppelin/contracts/utils/Context.sol/Context.json +10 -0
  39. package/artifacts/@openzeppelin/contracts/utils/Panic.sol/Panic.dbg.json +4 -0
  40. package/artifacts/@openzeppelin/contracts/utils/Panic.sol/Panic.json +10 -0
  41. package/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.dbg.json +4 -0
  42. package/artifacts/@openzeppelin/contracts/utils/Strings.sol/Strings.json +37 -0
  43. package/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.dbg.json +4 -0
  44. package/artifacts/@openzeppelin/contracts/utils/introspection/ERC165.sol/ERC165.json +30 -0
  45. package/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.dbg.json +4 -0
  46. package/artifacts/@openzeppelin/contracts/utils/introspection/IERC165.sol/IERC165.json +30 -0
  47. package/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.dbg.json +4 -0
  48. package/artifacts/@openzeppelin/contracts/utils/math/Math.sol/Math.json +10 -0
  49. package/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.dbg.json +4 -0
  50. package/artifacts/@openzeppelin/contracts/utils/math/SafeCast.sol/SafeCast.json +65 -0
  51. package/artifacts/@openzeppelin/contracts/utils/math/SignedMath.sol/SignedMath.dbg.json +4 -0
  52. package/artifacts/@openzeppelin/contracts/utils/math/SignedMath.sol/SignedMath.json +10 -0
  53. package/artifacts/build-info/357d1bba4062d461f497f221490811a3.json +1 -0
  54. package/artifacts/contracts/AgentCard.sol/AgentCard.dbg.json +4 -0
  55. package/artifacts/contracts/AgentCard.sol/AgentCard.json +1430 -0
  56. package/build_errors.txt +0 -0
  57. package/build_output.txt +0 -0
  58. package/cache/solidity-files-cache.json +885 -0
  59. package/contracts/AgentCard.sol +478 -0
  60. package/contracts/deploy/01-deploy-agentcard.ts +66 -0
  61. package/dist/index.d.ts.map +1 -0
  62. package/dist/index.js +12 -0
  63. package/dist/kya/accountability.d.ts.map +1 -0
  64. package/dist/kya/accountability.js +100 -0
  65. package/dist/kya/authorization.d.ts.map +1 -0
  66. package/dist/kya/authorization.js +258 -0
  67. package/dist/kya/behavior.d.ts.map +1 -0
  68. package/dist/kya/behavior.js +142 -0
  69. package/dist/kya/identity.d.ts.map +1 -0
  70. package/dist/kya/identity.js +187 -0
  71. package/dist/kya/index.d.ts.map +1 -0
  72. package/dist/kya/index.js +99 -0
  73. package/dist/kya/types.d.ts.map +1 -0
  74. package/dist/kya/types.js +5 -0
  75. package/dist/trust-1000-agents.test.d.ts.map +1 -0
  76. package/dist/trust-1000-agents.test.js +608 -0
  77. package/dist/trust-capabilities.d.ts.map +1 -0
  78. package/dist/trust-capabilities.js +478 -0
  79. package/dist/trust-factors.d.ts.map +1 -0
  80. package/dist/trust-factors.js +588 -0
  81. package/dist/trust-factors.test.d.ts.map +1 -0
  82. package/dist/trust-factors.test.js +179 -0
  83. package/dist/validation-gate.d.ts.map +1 -0
  84. package/dist/validation-gate.js +468 -0
  85. package/dist/validation-gate.test.d.ts.map +1 -0
  86. package/dist/validation-gate.test.js +419 -0
  87. package/hardhat.config.ts +55 -0
  88. package/package.json +57 -0
  89. package/scripts/certify-agent.ts +91 -0
  90. package/scripts/deploy-agentcard.ts +63 -0
  91. package/scripts/mint-agentcard.ts +87 -0
  92. package/specs/adversarial-sandbox-test-suite.md +1055 -0
  93. package/specs/kya-framework.md +910 -0
  94. package/specs/trust-factors-v2.md +437 -0
  95. package/src/index.ts +14 -0
  96. package/src/kya/accountability.ts +132 -0
  97. package/src/kya/authorization.ts +325 -0
  98. package/src/kya/behavior.ts +169 -0
  99. package/src/kya/identity.ts +224 -0
  100. package/src/kya/index.ts +125 -0
  101. package/src/kya/types.ts +242 -0
  102. package/src/trust-1000-agents.test.ts +745 -0
  103. package/src/trust-capabilities.ts +517 -0
  104. package/src/trust-factors.test.ts +241 -0
  105. package/src/trust-factors.ts +666 -0
  106. package/src/validation-gate.test.ts +531 -0
  107. package/src/validation-gate.ts +665 -0
  108. package/test-kya-simple.ts +258 -0
  109. package/test-kya.ts +245 -0
  110. package/tsconfig.json +14 -0
  111. package/typechain-types/@openzeppelin/contracts/access/AccessControl.ts +324 -0
  112. package/typechain-types/@openzeppelin/contracts/access/IAccessControl.ts +292 -0
  113. package/typechain-types/@openzeppelin/contracts/access/index.ts +5 -0
  114. package/typechain-types/@openzeppelin/contracts/index.ts +11 -0
  115. package/typechain-types/@openzeppelin/contracts/interfaces/IERC4906.ts +462 -0
  116. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors.ts +69 -0
  117. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors.ts +69 -0
  118. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors.ts +69 -0
  119. package/typechain-types/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
  120. package/typechain-types/@openzeppelin/contracts/interfaces/index.ts +6 -0
  121. package/typechain-types/@openzeppelin/contracts/token/ERC721/ERC721.ts +420 -0
  122. package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721.ts +393 -0
  123. package/typechain-types/@openzeppelin/contracts/token/ERC721/IERC721Receiver.ts +110 -0
  124. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.ts +470 -0
  125. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.ts +489 -0
  126. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable.ts +443 -0
  127. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.ts +420 -0
  128. package/typechain-types/@openzeppelin/contracts/token/ERC721/extensions/index.ts +7 -0
  129. package/typechain-types/@openzeppelin/contracts/token/ERC721/index.ts +8 -0
  130. package/typechain-types/@openzeppelin/contracts/token/index.ts +5 -0
  131. package/typechain-types/@openzeppelin/contracts/utils/Strings.ts +69 -0
  132. package/typechain-types/@openzeppelin/contracts/utils/index.ts +8 -0
  133. package/typechain-types/@openzeppelin/contracts/utils/introspection/ERC165.ts +94 -0
  134. package/typechain-types/@openzeppelin/contracts/utils/introspection/IERC165.ts +94 -0
  135. package/typechain-types/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
  136. package/typechain-types/@openzeppelin/contracts/utils/math/SafeCast.ts +69 -0
  137. package/typechain-types/@openzeppelin/contracts/utils/math/index.ts +4 -0
  138. package/typechain-types/@openzeppelin/index.ts +5 -0
  139. package/typechain-types/common.ts +131 -0
  140. package/typechain-types/contracts/AgentCard.ts +1415 -0
  141. package/typechain-types/contracts/index.ts +4 -0
  142. package/typechain-types/factories/@openzeppelin/contracts/access/AccessControl__factory.ts +250 -0
  143. package/typechain-types/factories/@openzeppelin/contracts/access/IAccessControl__factory.ts +218 -0
  144. package/typechain-types/factories/@openzeppelin/contracts/access/index.ts +5 -0
  145. package/typechain-types/factories/@openzeppelin/contracts/index.ts +7 -0
  146. package/typechain-types/factories/@openzeppelin/contracts/interfaces/IERC4906__factory.ts +339 -0
  147. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC1155Errors__factory.ts +127 -0
  148. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC20Errors__factory.ts +111 -0
  149. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/IERC721Errors__factory.ts +128 -0
  150. package/typechain-types/factories/@openzeppelin/contracts/interfaces/draft-IERC6093.sol/index.ts +6 -0
  151. package/typechain-types/factories/@openzeppelin/contracts/interfaces/index.ts +5 -0
  152. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/ERC721__factory.ts +455 -0
  153. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721Receiver__factory.ts +59 -0
  154. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/IERC721__factory.ts +307 -0
  155. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable__factory.ts +535 -0
  156. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage__factory.ts +490 -0
  157. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/IERC721Enumerable__factory.ts +366 -0
  158. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata__factory.ts +355 -0
  159. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/extensions/index.ts +7 -0
  160. package/typechain-types/factories/@openzeppelin/contracts/token/ERC721/index.ts +7 -0
  161. package/typechain-types/factories/@openzeppelin/contracts/token/index.ts +4 -0
  162. package/typechain-types/factories/@openzeppelin/contracts/utils/Strings__factory.ts +90 -0
  163. package/typechain-types/factories/@openzeppelin/contracts/utils/index.ts +6 -0
  164. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/ERC165__factory.ts +41 -0
  165. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/IERC165__factory.ts +41 -0
  166. package/typechain-types/factories/@openzeppelin/contracts/utils/introspection/index.ts +5 -0
  167. package/typechain-types/factories/@openzeppelin/contracts/utils/math/SafeCast__factory.ts +118 -0
  168. package/typechain-types/factories/@openzeppelin/contracts/utils/math/index.ts +4 -0
  169. package/typechain-types/factories/@openzeppelin/index.ts +4 -0
  170. package/typechain-types/factories/contracts/AgentCard__factory.ts +1480 -0
  171. package/typechain-types/factories/contracts/index.ts +4 -0
  172. package/typechain-types/factories/index.ts +5 -0
  173. package/typechain-types/index.ts +44 -0
  174. package/vitest.config.ts +8 -0
@@ -0,0 +1,531 @@
1
+ /**
2
+ * Tests for BASIS Validation Gate
3
+ */
4
+
5
+ import { describe, it, expect } from 'vitest';
6
+ import {
7
+ validateAgent,
8
+ isValidAgent,
9
+ createValidationGate,
10
+ strictValidationGate,
11
+ productionValidationGate,
12
+ GateDecision,
13
+ ValidationSeverity,
14
+ type AgentManifest,
15
+ type RegisteredProfile,
16
+ type ValidationGateOptions,
17
+ scoreToTier,
18
+ } from './validation-gate';
19
+ import { TrustTier } from './trust-factors';
20
+
21
+ describe('ValidationGate', () => {
22
+ // =============================================================================
23
+ // BASIC VALIDATION TESTS
24
+ // =============================================================================
25
+
26
+ describe('validateAgent', () => {
27
+ it('should PASS a valid manifest', () => {
28
+ const manifest: AgentManifest = {
29
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
30
+ organization: 'acme-corp',
31
+ agentClass: 'invoice-bot',
32
+ domains: ['A', 'B', 'F'],
33
+ capabilityLevel: 3,
34
+ version: '1.0.0',
35
+ trustScore: 450,
36
+ };
37
+
38
+ const result = validateAgent(manifest);
39
+
40
+ expect(result.decision).toBe(GateDecision.PASS);
41
+ expect(result.valid).toBe(true);
42
+ expect(result.errors).toHaveLength(0);
43
+ });
44
+
45
+ it('should REJECT manifest missing required agentId', () => {
46
+ const manifest = {
47
+ organization: 'acme-corp',
48
+ trustScore: 450,
49
+ } as AgentManifest;
50
+
51
+ const result = validateAgent(manifest);
52
+
53
+ expect(result.decision).toBe(GateDecision.REJECT);
54
+ expect(result.valid).toBe(false);
55
+ expect(result.errors.length).toBeGreaterThan(0);
56
+ });
57
+
58
+ it('should include timing information', () => {
59
+ const manifest: AgentManifest = {
60
+ agentId: 'test-agent',
61
+ trustScore: 500,
62
+ };
63
+
64
+ const result = validateAgent(manifest);
65
+
66
+ expect(result.validatedAt).toBeInstanceOf(Date);
67
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
68
+ });
69
+
70
+ it('should detect invalid CAR format', () => {
71
+ const manifest: AgentManifest = {
72
+ agentId: 'invalid-format:missing-parts@1.0.0',
73
+ trustScore: 500,
74
+ };
75
+
76
+ const result = validateAgent(manifest);
77
+
78
+ const formatIssue = result.issues.find((i) => i.code === 'INVALID_CAR_FORMAT');
79
+ expect(formatIssue).toBeDefined();
80
+ });
81
+
82
+ it('should accept simple ID format with info note', () => {
83
+ const manifest: AgentManifest = {
84
+ agentId: 'simple-agent-id',
85
+ trustScore: 500,
86
+ };
87
+
88
+ const result = validateAgent(manifest);
89
+
90
+ expect(result.valid).toBe(true);
91
+ const infoIssue = result.issues.find((i) => i.code === 'SIMPLE_ID_FORMAT');
92
+ expect(infoIssue).toBeDefined();
93
+ expect(infoIssue?.severity).toBe(ValidationSeverity.INFO);
94
+ });
95
+ });
96
+
97
+ // =============================================================================
98
+ // TRUST TIER VALIDATION
99
+ // =============================================================================
100
+
101
+ describe('trust tier validation', () => {
102
+ it('should calculate trust tier from score', () => {
103
+ // T0: 0-199
104
+ expect(scoreToTier(0)).toBe(TrustTier.T0_SANDBOX);
105
+ expect(scoreToTier(199)).toBe(TrustTier.T0_SANDBOX);
106
+ // T1: 200-349
107
+ expect(scoreToTier(200)).toBe(TrustTier.T1_OBSERVED);
108
+ expect(scoreToTier(349)).toBe(TrustTier.T1_OBSERVED);
109
+ // T2: 350-499
110
+ expect(scoreToTier(350)).toBe(TrustTier.T2_PROVISIONAL);
111
+ expect(scoreToTier(499)).toBe(TrustTier.T2_PROVISIONAL);
112
+ // T3: 500-649
113
+ expect(scoreToTier(500)).toBe(TrustTier.T3_VERIFIED);
114
+ expect(scoreToTier(649)).toBe(TrustTier.T3_VERIFIED);
115
+ // T4: 650-799
116
+ expect(scoreToTier(650)).toBe(TrustTier.T4_OPERATIONAL);
117
+ expect(scoreToTier(799)).toBe(TrustTier.T4_OPERATIONAL);
118
+ // T5: 800-875
119
+ expect(scoreToTier(800)).toBe(TrustTier.T5_TRUSTED);
120
+ expect(scoreToTier(875)).toBe(TrustTier.T5_TRUSTED);
121
+ // T6: 876-950
122
+ expect(scoreToTier(876)).toBe(TrustTier.T6_CERTIFIED);
123
+ expect(scoreToTier(950)).toBe(TrustTier.T6_CERTIFIED);
124
+ // T7: 951-1000
125
+ expect(scoreToTier(951)).toBe(TrustTier.T7_AUTONOMOUS);
126
+ expect(scoreToTier(1000)).toBe(TrustTier.T7_AUTONOMOUS);
127
+ });
128
+
129
+ it('should REJECT when trust tier is below minimum', () => {
130
+ const manifest: AgentManifest = {
131
+ agentId: 'test-agent',
132
+ trustScore: 100, // T0
133
+ };
134
+
135
+ const result = validateAgent(manifest, undefined, {
136
+ minimumTrustTier: TrustTier.T3_VERIFIED,
137
+ });
138
+
139
+ expect(result.decision).toBe(GateDecision.REJECT);
140
+ expect(result.errors.some((e) => e.code === 'INSUFFICIENT_TRUST_TIER')).toBe(true);
141
+ });
142
+
143
+ it('should PASS when trust tier meets minimum', () => {
144
+ const manifest: AgentManifest = {
145
+ agentId: 'test-agent',
146
+ trustScore: 700, // T4 (650-799)
147
+ };
148
+
149
+ const result = validateAgent(manifest, undefined, {
150
+ minimumTrustTier: TrustTier.T3_VERIFIED,
151
+ });
152
+
153
+ expect(result.decision).toBe(GateDecision.PASS);
154
+ expect(result.trustTier).toBe(TrustTier.T4_OPERATIONAL);
155
+ });
156
+
157
+ it('should warn when trust score is missing', () => {
158
+ const manifest: AgentManifest = {
159
+ agentId: 'test-agent',
160
+ };
161
+
162
+ const result = validateAgent(manifest);
163
+
164
+ expect(result.warnings.some((w) => w.code === 'MISSING_TRUST_SCORE')).toBe(true);
165
+ });
166
+ });
167
+
168
+ // =============================================================================
169
+ // PROFILE VALIDATION
170
+ // =============================================================================
171
+
172
+ describe('profile validation', () => {
173
+ const validProfile: RegisteredProfile = {
174
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
175
+ organization: 'acme-corp',
176
+ agentClass: 'invoice-bot',
177
+ approvedDomains: ['A', 'B', 'F'],
178
+ maxCapabilityLevel: 4,
179
+ approvedCapabilities: ['CAP-READ-PUBLIC', 'CAP-DB-READ', 'CAP-WRITE-APPROVED'],
180
+ trustScore: 500,
181
+ registeredAt: new Date('2024-01-01'),
182
+ };
183
+
184
+ it('should PASS when manifest matches profile', () => {
185
+ const manifest: AgentManifest = {
186
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
187
+ organization: 'acme-corp',
188
+ agentClass: 'invoice-bot',
189
+ domains: ['A', 'B'],
190
+ capabilityLevel: 3,
191
+ trustScore: 500,
192
+ };
193
+
194
+ const result = validateAgent(manifest, validProfile);
195
+
196
+ expect(result.decision).toBe(GateDecision.PASS);
197
+ expect(result.valid).toBe(true);
198
+ });
199
+
200
+ it('should REJECT when organization mismatches', () => {
201
+ const manifest: AgentManifest = {
202
+ agentId: 'test-agent',
203
+ organization: 'evil-corp',
204
+ trustScore: 500,
205
+ };
206
+
207
+ const result = validateAgent(manifest, validProfile);
208
+
209
+ expect(result.decision).toBe(GateDecision.REJECT);
210
+ expect(result.errors.some((e) => e.code === 'ORG_MISMATCH')).toBe(true);
211
+ });
212
+
213
+ it('should REJECT when capability level exceeds maximum', () => {
214
+ const manifest: AgentManifest = {
215
+ agentId: 'test-agent',
216
+ organization: 'acme-corp',
217
+ capabilityLevel: 7, // exceeds profile max of 4
218
+ trustScore: 500,
219
+ };
220
+
221
+ const result = validateAgent(manifest, validProfile);
222
+
223
+ expect(result.decision).toBe(GateDecision.REJECT);
224
+ expect(result.errors.some((e) => e.code === 'CAPABILITY_LEVEL_EXCEEDED')).toBe(true);
225
+ });
226
+
227
+ it('should REJECT unauthorized domains', () => {
228
+ const manifest: AgentManifest = {
229
+ agentId: 'test-agent',
230
+ organization: 'acme-corp',
231
+ domains: ['A', 'B', 'S'], // S not approved
232
+ trustScore: 500,
233
+ };
234
+
235
+ const result = validateAgent(manifest, validProfile);
236
+
237
+ expect(result.decision).toBe(GateDecision.REJECT);
238
+ expect(result.errors.some((e) => e.code === 'UNAUTHORIZED_DOMAINS')).toBe(true);
239
+ });
240
+
241
+ it('should warn on unauthorized capabilities', () => {
242
+ const manifest: AgentManifest = {
243
+ agentId: 'test-agent',
244
+ organization: 'acme-corp',
245
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-SYSTEM-ADMIN-FULL'], // admin not approved
246
+ trustScore: 500,
247
+ };
248
+
249
+ const result = validateAgent(manifest, validProfile);
250
+
251
+ expect(result.warnings.some((w) => w.code === 'UNAUTHORIZED_CAPABILITIES')).toBe(true);
252
+ });
253
+
254
+ it('should REJECT when profile required but missing', () => {
255
+ const manifest: AgentManifest = {
256
+ agentId: 'test-agent',
257
+ trustScore: 500,
258
+ };
259
+
260
+ const result = validateAgent(manifest, undefined, {
261
+ requireRegisteredProfile: true,
262
+ });
263
+
264
+ expect(result.decision).toBe(GateDecision.REJECT);
265
+ expect(result.errors.some((e) => e.code === 'PROFILE_NOT_FOUND')).toBe(true);
266
+ });
267
+ });
268
+
269
+ // =============================================================================
270
+ // CAPABILITY VALIDATION
271
+ // =============================================================================
272
+
273
+ describe('capability validation', () => {
274
+ it('should allow capabilities matching trust tier', () => {
275
+ const manifest: AgentManifest = {
276
+ agentId: 'test-agent',
277
+ trustScore: 700, // T4_STANDARD (650-799)
278
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-AGENT-COMMUNICATE'],
279
+ };
280
+
281
+ const result = validateAgent(manifest);
282
+
283
+ expect(result.allowedCapabilities).toContain('CAP-READ-PUBLIC');
284
+ expect(result.allowedCapabilities).toContain('CAP-AGENT-COMMUNICATE');
285
+ expect(result.deniedCapabilities).toBeUndefined();
286
+ });
287
+
288
+ it('should deny capabilities above trust tier', () => {
289
+ const manifest: AgentManifest = {
290
+ agentId: 'test-agent',
291
+ trustScore: 100, // T0_SANDBOX
292
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-AGENT-SPAWN'], // spawn requires T6
293
+ };
294
+
295
+ const result = validateAgent(manifest);
296
+
297
+ expect(result.allowedCapabilities).toContain('CAP-READ-PUBLIC');
298
+ expect(result.deniedCapabilities).toContain('CAP-AGENT-SPAWN');
299
+ });
300
+
301
+ it('should provide recommendations for denied capabilities', () => {
302
+ const manifest: AgentManifest = {
303
+ agentId: 'test-agent',
304
+ trustScore: 100,
305
+ requestedCapabilities: ['CAP-AGENT-SPAWN'],
306
+ };
307
+
308
+ const result = validateAgent(manifest);
309
+
310
+ expect(result.recommendations).toBeDefined();
311
+ expect(result.recommendations?.some((r) => r.includes('trust score'))).toBe(true);
312
+ });
313
+ });
314
+
315
+ // =============================================================================
316
+ // REQUIRED DOMAINS
317
+ // =============================================================================
318
+
319
+ describe('required domains', () => {
320
+ it('should REJECT when required domains are missing', () => {
321
+ const manifest: AgentManifest = {
322
+ agentId: 'test-agent',
323
+ domains: ['A', 'B'],
324
+ trustScore: 500,
325
+ };
326
+
327
+ const result = validateAgent(manifest, undefined, {
328
+ requiredDomains: ['A', 'F'], // F is missing
329
+ });
330
+
331
+ expect(result.decision).toBe(GateDecision.REJECT);
332
+ expect(result.errors.some((e) => e.code === 'MISSING_REQUIRED_DOMAINS')).toBe(true);
333
+ });
334
+
335
+ it('should PASS when all required domains present', () => {
336
+ const manifest: AgentManifest = {
337
+ agentId: 'test-agent',
338
+ domains: ['A', 'B', 'F'],
339
+ trustScore: 500,
340
+ };
341
+
342
+ const result = validateAgent(manifest, undefined, {
343
+ requiredDomains: ['A', 'F'],
344
+ });
345
+
346
+ expect(result.decision).toBe(GateDecision.PASS);
347
+ });
348
+ });
349
+
350
+ // =============================================================================
351
+ // STRICT MODE
352
+ // =============================================================================
353
+
354
+ describe('strict mode', () => {
355
+ it('should REJECT on warnings in strict mode', () => {
356
+ const manifest: AgentManifest = {
357
+ agentId: 'test-agent',
358
+ // No trust score - generates warning
359
+ };
360
+
361
+ const normalResult = validateAgent(manifest, undefined, { strict: false });
362
+ const strictResult = validateAgent(manifest, undefined, { strict: true });
363
+
364
+ expect(normalResult.decision).toBe(GateDecision.PASS);
365
+ expect(strictResult.decision).toBe(GateDecision.REJECT);
366
+ });
367
+ });
368
+
369
+ // =============================================================================
370
+ // CUSTOM VALIDATORS
371
+ // =============================================================================
372
+
373
+ describe('custom validators', () => {
374
+ it('should run custom validators', () => {
375
+ const manifest: AgentManifest = {
376
+ agentId: 'test-agent',
377
+ trustScore: 500,
378
+ metadata: { version: '0.0.1' },
379
+ };
380
+
381
+ const customValidator = (m: AgentManifest) => {
382
+ const issues = [];
383
+ if (m.metadata?.version === '0.0.1') {
384
+ issues.push({
385
+ code: 'UNSTABLE_VERSION',
386
+ message: 'Agent is using unstable version',
387
+ severity: ValidationSeverity.WARNING,
388
+ });
389
+ }
390
+ return issues;
391
+ };
392
+
393
+ const result = validateAgent(manifest, undefined, {
394
+ customValidators: [customValidator],
395
+ });
396
+
397
+ expect(result.warnings.some((w) => w.code === 'UNSTABLE_VERSION')).toBe(true);
398
+ });
399
+
400
+ it('should handle custom validator errors gracefully', () => {
401
+ const manifest: AgentManifest = {
402
+ agentId: 'test-agent',
403
+ trustScore: 500,
404
+ };
405
+
406
+ const failingValidator = () => {
407
+ throw new Error('Validator crashed');
408
+ };
409
+
410
+ const result = validateAgent(manifest, undefined, {
411
+ customValidators: [failingValidator],
412
+ });
413
+
414
+ // Should not crash, just add a warning
415
+ expect(result.warnings.some((w) => w.code === 'CUSTOM_VALIDATOR_ERROR')).toBe(true);
416
+ });
417
+ });
418
+
419
+ // =============================================================================
420
+ // HELPER FUNCTIONS
421
+ // =============================================================================
422
+
423
+ describe('isValidAgent', () => {
424
+ it('should return true for valid agent', () => {
425
+ const manifest: AgentManifest = {
426
+ agentId: 'test-agent',
427
+ trustScore: 500,
428
+ };
429
+
430
+ expect(isValidAgent(manifest)).toBe(true);
431
+ });
432
+
433
+ it('should return false for invalid agent', () => {
434
+ const manifest = {} as AgentManifest;
435
+
436
+ expect(isValidAgent(manifest)).toBe(false);
437
+ });
438
+ });
439
+
440
+ describe('createValidationGate', () => {
441
+ it('should create gate with preset options', () => {
442
+ const gate = createValidationGate({
443
+ minimumTrustTier: TrustTier.T3_VERIFIED,
444
+ });
445
+
446
+ const lowTrustManifest: AgentManifest = {
447
+ agentId: 'test-agent',
448
+ trustScore: 100,
449
+ };
450
+
451
+ const result = gate.validate(lowTrustManifest);
452
+ expect(result.decision).toBe(GateDecision.REJECT);
453
+ });
454
+
455
+ it('should allow option overrides', () => {
456
+ const gate = createValidationGate({
457
+ minimumTrustTier: TrustTier.T5_TRUSTED,
458
+ });
459
+
460
+ const manifest: AgentManifest = {
461
+ agentId: 'test-agent',
462
+ trustScore: 700, // T4 (650-799)
463
+ };
464
+
465
+ // With default options, should fail (T4 < T5)
466
+ const result1 = gate.validate(manifest);
467
+ expect(result1.decision).toBe(GateDecision.REJECT);
468
+
469
+ // With override, should pass (T4 >= T3)
470
+ const result2 = gate.validate(manifest, undefined, {
471
+ minimumTrustTier: TrustTier.T3_VERIFIED,
472
+ });
473
+ expect(result2.decision).toBe(GateDecision.PASS);
474
+ });
475
+ });
476
+
477
+ describe('preset gates', () => {
478
+ it('strictValidationGate should reject on warnings', () => {
479
+ const manifest: AgentManifest = {
480
+ agentId: 'test-agent',
481
+ // Missing trustScore generates warning
482
+ };
483
+
484
+ expect(strictValidationGate.isValid(manifest)).toBe(false);
485
+ });
486
+
487
+ it('productionValidationGate should require profile', () => {
488
+ const manifest: AgentManifest = {
489
+ agentId: 'test-agent',
490
+ trustScore: 500,
491
+ };
492
+
493
+ const result = productionValidationGate.validate(manifest);
494
+ expect(result.errors.some((e) => e.code === 'PROFILE_NOT_FOUND')).toBe(true);
495
+ });
496
+ });
497
+
498
+ // =============================================================================
499
+ // ESCALATION
500
+ // =============================================================================
501
+
502
+ describe('escalation', () => {
503
+ it('should ESCALATE when capability escalation allowed and denied caps exist', () => {
504
+ const manifest: AgentManifest = {
505
+ agentId: 'test-agent',
506
+ trustScore: 100, // T0
507
+ requestedCapabilities: ['CAP-AGENT-SPAWN'], // Requires T6
508
+ };
509
+
510
+ const result = validateAgent(manifest, undefined, {
511
+ allowCapabilityEscalation: true,
512
+ });
513
+
514
+ expect(result.decision).toBe(GateDecision.ESCALATE);
515
+ });
516
+
517
+ it('should REJECT when capability escalation not allowed', () => {
518
+ const manifest: AgentManifest = {
519
+ agentId: 'test-agent',
520
+ trustScore: 100,
521
+ requestedCapabilities: ['CAP-AGENT-SPAWN'],
522
+ };
523
+
524
+ const result = validateAgent(manifest, undefined, {
525
+ allowCapabilityEscalation: false,
526
+ });
527
+
528
+ expect(result.decision).toBe(GateDecision.REJECT);
529
+ });
530
+ });
531
+ });