@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/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/index.ts
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({ at: now, event: "resolve.hit", fingerprint: cached.fingerprint, name });
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({ at: now, event: "resolve.miss", fingerprint: entry.fingerprint, name });
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({ at: now, event: "rotate", fingerprint: entry.fingerprint, name });
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=733FE5935B42EE2D64756E2164756E21
1066
+ //# debugId=A90019DE57677EBB64756E2164756E21
999
1067
  //# sourceMappingURL=index.js.map