@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,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Valkey.AclFile` reconcile core, against any executor. Extracted from the old single-file
|
|
3
|
+
* `acl.ts` and reworked for the round-3 findings:
|
|
4
|
+
*
|
|
5
|
+
* ★ GATE FIRST (F3). `CONFIG GET aclfile` non-empty → `ValkeyAclFileRendered`, BEFORE any write.
|
|
6
|
+
* The rendered file is the source of truth (CT100: openbao-agent renders it and a runtime
|
|
7
|
+
* write reverts — the measured WRONGPASS seat). `delete` runs the same gate (`acl.ts`).
|
|
8
|
+
* ★ RUNTIME-ONLY WRITES, NO `ACL SAVE` (F3). In kit-owned mode (empty aclfile) `ACL SAVE`
|
|
9
|
+
* measurably errors on 8.1.10 — "This instance is not configured to use an ACL file" — so the
|
|
10
|
+
* kit-owned family never calls it. ACL state is runtime state, not data: it does not survive
|
|
11
|
+
* a restart even with appendonly (measured), so this family re-asserts on every reconcile.
|
|
12
|
+
* ★ NEVER-MANAGED USERS ARE PRESERVED BY DEFAULT (F1). `planAclUsers` only DELUSERs those
|
|
13
|
+
* under `exclusive: true`; removing a previously declared user always revokes it.
|
|
14
|
+
*/
|
|
15
|
+
import * as Effect from 'effect/Effect';
|
|
16
|
+
import { type Environment, type FromEnv, resolveAll, seal } from '../secrets/write-only.ts';
|
|
17
|
+
import type {
|
|
18
|
+
ValkeyAclFileAttributes,
|
|
19
|
+
ValkeyAclFileProps,
|
|
20
|
+
ValkeyAclUser,
|
|
21
|
+
ValkeyAclUserAttributes,
|
|
22
|
+
} from './acl-attrs.ts';
|
|
23
|
+
import { managedUserNames } from './acl-managed.ts';
|
|
24
|
+
import { matchesDeclared } from './acl-compare.ts';
|
|
25
|
+
import {
|
|
26
|
+
buildDelUserArgs,
|
|
27
|
+
buildSetUserArgs,
|
|
28
|
+
passwordState,
|
|
29
|
+
planAclUsers,
|
|
30
|
+
refusalBeforeWrite,
|
|
31
|
+
} from './acl-form.ts';
|
|
32
|
+
import { readAclFileConfig, readParsedUsers, toUserAttributes } from './acl-ops.ts';
|
|
33
|
+
import {
|
|
34
|
+
ValkeyAclFileRendered,
|
|
35
|
+
ValkeyAclPasswordMissing,
|
|
36
|
+
ValkeyAclReadbackFailed,
|
|
37
|
+
type ValkeyError,
|
|
38
|
+
} from './errors.ts';
|
|
39
|
+
import { type ValkeyExecutor, ValkeyServerError, type ValkeyTransportError } from './transport.ts';
|
|
40
|
+
|
|
41
|
+
/** The reconcile core: gate on the rendered aclfile, refuse bad declarations, resolve every
|
|
42
|
+
* password ONCE, plan against the live ACL, write, then re-read and verify (S10: never trust
|
|
43
|
+
* the write). `stored` is the state this stack already holds (`output`); it is what adoption
|
|
44
|
+
* lacks, and its absence is what makes the first plan a write. `self` is the connection's own
|
|
45
|
+
* username — never managed, like `default`. */
|
|
46
|
+
export const reconcileWithExecutor = (
|
|
47
|
+
executor: ValkeyExecutor,
|
|
48
|
+
props: ValkeyAclFileProps,
|
|
49
|
+
stored: ValkeyAclFileAttributes | undefined,
|
|
50
|
+
env: Environment = process.env,
|
|
51
|
+
self?: string,
|
|
52
|
+
previous?: ValkeyAclFileProps,
|
|
53
|
+
): Effect.Effect<ValkeyAclFileAttributes, ValkeyError | ValkeyTransportError> =>
|
|
54
|
+
Effect.gen(function* () {
|
|
55
|
+
// ⛔ BEFORE ANY WRITE. The aclfile gate stands in front of the declaration refusals and the
|
|
56
|
+
// writes: on a rendered instance this family writes nothing at all, good or bad.
|
|
57
|
+
const aclfile = yield* readAclFileConfig(executor);
|
|
58
|
+
if (aclfile !== '') {
|
|
59
|
+
return yield* Effect.fail(
|
|
60
|
+
new ValkeyAclFileRendered({ instance: props.instance, path: aclfile }),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Declaration refusals (reserved names, split record key, seat prefix escapes, glob chars in
|
|
65
|
+
// names, monitor-with-keyPrefix). Read hides `default` and the connection username, so a
|
|
66
|
+
// declaration of either would otherwise look absent and `reset` the kit's own credential.
|
|
67
|
+
const refused = refusalBeforeWrite(props.instance, props.users, self);
|
|
68
|
+
if (refused !== undefined) return yield* Effect.fail(refused);
|
|
69
|
+
|
|
70
|
+
// Resolve every declared password ONCE, at call time. A user the plan does not need to write
|
|
71
|
+
// does not demand its variable — that is the `unknown` state, and it never drifts (diff).
|
|
72
|
+
const refs: Record<string, FromEnv> = {};
|
|
73
|
+
for (const [name, user] of Object.entries(props.users)) refs[name] = user.password;
|
|
74
|
+
const { values } = resolveAll(refs, env);
|
|
75
|
+
|
|
76
|
+
const live = yield* readParsedUsers(executor, self);
|
|
77
|
+
const { create, update, remove, undeclared } = planAclUsers(
|
|
78
|
+
props.users,
|
|
79
|
+
live,
|
|
80
|
+
props.exclusive,
|
|
81
|
+
managedUserNames(stored, previous),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
// Preserve-by-default (F1): never-managed users need exclusive ownership to be removed.
|
|
85
|
+
// Previously managed users are revoked; `default`/`self` never appear in this live map.
|
|
86
|
+
for (const name of undeclared) {
|
|
87
|
+
yield* Effect.logWarning(
|
|
88
|
+
`Valkey.AclFile "${props.instance}": live ACL user "${name}" is not declared; ${
|
|
89
|
+
remove.includes(name)
|
|
90
|
+
? 'it is scheduled for deletion (previously managed or exclusive: true).'
|
|
91
|
+
: 'it was left alone (exclusive: false).'
|
|
92
|
+
}`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Rotate: live and shaped exactly as declared, but the stored seal is absent (an adopted
|
|
97
|
+
// user) or disagrees with the value this process holds — the reset-first rewrite is what
|
|
98
|
+
// retires the old password, so the seal change must reach the server, not only the state.
|
|
99
|
+
const rotate = Object.entries(props.users)
|
|
100
|
+
.filter(([name, user]) => {
|
|
101
|
+
const liveUser = live[name];
|
|
102
|
+
const sealed = stored?.users[name]?.passwordSeal ?? '';
|
|
103
|
+
return (
|
|
104
|
+
liveUser !== undefined &&
|
|
105
|
+
matchesDeclared(liveUser, user) &&
|
|
106
|
+
passwordState(sealed, values[name]) === 'stale'
|
|
107
|
+
);
|
|
108
|
+
})
|
|
109
|
+
.map(([, user]) => user);
|
|
110
|
+
|
|
111
|
+
// Every write re-sends the password (`reset` clears it), so a write without the value would
|
|
112
|
+
// leave the user unable to authenticate — refused, naming the first user and variable. The
|
|
113
|
+
// refusal is checked for EVERY user before the first write, so a missing variable never
|
|
114
|
+
// leaves half of the plan applied.
|
|
115
|
+
const writes = [...create, ...update, ...rotate];
|
|
116
|
+
const writeList: Array<{ readonly user: ValkeyAclUser; readonly password: string }> = [];
|
|
117
|
+
for (const user of writes) {
|
|
118
|
+
const password = values[user.name];
|
|
119
|
+
if (password === undefined) {
|
|
120
|
+
return yield* Effect.fail(
|
|
121
|
+
new ValkeyAclPasswordMissing({
|
|
122
|
+
instance: props.instance,
|
|
123
|
+
user: user.name,
|
|
124
|
+
variable: user.password.fromEnv,
|
|
125
|
+
}),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
writeList.push({ user, password });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ⛔ RUNTIME-ONLY. `reset`-first SETUSER per write; DELUSER for removed managed users or `exclusive`. No
|
|
132
|
+
// `ACL SAVE`: in the only mode this family writes (empty aclfile) it measurably errors on
|
|
133
|
+
// 8.1.10. See the header note for the restart semantics that follow.
|
|
134
|
+
for (const { user, password } of writeList) {
|
|
135
|
+
const reply = yield* executor.send(yield* buildSetUserArgs(user, password));
|
|
136
|
+
if (reply.kind === 'error') {
|
|
137
|
+
return yield* Effect.fail(new ValkeyServerError({ detail: reply.message }));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (remove.length > 0) {
|
|
141
|
+
const reply = yield* executor.send(buildDelUserArgs(remove));
|
|
142
|
+
if (reply.kind === 'error') {
|
|
143
|
+
return yield* Effect.fail(new ValkeyServerError({ detail: reply.message }));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Read back and verify: every declared user, exactly as declared (S10). Undeclared leftovers
|
|
148
|
+
// fail under `exclusive` or when a previously managed user was scheduled for revocation.
|
|
149
|
+
const after = yield* readParsedUsers(executor, self);
|
|
150
|
+
for (const [name, user] of Object.entries(props.users)) {
|
|
151
|
+
const parsed = after[name];
|
|
152
|
+
if (parsed === undefined || !matchesDeclared(parsed, user)) {
|
|
153
|
+
return yield* Effect.fail(
|
|
154
|
+
new ValkeyAclReadbackFailed({ instance: props.instance, user: name }),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (props.exclusive || remove.length > 0) {
|
|
159
|
+
for (const name of Object.keys(after)) {
|
|
160
|
+
if (props.users[name] === undefined && (props.exclusive || remove.includes(name))) {
|
|
161
|
+
return yield* Effect.fail(
|
|
162
|
+
new ValkeyAclReadbackFailed({ instance: props.instance, user: name }),
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Seals: keep what the store held for users this run did not write, mint a fresh one for
|
|
169
|
+
// every user it did. A user absent from `stored` (adoption) gets its first seal here.
|
|
170
|
+
const seals: Record<string, string> = {};
|
|
171
|
+
for (const name of Object.keys(props.users)) {
|
|
172
|
+
seals[name] = stored?.users[name]?.passwordSeal ?? '';
|
|
173
|
+
}
|
|
174
|
+
for (const { user, password } of writeList) seals[user.name] = seal({ password });
|
|
175
|
+
const users: Record<string, ValkeyAclUserAttributes> = {};
|
|
176
|
+
for (const [name, parsed] of Object.entries(after)) {
|
|
177
|
+
users[name] = { ...toUserAttributes(parsed), passwordSeal: seals[name] ?? '' };
|
|
178
|
+
}
|
|
179
|
+
return { instance: props.instance, users, managedUsers: Object.keys(props.users).sort() };
|
|
180
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declaring `default` or the connection username must fail before any `ACL SETUSER`.
|
|
3
|
+
* Read hides those names, so a plan would otherwise create them and `reset` the
|
|
4
|
+
* credential the kit authenticates with.
|
|
5
|
+
*/
|
|
6
|
+
import { describe, expect, test } from 'bun:test';
|
|
7
|
+
import * as Effect from 'effect/Effect';
|
|
8
|
+
import { reconcileWithExecutor } from './acl-reconcile.ts';
|
|
9
|
+
import { ValkeyAclReservedUser } from './errors.ts';
|
|
10
|
+
import { makeFakeValkey } from './fake-valkey.ts';
|
|
11
|
+
import type { ValkeyAclUser } from './acl-attrs.ts';
|
|
12
|
+
|
|
13
|
+
const fails = <A, E>(eff: Effect.Effect<A, E>): Promise<E> => Effect.runPromise(Effect.flip(eff));
|
|
14
|
+
|
|
15
|
+
const env = { CLAUDE_PW: 'FAKE-seat-password' };
|
|
16
|
+
const claude: ValkeyAclUser = {
|
|
17
|
+
name: 'claude',
|
|
18
|
+
keyPrefix: 'claude:*',
|
|
19
|
+
profile: 'seat',
|
|
20
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const setuser = (fake: ReturnType<typeof makeFakeValkey>): ReadonlyArray<unknown> =>
|
|
24
|
+
fake.commands.filter((command) => command.args[0] === 'ACL' && command.args[1] === 'SETUSER');
|
|
25
|
+
|
|
26
|
+
describe('reserved ACL names', () => {
|
|
27
|
+
test('refuses to declare the connection username before any SETUSER', async () => {
|
|
28
|
+
const fake = makeFakeValkey({ acl: { admin: 'user admin on >FAKE-seed ~* +@all' } });
|
|
29
|
+
const admin: ValkeyAclUser = {
|
|
30
|
+
name: 'admin',
|
|
31
|
+
keyPrefix: 'admin:*',
|
|
32
|
+
profile: 'seat',
|
|
33
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
34
|
+
};
|
|
35
|
+
const error = await fails(
|
|
36
|
+
reconcileWithExecutor(
|
|
37
|
+
fake,
|
|
38
|
+
{ instance: 'valkey-seats', users: { admin, claude } },
|
|
39
|
+
undefined,
|
|
40
|
+
env,
|
|
41
|
+
'admin',
|
|
42
|
+
),
|
|
43
|
+
);
|
|
44
|
+
expect(setuser(fake)).toEqual([]);
|
|
45
|
+
expect(error).toBeInstanceOf(ValkeyAclReservedUser);
|
|
46
|
+
expect(fake.acl.get('admin')).toContain('~* resetchannels +@all');
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('refuses to declare default before any SETUSER', async () => {
|
|
50
|
+
const fake = makeFakeValkey({ acl: { default: 'user default off' } });
|
|
51
|
+
const reserved: ValkeyAclUser = {
|
|
52
|
+
name: 'default',
|
|
53
|
+
keyPrefix: '*',
|
|
54
|
+
profile: 'service',
|
|
55
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
56
|
+
};
|
|
57
|
+
const error = await fails(
|
|
58
|
+
reconcileWithExecutor(
|
|
59
|
+
fake,
|
|
60
|
+
{ instance: 'valkey-seats', users: { default: reserved } },
|
|
61
|
+
undefined,
|
|
62
|
+
env,
|
|
63
|
+
'admin',
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
expect(error).toBeInstanceOf(ValkeyAclReservedUser);
|
|
67
|
+
expect(setuser(fake)).toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** A removed seat must lose access without claiming ownership of an operator's users. */
|
|
2
|
+
import { expect, test } from 'bun:test';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import { makeValkeyAclFileHandlers } from './acl.ts';
|
|
5
|
+
import type { ValkeyAclFileProps } from './acl-attrs.ts';
|
|
6
|
+
import { reconcileWithExecutor } from './acl-reconcile.ts';
|
|
7
|
+
import { makeFakeValkey } from './fake-valkey.ts';
|
|
8
|
+
import { config, connection, context, required, run } from './handler-test-fixture.ts';
|
|
9
|
+
import { ValkeySocketError } from './transport.ts';
|
|
10
|
+
import type { withValkey } from './connection.ts';
|
|
11
|
+
|
|
12
|
+
const props: ValkeyAclFileProps = {
|
|
13
|
+
instance: 'scratch',
|
|
14
|
+
users: {
|
|
15
|
+
seat: { name: 'seat', profile: 'seat', password: { fromEnv: 'TEST_VALKEY_SEAT_PW' } },
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
const news: ValkeyAclFileProps = { instance: 'scratch', users: {} };
|
|
19
|
+
const env = { TEST_VALKEY_SEAT_PW: 'FAKE-seat' };
|
|
20
|
+
const operator = 'user operator on >FAKE-operator ~* &* +@all';
|
|
21
|
+
|
|
22
|
+
for (const legacy of [false, true]) {
|
|
23
|
+
test(`removing a managed seat plans an update and revokes AUTH, preserving never-managed users (legacy=${legacy})`, async () => {
|
|
24
|
+
const fake = makeFakeValkey({ acl: { operator }, passwords: { admin: 'FAKE-admin' } });
|
|
25
|
+
const created = await Effect.runPromise(reconcileWithExecutor(fake, props, undefined, env));
|
|
26
|
+
const operatorBefore = fake.acl.get('operator');
|
|
27
|
+
const stored = legacy ? { instance: created.instance, users: created.users } : created;
|
|
28
|
+
expect(
|
|
29
|
+
await Effect.runPromise(fake.send(['AUTH', 'seat', env.TEST_VALKEY_SEAT_PW])),
|
|
30
|
+
).toMatchObject({ value: 'OK' });
|
|
31
|
+
const handlers = makeValkeyAclFileHandlers(connection(fake));
|
|
32
|
+
expect(
|
|
33
|
+
await run(required(handlers.diff)({ ...context, olds: props, news, output: stored })),
|
|
34
|
+
).toEqual({ action: 'update' });
|
|
35
|
+
// A drift read must preserve ownership independently of all the live users it observes.
|
|
36
|
+
const observed = required(
|
|
37
|
+
await run(required(handlers.read)({ ...context, olds: props, output: stored })),
|
|
38
|
+
);
|
|
39
|
+
expect(observed.managedUsers).toEqual(['seat']);
|
|
40
|
+
const output = await run(
|
|
41
|
+
handlers.reconcile({ ...context, olds: props, news, output: observed }),
|
|
42
|
+
);
|
|
43
|
+
expect(output.managedUsers).toEqual([]);
|
|
44
|
+
expect(Object.keys(output.users)).toEqual(['operator']);
|
|
45
|
+
expect(fake.acl.get('operator')).toBe(operatorBefore);
|
|
46
|
+
expect(
|
|
47
|
+
fake.commands.filter(({ args }) => args[1] === 'DELUSER').map(({ args }) => args),
|
|
48
|
+
).toEqual([['ACL', 'DELUSER', 'seat']]);
|
|
49
|
+
expect(
|
|
50
|
+
await Effect.runPromise(fake.send(['AUTH', 'seat', env.TEST_VALKEY_SEAT_PW])),
|
|
51
|
+
).toMatchObject({ kind: 'error' });
|
|
52
|
+
expect(await run(required(handlers.diff)({ ...context, olds: news, news, output }))).toEqual({
|
|
53
|
+
action: 'noop',
|
|
54
|
+
});
|
|
55
|
+
await run(handlers.reconcile({ ...context, olds: news, news, output }));
|
|
56
|
+
expect(fake.commands.filter(({ args }) => args[1] === 'DELUSER')).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
test('a removed seat re-added by another writer fails readback even without exclusive ownership', async () => {
|
|
61
|
+
const fake = makeFakeValkey({
|
|
62
|
+
reAddAfterWrite: { name: 'seat', line: 'user seat on nopass -@all' },
|
|
63
|
+
});
|
|
64
|
+
fake.acl.set('seat', 'user seat on nopass -@all');
|
|
65
|
+
const error = await Effect.runPromise(
|
|
66
|
+
Effect.flip(
|
|
67
|
+
reconcileWithExecutor(
|
|
68
|
+
fake,
|
|
69
|
+
news,
|
|
70
|
+
{ instance: 'scratch', users: {}, managedUsers: ['seat'] },
|
|
71
|
+
{},
|
|
72
|
+
),
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
expect(error).toMatchObject({ _tag: 'ValkeyAclReadbackFailed', user: 'seat' });
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('ACL socket acquisition failure is mapped before the executor callback can run', async () => {
|
|
79
|
+
const connect: typeof withValkey = () =>
|
|
80
|
+
Effect.fail(new ValkeySocketError({ reason: 'ECONNREFUSED' }));
|
|
81
|
+
const handlers = makeValkeyAclFileHandlers(connect);
|
|
82
|
+
for (const operation of [
|
|
83
|
+
required(handlers.read)({ ...context, olds: props, output: undefined }),
|
|
84
|
+
handlers.reconcile({ ...context, olds: props, news: props, output: undefined }),
|
|
85
|
+
handlers.delete({ ...context, olds: props, output: { instance: 'scratch', users: {} } }),
|
|
86
|
+
]) {
|
|
87
|
+
expect(await run(Effect.flip(operation))).toMatchObject({
|
|
88
|
+
_tag: 'ValkeyInstanceUnreachable',
|
|
89
|
+
instance: 'scratch',
|
|
90
|
+
host: config.host,
|
|
91
|
+
port: config.port,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A seat profile must not grant another seat's keys. `keyPrefix` is interpolated as
|
|
3
|
+
* `~${keyPrefix}` and read-back compares the declaration to itself, so `*` or `grok:*`
|
|
4
|
+
* on user `claude` would converge and widen the keyspace. Refused before any `ACL SETUSER`.
|
|
5
|
+
* `*` stays legal on the service profile — that user owns the instance.
|
|
6
|
+
*/
|
|
7
|
+
import { describe, expect, test } from 'bun:test';
|
|
8
|
+
import * as Effect from 'effect/Effect';
|
|
9
|
+
import type { ValkeyAclUser } from './acl-attrs.ts';
|
|
10
|
+
import { reconcileWithExecutor } from './acl-reconcile.ts';
|
|
11
|
+
import { ValkeyAclSeatKeyPrefix } from './errors.ts';
|
|
12
|
+
import { makeFakeValkey } from './fake-valkey.ts';
|
|
13
|
+
|
|
14
|
+
const fails = <A, E>(eff: Effect.Effect<A, E>): Promise<E> => Effect.runPromise(Effect.flip(eff));
|
|
15
|
+
|
|
16
|
+
const env = { CLAUDE_PW: 'FAKE-seat-password', LITELLM_PW: 'FAKE-cache-password' };
|
|
17
|
+
|
|
18
|
+
const setuser = (fake: ReturnType<typeof makeFakeValkey>): ReadonlyArray<unknown> =>
|
|
19
|
+
fake.commands.filter((command) => command.args[0] === 'ACL' && command.args[1] === 'SETUSER');
|
|
20
|
+
|
|
21
|
+
describe('seat key prefix', () => {
|
|
22
|
+
test("a seat keyPrefix of '*' issues no SETUSER", async () => {
|
|
23
|
+
const fake = makeFakeValkey({ acl: { admin: 'user admin on >FAKE-seed ~* +@all' } });
|
|
24
|
+
const claude: ValkeyAclUser = {
|
|
25
|
+
name: 'claude',
|
|
26
|
+
keyPrefix: '*',
|
|
27
|
+
profile: 'seat',
|
|
28
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
29
|
+
};
|
|
30
|
+
const error = await fails(
|
|
31
|
+
reconcileWithExecutor(
|
|
32
|
+
fake,
|
|
33
|
+
{ instance: 'valkey-seats', users: { claude } },
|
|
34
|
+
undefined,
|
|
35
|
+
env,
|
|
36
|
+
'admin',
|
|
37
|
+
),
|
|
38
|
+
);
|
|
39
|
+
expect(setuser(fake)).toEqual([]);
|
|
40
|
+
expect(error).toBeInstanceOf(ValkeyAclSeatKeyPrefix);
|
|
41
|
+
expect(fake.acl.has('claude')).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('a seat keyPrefix that only shares the name prefix issues no SETUSER', async () => {
|
|
45
|
+
const fake = makeFakeValkey();
|
|
46
|
+
const claude: ValkeyAclUser = {
|
|
47
|
+
name: 'claude',
|
|
48
|
+
keyPrefix: 'claude:grok:*',
|
|
49
|
+
profile: 'seat',
|
|
50
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
51
|
+
};
|
|
52
|
+
const error = await fails(
|
|
53
|
+
reconcileWithExecutor(
|
|
54
|
+
fake,
|
|
55
|
+
{ instance: 'valkey-seats', users: { claude } },
|
|
56
|
+
undefined,
|
|
57
|
+
env,
|
|
58
|
+
'admin',
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
expect(setuser(fake)).toEqual([]);
|
|
62
|
+
expect(error).toBeInstanceOf(ValkeyAclSeatKeyPrefix);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("a seat keyPrefix of another user's pattern issues no SETUSER", async () => {
|
|
66
|
+
const fake = makeFakeValkey();
|
|
67
|
+
const claude: ValkeyAclUser = {
|
|
68
|
+
name: 'claude',
|
|
69
|
+
keyPrefix: 'grok:*',
|
|
70
|
+
profile: 'seat',
|
|
71
|
+
password: { fromEnv: 'CLAUDE_PW' },
|
|
72
|
+
};
|
|
73
|
+
const error = await fails(
|
|
74
|
+
reconcileWithExecutor(
|
|
75
|
+
fake,
|
|
76
|
+
{ instance: 'valkey-seats', users: { claude } },
|
|
77
|
+
undefined,
|
|
78
|
+
env,
|
|
79
|
+
'admin',
|
|
80
|
+
),
|
|
81
|
+
);
|
|
82
|
+
expect(setuser(fake)).toEqual([]);
|
|
83
|
+
expect(error).toBeInstanceOf(ValkeyAclSeatKeyPrefix);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("a service keyPrefix of '*' is still written", async () => {
|
|
87
|
+
const fake = makeFakeValkey();
|
|
88
|
+
const litellm: ValkeyAclUser = {
|
|
89
|
+
name: 'litellm',
|
|
90
|
+
keyPrefix: '*',
|
|
91
|
+
profile: 'service',
|
|
92
|
+
password: { fromEnv: 'LITELLM_PW' },
|
|
93
|
+
};
|
|
94
|
+
const output = await Effect.runPromise(
|
|
95
|
+
reconcileWithExecutor(
|
|
96
|
+
fake,
|
|
97
|
+
{ instance: 'valkey-litellm', users: { litellm } },
|
|
98
|
+
undefined,
|
|
99
|
+
env,
|
|
100
|
+
'admin',
|
|
101
|
+
),
|
|
102
|
+
);
|
|
103
|
+
// The fake now echoes &*, matching the measured live echo; read-back must succeed.
|
|
104
|
+
expect(output.users.litellm?.profile).toBe('service');
|
|
105
|
+
const wrote = fake.commands.filter(
|
|
106
|
+
(command) => command.args[0] === 'ACL' && command.args[1] === 'SETUSER',
|
|
107
|
+
);
|
|
108
|
+
expect(wrote.length).toBe(1);
|
|
109
|
+
expect(wrote[0]?.args.includes('~*')).toBe(true);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** Validate declarations before any write; a seat name becomes part of a glob. */
|
|
2
|
+
import { expect, test } from 'bun:test';
|
|
3
|
+
import * as Effect from 'effect/Effect';
|
|
4
|
+
import type { ValkeyError } from './errors.ts';
|
|
5
|
+
import type { ValkeyAclUser } from './acl-attrs.ts';
|
|
6
|
+
import { reconcileWithExecutor } from './acl-reconcile.ts';
|
|
7
|
+
import { makeValkeyAclFileHandlers } from './acl.ts';
|
|
8
|
+
import { makeFakeValkey } from './fake-valkey.ts';
|
|
9
|
+
import { connection, context, required, run } from './handler-test-fixture.ts';
|
|
10
|
+
|
|
11
|
+
const seat: ValkeyAclUser = {
|
|
12
|
+
name: 'seat',
|
|
13
|
+
profile: 'seat',
|
|
14
|
+
password: { fromEnv: 'TEST_VALKEY_USER_PW' },
|
|
15
|
+
};
|
|
16
|
+
const invalid: ReadonlyArray<readonly [ValkeyAclUser, ValkeyError['_tag']]> = [
|
|
17
|
+
...['*', '?', '[ab]', '\\'].map(
|
|
18
|
+
(glob) => [{ ...seat, name: `seat${glob}` }, 'ValkeyAclNameGlob'] as const,
|
|
19
|
+
),
|
|
20
|
+
[{ ...seat, channelPatterns: ['*'] }, 'ValkeyAclChannelPatterns'],
|
|
21
|
+
[{ ...seat, profile: 'monitor', keyPrefix: '*' }, 'ValkeyAclMonitorKeyPrefix'],
|
|
22
|
+
[{ ...seat, profile: 'monitor', channelPatterns: ['*'] }, 'ValkeyAclChannelPatterns'],
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
for (const [user, tag] of invalid) {
|
|
26
|
+
test(`refuse ${user.name} ${user.profile} with ${tag} in diff and reconcile`, async () => {
|
|
27
|
+
const fake = makeFakeValkey();
|
|
28
|
+
const props = { instance: 'scratch', users: { [user.name]: user } };
|
|
29
|
+
const error = await Effect.runPromise(
|
|
30
|
+
Effect.flip(
|
|
31
|
+
reconcileWithExecutor(fake, props, undefined, { TEST_VALKEY_USER_PW: 'FAKE-password' }),
|
|
32
|
+
),
|
|
33
|
+
);
|
|
34
|
+
expect(error._tag).toBe(tag);
|
|
35
|
+
expect(fake.commands.some(({ args }) => args[1] === 'SETUSER')).toBe(false);
|
|
36
|
+
const handlers = makeValkeyAclFileHandlers(connection(fake));
|
|
37
|
+
const failure = await run(
|
|
38
|
+
Effect.flip(
|
|
39
|
+
required(handlers.diff)({ ...context, olds: props, news: props, output: undefined }),
|
|
40
|
+
),
|
|
41
|
+
);
|
|
42
|
+
expect(failure._tag).toBe(tag);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
test('aclfile probe failure is not treated as an empty file path', async () => {
|
|
47
|
+
const fake = makeFakeValkey();
|
|
48
|
+
fake.config.delete('aclfile');
|
|
49
|
+
const failure = await Effect.runPromise(
|
|
50
|
+
Effect.flip(reconcileWithExecutor(fake, { instance: 'scratch', users: {} }, undefined, {})),
|
|
51
|
+
);
|
|
52
|
+
expect(failure._tag).toBe('ValkeyServerError');
|
|
53
|
+
expect(fake.commands.some(({ args }) => args[1] === 'SETUSER')).toBe(false);
|
|
54
|
+
});
|