@homeflare/alchemy 0.42.0 → 0.44.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/README.md +10 -1
- package/dist/caddy/index.js +35 -1
- package/dist/caddy/index.js.map +3 -3
- package/dist/launchd/index.js +35 -1
- package/dist/launchd/index.js.map +3 -3
- package/dist/linux/index.js +35 -1
- package/dist/linux/index.js.map +3 -3
- package/dist/litellm/access-group-form.d.ts +26 -0
- package/dist/litellm/access-group-form.d.ts.map +1 -0
- package/dist/litellm/access-group-operations.d.ts +37 -0
- package/dist/litellm/access-group-operations.d.ts.map +1 -0
- package/dist/litellm/access-group-types.d.ts +49 -0
- package/dist/litellm/access-group-types.d.ts.map +1 -0
- package/dist/litellm/access-group.d.ts +55 -0
- package/dist/litellm/access-group.d.ts.map +1 -0
- package/dist/litellm/budget-errors.d.ts +36 -0
- package/dist/litellm/budget-errors.d.ts.map +1 -0
- package/dist/litellm/budget-form.d.ts +50 -0
- package/dist/litellm/budget-form.d.ts.map +1 -0
- package/dist/litellm/budget-operations.d.ts +20 -0
- package/dist/litellm/budget-operations.d.ts.map +1 -0
- package/dist/litellm/budget.d.ts +61 -0
- package/dist/litellm/budget.d.ts.map +1 -0
- package/dist/litellm/credential-errors.d.ts +131 -0
- package/dist/litellm/credential-errors.d.ts.map +1 -0
- package/dist/litellm/credential-form.d.ts +79 -0
- package/dist/litellm/credential-form.d.ts.map +1 -0
- package/dist/litellm/credential-operations.d.ts +84 -0
- package/dist/litellm/credential-operations.d.ts.map +1 -0
- package/dist/litellm/credential-rewrite.d.ts +6 -0
- package/dist/litellm/credential-rewrite.d.ts.map +1 -0
- package/dist/litellm/credential-types.d.ts +87 -0
- package/dist/litellm/credential-types.d.ts.map +1 -0
- package/dist/litellm/credential-values.d.ts +53 -0
- package/dist/litellm/credential-values.d.ts.map +1 -0
- package/dist/litellm/credential.d.ts +83 -0
- package/dist/litellm/credential.d.ts.map +1 -0
- package/dist/litellm/fake-access-group-litellm.d.ts +34 -0
- package/dist/litellm/fake-access-group-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-credential-litellm.d.ts +54 -0
- package/dist/litellm/fake-credential-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-keys.d.ts +53 -0
- package/dist/litellm/fake-keys.d.ts.map +1 -0
- package/dist/litellm/fake-litellm.d.ts +9 -1
- package/dist/litellm/fake-litellm.d.ts.map +1 -1
- package/dist/litellm/fake-mcp-litellm.d.ts +67 -0
- package/dist/litellm/fake-mcp-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts +49 -0
- package/dist/litellm/fake-model-litellm-post-update.d.ts.map +1 -0
- package/dist/litellm/fake-model-litellm.d.ts +48 -0
- package/dist/litellm/fake-model-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts +33 -0
- package/dist/litellm/fake-policy-attachment-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-policy-litellm.d.ts +32 -0
- package/dist/litellm/fake-policy-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-registry-base.d.ts +42 -0
- package/dist/litellm/fake-registry-base.d.ts.map +1 -0
- package/dist/litellm/fake-stack.d.ts +8 -1
- package/dist/litellm/fake-stack.d.ts.map +1 -1
- package/dist/litellm/fake-team-litellm.d.ts +47 -0
- package/dist/litellm/fake-team-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-tool-litellm.d.ts +28 -0
- package/dist/litellm/fake-tool-litellm.d.ts.map +1 -0
- package/dist/litellm/fake-toolset-litellm.d.ts +29 -0
- package/dist/litellm/fake-toolset-litellm.d.ts.map +1 -0
- package/dist/litellm/index.d.ts +20 -0
- package/dist/litellm/index.d.ts.map +1 -1
- package/dist/litellm/index.js +3201 -2
- package/dist/litellm/index.js.map +70 -5
- package/dist/litellm/key-errors.d.ts +169 -0
- package/dist/litellm/key-errors.d.ts.map +1 -0
- package/dist/litellm/key-form.d.ts +119 -0
- package/dist/litellm/key-form.d.ts.map +1 -0
- package/dist/litellm/key-harness.d.ts +41 -0
- package/dist/litellm/key-harness.d.ts.map +1 -0
- package/dist/litellm/key-metadata-errors.d.ts +30 -0
- package/dist/litellm/key-metadata-errors.d.ts.map +1 -0
- package/dist/litellm/key-metadata.d.ts +22 -0
- package/dist/litellm/key-metadata.d.ts.map +1 -0
- package/dist/litellm/key-operations.d.ts +63 -0
- package/dist/litellm/key-operations.d.ts.map +1 -0
- package/dist/litellm/key-secret.d.ts +33 -0
- package/dist/litellm/key-secret.d.ts.map +1 -0
- package/dist/litellm/key.d.ts +78 -0
- package/dist/litellm/key.d.ts.map +1 -0
- package/dist/litellm/mcp-server-credential.d.ts +50 -0
- package/dist/litellm/mcp-server-credential.d.ts.map +1 -0
- package/dist/litellm/mcp-server-errors.d.ts +101 -0
- package/dist/litellm/mcp-server-errors.d.ts.map +1 -0
- package/dist/litellm/mcp-server-form.d.ts +56 -0
- package/dist/litellm/mcp-server-form.d.ts.map +1 -0
- package/dist/litellm/mcp-server-locate.d.ts +26 -0
- package/dist/litellm/mcp-server-locate.d.ts.map +1 -0
- package/dist/litellm/mcp-server-operations.d.ts +63 -0
- package/dist/litellm/mcp-server-operations.d.ts.map +1 -0
- package/dist/litellm/mcp-server-shadow.d.ts +24 -0
- package/dist/litellm/mcp-server-shadow.d.ts.map +1 -0
- package/dist/litellm/mcp-server-types.d.ts +118 -0
- package/dist/litellm/mcp-server-types.d.ts.map +1 -0
- package/dist/litellm/mcp-server-url.d.ts +11 -0
- package/dist/litellm/mcp-server-url.d.ts.map +1 -0
- package/dist/litellm/mcp-server.d.ts +95 -0
- package/dist/litellm/mcp-server.d.ts.map +1 -0
- package/dist/litellm/model-claim.d.ts +24 -0
- package/dist/litellm/model-claim.d.ts.map +1 -0
- package/dist/litellm/model-credential.d.ts +12 -0
- package/dist/litellm/model-credential.d.ts.map +1 -0
- package/dist/litellm/model-errors.d.ts +119 -0
- package/dist/litellm/model-errors.d.ts.map +1 -0
- package/dist/litellm/model-form.d.ts +78 -0
- package/dist/litellm/model-form.d.ts.map +1 -0
- package/dist/litellm/model-locate.d.ts +13 -0
- package/dist/litellm/model-locate.d.ts.map +1 -0
- package/dist/litellm/model-operations.d.ts +59 -0
- package/dist/litellm/model-operations.d.ts.map +1 -0
- package/dist/litellm/model-types.d.ts +91 -0
- package/dist/litellm/model-types.d.ts.map +1 -0
- package/dist/litellm/model.d.ts +88 -0
- package/dist/litellm/model.d.ts.map +1 -0
- package/dist/litellm/operations.d.ts +22 -0
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/litellm/policy-attachment-form.d.ts +19 -0
- package/dist/litellm/policy-attachment-form.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-operations.d.ts +31 -0
- package/dist/litellm/policy-attachment-operations.d.ts.map +1 -0
- package/dist/litellm/policy-attachment-types.d.ts +48 -0
- package/dist/litellm/policy-attachment-types.d.ts.map +1 -0
- package/dist/litellm/policy-attachment.d.ts +61 -0
- package/dist/litellm/policy-attachment.d.ts.map +1 -0
- package/dist/litellm/policy-form.d.ts +22 -0
- package/dist/litellm/policy-form.d.ts.map +1 -0
- package/dist/litellm/policy-operations.d.ts +42 -0
- package/dist/litellm/policy-operations.d.ts.map +1 -0
- package/dist/litellm/policy-types.d.ts +57 -0
- package/dist/litellm/policy-types.d.ts.map +1 -0
- package/dist/litellm/policy.d.ts +65 -0
- package/dist/litellm/policy.d.ts.map +1 -0
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/litellm/registry-errors.d.ts +62 -0
- package/dist/litellm/registry-errors.d.ts.map +1 -0
- package/dist/litellm/registry-support.d.ts +42 -0
- package/dist/litellm/registry-support.d.ts.map +1 -0
- package/dist/litellm/team-form.d.ts +26 -0
- package/dist/litellm/team-form.d.ts.map +1 -0
- package/dist/litellm/team-members.d.ts +10 -0
- package/dist/litellm/team-members.d.ts.map +1 -0
- package/dist/litellm/team-operations.d.ts +38 -0
- package/dist/litellm/team-operations.d.ts.map +1 -0
- package/dist/litellm/team-permission.d.ts +35 -0
- package/dist/litellm/team-permission.d.ts.map +1 -0
- package/dist/litellm/team-types.d.ts +101 -0
- package/dist/litellm/team-types.d.ts.map +1 -0
- package/dist/litellm/team.d.ts +67 -0
- package/dist/litellm/team.d.ts.map +1 -0
- package/dist/litellm/tool-policy-form.d.ts +21 -0
- package/dist/litellm/tool-policy-form.d.ts.map +1 -0
- package/dist/litellm/tool-policy-operations.d.ts +30 -0
- package/dist/litellm/tool-policy-operations.d.ts.map +1 -0
- package/dist/litellm/tool-policy-types.d.ts +46 -0
- package/dist/litellm/tool-policy-types.d.ts.map +1 -0
- package/dist/litellm/tool-policy.d.ts +62 -0
- package/dist/litellm/tool-policy.d.ts.map +1 -0
- package/dist/litellm/toolset-form.d.ts +20 -0
- package/dist/litellm/toolset-form.d.ts.map +1 -0
- package/dist/litellm/toolset-operations.d.ts +39 -0
- package/dist/litellm/toolset-operations.d.ts.map +1 -0
- package/dist/litellm/toolset-types.d.ts +46 -0
- package/dist/litellm/toolset-types.d.ts.map +1 -0
- package/dist/litellm/toolset.d.ts +55 -0
- package/dist/litellm/toolset.d.ts.map +1 -0
- package/dist/openbao/auth-role-form.d.ts +9 -0
- package/dist/openbao/auth-role-form.d.ts.map +1 -1
- package/dist/openbao/auth-role-wire.d.ts.map +1 -1
- package/dist/openbao/fake-engines-roles.d.ts.map +1 -1
- package/dist/openbao/index.js +43 -6
- package/dist/openbao/index.js.map +5 -5
- package/dist/ownership/rows.d.ts +11 -0
- package/dist/ownership/rows.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +32 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +28 -9
- package/dist/postgres/database-sql.d.ts.map +1 -1
- package/dist/postgres/database.d.ts +1 -1
- package/dist/postgres/database.d.ts.map +1 -1
- package/dist/postgres/fake-grants-parse.d.ts +37 -0
- package/dist/postgres/fake-grants-parse.d.ts.map +1 -0
- package/dist/postgres/fake-grants-read.d.ts +61 -0
- package/dist/postgres/fake-grants-read.d.ts.map +1 -0
- package/dist/postgres/fake-grants-sql.d.ts +46 -0
- package/dist/postgres/fake-grants-sql.d.ts.map +1 -0
- package/dist/postgres/fake-grants-write.d.ts +29 -0
- package/dist/postgres/fake-grants-write.d.ts.map +1 -0
- package/dist/postgres/fake-role-sql.d.ts +40 -0
- package/dist/postgres/fake-role-sql.d.ts.map +1 -0
- package/dist/postgres/fake-schema-sql.d.ts +42 -0
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -0
- package/dist/postgres/fake-sql-parse.d.ts +23 -0
- package/dist/postgres/fake-sql-parse.d.ts.map +1 -0
- package/dist/postgres/fake-sql-quote.d.ts +12 -0
- package/dist/postgres/fake-sql-quote.d.ts.map +1 -0
- package/dist/postgres/fake-sql.d.ts +42 -0
- package/dist/postgres/fake-sql.d.ts.map +1 -1
- package/dist/postgres/grants-attrs.d.ts +115 -0
- package/dist/postgres/grants-attrs.d.ts.map +1 -0
- package/dist/postgres/grants-declare.d.ts +88 -0
- package/dist/postgres/grants-declare.d.ts.map +1 -0
- package/dist/postgres/grants-diff.d.ts +25 -0
- package/dist/postgres/grants-diff.d.ts.map +1 -0
- package/dist/postgres/grants-errors.d.ts +137 -0
- package/dist/postgres/grants-errors.d.ts.map +1 -0
- package/dist/postgres/grants-existence.d.ts +14 -0
- package/dist/postgres/grants-existence.d.ts.map +1 -0
- package/dist/postgres/grants-ops.d.ts +65 -0
- package/dist/postgres/grants-ops.d.ts.map +1 -0
- package/dist/postgres/grants-ownership.d.ts +18 -0
- package/dist/postgres/grants-ownership.d.ts.map +1 -0
- package/dist/postgres/grants-plan-restore.d.ts +22 -0
- package/dist/postgres/grants-plan-restore.d.ts.map +1 -0
- package/dist/postgres/grants-plan.d.ts +65 -0
- package/dist/postgres/grants-plan.d.ts.map +1 -0
- package/dist/postgres/grants-read-defaults.d.ts +17 -0
- package/dist/postgres/grants-read-defaults.d.ts.map +1 -0
- package/dist/postgres/grants-read.d.ts +77 -0
- package/dist/postgres/grants-read.d.ts.map +1 -0
- package/dist/postgres/grants-refuse.d.ts +25 -0
- package/dist/postgres/grants-refuse.d.ts.map +1 -0
- package/dist/postgres/grants-sql.d.ts +42 -0
- package/dist/postgres/grants-sql.d.ts.map +1 -0
- package/dist/postgres/grants-words.d.ts +29 -0
- package/dist/postgres/grants-words.d.ts.map +1 -0
- package/dist/postgres/grants.d.ts +37 -0
- package/dist/postgres/grants.d.ts.map +1 -0
- package/dist/postgres/index.d.ts +35 -8
- package/dist/postgres/index.d.ts.map +1 -1
- package/dist/postgres/index.js +2063 -39
- package/dist/postgres/index.js.map +47 -7
- package/dist/postgres/installed-classifier.d.ts +13 -0
- package/dist/postgres/installed-classifier.d.ts.map +1 -0
- package/dist/postgres/providers.d.ts +17 -7
- package/dist/postgres/providers.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts +25 -0
- package/dist/postgres/psql-executor.d.ts.map +1 -0
- package/dist/postgres/role-attrs.d.ts +109 -0
- package/dist/postgres/role-attrs.d.ts.map +1 -0
- package/dist/postgres/role-diff.d.ts +22 -0
- package/dist/postgres/role-diff.d.ts.map +1 -0
- package/dist/postgres/role-errors.d.ts +126 -0
- package/dist/postgres/role-errors.d.ts.map +1 -0
- package/dist/postgres/role-membership-sql.d.ts +75 -0
- package/dist/postgres/role-membership-sql.d.ts.map +1 -0
- package/dist/postgres/role-provider.d.ts +11 -0
- package/dist/postgres/role-provider.d.ts.map +1 -0
- package/dist/postgres/role-scram.d.ts +6 -0
- package/dist/postgres/role-scram.d.ts.map +1 -0
- package/dist/postgres/role-secrets.d.ts +30 -0
- package/dist/postgres/role-secrets.d.ts.map +1 -0
- package/dist/postgres/role-sql.d.ts +68 -0
- package/dist/postgres/role-sql.d.ts.map +1 -0
- package/dist/postgres/role.d.ts +57 -0
- package/dist/postgres/role.d.ts.map +1 -0
- package/dist/postgres/schema-assert.d.ts +50 -0
- package/dist/postgres/schema-assert.d.ts.map +1 -0
- package/dist/postgres/schema-attrs.d.ts +51 -0
- package/dist/postgres/schema-attrs.d.ts.map +1 -0
- package/dist/postgres/schema-delete.d.ts +28 -0
- package/dist/postgres/schema-delete.d.ts.map +1 -0
- package/dist/postgres/schema-diff.d.ts +14 -0
- package/dist/postgres/schema-diff.d.ts.map +1 -0
- package/dist/postgres/schema-errors.d.ts +139 -0
- package/dist/postgres/schema-errors.d.ts.map +1 -0
- package/dist/postgres/schema-identity.d.ts +8 -0
- package/dist/postgres/schema-identity.d.ts.map +1 -0
- package/dist/postgres/schema-reconcile.d.ts +12 -0
- package/dist/postgres/schema-reconcile.d.ts.map +1 -0
- package/dist/postgres/schema-sql.d.ts +45 -0
- package/dist/postgres/schema-sql.d.ts.map +1 -0
- package/dist/postgres/schema-test-kit.d.ts +67 -0
- package/dist/postgres/schema-test-kit.d.ts.map +1 -0
- package/dist/postgres/schema.d.ts +54 -0
- package/dist/postgres/schema.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-types.d.ts +57 -0
- package/dist/proxmox/ceph-flag-types.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag-wire.d.ts +77 -0
- package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -0
- package/dist/proxmox/ceph-flag.d.ts +15 -50
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +10 -13
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/index.js +806 -740
- package/dist/proxmox/index.js.map +9 -8
- package/dist/release/fake-engine.d.ts +10 -0
- package/dist/release/fake-engine.d.ts.map +1 -1
- package/dist/release/index.js +35 -1
- package/dist/release/index.js.map +3 -3
- package/dist/valkey/acl-attrs.d.ts +94 -0
- package/dist/valkey/acl-attrs.d.ts.map +1 -0
- package/dist/valkey/acl-compare.d.ts +28 -0
- package/dist/valkey/acl-compare.d.ts.map +1 -0
- package/dist/valkey/acl-connection.d.ts +6 -0
- package/dist/valkey/acl-connection.d.ts.map +1 -0
- package/dist/valkey/acl-form.d.ts +62 -0
- package/dist/valkey/acl-form.d.ts.map +1 -0
- package/dist/valkey/acl-managed.d.ts +4 -0
- package/dist/valkey/acl-managed.d.ts.map +1 -0
- package/dist/valkey/acl-ops.d.ts +37 -0
- package/dist/valkey/acl-ops.d.ts.map +1 -0
- package/dist/valkey/acl-profiles.d.ts +53 -0
- package/dist/valkey/acl-profiles.d.ts.map +1 -0
- package/dist/valkey/acl-reconcile.d.ts +26 -0
- package/dist/valkey/acl-reconcile.d.ts.map +1 -0
- package/dist/valkey/acl.d.ts +24 -0
- package/dist/valkey/acl.d.ts.map +1 -0
- package/dist/valkey/connection-service.d.ts +22 -0
- package/dist/valkey/connection-service.d.ts.map +1 -0
- package/dist/valkey/connection.d.ts +59 -0
- package/dist/valkey/connection.d.ts.map +1 -0
- package/dist/valkey/errors.d.ts +165 -0
- package/dist/valkey/errors.d.ts.map +1 -0
- package/dist/valkey/fake-acl.d.ts +29 -0
- package/dist/valkey/fake-acl.d.ts.map +1 -0
- package/dist/valkey/fake-valkey.d.ts +35 -0
- package/dist/valkey/fake-valkey.d.ts.map +1 -0
- package/dist/valkey/handler-test-fixture.d.ts +20 -0
- package/dist/valkey/handler-test-fixture.d.ts.map +1 -0
- package/dist/valkey/index.d.ts +18 -0
- package/dist/valkey/index.d.ts.map +1 -0
- package/dist/valkey/index.js +964 -0
- package/dist/valkey/index.js.map +27 -0
- package/dist/valkey/instance-attrs.d.ts +46 -0
- package/dist/valkey/instance-attrs.d.ts.map +1 -0
- package/dist/valkey/instance-form.d.ts +22 -0
- package/dist/valkey/instance-form.d.ts.map +1 -0
- package/dist/valkey/instance.d.ts +48 -0
- package/dist/valkey/instance.d.ts.map +1 -0
- package/dist/valkey/provider-socket-fixture.d.ts +8 -0
- package/dist/valkey/provider-socket-fixture.d.ts.map +1 -0
- package/dist/valkey/providers.d.ts +16 -0
- package/dist/valkey/providers.d.ts.map +1 -0
- package/dist/valkey/resp.d.ts +38 -0
- package/dist/valkey/resp.d.ts.map +1 -0
- package/dist/valkey/transport-error.d.ts +36 -0
- package/dist/valkey/transport-error.d.ts.map +1 -0
- package/dist/valkey/transport.d.ts +50 -0
- package/dist/valkey/transport.d.ts.map +1 -0
- package/docs/litellm-access-group.md +105 -0
- package/docs/litellm-budget.md +55 -0
- package/docs/litellm-credential.md +60 -0
- package/docs/litellm-key-metadata.md +56 -0
- package/docs/litellm-key.md +194 -0
- package/docs/litellm-mcp.md +187 -0
- package/docs/litellm-model.md +111 -0
- package/docs/litellm-policy-attachment.md +86 -0
- package/docs/litellm-policy.md +103 -0
- package/docs/litellm-team.md +117 -0
- package/docs/litellm-tool-policy.md +90 -0
- package/docs/litellm-toolset.md +92 -0
- package/docs/litellm.md +16 -8
- package/docs/peers.md +15 -6
- package/docs/postgres-grants-example.md +55 -0
- package/docs/postgres-grants.md +157 -0
- package/docs/postgres-role.md +114 -0
- package/docs/postgres-schema.md +139 -0
- package/docs/postgres.md +39 -0
- package/docs/proxmox-sdk-migration.md +45 -0
- package/docs/valkey-transport.md +29 -0
- package/docs/valkey.md +187 -0
- package/package.json +7 -3
- package/src/litellm/access-group-form.ts +105 -0
- package/src/litellm/access-group-operations.ts +92 -0
- package/src/litellm/access-group-types.ts +49 -0
- package/src/litellm/access-group.test.ts +197 -0
- package/src/litellm/access-group.ts +151 -0
- package/src/litellm/budget-errors.ts +38 -0
- package/src/litellm/budget-form.ts +94 -0
- package/src/litellm/budget-operations.ts +51 -0
- package/src/litellm/budget.test.ts +105 -0
- package/src/litellm/budget.ts +127 -0
- package/src/litellm/credential-errors.ts +183 -0
- package/src/litellm/credential-form.test.ts +151 -0
- package/src/litellm/credential-form.ts +211 -0
- package/src/litellm/credential-guards.test.ts +241 -0
- package/src/litellm/credential-operations.ts +208 -0
- package/src/litellm/credential-recovery.test.ts +93 -0
- package/src/litellm/credential-rewrite.test.ts +164 -0
- package/src/litellm/credential-rewrite.ts +50 -0
- package/src/litellm/credential-types.ts +117 -0
- package/src/litellm/credential-values.ts +94 -0
- package/src/litellm/credential.test.ts +218 -0
- package/src/litellm/credential.ts +227 -0
- package/src/litellm/fake-access-group-litellm.ts +127 -0
- package/src/litellm/fake-credential-litellm.ts +216 -0
- package/src/litellm/fake-keys.ts +190 -0
- package/src/litellm/fake-litellm.ts +66 -7
- package/src/litellm/fake-mcp-litellm.ts +214 -0
- package/src/litellm/fake-model-litellm-post-update.ts +103 -0
- package/src/litellm/fake-model-litellm.ts +233 -0
- package/src/litellm/fake-policy-attachment-litellm.ts +97 -0
- package/src/litellm/fake-policy-litellm.ts +186 -0
- package/src/litellm/fake-registry-base.ts +69 -0
- package/src/litellm/fake-stack.ts +17 -1
- package/src/litellm/fake-team-litellm.ts +229 -0
- package/src/litellm/fake-tool-litellm.ts +88 -0
- package/src/litellm/fake-toolset-litellm.ts +110 -0
- package/src/litellm/index.ts +153 -0
- package/src/litellm/key-delete.test.ts +212 -0
- package/src/litellm/key-errors.ts +241 -0
- package/src/litellm/key-form.ts +200 -0
- package/src/litellm/key-harness.ts +121 -0
- package/src/litellm/key-metadata-errors.ts +49 -0
- package/src/litellm/key-metadata.test.ts +156 -0
- package/src/litellm/key-metadata.ts +74 -0
- package/src/litellm/key-operations.ts +184 -0
- package/src/litellm/key-rotation.test.ts +110 -0
- package/src/litellm/key-scope.test.ts +135 -0
- package/src/litellm/key-secret.test.ts +248 -0
- package/src/litellm/key-secret.ts +137 -0
- package/src/litellm/key-transport.test.ts +166 -0
- package/src/litellm/key.test.ts +231 -0
- package/src/litellm/key.ts +213 -0
- package/src/litellm/mcp-server-adopt.test.ts +86 -0
- package/src/litellm/mcp-server-alias.test.ts +184 -0
- package/src/litellm/mcp-server-credential.ts +85 -0
- package/src/litellm/mcp-server-errors.ts +141 -0
- package/src/litellm/mcp-server-exports.test.ts +15 -0
- package/src/litellm/mcp-server-form.test.ts +241 -0
- package/src/litellm/mcp-server-form.ts +233 -0
- package/src/litellm/mcp-server-handlers.test.ts +150 -0
- package/src/litellm/mcp-server-locate.ts +66 -0
- package/src/litellm/mcp-server-operations.ts +111 -0
- package/src/litellm/mcp-server-registry.test.ts +146 -0
- package/src/litellm/mcp-server-retype.test.ts +114 -0
- package/src/litellm/mcp-server-shadow.test.ts +91 -0
- package/src/litellm/mcp-server-shadow.ts +45 -0
- package/src/litellm/mcp-server-tools.test.ts +85 -0
- package/src/litellm/mcp-server-types.ts +143 -0
- package/src/litellm/mcp-server-url.ts +66 -0
- package/src/litellm/mcp-server.test.ts +213 -0
- package/src/litellm/mcp-server.ts +225 -0
- package/src/litellm/model-claim.ts +69 -0
- package/src/litellm/model-credential.ts +45 -0
- package/src/litellm/model-errors.ts +168 -0
- package/src/litellm/model-foreign-row.test.ts +173 -0
- package/src/litellm/model-form.test.ts +228 -0
- package/src/litellm/model-form.ts +223 -0
- package/src/litellm/model-locate.test.ts +128 -0
- package/src/litellm/model-locate.ts +67 -0
- package/src/litellm/model-operations.test.ts +93 -0
- package/src/litellm/model-operations.ts +146 -0
- package/src/litellm/model-params-preserve.test.ts +119 -0
- package/src/litellm/model-recovery.test.ts +57 -0
- package/src/litellm/model-types.ts +112 -0
- package/src/litellm/model.test.ts +222 -0
- package/src/litellm/model.ts +237 -0
- package/src/litellm/operations.ts +1 -1
- package/src/litellm/policy-attachment-form.ts +103 -0
- package/src/litellm/policy-attachment-operations.ts +74 -0
- package/src/litellm/policy-attachment-types.ts +48 -0
- package/src/litellm/policy-attachment.test.ts +198 -0
- package/src/litellm/policy-attachment.ts +178 -0
- package/src/litellm/policy-form.ts +122 -0
- package/src/litellm/policy-operations.ts +112 -0
- package/src/litellm/policy-types.ts +58 -0
- package/src/litellm/policy.test.ts +214 -0
- package/src/litellm/policy.ts +146 -0
- package/src/litellm/providers.ts +25 -1
- package/src/litellm/registry-errors.ts +88 -0
- package/src/litellm/registry-exports.test.ts +66 -0
- package/src/litellm/registry-support.ts +109 -0
- package/src/litellm/team-form.ts +140 -0
- package/src/litellm/team-members.test.ts +150 -0
- package/src/litellm/team-members.ts +58 -0
- package/src/litellm/team-operations.ts +90 -0
- package/src/litellm/team-permission.ts +159 -0
- package/src/litellm/team-read.test.ts +89 -0
- package/src/litellm/team-types.ts +106 -0
- package/src/litellm/team.test.ts +206 -0
- package/src/litellm/team.ts +159 -0
- package/src/litellm/tool-policy-form.ts +94 -0
- package/src/litellm/tool-policy-operations.ts +58 -0
- package/src/litellm/tool-policy-types.ts +48 -0
- package/src/litellm/tool-policy.test.ts +172 -0
- package/src/litellm/tool-policy.ts +125 -0
- package/src/litellm/toolset-form.ts +104 -0
- package/src/litellm/toolset-operations.ts +90 -0
- package/src/litellm/toolset-types.ts +47 -0
- package/src/litellm/toolset.test.ts +198 -0
- package/src/litellm/toolset.ts +151 -0
- package/src/openbao/auth-role-form.test.ts +37 -0
- package/src/openbao/auth-role-form.ts +12 -1
- package/src/openbao/auth-role-wire.test.ts +1 -0
- package/src/openbao/auth-role-wire.ts +13 -1
- package/src/openbao/distilled-retry.test.ts +1 -0
- package/src/openbao/fake-engines-roles.ts +7 -1
- package/src/ownership/ownership.test.ts +33 -1
- package/src/ownership/rows.ts +53 -0
- package/src/postgres/connection.ts +72 -3
- package/src/postgres/database-bigint-serialization.test.ts +1 -0
- package/src/postgres/database-refusals.test.ts +2 -2
- package/src/postgres/database-sql.ts +40 -12
- package/src/postgres/database.ts +3 -2
- package/src/postgres/fake-grants-parse.ts +189 -0
- package/src/postgres/fake-grants-read.ts +250 -0
- package/src/postgres/fake-grants-sql.ts +207 -0
- package/src/postgres/fake-grants-write.ts +90 -0
- package/src/postgres/fake-role-sql.ts +220 -0
- package/src/postgres/fake-schema-semantics.test.ts +36 -0
- package/src/postgres/fake-schema-sql.ts +146 -0
- package/src/postgres/fake-sql-parse.ts +86 -0
- package/src/postgres/fake-sql-quote.ts +36 -0
- package/src/postgres/fake-sql.ts +161 -46
- package/src/postgres/fixtures/pg-REL_18_6-acl.h.txt +147 -0
- package/src/postgres/fixtures/pg-REL_18_6-aclexplode-func.txt +31 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter-default-privileges-synopsis.txt +82 -0
- package/src/postgres/fixtures/pg-REL_18_6-alter_role.sgml.txt +44 -0
- package/src/postgres/fixtures/pg-REL_18_6-create_role.sgml.txt +26 -0
- package/src/postgres/fixtures/pg-REL_18_6-grant-synopsis.txt +95 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_attribute.h.txt +24 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_auth_members.h.txt +62 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_authid.h.txt +70 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_class.h.txt +33 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_default_acl.h.txt +81 -0
- package/src/postgres/fixtures/pg-REL_18_6-pg_namespace.h.txt +28 -0
- package/src/postgres/fixtures/pg-REL_18_6-revoke-synopsis.txt +124 -0
- package/src/postgres/grants-acl.test.ts +61 -0
- package/src/postgres/grants-attrs.ts +185 -0
- package/src/postgres/grants-database.test.ts +158 -0
- package/src/postgres/grants-declare.ts +172 -0
- package/src/postgres/grants-delete-proof.test.ts +154 -0
- package/src/postgres/grants-diff.ts +101 -0
- package/src/postgres/grants-errors.ts +215 -0
- package/src/postgres/grants-existence-guards.test.ts +113 -0
- package/src/postgres/grants-existence.ts +101 -0
- package/src/postgres/grants-lifecycle-guards.test.ts +208 -0
- package/src/postgres/grants-lifecycle-repair.test.ts +208 -0
- package/src/postgres/grants-lifecycle.test.ts +181 -0
- package/src/postgres/grants-ops.ts +229 -0
- package/src/postgres/grants-owner-revoke.test.ts +121 -0
- package/src/postgres/grants-ownership.ts +49 -0
- package/src/postgres/grants-plan-collateral.test.ts +202 -0
- package/src/postgres/grants-plan-diff.test.ts +204 -0
- package/src/postgres/grants-plan-restore.ts +43 -0
- package/src/postgres/grants-plan-revocations.test.ts +69 -0
- package/src/postgres/grants-plan.test.ts +148 -0
- package/src/postgres/grants-plan.ts +245 -0
- package/src/postgres/grants-provenance.test.ts +134 -0
- package/src/postgres/grants-psql-lifecycle.test.ts +105 -0
- package/src/postgres/grants-read-absent.test.ts +91 -0
- package/src/postgres/grants-read-defaults.ts +51 -0
- package/src/postgres/grants-read.ts +250 -0
- package/src/postgres/grants-refusals.test.ts +136 -0
- package/src/postgres/grants-refuse.ts +119 -0
- package/src/postgres/grants-relkind-wire.test.ts +111 -0
- package/src/postgres/grants-repair-plan.test.ts +201 -0
- package/src/postgres/grants-sql.test.ts +128 -0
- package/src/postgres/grants-sql.ts +144 -0
- package/src/postgres/grants-words.ts +34 -0
- package/src/postgres/grants.ts +110 -0
- package/src/postgres/index.ts +137 -7
- package/src/postgres/installed-classifier.ts +36 -0
- package/src/postgres/providers.ts +44 -7
- package/src/postgres/psql-executor-escaping.test.ts +67 -0
- package/src/postgres/psql-executor.test.ts +167 -0
- package/src/postgres/psql-executor.ts +170 -0
- package/src/postgres/role-adopt.test.ts +98 -0
- package/src/postgres/role-attrs.ts +134 -0
- package/src/postgres/role-diff.ts +89 -0
- package/src/postgres/role-errors.ts +198 -0
- package/src/postgres/role-guard.test.ts +60 -0
- package/src/postgres/role-identity.test.ts +185 -0
- package/src/postgres/role-lifecycle.test.ts +228 -0
- package/src/postgres/role-membership-sql.ts +198 -0
- package/src/postgres/role-password.test.ts +158 -0
- package/src/postgres/role-privilege.test.ts +80 -0
- package/src/postgres/role-provenance.test.ts +200 -0
- package/src/postgres/role-provider.ts +104 -0
- package/src/postgres/role-refusals.test.ts +250 -0
- package/src/postgres/role-scram.test.ts +38 -0
- package/src/postgres/role-scram.ts +38 -0
- package/src/postgres/role-secrets.ts +46 -0
- package/src/postgres/role-sql.ts +211 -0
- package/src/postgres/role-valid-until.test.ts +68 -0
- package/src/postgres/role.ts +218 -0
- package/src/postgres/schema-assert.ts +139 -0
- package/src/postgres/schema-attrs.ts +71 -0
- package/src/postgres/schema-delete-proofs.test.ts +192 -0
- package/src/postgres/schema-delete.ts +96 -0
- package/src/postgres/schema-diff.ts +44 -0
- package/src/postgres/schema-drop-2bp01.test.ts +146 -0
- package/src/postgres/schema-errors.ts +209 -0
- package/src/postgres/schema-handlers.test.ts +193 -0
- package/src/postgres/schema-identity.ts +39 -0
- package/src/postgres/schema-lifecycle.test.ts +246 -0
- package/src/postgres/schema-race.test.ts +70 -0
- package/src/postgres/schema-reconcile.ts +100 -0
- package/src/postgres/schema-refusals.test.ts +144 -0
- package/src/postgres/schema-socket.test.ts +161 -0
- package/src/postgres/schema-sql.ts +130 -0
- package/src/postgres/schema-takeover.test.ts +149 -0
- package/src/postgres/schema-test-kit.ts +85 -0
- package/src/postgres/schema.ts +130 -0
- package/src/proxmox/ceph-flag-types.ts +70 -0
- package/src/proxmox/ceph-flag-wire.test.ts +72 -0
- package/src/proxmox/ceph-flag-wire.ts +123 -0
- package/src/proxmox/ceph-flag.ts +77 -130
- package/src/proxmox/ceph-osd-write.ts +10 -13
- package/src/release/binary-alias.test.ts +3 -3
- package/src/release/binary-claims.test.ts +3 -3
- package/src/release/binary-directory-umask.test.ts +65 -0
- package/src/release/fake-engine.ts +15 -0
- package/src/valkey/acl-attrs.ts +98 -0
- package/src/valkey/acl-compare.ts +57 -0
- package/src/valkey/acl-connection.ts +13 -0
- package/src/valkey/acl-delete.test.ts +127 -0
- package/src/valkey/acl-form.ts +239 -0
- package/src/valkey/acl-managed.ts +13 -0
- package/src/valkey/acl-ops.ts +122 -0
- package/src/valkey/acl-ownership.test.ts +118 -0
- package/src/valkey/acl-prefix.test.ts +38 -0
- package/src/valkey/acl-profiles.ts +81 -0
- package/src/valkey/acl-reconcile.ts +180 -0
- package/src/valkey/acl-reserved.test.ts +69 -0
- package/src/valkey/acl-revocation.test.ts +94 -0
- package/src/valkey/acl-seat-prefix.test.ts +111 -0
- package/src/valkey/acl-validation.test.ts +54 -0
- package/src/valkey/acl.test.ts +215 -0
- package/src/valkey/acl.ts +169 -0
- package/src/valkey/connection-service.ts +46 -0
- package/src/valkey/connection.ts +180 -0
- package/src/valkey/errors.ts +239 -0
- package/src/valkey/fake-acl.ts +128 -0
- package/src/valkey/fake-valkey.ts +224 -0
- package/src/valkey/handler-test-fixture.ts +43 -0
- package/src/valkey/handlers.test.ts +205 -0
- package/src/valkey/index.ts +54 -0
- package/src/valkey/instance-attrs.ts +48 -0
- package/src/valkey/instance-form.ts +104 -0
- package/src/valkey/instance.test.ts +108 -0
- package/src/valkey/instance.ts +160 -0
- package/src/valkey/provider-socket-fixture.ts +71 -0
- package/src/valkey/providers.test.ts +129 -0
- package/src/valkey/providers.ts +21 -0
- package/src/valkey/resp.ts +212 -0
- package/src/valkey/transport-bounds.test.ts +150 -0
- package/src/valkey/transport-error.ts +37 -0
- package/src/valkey/transport.test.ts +158 -0
- package/src/valkey/transport.ts +109 -0
- package/src/valkey/upstream-bounds.test.ts +14 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read-answering half of the `Postgres.Grants` test fake: the `aclexplode`-shaped
|
|
3
|
+
* queries and the existence/ownership checks, answered from the server model's ACL
|
|
4
|
+
* (`fake-grants-sql.ts`), never from the statement list (S28). The entry and model shape
|
|
5
|
+
* are defined HERE so the write half (`fake-grants-write.ts`) can import them without a
|
|
6
|
+
* cycle.
|
|
7
|
+
*/
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import type { SqlError } from 'effect/unstable/sql/SqlError';
|
|
10
|
+
import type { AclObject } from './fake-grants-parse.ts';
|
|
11
|
+
|
|
12
|
+
/** One `aclitem` as the fake stores it: one (object, grantee, grantor) with the words that
|
|
13
|
+
* grantor granted, `*`-marked when WITH GRANT OPTION. `words` is mutable: grants and
|
|
14
|
+
* revokes edit it. */
|
|
15
|
+
export interface AclEntry {
|
|
16
|
+
readonly object: AclObject;
|
|
17
|
+
readonly grantee: string;
|
|
18
|
+
readonly grantor: string;
|
|
19
|
+
words: string[];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** One relation in the fake's catalog: every relation a table/column statement may name,
|
|
23
|
+
* with its columns, its `relkind` (default `'r'`) and its owner (default: the executor
|
|
24
|
+
* role, which no declared seat role owns). A sequence is a row with `relkind: 'S'`. */
|
|
25
|
+
export interface FakeCatalogTable {
|
|
26
|
+
readonly schema: string;
|
|
27
|
+
readonly table: string;
|
|
28
|
+
readonly columns?: ReadonlyArray<string>;
|
|
29
|
+
readonly relkind?: string;
|
|
30
|
+
readonly owner?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** What the read half needs from the factory, keyed per schema so two schemas may hold
|
|
34
|
+
* same-named relations: `relkinds`/`tableOwners` map `"schema\0table"`, `schemaOwners`
|
|
35
|
+
* maps the schema to its owning role. */
|
|
36
|
+
export interface FakeGrantsModel {
|
|
37
|
+
readonly schemas: ReadonlySet<string>;
|
|
38
|
+
readonly roles: ReadonlySet<string>;
|
|
39
|
+
readonly databases: ReadonlySet<string>;
|
|
40
|
+
readonly tables: ReadonlyArray<FakeCatalogTable>;
|
|
41
|
+
readonly acl: AclEntry[];
|
|
42
|
+
readonly relkinds: ReadonlyMap<string, string>;
|
|
43
|
+
readonly tableOwners: ReadonlyMap<string, string>;
|
|
44
|
+
readonly schemaOwners: ReadonlyMap<string, string>;
|
|
45
|
+
/** `current_user` — the grantor a write records, and the revoker the column read reports. */
|
|
46
|
+
readonly executor: string;
|
|
47
|
+
/** Whether `current_user` is a superuser: one arm of `revokesAsOwner` (a superuser revokes
|
|
48
|
+
* as the object owner, `revoke.sgml`). */
|
|
49
|
+
readonly executorSuper: boolean;
|
|
50
|
+
/** The roles `current_user` is a member of (recursively): a member of the owning role revokes
|
|
51
|
+
* as that role (`revokesAsOwner`). */
|
|
52
|
+
readonly executorMemberships: ReadonlySet<string>;
|
|
53
|
+
/** What `SELECT current_database()` answers. */
|
|
54
|
+
readonly connected: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const aclShapeRow = (marked: string): { privilege: string; grantable: boolean } => ({
|
|
58
|
+
privilege: marked.replace(/\*$/, ''),
|
|
59
|
+
grantable: marked.endsWith('*'),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
/** Whether a `REVOKE` from the executor is performed as the object's owner (`select_best_grantor`
|
|
63
|
+
* acl.c@REL_18_6): a superuser, the owner itself, or a member of the owning role. Gates the
|
|
64
|
+
* column read's `grantor === owner` arm; the write path removes the owner's grant under it. */
|
|
65
|
+
export const revokesAsOwner = (model: FakeGrantsModel, owner: string): boolean =>
|
|
66
|
+
model.executorSuper || model.executor === owner || model.executorMemberships.has(owner);
|
|
67
|
+
|
|
68
|
+
/** Explode the model into aclexplode-shaped rows, filtered to one read's object shape
|
|
69
|
+
* and grantee set. */
|
|
70
|
+
const rows = <R>(
|
|
71
|
+
acl: ReadonlyArray<AclEntry>,
|
|
72
|
+
pickObject: (object: AclObject) => boolean,
|
|
73
|
+
pickGrantee: (grantee: string) => boolean,
|
|
74
|
+
shape: (entry: AclEntry, word: string) => R,
|
|
75
|
+
): R[] => {
|
|
76
|
+
const out: R[] = [];
|
|
77
|
+
for (const entry of acl) {
|
|
78
|
+
if (!pickObject(entry.object) || !pickGrantee(entry.grantee)) continue;
|
|
79
|
+
for (const word of entry.words) out.push(shape(entry, word));
|
|
80
|
+
}
|
|
81
|
+
return out;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const granteeFilter =
|
|
85
|
+
(role: string) =>
|
|
86
|
+
(grantee: string): boolean =>
|
|
87
|
+
grantee === role || grantee === 'PUBLIC';
|
|
88
|
+
|
|
89
|
+
/** Answer the reads the family issues: the two existence checks, the schema/table/column/
|
|
90
|
+
* default `aclexplode` reads, and the two ownership reads. `undefined` when the text is no
|
|
91
|
+
* read this fake answers — the caller applies it as a write. */
|
|
92
|
+
export const answerRead = <A extends object>(
|
|
93
|
+
text: string,
|
|
94
|
+
params: ReadonlyArray<unknown>,
|
|
95
|
+
model: FakeGrantsModel,
|
|
96
|
+
): Effect.Effect<ReadonlyArray<A>, SqlError> | undefined => {
|
|
97
|
+
const { acl, schemas, roles, databases, tables } = model;
|
|
98
|
+
|
|
99
|
+
if (text.startsWith('SELECT 1 AS present FROM pg_roles')) {
|
|
100
|
+
return Effect.succeed(
|
|
101
|
+
(roles.has(params[0] as string) ? [{ present: 1 }] : []) as unknown as ReadonlyArray<A>,
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
if (text.startsWith('SELECT 1 AS present FROM pg_namespace')) {
|
|
105
|
+
return Effect.succeed(
|
|
106
|
+
(schemas.has(params[0] as string) ? [{ present: 1 }] : []) as unknown as ReadonlyArray<A>,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
if (text.startsWith('SELECT 1 AS present FROM pg_database')) {
|
|
110
|
+
return Effect.succeed(
|
|
111
|
+
(databases.has(params[0] as string) ? [{ present: 1 }] : []) as unknown as ReadonlyArray<A>,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
if (text.startsWith('SELECT current_database()')) {
|
|
115
|
+
return Effect.succeed([{ database: model.connected }] as unknown as ReadonlyArray<A>);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const jsonNames = (value: unknown): unknown => {
|
|
119
|
+
if (typeof value !== 'string') {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`fake-grants-read: existence param must be a JSON string, got ${typeof value}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
return JSON.parse(value) as unknown;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const [schema, role] = [params[0] as string, params[1] as string];
|
|
128
|
+
if (
|
|
129
|
+
text.includes('c.relname AS table') &&
|
|
130
|
+
text.includes('pg_class c') &&
|
|
131
|
+
text.includes('json_array_elements_text') &&
|
|
132
|
+
!text.includes('pg_attribute')
|
|
133
|
+
) {
|
|
134
|
+
const want = new Set(jsonNames(params[1]) as ReadonlyArray<string>);
|
|
135
|
+
return Effect.succeed(
|
|
136
|
+
tables
|
|
137
|
+
.filter((t) => t.schema === schema && want.has(t.table))
|
|
138
|
+
.map((t) => ({ table: t.table })) as unknown as ReadonlyArray<A>,
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
if (text.includes('a.attname AS column') && text.includes('json_array_elements($2::json)')) {
|
|
142
|
+
const pairs = jsonNames(params[1]) as ReadonlyArray<readonly [string, string]>;
|
|
143
|
+
const want = new Set(pairs.map(([table, column]) => `${table}\u0000${column}`));
|
|
144
|
+
return Effect.succeed(
|
|
145
|
+
tables
|
|
146
|
+
.filter((t) => t.schema === schema)
|
|
147
|
+
.flatMap((t) =>
|
|
148
|
+
(t.columns ?? [])
|
|
149
|
+
.filter((c) => want.has(`${t.table}\u0000${c}`))
|
|
150
|
+
.map((c) => ({ table: t.table, column: c })),
|
|
151
|
+
) as unknown as ReadonlyArray<A>,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
if (text.includes('aclexplode(n.nspacl)')) {
|
|
155
|
+
return Effect.succeed(
|
|
156
|
+
rows(
|
|
157
|
+
acl,
|
|
158
|
+
(o) =>
|
|
159
|
+
o.schema === schema &&
|
|
160
|
+
o.table === undefined &&
|
|
161
|
+
o.column === undefined &&
|
|
162
|
+
o.defaultFor === undefined,
|
|
163
|
+
granteeFilter(role),
|
|
164
|
+
(entry, marked) => ({ public: entry.grantee === 'PUBLIC', ...aclShapeRow(marked) }),
|
|
165
|
+
) as unknown as ReadonlyArray<A>,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
if (text.includes('aclexplode(c.relacl)')) {
|
|
169
|
+
// The relkind comes back shaped exactly as the query TEXT dictates: the production
|
|
170
|
+
// SQL casts `c.relkind::text` (OID 25, a string); without the cast the `"char"` OID 18
|
|
171
|
+
// column decodes to raw bytes on the socket transport (`PgTypes` has no OID 18 codec),
|
|
172
|
+
// so this fake hands back the same `Uint8Array` the real wire would — one byte per
|
|
173
|
+
// relkind letter — to keep a regression test honest.
|
|
174
|
+
const relkindFor = (object: AclObject): unknown => {
|
|
175
|
+
const relkind = model.relkinds.get(`${object.schema}\u0000${object.table ?? ''}`) ?? 'r';
|
|
176
|
+
if (text.includes('c.relkind::text')) return relkind;
|
|
177
|
+
return new Uint8Array(relkind.split('').map((ch) => ch.charCodeAt(0)));
|
|
178
|
+
};
|
|
179
|
+
return Effect.succeed(
|
|
180
|
+
rows(
|
|
181
|
+
acl,
|
|
182
|
+
(o) =>
|
|
183
|
+
o.schema === schema &&
|
|
184
|
+
o.table !== undefined &&
|
|
185
|
+
o.column === undefined &&
|
|
186
|
+
o.defaultFor === undefined,
|
|
187
|
+
granteeFilter(role),
|
|
188
|
+
(entry, marked) => ({
|
|
189
|
+
table: entry.object.table,
|
|
190
|
+
relkind: relkindFor(entry.object),
|
|
191
|
+
public: entry.grantee === 'PUBLIC',
|
|
192
|
+
...aclShapeRow(marked),
|
|
193
|
+
}),
|
|
194
|
+
) as unknown as ReadonlyArray<A>,
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (text.includes('aclexplode(v.attacl)')) {
|
|
198
|
+
return Effect.succeed(
|
|
199
|
+
rows(
|
|
200
|
+
acl,
|
|
201
|
+
(o) => o.schema === schema && o.column !== undefined,
|
|
202
|
+
granteeFilter(role),
|
|
203
|
+
(entry, marked) => {
|
|
204
|
+
const owner =
|
|
205
|
+
model.tableOwners.get(`${entry.object.schema}\u0000${entry.object.table ?? ''}`) ??
|
|
206
|
+
model.executor;
|
|
207
|
+
return {
|
|
208
|
+
table: entry.object.table,
|
|
209
|
+
column: entry.object.column,
|
|
210
|
+
public: entry.grantee === 'PUBLIC',
|
|
211
|
+
grantor: entry.grantor,
|
|
212
|
+
owner,
|
|
213
|
+
revoker: model.executor,
|
|
214
|
+
revoker_as_owner: revokesAsOwner(model, owner),
|
|
215
|
+
...aclShapeRow(marked),
|
|
216
|
+
};
|
|
217
|
+
},
|
|
218
|
+
) as unknown as ReadonlyArray<A>,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (text.includes('aclexplode(d.defaclacl)')) {
|
|
222
|
+
// The defaults read selects ONLY the declared role's words — never PUBLIC's.
|
|
223
|
+
return Effect.succeed(
|
|
224
|
+
rows(
|
|
225
|
+
acl,
|
|
226
|
+
(o) => o.schema === schema && o.defaultFor !== undefined,
|
|
227
|
+
(grantee) => grantee === role,
|
|
228
|
+
(entry, marked) => ({ for_role: entry.object.defaultFor, ...aclShapeRow(marked) }),
|
|
229
|
+
) as unknown as ReadonlyArray<A>,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// The ownership reads: `nspowner` answers per schema, `relowner` per relation, all
|
|
234
|
+
// relkinds — from the catalog and the owner maps, never from ACL rows (a fresh owned
|
|
235
|
+
// object carries none).
|
|
236
|
+
if (text.includes('nspowner')) {
|
|
237
|
+
const owns = model.schemaOwners.get(schema) === role;
|
|
238
|
+
return Effect.succeed([{ role_owns: owns }] as unknown as ReadonlyArray<A>);
|
|
239
|
+
}
|
|
240
|
+
if (text.includes('relowner')) {
|
|
241
|
+
const owned = tables
|
|
242
|
+
.filter(
|
|
243
|
+
(t) => t.schema === schema && model.tableOwners.get(`${schema}\u0000${t.table}`) === role,
|
|
244
|
+
)
|
|
245
|
+
.map((t) => ({ table: t.table }));
|
|
246
|
+
return Effect.succeed(owned as unknown as ReadonlyArray<A>);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return undefined;
|
|
250
|
+
};
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server-model half of the `Postgres.Grants` test fake: an in-memory ACL the way
|
|
3
|
+
* PostgreSQL 18 packs it — one entry per (object, grantee, grantor) pair holding that
|
|
4
|
+
* grantor's granted words — plus the ten statements the parser (`fake-grants-parse.ts`)
|
|
5
|
+
* reduces, applied with the server rules the plan's convergence depends on. The
|
|
6
|
+
* `aclexplode`-shaped reads are answered by `fake-grants-read.ts` from the same model; the
|
|
7
|
+
* grant/revoke semantics (the "revokes as owner" rule included) live in
|
|
8
|
+
* `fake-grants-write.ts`.
|
|
9
|
+
*
|
|
10
|
+
* ★ `REVOKE ALL ON <table>` ALSO clears that grantee's column entries on the table
|
|
11
|
+
* (measured on PG 18.6 — the plan's convergence proof depends on the model answering
|
|
12
|
+
* the same), and `REVOKE ALL ON ALL TABLES IN SCHEMA` skips the relkinds the server
|
|
13
|
+
* skips — a sequence keeps its grants (measured, `grants-plan.ts`).
|
|
14
|
+
* ★ A statement naming a relation or column the catalog does not know fails `42P01` /
|
|
15
|
+
* `42703`, the way the server refuses a missing object.
|
|
16
|
+
*/
|
|
17
|
+
import * as Effect from 'effect/Effect';
|
|
18
|
+
import { SqlError, SqlSyntaxError } from 'effect/unstable/sql/SqlError';
|
|
19
|
+
import type { PgExecutor } from './database-sql.ts';
|
|
20
|
+
import { type AclEntry, type FakeCatalogTable, answerRead } from './fake-grants-read.ts';
|
|
21
|
+
import { parseGrantStatement } from './fake-grants-parse.ts';
|
|
22
|
+
import { grantWords, revoke } from './fake-grants-write.ts';
|
|
23
|
+
import { relkindIsPublicRevocable } from './grants-words.ts';
|
|
24
|
+
|
|
25
|
+
export type { AclEntry, FakeCatalogTable };
|
|
26
|
+
|
|
27
|
+
export interface RecordedStatement {
|
|
28
|
+
readonly text: string;
|
|
29
|
+
readonly params: ReadonlyArray<unknown>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface FakeGrants extends PgExecutor {
|
|
33
|
+
readonly statements: ReadonlyArray<RecordedStatement>;
|
|
34
|
+
/** Each `transaction` call, in order — the statement list that committed together. */
|
|
35
|
+
readonly transactions: ReadonlyArray<ReadonlyArray<string>>;
|
|
36
|
+
/** Mutable on purpose: a test seeds a "competing" grant the same way `fake-sql.ts`'s
|
|
37
|
+
* `databases` map is seeded before the reconcile ever runs. */
|
|
38
|
+
readonly acl: AclEntry[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface FakeGrantsOptions {
|
|
42
|
+
/** Schemas the existence check (`pg_namespace`) answers yes for. */
|
|
43
|
+
readonly schemas?: ReadonlyArray<string>;
|
|
44
|
+
/** Roles the existence check (`pg_roles`) answers yes for. */
|
|
45
|
+
readonly roles?: ReadonlyArray<string>;
|
|
46
|
+
/** Databases the existence check (`pg_database`) answers yes for. */
|
|
47
|
+
readonly databases?: ReadonlyArray<string>;
|
|
48
|
+
/** The catalog: every relation a table/column statement may name, with its columns,
|
|
49
|
+
* relkind and owner (see `fake-grants-read.ts#FakeCatalogTable`). */
|
|
50
|
+
readonly tables?: ReadonlyArray<FakeCatalogTable>;
|
|
51
|
+
/** The role that owns each seeded schema; unset means the executor owns it. */
|
|
52
|
+
readonly schemaOwner?: string;
|
|
53
|
+
/** Seed grants, each carrying its own grantor (the third-grantor survival cases). */
|
|
54
|
+
readonly acl?: ReadonlyArray<Omit<AclEntry, 'words'> & { readonly words: ReadonlyArray<string> }>;
|
|
55
|
+
/** The role the statements run AS — the grantor recorded on every write, and
|
|
56
|
+
* `current_user` on the column read (default `postgres`, the owner the fixtures assume). */
|
|
57
|
+
readonly executor?: string;
|
|
58
|
+
/** Whether the executor is a superuser (default `true`: `postgres` is). A superuser, the
|
|
59
|
+
* owner itself, or a member of the owning role revokes as the owner — `revoke.sgml`'s rule,
|
|
60
|
+
* modelled by `revokesAsOwner` (fake-grants-read.ts) on both the read and the write. */
|
|
61
|
+
readonly executorSuper?: boolean;
|
|
62
|
+
/** The roles the executor is a member of (recursively): a member of a table's owning role
|
|
63
|
+
* revokes that table's grants as the owner, the same as a superuser. */
|
|
64
|
+
readonly executorMemberships?: ReadonlyArray<string>;
|
|
65
|
+
/** What `current_database()` answers (default `agents`, the declaration the fixtures use). */
|
|
66
|
+
readonly connected?: string;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const failSql = (code: string, message: string, operation: string) =>
|
|
70
|
+
Effect.fail(
|
|
71
|
+
new SqlError({
|
|
72
|
+
reason: new SqlSyntaxError({
|
|
73
|
+
cause: Object.assign(new Error(message), { code }),
|
|
74
|
+
message,
|
|
75
|
+
operation,
|
|
76
|
+
}),
|
|
77
|
+
}),
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
export const makeFakeGrants = (options: FakeGrantsOptions = {}): FakeGrants => {
|
|
81
|
+
const statements: RecordedStatement[] = [];
|
|
82
|
+
const transactions: string[][] = [];
|
|
83
|
+
const schemas = new Set(options.schemas ?? []);
|
|
84
|
+
const roles = new Set(options.roles ?? []);
|
|
85
|
+
const databases = new Set(options.databases ?? []);
|
|
86
|
+
const tables = options.tables ?? [];
|
|
87
|
+
const executor = options.executor ?? 'postgres';
|
|
88
|
+
const executorSuper = options.executorSuper ?? true;
|
|
89
|
+
const executorMemberships = new Set(options.executorMemberships ?? []);
|
|
90
|
+
const connected = options.connected ?? 'agents';
|
|
91
|
+
const acl: AclEntry[] = (options.acl ?? []).map((seed) => ({ ...seed, words: [...seed.words] }));
|
|
92
|
+
|
|
93
|
+
// The catalog as pg_class really holds it: relkind and owner per (schema, table), the
|
|
94
|
+
// schema owned by `schemaOwner` or the executor. Default table owner is the schema
|
|
95
|
+
// owner — a CREATE inside a namespace makes its creator the relation's owner too.
|
|
96
|
+
const schemaOwner = options.schemaOwner ?? executor;
|
|
97
|
+
const relkinds = new Map<string, string>();
|
|
98
|
+
const tableOwners = new Map<string, string>();
|
|
99
|
+
for (const t of tables) {
|
|
100
|
+
relkinds.set(`${t.schema}\u0000${t.table}`, t.relkind ?? 'r');
|
|
101
|
+
tableOwners.set(`${t.schema}\u0000${t.table}`, t.owner ?? schemaOwner);
|
|
102
|
+
}
|
|
103
|
+
const schemaOwners = new Map<string, string>();
|
|
104
|
+
for (const schema of schemas) schemaOwners.set(schema, schemaOwner);
|
|
105
|
+
const model = {
|
|
106
|
+
schemas,
|
|
107
|
+
roles,
|
|
108
|
+
databases,
|
|
109
|
+
tables,
|
|
110
|
+
acl,
|
|
111
|
+
relkinds,
|
|
112
|
+
tableOwners,
|
|
113
|
+
schemaOwners,
|
|
114
|
+
executor,
|
|
115
|
+
executorSuper,
|
|
116
|
+
executorMemberships,
|
|
117
|
+
connected,
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const knownTable = (schema: string, table: string) =>
|
|
121
|
+
tables.find((t) => t.schema === schema && t.table === table);
|
|
122
|
+
|
|
123
|
+
/** Apply one parsed write, validating its target against the catalog first. */
|
|
124
|
+
const applyWrite = (text: string): Effect.Effect<ReadonlyArray<never>, SqlError> => {
|
|
125
|
+
const parsed = parseGrantStatement(text);
|
|
126
|
+
if (parsed === undefined) {
|
|
127
|
+
throw new Error(`fake-grants-sql: unrecognised statement: ${text}`);
|
|
128
|
+
}
|
|
129
|
+
if (parsed.object.table !== undefined) {
|
|
130
|
+
const known = knownTable(parsed.object.schema, parsed.object.table);
|
|
131
|
+
if (known === undefined) {
|
|
132
|
+
return failSql(
|
|
133
|
+
'42P01',
|
|
134
|
+
`relation "${parsed.object.table}" does not exist`,
|
|
135
|
+
text.slice(0, 30),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (
|
|
139
|
+
parsed.object.column !== undefined &&
|
|
140
|
+
!(known.columns ?? []).includes(parsed.object.column)
|
|
141
|
+
) {
|
|
142
|
+
return failSql(
|
|
143
|
+
'42703',
|
|
144
|
+
`column "${parsed.object.column}" does not exist`,
|
|
145
|
+
text.slice(0, 30),
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const operation = text.slice(0, 30);
|
|
150
|
+
if (parsed.allTables === true) {
|
|
151
|
+
// `ON ALL TABLES IN SCHEMA` reaches only the revocable relkinds — a sequence keeps
|
|
152
|
+
// its grants (measured on PG 18.6, `grants-plan.ts`).
|
|
153
|
+
for (const table of tables.filter(
|
|
154
|
+
(t) => t.schema === parsed.object.schema && relkindIsPublicRevocable(t.relkind ?? 'r'),
|
|
155
|
+
)) {
|
|
156
|
+
const tableObject = { schema: parsed.object.schema, table: table.table };
|
|
157
|
+
const tableError = revoke(model, tableObject, parsed.grantee, operation);
|
|
158
|
+
if (tableError !== undefined) return Effect.fail(tableError);
|
|
159
|
+
for (const column of table.columns ?? []) {
|
|
160
|
+
const columnError = revoke(model, { ...tableObject, column }, parsed.grantee, operation);
|
|
161
|
+
if (columnError !== undefined) return Effect.fail(columnError);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
return Effect.succeed([]);
|
|
165
|
+
}
|
|
166
|
+
if (parsed.kind === 'grant') {
|
|
167
|
+
grantWords(model, parsed.object, parsed.grantee, parsed.words, parsed.option);
|
|
168
|
+
return Effect.succeed([]);
|
|
169
|
+
}
|
|
170
|
+
const error = revoke(model, parsed.object, parsed.grantee, operation);
|
|
171
|
+
if (error !== undefined) return Effect.fail(error);
|
|
172
|
+
// A table-level `REVOKE ALL` also clears that grantee's column entries on the table
|
|
173
|
+
// (measured on PG 18.6 — a table revoke reaches its columns, unlike `ON ALL TABLES`).
|
|
174
|
+
if (parsed.object.table !== undefined && parsed.object.column === undefined) {
|
|
175
|
+
const known = knownTable(parsed.object.schema, parsed.object.table);
|
|
176
|
+
for (const column of known?.columns ?? []) {
|
|
177
|
+
const columnError = revoke(
|
|
178
|
+
model,
|
|
179
|
+
{ schema: parsed.object.schema, table: parsed.object.table, column },
|
|
180
|
+
parsed.grantee,
|
|
181
|
+
operation,
|
|
182
|
+
);
|
|
183
|
+
if (columnError !== undefined) return Effect.fail(columnError);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return Effect.succeed([]);
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const unsafe = <A extends object>(
|
|
190
|
+
text: string,
|
|
191
|
+
params: ReadonlyArray<unknown> = [],
|
|
192
|
+
): Effect.Effect<ReadonlyArray<A>, SqlError> =>
|
|
193
|
+
Effect.suspend(() => {
|
|
194
|
+
statements.push({ text, params });
|
|
195
|
+
const read = answerRead<A>(text, params, model);
|
|
196
|
+
if (read !== undefined) return read;
|
|
197
|
+
return applyWrite(text) as unknown as Effect.Effect<ReadonlyArray<A>, SqlError>;
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
const transaction = (sqls: readonly string[]): Effect.Effect<void, SqlError> =>
|
|
201
|
+
Effect.gen(function* () {
|
|
202
|
+
transactions.push([...sqls]);
|
|
203
|
+
for (const sql of sqls) yield* unsafe(sql).pipe(Effect.asVoid);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return { unsafe, transaction, statements, transactions, acl };
|
|
207
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The write-semantics half of the `Postgres.Grants` test fake, extracted from
|
|
3
|
+
* `fake-grants-sql.ts` (the factory and the statement parser) to keep both files under the
|
|
4
|
+
* cap: how one `GRANT`/`REVOKE` edits the in-memory ACL with the server's rule that a
|
|
5
|
+
* superuser, the owner itself, or a member of the owning role performs the command AS the
|
|
6
|
+
* owner (`select_best_grantor`, acl.c@REL_18_6; `revoke.sgml@REL_18_6`).
|
|
7
|
+
*
|
|
8
|
+
* ★ THE EFFECTIVE GRANTOR. `effectiveGrantor` names the role a write is recorded as: the
|
|
9
|
+
* owner when the executor acts as owner, otherwise the executor. A relation (table, column)
|
|
10
|
+
* is owned by its `relowner`; a schema by its `nspowner`; a default ACL has no owner, so the
|
|
11
|
+
* executor's own grants are the only ones its writes touch.
|
|
12
|
+
* ★ `GRANT` records the words on the effective grantor's entry, upgrading a base word to its
|
|
13
|
+
* `*` (WITH GRANT OPTION) form rather than keeping both — one `aclitem` per pair.
|
|
14
|
+
* ★ `REVOKE ALL` removes the effective grantor's entry only: a third grantor's grant to the
|
|
15
|
+
* same grantee SURVIVES silently (the survival `PostgresGrantsRepairRefused` surfaces), and
|
|
16
|
+
* a grantee that re-granted onward fails like the server without CASCADE (`2BP01`).
|
|
17
|
+
*/
|
|
18
|
+
import { SqlError, SqlSyntaxError } from 'effect/unstable/sql/SqlError';
|
|
19
|
+
import type { AclObject } from './fake-grants-parse.ts';
|
|
20
|
+
import { type FakeGrantsModel, revokesAsOwner } from './fake-grants-read.ts';
|
|
21
|
+
|
|
22
|
+
const sameObject = (a: AclObject, b: AclObject): boolean =>
|
|
23
|
+
a.schema === b.schema &&
|
|
24
|
+
a.table === b.table &&
|
|
25
|
+
a.column === b.column &&
|
|
26
|
+
a.defaultFor === b.defaultFor;
|
|
27
|
+
|
|
28
|
+
/** The role a `GRANT`/`REVOKE` from the executor on `object` is performed AS (see the header). */
|
|
29
|
+
export const effectiveGrantor = (model: FakeGrantsModel, object: AclObject): string => {
|
|
30
|
+
if (object.table !== undefined) {
|
|
31
|
+
const owner = model.tableOwners.get(`${object.schema}\u0000${object.table}`) ?? model.executor;
|
|
32
|
+
return revokesAsOwner(model, owner) ? owner : model.executor;
|
|
33
|
+
}
|
|
34
|
+
if (object.defaultFor === undefined) {
|
|
35
|
+
const owner = model.schemaOwners.get(object.schema) ?? model.executor;
|
|
36
|
+
return revokesAsOwner(model, owner) ? owner : model.executor;
|
|
37
|
+
}
|
|
38
|
+
return model.executor;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/** Add words to the (object, grantee, effective-grantor) entry, upgrading a base word to its
|
|
42
|
+
* `*` form rather than keeping both. */
|
|
43
|
+
export const grantWords = (
|
|
44
|
+
model: FakeGrantsModel,
|
|
45
|
+
object: AclObject,
|
|
46
|
+
grantee: string,
|
|
47
|
+
words: ReadonlyArray<string>,
|
|
48
|
+
option: boolean,
|
|
49
|
+
): void => {
|
|
50
|
+
const grantor = effectiveGrantor(model, object);
|
|
51
|
+
const acl = model.acl;
|
|
52
|
+
let entry = acl.find(
|
|
53
|
+
(e) => sameObject(e.object, object) && e.grantee === grantee && e.grantor === grantor,
|
|
54
|
+
);
|
|
55
|
+
if (entry === undefined) {
|
|
56
|
+
entry = { object, grantee, grantor, words: [] };
|
|
57
|
+
acl.push(entry);
|
|
58
|
+
}
|
|
59
|
+
for (const word of words) {
|
|
60
|
+
const base = word.replace(/\*$/, '');
|
|
61
|
+
entry.words = entry.words.filter((w) => w.replace(/\*$/, '') !== base);
|
|
62
|
+
entry.words.push(option ? `${word}*` : word);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** Remove the effective grantor's grants for (object, grantee); a third grantor's entry
|
|
67
|
+
* survives by the keying, and a grantee that re-granted onward fails without CASCADE. */
|
|
68
|
+
export const revoke = (
|
|
69
|
+
model: FakeGrantsModel,
|
|
70
|
+
object: AclObject,
|
|
71
|
+
grantee: string,
|
|
72
|
+
operation: string,
|
|
73
|
+
): SqlError | undefined => {
|
|
74
|
+
const grantor = effectiveGrantor(model, object);
|
|
75
|
+
const acl = model.acl;
|
|
76
|
+
const own = acl.filter(
|
|
77
|
+
(e) => sameObject(e.object, object) && e.grantee === grantee && e.grantor === grantor,
|
|
78
|
+
);
|
|
79
|
+
if (own.length > 0 && acl.some((e) => sameObject(e.object, object) && e.grantor === grantee)) {
|
|
80
|
+
return new SqlError({
|
|
81
|
+
reason: new SqlSyntaxError({
|
|
82
|
+
cause: Object.assign(new Error('dependent privileges exist'), { code: '2BP01' }),
|
|
83
|
+
message: 'dependent privileges exist',
|
|
84
|
+
operation,
|
|
85
|
+
}),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
for (const entry of own) acl.splice(acl.indexOf(entry), 1);
|
|
89
|
+
return undefined;
|
|
90
|
+
};
|