@nacre.work/api 0.0.0 → 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/LICENSE +202 -0
- package/NOTICE +9 -0
- package/dist/adapters.d.ts +326 -15
- package/dist/adapters.d.ts.map +1 -1
- package/dist/adapters.js +992 -52
- package/dist/adapters.js.map +1 -1
- package/dist/audit-export.d.ts +45 -0
- package/dist/audit-export.d.ts.map +1 -0
- package/dist/audit-export.js +155 -0
- package/dist/audit-export.js.map +1 -0
- package/dist/auth.d.ts +17 -0
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +17 -7
- package/dist/auth.js.map +1 -1
- package/dist/idempotency.d.ts +62 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +147 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +11 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +9 -0
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +50 -5
- package/dist/init.js.map +1 -1
- package/dist/limits.d.ts +80 -0
- package/dist/limits.d.ts.map +1 -0
- package/dist/limits.js +63 -0
- package/dist/limits.js.map +1 -0
- package/dist/login.d.ts +94 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +283 -0
- package/dist/login.js.map +1 -0
- package/dist/main.js +136 -53
- package/dist/main.js.map +1 -1
- package/dist/pagination.d.ts +72 -0
- package/dist/pagination.d.ts.map +1 -0
- package/dist/pagination.js +110 -0
- package/dist/pagination.js.map +1 -0
- package/dist/rerank.d.ts +99 -0
- package/dist/rerank.d.ts.map +1 -0
- package/dist/rerank.js +138 -0
- package/dist/rerank.js.map +1 -0
- package/dist/server.d.ts +345 -6
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1035 -24
- package/dist/server.js.map +1 -1
- package/dist/service-keys.d.ts +13 -5
- package/dist/service-keys.d.ts.map +1 -1
- package/dist/service-keys.js +54 -31
- package/dist/service-keys.js.map +1 -1
- package/dist/source.d.ts +53 -0
- package/dist/source.d.ts.map +1 -0
- package/dist/source.js +109 -0
- package/dist/source.js.map +1 -0
- package/package.json +28 -10
- package/dist/__tests__/admin-surface.test.d.ts +0 -2
- package/dist/__tests__/admin-surface.test.d.ts.map +0 -1
- package/dist/__tests__/admin-surface.test.js +0 -431
- package/dist/__tests__/admin-surface.test.js.map +0 -1
- package/dist/__tests__/init.test.d.ts +0 -2
- package/dist/__tests__/init.test.d.ts.map +0 -1
- package/dist/__tests__/init.test.js +0 -125
- package/dist/__tests__/init.test.js.map +0 -1
- package/dist/__tests__/service-keys.test.d.ts +0 -2
- package/dist/__tests__/service-keys.test.d.ts.map +0 -1
- package/dist/__tests__/service-keys.test.js +0 -204
- package/dist/__tests__/service-keys.test.js.map +0 -1
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
import { createPool } from '@nacre.work/core';
|
|
2
|
-
import { afterAll, beforeAll, describe, expect, it } from 'vitest';
|
|
3
|
-
import { authenticate } from '../auth.js';
|
|
4
|
-
import { Problem } from '../errors.js';
|
|
5
|
-
import { generateKey, hashOf, KEY_PREFIX, looksLikeServiceKey, PostgresServiceAccounts, PostgresServiceKeys, prefixOf, } from '../service-keys.js';
|
|
6
|
-
/**
|
|
7
|
-
* Service account keys.
|
|
8
|
-
*
|
|
9
|
-
* The one credential meant to outlive a session, and therefore the one whose
|
|
10
|
-
* failures are worth being paranoid about: a key that survives revocation, a
|
|
11
|
-
* key that authenticates into the wrong organization, or a key recoverable from
|
|
12
|
-
* the database are each worse than anything the token path can do, because a
|
|
13
|
-
* token expires on its own and this does not.
|
|
14
|
-
*/
|
|
15
|
-
const url = process.env.NACRE_PG_URL;
|
|
16
|
-
if (!url && process.env.CI) {
|
|
17
|
-
throw new Error('NACRE_PG_URL is not set and CI is; the service key path would go untested.');
|
|
18
|
-
}
|
|
19
|
-
const when = url ? describe : describe.skip;
|
|
20
|
-
const ORG = 'cccccccc-cccc-cccc-cccc-cccccccccccc';
|
|
21
|
-
const OTHER = 'dddddddd-dddd-dddd-dddd-dddddddddddd';
|
|
22
|
-
const admin = { orgId: ORG, principal: { type: 'user', id: 'u1' }, role: 'org_admin' };
|
|
23
|
-
let pool;
|
|
24
|
-
let accounts;
|
|
25
|
-
let keys;
|
|
26
|
-
describe('key shape', () => {
|
|
27
|
-
it('a key is opaque, prefixed, and not a UUID', () => {
|
|
28
|
-
const key = generateKey();
|
|
29
|
-
expect(key.startsWith(KEY_PREFIX)).toBe(true);
|
|
30
|
-
expect(looksLikeServiceKey(key)).toBe(true);
|
|
31
|
-
// 32 bytes from the CSPRNG. A UUID is 122 bits of which several are fixed,
|
|
32
|
-
// and it is routinely treated as an identifier rather than a secret.
|
|
33
|
-
expect(key.length).toBeGreaterThan(KEY_PREFIX.length + 40);
|
|
34
|
-
});
|
|
35
|
-
it('two keys never collide', () => {
|
|
36
|
-
const many = new Set(Array.from({ length: 500 }, () => generateKey()));
|
|
37
|
-
expect(many.size).toBe(500);
|
|
38
|
-
});
|
|
39
|
-
it('the stored prefix is not enough to reconstruct the key', () => {
|
|
40
|
-
const key = generateKey();
|
|
41
|
-
expect(prefixOf(key).length).toBe(KEY_PREFIX.length + 8);
|
|
42
|
-
expect(key.startsWith(prefixOf(key))).toBe(true);
|
|
43
|
-
expect(prefixOf(key).length).toBeLessThan(key.length / 2);
|
|
44
|
-
});
|
|
45
|
-
it('the hash is not the key', () => {
|
|
46
|
-
const key = generateKey();
|
|
47
|
-
expect(hashOf(key)).not.toContain(key.slice(KEY_PREFIX.length));
|
|
48
|
-
expect(hashOf(key)).toBe(hashOf(key));
|
|
49
|
-
expect(hashOf(key)).not.toBe(hashOf(generateKey()));
|
|
50
|
-
});
|
|
51
|
-
});
|
|
52
|
-
when('service accounts, against the database', () => {
|
|
53
|
-
beforeAll(async () => {
|
|
54
|
-
pool = createPool({ connectionString: url });
|
|
55
|
-
accounts = new PostgresServiceAccounts(pool, 'nacre_app');
|
|
56
|
-
keys = new PostgresServiceKeys(pool, 'nacre_app');
|
|
57
|
-
const c = await pool.connect();
|
|
58
|
-
try {
|
|
59
|
-
for (const [id, slug] of [
|
|
60
|
-
[ORG, 'keysone'],
|
|
61
|
-
[OTHER, 'keystwo'],
|
|
62
|
-
]) {
|
|
63
|
-
await c.query(
|
|
64
|
-
// slug is citext and name is text; one parameter cannot feed both.
|
|
65
|
-
`INSERT INTO organizations (id, slug, name, vector_collection)
|
|
66
|
-
VALUES ($1,$2,$3,$4) ON CONFLICT DO NOTHING`, [id, slug, slug, `org_${slug}`]);
|
|
67
|
-
}
|
|
68
|
-
await c.query(`DELETE FROM service_accounts WHERE org_id IN ($1,$2)`, [ORG, OTHER]);
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
c.release();
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
afterAll(async () => {
|
|
75
|
-
await pool?.end();
|
|
76
|
-
});
|
|
77
|
-
it('a new key authenticates as its own organization, as a member', async () => {
|
|
78
|
-
const { key, account } = await accounts.create(admin, 'agent');
|
|
79
|
-
const resolved = await keys.resolve(key);
|
|
80
|
-
expect(resolved?.orgId).toBe(ORG);
|
|
81
|
-
expect(resolved?.principal).toEqual({ type: 'service_account', id: account.id });
|
|
82
|
-
// Never an admin by virtue of being a service account. Everything it can
|
|
83
|
-
// reach comes from a grant — which is what "permissions are exactly the
|
|
84
|
-
// service account's" has to mean if it means anything.
|
|
85
|
-
expect(resolved?.role).toBe('member');
|
|
86
|
-
});
|
|
87
|
-
it('the key is never readable again', async () => {
|
|
88
|
-
const { key, account } = await accounts.create(admin, 'agent-2');
|
|
89
|
-
const listed = (await accounts.list(admin)).find((a) => a.id === account.id);
|
|
90
|
-
expect(listed).toBeDefined();
|
|
91
|
-
expect(JSON.stringify(listed)).not.toContain(key.slice(KEY_PREFIX.length));
|
|
92
|
-
// The prefix is shown so two keys can be told apart when revoking one.
|
|
93
|
-
expect(listed?.keyPrefix).toBe(prefixOf(key));
|
|
94
|
-
});
|
|
95
|
-
it('a revoked key stops working immediately', async () => {
|
|
96
|
-
const { key, account } = await accounts.create(admin, 'agent-3');
|
|
97
|
-
expect(await keys.resolve(key)).toBeDefined();
|
|
98
|
-
expect(await accounts.revoke(admin, account.id)).toBe(true);
|
|
99
|
-
// No TTL, no propagation window, nothing to wait for. Unlike a token, this
|
|
100
|
-
// credential has no expiry of its own, so revocation is the only thing that
|
|
101
|
-
// ever ends it.
|
|
102
|
-
expect(await keys.resolve(key)).toBeUndefined();
|
|
103
|
-
});
|
|
104
|
-
it('revoking twice is not an error the second time, it is a no', async () => {
|
|
105
|
-
const { account } = await accounts.create(admin, 'agent-4');
|
|
106
|
-
expect(await accounts.revoke(admin, account.id)).toBe(true);
|
|
107
|
-
expect(await accounts.revoke(admin, account.id)).toBe(false);
|
|
108
|
-
});
|
|
109
|
-
it('a revoked key is still listed, and says when', async () => {
|
|
110
|
-
const { account } = await accounts.create(admin, 'agent-5');
|
|
111
|
-
await accounts.revoke(admin, account.id);
|
|
112
|
-
const listed = (await accounts.list(admin)).find((a) => a.id === account.id);
|
|
113
|
-
// A key that vanishes on revocation looks like one that never existed, and
|
|
114
|
-
// the audit log refers to this id — a row that disappears turns every past
|
|
115
|
-
// event into an unresolvable reference.
|
|
116
|
-
expect(listed?.revokedAt).not.toBeNull();
|
|
117
|
-
});
|
|
118
|
-
it('another organization cannot revoke this one’s key', async () => {
|
|
119
|
-
const { key, account } = await accounts.create(admin, 'agent-6');
|
|
120
|
-
const intruder = { ...admin, orgId: OTHER };
|
|
121
|
-
expect(await accounts.revoke(intruder, account.id)).toBe(false);
|
|
122
|
-
expect(await keys.resolve(key), 'the key must still work').toBeDefined();
|
|
123
|
-
});
|
|
124
|
-
it('another organization does not see this one’s keys', async () => {
|
|
125
|
-
await accounts.create(admin, 'agent-7');
|
|
126
|
-
const theirs = await accounts.list({ ...admin, orgId: OTHER });
|
|
127
|
-
expect(theirs.every((a) => a.name !== 'agent-7')).toBe(true);
|
|
128
|
-
});
|
|
129
|
-
it('a key that does not exist, and a mangled one, resolve to nothing', async () => {
|
|
130
|
-
const { key } = await accounts.create(admin, 'agent-8');
|
|
131
|
-
for (const bad of [
|
|
132
|
-
generateKey(),
|
|
133
|
-
`${key}x`,
|
|
134
|
-
key.slice(0, -1),
|
|
135
|
-
`${prefixOf(key)}${'A'.repeat(43)}`,
|
|
136
|
-
'nacre_sk_',
|
|
137
|
-
'not-a-key',
|
|
138
|
-
]) {
|
|
139
|
-
expect(await keys.resolve(bad), bad.slice(0, 20)).toBeUndefined();
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
it('a key with the right prefix and the wrong secret is refused', async () => {
|
|
143
|
-
const { key } = await accounts.create(admin, 'agent-9');
|
|
144
|
-
// The prefix is the indexed lookup, not the credential. If the hash
|
|
145
|
-
// comparison were ever dropped, every one of these would authenticate as
|
|
146
|
-
// the real account — and the prefix is stored in clear and shown in
|
|
147
|
-
// listings, so it is not a secret to begin with.
|
|
148
|
-
const forged = `${prefixOf(key)}${'B'.repeat(key.length - prefixOf(key).length)}`;
|
|
149
|
-
expect(forged.startsWith(prefixOf(key))).toBe(true);
|
|
150
|
-
expect(await keys.resolve(forged)).toBeUndefined();
|
|
151
|
-
});
|
|
152
|
-
it('authenticate() answers a bad key exactly as it answers a bad token', async () => {
|
|
153
|
-
const verify = {
|
|
154
|
-
key: new TextEncoder().encode('a'.repeat(32)),
|
|
155
|
-
issuer: 'https://api.nacre.test',
|
|
156
|
-
audience: 'nacre',
|
|
157
|
-
serviceKeys: keys,
|
|
158
|
-
};
|
|
159
|
-
const badKey = await authenticate(`Bearer ${generateKey()}`, verify, '/v1/search', 'r1');
|
|
160
|
-
const badToken = await authenticate('Bearer not-a-token', verify, '/v1/search', 'r1');
|
|
161
|
-
expect(badKey).toBeInstanceOf(Problem);
|
|
162
|
-
expect(badToken).toBeInstanceOf(Problem);
|
|
163
|
-
// "Revoked key", "unknown key" and "expired token" are one answer. Telling
|
|
164
|
-
// them apart says which guess was closest, and a key is guessable in a way
|
|
165
|
-
// a signature is not.
|
|
166
|
-
expect(badKey.toJSON()).toEqual(badToken.toJSON());
|
|
167
|
-
});
|
|
168
|
-
it('authenticate() accepts a real key and carries its organization', async () => {
|
|
169
|
-
const { key, account } = await accounts.create(admin, 'agent-10');
|
|
170
|
-
const resolved = await authenticate(`Bearer ${key}`, {
|
|
171
|
-
key: new TextEncoder().encode('a'.repeat(32)),
|
|
172
|
-
issuer: 'https://api.nacre.test',
|
|
173
|
-
audience: 'nacre',
|
|
174
|
-
serviceKeys: keys,
|
|
175
|
-
}, '/v1/search', 'r1');
|
|
176
|
-
expect(resolved).not.toBeInstanceOf(Problem);
|
|
177
|
-
const context = resolved;
|
|
178
|
-
expect(context.orgId).toBe(ORG);
|
|
179
|
-
// The account it names, not just some account in the right organization.
|
|
180
|
-
// Every grant is keyed on this id, so resolving to the wrong one would
|
|
181
|
-
// hand the caller another service account's permissions.
|
|
182
|
-
expect(context.principal).toEqual({ type: 'service_account', id: account.id });
|
|
183
|
-
});
|
|
184
|
-
it('a surface with no resolver refuses keys rather than ignoring the prefix', async () => {
|
|
185
|
-
const { key } = await accounts.create(admin, 'agent-11');
|
|
186
|
-
const result = await authenticate(`Bearer ${key}`, {
|
|
187
|
-
key: new TextEncoder().encode('a'.repeat(32)),
|
|
188
|
-
issuer: 'https://api.nacre.test',
|
|
189
|
-
audience: 'nacre',
|
|
190
|
-
}, '/v1/search', 'r1');
|
|
191
|
-
// Falling through to the JWT path would try to verify an opaque string as a
|
|
192
|
-
// signed token. That fails today, but it fails for the wrong reason, and
|
|
193
|
-
// "this credential type is not served here" should not depend on that.
|
|
194
|
-
expect(result).toBeInstanceOf(Problem);
|
|
195
|
-
});
|
|
196
|
-
it('using a key records when, without touching the decision', async () => {
|
|
197
|
-
const { key, account } = await accounts.create(admin, 'agent-12');
|
|
198
|
-
expect((await accounts.list(admin)).find((a) => a.id === account.id)?.lastUsedAt).toBeNull();
|
|
199
|
-
expect(await keys.resolve(key)).toBeDefined();
|
|
200
|
-
await new Promise((r) => setTimeout(r, 50));
|
|
201
|
-
expect((await accounts.list(admin)).find((a) => a.id === account.id)?.lastUsedAt).not.toBeNull();
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
//# sourceMappingURL=service-keys.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"service-keys.test.js","sourceRoot":"","sources":["../../src/__tests__/service-keys.test.ts"],"names":[],"mappings":"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"}
|