@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.
- package/README.md +115 -0
- package/dist/cleanup.d.ts +15 -0
- package/dist/cleanup.d.ts.map +1 -0
- package/dist/cleanup.js +62 -0
- package/dist/cleanup.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +41 -0
- package/dist/cli.js.map +1 -0
- package/dist/flow.d.ts +29 -0
- package/dist/flow.d.ts.map +1 -0
- package/dist/flow.js +77 -0
- package/dist/flow.js.map +1 -0
- package/dist/helpers.d.ts +15 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +70 -0
- package/dist/helpers.js.map +1 -0
- package/dist/http-client.d.ts +15 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +71 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/reporter.d.ts +4 -0
- package/dist/reporter.d.ts.map +1 -0
- package/dist/reporter.js +72 -0
- package/dist/reporter.js.map +1 -0
- package/dist/runner.d.ts +3 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +160 -0
- package/dist/runner.js.map +1 -0
- package/dist/suites/agents.d.ts +3 -0
- package/dist/suites/agents.d.ts.map +1 -0
- package/dist/suites/agents.js +53 -0
- package/dist/suites/agents.js.map +1 -0
- package/dist/suites/anomalies.d.ts +3 -0
- package/dist/suites/anomalies.d.ts.map +1 -0
- package/dist/suites/anomalies.js +27 -0
- package/dist/suites/anomalies.js.map +1 -0
- package/dist/suites/audit.d.ts +3 -0
- package/dist/suites/audit.d.ts.map +1 -0
- package/dist/suites/audit.js +70 -0
- package/dist/suites/audit.js.map +1 -0
- package/dist/suites/authorize.d.ts +3 -0
- package/dist/suites/authorize.d.ts.map +1 -0
- package/dist/suites/authorize.js +54 -0
- package/dist/suites/authorize.js.map +1 -0
- package/dist/suites/compliance.d.ts +3 -0
- package/dist/suites/compliance.d.ts.map +1 -0
- package/dist/suites/compliance.js +33 -0
- package/dist/suites/compliance.js.map +1 -0
- package/dist/suites/delegation.d.ts +3 -0
- package/dist/suites/delegation.d.ts.map +1 -0
- package/dist/suites/delegation.js +120 -0
- package/dist/suites/delegation.js.map +1 -0
- package/dist/suites/grants.d.ts +3 -0
- package/dist/suites/grants.d.ts.map +1 -0
- package/dist/suites/grants.js +34 -0
- package/dist/suites/grants.js.map +1 -0
- package/dist/suites/health.d.ts +3 -0
- package/dist/suites/health.d.ts.map +1 -0
- package/dist/suites/health.js +30 -0
- package/dist/suites/health.js.map +1 -0
- package/dist/suites/policies.d.ts +3 -0
- package/dist/suites/policies.d.ts.map +1 -0
- package/dist/suites/policies.js +51 -0
- package/dist/suites/policies.js.map +1 -0
- package/dist/suites/scim.d.ts +3 -0
- package/dist/suites/scim.d.ts.map +1 -0
- package/dist/suites/scim.js +64 -0
- package/dist/suites/scim.js.map +1 -0
- package/dist/suites/security.d.ts +3 -0
- package/dist/suites/security.d.ts.map +1 -0
- package/dist/suites/security.js +69 -0
- package/dist/suites/security.js.map +1 -0
- package/dist/suites/sso.d.ts +3 -0
- package/dist/suites/sso.d.ts.map +1 -0
- package/dist/suites/sso.js +35 -0
- package/dist/suites/sso.js.map +1 -0
- package/dist/suites/token.d.ts +3 -0
- package/dist/suites/token.d.ts.map +1 -0
- package/dist/suites/token.js +61 -0
- package/dist/suites/token.js.map +1 -0
- package/dist/suites/tokens.d.ts +3 -0
- package/dist/suites/tokens.d.ts.map +1 -0
- package/dist/suites/tokens.js +43 -0
- package/dist/suites/tokens.js.map +1 -0
- package/dist/suites/webhooks.d.ts +3 -0
- package/dist/suites/webhooks.d.ts.map +1 -0
- package/dist/suites/webhooks.js +36 -0
- package/dist/suites/webhooks.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|