@grantex/conformance 0.1.0

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 (98) hide show
  1. package/README.md +115 -0
  2. package/dist/cleanup.d.ts +15 -0
  3. package/dist/cleanup.d.ts.map +1 -0
  4. package/dist/cleanup.js +62 -0
  5. package/dist/cleanup.js.map +1 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.d.ts.map +1 -0
  8. package/dist/cli.js +41 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/flow.d.ts +29 -0
  11. package/dist/flow.d.ts.map +1 -0
  12. package/dist/flow.js +77 -0
  13. package/dist/flow.js.map +1 -0
  14. package/dist/helpers.d.ts +15 -0
  15. package/dist/helpers.d.ts.map +1 -0
  16. package/dist/helpers.js +70 -0
  17. package/dist/helpers.js.map +1 -0
  18. package/dist/http-client.d.ts +15 -0
  19. package/dist/http-client.d.ts.map +1 -0
  20. package/dist/http-client.js +71 -0
  21. package/dist/http-client.js.map +1 -0
  22. package/dist/index.d.ts +3 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +4 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/reporter.d.ts +4 -0
  27. package/dist/reporter.d.ts.map +1 -0
  28. package/dist/reporter.js +72 -0
  29. package/dist/reporter.js.map +1 -0
  30. package/dist/runner.d.ts +3 -0
  31. package/dist/runner.d.ts.map +1 -0
  32. package/dist/runner.js +160 -0
  33. package/dist/runner.js.map +1 -0
  34. package/dist/suites/agents.d.ts +3 -0
  35. package/dist/suites/agents.d.ts.map +1 -0
  36. package/dist/suites/agents.js +53 -0
  37. package/dist/suites/agents.js.map +1 -0
  38. package/dist/suites/anomalies.d.ts +3 -0
  39. package/dist/suites/anomalies.d.ts.map +1 -0
  40. package/dist/suites/anomalies.js +27 -0
  41. package/dist/suites/anomalies.js.map +1 -0
  42. package/dist/suites/audit.d.ts +3 -0
  43. package/dist/suites/audit.d.ts.map +1 -0
  44. package/dist/suites/audit.js +70 -0
  45. package/dist/suites/audit.js.map +1 -0
  46. package/dist/suites/authorize.d.ts +3 -0
  47. package/dist/suites/authorize.d.ts.map +1 -0
  48. package/dist/suites/authorize.js +54 -0
  49. package/dist/suites/authorize.js.map +1 -0
  50. package/dist/suites/compliance.d.ts +3 -0
  51. package/dist/suites/compliance.d.ts.map +1 -0
  52. package/dist/suites/compliance.js +33 -0
  53. package/dist/suites/compliance.js.map +1 -0
  54. package/dist/suites/delegation.d.ts +3 -0
  55. package/dist/suites/delegation.d.ts.map +1 -0
  56. package/dist/suites/delegation.js +120 -0
  57. package/dist/suites/delegation.js.map +1 -0
  58. package/dist/suites/grants.d.ts +3 -0
  59. package/dist/suites/grants.d.ts.map +1 -0
  60. package/dist/suites/grants.js +34 -0
  61. package/dist/suites/grants.js.map +1 -0
  62. package/dist/suites/health.d.ts +3 -0
  63. package/dist/suites/health.d.ts.map +1 -0
  64. package/dist/suites/health.js +30 -0
  65. package/dist/suites/health.js.map +1 -0
  66. package/dist/suites/policies.d.ts +3 -0
  67. package/dist/suites/policies.d.ts.map +1 -0
  68. package/dist/suites/policies.js +51 -0
  69. package/dist/suites/policies.js.map +1 -0
  70. package/dist/suites/scim.d.ts +3 -0
  71. package/dist/suites/scim.d.ts.map +1 -0
  72. package/dist/suites/scim.js +64 -0
  73. package/dist/suites/scim.js.map +1 -0
  74. package/dist/suites/security.d.ts +3 -0
  75. package/dist/suites/security.d.ts.map +1 -0
  76. package/dist/suites/security.js +69 -0
  77. package/dist/suites/security.js.map +1 -0
  78. package/dist/suites/sso.d.ts +3 -0
  79. package/dist/suites/sso.d.ts.map +1 -0
  80. package/dist/suites/sso.js +35 -0
  81. package/dist/suites/sso.js.map +1 -0
  82. package/dist/suites/token.d.ts +3 -0
  83. package/dist/suites/token.d.ts.map +1 -0
  84. package/dist/suites/token.js +61 -0
  85. package/dist/suites/token.js.map +1 -0
  86. package/dist/suites/tokens.d.ts +3 -0
  87. package/dist/suites/tokens.d.ts.map +1 -0
  88. package/dist/suites/tokens.js +43 -0
  89. package/dist/suites/tokens.js.map +1 -0
  90. package/dist/suites/webhooks.d.ts +3 -0
  91. package/dist/suites/webhooks.d.ts.map +1 -0
  92. package/dist/suites/webhooks.js +36 -0
  93. package/dist/suites/webhooks.js.map +1 -0
  94. package/dist/types.d.ts +60 -0
  95. package/dist/types.d.ts.map +1 -0
  96. package/dist/types.js +2 -0
  97. package/dist/types.js.map +1 -0
  98. package/package.json +49 -0
@@ -0,0 +1,120 @@
1
+ import { test, expectStatus, expectKeys, expectString, expectEqual } from '../helpers.js';
2
+ export const delegationSuite = {
3
+ name: 'delegation',
4
+ description: 'Grant delegation and scope enforcement',
5
+ optional: false,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ const { agentId, agentDid } = ctx.sharedAgent;
9
+ // Create parent flow using shared agent
10
+ const parentFlow = await ctx.flow.executeFullFlow({
11
+ agentId,
12
+ agentDid,
13
+ scopes: ['read', 'write'],
14
+ });
15
+ // Use the shared agent as both parent and sub-agent (self-delegation is valid)
16
+ const subAgentId = agentId;
17
+ results.push(await test('POST /v1/grants/delegate returns 201 with grantToken', '§9', async () => {
18
+ const res = await ctx.http.post('/v1/grants/delegate', {
19
+ parentGrantToken: parentFlow.grantToken,
20
+ subAgentId,
21
+ scopes: ['read'],
22
+ });
23
+ expectStatus(res, 201);
24
+ expectKeys(res.body, ['grantToken', 'expiresAt', 'scopes', 'grantId']);
25
+ expectString(res.body.grantToken, 'grantToken');
26
+ ctx.cleanup.trackGrant(res.body.grantId);
27
+ }));
28
+ results.push(await test('Delegated JWT contains parentAgt, parentGrnt, delegationDepth', '§9', async () => {
29
+ const res = await ctx.http.post('/v1/grants/delegate', {
30
+ parentGrantToken: parentFlow.grantToken,
31
+ subAgentId,
32
+ scopes: ['read'],
33
+ });
34
+ expectStatus(res, 201);
35
+ ctx.cleanup.trackGrant(res.body.grantId);
36
+ const parts = res.body.grantToken.split('.');
37
+ const payload = JSON.parse(atob(parts[1]));
38
+ expectString(payload.parentAgt, 'parentAgt');
39
+ expectString(payload.parentGrnt, 'parentGrnt');
40
+ expectEqual(typeof payload.delegationDepth, 'number', 'delegationDepth type');
41
+ expectEqual(payload.delegationDepth, 1, 'delegationDepth');
42
+ }));
43
+ results.push(await test('Delegation rejects scope superset (400)', '§9', async () => {
44
+ const res = await ctx.http.post('/v1/grants/delegate', {
45
+ parentGrantToken: parentFlow.grantToken,
46
+ subAgentId,
47
+ scopes: ['read', 'write', 'admin'],
48
+ });
49
+ expectStatus(res, 400);
50
+ }));
51
+ results.push(await test('Delegation depth limit is enforced', '§9', async () => {
52
+ // Delegate parent → self (depth 1)
53
+ const del1 = await ctx.http.post('/v1/grants/delegate', {
54
+ parentGrantToken: parentFlow.grantToken,
55
+ subAgentId,
56
+ scopes: ['read'],
57
+ });
58
+ expectStatus(del1, 201);
59
+ ctx.cleanup.trackGrant(del1.body.grantId);
60
+ // Delegate depth-1 → self (depth 2)
61
+ const del2 = await ctx.http.post('/v1/grants/delegate', {
62
+ parentGrantToken: del1.body.grantToken,
63
+ subAgentId,
64
+ scopes: ['read'],
65
+ });
66
+ if (del2.status === 201) {
67
+ ctx.cleanup.trackGrant(del2.body.grantId);
68
+ const parts = del2.body.grantToken.split('.');
69
+ const payload = JSON.parse(atob(parts[1]));
70
+ expectEqual(payload.delegationDepth, 2, 'delegationDepth');
71
+ }
72
+ else {
73
+ // Server enforces depth limit — also valid
74
+ expectStatus(del2, 400);
75
+ }
76
+ }));
77
+ results.push(await test('Revoking parent cascades to delegated grants', '§9', async () => {
78
+ // New authorize+token flow using shared agent
79
+ const authRes = await ctx.http.post('/v1/authorize', {
80
+ agentId,
81
+ principalId: `principal-cascade-${Date.now()}`,
82
+ scopes: ['read'],
83
+ });
84
+ expectStatus(authRes, 201);
85
+ let code;
86
+ if (authRes.body.code) {
87
+ code = authRes.body.code;
88
+ }
89
+ else {
90
+ const consentRes = await ctx.http.requestPublic('POST', `/v1/consent/${authRes.body.authRequestId}/approve`);
91
+ if (consentRes.status !== 200) {
92
+ throw new Error(`Consent approve failed: ${consentRes.status} ${consentRes.rawText}`);
93
+ }
94
+ code = consentRes.body.code;
95
+ }
96
+ const tokenRes = await ctx.http.post('/v1/token', { code, agentId });
97
+ expectStatus(tokenRes, 201);
98
+ ctx.cleanup.trackGrant(tokenRes.body.grantId);
99
+ // Delegate to self
100
+ const delRes = await ctx.http.post('/v1/grants/delegate', {
101
+ parentGrantToken: tokenRes.body.grantToken,
102
+ subAgentId,
103
+ scopes: ['read'],
104
+ });
105
+ expectStatus(delRes, 201);
106
+ ctx.cleanup.trackGrant(delRes.body.grantId);
107
+ // Revoke parent grant
108
+ const revokeRes = await ctx.http.delete(`/v1/grants/${tokenRes.body.grantId}`);
109
+ expectStatus(revokeRes, 204);
110
+ // Verify child token is now invalid
111
+ const verifyRes = await ctx.http.post('/v1/tokens/verify', {
112
+ token: delRes.body.grantToken,
113
+ });
114
+ expectStatus(verifyRes, 200);
115
+ expectEqual(verifyRes.body.valid, false, 'valid');
116
+ }));
117
+ return results;
118
+ },
119
+ };
120
+ //# sourceMappingURL=delegation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delegation.js","sourceRoot":"","sources":["../../src/suites/delegation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const grantsSuite: SuiteDefinition;
3
+ //# sourceMappingURL=grants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.d.ts","sourceRoot":"","sources":["../../src/suites/grants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,WAAW,EAAE,eAkDzB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { test, expectStatus, expectKeys, expectArray, expectEqual } from '../helpers.js';
2
+ export const grantsSuite = {
3
+ name: 'grants',
4
+ description: 'Grant listing, retrieval, and revocation',
5
+ optional: false,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ const { agentId, agentDid } = ctx.sharedAgent;
9
+ const flow = await ctx.flow.executeFullFlow({ agentId, agentDid });
10
+ results.push(await test('GET /v1/grants lists grants', '§7.1', async () => {
11
+ const res = await ctx.http.get('/v1/grants');
12
+ expectStatus(res, 200);
13
+ expectKeys(res.body, ['grants']);
14
+ expectArray(res.body.grants, 'grants');
15
+ }));
16
+ results.push(await test('GET /v1/grants/:id returns grant details', '§7.1', async () => {
17
+ const res = await ctx.http.get(`/v1/grants/${flow.grantId}`);
18
+ expectStatus(res, 200);
19
+ expectKeys(res.body, ['grantId', 'agentId', 'scopes', 'status']);
20
+ expectEqual(res.body.grantId, flow.grantId, 'grantId');
21
+ }));
22
+ results.push(await test('DELETE /v1/grants/:id returns 204', '§7.1', async () => {
23
+ const res = await ctx.http.delete(`/v1/grants/${flow.grantId}`);
24
+ expectStatus(res, 204);
25
+ }));
26
+ results.push(await test('Grant status is revoked after DELETE', '§7.1', async () => {
27
+ const res = await ctx.http.get(`/v1/grants/${flow.grantId}`);
28
+ expectStatus(res, 200);
29
+ expectEqual(res.body.status, 'revoked', 'status');
30
+ }));
31
+ return results;
32
+ },
33
+ };
34
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../../src/suites/grants.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEzF,MAAM,CAAC,MAAM,WAAW,GAAoB;IAC1C,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,0CAA0C;IACvD,QAAQ,EAAE,KAAK;IACf,GAAG,EAAE,KAAK,EAAE,GAAiB,EAAyB,EAAE;QACtD,MAAM,OAAO,GAAiB,EAAE,CAAC;QACjC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,GAAG,CAAC,WAAW,CAAC;QAE9C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;QAEnE,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,6BAA6B,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAwB,YAAY,CAAC,CAAC;YACpE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,0CAA0C,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YACxE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAK3B,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACjC,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YACjE,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACzD,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,mCAAmC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YACjE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YAChE,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,sCAAsC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAAqB,cAAc,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;YACjF,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QACpD,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const healthSuite: SuiteDefinition;
3
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/suites/health.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,WAAW,EAAE,eAqCzB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import { test, expectStatus, expectKeys, expectString } from '../helpers.js';
2
+ export const healthSuite = {
3
+ name: 'health',
4
+ description: 'Health check and JWKS endpoints',
5
+ optional: false,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ results.push(await test('GET /health returns 200 with status ok', '§3.3', async () => {
9
+ const res = await ctx.http.requestPublic('GET', '/health');
10
+ expectStatus(res, 200);
11
+ expectKeys(res.body, ['status']);
12
+ expectString(res.body.status, 'status');
13
+ }));
14
+ results.push(await test('JWKS endpoint has RS256 keys', '§10', async () => {
15
+ const res = await ctx.http.requestPublic('GET', '/.well-known/jwks.json');
16
+ expectStatus(res, 200);
17
+ expectKeys(res.body, ['keys']);
18
+ const keys = res.body.keys;
19
+ if (!Array.isArray(keys) || keys.length === 0) {
20
+ throw new Error('JWKS must contain at least one key');
21
+ }
22
+ const rsaKeys = keys.filter((k) => k.kty === 'RSA');
23
+ if (rsaKeys.length === 0) {
24
+ throw new Error('JWKS must contain at least one RSA key');
25
+ }
26
+ }));
27
+ return results;
28
+ },
29
+ };
30
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/suites/health.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,CAAC,MAAM,WAAW,GAAoB;IAC1C,IAAI,EAAE,QAAQ;IACd,WAAW,EAAE,iCAAiC;IAC9C,QAAQ,EAAE,KAAK;IACf,GAAG,EAAE,KAAK,EAAE,GAAiB,EAAyB,EAAE;QACtD,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,wCAAwC,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE;YACtE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CAAqB,KAAK,EAAE,SAAS,CAAC,CAAC;YAC/E,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;YACjC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC1C,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,8BAA8B,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;YAC3D,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CACtC,KAAK,EACL,wBAAwB,CACzB,CAAC;YACF,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;YAC3B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC9C,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;YACxD,CAAC;YACD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,CAAC;YACpD,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;YAC5D,CAAC;QACH,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const policiesSuite: SuiteDefinition;
3
+ //# sourceMappingURL=policies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policies.d.ts","sourceRoot":"","sources":["../../src/suites/policies.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,aAAa,EAAE,eAsE3B,CAAC"}
@@ -0,0 +1,51 @@
1
+ import { test, expectStatus, expectKeys, expectString, expectArray, expectEqual } from '../helpers.js';
2
+ export const policiesSuite = {
3
+ name: 'policies',
4
+ description: 'Policy CRUD and enforcement',
5
+ optional: true,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ let policyId = '';
9
+ results.push(await test('POST /v1/policies creates policy (201)', '§12', async () => {
10
+ const res = await ctx.http.post('/v1/policies', {
11
+ name: `conformance-policy-${Date.now()}`,
12
+ effect: 'allow',
13
+ scopes: ['read'],
14
+ });
15
+ expectStatus(res, 201);
16
+ expectKeys(res.body, ['id', 'name', 'effect']);
17
+ expectString(res.body.id, 'id');
18
+ policyId = res.body.id;
19
+ ctx.cleanup.trackPolicy(policyId);
20
+ }));
21
+ results.push(await test('GET /v1/policies lists policies', '§12', async () => {
22
+ const res = await ctx.http.get('/v1/policies');
23
+ expectStatus(res, 200);
24
+ expectKeys(res.body, ['policies']);
25
+ expectArray(res.body.policies, 'policies');
26
+ }));
27
+ results.push(await test('GET /v1/policies/:id returns policy details', '§12', async () => {
28
+ if (!policyId)
29
+ throw new Error('No policy created');
30
+ const res = await ctx.http.get(`/v1/policies/${policyId}`);
31
+ expectStatus(res, 200);
32
+ expectKeys(res.body, ['id', 'name', 'effect']);
33
+ expectEqual(res.body.id, policyId, 'id');
34
+ }));
35
+ results.push(await test('PATCH /v1/policies/:id updates policy', '§12', async () => {
36
+ if (!policyId)
37
+ throw new Error('No policy created');
38
+ const res = await ctx.http.patch(`/v1/policies/${policyId}`, { effect: 'deny' });
39
+ expectStatus(res, 200);
40
+ expectEqual(res.body.effect, 'deny', 'effect');
41
+ }));
42
+ results.push(await test('DELETE /v1/policies/:id returns 204', '§12', async () => {
43
+ if (!policyId)
44
+ throw new Error('No policy created');
45
+ const res = await ctx.http.delete(`/v1/policies/${policyId}`);
46
+ expectStatus(res, 204);
47
+ }));
48
+ return results;
49
+ },
50
+ };
51
+ //# sourceMappingURL=policies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policies.js","sourceRoot":"","sources":["../../src/suites/policies.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const scimSuite: SuiteDefinition;
3
+ //# sourceMappingURL=scim.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scim.d.ts","sourceRoot":"","sources":["../../src/suites/scim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,SAAS,EAAE,eAiGvB,CAAC"}
@@ -0,0 +1,64 @@
1
+ import { test, expectStatus, expectKeys, expectString, expectArray } from '../helpers.js';
2
+ export const scimSuite = {
3
+ name: 'scim',
4
+ description: 'SCIM 2.0 provisioning endpoints',
5
+ optional: true,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ let scimToken = '';
9
+ let scimTokenId = '';
10
+ let userId = '';
11
+ results.push(await test('POST /v1/scim/tokens creates SCIM token (201)', '§13', async () => {
12
+ const res = await ctx.http.post('/v1/scim/tokens', {
13
+ label: `conformance-scim-${Date.now()}`,
14
+ });
15
+ expectStatus(res, 201);
16
+ expectKeys(res.body, ['id', 'label', 'token']);
17
+ expectString(res.body.token, 'token');
18
+ scimToken = res.body.token;
19
+ scimTokenId = res.body.id;
20
+ }));
21
+ results.push(await test('GET /v1/scim/tokens lists SCIM tokens', '§13', async () => {
22
+ const res = await ctx.http.get('/v1/scim/tokens');
23
+ expectStatus(res, 200);
24
+ expectKeys(res.body, ['tokens']);
25
+ expectArray(res.body.tokens, 'tokens');
26
+ }));
27
+ results.push(await test('GET /scim/v2/ServiceProviderConfig returns config', '§13', async () => {
28
+ const res = await ctx.http.requestPublic('GET', '/scim/v2/ServiceProviderConfig');
29
+ expectStatus(res, 200);
30
+ expectKeys(res.body, ['schemas']);
31
+ }));
32
+ results.push(await test('POST /scim/v2/Users creates user (201)', '§13', async () => {
33
+ if (!scimToken)
34
+ throw new Error('No SCIM token created');
35
+ const res = await ctx.http.doRequestWithToken('POST', '/scim/v2/Users', scimToken, {
36
+ userName: `conformance-user-${Date.now()}@example.com`,
37
+ displayName: 'Conformance Test User',
38
+ });
39
+ expectStatus(res, 201);
40
+ expectKeys(res.body, ['id', 'userName', 'schemas']);
41
+ expectString(res.body.id, 'id');
42
+ userId = res.body.id;
43
+ }));
44
+ results.push(await test('GET /scim/v2/Users lists users', '§13', async () => {
45
+ if (!scimToken)
46
+ throw new Error('No SCIM token created');
47
+ const res = await ctx.http.doRequestWithToken('GET', '/scim/v2/Users', scimToken);
48
+ expectStatus(res, 200);
49
+ expectKeys(res.body, ['Resources', 'totalResults']);
50
+ }));
51
+ results.push(await test('DELETE /scim/v2/Users/:id returns 204', '§13', async () => {
52
+ if (!scimToken || !userId)
53
+ throw new Error('No SCIM user created');
54
+ const res = await ctx.http.doRequestWithToken('DELETE', `/scim/v2/Users/${userId}`, scimToken);
55
+ expectStatus(res, 204);
56
+ // Clean up SCIM token
57
+ if (scimTokenId) {
58
+ await ctx.http.delete(`/v1/scim/tokens/${scimTokenId}`);
59
+ }
60
+ }));
61
+ return results;
62
+ },
63
+ };
64
+ //# sourceMappingURL=scim.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scim.js","sourceRoot":"","sources":["../../src/suites/scim.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const securitySuite: SuiteDefinition;
3
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/suites/security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAI7E,eAAO,MAAM,aAAa,EAAE,eA0F3B,CAAC"}
@@ -0,0 +1,69 @@
1
+ import { test, expectStatus } from '../helpers.js';
2
+ import { ConformanceHttpClient } from '../http-client.js';
3
+ export const securitySuite = {
4
+ name: 'security',
5
+ description: 'Authentication, authorization, and security enforcement',
6
+ optional: false,
7
+ run: async (ctx) => {
8
+ const results = [];
9
+ const { agentId, agentDid } = ctx.sharedAgent;
10
+ results.push(await test('Request without auth returns 401', '§14', async () => {
11
+ const res = await ctx.http.requestPublic('GET', '/v1/agents');
12
+ expectStatus(res, 401);
13
+ }));
14
+ results.push(await test('Request with bad auth returns 401', '§14', async () => {
15
+ const client = new ConformanceHttpClient(ctx.baseUrl, 'invalid-api-key-12345');
16
+ const res = await client.get('/v1/agents');
17
+ expectStatus(res, 401);
18
+ }));
19
+ results.push(await test('JWKS only contains RS256 keys', '§14', async () => {
20
+ const res = await ctx.http.requestPublic('GET', '/.well-known/jwks.json');
21
+ expectStatus(res, 200);
22
+ for (const key of res.body.keys) {
23
+ if (key.alg && key.alg !== 'RS256') {
24
+ throw new Error(`Expected RS256 algorithm, found: ${key.alg}`);
25
+ }
26
+ if (key.kty !== 'RSA') {
27
+ throw new Error(`Expected RSA key type, found: ${key.kty}`);
28
+ }
29
+ }
30
+ }));
31
+ // Use shared agent — get a grant with limited scopes
32
+ const flow = await ctx.flow.executeFullFlow({
33
+ agentId,
34
+ agentDid,
35
+ scopes: ['read'],
36
+ });
37
+ results.push(await test('Delegation scope enforcement prevents escalation', '§14', async () => {
38
+ // Try to delegate with scopes the parent doesn't have
39
+ const delRes = await ctx.http.post('/v1/grants/delegate', {
40
+ parentGrantToken: flow.grantToken,
41
+ subAgentId: agentId,
42
+ scopes: ['read', 'write'],
43
+ });
44
+ expectStatus(delRes, 400);
45
+ }));
46
+ results.push(await test('Audit log is append-only (PUT/DELETE return 404 or 405)', '§14', async () => {
47
+ const logRes = await ctx.http.post('/v1/audit/log', {
48
+ agentId: flow.agentId,
49
+ agentDid: flow.agentDid,
50
+ grantId: flow.grantId,
51
+ principalId: flow.principalId,
52
+ action: 'conformance.security.test',
53
+ });
54
+ expectStatus(logRes, 201);
55
+ const putRes = await ctx.http.request('PUT', `/v1/audit/${logRes.body.entryId}`, {
56
+ action: 'modified',
57
+ });
58
+ if (putRes.status !== 404 && putRes.status !== 405) {
59
+ throw new Error(`Expected 404 or 405 for PUT /v1/audit/:id, got ${putRes.status}`);
60
+ }
61
+ const deleteRes = await ctx.http.delete(`/v1/audit/${logRes.body.entryId}`);
62
+ if (deleteRes.status !== 404 && deleteRes.status !== 405) {
63
+ throw new Error(`Expected 404 or 405 for DELETE /v1/audit/:id, got ${deleteRes.status}`);
64
+ }
65
+ }));
66
+ return results;
67
+ },
68
+ };
69
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/suites/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const ssoSuite: SuiteDefinition;
3
+ //# sourceMappingURL=sso.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso.d.ts","sourceRoot":"","sources":["../../src/suites/sso.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,QAAQ,EAAE,eAoDtB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { test, expectStatus, expectKeys, expectString } from '../helpers.js';
2
+ export const ssoSuite = {
3
+ name: 'sso',
4
+ description: 'SSO configuration and flow',
5
+ optional: true,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ results.push(await test('POST /v1/sso/config creates SSO config (201)', '§13', async () => {
9
+ const res = await ctx.http.post('/v1/sso/config', {
10
+ issuerUrl: 'https://accounts.google.com',
11
+ clientId: 'conformance-test-client',
12
+ clientSecret: 'conformance-test-secret',
13
+ redirectUri: 'https://example.com/sso/callback',
14
+ });
15
+ expectStatus(res, 201);
16
+ expectKeys(res.body, ['issuerUrl', 'clientId', 'redirectUri']);
17
+ }));
18
+ results.push(await test('GET /v1/sso/config returns SSO config', '§13', async () => {
19
+ const res = await ctx.http.get('/v1/sso/config');
20
+ expectStatus(res, 200);
21
+ expectKeys(res.body, ['issuerUrl', 'clientId', 'redirectUri']);
22
+ expectString(res.body.issuerUrl, 'issuerUrl');
23
+ }));
24
+ results.push(await test('GET /sso/login requires org parameter', '§13', async () => {
25
+ const res = await ctx.http.requestPublic('GET', '/sso/login');
26
+ expectStatus(res, 400);
27
+ }));
28
+ results.push(await test('DELETE /v1/sso/config returns 204', '§13', async () => {
29
+ const res = await ctx.http.delete('/v1/sso/config');
30
+ expectStatus(res, 204);
31
+ }));
32
+ return results;
33
+ },
34
+ };
35
+ //# sourceMappingURL=sso.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sso.js","sourceRoot":"","sources":["../../src/suites/sso.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,CAAC,MAAM,QAAQ,GAAoB;IACvC,IAAI,EAAE,KAAK;IACX,WAAW,EAAE,4BAA4B;IACzC,QAAQ,EAAE,IAAI;IACd,GAAG,EAAE,KAAK,EAAE,GAAiB,EAAyB,EAAE;QACtD,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,8CAA8C,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;YAC3E,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAI5B,gBAAgB,EAAE;gBACnB,SAAS,EAAE,6BAA6B;gBACxC,QAAQ,EAAE,yBAAyB;gBACnC,YAAY,EAAE,yBAAyB;gBACvC,WAAW,EAAE,kCAAkC;aAChD,CAAC,CAAC;YACH,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;QACjE,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,uCAAuC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,GAAG,CAG3B,gBAAgB,CAAC,CAAC;YACrB,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YACvB,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC;YAC/D,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAChD,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,uCAAuC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;YACpE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;YAC9D,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,CAAC,IAAI,CACV,MAAM,IAAI,CAAC,mCAAmC,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE;YAChE,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC;YACpD,YAAY,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACzB,CAAC,CAAC,CACH,CAAC;QAEF,OAAO,OAAO,CAAC;IACjB,CAAC;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const tokenSuite: SuiteDefinition;
3
+ //# sourceMappingURL=token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/suites/token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,UAAU,EAAE,eAgFxB,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { test, expectStatus, expectString, expectArray, expectIsoDate } from '../helpers.js';
2
+ export const tokenSuite = {
3
+ name: 'token',
4
+ description: 'Token exchange (code → grant token)',
5
+ optional: false,
6
+ run: async (ctx) => {
7
+ const results = [];
8
+ const { agentId, agentDid } = ctx.sharedAgent;
9
+ results.push(await test('POST /v1/token exchanges code for grantToken, refreshToken, grantId, scopes, expiresAt', '§5.3', async () => {
10
+ const flow = await ctx.flow.executeFullFlow({
11
+ agentId,
12
+ agentDid,
13
+ scopes: ['read', 'write'],
14
+ });
15
+ expectString(flow.grantToken, 'grantToken');
16
+ expectString(flow.refreshToken, 'refreshToken');
17
+ expectString(flow.grantId, 'grantId');
18
+ expectArray(flow.scopes, 'scopes');
19
+ expectIsoDate(flow.expiresAt, 'expiresAt');
20
+ }));
21
+ results.push(await test('POST /v1/token rejects invalid code (400)', '§5.3', async () => {
22
+ const res = await ctx.http.post('/v1/token', {
23
+ code: 'invalid-code-12345',
24
+ agentId,
25
+ });
26
+ expectStatus(res, 400);
27
+ }));
28
+ results.push(await test('POST /v1/token rejects reused code (400)', '§5.3', async () => {
29
+ // Authorize to get a code
30
+ const authRes = await ctx.http.post('/v1/authorize', {
31
+ agentId,
32
+ principalId: `principal-reuse-${Date.now()}`,
33
+ scopes: ['read'],
34
+ });
35
+ expectStatus(authRes, 201);
36
+ let code;
37
+ if (authRes.body.code) {
38
+ code = authRes.body.code;
39
+ }
40
+ else {
41
+ const consentRes = await ctx.http.requestPublic('POST', `/v1/consent/${authRes.body.authRequestId}/approve`);
42
+ code = consentRes.body.code;
43
+ }
44
+ // First exchange — should succeed
45
+ const first = await ctx.http.post('/v1/token', {
46
+ code,
47
+ agentId,
48
+ });
49
+ expectStatus(first, 201);
50
+ ctx.cleanup.trackGrant(first.body.grantId);
51
+ // Second exchange with same code — should fail
52
+ const second = await ctx.http.post('/v1/token', {
53
+ code,
54
+ agentId,
55
+ });
56
+ expectStatus(second, 400);
57
+ }));
58
+ return results;
59
+ },
60
+ };
61
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/suites/token.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { SuiteDefinition } from '../types.js';
2
+ export declare const tokensSuite: SuiteDefinition;
3
+ //# sourceMappingURL=tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../../src/suites/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAA4B,MAAM,aAAa,CAAC;AAG7E,eAAO,MAAM,WAAW,EAAE,eAiEzB,CAAC"}