@centient/secrets 0.10.0 → 0.11.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 (99) hide show
  1. package/README.md +355 -7
  2. package/dist/audit/hmac-chain.d.ts +117 -0
  3. package/dist/audit/hmac-chain.d.ts.map +1 -0
  4. package/dist/audit/hmac-chain.js +811 -0
  5. package/dist/audit/hmac-chain.js.map +1 -0
  6. package/dist/audit/ocsf.d.ts +108 -0
  7. package/dist/audit/ocsf.d.ts.map +1 -0
  8. package/dist/audit/ocsf.js +204 -0
  9. package/dist/audit/ocsf.js.map +1 -0
  10. package/dist/cli/hidden-prompt.d.ts.map +1 -1
  11. package/dist/cli/hidden-prompt.js +55 -10
  12. package/dist/cli/hidden-prompt.js.map +1 -1
  13. package/dist/cli/messages.d.ts +40 -8
  14. package/dist/cli/messages.d.ts.map +1 -1
  15. package/dist/cli/messages.js +34 -8
  16. package/dist/cli/messages.js.map +1 -1
  17. package/dist/client.d.ts +26 -0
  18. package/dist/client.d.ts.map +1 -0
  19. package/dist/client.js +129 -0
  20. package/dist/client.js.map +1 -0
  21. package/dist/compatibility.d.ts +199 -0
  22. package/dist/compatibility.d.ts.map +1 -0
  23. package/dist/compatibility.js +419 -0
  24. package/dist/compatibility.js.map +1 -0
  25. package/dist/index.d.ts +19 -5
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +16 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/policies/audit-trail.d.ts +25 -0
  30. package/dist/policies/audit-trail.d.ts.map +1 -0
  31. package/dist/policies/audit-trail.js +31 -0
  32. package/dist/policies/audit-trail.js.map +1 -0
  33. package/dist/sinks/index.d.ts +9 -0
  34. package/dist/sinks/index.d.ts.map +1 -0
  35. package/dist/sinks/index.js +5 -0
  36. package/dist/sinks/index.js.map +1 -0
  37. package/dist/sinks/jsonl.d.ts +16 -0
  38. package/dist/sinks/jsonl.d.ts.map +1 -0
  39. package/dist/sinks/jsonl.js +51 -0
  40. package/dist/sinks/jsonl.js.map +1 -0
  41. package/dist/sinks/otel.d.ts +22 -0
  42. package/dist/sinks/otel.d.ts.map +1 -0
  43. package/dist/sinks/otel.js +155 -0
  44. package/dist/sinks/otel.js.map +1 -0
  45. package/dist/sinks/queue.d.ts +12 -0
  46. package/dist/sinks/queue.d.ts.map +1 -0
  47. package/dist/sinks/queue.js +89 -0
  48. package/dist/sinks/queue.js.map +1 -0
  49. package/dist/sinks/syslog.d.ts +17 -0
  50. package/dist/sinks/syslog.d.ts.map +1 -0
  51. package/dist/sinks/syslog.js +103 -0
  52. package/dist/sinks/syslog.js.map +1 -0
  53. package/dist/sinks/types.d.ts +27 -0
  54. package/dist/sinks/types.d.ts.map +1 -0
  55. package/dist/sinks/types.js +18 -0
  56. package/dist/sinks/types.js.map +1 -0
  57. package/dist/vault/policy.d.ts +64 -34
  58. package/dist/vault/policy.d.ts.map +1 -1
  59. package/dist/vault/policy.js +109 -67
  60. package/dist/vault/policy.js.map +1 -1
  61. package/dist/vault/session-vault.d.ts +43 -0
  62. package/dist/vault/session-vault.d.ts.map +1 -1
  63. package/dist/vault/session-vault.js +323 -36
  64. package/dist/vault/session-vault.js.map +1 -1
  65. package/dist/vault/sidecar.d.ts +9 -0
  66. package/dist/vault/sidecar.d.ts.map +1 -1
  67. package/dist/vault/sidecar.js +72 -3
  68. package/dist/vault/sidecar.js.map +1 -1
  69. package/dist/vault/types.d.ts +16 -9
  70. package/dist/vault/types.d.ts.map +1 -1
  71. package/dist/vault/vault-env.d.ts +41 -62
  72. package/dist/vault/vault-env.d.ts.map +1 -1
  73. package/dist/vault/vault-env.js +139 -75
  74. package/dist/vault/vault-env.js.map +1 -1
  75. package/dist/vault/vault-gpg.d.ts +1 -0
  76. package/dist/vault/vault-gpg.d.ts.map +1 -1
  77. package/dist/vault/vault-gpg.js +1 -0
  78. package/dist/vault/vault-gpg.js.map +1 -1
  79. package/dist/vault/vault-libsecret.d.ts +1 -0
  80. package/dist/vault/vault-libsecret.d.ts.map +1 -1
  81. package/dist/vault/vault-libsecret.js +7 -6
  82. package/dist/vault/vault-libsecret.js.map +1 -1
  83. package/dist/vault/vault-onepassword.d.ts +1 -0
  84. package/dist/vault/vault-onepassword.d.ts.map +1 -1
  85. package/dist/vault/vault-onepassword.js +1 -0
  86. package/dist/vault/vault-onepassword.js.map +1 -1
  87. package/dist/vault/vault-utils.d.ts +7 -6
  88. package/dist/vault/vault-utils.d.ts.map +1 -1
  89. package/dist/vault/vault-utils.js +8 -7
  90. package/dist/vault/vault-utils.js.map +1 -1
  91. package/dist/vault/vault-windows.d.ts +2 -1
  92. package/dist/vault/vault-windows.d.ts.map +1 -1
  93. package/dist/vault/vault-windows.js +12 -8
  94. package/dist/vault/vault-windows.js.map +1 -1
  95. package/dist/vault/vault.d.ts +6 -7
  96. package/dist/vault/vault.d.ts.map +1 -1
  97. package/dist/vault/vault.js +37 -193
  98. package/dist/vault/vault.js.map +1 -1
  99. package/package.json +8 -2
@@ -1,14 +1,40 @@
1
1
  /**
2
- * Auth Module - Centralized Message Strings
2
+ * Auth CLI message catalog the shared strings for the credential lifecycle a
3
+ * consuming CLI drives on top of this vault (`login`, `logout`, `auth status`,
4
+ * `auth refresh`, device flow, api-key entry).
3
5
  *
4
- * All user-visible strings for the auth module are defined here.
5
- * This module is i18n-ready: message values do not contain interpolated
6
- * strings template functions accept parameters and return formatted strings.
6
+ * Scope (#217 C6-34). The previous header claimed "all user-visible strings for
7
+ * the auth module", which was never true of this package — there is no auth
8
+ * module here, and only one entry had an in-package call site. The verified
9
+ * scope is:
10
+ *
11
+ * - IN — the auth/device-flow/token lifecycle listed above, driven by the
12
+ * consuming CLI, plus the one credential-storage warning this package
13
+ * itself emits: `warning.envVaultNoStorage`, from `EnvVault.store()` in
14
+ * `../vault/vault-env.ts`.
15
+ * - OUT — the `centient secrets …` operator CLI in `./secrets-cli.ts` and the
16
+ * `[secrets] …` vault diagnostics under `../vault/`. Those are
17
+ * command-specific and carry their own next-step lines; funnelling them
18
+ * through a flat catalog would drop that specificity, so they are
19
+ * deliberately not catalog entries.
20
+ *
21
+ * This catalog is part of the package's public surface — import it, do not copy
22
+ * it. It is exported precisely so a consuming CLI stops maintaining a fork:
23
+ * before #217, `centient` carried a byte-identical copy at
24
+ * `packages/centient/src/auth/messages.ts` that had already drifted on
25
+ * `warning.envVaultNoStorage` (the single entry this package consumes, and so
26
+ * the single entry that had been updated here).
27
+ *
28
+ * i18n-ready: no message value interpolates at the call site. Parameterized
29
+ * messages are template functions that take their parameters and return the
30
+ * finished string, so a translation layer can replace the catalog wholesale.
7
31
  *
8
32
  * Usage:
9
- * import { AUTH_MESSAGES } from './messages.js';
10
- * process.stderr.write(AUTH_MESSAGES.error.vaultWriteFailed + '\n');
11
- * process.stderr.write(AUTH_MESSAGES.info.loginPrompt('https://auth.example.com') + '\n');
33
+ * import { AUTH_MESSAGES } from "@centient/secrets";
34
+ * process.stderr.write(AUTH_MESSAGES.error.vaultWriteFailed + "\n");
35
+ * process.stderr.write(
36
+ * AUTH_MESSAGES.info.loginPrompt("https://auth.example.com") + "\n",
37
+ * );
12
38
  */
13
39
  // =============================================================================
14
40
  // Message catalog
@@ -45,7 +71,7 @@ export const AUTH_MESSAGES = {
45
71
  revokeNetworkFailure: "Could not reach server to revoke token — local credentials have been removed.",
46
72
  noCredentialsFound: "No stored credentials found. Run `centient login` to authenticate.",
47
73
  sessionExpiredIdle: "Session expired due to inactivity.",
48
- envVaultNoStorage: "No secure credential storage available. Install libsecret (Linux: apt install libsecret-tools) or GPG for persistent storage. Using ENGRAM_API_KEY environment variable only.",
74
+ envVaultNoStorage: "No secure credential storage available. Install libsecret (Linux: apt install libsecret-tools) or GPG for persistent storage. The environment fallback is read-only; set ENGRAM_API_KEY for auth-token or the key's CENTIENT_SECRET_* variable.",
49
75
  },
50
76
  info: {
51
77
  loginPrompt: (verificationUri) => `Visit the following URL to authorize this device:\n ${verificationUri}`,
@@ -1 +1 @@
1
- {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/cli/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE;QACP,QAAQ,EAAE,mDAAmD;QAC7D,SAAS,EAAE,+CAA+C;QAC1D,WAAW,EAAE,iCAAiC;QAC9C,cAAc,EAAE,+BAA+B;QAC/C,YAAY,EAAE,mCAAmC;QACjD,cAAc,EAAE,0BAA0B;KAC3C;IAED,KAAK,EAAE;QACL,gBAAgB,EAAE,uCAAuC;QACzD,eAAe,EAAE,wCAAwC;QACzD,iBAAiB,EAAE,0CAA0C;QAC7D,gBAAgB,EAAE,mCAAmC;QACrD,iBAAiB,EAAE,mDAAmD;QACtE,sBAAsB,EAAE,4CAA4C;QACpE,iBAAiB,EAAE,8CAA8C;QACjE,YAAY,EAAE,wDAAwD;QACtE,YAAY,EAAE,uBAAuB;QACrC,cAAc,EAAE,6CAA6C;QAC7D,YAAY,EAAE,sCAAsC;QACpD,aAAa,EAAE,0DAA0D;QACzE,YAAY,EAAE,sDAAsD;QACpE,mBAAmB,EAAE,CAAC,GAAW,EAAU,EAAE,CAC3C,4BAA4B,GAAG,qCAAqC;QACtE,uBAAuB,EACrB,sDAAsD;QACxD,iBAAiB,EAAE,CAAC,GAAW,EAAU,EAAE,CACzC,wBAAwB,GAAG,4CAA4C;KAC1E;IAED,OAAO,EAAE;QACP,iBAAiB,EAAE,CAAC,OAAe,EAAU,EAAE,CAC7C,yBAAyB,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,sCAAsC;QAC1G,oBAAoB,EAClB,+EAA+E;QACjF,kBAAkB,EAChB,oEAAoE;QACtE,kBAAkB,EAAE,oCAAoC;QACxD,iBAAiB,EACf,+KAA+K;KAClL;IAED,IAAI,EAAE;QACJ,WAAW,EAAE,CAAC,eAAuB,EAAU,EAAE,CAC/C,wDAAwD,eAAe,EAAE;QAC3E,eAAe,EAAE,CAAC,QAAgB,EAAU,EAAE,CAC5C,qCAAqC,QAAQ,EAAE;QACjD,WAAW,EAAE,CAAC,OAAe,EAAU,EAAE,CACvC,iCAAiC,OAAO,cAAc;QACxD,iBAAiB,EACf,+EAA+E;QACjF,uBAAuB,EAAE,CAAC,SAAiB,EAAU,EAAE,CACrD,mCAAmC,SAAS,GAAG;QACjD,yBAAyB,EAAE,0CAA0C;QACrE,sBAAsB,EAAE,CAAC,OAAe,EAAU,EAAE,CAClD,8BAA8B,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;QAC7E,SAAS,EAAE,CAAC,SAAiB,EAAU,EAAE,CAAC,UAAU,SAAS,EAAE;QAC/D,cAAc,EAAE,gBAAgB;QAChC,aAAa,EAAE,uCAAuC;KACvD;CACO,CAAC"}
1
+ {"version":3,"file":"messages.js","sourceRoot":"","sources":["../../src/cli/messages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,gFAAgF;AAChF,kBAAkB;AAClB,gFAAgF;AAEhF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,OAAO,EAAE;QACP,QAAQ,EAAE,mDAAmD;QAC7D,SAAS,EAAE,+CAA+C;QAC1D,WAAW,EAAE,iCAAiC;QAC9C,cAAc,EAAE,+BAA+B;QAC/C,YAAY,EAAE,mCAAmC;QACjD,cAAc,EAAE,0BAA0B;KAC3C;IAED,KAAK,EAAE;QACL,gBAAgB,EAAE,uCAAuC;QACzD,eAAe,EAAE,wCAAwC;QACzD,iBAAiB,EAAE,0CAA0C;QAC7D,gBAAgB,EAAE,mCAAmC;QACrD,iBAAiB,EAAE,mDAAmD;QACtE,sBAAsB,EAAE,4CAA4C;QACpE,iBAAiB,EAAE,8CAA8C;QACjE,YAAY,EAAE,wDAAwD;QACtE,YAAY,EAAE,uBAAuB;QACrC,cAAc,EAAE,6CAA6C;QAC7D,YAAY,EAAE,sCAAsC;QACpD,aAAa,EAAE,0DAA0D;QACzE,YAAY,EAAE,sDAAsD;QACpE,mBAAmB,EAAE,CAAC,GAAW,EAAU,EAAE,CAC3C,4BAA4B,GAAG,qCAAqC;QACtE,uBAAuB,EACrB,sDAAsD;QACxD,iBAAiB,EAAE,CAAC,GAAW,EAAU,EAAE,CACzC,wBAAwB,GAAG,4CAA4C;KAC1E;IAED,OAAO,EAAE;QACP,iBAAiB,EAAE,CAAC,OAAe,EAAU,EAAE,CAC7C,yBAAyB,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,sCAAsC;QAC1G,oBAAoB,EAClB,+EAA+E;QACjF,kBAAkB,EAChB,oEAAoE;QACtE,kBAAkB,EAAE,oCAAoC;QACxD,iBAAiB,EACf,iPAAiP;KACpP;IAED,IAAI,EAAE;QACJ,WAAW,EAAE,CAAC,eAAuB,EAAU,EAAE,CAC/C,wDAAwD,eAAe,EAAE;QAC3E,eAAe,EAAE,CAAC,QAAgB,EAAU,EAAE,CAC5C,qCAAqC,QAAQ,EAAE;QACjD,WAAW,EAAE,CAAC,OAAe,EAAU,EAAE,CACvC,iCAAiC,OAAO,cAAc;QACxD,iBAAiB,EACf,+EAA+E;QACjF,uBAAuB,EAAE,CAAC,SAAiB,EAAU,EAAE,CACrD,mCAAmC,SAAS,GAAG;QACjD,yBAAyB,EAAE,0CAA0C;QACrE,sBAAsB,EAAE,CAAC,OAAe,EAAU,EAAE,CAClD,8BAA8B,OAAO,UAAU,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI;QAC7E,SAAS,EAAE,CAAC,SAAiB,EAAU,EAAE,CAAC,UAAU,SAAS,EAAE;QAC/D,cAAc,EAAE,gBAAgB;QAChC,aAAa,EAAE,uCAAuC;KACvD;CACO,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { type PolicyRunner, type SecretsOperationContext, type SecretsPolicy } from "./vault/policy.js";
2
+ import type { SecretsProvider } from "./vault/types.js";
3
+ export interface CreateSecretsClientOptions {
4
+ /** Credential-value storage provider used by this client only. */
5
+ readonly provider: SecretsProvider;
6
+ /** Policy membership is snapshotted at construction for this client. */
7
+ readonly policies?: readonly SecretsPolicy[];
8
+ /** Honest event identity when a legacy provider has no `name`. */
9
+ readonly providerName?: string;
10
+ }
11
+ export interface SecretsClient {
12
+ readonly providerName: string;
13
+ storeCredential(key: string, value: string, context?: SecretsOperationContext): Promise<boolean>;
14
+ getCredential(key: string, context?: SecretsOperationContext): Promise<string | null>;
15
+ deleteCredential(key: string, context?: SecretsOperationContext): Promise<boolean>;
16
+ listCredentials(prefix?: string, context?: SecretsOperationContext): Promise<string[]>;
17
+ isSessionValid(): boolean;
18
+ }
19
+ type InternalSecretsClientOptions = Omit<CreateSecretsClientOptions, "policies"> & {
20
+ readonly policyRunner: PolicyRunner;
21
+ };
22
+ export declare function createSecretsClient(options: CreateSecretsClientOptions): SecretsClient;
23
+ /** @internal Legacy default-client construction seam. */
24
+ export declare function createSecretsClientWithPolicyRunner(options: InternalSecretsClientOptions): SecretsClient;
25
+ export {};
26
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,YAAY,EAKjB,KAAK,uBAAuB,EAC5B,KAAK,aAAa,EACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAOxD,MAAM,WAAW,0BAA0B;IACzC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;IAC7C,kEAAkE;IAClE,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,eAAe,CACb,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,aAAa,CACX,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1B,gBAAgB,CACd,GAAG,EAAE,MAAM,EACX,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,eAAe,CACb,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrB,cAAc,IAAI,OAAO,CAAC;CAC3B;AAED,KAAK,4BAA4B,GAAG,IAAI,CACtC,0BAA0B,EAC1B,UAAU,CACX,GAAG;IACF,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC,CAAC;AAoNF,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,aAAa,CAMf;AAED,yDAAyD;AACzD,wBAAgB,mCAAmC,CACjD,OAAO,EAAE,4BAA4B,GACpC,aAAa,CAMf"}
package/dist/client.js ADDED
@@ -0,0 +1,129 @@
1
+ import { createPolicyRunner, rejectedEventType, } from "./vault/policy.js";
2
+ import { isValidKey, isValidKeyPrefix } from "./vault/vault-utils.js";
3
+ import { InvalidCredentialKeyError } from "./vault/session-vault-errors.js";
4
+ const SESSION_TTL_MS = 4 * 60 * 60 * 1000;
5
+ const PROVIDER_FAILURE_ERROR = "provider operation failed";
6
+ function operationStart() {
7
+ return {
8
+ timestamp: new Date().toISOString(),
9
+ monotonicMs: performance.now(),
10
+ };
11
+ }
12
+ function operationWithContext(fields, context) {
13
+ const caller = context?.caller;
14
+ return Object.freeze({
15
+ ...fields,
16
+ ...(caller
17
+ ? {
18
+ caller: Object.freeze({
19
+ id: caller.id,
20
+ ...(caller.kind !== undefined ? { kind: caller.kind } : {}),
21
+ }),
22
+ }
23
+ : {}),
24
+ });
25
+ }
26
+ class SecretsClientImpl {
27
+ provider;
28
+ policies;
29
+ providerName;
30
+ lastAccessAt = null;
31
+ constructor(provider, policies, providerName) {
32
+ this.provider = provider;
33
+ this.policies = policies;
34
+ const candidate = providerName ?? provider.name;
35
+ this.providerName = candidate?.trim() || "unknown";
36
+ }
37
+ isSessionValid() {
38
+ return (this.lastAccessAt !== null &&
39
+ Date.now() - this.lastAccessAt < SESSION_TTL_MS);
40
+ }
41
+ async storeCredential(key, value, context) {
42
+ const operation = operationWithContext({ type: "write", key }, context);
43
+ this.assertValidOperation(operation);
44
+ return this.execute(operation, "credential_write_failed", () => this.provider.store(key, value), (success) => success ? "credential_written" : "credential_write_failed", (success) => {
45
+ if (success)
46
+ this.lastAccessAt = Date.now();
47
+ });
48
+ }
49
+ async getCredential(key, context) {
50
+ const operation = operationWithContext({ type: "read", key }, context);
51
+ this.assertValidOperation(operation);
52
+ return this.execute(operation, "credential_read_failed", () => this.provider.retrieve(key), (value) => value === null ? "credential_read_missing" : "credential_read", (value) => {
53
+ if (value !== null)
54
+ this.lastAccessAt = Date.now();
55
+ });
56
+ }
57
+ async deleteCredential(key, context) {
58
+ const operation = operationWithContext({ type: "delete", key }, context);
59
+ this.assertValidOperation(operation);
60
+ return this.execute(operation, "credential_delete_failed", () => this.provider.delete(key), (success) => success ? "credential_deleted" : "credential_delete_failed");
61
+ }
62
+ async listCredentials(prefix, context) {
63
+ const operation = operationWithContext({ type: "enumerate", ...(prefix !== undefined ? { prefix } : {}) }, context);
64
+ this.assertValidOperation(operation);
65
+ return this.execute(operation, "credential_enumerate_failed", () => this.provider.listKeys(prefix), () => "credential_enumerated", (keys) => {
66
+ if (keys.length > 0)
67
+ this.lastAccessAt = Date.now();
68
+ }, (keys) => ({ keyCount: keys.length }));
69
+ }
70
+ assertValidOperation(operation) {
71
+ let error;
72
+ if (operation.type === "enumerate") {
73
+ if (operation.prefix !== undefined &&
74
+ !isValidKeyPrefix(operation.prefix)) {
75
+ error = new InvalidCredentialKeyError(operation.prefix, "enumerate", "prefix");
76
+ }
77
+ }
78
+ else if (operation.key !== undefined && !isValidKey(operation.key)) {
79
+ error = new InvalidCredentialKeyError(operation.key, operation.type, "key");
80
+ }
81
+ if (!error)
82
+ return;
83
+ const start = operationStart();
84
+ this.policies.runAfter(this.makeEvent(operation, rejectedEventType(operation), start, { error: error.message }));
85
+ throw error;
86
+ }
87
+ async execute(operation, failedType, invoke, successType, onSuccess, extras) {
88
+ const start = operationStart();
89
+ let frame;
90
+ frame = await this.policies.runBefore(operation, (error) => this.makeEvent(operation, rejectedEventType(operation), start, { error }));
91
+ let value;
92
+ try {
93
+ value = await invoke();
94
+ }
95
+ catch (error) {
96
+ this.policies.runAfter(this.makeEvent(operation, failedType, start, {
97
+ // Providers receive credential values on writes and may include one
98
+ // in a thrown message. Preserve the original error for the caller,
99
+ // but never forward provider-controlled text into an audit event.
100
+ error: PROVIDER_FAILURE_ERROR,
101
+ }), frame);
102
+ throw error;
103
+ }
104
+ onSuccess?.(value);
105
+ this.policies.runAfter(this.makeEvent(operation, successType(value), start, extras?.(value)), frame);
106
+ return value;
107
+ }
108
+ makeEvent(operation, type, start, extras = {}) {
109
+ return {
110
+ type,
111
+ // OCSF `time` is the operation start, not completion time.
112
+ timestamp: start.timestamp,
113
+ backend: this.providerName,
114
+ operation,
115
+ ...(operation.key !== undefined ? { key: operation.key } : {}),
116
+ ...(operation.prefix !== undefined ? { prefix: operation.prefix } : {}),
117
+ ...extras,
118
+ durationMs: performance.now() - start.monotonicMs,
119
+ };
120
+ }
121
+ }
122
+ export function createSecretsClient(options) {
123
+ return new SecretsClientImpl(options.provider, createPolicyRunner(options.policies ?? []), options.providerName);
124
+ }
125
+ /** @internal Legacy default-client construction seam. */
126
+ export function createSecretsClientWithPolicyRunner(options) {
127
+ return new SecretsClientImpl(options.provider, options.policyRunner, options.providerName);
128
+ }
129
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,199 @@
1
+ /**
2
+ * The compatibility floor: what an OLD `@centient/secrets` silently does wrong,
3
+ * published as data so a consumer can grade itself (#214).
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * Five consumers pin this package at four disjoint minors (`^0.5.0` … `0.10.0`)
8
+ * with no negotiation surface between them and the provider. Several releases
9
+ * closed defects whose only symptom, at the old version, is **silence**: a
10
+ * denied credential operation that leaves no audit trace, a keychain write that
11
+ * reports success into a keychain this context's reader cannot see, a malformed
12
+ * key that stores on one backend and reads as absent on the next. A consumer
13
+ * running such a version has no way to learn that from the package — the
14
+ * behaviour looks fine and the logs look clean.
15
+ *
16
+ * So the provider publishes the list. {@link COMPATIBILITY_FLOOR} names each
17
+ * closed gap, the version that closed it, and the symptom it presented before
18
+ * then; {@link assessCompatibility} turns an installed version into a grade a
19
+ * `doctor` command can print.
20
+ *
21
+ * ## What this is NOT
22
+ *
23
+ * **Never a boot-time refusal.** Nothing here runs at import, nothing throws
24
+ * from a constructor, and no vault path consults it. A package that refuses to
25
+ * load because the caller is old converts a documentation problem into an
26
+ * outage. Every function in this module is pure, total, and advisory: malformed
27
+ * input comes back as a typed `"unknown"` grade carrying the reason (P2, No
28
+ * Silent Degradation; P10, Honest Uncertainty), never as a throw.
29
+ *
30
+ * ## What a consumer does with it
31
+ *
32
+ * ```ts
33
+ * import { assessCompatibility, SECRETS_PACKAGE_VERSION } from "@centient/secrets";
34
+ *
35
+ * const assessment = assessCompatibility(SECRETS_PACKAGE_VERSION);
36
+ * if (assessment.grade !== "ok") {
37
+ * for (const gap of assessment.openGaps) {
38
+ * report(`${gap.severity}: ${gap.symptom} (fixed in ${gap.closedIn}, ${gap.reference})`);
39
+ * }
40
+ * }
41
+ * ```
42
+ *
43
+ * `SECRETS_PACKAGE_VERSION` is the version of the build the consumer actually
44
+ * imported, so the assessment describes the code in that tree — not whatever is
45
+ * latest on the registry. A consumer auditing a *manifest* range instead (`the
46
+ * pin says ^0.6.0 — what does that admit at worst?`) uses {@link assessPin}.
47
+ *
48
+ * Issue: centient-labs/centient-sdk#214 (findings C6-27, C6-29, C6-61).
49
+ */
50
+ /**
51
+ * The version of THIS build of `@centient/secrets`.
52
+ *
53
+ * Kept in step with `package.json` two ways: `scripts/sync-claudemd-versions.mjs`
54
+ * rewrites it during `pnpm run version-packages` (the same step that syncs the
55
+ * CLAUDE.md package table), and `tests/compatibility.test.ts` fails the build if
56
+ * the two ever disagree. A stale constant here would misgrade every consumer, so
57
+ * drift is a test failure rather than a silent wrong answer.
58
+ */
59
+ export declare const SECRETS_PACKAGE_VERSION = "0.11.0";
60
+ /**
61
+ * The oldest version {@link COMPATIBILITY_FLOOR} can honestly describe.
62
+ *
63
+ * `0.5.0` is the oldest release any current consumer pins, and the oldest one
64
+ * whose behaviour the table's entries were written against. Below it the table
65
+ * is not wrong so much as **incomplete** — returning its short list for a 0.4.x
66
+ * install would understate what is open — so {@link assessCompatibility} grades
67
+ * such a version `"unsupported"` and says so, rather than quietly reporting the
68
+ * gaps it happens to know about.
69
+ *
70
+ * This is an epistemic limit on the table, not a support policy and not a gate:
71
+ * an `"unsupported"` grade still returns every gap the table does know about.
72
+ */
73
+ export declare const MIN_ASSESSABLE_VERSION = "0.5.0";
74
+ /** How badly the gap bites a consumer still running below `closedIn`. */
75
+ export type GapSeverity = "high" | "medium" | "low";
76
+ /**
77
+ * One known behavioural gap, keyed by the version that closed it.
78
+ *
79
+ * A gap is **open** for an installed version `v` exactly when
80
+ * `v < closedIn` — there is no upper bound, because a fix that shipped is not
81
+ * un-shipped. Everything here is value-free public metadata: no credential
82
+ * material, no host paths, nothing that changes at runtime.
83
+ */
84
+ export interface CompatibilityGap {
85
+ /** Stable machine-readable id. Never renamed — consumers may suppress by id. */
86
+ readonly id: string;
87
+ /** The first release in which the gap is closed. A valid `major.minor.patch`. */
88
+ readonly closedIn: string;
89
+ /** How badly this bites a consumer still below `closedIn`. */
90
+ readonly severity: GapSeverity;
91
+ /** One line, consumer-facing: what the OLD version does wrong. */
92
+ readonly symptom: string;
93
+ /** Issue or PR that closed it, `owner/repo#n`. */
94
+ readonly reference: string;
95
+ /**
96
+ * What the consumer must change when it adopts the fix, when adopting is not
97
+ * a pure no-op. Absent means "bump and nothing else". This is the field that
98
+ * turns the table from a scorecard into a bump plan.
99
+ */
100
+ readonly adoptionNote?: string;
101
+ /** The C6 audit finding this gap corresponds to, where one exists. */
102
+ readonly finding?: string;
103
+ }
104
+ /**
105
+ * The published floor — deeply frozen at module initialization (every field on
106
+ * a {@link CompatibilityGap} is a primitive, so freezing each entry plus the
107
+ * array is a complete freeze). `assessCompatibility()` defaults to this same
108
+ * object, so a runtime mutation — a JS consumer, a test helper, a cast past
109
+ * the `readonly` type — would silently change every later assessment in the
110
+ * process. Frozen, the mutation throws at the mutation site instead
111
+ * (mb:f/7e54ba; the same no-silent-degradation stance as the rest of this
112
+ * module).
113
+ */
114
+ export declare const COMPATIBILITY_FLOOR: readonly CompatibilityGap[];
115
+ /** The grade a consumer's installed version earns against the floor. */
116
+ export type CompatibilityGrade =
117
+ /** At or above every known fix. Nothing in the table is open. */
118
+ "ok"
119
+ /** Assessable, but one or more known gaps are open. `openGaps` lists them. */
120
+ | "degraded"
121
+ /** Below {@link MIN_ASSESSABLE_VERSION}: the table cannot claim to be complete. */
122
+ | "unsupported"
123
+ /** The version could not be parsed. `reason` says why. Never a throw. */
124
+ | "unknown";
125
+ /**
126
+ * The result of grading one version against the floor. Every field is derived
127
+ * and value-free; the input is echoed back so a caller can see what was graded
128
+ * (P6, Single Source of Truth — echo interpreted parameters).
129
+ */
130
+ export interface CompatibilityAssessment {
131
+ readonly grade: CompatibilityGrade;
132
+ /** The version as given, echoed verbatim — including unparseable input. */
133
+ readonly installedVersion: string;
134
+ /** The version of the build that produced this assessment. */
135
+ readonly currentVersion: string;
136
+ /** The floor below which the table is incomplete. */
137
+ readonly minAssessableVersion: string;
138
+ /**
139
+ * Gaps open at `installedVersion`, oldest fix first. Empty for `"ok"` and for
140
+ * `"unknown"` — and for `"unknown"` that emptiness means `not assessed`, which
141
+ * is why the grade, not the list length, is what a caller branches on.
142
+ */
143
+ readonly openGaps: readonly CompatibilityGap[];
144
+ /** The worst severity among `openGaps`, or `null` when there are none. */
145
+ readonly highestSeverity: GapSeverity | null;
146
+ /** One line suitable for a doctor's status column. */
147
+ readonly summary: string;
148
+ /** Why the grade is `"unknown"` or `"unsupported"`. Absent otherwise. */
149
+ readonly reason?: string;
150
+ }
151
+ /**
152
+ * Grade an installed version against the compatibility floor.
153
+ *
154
+ * Pure and total: it reads no environment, touches no keychain, and **never
155
+ * throws** — a version string it cannot parse comes back as
156
+ * `grade: "unknown"` naming the problem. Totality is enforced here rather than
157
+ * assumed of the parser: input is narrowed by this module's own guard, so a JS
158
+ * caller handing it `null`, `undefined`, a number or an object gets the same
159
+ * typed `"unknown"` result as a misspelt version, never an exception. Call it
160
+ * from a `doctor`, a startup log line, or a CI check; do not call it from a
161
+ * code path that would refuse to run on the answer.
162
+ *
163
+ * @param installedVersion - the version actually installed in the consumer's
164
+ * tree. Import {@link SECRETS_PACKAGE_VERSION} for that; a leading `v` and
165
+ * surrounding whitespace are tolerated.
166
+ * @param floor - the gap table to grade against. Defaults to
167
+ * {@link COMPATIBILITY_FLOOR}; injectable so a test can grade a fixture table
168
+ * without pinning itself to the shipped one.
169
+ */
170
+ export declare function assessCompatibility(installedVersion: string, floor?: readonly CompatibilityGap[]): CompatibilityAssessment;
171
+ /**
172
+ * The lowest version a dependency range admits, or `null` when the range form
173
+ * is one this helper does not understand.
174
+ *
175
+ * Deliberately narrow: it recognises the forms that actually appear in the
176
+ * consumers' manifests — `^x.y.z`, `~x.y.z`, `>=x.y.z` and a bare `x.y.z` — and
177
+ * returns `null` for everything else rather than guessing. A guess here would
178
+ * grade the wrong version and report a clean bill of health for a pin nobody
179
+ * checked.
180
+ *
181
+ * The accepted grammar is matched whole and enumerated on
182
+ * {@link SUPPORTED_RANGE}; nothing outside it is partially interpreted. Total:
183
+ * a non-string, an empty string, and every unsupported form all return `null`.
184
+ */
185
+ export declare function lowestVersionInRange(range: string): string | null;
186
+ /**
187
+ * Grade a manifest **pin** by its worst admissible version.
188
+ *
189
+ * `assessCompatibility` answers "what is open in the build I imported"; this
190
+ * answers "what could be open in any build this pin admits". A `^0.6.0` pin can
191
+ * resolve to any 0.6.x, so the version worth grading is its base — which is also
192
+ * the one a lockfile that has never been refreshed is most likely holding.
193
+ *
194
+ * Returns `grade: "unknown"` carrying the reason for a range form
195
+ * {@link lowestVersionInRange} does not recognise — including a non-string a JS
196
+ * caller slipped past the signature. Never throws.
197
+ */
198
+ export declare function assessPin(pin: string, floor?: readonly CompatibilityGap[]): CompatibilityAssessment;
199
+ //# sourceMappingURL=compatibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compatibility.d.ts","sourceRoot":"","sources":["../src/compatibility.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAIH;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,UAAU,CAAC;AAE9C,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAQpD;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gFAAgF;IAChF,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,kDAAkD;IAClD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AA+ED;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,gBAAgB,EAE1D,CAAC;AA4DF,wEAAwE;AACxE,MAAM,MAAM,kBAAkB;AAC5B,iEAAiE;AAC/D,IAAI;AACN,8EAA8E;GAC5E,UAAU;AACZ,mFAAmF;GACjF,aAAa;AACf,yEAAyE;GACvE,SAAS,CAAC;AAEd;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,qDAAqD;IACrD,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC/C,0EAA0E;IAC1E,QAAQ,CAAC,eAAe,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7C,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,mBAAmB,CACjC,gBAAgB,EAAE,MAAM,EACxB,KAAK,GAAE,SAAS,gBAAgB,EAAwB,GACvD,uBAAuB,CAwEzB;AA0FD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAGjE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,SAAS,gBAAgB,EAAwB,GACvD,uBAAuB,CAezB"}