@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,419 @@
1
+ /**
2
+ * Tests for BASIS Validation Gate
3
+ */
4
+ import { describe, it, expect } from 'vitest';
5
+ import { validateAgent, isValidAgent, createValidationGate, strictValidationGate, productionValidationGate, GateDecision, ValidationSeverity, scoreToTier, } from './validation-gate';
6
+ import { TrustTier } from './trust-factors';
7
+ describe('ValidationGate', () => {
8
+ // =============================================================================
9
+ // BASIC VALIDATION TESTS
10
+ // =============================================================================
11
+ describe('validateAgent', () => {
12
+ it('should PASS a valid manifest', () => {
13
+ const manifest = {
14
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
15
+ organization: 'acme-corp',
16
+ agentClass: 'invoice-bot',
17
+ domains: ['A', 'B', 'F'],
18
+ capabilityLevel: 3,
19
+ version: '1.0.0',
20
+ trustScore: 450,
21
+ };
22
+ const result = validateAgent(manifest);
23
+ expect(result.decision).toBe(GateDecision.PASS);
24
+ expect(result.valid).toBe(true);
25
+ expect(result.errors).toHaveLength(0);
26
+ });
27
+ it('should REJECT manifest missing required agentId', () => {
28
+ const manifest = {
29
+ organization: 'acme-corp',
30
+ trustScore: 450,
31
+ };
32
+ const result = validateAgent(manifest);
33
+ expect(result.decision).toBe(GateDecision.REJECT);
34
+ expect(result.valid).toBe(false);
35
+ expect(result.errors.length).toBeGreaterThan(0);
36
+ });
37
+ it('should include timing information', () => {
38
+ const manifest = {
39
+ agentId: 'test-agent',
40
+ trustScore: 500,
41
+ };
42
+ const result = validateAgent(manifest);
43
+ expect(result.validatedAt).toBeInstanceOf(Date);
44
+ expect(result.durationMs).toBeGreaterThanOrEqual(0);
45
+ });
46
+ it('should detect invalid CAR format', () => {
47
+ const manifest = {
48
+ agentId: 'invalid-format:missing-parts@1.0.0',
49
+ trustScore: 500,
50
+ };
51
+ const result = validateAgent(manifest);
52
+ const formatIssue = result.issues.find((i) => i.code === 'INVALID_CAR_FORMAT');
53
+ expect(formatIssue).toBeDefined();
54
+ });
55
+ it('should accept simple ID format with info note', () => {
56
+ const manifest = {
57
+ agentId: 'simple-agent-id',
58
+ trustScore: 500,
59
+ };
60
+ const result = validateAgent(manifest);
61
+ expect(result.valid).toBe(true);
62
+ const infoIssue = result.issues.find((i) => i.code === 'SIMPLE_ID_FORMAT');
63
+ expect(infoIssue).toBeDefined();
64
+ expect(infoIssue?.severity).toBe(ValidationSeverity.INFO);
65
+ });
66
+ });
67
+ // =============================================================================
68
+ // TRUST TIER VALIDATION
69
+ // =============================================================================
70
+ describe('trust tier validation', () => {
71
+ it('should calculate trust tier from score', () => {
72
+ // T0: 0-199
73
+ expect(scoreToTier(0)).toBe(TrustTier.T0_SANDBOX);
74
+ expect(scoreToTier(199)).toBe(TrustTier.T0_SANDBOX);
75
+ // T1: 200-349
76
+ expect(scoreToTier(200)).toBe(TrustTier.T1_OBSERVED);
77
+ expect(scoreToTier(349)).toBe(TrustTier.T1_OBSERVED);
78
+ // T2: 350-500
79
+ expect(scoreToTier(350)).toBe(TrustTier.T2_PROVISIONAL);
80
+ expect(scoreToTier(500)).toBe(TrustTier.T2_PROVISIONAL);
81
+ // T3: 501-649
82
+ expect(scoreToTier(501)).toBe(TrustTier.T3_MONITORED);
83
+ expect(scoreToTier(649)).toBe(TrustTier.T3_MONITORED);
84
+ // T4: 650-799
85
+ expect(scoreToTier(650)).toBe(TrustTier.T4_STANDARD);
86
+ expect(scoreToTier(799)).toBe(TrustTier.T4_STANDARD);
87
+ // T5: 800-875
88
+ expect(scoreToTier(800)).toBe(TrustTier.T5_TRUSTED);
89
+ expect(scoreToTier(875)).toBe(TrustTier.T5_TRUSTED);
90
+ // T6: 876-950
91
+ expect(scoreToTier(876)).toBe(TrustTier.T6_CERTIFIED);
92
+ expect(scoreToTier(950)).toBe(TrustTier.T6_CERTIFIED);
93
+ // T7: 951-1000
94
+ expect(scoreToTier(951)).toBe(TrustTier.T7_AUTONOMOUS);
95
+ expect(scoreToTier(1000)).toBe(TrustTier.T7_AUTONOMOUS);
96
+ });
97
+ it('should REJECT when trust tier is below minimum', () => {
98
+ const manifest = {
99
+ agentId: 'test-agent',
100
+ trustScore: 100, // T0
101
+ };
102
+ const result = validateAgent(manifest, undefined, {
103
+ minimumTrustTier: TrustTier.T3_MONITORED,
104
+ });
105
+ expect(result.decision).toBe(GateDecision.REJECT);
106
+ expect(result.errors.some((e) => e.code === 'INSUFFICIENT_TRUST_TIER')).toBe(true);
107
+ });
108
+ it('should PASS when trust tier meets minimum', () => {
109
+ const manifest = {
110
+ agentId: 'test-agent',
111
+ trustScore: 700, // T4 (650-799)
112
+ };
113
+ const result = validateAgent(manifest, undefined, {
114
+ minimumTrustTier: TrustTier.T3_MONITORED,
115
+ });
116
+ expect(result.decision).toBe(GateDecision.PASS);
117
+ expect(result.trustTier).toBe(TrustTier.T4_STANDARD);
118
+ });
119
+ it('should warn when trust score is missing', () => {
120
+ const manifest = {
121
+ agentId: 'test-agent',
122
+ };
123
+ const result = validateAgent(manifest);
124
+ expect(result.warnings.some((w) => w.code === 'MISSING_TRUST_SCORE')).toBe(true);
125
+ });
126
+ });
127
+ // =============================================================================
128
+ // PROFILE VALIDATION
129
+ // =============================================================================
130
+ describe('profile validation', () => {
131
+ const validProfile = {
132
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
133
+ organization: 'acme-corp',
134
+ agentClass: 'invoice-bot',
135
+ approvedDomains: ['A', 'B', 'F'],
136
+ maxCapabilityLevel: 4,
137
+ approvedCapabilities: ['CAP-READ-PUBLIC', 'CAP-DB-READ', 'CAP-WRITE-APPROVED'],
138
+ trustScore: 500,
139
+ registeredAt: new Date('2024-01-01'),
140
+ };
141
+ it('should PASS when manifest matches profile', () => {
142
+ const manifest = {
143
+ agentId: 'a3i.acme-corp.invoice-bot:ABF-L3@1.0.0',
144
+ organization: 'acme-corp',
145
+ agentClass: 'invoice-bot',
146
+ domains: ['A', 'B'],
147
+ capabilityLevel: 3,
148
+ trustScore: 500,
149
+ };
150
+ const result = validateAgent(manifest, validProfile);
151
+ expect(result.decision).toBe(GateDecision.PASS);
152
+ expect(result.valid).toBe(true);
153
+ });
154
+ it('should REJECT when organization mismatches', () => {
155
+ const manifest = {
156
+ agentId: 'test-agent',
157
+ organization: 'evil-corp',
158
+ trustScore: 500,
159
+ };
160
+ const result = validateAgent(manifest, validProfile);
161
+ expect(result.decision).toBe(GateDecision.REJECT);
162
+ expect(result.errors.some((e) => e.code === 'ORG_MISMATCH')).toBe(true);
163
+ });
164
+ it('should REJECT when capability level exceeds maximum', () => {
165
+ const manifest = {
166
+ agentId: 'test-agent',
167
+ organization: 'acme-corp',
168
+ capabilityLevel: 7, // exceeds profile max of 4
169
+ trustScore: 500,
170
+ };
171
+ const result = validateAgent(manifest, validProfile);
172
+ expect(result.decision).toBe(GateDecision.REJECT);
173
+ expect(result.errors.some((e) => e.code === 'CAPABILITY_LEVEL_EXCEEDED')).toBe(true);
174
+ });
175
+ it('should REJECT unauthorized domains', () => {
176
+ const manifest = {
177
+ agentId: 'test-agent',
178
+ organization: 'acme-corp',
179
+ domains: ['A', 'B', 'S'], // S not approved
180
+ trustScore: 500,
181
+ };
182
+ const result = validateAgent(manifest, validProfile);
183
+ expect(result.decision).toBe(GateDecision.REJECT);
184
+ expect(result.errors.some((e) => e.code === 'UNAUTHORIZED_DOMAINS')).toBe(true);
185
+ });
186
+ it('should warn on unauthorized capabilities', () => {
187
+ const manifest = {
188
+ agentId: 'test-agent',
189
+ organization: 'acme-corp',
190
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-SYSTEM-ADMIN-FULL'], // admin not approved
191
+ trustScore: 500,
192
+ };
193
+ const result = validateAgent(manifest, validProfile);
194
+ expect(result.warnings.some((w) => w.code === 'UNAUTHORIZED_CAPABILITIES')).toBe(true);
195
+ });
196
+ it('should REJECT when profile required but missing', () => {
197
+ const manifest = {
198
+ agentId: 'test-agent',
199
+ trustScore: 500,
200
+ };
201
+ const result = validateAgent(manifest, undefined, {
202
+ requireRegisteredProfile: true,
203
+ });
204
+ expect(result.decision).toBe(GateDecision.REJECT);
205
+ expect(result.errors.some((e) => e.code === 'PROFILE_NOT_FOUND')).toBe(true);
206
+ });
207
+ });
208
+ // =============================================================================
209
+ // CAPABILITY VALIDATION
210
+ // =============================================================================
211
+ describe('capability validation', () => {
212
+ it('should allow capabilities matching trust tier', () => {
213
+ const manifest = {
214
+ agentId: 'test-agent',
215
+ trustScore: 700, // T4_STANDARD (650-799)
216
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-AGENT-COMMUNICATE'],
217
+ };
218
+ const result = validateAgent(manifest);
219
+ expect(result.allowedCapabilities).toContain('CAP-READ-PUBLIC');
220
+ expect(result.allowedCapabilities).toContain('CAP-AGENT-COMMUNICATE');
221
+ expect(result.deniedCapabilities).toBeUndefined();
222
+ });
223
+ it('should deny capabilities above trust tier', () => {
224
+ const manifest = {
225
+ agentId: 'test-agent',
226
+ trustScore: 100, // T0_SANDBOX
227
+ requestedCapabilities: ['CAP-READ-PUBLIC', 'CAP-AGENT-SPAWN'], // spawn requires T6
228
+ };
229
+ const result = validateAgent(manifest);
230
+ expect(result.allowedCapabilities).toContain('CAP-READ-PUBLIC');
231
+ expect(result.deniedCapabilities).toContain('CAP-AGENT-SPAWN');
232
+ });
233
+ it('should provide recommendations for denied capabilities', () => {
234
+ const manifest = {
235
+ agentId: 'test-agent',
236
+ trustScore: 100,
237
+ requestedCapabilities: ['CAP-AGENT-SPAWN'],
238
+ };
239
+ const result = validateAgent(manifest);
240
+ expect(result.recommendations).toBeDefined();
241
+ expect(result.recommendations?.some((r) => r.includes('trust score'))).toBe(true);
242
+ });
243
+ });
244
+ // =============================================================================
245
+ // REQUIRED DOMAINS
246
+ // =============================================================================
247
+ describe('required domains', () => {
248
+ it('should REJECT when required domains are missing', () => {
249
+ const manifest = {
250
+ agentId: 'test-agent',
251
+ domains: ['A', 'B'],
252
+ trustScore: 500,
253
+ };
254
+ const result = validateAgent(manifest, undefined, {
255
+ requiredDomains: ['A', 'F'], // F is missing
256
+ });
257
+ expect(result.decision).toBe(GateDecision.REJECT);
258
+ expect(result.errors.some((e) => e.code === 'MISSING_REQUIRED_DOMAINS')).toBe(true);
259
+ });
260
+ it('should PASS when all required domains present', () => {
261
+ const manifest = {
262
+ agentId: 'test-agent',
263
+ domains: ['A', 'B', 'F'],
264
+ trustScore: 500,
265
+ };
266
+ const result = validateAgent(manifest, undefined, {
267
+ requiredDomains: ['A', 'F'],
268
+ });
269
+ expect(result.decision).toBe(GateDecision.PASS);
270
+ });
271
+ });
272
+ // =============================================================================
273
+ // STRICT MODE
274
+ // =============================================================================
275
+ describe('strict mode', () => {
276
+ it('should REJECT on warnings in strict mode', () => {
277
+ const manifest = {
278
+ agentId: 'test-agent',
279
+ // No trust score - generates warning
280
+ };
281
+ const normalResult = validateAgent(manifest, undefined, { strict: false });
282
+ const strictResult = validateAgent(manifest, undefined, { strict: true });
283
+ expect(normalResult.decision).toBe(GateDecision.PASS);
284
+ expect(strictResult.decision).toBe(GateDecision.REJECT);
285
+ });
286
+ });
287
+ // =============================================================================
288
+ // CUSTOM VALIDATORS
289
+ // =============================================================================
290
+ describe('custom validators', () => {
291
+ it('should run custom validators', () => {
292
+ const manifest = {
293
+ agentId: 'test-agent',
294
+ trustScore: 500,
295
+ metadata: { version: '0.0.1' },
296
+ };
297
+ const customValidator = (m) => {
298
+ const issues = [];
299
+ if (m.metadata?.version === '0.0.1') {
300
+ issues.push({
301
+ code: 'UNSTABLE_VERSION',
302
+ message: 'Agent is using unstable version',
303
+ severity: ValidationSeverity.WARNING,
304
+ });
305
+ }
306
+ return issues;
307
+ };
308
+ const result = validateAgent(manifest, undefined, {
309
+ customValidators: [customValidator],
310
+ });
311
+ expect(result.warnings.some((w) => w.code === 'UNSTABLE_VERSION')).toBe(true);
312
+ });
313
+ it('should handle custom validator errors gracefully', () => {
314
+ const manifest = {
315
+ agentId: 'test-agent',
316
+ trustScore: 500,
317
+ };
318
+ const failingValidator = () => {
319
+ throw new Error('Validator crashed');
320
+ };
321
+ const result = validateAgent(manifest, undefined, {
322
+ customValidators: [failingValidator],
323
+ });
324
+ // Should not crash, just add a warning
325
+ expect(result.warnings.some((w) => w.code === 'CUSTOM_VALIDATOR_ERROR')).toBe(true);
326
+ });
327
+ });
328
+ // =============================================================================
329
+ // HELPER FUNCTIONS
330
+ // =============================================================================
331
+ describe('isValidAgent', () => {
332
+ it('should return true for valid agent', () => {
333
+ const manifest = {
334
+ agentId: 'test-agent',
335
+ trustScore: 500,
336
+ };
337
+ expect(isValidAgent(manifest)).toBe(true);
338
+ });
339
+ it('should return false for invalid agent', () => {
340
+ const manifest = {};
341
+ expect(isValidAgent(manifest)).toBe(false);
342
+ });
343
+ });
344
+ describe('createValidationGate', () => {
345
+ it('should create gate with preset options', () => {
346
+ const gate = createValidationGate({
347
+ minimumTrustTier: TrustTier.T3_MONITORED,
348
+ });
349
+ const lowTrustManifest = {
350
+ agentId: 'test-agent',
351
+ trustScore: 100,
352
+ };
353
+ const result = gate.validate(lowTrustManifest);
354
+ expect(result.decision).toBe(GateDecision.REJECT);
355
+ });
356
+ it('should allow option overrides', () => {
357
+ const gate = createValidationGate({
358
+ minimumTrustTier: TrustTier.T5_TRUSTED,
359
+ });
360
+ const manifest = {
361
+ agentId: 'test-agent',
362
+ trustScore: 700, // T4 (650-799)
363
+ };
364
+ // With default options, should fail (T4 < T5)
365
+ const result1 = gate.validate(manifest);
366
+ expect(result1.decision).toBe(GateDecision.REJECT);
367
+ // With override, should pass (T4 >= T3)
368
+ const result2 = gate.validate(manifest, undefined, {
369
+ minimumTrustTier: TrustTier.T3_MONITORED,
370
+ });
371
+ expect(result2.decision).toBe(GateDecision.PASS);
372
+ });
373
+ });
374
+ describe('preset gates', () => {
375
+ it('strictValidationGate should reject on warnings', () => {
376
+ const manifest = {
377
+ agentId: 'test-agent',
378
+ // Missing trustScore generates warning
379
+ };
380
+ expect(strictValidationGate.isValid(manifest)).toBe(false);
381
+ });
382
+ it('productionValidationGate should require profile', () => {
383
+ const manifest = {
384
+ agentId: 'test-agent',
385
+ trustScore: 500,
386
+ };
387
+ const result = productionValidationGate.validate(manifest);
388
+ expect(result.errors.some((e) => e.code === 'PROFILE_NOT_FOUND')).toBe(true);
389
+ });
390
+ });
391
+ // =============================================================================
392
+ // ESCALATION
393
+ // =============================================================================
394
+ describe('escalation', () => {
395
+ it('should ESCALATE when capability escalation allowed and denied caps exist', () => {
396
+ const manifest = {
397
+ agentId: 'test-agent',
398
+ trustScore: 100, // T0
399
+ requestedCapabilities: ['CAP-AGENT-SPAWN'], // Requires T6
400
+ };
401
+ const result = validateAgent(manifest, undefined, {
402
+ allowCapabilityEscalation: true,
403
+ });
404
+ expect(result.decision).toBe(GateDecision.ESCALATE);
405
+ });
406
+ it('should REJECT when capability escalation not allowed', () => {
407
+ const manifest = {
408
+ agentId: 'test-agent',
409
+ trustScore: 100,
410
+ requestedCapabilities: ['CAP-AGENT-SPAWN'],
411
+ };
412
+ const result = validateAgent(manifest, undefined, {
413
+ allowCapabilityEscalation: false,
414
+ });
415
+ expect(result.decision).toBe(GateDecision.REJECT);
416
+ });
417
+ });
418
+ });
419
+ //# sourceMappingURL=validation-gate.test.js.map
@@ -0,0 +1,55 @@
1
+ import { HardhatUserConfig } from 'hardhat/config';
2
+ import '@nomicfoundation/hardhat-ethers';
3
+ import * as dotenv from 'dotenv';
4
+
5
+ dotenv.config();
6
+
7
+ const config: HardhatUserConfig = {
8
+ solidity: {
9
+ version: '0.8.20',
10
+ settings: {
11
+ optimizer: {
12
+ enabled: true,
13
+ runs: 200,
14
+ },
15
+ },
16
+ },
17
+
18
+ networks: {
19
+ hardhat: {
20
+ chainId: 31337,
21
+ },
22
+
23
+ // Ethereum Sepolia Testnet (uses ETH)
24
+ sepolia: {
25
+ url: process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com',
26
+ accounts: process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.startsWith('0x') && process.env.PRIVATE_KEY.length === 66 ? [process.env.PRIVATE_KEY] : [],
27
+ chainId: 11155111,
28
+ },
29
+
30
+ // Polygon Amoy Testnet
31
+ amoy: {
32
+ url: process.env.AMOY_RPC_URL || 'https://rpc-amoy.polygon.technology',
33
+ accounts: process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.startsWith('0x') && process.env.PRIVATE_KEY.length === 66 ? [process.env.PRIVATE_KEY] : [],
34
+ chainId: 80002,
35
+ gasPrice: 30000000000, // 30 gwei
36
+ },
37
+
38
+ // Polygon Mainnet (uses POL token)
39
+ polygon: {
40
+ url: process.env.POLYGON_RPC_URL || 'https://polygon-rpc.com',
41
+ accounts: process.env.PRIVATE_KEY && process.env.PRIVATE_KEY.startsWith('0x') && process.env.PRIVATE_KEY.length === 66 ? [process.env.PRIVATE_KEY] : [],
42
+ chainId: 137,
43
+ gasPrice: 50000000000, // 50 gwei
44
+ },
45
+ },
46
+
47
+ paths: {
48
+ sources: './contracts',
49
+ tests: './test',
50
+ cache: './cache',
51
+ artifacts: './artifacts',
52
+ },
53
+ };
54
+
55
+ export default config;
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@vorionsys/basis",
3
+ "version": "1.0.1",
4
+ "type": "module",
5
+ "description": "Blockchain Agent Standard for Identity and Security (BASIS) - Open standard for AI agent governance",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public"
9
+ },
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ },
17
+ "./kya": {
18
+ "types": "./dist/kya/index.d.ts",
19
+ "import": "./dist/kya/index.js"
20
+ }
21
+ },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "test:trust": "vitest run src/trust-1000-agents.test.ts",
25
+ "test:trust:watch": "vitest src/trust-1000-agents.test.ts"
26
+ },
27
+ "dependencies": {
28
+ "@noble/ed25519": "^2.0.0",
29
+ "did-resolver": "^4.1.0",
30
+ "zod": "^3.22.4"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.10.6",
34
+ "typescript": "^5.3.3",
35
+ "vitest": "4.0.18"
36
+ },
37
+ "keywords": [
38
+ "vorion",
39
+ "basis",
40
+ "trust",
41
+ "ai",
42
+ "agent",
43
+ "governance",
44
+ "blockchain",
45
+ "identity"
46
+ ],
47
+ "author": "Vorion <team@vorion.org>",
48
+ "repository": {
49
+ "type": "git",
50
+ "url": "https://github.com/voriongit/vorion.git",
51
+ "directory": "packages/basis"
52
+ },
53
+ "homepage": "https://vorion.org",
54
+ "engines": {
55
+ "node": ">=18.0.0"
56
+ }
57
+ }
@@ -0,0 +1,91 @@
1
+ import { ethers } from 'hardhat';
2
+
3
+ /**
4
+ * Certify CC Agent with AgentAnchor (T2: Standard tier, 350 trust score)
5
+ */
6
+ async function main() {
7
+ const [deployer] = await ethers.getSigners();
8
+
9
+ console.log('Certifying agent with account:', deployer.address);
10
+
11
+ // Get deployed AgentCard contract
12
+ const AgentCard = await ethers.getContractFactory('AgentCard');
13
+ const agentCard = await AgentCard.attach(
14
+ process.env.AGENTCARD_ADDRESS || 'REPLACE_WITH_DEPLOYED_ADDRESS'
15
+ );
16
+
17
+ console.log('AgentCard contract:', await agentCard.getAddress());
18
+
19
+ const tokenId = 0; // First minted card (CC Agent)
20
+
21
+ // Check if account has CERTIFIER_ROLE
22
+ const CERTIFIER_ROLE = await agentCard.CERTIFIER_ROLE();
23
+ const hasCertifierRole = await agentCard.hasRole(CERTIFIER_ROLE, deployer.address);
24
+
25
+ if (!hasCertifierRole) {
26
+ console.error('āŒ Account does not have CERTIFIER_ROLE');
27
+ console.log('Granting CERTIFIER_ROLE to:', deployer.address);
28
+
29
+ const grantTx = await agentCard.grantRole(CERTIFIER_ROLE, deployer.address);
30
+ await grantTx.wait();
31
+
32
+ console.log('āœ… CERTIFIER_ROLE granted');
33
+ }
34
+
35
+ // Certify with trust score 350 (T2: Standard)
36
+ const trustScore = 350;
37
+ const expiryTimestamp = Math.floor(Date.now() / 1000) + (365 * 24 * 60 * 60); // 1 year from now
38
+
39
+ console.log('\nCertifying agent:');
40
+ console.log('- Token ID:', tokenId);
41
+ console.log('- Trust Score:', trustScore);
42
+ console.log('- Tier: T2 (Standard)');
43
+ console.log('- Expires:', new Date(expiryTimestamp * 1000).toISOString());
44
+
45
+ const tx = await agentCard.certify(tokenId, trustScore, expiryTimestamp);
46
+
47
+ console.log('Certification transaction submitted:', tx.hash);
48
+ const receipt = await tx.wait();
49
+
50
+ // Get certification event
51
+ const certifyEvent = receipt?.logs?.find(
52
+ (log: any) => log.fragment?.name === 'AgentCertified'
53
+ );
54
+
55
+ if (certifyEvent) {
56
+ console.log('\nāœ… Agent certified successfully!');
57
+ console.log('Token ID:', certifyEvent.args?.tokenId.toString());
58
+ console.log('DID:', certifyEvent.args?.did);
59
+ console.log('Certifier:', certifyEvent.args?.certifier);
60
+ console.log('Trust Score:', certifyEvent.args?.trustScore.toString());
61
+ console.log('Tier:', certifyEvent.args?.tier); // Should be 2 (T2)
62
+ }
63
+
64
+ // Query updated card
65
+ const card = await agentCard.getCard(tokenId);
66
+
67
+ console.log('\nšŸ“‹ Updated AgentCard:');
68
+ console.log('-------------------');
69
+ console.log('DID:', card.did);
70
+ console.log('Name:', card.name);
71
+ console.log('Trust Score:', card.trustScore.toString());
72
+ console.log('Tier:', ['T0', 'T1', 'T2', 'T3', 'T4', 'T5'][card.tier]);
73
+ console.log('Certified:', card.certified);
74
+ console.log('Certifier:', card.certifier);
75
+ console.log('Certification Date:', new Date(Number(card.certificationDate) * 1000).toISOString());
76
+ console.log('Certification Expiry:', new Date(Number(card.certificationExpiry) * 1000).toISOString());
77
+
78
+ // Check if certified and valid
79
+ const isCertified = await agentCard.isCertified(tokenId);
80
+ console.log('\nIs Certified (not expired/revoked):', isCertified);
81
+
82
+ console.log('\nšŸ”— View on PolygonScan:');
83
+ console.log(`https://mumbai.polygonscan.com/token/${await agentCard.getAddress()}?a=${tokenId}`);
84
+ }
85
+
86
+ main()
87
+ .then(() => process.exit(0))
88
+ .catch((error) => {
89
+ console.error(error);
90
+ process.exit(1);
91
+ });
@@ -0,0 +1,63 @@
1
+ import { ethers } from 'hardhat';
2
+
3
+ /**
4
+ * Deploy AgentCard contract to network
5
+ */
6
+ async function main() {
7
+ const [deployer] = await ethers.getSigners();
8
+
9
+ console.log('Deploying AgentCard with account:', deployer.address);
10
+ console.log('Account balance:', ethers.formatEther(await ethers.provider.getBalance(deployer.address)), 'MATIC');
11
+
12
+ // Deploy AgentCard
13
+ const AgentCard = await ethers.getContractFactory('AgentCard');
14
+ const agentCard = await AgentCard.deploy();
15
+
16
+ await agentCard.waitForDeployment();
17
+
18
+ const contractAddress = await agentCard.getAddress();
19
+
20
+ console.log('\nāœ… AgentCard deployed to:', contractAddress);
21
+
22
+ // Grant CERTIFIER_ROLE to deployer (for testing)
23
+ console.log('\nGranting CERTIFIER_ROLE to deployer...');
24
+ const CERTIFIER_ROLE = await agentCard.CERTIFIER_ROLE();
25
+ await agentCard.grantRole(CERTIFIER_ROLE, deployer.address);
26
+
27
+ console.log('āœ… CERTIFIER_ROLE granted');
28
+
29
+ console.log('\nšŸ“‹ Deployment Summary:');
30
+ console.log('=====================');
31
+ console.log('Contract Address:', contractAddress);
32
+ console.log('Deployer:', deployer.address);
33
+ console.log('Network:', (await ethers.provider.getNetwork()).name);
34
+ console.log('Chain ID:', (await ethers.provider.getNetwork()).chainId);
35
+
36
+ console.log('\nšŸ”— View on Block Explorer:');
37
+ const chainId = (await ethers.provider.getNetwork()).chainId;
38
+ if (chainId === 11155111n) {
39
+ console.log(`https://sepolia.etherscan.io/address/${contractAddress}`);
40
+ } else if (chainId === 80002n) {
41
+ console.log(`https://amoy.polygonscan.com/address/${contractAddress}`);
42
+ } else if (chainId === 80001n) {
43
+ console.log(`https://mumbai.polygonscan.com/address/${contractAddress}`);
44
+ console.log('āš ļø WARNING: Mumbai testnet is deprecated. Use Amoy instead!');
45
+ } else if (chainId === 137n) {
46
+ console.log(`https://polygonscan.com/address/${contractAddress}`);
47
+ } else if (chainId === 1n) {
48
+ console.log(`https://etherscan.io/address/${contractAddress}`);
49
+ }
50
+
51
+ console.log('\nšŸ“ Next Steps:');
52
+ console.log('1. Save contract address:', contractAddress);
53
+ console.log('2. Verify contract: npx hardhat verify --network mumbai', contractAddress);
54
+ console.log('3. Mint AgentCard: npx hardhat run scripts/mint-agentcard.ts --network mumbai');
55
+ console.log('4. Certify agent: npx hardhat run scripts/certify-agent.ts --network mumbai');
56
+ }
57
+
58
+ main()
59
+ .then(() => process.exit(0))
60
+ .catch((error) => {
61
+ console.error(error);
62
+ process.exit(1);
63
+ });