@absolutejs/secrets 0.6.1 → 0.7.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.
- package/README.md +53 -41
- package/dist/agent.d.ts +2 -0
- package/dist/agent.js +264 -0
- package/dist/agent.js.map +12 -0
- package/dist/broker.d.ts +340 -0
- package/dist/broker.js +825 -0
- package/dist/broker.js.map +11 -0
- package/dist/index.d.ts +2 -341
- package/dist/index.js +126 -58
- package/dist/index.js.map +7 -6
- package/dist/manifest.d.ts +1 -1
- package/dist/manifest.js +2 -4
- package/dist/manifest.js.map +3 -3
- package/dist/operations.d.ts +1 -1
- package/dist/postgres.d.ts +13 -0
- package/package.json +13 -3
package/dist/index.js
CHANGED
|
@@ -15,59 +15,6 @@ var __export = (target, all) => {
|
|
|
15
15
|
};
|
|
16
16
|
var __require = import.meta.require;
|
|
17
17
|
|
|
18
|
-
// node_modules/@absolutejs/telemetry/dist/index.js
|
|
19
|
-
var NOOP_SPAN_CONTEXT = {
|
|
20
|
-
spanId: "0000000000000000",
|
|
21
|
-
traceFlags: 0,
|
|
22
|
-
traceId: "00000000000000000000000000000000"
|
|
23
|
-
};
|
|
24
|
-
var noopSpan = {
|
|
25
|
-
addEvent: () => noopSpan,
|
|
26
|
-
end: () => {},
|
|
27
|
-
isRecording: () => false,
|
|
28
|
-
recordException: () => {},
|
|
29
|
-
setAttribute: () => noopSpan,
|
|
30
|
-
setAttributes: () => noopSpan,
|
|
31
|
-
setStatus: () => noopSpan,
|
|
32
|
-
spanContext: () => NOOP_SPAN_CONTEXT,
|
|
33
|
-
updateName: () => noopSpan
|
|
34
|
-
};
|
|
35
|
-
var startActiveSpanNoop = (_name, optionsOrFn, maybeFn) => {
|
|
36
|
-
const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
|
|
37
|
-
return fn(noopSpan);
|
|
38
|
-
};
|
|
39
|
-
var noopTracer = {
|
|
40
|
-
startActiveSpan: startActiveSpanNoop,
|
|
41
|
-
startSpan: () => noopSpan
|
|
42
|
-
};
|
|
43
|
-
var tracerOrNoop = (provider, name, version) => provider !== undefined ? provider.getTracer(name, version) : noopTracer;
|
|
44
|
-
var ABS_ATTRS = {
|
|
45
|
-
tenant: "abs.tenant",
|
|
46
|
-
shardId: "abs.shard.id",
|
|
47
|
-
engineId: "abs.engine.id",
|
|
48
|
-
collection: "abs.collection",
|
|
49
|
-
mutation: "abs.mutation",
|
|
50
|
-
mutationAttempt: "abs.mutation.attempt",
|
|
51
|
-
subscriptionId: "abs.subscription.id",
|
|
52
|
-
batchSize: "abs.batch.size",
|
|
53
|
-
clusterMessageOrigin: "abs.cluster.origin",
|
|
54
|
-
jobId: "abs.job.id",
|
|
55
|
-
jobKind: "abs.job.kind",
|
|
56
|
-
jobAttempt: "abs.job.attempt",
|
|
57
|
-
jobMaxAttempts: "abs.job.max_attempts",
|
|
58
|
-
workerId: "abs.worker.id",
|
|
59
|
-
runtimeKey: "abs.runtime.key",
|
|
60
|
-
runtimePid: "abs.runtime.pid",
|
|
61
|
-
runtimePort: "abs.runtime.port",
|
|
62
|
-
runtimeExitReason: "abs.runtime.exit_reason",
|
|
63
|
-
runtimeReadinessMs: "abs.runtime.readiness_ms",
|
|
64
|
-
routeShard: "abs.route.shard",
|
|
65
|
-
routeDecision: "abs.route.decision",
|
|
66
|
-
secretName: "abs.secret.name",
|
|
67
|
-
secretFingerprint: "abs.secret.fingerprint",
|
|
68
|
-
auditKind: "abs.audit.kind"
|
|
69
|
-
};
|
|
70
|
-
|
|
71
18
|
// node_modules/@absolutejs/agency/dist/index.js
|
|
72
19
|
var normalize = (value) => {
|
|
73
20
|
if (Array.isArray(value))
|
|
@@ -254,8 +201,112 @@ var createCredentialOperationBroker = ({
|
|
|
254
201
|
};
|
|
255
202
|
return { request, resume, revoke: store.revoke };
|
|
256
203
|
};
|
|
204
|
+
// src/postgres.ts
|
|
205
|
+
var namespaceOf = (namespace) => {
|
|
206
|
+
if (!/^[a-z_][a-z0-9_]*$/.test(namespace))
|
|
207
|
+
throw new Error("Secrets PostgreSQL namespace must be a simple identifier");
|
|
208
|
+
return namespace;
|
|
209
|
+
};
|
|
210
|
+
var credentialGrantsPostgresSchemaSql = (namespace = "secrets") => {
|
|
211
|
+
const ns = namespaceOf(namespace);
|
|
212
|
+
return `CREATE SCHEMA IF NOT EXISTS ${ns};
|
|
213
|
+
CREATE TABLE IF NOT EXISTS ${ns}.credential_grants (
|
|
214
|
+
grant_id text PRIMARY KEY, agent_id text NOT NULL, user_id text NOT NULL,
|
|
215
|
+
provider text NOT NULL, expires_at bigint NOT NULL, maximum_uses integer NOT NULL CHECK (maximum_uses > 0),
|
|
216
|
+
used integer NOT NULL DEFAULT 0 CHECK (used >= 0 AND used <= maximum_uses), data jsonb NOT NULL
|
|
217
|
+
);
|
|
218
|
+
CREATE INDEX IF NOT EXISTS credential_grants_agent_idx ON ${ns}.credential_grants (agent_id, expires_at);
|
|
219
|
+
CREATE TABLE IF NOT EXISTS ${ns}.pending_operations (
|
|
220
|
+
action_id text PRIMARY KEY, grant_id text NOT NULL REFERENCES ${ns}.credential_grants(grant_id) ON DELETE CASCADE,
|
|
221
|
+
created_at timestamptz NOT NULL DEFAULT now(), data jsonb NOT NULL
|
|
222
|
+
);`;
|
|
223
|
+
};
|
|
224
|
+
var createPostgresCredentialGrantStore = ({
|
|
225
|
+
client,
|
|
226
|
+
namespace = "secrets"
|
|
227
|
+
}) => {
|
|
228
|
+
const ns = namespaceOf(namespace);
|
|
229
|
+
return {
|
|
230
|
+
consume: async (grantId, now) => {
|
|
231
|
+
const result = await client.query(`UPDATE ${ns}.credential_grants SET used = used + 1, data = jsonb_set(data, '{used}', to_jsonb(used + 1), true) WHERE grant_id = $1 AND expires_at > $2 AND used < maximum_uses RETURNING data`, [grantId, now]);
|
|
232
|
+
return result.rows[0]?.data;
|
|
233
|
+
},
|
|
234
|
+
get: async (grantId) => (await client.query(`SELECT data FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rows[0]?.data,
|
|
235
|
+
getPending: async (actionId) => (await client.query(`SELECT data FROM ${ns}.pending_operations WHERE action_id = $1`, [actionId])).rows[0]?.data,
|
|
236
|
+
put: async (grant) => {
|
|
237
|
+
if (grant.maximumUses < 1 || grant.used < 0 || grant.used > grant.maximumUses)
|
|
238
|
+
throw new Error("Invalid credential grant usage");
|
|
239
|
+
await client.query(`INSERT INTO ${ns}.credential_grants (grant_id, agent_id, user_id, provider, expires_at, maximum_uses, used, data) VALUES ($1,$2,$3,$4,$5,$6,$7,$8::jsonb) ON CONFLICT (grant_id) DO UPDATE SET expires_at=EXCLUDED.expires_at, maximum_uses=EXCLUDED.maximum_uses, used=EXCLUDED.used, data=EXCLUDED.data`, [
|
|
240
|
+
grant.grantId,
|
|
241
|
+
grant.agentId,
|
|
242
|
+
grant.userId,
|
|
243
|
+
grant.provider,
|
|
244
|
+
grant.expiresAt,
|
|
245
|
+
grant.maximumUses,
|
|
246
|
+
grant.used,
|
|
247
|
+
JSON.stringify(grant)
|
|
248
|
+
]);
|
|
249
|
+
},
|
|
250
|
+
putPending: async (pending) => {
|
|
251
|
+
await client.query(`INSERT INTO ${ns}.pending_operations (action_id, grant_id, data) VALUES ($1,$2,$3::jsonb) ON CONFLICT (action_id) DO UPDATE SET data=EXCLUDED.data`, [pending.actionId, pending.input.grantId, JSON.stringify(pending)]);
|
|
252
|
+
},
|
|
253
|
+
revoke: async (grantId) => (await client.query(`DELETE FROM ${ns}.credential_grants WHERE grant_id = $1`, [grantId])).rowCount === 1
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
// node_modules/@absolutejs/telemetry/dist/index.js
|
|
257
|
+
var NOOP_SPAN_CONTEXT = {
|
|
258
|
+
spanId: "0000000000000000",
|
|
259
|
+
traceFlags: 0,
|
|
260
|
+
traceId: "00000000000000000000000000000000"
|
|
261
|
+
};
|
|
262
|
+
var noopSpan = {
|
|
263
|
+
addEvent: () => noopSpan,
|
|
264
|
+
end: () => {},
|
|
265
|
+
isRecording: () => false,
|
|
266
|
+
recordException: () => {},
|
|
267
|
+
setAttribute: () => noopSpan,
|
|
268
|
+
setAttributes: () => noopSpan,
|
|
269
|
+
setStatus: () => noopSpan,
|
|
270
|
+
spanContext: () => NOOP_SPAN_CONTEXT,
|
|
271
|
+
updateName: () => noopSpan
|
|
272
|
+
};
|
|
273
|
+
var startActiveSpanNoop = (_name, optionsOrFn, maybeFn) => {
|
|
274
|
+
const fn = typeof optionsOrFn === "function" ? optionsOrFn : maybeFn;
|
|
275
|
+
return fn(noopSpan);
|
|
276
|
+
};
|
|
277
|
+
var noopTracer = {
|
|
278
|
+
startActiveSpan: startActiveSpanNoop,
|
|
279
|
+
startSpan: () => noopSpan
|
|
280
|
+
};
|
|
281
|
+
var tracerOrNoop = (provider, name, version) => provider !== undefined ? provider.getTracer(name, version) : noopTracer;
|
|
282
|
+
var ABS_ATTRS = {
|
|
283
|
+
tenant: "abs.tenant",
|
|
284
|
+
shardId: "abs.shard.id",
|
|
285
|
+
engineId: "abs.engine.id",
|
|
286
|
+
collection: "abs.collection",
|
|
287
|
+
mutation: "abs.mutation",
|
|
288
|
+
mutationAttempt: "abs.mutation.attempt",
|
|
289
|
+
subscriptionId: "abs.subscription.id",
|
|
290
|
+
batchSize: "abs.batch.size",
|
|
291
|
+
clusterMessageOrigin: "abs.cluster.origin",
|
|
292
|
+
jobId: "abs.job.id",
|
|
293
|
+
jobKind: "abs.job.kind",
|
|
294
|
+
jobAttempt: "abs.job.attempt",
|
|
295
|
+
jobMaxAttempts: "abs.job.max_attempts",
|
|
296
|
+
workerId: "abs.worker.id",
|
|
297
|
+
runtimeKey: "abs.runtime.key",
|
|
298
|
+
runtimePid: "abs.runtime.pid",
|
|
299
|
+
runtimePort: "abs.runtime.port",
|
|
300
|
+
runtimeExitReason: "abs.runtime.exit_reason",
|
|
301
|
+
runtimeReadinessMs: "abs.runtime.readiness_ms",
|
|
302
|
+
routeShard: "abs.route.shard",
|
|
303
|
+
routeDecision: "abs.route.decision",
|
|
304
|
+
secretName: "abs.secret.name",
|
|
305
|
+
secretFingerprint: "abs.secret.fingerprint",
|
|
306
|
+
auditKind: "abs.audit.kind"
|
|
307
|
+
};
|
|
257
308
|
|
|
258
|
-
// src/
|
|
309
|
+
// src/broker.ts
|
|
259
310
|
class BrokerDrainedError extends Error {
|
|
260
311
|
constructor() {
|
|
261
312
|
super("[secrets] Broker is draining \u2014 resolve/rotate refused. " + "Use the broker before the shutdown handler fires.");
|
|
@@ -808,7 +859,12 @@ var createSecretBroker = (options) => {
|
|
|
808
859
|
counters.resolveHits += 1;
|
|
809
860
|
span.setAttribute(ABS_ATTRS.secretFingerprint, cached.fingerprint);
|
|
810
861
|
span.setAttribute("secrets.cache", "hit");
|
|
811
|
-
fireAudit({
|
|
862
|
+
fireAudit({
|
|
863
|
+
at: now,
|
|
864
|
+
event: "resolve.hit",
|
|
865
|
+
fingerprint: cached.fingerprint,
|
|
866
|
+
name
|
|
867
|
+
});
|
|
812
868
|
span.setStatus({ code: 1 });
|
|
813
869
|
return { fingerprint: cached.fingerprint, value: cached.value };
|
|
814
870
|
}
|
|
@@ -824,7 +880,12 @@ var createSecretBroker = (options) => {
|
|
|
824
880
|
}
|
|
825
881
|
const entry = cacheEntry(name, value, now);
|
|
826
882
|
span.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);
|
|
827
|
-
fireAudit({
|
|
883
|
+
fireAudit({
|
|
884
|
+
at: now,
|
|
885
|
+
event: "resolve.miss",
|
|
886
|
+
fingerprint: entry.fingerprint,
|
|
887
|
+
name
|
|
888
|
+
});
|
|
828
889
|
span.setStatus({ code: 1 });
|
|
829
890
|
return { fingerprint: entry.fingerprint, value: entry.value };
|
|
830
891
|
} catch (error) {
|
|
@@ -863,7 +924,12 @@ var createSecretBroker = (options) => {
|
|
|
863
924
|
counters.rotates += 1;
|
|
864
925
|
span.setAttribute(ABS_ATTRS.secretFingerprint, entry.fingerprint);
|
|
865
926
|
span.setStatus({ code: 1 });
|
|
866
|
-
fireAudit({
|
|
927
|
+
fireAudit({
|
|
928
|
+
at: now,
|
|
929
|
+
event: "rotate",
|
|
930
|
+
fingerprint: entry.fingerprint,
|
|
931
|
+
name
|
|
932
|
+
});
|
|
867
933
|
fireRotation(name, entry.value, entry.fingerprint, now);
|
|
868
934
|
return { fingerprint: entry.fingerprint, value: entry.value };
|
|
869
935
|
} catch (error) {
|
|
@@ -988,12 +1054,14 @@ export {
|
|
|
988
1054
|
inMemoryAdapter,
|
|
989
1055
|
envAdapter,
|
|
990
1056
|
encryptedFileAdapter,
|
|
1057
|
+
credentialGrantsPostgresSchemaSql,
|
|
991
1058
|
createSecretBroker,
|
|
1059
|
+
createPostgresCredentialGrantStore,
|
|
992
1060
|
createMemoryCredentialGrantStore,
|
|
993
1061
|
createCredentialOperationBroker,
|
|
994
1062
|
compositeAdapter,
|
|
995
1063
|
BrokerDrainedError
|
|
996
1064
|
};
|
|
997
1065
|
|
|
998
|
-
//# debugId=
|
|
1066
|
+
//# debugId=A90019DE57677EBB64756E2164756E21
|
|
999
1067
|
//# sourceMappingURL=index.js.map
|