@homeflare/alchemy 0.41.0 → 0.42.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 (38) hide show
  1. package/dist/proxmox/acl.d.ts.map +1 -1
  2. package/dist/proxmox/api-token.d.ts.map +1 -1
  3. package/dist/proxmox/credential-errors.d.ts +18 -4
  4. package/dist/proxmox/credential-errors.d.ts.map +1 -1
  5. package/dist/proxmox/credentials.d.ts +35 -1
  6. package/dist/proxmox/credentials.d.ts.map +1 -1
  7. package/dist/proxmox/group.d.ts.map +1 -1
  8. package/dist/proxmox/index.js +34 -18
  9. package/dist/proxmox/index.js.map +16 -15
  10. package/dist/proxmox/lease-cache.d.ts +67 -5
  11. package/dist/proxmox/lease-cache.d.ts.map +1 -1
  12. package/dist/proxmox/mint.d.ts +4 -2
  13. package/dist/proxmox/mint.d.ts.map +1 -1
  14. package/dist/proxmox/node-network.d.ts.map +1 -1
  15. package/dist/proxmox/role.d.ts.map +1 -1
  16. package/dist/proxmox/storage.d.ts.map +1 -1
  17. package/dist/proxmox/unreadable-read.d.ts +8 -1
  18. package/dist/proxmox/unreadable-read.d.ts.map +1 -1
  19. package/dist/proxmox/user.d.ts.map +1 -1
  20. package/dist/proxmox/zfs-pool.d.ts.map +1 -1
  21. package/docs/credentials.md +14 -1
  22. package/package.json +1 -1
  23. package/src/proxmox/acl.ts +7 -1
  24. package/src/proxmox/api-token.ts +7 -1
  25. package/src/proxmox/credential-errors.ts +19 -5
  26. package/src/proxmox/credentials.test.ts +73 -1
  27. package/src/proxmox/credentials.ts +72 -1
  28. package/src/proxmox/group.ts +7 -1
  29. package/src/proxmox/lease-cache-mint.test.ts +70 -0
  30. package/src/proxmox/lease-cache.test.ts +83 -7
  31. package/src/proxmox/lease-cache.ts +74 -10
  32. package/src/proxmox/mint.ts +12 -5
  33. package/src/proxmox/node-network.ts +7 -1
  34. package/src/proxmox/role.ts +7 -1
  35. package/src/proxmox/storage.ts +7 -1
  36. package/src/proxmox/unreadable-read.ts +16 -4
  37. package/src/proxmox/user.ts +7 -1
  38. package/src/proxmox/zfs-pool.ts +7 -1
@@ -1 +1 @@
1
- {"version":3,"file":"acl.d.ts","sourceRoot":"","sources":["../../src/proxmox/acl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAStE,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,cAAc,CAAC;IACrB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,+FAA+F;IAC/F,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAyB9D,eAAO,MAAM,kBAAkB,gIA6E5B,CAAC"}
1
+ {"version":3,"file":"acl.d.ts","sourceRoot":"","sources":["../../src/proxmox/acl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAI7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAUtE,4FAA4F;AAC5F,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAExD,MAAM,WAAW,QAAS,SAAQ,UAAU;IAC1C;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,sFAAsF;IACtF,IAAI,EAAE,cAAc,CAAC;IACrB,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,gGAAgG;IAChG,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,cAAc,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,+FAA+F;IAC/F,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAC1C,aAAa,EACb,QAAQ,EACR,aAAa,EACb,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,eAAO,MAAM,UAAU,6CAAsC,CAAC;AAyB9D,eAAO,MAAM,kBAAkB,gIAkF5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/proxmox/api-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAK7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAStE,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;OAYG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAKlB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,eAAe,kDAE1B,CAAC;AAuBH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,qIA8EjC,CAAC"}
1
+ {"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/proxmox/api-token.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAM7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAStE,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C;;;;;;;OAOG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;;OAYG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,8FAA8F;IAC9F,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,CAAC;CAKlB;AAED,MAAM,WAAW,eAAgB,SAAQ,QAAQ,CAC/C,kBAAkB,EAClB,aAAa,EACb,kBAAkB,EAClB,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ;;;;;GAKG;AACH,eAAO,MAAM,eAAe,kDAE1B,CAAC;AAuBH;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,qIAmFjC,CAAC"}
@@ -1,10 +1,9 @@
1
- import type { PveRole } from './credentials.ts';
2
1
  declare const PveCredentialDenied_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
3
2
  readonly _tag: "PveCredentialDenied";
4
3
  } & Readonly<A>;
5
4
  /**
6
- * OpenBao answered 403 to `GET /v1/<mount>/creds/<role>`: this identity's AppRole has no grant
7
- * for `role` on `mount` — measured 2026-09-24 as "the agent lane cannot mint `provision`" (the
5
+ * OpenBao answered 403 to `GET /v1/<mount>/creds/<tier>`: this identity's AppRole has no grant
6
+ * for `tier` on `mount` — measured 2026-09-24 as "the agent lane cannot mint `provision`" (the
8
7
  * lane's policy grants `read` but not `provision`). A TYPED tag, not the plain `Error` every
9
8
  * other mint failure still is (404 no such role/mount, 503 sealed, a network failure), because
10
9
  * this ONE case means "refused, not evidence of anything about the object" — a family's
@@ -15,10 +14,25 @@ declare const PveCredentialDenied_base: new <A extends Record<string, any> = {}>
15
14
  * BROKEN, not this identity being narrowly scoped — folding those into "unreadable, report
16
15
  * noop" would hide a real outage behind a quiet, misleadingly reassuring plan. Only 403 is
17
16
  * "this identity, this role, denied" and safe to read as "cannot see, not evidence of absence".
17
+ *
18
+ * ⛔ NO `role` FIELD (removed, K-T1 second red-team pass). `mint.ts` knows the semantic `PveRole`
19
+ * it was asked for, but `lease-cache.ts`'s synthetic `mintForKey` reconstruction (after M3
20
+ * dropped `role` from `LeaseKey`) cannot supply the ORIGINAL caller's role on a cache-path
21
+ * mint — only the tier. A `role` field would then read as `'read'` on every pve cache miss
22
+ * regardless of which role was actually denied, which is exactly the stale/misleading-field
23
+ * trap M6 existed to close, one layer down. `tier` alone is what the message reads and what
24
+ * `readOrUnreadable`'s callers act on; nothing needs the semantic role name.
18
25
  */
19
26
  export declare class PveCredentialDenied extends PveCredentialDenied_base<{
20
27
  readonly mount: string;
21
- readonly role: PveRole;
28
+ /**
29
+ * The OpenBao mint TIER actually requested (`credentials.ts`'s `mintTier`). ⛔ THE MESSAGE
30
+ * READS THIS, NOT A SEMANTIC ROLE NAME: printing `'read'` for a denied `talos-provision`
31
+ * mint would spell it as `creds/read`, exactly the path that was never called — silently
32
+ * wrong at precisely the moment an operator is reading this string to decide whether a
33
+ * grant, a policy or a target config is wrong (K-T1's own PR discussion).
34
+ */
35
+ readonly tier: string;
22
36
  readonly detail: string;
23
37
  }> {
24
38
  get message(): string;
@@ -1 +1 @@
1
- {"version":3,"file":"credential-errors.d.ts","sourceRoot":"","sources":["../../src/proxmox/credential-errors.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;;;;AAEhD;;;;;;;;;;;;;GAaG;AACH,qBAAa,mBAAoB,SAAQ,yBAAwC;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAK7B;CACF"}
1
+ {"version":3,"file":"credential-errors.d.ts","sourceRoot":"","sources":["../../src/proxmox/credential-errors.ts"],"names":[],"mappings":";;;AAMA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,mBAAoB,SAAQ,yBAAwC;IAC/E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,CAAC;IACA,IAAa,OAAO,IAAI,MAAM,CAK7B;CACF"}
@@ -85,8 +85,41 @@ export type PveTarget = {
85
85
  * and a wrong guess fails closed with a 401 rather than doing something odd.
86
86
  */
87
87
  readonly scheme: 'pve';
88
+ /**
89
+ * Overrides which OpenBao mint TIER NAME (`<mount>/creds/<tier>`) a semantic role resolves to.
90
+ * Omitted or missing a role: unchanged, `role` is also the tier name, as every consumer before
91
+ * this field got. Present: `mintTier` below reads it first.
92
+ *
93
+ * ★ WHY A TARGET-LEVEL OVERRIDE, NOT A THIRD `PveRole`. A consumer whose OpenBao mount vends a
94
+ * single least-privilege tier for BOTH read and write (one tier that can only ever reach the
95
+ * scope that consumer needs, rather than the estate's general `read`/`provision` split) sets
96
+ * `roles: { read: 'my-tier', provision: 'my-tier' }` and every read/diff/reconcile/delete this
97
+ * package already issues resolves to that tier, with no new call site anywhere in the package.
98
+ * Widening `PveRole` itself to a per-consumer string would instead touch every literal
99
+ * `'read'`/`'provision'` call site across the package (`client.ts`, `lxc-read.ts`,
100
+ * `lxc-task.ts`, `network-apply-read.ts`, `network-apply-run.ts`, `qemu-read.ts`,
101
+ * `qemu-task.ts`, `storage-download-task.ts` — the eight this field's `mintTier` indirection
102
+ * above already covers) for something only the TARGET, never the CALL, needs to know.
103
+ *
104
+ * ⛔ SET BOTH ROLES OR NEITHER (I2, red team on K-T1). An unmentioned role is NOT scoped down —
105
+ * it still mints the estate-wide tier this file's own header describes (`hf-provision@pve`,
106
+ * 27 privileges including `Permissions.Modify`/`Sys.Modify` for `provision`). Setting only
107
+ * `roles: { read: 'my-tier' }` leaves every reconcile/delete on this target minting that wide
108
+ * credential while the plan output looks fully scoped down — nothing here warns. See
109
+ * `docs/credentials.md`'s override paragraph for the same warning at the consumer-facing level.
110
+ */
111
+ readonly roles?: {
112
+ readonly read?: string;
113
+ readonly provision?: string;
114
+ };
88
115
  };
89
- /** The same client against a Proxmox Backup Server. See the ⛔ on `scheme` above. */
116
+ /**
117
+ * The same client against a Proxmox Backup Server. See the ⛔ on `scheme` above.
118
+ * ⛔ NO `roles` FIELD. The estate has no PBS consumer with a scoped tier yet, and a PBS mount
119
+ * vending only `read`/`provision` is the same shape `mint.ts` always assumed — `mintTier` below
120
+ * never overrides a PBS target for exactly that reason. Add the field here, the same way, when
121
+ * a PBS consumer needs it.
122
+ */
90
123
  export type PbsTarget = {
91
124
  readonly mount: string;
92
125
  readonly api: string;
@@ -94,6 +127,7 @@ export type PbsTarget = {
94
127
  };
95
128
  /** Either product. What `pve()` and `pveOperations` accept; what a RESOURCE accepts is narrower. */
96
129
  export type ApiTarget = PbsTarget | PveTarget;
130
+ export declare const mintTier: (target: ApiTarget, role: PveRole) => string;
97
131
  /**
98
132
  * What a mint returns.
99
133
  *
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/proxmox/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;;;;;;;;;;;;GAYG;AACH,uFAAuF;AACvF,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,oGAAoG;AACpG,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAE9C;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/proxmox/credentials.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH;;;;;;;;;;;;GAYG;AACH,uFAAuF;AACvF,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3C;;;;;;;GAOG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;IACvB;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE;QACf,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;KAC7B,CAAC;CACH,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC;CACxB,CAAC;AAEF,oGAAoG;AACpG,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AA0B9C,eAAO,MAAM,QAAQ,WAAY,SAAS,QAAQ,OAAO,KAAG,MAY3D,CAAC;AAEF;;;;;;;GAOG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,iGAAiG;AACjG,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/proxmox/group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAc7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAItE,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C;;;;;;;OAOG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,UAAU,EACV,eAAe,EACf,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,oGAAoG;AACpG,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,eAAO,MAAM,oBAAoB,kIA4F9B,CAAC"}
1
+ {"version":3,"file":"group.d.ts","sourceRoot":"","sources":["../../src/proxmox/group.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,KAAK,QAAQ,MAAM,kBAAkB,CAAC;AAc7C,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAKtE,MAAM,WAAW,UAAW,SAAQ,UAAU;IAC5C;;;;;;;OAOG;IACH,OAAO,EAAE,MAAM,CAAC;IAChB,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,YAAa,SAAQ,QAAQ,CAC5C,eAAe,EACf,UAAU,EACV,eAAe,EACf,KAAK,EACL,eAAe,CAChB;CAAG;AAEJ,oGAAoG;AACpG,eAAO,MAAM,YAAY,+CAEvB,CAAC;AAEH,eAAO,MAAM,oBAAoB,kIAiG9B,CAAC"}
@@ -1025,6 +1025,20 @@ import * as Duration from "effect/Duration";
1025
1025
  import * as Effect3 from "effect/Effect";
1026
1026
  import * as Exit from "effect/Exit";
1027
1027
 
1028
+ // src/proxmox/credentials.ts
1029
+ var VALID_TIER = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
1030
+ var mintTier = (target, role) => {
1031
+ if (target.scheme !== "pve")
1032
+ return role;
1033
+ const tier = target.roles?.[role];
1034
+ if (tier === undefined)
1035
+ return role;
1036
+ if (!VALID_TIER.test(tier)) {
1037
+ throw new Error(`PveTarget.roles.${role} = ${JSON.stringify(tier)} is not a valid OpenBao tier name -- ` + 'it would be interpolated straight into "<mount>/creds/<tier>" and must be a plain name ' + '(letters, digits, ".", "_", "-", not starting with one of those and not "..").');
1038
+ }
1039
+ return tier;
1040
+ };
1041
+
1028
1042
  // src/proxmox/mint.ts
1029
1043
  import * as Effect2 from "effect/Effect";
1030
1044
  import * as Option from "effect/Option";
@@ -1038,14 +1052,15 @@ import * as Data from "effect/Data";
1038
1052
 
1039
1053
  class PveCredentialDenied extends Data.TaggedError("PveCredentialDenied") {
1040
1054
  get message() {
1041
- return `OpenBao GET /v1/${this.mount}/creds/${this.role} -> 403: ${this.detail}. This identity's ` + "AppRole has no grant for this role -- a refused read, not evidence the object is gone.";
1055
+ return `OpenBao GET /v1/${this.mount}/creds/${this.tier} -> 403: ${this.detail}. This identity's ` + "AppRole has no grant for this role -- a refused read, not evidence the object is gone.";
1042
1056
  }
1043
1057
  }
1044
1058
 
1045
1059
  // src/proxmox/mint.ts
1046
1060
  var baoVariable = (env, name) => env[`BAO_${name}`] ?? env[`VAULT_${name}`] ?? "";
1047
1061
  var mint = (target, role, env = process.env) => Effect2.gen(function* () {
1048
- const path = `${target.mount}/creds/${role}`;
1062
+ const tier = mintTier(target, role);
1063
+ const path = `${target.mount}/creds/${tier}`;
1049
1064
  const refuse = (status2, detail) => new Error(`OpenBao GET /v1/${path} -> ${status2 === 0 ? "no response" : status2}: ${detail}`);
1050
1065
  const address = baoVariable(env, "AGENT_ADDR") || baoVariable(env, "ADDR") || "https://127.0.0.1:8200";
1051
1066
  const socket = address.startsWith("unix://") ? address.slice("unix://".length) : undefined;
@@ -1078,14 +1093,14 @@ var mint = (target, role, env = process.env) => Effect2.gen(function* () {
1078
1093
  const isOpenBaoBody = Array.isArray(errors);
1079
1094
  const detail = isOpenBaoBody ? errors.map(String).join("; ") : "not an OpenBao error body";
1080
1095
  if (status === 403 && isOpenBaoBody) {
1081
- return yield* Effect2.fail(new PveCredentialDenied({ detail, mount: target.mount, role }));
1096
+ return yield* Effect2.fail(new PveCredentialDenied({ detail, mount: target.mount, tier }));
1082
1097
  }
1083
1098
  return yield* Effect2.fail(refuse(status, detail || "(no errors given)"));
1084
1099
  }
1085
1100
  const tokenId = parsed?.data?.token_id;
1086
1101
  const secret = parsed?.data?.secret;
1087
1102
  if (typeof tokenId !== "string" || typeof secret !== "string") {
1088
- return yield* Effect2.fail(new Error(`${target.mount}/creds/${role} returned no token_id/secret. Either this approle lacks ` + `the grant, or the mount is not ${target.mount}. Say which mount and role you needed ` + `than falling back to a stored credential -- every stored PVE token is read-only.`));
1103
+ return yield* Effect2.fail(new Error(`${target.mount}/creds/${tier} returned no token_id/secret. Either this approle lacks ` + `the grant, or the mount is not ${target.mount}. Say which mount and role you needed ` + `than falling back to a stored credential -- every stored PVE token is read-only.`));
1089
1104
  }
1090
1105
  const lease = parsed?.lease_duration;
1091
1106
  const leaseSeconds = typeof lease === "number" ? lease : 0;
@@ -1097,13 +1112,14 @@ var authorization = (credential, target) => target.scheme === "pbs" ? `PBSAPITok
1097
1112
  var REMINT_MARGIN_SECONDS = 60;
1098
1113
  var keyOf = (target, role) => ({
1099
1114
  mount: target.mount,
1100
- role,
1101
- scheme: target.scheme
1115
+ scheme: target.scheme,
1116
+ tier: mintTier(target, role)
1102
1117
  });
1103
1118
  var timeToLive = (exit) => Exit.isSuccess(exit) && exit.value.leaseSeconds > REMINT_MARGIN_SECONDS ? Duration.seconds(exit.value.leaseSeconds - REMINT_MARGIN_SECONDS) : Duration.zero;
1104
1119
  var makeLeases = (mintFor) => Cache.makeWith(mintFor, { capacity: 64, requireServicesAt: "lookup", timeToLive });
1105
- var targetForKey = (key) => key.scheme === "pbs" ? { api: "https://pbs.invalid/api2/json", mount: key.mount, scheme: "pbs" } : { members: [], mount: key.mount, scheme: "pve" };
1106
- var leases = Effect3.runSync(makeLeases((key) => mint(targetForKey(key), key.role)));
1120
+ var targetForKey = (key) => key.scheme === "pbs" ? { api: "https://pbs.invalid/api2/json", mount: key.mount, scheme: "pbs" } : { members: [], mount: key.mount, roles: { read: key.tier }, scheme: "pve" };
1121
+ var mintForKey = (key, env = process.env) => mint(targetForKey(key), key.scheme === "pbs" ? key.tier : "read", env);
1122
+ var leases = Effect3.runSync(makeLeases(mintForKey));
1107
1123
  var leased = (target, role) => Cache.get(leases, keyOf(target, role));
1108
1124
 
1109
1125
  // src/proxmox/members.ts
@@ -1233,7 +1249,7 @@ var runPve = (target, role, isWrite, op) => Effect5.gen(function* () {
1233
1249
  import * as Effect6 from "effect/Effect";
1234
1250
  var UNREADABLE = Symbol("pve-unreadable");
1235
1251
  var readOrUnreadable = (effect) => effect.pipe(Effect6.catchTag("PveCredentialDenied", () => Effect6.succeed(UNREADABLE)));
1236
- var unreadableWarning = (type, identity2) => Effect6.logWarning(`${type} ${identity2}: the read was refused (no grant for this credential's role) -- ` + "reporting noop rather than forcing an update with nothing compared. Re-plan on a lane " + "that can read this object before trusting this row.");
1252
+ var unreadableWarning = (type, identity2, mount, tier) => Effect6.logWarning(`${type} ${identity2}: the read of ${mount}/creds/${tier} was refused (no grant for this ` + "credential's role) -- reporting noop rather than forcing an update with nothing compared. " + "Re-plan on a lane that can read this object before trusting this row.");
1237
1253
 
1238
1254
  // src/proxmox/acl.ts
1239
1255
  var ProxmoxAcl = Resource("Proxmox.Acl");
@@ -1255,7 +1271,7 @@ var ProxmoxAclProvider = () => Provider.effect(ProxmoxAcl, Effect7.succeed(Proxm
1255
1271
  return;
1256
1272
  const live = yield* readAttributes(news);
1257
1273
  if (live === UNREADABLE) {
1258
- yield* unreadableWarning("Proxmox.Acl", identity(news));
1274
+ yield* unreadableWarning("Proxmox.Acl", identity(news), news.target.mount, mintTier(news.target, "provision"));
1259
1275
  return { action: "noop" };
1260
1276
  }
1261
1277
  return live !== undefined && matches(live, news) ? { action: "noop" } : { action: "update" };
@@ -1425,7 +1441,7 @@ var ProxmoxApiTokenProvider = () => Provider2.effect(ProxmoxApiToken, Effect8.su
1425
1441
  return;
1426
1442
  const live = yield* readToken(news);
1427
1443
  if (live === UNREADABLE) {
1428
- yield* unreadableWarning("Proxmox.ApiToken", `${news.userid}!${news.tokenid}`);
1444
+ yield* unreadableWarning("Proxmox.ApiToken", `${news.userid}!${news.tokenid}`, news.target.mount, mintTier(news.target, "provision"));
1429
1445
  return { action: "noop" };
1430
1446
  }
1431
1447
  return live !== undefined && matches2(live, news) ? { action: "noop" } : { action: "update" };
@@ -2393,7 +2409,7 @@ var ProxmoxGroupProvider = () => Provider10.effect(ProxmoxGroup, Effect28.succee
2393
2409
  return;
2394
2410
  const live = yield* readGroupOrFail(news);
2395
2411
  if (live === UNREADABLE) {
2396
- yield* unreadableWarning("Proxmox.Group", news.groupid);
2412
+ yield* unreadableWarning("Proxmox.Group", news.groupid, news.target.mount, mintTier(news.target, "read"));
2397
2413
  return { action: "noop" };
2398
2414
  }
2399
2415
  if (live === undefined) {
@@ -3866,7 +3882,7 @@ var ProxmoxNodeNetworkProvider = () => Provider16.effect(ProxmoxNodeNetwork, Eff
3866
3882
  return;
3867
3883
  const live = yield* readInterfaceOrFail(news);
3868
3884
  if (live === UNREADABLE) {
3869
- yield* unreadableWarning("Proxmox.NodeNetwork", `${news.node}/${news.iface}`);
3885
+ yield* unreadableWarning("Proxmox.NodeNetwork", `${news.node}/${news.iface}`, news.target.mount, mintTier(news.target, "read"));
3870
3886
  return { action: "noop" };
3871
3887
  }
3872
3888
  if (live === undefined) {
@@ -5801,7 +5817,7 @@ var ProxmoxRoleProvider = () => Provider26.effect(ProxmoxRole, Effect78.succeed(
5801
5817
  return;
5802
5818
  const live = yield* readRole(news);
5803
5819
  if (live === UNREADABLE) {
5804
- yield* unreadableWarning("Proxmox.Role", news.roleid);
5820
+ yield* unreadableWarning("Proxmox.Role", news.roleid, news.target.mount, mintTier(news.target, "read"));
5805
5821
  return { action: "noop" };
5806
5822
  }
5807
5823
  if (live === undefined) {
@@ -5901,7 +5917,7 @@ var ProxmoxUserProvider = () => Provider27.effect(ProxmoxUser, Effect80.succeed(
5901
5917
  return;
5902
5918
  const live = yield* readUserOrFail(news);
5903
5919
  if (live === UNREADABLE) {
5904
- yield* unreadableWarning("Proxmox.User", news.userid);
5920
+ yield* unreadableWarning("Proxmox.User", news.userid, news.target.mount, mintTier(news.target, "read"));
5905
5921
  return { action: "noop" };
5906
5922
  }
5907
5923
  if (live === undefined) {
@@ -6989,7 +7005,7 @@ var ProxmoxStorageProvider = () => Provider35.effect(ProxmoxStorage, Effect97.su
6989
7005
  return;
6990
7006
  const live = yield* readStorageOrFail(news);
6991
7007
  if (live === UNREADABLE) {
6992
- yield* unreadableWarning("Proxmox.Storage", news.storage);
7008
+ yield* unreadableWarning("Proxmox.Storage", news.storage, news.target.mount, mintTier(news.target, "provision"));
6993
7009
  return { action: "noop" };
6994
7010
  }
6995
7011
  if (live === undefined) {
@@ -7112,7 +7128,7 @@ var ProxmoxZfsPoolProvider = () => Provider36.effect(ProxmoxZfsPool, Effect100.s
7112
7128
  return;
7113
7129
  const live = yield* readPoolOrFail(news);
7114
7130
  if (live === UNREADABLE) {
7115
- yield* unreadableWarning("Proxmox.ZfsPool", `${news.node}/${news.name}`);
7131
+ yield* unreadableWarning("Proxmox.ZfsPool", `${news.node}/${news.name}`, news.target.mount, mintTier(news.target, "read"));
7116
7132
  return { action: "noop" };
7117
7133
  }
7118
7134
  if (live === undefined) {
@@ -7207,5 +7223,5 @@ export {
7207
7223
  violations
7208
7224
  };
7209
7225
 
7210
- //# debugId=23CD7F01601D5A3A64756E2164756E21
7226
+ //# debugId=71934628F9E3FB7664756E2164756E21
7211
7227
  //# sourceMappingURL=index.js.map