@homeflare/alchemy 0.44.0 → 0.46.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/dist/postgres/fake-role-sql.d.ts +2 -1
- package/dist/postgres/fake-role-sql.d.ts.map +1 -1
- package/dist/postgres/fake-sql.d.ts +3 -3
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/index.d.ts +1 -1
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +117 -94
- package/dist/postgres/index.js.map +11 -11
- package/dist/postgres/role-attrs.d.ts +7 -4
- package/dist/postgres/role-attrs.d.ts.map +1 -1
- package/dist/postgres/role-diff.d.ts +2 -2
- package/dist/postgres/role-diff.d.ts.map +1 -1
- package/dist/postgres/role-errors.d.ts +13 -7
- package/dist/postgres/role-errors.d.ts.map +1 -1
- package/dist/postgres/role-membership-sql.d.ts +30 -27
- package/dist/postgres/role-membership-sql.d.ts.map +1 -1
- package/dist/postgres/role-provider.d.ts.map +1 -1
- package/dist/postgres/role-scram.d.ts +2 -0
- package/dist/postgres/role-scram.d.ts.map +1 -1
- package/dist/postgres/role-secrets.d.ts +8 -0
- package/dist/postgres/role-secrets.d.ts.map +1 -1
- package/dist/postgres/role-sql.d.ts.map +1 -1
- package/dist/postgres/role.d.ts +2 -2
- package/dist/postgres/role.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/index.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-access.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-backup.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-firewall.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-ha.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-metrics.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-notifications.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-replication.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-cluster-sdn.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-ceph.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-disks.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-lxc.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-network.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-qemu.d.ts.map +1 -1
- package/dist/proxmox/generated/constraints/pve-nodes-storage.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-pools.d.ts +1 -1
- package/dist/proxmox/generated/constraints/pve-storage.d.ts +1 -1
- package/dist/proxmox/index.d.ts +1 -0
- package/dist/proxmox/index.d.ts.map +1 -1
- package/dist/proxmox/index.js +283 -130
- package/dist/proxmox/index.js.map +31 -27
- package/dist/proxmox/qemu-dns.d.ts +2 -0
- package/dist/proxmox/qemu-dns.d.ts.map +1 -0
- package/dist/proxmox/qemu-errors.d.ts +1 -0
- package/dist/proxmox/qemu-errors.d.ts.map +1 -1
- package/dist/proxmox/qemu-form.d.ts.map +1 -1
- package/dist/proxmox/qemu-judge.d.ts.map +1 -1
- package/dist/proxmox/qemu-lifecycle.d.ts +15 -10
- package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/qemu-props.d.ts +10 -0
- package/dist/proxmox/qemu-props.d.ts.map +1 -1
- package/dist/proxmox/qemu-resize.d.ts +10 -0
- package/dist/proxmox/qemu-resize.d.ts.map +1 -0
- package/dist/proxmox/qemu-size.d.ts +20 -0
- package/dist/proxmox/qemu-size.d.ts.map +1 -0
- package/dist/proxmox/qemu-spec.d.ts +25 -0
- package/dist/proxmox/qemu-spec.d.ts.map +1 -0
- package/dist/verify/fake-engine.d.ts +4 -2
- package/dist/verify/fake-engine.d.ts.map +1 -1
- package/docs/postgres-role.md +18 -6
- package/docs/proxmox-qemu-resize.md +62 -0
- package/package.json +1 -1
- package/src/ceph/ceph-argv.test.ts +1 -1
- package/src/launchd/sudo-allowlist.test.ts +2 -2
- package/src/linux/sudo-allowlist.test.ts +3 -3
- package/src/linux/sudo-runner.test.ts +2 -2
- package/src/postgres/fake-role-sql.ts +26 -6
- package/src/postgres/fake-sql.ts +10 -5
- package/src/postgres/index.ts +1 -0
- package/src/postgres/role-attrs.ts +7 -4
- package/src/postgres/role-diff.ts +7 -3
- package/src/postgres/role-errors.ts +22 -14
- package/src/postgres/role-guard.test.ts +3 -3
- package/src/postgres/role-identity.test.ts +14 -2
- package/src/postgres/role-lifecycle.test.ts +2 -2
- package/src/postgres/role-membership-options.test.ts +73 -0
- package/src/postgres/role-membership-repair.test.ts +153 -0
- package/src/postgres/role-membership-sql.ts +88 -63
- package/src/postgres/role-password-ascii.test.ts +53 -0
- package/src/postgres/role-password-transports.test.ts +123 -0
- package/src/postgres/role-privilege.test.ts +37 -10
- package/src/postgres/role-provenance.test.ts +1 -1
- package/src/postgres/role-provider.ts +3 -2
- package/src/postgres/role-refusals.test.ts +0 -25
- package/src/postgres/role-scram.ts +2 -0
- package/src/postgres/role-secrets.ts +15 -0
- package/src/postgres/role-sql.ts +3 -1
- package/src/postgres/role.ts +9 -1
- package/src/postgres/schema-socket.test.ts +1 -0
- package/src/proxmox/generated/constraints/index.ts +1 -1
- package/src/proxmox/generated/constraints/pve-access.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-backup.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-firewall.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-ha.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-metrics.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-notifications.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-replication.ts +1 -1
- package/src/proxmox/generated/constraints/pve-cluster-sdn.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-ceph.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-disks.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-lxc.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-network.ts +1 -1
- package/src/proxmox/generated/constraints/pve-nodes-qemu.ts +6 -1
- package/src/proxmox/generated/constraints/pve-nodes-storage.ts +1 -1
- package/src/proxmox/generated/constraints/pve-pools.ts +1 -1
- package/src/proxmox/generated/constraints/pve-storage.ts +1 -1
- package/src/proxmox/index.ts +1 -0
- package/src/proxmox/qemu-dns.test.ts +73 -0
- package/src/proxmox/qemu-dns.ts +32 -0
- package/src/proxmox/qemu-errors.ts +1 -0
- package/src/proxmox/qemu-form.ts +6 -3
- package/src/proxmox/qemu-judge.ts +2 -1
- package/src/proxmox/qemu-lifecycle.ts +28 -47
- package/src/proxmox/qemu-props.ts +14 -2
- package/src/proxmox/qemu-resize-lock.test.ts +121 -0
- package/src/proxmox/qemu-resize-recovery.test.ts +81 -0
- package/src/proxmox/qemu-resize.test.ts +199 -0
- package/src/proxmox/qemu-resize.ts +86 -0
- package/src/proxmox/qemu-size.test.ts +64 -0
- package/src/proxmox/qemu-size.ts +95 -0
- package/src/proxmox/qemu-spec.ts +44 -0
- package/src/proxmox/qemu-volume.ts +5 -5
- package/src/verify/fake-engine.ts +6 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-dns.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-dns.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,WAAW,eAAgB,OAAO,KAAG,MAAM,EAQvD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qemu-errors.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-errors.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
|
|
1
|
+
{"version":3,"file":"qemu-errors.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-errors.ts"],"names":[],"mappings":"AAAA,yFAAyF;AACzF,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,IAAI,sBAAsB;IACnC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qemu-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-form.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"qemu-form.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-form.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EACL,KAAK,OAAO,EAKb,MAAM,iBAAiB,CAAC;AAGzB;;;;GAIG;AACH,eAAO,MAAM,YAAY,UAAW,OAAO,KAAG,MAAM,EAKnD,CAAC;AAEF,2FAA2F;AAC3F,eAAO,MAAM,IAAI,UAAW,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAO1D,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,UAAU,UAAW,OAAO;;CAGvC,CAAC;AAEH,qGAAqG;AACrG,eAAO,MAAM,UAAU,aAAO,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qemu-judge.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,KAAK,OAAO,EAAsD,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"qemu-judge.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,KAAK,OAAO,EAAsD,MAAM,iBAAiB,CAAC;AAKnG,MAAM,MAAM,QAAQ,GAAG;IACrB,mFAAmF;IACnF,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oFAAoF;IACpF,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,iEAAiE;IACjE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC,CAAC;AAEF,eAAO,MAAM,KAAK,UAAW,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,QA8CtE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,SAAU,MAAM,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAI1B,CAAC"}
|
|
@@ -1,40 +1,45 @@
|
|
|
1
1
|
import type { Input } from 'alchemy/Input';
|
|
2
2
|
import * as nodes from '@distilled.cloud/proxmox/nodes';
|
|
3
3
|
import * as Effect from 'effect/Effect';
|
|
4
|
-
import
|
|
5
|
-
|
|
4
|
+
import type * as HttpClient from 'effect/unstable/http/HttpClient';
|
|
5
|
+
import { QemuRefusedError } from './qemu-errors.ts';
|
|
6
|
+
import type { VmAttributes, VmProps } from './qemu-props.ts';
|
|
7
|
+
import { type QemuDiskResizeRefused } from './qemu-size.ts';
|
|
8
|
+
type QemuLifecycleError = Effect.Error<ReturnType<typeof readQemu>> | nodes.PutNodeQemuResizeError | QemuRefusedError | QemuDiskResizeRefused;
|
|
9
|
+
export declare const readQemu: (props: VmProps) => Effect.Effect<VmAttributes | undefined, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, HttpClient.HttpClient>;
|
|
6
10
|
/** No purge, no skiplock, no destroy-unreferenced-disks. A missing config is already gone. */
|
|
7
|
-
export declare const deleteQemu: (props: VmProps) => Effect.Effect<void | undefined, Error | import("./credential-errors.ts").PveCredentialDenied | nodes.ProxmoxOpError,
|
|
11
|
+
export declare const deleteQemu: (props: VmProps) => Effect.Effect<void | undefined, Error | import("./credential-errors.ts").PveCredentialDenied | nodes.ProxmoxOpError, HttpClient.HttpClient>;
|
|
8
12
|
export declare const qemuHandlers: {
|
|
9
13
|
list: () => Effect.Effect<never[], never, never>;
|
|
10
14
|
/**
|
|
11
15
|
* ⛔ `Unowned` UNLESS STATE ALREADY VOUCHES FOR IT (C2). With no attributes this is Alchemy's
|
|
12
16
|
* adoption probe or the recovery read for an interrupted create (ownership/probe.ts); `settled`
|
|
13
|
-
*
|
|
14
|
-
*
|
|
17
|
+
* uses the same config comparison as reconcile. Disk growth is a post-create step, so its
|
|
18
|
+
* drift cannot disown a VM after an interrupted/failed resize (measured 2026-10-05).
|
|
15
19
|
*/
|
|
16
20
|
read: (args_0: {
|
|
17
21
|
fqn: string;
|
|
18
22
|
instanceId: string;
|
|
19
23
|
olds: VmProps;
|
|
20
24
|
output: VmAttributes | undefined;
|
|
21
|
-
}) => Effect.Effect<VmAttributes | undefined, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied,
|
|
25
|
+
}) => Effect.Effect<VmAttributes | undefined, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, HttpClient.HttpClient>;
|
|
22
26
|
diff: (args_0: {
|
|
23
27
|
news: Input<VmProps>;
|
|
24
28
|
olds: VmProps;
|
|
25
29
|
output: VmAttributes | undefined;
|
|
26
30
|
}) => Effect.Effect<{
|
|
27
|
-
readonly action:
|
|
28
|
-
} | undefined,
|
|
31
|
+
readonly action: 'noop' | 'update';
|
|
32
|
+
} | undefined, QemuLifecycleError, HttpClient.HttpClient>;
|
|
29
33
|
reconcile: (args_0: {
|
|
30
34
|
fqn: string;
|
|
31
35
|
instanceId: string;
|
|
32
36
|
news: VmProps;
|
|
33
37
|
olds: VmProps | undefined;
|
|
34
38
|
output: VmAttributes | undefined;
|
|
35
|
-
}) => Effect.Effect<VmAttributes,
|
|
39
|
+
}) => Effect.Effect<VmAttributes, QemuLifecycleError, HttpClient.HttpClient>;
|
|
36
40
|
delete: ({ olds }: {
|
|
37
41
|
olds: VmProps;
|
|
38
|
-
}) => Effect.Effect<void | undefined, Error | import("./credential-errors.ts").PveCredentialDenied | nodes.ProxmoxOpError,
|
|
42
|
+
}) => Effect.Effect<void | undefined, Error | import("./credential-errors.ts").PveCredentialDenied | nodes.ProxmoxOpError, HttpClient.HttpClient>;
|
|
39
43
|
};
|
|
44
|
+
export {};
|
|
40
45
|
//# sourceMappingURL=qemu-lifecycle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qemu-lifecycle.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-lifecycle.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"qemu-lifecycle.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-lifecycle.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,KAAK,KAAK,MAAM,gCAAgC,CAAC;AACxD,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,UAAU,MAAM,iCAAiC,CAAC;AAKnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAI7D,OAAO,EAAE,KAAK,qBAAqB,EAAyC,MAAM,gBAAgB,CAAC;AAOnG,KAAK,kBAAkB,GACnB,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,GACzC,KAAK,CAAC,sBAAsB,GAC5B,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,eAAO,MAAM,QAAQ,UAAW,OAAO,kMAapC,CAAC;AAEJ,8FAA8F;AAC9F,eAAO,MAAM,UAAU,UAAW,OAAO,gJAMyB,CAAC;AAmBnE,eAAO,MAAM,YAAY;IACvB,IAAI;IACJ;;;;;OAKG;IACH,IAAI;aAMG,MAAM;oBACC,MAAM;cACZ,OAAO;gBACL,YAAY,GAAG,SAAS;;IAUlC,IAAI;cAKI,KAAK,CAAC,OAAO,CAAC;cACd,OAAO;gBACL,YAAY,GAAG,SAAS;;yBAEb,MAAM,GAAG,QAAQ;;IA4BtC,SAAS;aAOF,MAAM;oBACC,MAAM;cACZ,OAAO;cACP,OAAO,GAAG,SAAS;gBACjB,YAAY,GAAG,SAAS;;IAuDlC,MAAM,aAAa;QAAE,IAAI,EAAE,OAAO,CAAA;KAAE;CACrC,CAAC"}
|
|
@@ -46,6 +46,16 @@ export interface VmProps extends WithTarget {
|
|
|
46
46
|
boot?: string;
|
|
47
47
|
/** e.g. `virtio-scsi-single`. */
|
|
48
48
|
scsihw?: string;
|
|
49
|
+
/** Cloud-init DNS servers: PVE's `address-list` (IP addresses or DNS names). */
|
|
50
|
+
nameserver?: string;
|
|
51
|
+
/** Cloud-init DNS search domains, in PVE's wire spelling. */
|
|
52
|
+
searchdomain?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Minimum disk sizes in GiB, e.g. `{ scsi0: 64 }`, grown after import completes.
|
|
55
|
+
* Existing larger disks are left alone. Lowering a previously declared target is refused.
|
|
56
|
+
* These are resize targets, never config fields; declare the corresponding disk slot too.
|
|
57
|
+
*/
|
|
58
|
+
diskSizesGiB?: Partial<Record<`scsi${number}` | `ide${number}`, number>>;
|
|
49
59
|
/**
|
|
50
60
|
* `local-zfs:32` to create a new volume, or the live volume string as adopted —
|
|
51
61
|
* `cephtb4:vm-101-disk-0,size=32G` (n is 0 to 30, pve-qemu-server's own `$MAX_SCSI_DISKS`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"qemu-props.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-props.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,kGAAkG;AAClG,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,OAAQ,SAAQ,UAAU;IACzC,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,CAAC,IAAI,EAAE,OAAO,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,CAAC,GAAG,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,CAAC,SAAS,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAChD,mFAAmF;IACnF,CAAC,QAAQ,EAAE,WAAW,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD,gFAAgF;IAChF,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAChD,kCAAkC;IAClC,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,wCAAwC;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAKD,8FAA8F;AAC9F,eAAO,MAAM,OAAO;aAClB,GAAG,EAAE,CAAC;aACN,QAAQ,EAAE,EAAE;aACZ,GAAG,EAAE,EAAE;aACP,IAAI,EAAE,EAAE;aACR,MAAM,EAAE,CAAC;CACD,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,OAAO,CAAC;AAEjD,4FAA4F;AAC5F,eAAO,MAAM,UAAU,QAAS,MAAM,KAAG,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,SAM3E,CAAC;
|
|
1
|
+
{"version":3,"file":"qemu-props.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-props.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,kGAAkG;AAClG,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,OAAQ,SAAQ,UAAU;IACzC,uFAAuF;IACvF,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yFAAyF;IACzF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+BAA+B;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,MAAM,EAAE,GAAG,MAAM,MAAM,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IACzE;;;OAGG;IACH,CAAC,IAAI,EAAE,OAAO,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC5C;;;OAGG;IACH,CAAC,GAAG,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAC1C;;;;OAIG;IACH,CAAC,SAAS,EAAE,MAAM,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAChD,mFAAmF;IACnF,CAAC,QAAQ,EAAE,WAAW,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IACpD,gFAAgF;IAChF,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;IAChD,kCAAkC;IAClC,UAAU,CAAC,EAAE,KAAK,CAAC;IACnB,wCAAwC;IACxC,OAAO,CAAC,EAAE,KAAK,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAKD,8FAA8F;AAC9F,eAAO,MAAM,OAAO;aAClB,GAAG,EAAE,CAAC;aACN,QAAQ,EAAE,EAAE;aACZ,GAAG,EAAE,EAAE;aACP,IAAI,EAAE,EAAE;aACR,MAAM,EAAE,CAAC;CACD,CAAC;AACX,MAAM,MAAM,aAAa,GAAG,MAAM,OAAO,OAAO,CAAC;AAEjD,4FAA4F;AAC5F,eAAO,MAAM,UAAU,QAAS,MAAM,KAAG,SAAS,CAAC,aAAa,EAAE,MAAM,CAAC,GAAG,SAM3E,CAAC;AAiBF;;;;;GAKG;AACH,eAAO,MAAM,YAAY,QAAS,MAAM,KAAG,OACY,CAAC;AAExD,6GAA6G;AAC7G,eAAO,MAAM,aAAa,UAAW,OAAO,OAAO,MAAM,KAAG,OACR,CAAC;AAErD,wFAAwF;AACxF,eAAO,MAAM,YAAY,UAAW,OAAO,KAAG,MAAM,EAGzC,CAAC;AAEZ,iGAAiG;AACjG,eAAO,MAAM,SAAS,UAAW,OAAO,KAAG,MACmB,CAAC;AAE/D;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAQjF,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import { type VmProps } from './qemu-props.ts';
|
|
3
|
+
/**
|
|
4
|
+
* ⛔ Observe the unlocked, allocated disk before each resize, including recovery after import.
|
|
5
|
+
* Absolute targets make retries safe; `+60G` would grow again after interrupted state writes.
|
|
6
|
+
* This resource never starts a guest. Its caller can power on only after reconcile returns.
|
|
7
|
+
* SDK failures retain their generated tags; provider refusals are QemuDiskResizeRefused.
|
|
8
|
+
*/
|
|
9
|
+
export declare const resizeDisks: (props: VmProps) => Effect.Effect<undefined, Error | import("effect/unstable/http/HttpClientError").HttpClientError | import("./credential-errors.ts").PveCredentialDenied, import("effect/unstable/http/HttpClient").HttpClient>;
|
|
10
|
+
//# sourceMappingURL=qemu-resize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-resize.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-resize.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,OAAO,EAAgB,MAAM,iBAAiB,CAAC;AAqC7D;;;;;GAKG;AACH,eAAO,MAAM,WAAW,UAAW,OAAO,kNAuCtC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Effect from 'effect/Effect';
|
|
2
|
+
import { type VmProps } from './qemu-props.ts';
|
|
3
|
+
declare const QemuDiskResizeRefused_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 & {
|
|
4
|
+
readonly _tag: "QemuDiskResizeRefused";
|
|
5
|
+
} & Readonly<A>;
|
|
6
|
+
export declare class QemuDiskResizeRefused extends QemuDiskResizeRefused_base<{
|
|
7
|
+
readonly disk: string;
|
|
8
|
+
readonly message: string;
|
|
9
|
+
}> {
|
|
10
|
+
}
|
|
11
|
+
/** PVE config reports binary sizes, including fractional G and integer M/K for imported images. */
|
|
12
|
+
export declare const diskBytes: (config: string | undefined) => number | undefined;
|
|
13
|
+
/** Validate the whole declaration before any write, including a later attempted target decrease. */
|
|
14
|
+
export declare const validateDiskSizes: (props: VmProps, olds?: VmProps) => Effect.Effect<undefined, QemuDiskResizeRefused, never>;
|
|
15
|
+
/** Capacity drift drives reconcile; recovery ownership ignores it because resize follows create. */
|
|
16
|
+
export declare const diskSizeDrift: (props: VmProps, config: Record<string, string>) => string[];
|
|
17
|
+
/** Missing slots may be imported by the upcoming config write; unreadable existing sizes fail closed. */
|
|
18
|
+
export declare const checkLiveDiskSizes: (props: VmProps, config: Record<string, string>, allowMissing?: boolean) => Effect.Effect<undefined, QemuDiskResizeRefused, never>;
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=qemu-size.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-size.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-size.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,KAAK,OAAO,EAA6B,MAAM,iBAAiB,CAAC;;;;AAG1E,qBAAa,qBAAsB,SAAQ,2BAA0C;IACnF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;CAAG;AAEL,mGAAmG;AACnG,eAAO,MAAM,SAAS,WAAY,MAAM,GAAG,SAAS,KAAG,MAAM,GAAG,SAO/D,CAAC;AAEF,oGAAoG;AACpG,eAAO,MAAM,iBAAiB,UAAW,OAAO,SAAS,OAAO,2DAwC5D,CAAC;AAEL,oGAAoG;AACpG,eAAO,MAAM,aAAa,UAAW,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAAM,EAKzC,CAAC;AAE7C,yGAAyG;AACzG,eAAO,MAAM,kBAAkB,UACtB,OAAO,UACN,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,mFAmB5B,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/** QEMU config forms and vendor guards, separated from lifecycle to keep both reviewable. */
|
|
2
|
+
import { createForm } from './qemu-form.ts';
|
|
3
|
+
import { type VmAttributes, type VmProps } from './qemu-props.ts';
|
|
4
|
+
export declare const attributesOf: (live: Record<string, unknown>, props: VmProps) => VmAttributes;
|
|
5
|
+
/**
|
|
6
|
+
* ⚠️ KEPT ONLY TO SATISFY `PveSpec`'S REQUIRED FIELD — `qemu-judge.ts`'s `judge` is what diff and
|
|
7
|
+
* reconcile actually decide by, since a plain string compare is exactly the bug C1 found (it
|
|
8
|
+
* never matches the "new disk" or MAC-less spellings a declaration may use).
|
|
9
|
+
*/
|
|
10
|
+
declare const matches: (attributes: VmAttributes, props: VmProps) => boolean;
|
|
11
|
+
export declare const spec: {
|
|
12
|
+
attributes: typeof attributesOf;
|
|
13
|
+
collection: (props: VmProps) => string;
|
|
14
|
+
createForm: typeof createForm;
|
|
15
|
+
endpoint: {
|
|
16
|
+
create: string;
|
|
17
|
+
update: string;
|
|
18
|
+
};
|
|
19
|
+
matches: typeof matches;
|
|
20
|
+
path: (props: VmProps) => string;
|
|
21
|
+
updateForm: typeof import("./qemu-form.ts").form;
|
|
22
|
+
};
|
|
23
|
+
export declare const guardCreate: (props: VmProps, presence: boolean) => import("effect/Effect").Effect<void>, guardUpdate: (props: VmProps) => import("effect/Effect").Effect<void>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=qemu-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qemu-spec.d.ts","sourceRoot":"","sources":["../../src/proxmox/qemu-spec.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,OAAO,EAAE,UAAU,EAAc,MAAM,gBAAgB,CAAC;AACxD,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,OAAO,EAMb,MAAM,iBAAiB,CAAC;AAIzB,eAAO,MAAM,YAAY,SAAU,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,OAAO,KAAG,YAI3E,CAAC;AAEH;;;;GAIG;AACH,QAAA,MAAM,OAAO,eAAgB,YAAY,SAAS,OAAO,YAG2B,CAAC;AAErF,eAAO,MAAM,IAAI;;wBAEK,OAAO;;;QAGzB,MAAM;QACN,MAAM;;;kBAGM,OAAO;;CAEmB,CAAC;AAE3C,eAAO,MAAQ,WAAW,+EAAE,WAAW,0DAAqB,CAAC"}
|
|
@@ -53,7 +53,7 @@ export type DriftRow = {
|
|
|
53
53
|
readonly action: string;
|
|
54
54
|
};
|
|
55
55
|
export interface FakeEngine {
|
|
56
|
-
/** Plan and apply `body
|
|
56
|
+
/** Plan and apply `body` with the configured adoption policy; resolves to planned actions. */
|
|
57
57
|
readonly deploy: (body: Body) => Promise<Record<string, string>>;
|
|
58
58
|
/** Verify `body` against what the earlier deploys recorded. */
|
|
59
59
|
readonly verify: (body: Body, options?: VerifyOptions) => Promise<AdoptReport>;
|
|
@@ -78,7 +78,9 @@ export interface FakeEngine {
|
|
|
78
78
|
* hands in its real provider over a fake transport (proxmox/ceph-pool-adopt.test.ts).
|
|
79
79
|
* ⚠️ THE CASTS ARE AT THE ENGINE'S TYPED BOUNDARY — openbao/fake-stack.ts has the reasoning.
|
|
80
80
|
*/
|
|
81
|
-
export declare const engineOver: <ROut, E, RIn>(layer: Layer.Layer<ROut, E, RIn
|
|
81
|
+
export declare const engineOver: <ROut, E, RIn>(layer: Layer.Layer<ROut, E, RIn>, options?: {
|
|
82
|
+
readonly adopt?: boolean;
|
|
83
|
+
}) => FakeEngine;
|
|
82
84
|
/** The fake family over `cloud`. */
|
|
83
85
|
export declare const fakeEngine: (cloud: Cloud) => FakeEngine;
|
|
84
86
|
//# sourceMappingURL=fake-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-engine.d.ts","sourceRoot":"","sources":["../../src/verify/fake-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAiB,MAAM,aAAa,CAAC;AAElF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,KAAM,SAAQ,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AAC7F,eAAO,MAAM,KAAK,8BAAwC,CAAC;AAE3D,4EAA4E;AAC5E,MAAM,WAAW,KAAM,SAAQ,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AAC7F,eAAO,MAAM,KAAK,8BAAwC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,QAAS,SAAQ,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AACnG,eAAO,MAAM,QAAQ,iCAA8C,CAAC;AAEpE,gGAAgG;AAChG,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAQ,KAI1D,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,UAAW,KAAK,KAAG,MAAM,EAC2C,CAAC;AAyB1F,4FAA4F;AAC5F,eAAO,MAAM,cAAc,UAAW,KAAK,8GAmCxC,CAAC;AAEJ,oFAAoF;AACpF,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAK5D,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,
|
|
1
|
+
{"version":3,"file":"fake-engine.d.ts","sourceRoot":"","sources":["../../src/verify/fake-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAKnC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAiB,MAAM,aAAa,CAAC;AAElF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,KAAM,SAAQ,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AAC7F,eAAO,MAAM,KAAK,8BAAwC,CAAC;AAE3D,4EAA4E;AAC5E,MAAM,WAAW,KAAM,SAAQ,OAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AAC7F,eAAO,MAAM,KAAK,8BAAwC,CAAC;AAE3D;;;;GAIG;AACH,MAAM,WAAW,QAAS,SAAQ,OAAO,CAAC,QAAQ,CAAC,eAAe,EAAE,UAAU,EAAE,eAAe,CAAC;CAAG;AACnG,eAAO,MAAM,QAAQ,iCAA8C,CAAC;AAEpE,gGAAgG;AAChG,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,eAAO,MAAM,OAAO,UAAU,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAQ,KAI1D,CAAC;AAEH,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,UAAW,KAAK,KAAG,MAAM,EAC2C,CAAC;AAyB1F,4FAA4F;AAC5F,eAAO,MAAM,cAAc,UAAW,KAAK,8GAmCxC,CAAC;AAEJ,oFAAoF;AACpF,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAK5D,gGAAgG;AAChG,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnD,MAAM,WAAW,UAAU;IACzB,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjE,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,aAAa,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC/E;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClE;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC;CAC/B;AAED;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,IAAI,EAAE,CAAC,EAAE,GAAG,SAC9B,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,YACvB;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,KACpC,UAmDF,CAAC;AAEF,oCAAoC;AACpC,eAAO,MAAM,UAAU,UAAW,KAAK,KAAG,UAA+C,CAAC"}
|
package/docs/postgres-role.md
CHANGED
|
@@ -26,16 +26,26 @@ run yourself. The `Postgres.Database` resource in this kit already binds `@effec
|
|
|
26
26
|
never re-sends a secret that already matches, and never stores one. A create that declares a
|
|
27
27
|
password but whose variable is unset refuses before any write
|
|
28
28
|
(`PostgresRolePasswordEnvUnsetError`), including the retry of a create whose password statement
|
|
29
|
-
never sealed.
|
|
29
|
+
never sealed. Non-ASCII passwords fail typed before writes (`PostgresRolePasswordNonAsciiRefused`):
|
|
30
|
+
PostgreSQL applies SASLprep, and this provider does not implement that normalization.
|
|
30
31
|
- **Membership is `pg_auth_members`, compared as a sorted set.** `memberOf` omitted leaves live
|
|
31
32
|
memberships alone; `[]` ensures none. Moves run through one-parent `GRANT`/`REVOKE`
|
|
32
33
|
(`alter_role.sgml`: "there are no options for adding or removing memberships; use GRANT and
|
|
33
34
|
REVOKE"). A plain `REVOKE` only removes the session grantor's row (`plan_single_revoke` matches
|
|
34
35
|
`grantor`); each unwanted row is `REVOKE … GRANTED BY` its own grantor. A wanted row that is
|
|
35
|
-
`WITH ADMIN
|
|
36
|
-
`
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
`WITH ADMIN`, still `SET TRUE`, or `INHERIT TRUE` when `inherit:false` is declared is repaired
|
|
37
|
+
with `REVOKE ADMIN/SET/INHERIT OPTION FOR … GRANTED BY … RESTRICT`. Unwanted-row revokes commit
|
|
38
|
+
first, then each retained row's options share a repair transaction. SQLSTATE 2BP01/42501 becomes
|
|
39
|
+
`PostgresRoleMembershipUnrepaired` naming that parent and grantor, preserving refused options
|
|
40
|
+
and dependent rows without rolling back unwanted-row revokes. No CASCADE is issued.
|
|
41
|
+
Option repair was measured once by hand on a throwaway PostgreSQL 17.11 (2026-10-02);
|
|
42
|
+
automated tests stub the 2BP01/42501 responses. Semantics: PostgreSQL
|
|
43
|
+
[16 GRANT](https://www.postgresql.org/docs/16/sql-grant.html) / [REVOKE](https://www.postgresql.org/docs/16/sql-revoke.html),
|
|
44
|
+
[17 GRANT](https://www.postgresql.org/docs/17/sql-grant.html) / [REVOKE](https://www.postgresql.org/docs/17/sql-revoke.html),
|
|
45
|
+
[18 GRANT](https://www.postgresql.org/docs/18/sql-grant.html) / [REVOKE](https://www.postgresql.org/docs/18/sql-revoke.html).
|
|
46
|
+
`buildRepairMembershipSql` now requires the grantor and option (`ADMIN`, `SET` or `INHERIT`).
|
|
47
|
+
A null grantor is a defensive inconsistent-catalog case, not an ordinary DROP ROLE outcome,
|
|
48
|
+
and fails `PostgresRoleMembershipUnrepaired`. A missing parent fails
|
|
39
49
|
`PostgresRoleParentMissing` before any statement.
|
|
40
50
|
- **`defaultRemovalPolicy: 'retain'`.** A seat group role may own objects and be granted across
|
|
41
51
|
databases. A destroy is still implemented in full (`DROP ROLE IF EXISTS`, idempotent), opted in
|
|
@@ -47,7 +57,9 @@ run yourself. The `Postgres.Database` resource in this kit already binds `@effec
|
|
|
47
57
|
says `WITH SET FALSE`. Create runs `CREATE`, the password `ALTER` and the seat `GRANT`s in one
|
|
48
58
|
transaction, so a later statement failure does not leave a LOGIN role behind. `diff` reads
|
|
49
59
|
`pg_auth_members` live — stored attributes omit the option rows, and the engine passes stored
|
|
50
|
-
attributes — so `ADMIN` or `
|
|
60
|
+
attributes — so unsafe `ADMIN`, `SET` or `INHERIT` plans as `update`. Privileged catalog flags also plan
|
|
61
|
+
`update`, reaching the typed reconcile refusal. `read` omits membership option rows just as
|
|
62
|
+
reconcile does, so an unchanged role does not report structural drift. A live oid that is not the stored oid
|
|
51
63
|
is `PostgresRoleIdentityRefused` on read, diff, reconcile and delete: the name was recreated
|
|
52
64
|
out of band and is not dropped or altered.
|
|
53
65
|
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Cloud-init DNS and imported disk growth
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
Proxmox.Vm('talos', {
|
|
5
|
+
target,
|
|
6
|
+
node: 'n2',
|
|
7
|
+
vmid: 10000,
|
|
8
|
+
scsi0: 'cephtb4:0,import-from=cephfs-tb4:import/talos.raw',
|
|
9
|
+
diskSizesGiB: { scsi0: 64 },
|
|
10
|
+
ide2: 'cephtb4:cloudinit',
|
|
11
|
+
ipconfig0: 'ip=10.20.16.20/24,gw=10.20.16.254',
|
|
12
|
+
nameserver: '10.20.16.254',
|
|
13
|
+
searchdomain: 'example.internal',
|
|
14
|
+
});
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
`diskSizesGiB` declares minimum capacity in positive integer GiB. Declare the disk
|
|
18
|
+
slot alongside its target. Equal or larger live disks need no resize; lowering a
|
|
19
|
+
previously declared target is refused with `QemuDiskResizeRefused`, which callers
|
|
20
|
+
can handle with `Effect.catchTag`. Removing a target leaves capacity unmanaged.
|
|
21
|
+
Unsupported slots, CD-ROM/cloud-init drives and unreadable live sizes are refused.
|
|
22
|
+
|
|
23
|
+
The provider waits for import, reads the allocated disk, sends an absolute target
|
|
24
|
+
through the generated `putNodeQemuResize` operation, waits for its task, and verifies
|
|
25
|
+
the resulting capacity. An interrupted create resumes without `--adopt` when its
|
|
26
|
+
config matches, even if disk growth remains unfinished. Each resize checks the raw
|
|
27
|
+
VM lock first; lock waits and resize task polling share a 60-observation budget per
|
|
28
|
+
disk. A persistent lock raises `QemuDiskResizeRefused` without a resize write.
|
|
29
|
+
Absolute targets let retries finish growth without adding capacity twice.
|
|
30
|
+
`size=` in a volume config string is still observed metadata: omit it when
|
|
31
|
+
using a resize target. An unrelated update never resends the import source.
|
|
32
|
+
|
|
33
|
+
This resource never starts a VM. Complete its reconciliation before the separate
|
|
34
|
+
power-on step. Resizing an existing guest does not grow its partitions/filesystems.
|
|
35
|
+
|
|
36
|
+
DNS keys use the same declared-key comparison as `ipconfig0`: omitted keys remain
|
|
37
|
+
unmanaged. `nameserver` enforces the generated `address-list` constraint; PVE permits
|
|
38
|
+
IP addresses or DNS names, separated by whitespace, commas or semicolons. The provider
|
|
39
|
+
preserves the supplied spelling. `searchdomain` has no extra schema constraint.
|
|
40
|
+
|
|
41
|
+
Schema provenance: `codegen/manifest.json`, pve-manager **9.2.11/f6997e698c7933ea**,
|
|
42
|
+
SHA-256 `9def8f13611184ee1c7d0399713130dfc4a065701d0d91a69b9c03df929344e9`.
|
|
43
|
+
QEMU resize already exists in both generated surfaces: distilled's `nodes.ts` and
|
|
44
|
+
the legacy generator's packed `nodes-node-qemu-vmid-mtunnel.ts`. A filename search
|
|
45
|
+
for `qemu-vmid-resize.ts` misses the latter; neither output needs hand editing.
|
|
46
|
+
Both caches were recovered byte-for-byte from public vendor sources, then
|
|
47
|
+
`bun codegen/constraints.ts` generated the resize guard. The existing type generator
|
|
48
|
+
already supports the operation. No generated file was edited by hand.
|
|
49
|
+
|
|
50
|
+
Recovery used the vendor Makefile's concatenation order: `api-viewer/apidata.js`
|
|
51
|
+
and `api-viewer/PVEAPI.js` from proxmox/pve-docs
|
|
52
|
+
`4e7ff22c70eb35c63e65b0ba65c98980cb4d7bf5`, then `src/api-viewer/APIViewer.js`
|
|
53
|
+
from proxmox/proxmox-widget-toolkit `9204a77880eb31aff6ffc8bcf65ca48539685ab1`.
|
|
54
|
+
The result is exactly 4,337,847 bytes and the manifest SHA-256 above. PBS's 1,508,860
|
|
55
|
+
bytes were recovered from the public `proxmox-backup-docs_4.2.3-1_all.deb`, matching
|
|
56
|
+
the manifest's full SHA-256 (the recorded server version is 4.2.6-1, running 4.2.3).
|
|
57
|
+
No host was contacted. Tests cover generated constraints/types and fake SDK transport.
|
|
58
|
+
|
|
59
|
+
The named format's semantics come from
|
|
60
|
+
[PVE::JSONSchema](https://github.com/proxmox/pve-common/blob/defd246f31f327463f901a2daaf8dc52efcc5a97/src/PVE/JSONSchema.pm)
|
|
61
|
+
and `PVE::ParseUtils` at the same commit, inspected 2026-10-05. This is vendor-source
|
|
62
|
+
and fake-transport evidence; no live PVE call or Talos boot was performed.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@homeflare/alchemy",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.46.0",
|
|
4
4
|
"description": "Custom Alchemy providers for Cloudflare, Proxmox, OpenBao, Forgejo, Talos, launchd and Caddy, and a verifier that proves adoptions are no-ops.",
|
|
5
5
|
"homepage": "https://github.com/taslabs-net/homeflare-kit/tree/main/packages/alchemy#readme",
|
|
6
6
|
"bugs": "https://github.com/taslabs-net/homeflare-kit/issues",
|
|
@@ -208,7 +208,7 @@ describe('K-A4 finding 4: configValueProblem never accepts a flag-shaped value',
|
|
|
208
208
|
['a short flag', '-n'],
|
|
209
209
|
['a file-overwrite flag glued to its argument', '-o/etc/ceph/ceph.conf'],
|
|
210
210
|
['a long flag with =', '--admin-daemon=/var/run/ceph/ceph-mon.a.asok'],
|
|
211
|
-
['another long flag', '--conf=/tmp/x'],
|
|
211
|
+
['another long flag', '--conf=/tmp/x'], // tmp-allow: refused argv, not a directory this test creates
|
|
212
212
|
['the empty string', ''],
|
|
213
213
|
['a bare dash', '-'],
|
|
214
214
|
])('refuses %s (%j)', (_name, value) => {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
} from './sudo-allowlist.ts';
|
|
16
16
|
|
|
17
17
|
const DAEMONS = '/Library/LaunchDaemons';
|
|
18
|
-
const context = { prefixes: [DAEMONS, '/opt/example'], staged: '/tmp/hf-sudo-x/staged' };
|
|
18
|
+
const context = { prefixes: [DAEMONS, '/opt/example'], staged: '/tmp/hf-sudo-x/staged' }; // tmp-allow: in-memory staging path, not a directory this test creates
|
|
19
19
|
const allowed = (argv: string[]) => privilegedProblem(argv, context);
|
|
20
20
|
const PLIST = `${DAEMONS}/com.example.a.plist`;
|
|
21
21
|
|
|
@@ -66,7 +66,7 @@ describe('launchctl shapes', () => {
|
|
|
66
66
|
['bootstrap of two plists', [LAUNCHCTL, 'bootstrap', 'system', PLIST, PLIST]],
|
|
67
67
|
[
|
|
68
68
|
'bootstrap outside every prefix',
|
|
69
|
-
[LAUNCHCTL, 'bootstrap', 'system', '/tmp/com.example.a.plist'],
|
|
69
|
+
[LAUNCHCTL, 'bootstrap', 'system', '/tmp/com.example.a.plist'], // tmp-allow: refused argv, not a directory this test creates
|
|
70
70
|
],
|
|
71
71
|
['bootstrap of a non-plist', [LAUNCHCTL, 'bootstrap', 'system', `${DAEMONS}/com.example.a`]],
|
|
72
72
|
// ★ Only where launchd loads daemons at boot: anywhere else is a job that vanishes on restart.
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
} from './sudo-allowlist.ts';
|
|
23
23
|
|
|
24
24
|
const PREFIXES = ['/etc/systemd/system', '/usr/local/bin'];
|
|
25
|
-
const STAGED = '/tmp/hf-sudo-1/staged';
|
|
25
|
+
const STAGED = '/tmp/hf-sudo-1/staged'; // tmp-allow: in-memory staging path, not a directory this test creates
|
|
26
26
|
const TEMP = '/etc/systemd/system/.thing.service.hf-abcdef012345.tmp';
|
|
27
27
|
const context: AllowContext = { prefixes: PREFIXES, staged: STAGED, temp: TEMP };
|
|
28
28
|
const allowed = (argv: string[]) => privilegedProblem(argv, context);
|
|
@@ -51,7 +51,7 @@ describe('install shapes', () => {
|
|
|
51
51
|
'a target that is not the derived temp',
|
|
52
52
|
[INSTALL, '-m', '0644', '-T', '--', STAGED, '/etc/systemd/system/x.service'],
|
|
53
53
|
],
|
|
54
|
-
['a temp outside every prefix', [INSTALL, '-m', '0644', '-T', '--', STAGED, '/tmp/x.tmp']],
|
|
54
|
+
['a temp outside every prefix', [INSTALL, '-m', '0644', '-T', '--', STAGED, '/tmp/x.tmp']], // tmp-allow: refused argv, not a directory this test creates
|
|
55
55
|
['no -T', [INSTALL, '-m', '0644', '--', STAGED, TEMP]],
|
|
56
56
|
['a three-digit mode', [INSTALL, '-m', '644', '-T', '--', STAGED, TEMP]],
|
|
57
57
|
['-S (the Mac flag)', [INSTALL, '-S', '-m', '0644', '-T', '--', STAGED, TEMP]],
|
|
@@ -103,7 +103,7 @@ describe('mv and rm shapes', () => {
|
|
|
103
103
|
['mv without -T', [MV, '-f', '--', TEMP, '/etc/systemd/system/thing.service']],
|
|
104
104
|
['rm -r', [RM, '-rf', '--', TEMP]],
|
|
105
105
|
['rm without --', [RM, '-f', TEMP]],
|
|
106
|
-
['rm outside every prefix', [RM, '-f', '--', '/tmp/x']],
|
|
106
|
+
['rm outside every prefix', [RM, '-f', '--', '/tmp/x']], // tmp-allow: refused argv, not a directory this test creates
|
|
107
107
|
['sudo in argv', ['/usr/bin/sudo', '-n', RM, '-f', '--', TEMP]],
|
|
108
108
|
])('refuses %s', (_name, argv) => {
|
|
109
109
|
expect(allowed(argv)).toBeString();
|
|
@@ -52,7 +52,7 @@ describe('writeFileAtomic under a prefix', () => {
|
|
|
52
52
|
for (const line of logs) expect(line.startsWith('homeflare/linux sudo -n ')).toBe(true);
|
|
53
53
|
// No temp file left behind, and the staging directory is gone too.
|
|
54
54
|
expect([...fake.files.keys()].some((path) => path.includes('.hf-'))).toBe(false);
|
|
55
|
-
expect([...fake.dirs.keys()].some((path) => path.startsWith('/tmp/hf-sudo-'))).toBe(false);
|
|
55
|
+
expect([...fake.dirs.keys()].some((path) => path.startsWith('/tmp/hf-sudo-'))).toBe(false); // tmp-allow: in-memory fake path from fake-sudo, not a directory this test creates
|
|
56
56
|
});
|
|
57
57
|
|
|
58
58
|
test('a failed mv removes the temp it just installed, then still throws', async () => {
|
|
@@ -68,7 +68,7 @@ describe('writeFileAtomic under a prefix', () => {
|
|
|
68
68
|
expect(calls[2]?.at(-1)).toBe(calls[0]?.at(-1));
|
|
69
69
|
expect(fake.files.has(DEST)).toBe(false);
|
|
70
70
|
expect([...fake.files.keys()].some((path) => path.includes('.hf-'))).toBe(false);
|
|
71
|
-
expect([...fake.dirs.keys()].some((path) => path.startsWith('/tmp/hf-sudo-'))).toBe(false);
|
|
71
|
+
expect([...fake.dirs.keys()].some((path) => path.startsWith('/tmp/hf-sudo-'))).toBe(false); // tmp-allow: in-memory fake path from fake-sudo, not a directory this test creates
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
// 🔴 Adversarial review, round 2: a failed CLEANUP rm after a failed mv used to be swallowed
|
|
@@ -22,11 +22,14 @@ export interface FakeRoleState {
|
|
|
22
22
|
/** Bare role names, backing the `roleExists` check the database family's owner probe uses. */
|
|
23
23
|
readonly roleNames: Set<string>;
|
|
24
24
|
readonly roleRows: Map<string, PostgresRoleAttributes>;
|
|
25
|
-
/** `member\0parent\0grantor` triples backing `pg_auth_members` (`''` grantor =
|
|
25
|
+
/** `member\0parent\0grantor` triples backing `pg_auth_members` (`''` grantor = unresolvable
|
|
26
26
|
* grantor); `GRANT`/`REVOKE` mutate it. */
|
|
27
27
|
readonly memberships: Set<string>;
|
|
28
28
|
/** Options a name-only compare would hide, keyed `member\0parent\0grantor`. */
|
|
29
|
-
readonly membershipOptions: Map<
|
|
29
|
+
readonly membershipOptions: Map<
|
|
30
|
+
string,
|
|
31
|
+
{ readonly admin: boolean; readonly set: boolean; readonly inherit?: boolean }
|
|
32
|
+
>;
|
|
30
33
|
/** Hands out the next `oid` a real cluster would assign. */
|
|
31
34
|
nextOid(): number;
|
|
32
35
|
}
|
|
@@ -106,6 +109,7 @@ export const applyRoleStatement = <A extends object>(
|
|
|
106
109
|
grantor: parts[2] === undefined || parts[2] === '' ? null : (parts[2] as string),
|
|
107
110
|
admin: options?.admin === true,
|
|
108
111
|
set: options?.set === true,
|
|
112
|
+
inherit: options?.inherit === true,
|
|
109
113
|
};
|
|
110
114
|
})
|
|
111
115
|
.sort(
|
|
@@ -165,17 +169,33 @@ export const applyRoleStatement = <A extends object>(
|
|
|
165
169
|
// `grant.sgml` (REL_18_6): altering an existing membership retains every option the new
|
|
166
170
|
// GRANT omits, so only the full-options form clears ADMIN; `WITH SET FALSE` alone keeps a
|
|
167
171
|
// current ADMIN. A bare `GRANT` (never issued by this family) leaves options untouched.
|
|
168
|
-
const options = state.membershipOptions.get(key) ?? {
|
|
172
|
+
const options = state.membershipOptions.get(key) ?? {
|
|
173
|
+
admin: false,
|
|
174
|
+
set: false,
|
|
175
|
+
inherit: state.roleRows.get(member)?.inherit ?? true,
|
|
176
|
+
};
|
|
169
177
|
if (text.endsWith('WITH ADMIN FALSE, SET FALSE')) {
|
|
170
|
-
state.membershipOptions.
|
|
178
|
+
state.membershipOptions.set(key, { ...options, admin: false, set: false });
|
|
171
179
|
} else if (text.endsWith('WITH SET FALSE')) {
|
|
172
|
-
|
|
173
|
-
else state.membershipOptions.delete(key);
|
|
180
|
+
state.membershipOptions.set(key, { ...options, set: false });
|
|
174
181
|
}
|
|
175
182
|
return Effect.succeed([] as unknown as ReadonlyArray<A>);
|
|
176
183
|
}
|
|
177
184
|
|
|
178
185
|
if (text.startsWith('REVOKE')) {
|
|
186
|
+
const option =
|
|
187
|
+
/^REVOKE (ADMIN|SET|INHERIT) OPTION FOR "((?:[^"]|"")*)" FROM "((?:[^"]|"")*)" GRANTED BY "((?:[^"]|"")*)" RESTRICT$/.exec(
|
|
188
|
+
text,
|
|
189
|
+
);
|
|
190
|
+
if (option !== null) {
|
|
191
|
+
const key = `${unquoteIdent(option[3] as string)}\0${unquoteIdent(option[2] as string)}\0${unquoteIdent(option[4] as string)}`;
|
|
192
|
+
const options = state.membershipOptions.get(key) ?? { admin: false, set: false };
|
|
193
|
+
const next = { ...options, [(option[1] as string).toLowerCase()]: false };
|
|
194
|
+
if (next.admin || next.set || next.inherit !== undefined)
|
|
195
|
+
state.membershipOptions.set(key, next);
|
|
196
|
+
else state.membershipOptions.delete(key);
|
|
197
|
+
return Effect.succeed([] as unknown as ReadonlyArray<A>);
|
|
198
|
+
}
|
|
179
199
|
const granted =
|
|
180
200
|
/^REVOKE "((?:[^"]|"")*)" FROM "((?:[^"]|"")*)" GRANTED BY "((?:[^"]|"")*)"$/.exec(text);
|
|
181
201
|
if (granted !== null) {
|
package/src/postgres/fake-sql.ts
CHANGED
|
@@ -35,12 +35,14 @@ export interface FakeSql extends PgExecutor {
|
|
|
35
35
|
readonly roleRows: Map<string, PostgresRoleAttributes>;
|
|
36
36
|
/** `member\0parent\0grantor` triples backing `pg_auth_members` (a plain `pg_auth_members`
|
|
37
37
|
* read, a grant, a revoke and a DROP ROLE cascade all go through `fake-role-sql.ts`);
|
|
38
|
-
* `GRANT`/`REVOKE` mutate it. An empty grantor segment is
|
|
39
|
-
* exists. */
|
|
38
|
+
* `GRANT`/`REVOKE` mutate it. An empty grantor segment is an inconsistent catalog/test row. */
|
|
40
39
|
readonly memberships: Set<string>;
|
|
41
40
|
/** Options on a membership the name alone hides, keyed `member\0parent\0grantor`. Absent
|
|
42
|
-
* means neither ADMIN nor
|
|
43
|
-
readonly membershipOptions: Map<
|
|
41
|
+
* means neither ADMIN, SET nor an explicit per-grant INHERIT. */
|
|
42
|
+
readonly membershipOptions: Map<
|
|
43
|
+
string,
|
|
44
|
+
{ readonly admin: boolean; readonly set: boolean; readonly inherit?: boolean }
|
|
45
|
+
>;
|
|
44
46
|
/** Mutable on purpose: a test seeds a live schema (adoption, drift) or clears one (drop). */
|
|
45
47
|
readonly schemas: Map<string, PostgresSchemaAttributes>;
|
|
46
48
|
/** Mutable on purpose: names of schemas this fake pretends hold at least one relation, so a
|
|
@@ -85,7 +87,10 @@ export const makeFakeSql = (options: FakeSqlOptions = {}): FakeSql => {
|
|
|
85
87
|
const roleRows = new Map(options.roleRows?.map((r) => [r.name, r] as const) ?? []);
|
|
86
88
|
const databases = new Map(options.databases?.map((d) => [d.name, d] as const) ?? []);
|
|
87
89
|
const memberships = new Set<string>();
|
|
88
|
-
const membershipOptions = new Map<
|
|
90
|
+
const membershipOptions = new Map<
|
|
91
|
+
string,
|
|
92
|
+
{ readonly admin: boolean; readonly set: boolean; readonly inherit?: boolean }
|
|
93
|
+
>();
|
|
89
94
|
const schemas = seedSchemas(options.schemas, options.database ?? 'postgres');
|
|
90
95
|
const relationsIn = new Set(options.schemasWithRelations ?? []);
|
|
91
96
|
let raceRemaining = options.raceNextCreate === true ? 1 : 0;
|
package/src/postgres/index.ts
CHANGED
|
@@ -62,7 +62,8 @@ export interface PostgresRoleProps {
|
|
|
62
62
|
readonly login: boolean;
|
|
63
63
|
/** `CONNECTION LIMIT n`, `-1` for unlimited — maps to `pg_roles.rolconnlimit`. */
|
|
64
64
|
readonly connectionLimit: number;
|
|
65
|
-
/** `INHERIT` or `NOINHERIT` — maps to `pg_roles.rolinherit
|
|
65
|
+
/** `INHERIT` or `NOINHERIT` — maps to `pg_roles.rolinherit`; false also clears per-grant
|
|
66
|
+
* INHERIT on declared memberships (PG 16+ uses the role flag only to default new grants). */
|
|
66
67
|
readonly inherit: boolean;
|
|
67
68
|
/**
|
|
68
69
|
* `VALID UNTIL 'timestamp'` — maps to `pg_roles.rolvaliduntil`. ISO 8601 without a timezone is
|
|
@@ -112,18 +113,20 @@ export interface PostgresRoleAttributes {
|
|
|
112
113
|
*/
|
|
113
114
|
readonly memberOf: readonly string[] | null;
|
|
114
115
|
/**
|
|
115
|
-
* The membership rows behind `memberOf`, including `admin_option
|
|
116
|
+
* The membership rows behind `memberOf`, including `admin_option`, `set_option` and
|
|
117
|
+
* `inherit_option`. Present
|
|
116
118
|
* on a catalog read; stripped before attributes are stored (`storedAttributes`), because the
|
|
117
119
|
* engine's diff receives stored attributes and would never see them there. The provider's
|
|
118
120
|
* diff reads these rows live. `grantor` is the role that made the grant
|
|
119
|
-
* (`pg_auth_members.grantor`)
|
|
120
|
-
* be named in `REVOKE … GRANTED BY
|
|
121
|
+
* (`pg_auth_members.grantor`). Null is a defensive inconsistent-catalog case, not an ordinary
|
|
122
|
+
* DROP ROLE outcome; such a row cannot be named in `REVOKE … GRANTED BY`.
|
|
121
123
|
*/
|
|
122
124
|
readonly memberships?: readonly {
|
|
123
125
|
readonly parent: string;
|
|
124
126
|
readonly grantor: string | null;
|
|
125
127
|
readonly admin: boolean;
|
|
126
128
|
readonly set: boolean;
|
|
129
|
+
readonly inherit: boolean;
|
|
127
130
|
}[];
|
|
128
131
|
/**
|
|
129
132
|
* A seal of the last password value written, or `''` if none was ever written (`seal()` from
|