@homeflare/alchemy 0.46.1 → 0.47.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 -10
- package/dist/argocd/cluster.d.ts +5 -5
- package/dist/argocd/cluster.d.ts.map +1 -1
- package/dist/argocd/fake-argocd.d.ts +1 -1
- package/dist/argocd/fake-argocd.d.ts.map +1 -1
- package/dist/argocd/index.js.map +1 -1
- package/dist/argocd/providers.d.ts +1 -1
- package/dist/argocd/providers.d.ts.map +1 -1
- package/dist/argocd/repo-creds.d.ts +5 -5
- package/dist/argocd/repo-creds.d.ts.map +1 -1
- package/dist/argocd/repository.d.ts +5 -5
- package/dist/argocd/repository.d.ts.map +1 -1
- package/dist/argocd/resource.d.ts +1 -1
- package/dist/argocd/resource.d.ts.map +1 -1
- package/dist/caddy/admin.d.ts +1 -1
- package/dist/caddy/admin.d.ts.map +1 -1
- package/dist/caddy/caddy-http-client.d.ts +2 -2
- package/dist/caddy/caddy-http-client.d.ts.map +1 -1
- package/dist/caddy/format.d.ts +1 -1
- package/dist/caddy/format.d.ts.map +1 -1
- package/dist/caddy/index.js +6 -6
- package/dist/caddy/index.js.map +4 -4
- package/dist/ceph/auth-entity.d.ts +1 -1
- package/dist/ceph/auth-entity.d.ts.map +1 -1
- package/dist/ceph/ceph-auth-reconcile.d.ts +1 -1
- package/dist/ceph/ceph-auth-reconcile.d.ts.map +1 -1
- package/dist/ceph/index.js +5 -5
- package/dist/ceph/index.js.map +4 -4
- package/dist/cloudflare/fake-mesh.d.ts +2 -2
- package/dist/cloudflare/fake-mesh.d.ts.map +1 -1
- package/dist/cloudflare/fake-r2-lock.d.ts +1 -1
- package/dist/cloudflare/fake-r2-lock.d.ts.map +1 -1
- package/dist/cloudflare/index.js +3 -3
- package/dist/cloudflare/index.js.map +3 -3
- package/dist/cloudflare/mesh-node-token.d.ts +1 -1
- package/dist/cloudflare/mesh-node-token.d.ts.map +1 -1
- package/dist/cloudflare/mesh-node.d.ts +1 -1
- package/dist/cloudflare/mesh-node.d.ts.map +1 -1
- package/dist/cloudflare/providers.d.ts +1 -1
- package/dist/cloudflare/providers.d.ts.map +1 -1
- package/dist/cloudflare/r2-bucket-lock.d.ts +1 -1
- package/dist/cloudflare/r2-bucket-lock.d.ts.map +1 -1
- package/dist/discord/application-command.d.ts +6 -6
- package/dist/discord/application-command.d.ts.map +1 -1
- package/dist/discord/fake-discord.d.ts +1 -1
- package/dist/discord/fake-discord.d.ts.map +1 -1
- package/dist/discord/guild-application-command.d.ts +6 -6
- package/dist/discord/guild-application-command.d.ts.map +1 -1
- package/dist/discord/index.js.map +1 -1
- package/dist/discord/providers.d.ts +1 -1
- package/dist/discord/providers.d.ts.map +1 -1
- package/dist/discord/resource.d.ts +1 -1
- package/dist/discord/resource.d.ts.map +1 -1
- package/dist/forgejo/branch-protection.d.ts +5 -5
- package/dist/forgejo/branch-protection.d.ts.map +1 -1
- package/dist/forgejo/fake-forgejo.d.ts +1 -1
- package/dist/forgejo/fake-forgejo.d.ts.map +1 -1
- package/dist/forgejo/index.js.map +1 -1
- package/dist/forgejo/org-actions-secrets.d.ts +5 -5
- package/dist/forgejo/org-actions-secrets.d.ts.map +1 -1
- package/dist/forgejo/org-label.d.ts +5 -5
- package/dist/forgejo/org-label.d.ts.map +1 -1
- package/dist/forgejo/org-team.d.ts +5 -5
- package/dist/forgejo/org-team.d.ts.map +1 -1
- package/dist/forgejo/repo-webhook.d.ts +5 -5
- package/dist/forgejo/repo-webhook.d.ts.map +1 -1
- package/dist/forgejo/repository.d.ts +5 -5
- package/dist/forgejo/repository.d.ts.map +1 -1
- package/dist/forgejo/resource.d.ts +1 -1
- package/dist/forgejo/resource.d.ts.map +1 -1
- package/dist/forgejo/team-member.d.ts +5 -5
- package/dist/forgejo/team-member.d.ts.map +1 -1
- package/dist/github/repository-ruleset-providers.d.ts +1 -1
- package/dist/github/repository-ruleset-providers.d.ts.map +1 -1
- package/dist/google-workspace/domain-alias.d.ts +5 -5
- package/dist/google-workspace/domain-alias.d.ts.map +1 -1
- package/dist/google-workspace/fake-google-workspace.d.ts +1 -1
- package/dist/google-workspace/fake-google-workspace.d.ts.map +1 -1
- package/dist/google-workspace/group-member.d.ts +5 -5
- package/dist/google-workspace/group-member.d.ts.map +1 -1
- package/dist/google-workspace/group.d.ts +5 -5
- package/dist/google-workspace/group.d.ts.map +1 -1
- package/dist/google-workspace/index.js.map +1 -1
- package/dist/google-workspace/org-unit.d.ts +5 -5
- package/dist/google-workspace/org-unit.d.ts.map +1 -1
- package/dist/google-workspace/providers.d.ts +1 -1
- package/dist/google-workspace/providers.d.ts.map +1 -1
- package/dist/google-workspace/resource.d.ts +1 -1
- package/dist/google-workspace/resource.d.ts.map +1 -1
- package/dist/grafana/alert-rule-group.d.ts +4 -4
- package/dist/grafana/alert-rule-group.d.ts.map +1 -1
- package/dist/grafana/contact-point.d.ts +4 -4
- package/dist/grafana/dashboard.d.ts +4 -4
- package/dist/grafana/datasource.d.ts +4 -4
- package/dist/grafana/fake-grafana.d.ts +1 -1
- package/dist/grafana/fake-grafana.d.ts.map +1 -1
- package/dist/grafana/folder.d.ts +4 -4
- package/dist/grafana/message-template.d.ts +4 -4
- package/dist/grafana/mute-timing.d.ts +4 -4
- package/dist/grafana/notification-policy.d.ts +4 -4
- package/dist/grafana/notification-policy.d.ts.map +1 -1
- package/dist/grafana/providers.d.ts +1 -1
- package/dist/grafana/providers.d.ts.map +1 -1
- package/dist/litellm/access-group.d.ts +1 -1
- package/dist/litellm/budget-operations.d.ts +1 -1
- package/dist/litellm/budget-operations.d.ts.map +1 -1
- package/dist/litellm/budget.d.ts +2 -2
- package/dist/litellm/credential-errors.d.ts +1 -1
- package/dist/litellm/credential-errors.d.ts.map +1 -1
- package/dist/litellm/credential.d.ts +1 -1
- package/dist/litellm/index.js +26 -5
- package/dist/litellm/index.js.map +8 -8
- package/dist/litellm/key-errors.d.ts +1 -1
- package/dist/litellm/key-errors.d.ts.map +1 -1
- package/dist/litellm/key.d.ts +2 -2
- package/dist/litellm/mcp-server-locate.d.ts +1 -1
- package/dist/litellm/mcp-server-locate.d.ts.map +1 -1
- package/dist/litellm/mcp-server.d.ts +2 -2
- package/dist/litellm/model-operations.d.ts +1 -1
- package/dist/litellm/model-operations.d.ts.map +1 -1
- package/dist/litellm/model.d.ts +2 -2
- package/dist/litellm/operations.d.ts +1 -1
- package/dist/litellm/operations.d.ts.map +1 -1
- package/dist/litellm/policy-attachment.d.ts +1 -1
- package/dist/litellm/policy.d.ts +1 -1
- package/dist/litellm/providers.d.ts +1 -1
- package/dist/litellm/providers.d.ts.map +1 -1
- package/dist/litellm/team-operations.d.ts +1 -1
- package/dist/litellm/team-operations.d.ts.map +1 -1
- package/dist/litellm/team.d.ts +1 -1
- package/dist/litellm/tool-policy-operations.d.ts +1 -1
- package/dist/litellm/tool-policy-operations.d.ts.map +1 -1
- package/dist/litellm/tool-policy.d.ts +1 -1
- package/dist/litellm/toolset.d.ts +1 -1
- package/dist/netbox/fake-netbox.d.ts +1 -1
- package/dist/netbox/fake-netbox.d.ts.map +1 -1
- package/dist/netbox/index.js.map +1 -1
- package/dist/netbox/prefix.d.ts +5 -5
- package/dist/netbox/prefix.d.ts.map +1 -1
- package/dist/netbox/resource.d.ts +1 -1
- package/dist/netbox/resource.d.ts.map +1 -1
- package/dist/openbao/approle-login.d.ts +1 -1
- package/dist/openbao/approle-login.d.ts.map +1 -1
- package/dist/openbao/auth-method-reconcile.d.ts +1 -1
- package/dist/openbao/auth-method-reconcile.d.ts.map +1 -1
- package/dist/openbao/auth-method-wire.d.ts +4 -4
- package/dist/openbao/auth-method-wire.d.ts.map +1 -1
- package/dist/openbao/auth-method.d.ts +1 -1
- package/dist/openbao/auth-method.d.ts.map +1 -1
- package/dist/openbao/auth-role-identity.d.ts +1 -1
- package/dist/openbao/auth-role-identity.d.ts.map +1 -1
- package/dist/openbao/auth-role-wire.d.ts +4 -4
- package/dist/openbao/auth-role-wire.d.ts.map +1 -1
- package/dist/openbao/auth-role.d.ts +1 -1
- package/dist/openbao/auth-role.d.ts.map +1 -1
- package/dist/openbao/bao-http.d.ts +1 -1
- package/dist/openbao/bao-http.d.ts.map +1 -1
- package/dist/openbao/bao-identity.d.ts +1 -1
- package/dist/openbao/bao-identity.d.ts.map +1 -1
- package/dist/openbao/cloudflare-permission-groups.d.ts +1 -1
- package/dist/openbao/cloudflare-permission-groups.d.ts.map +1 -1
- package/dist/openbao/cloudflare-role-wire.d.ts +1 -1
- package/dist/openbao/cloudflare-role-wire.d.ts.map +1 -1
- package/dist/openbao/cloudflare-role.d.ts +1 -1
- package/dist/openbao/cloudflare-role.d.ts.map +1 -1
- package/dist/openbao/distilled.d.ts +1 -1
- package/dist/openbao/distilled.d.ts.map +1 -1
- package/dist/openbao/fake-bao.d.ts +1 -1
- package/dist/openbao/fake-bao.d.ts.map +1 -1
- package/dist/openbao/fake-core.d.ts +1 -1
- package/dist/openbao/fake-core.d.ts.map +1 -1
- package/dist/openbao/fake-engines.d.ts +1 -1
- package/dist/openbao/fake-engines.d.ts.map +1 -1
- package/dist/openbao/fake-families.d.ts +2 -2
- package/dist/openbao/fake-families.d.ts.map +1 -1
- package/dist/openbao/fake-stack.d.ts +5 -0
- package/dist/openbao/fake-stack.d.ts.map +1 -1
- package/dist/openbao/forgejo-bootstrap.d.ts +1 -1
- package/dist/openbao/forgejo-bootstrap.d.ts.map +1 -1
- package/dist/openbao/index.js +31 -10
- package/dist/openbao/index.js.map +31 -31
- package/dist/openbao/jwt-config.d.ts +1 -1
- package/dist/openbao/jwt-config.d.ts.map +1 -1
- package/dist/openbao/jwt-role.d.ts +1 -1
- package/dist/openbao/jwt-role.d.ts.map +1 -1
- package/dist/openbao/kubernetes-role.d.ts +1 -1
- package/dist/openbao/kubernetes-role.d.ts.map +1 -1
- package/dist/openbao/mfa-enforcement.d.ts +1 -1
- package/dist/openbao/mfa-enforcement.d.ts.map +1 -1
- package/dist/openbao/mfa-totp.d.ts +1 -1
- package/dist/openbao/mfa-totp.d.ts.map +1 -1
- package/dist/openbao/mfa-wire.d.ts +1 -1
- package/dist/openbao/mfa-wire.d.ts.map +1 -1
- package/dist/openbao/mount-move.d.ts +1 -1
- package/dist/openbao/mount-move.d.ts.map +1 -1
- package/dist/openbao/mount-reconcile.d.ts +1 -1
- package/dist/openbao/mount-reconcile.d.ts.map +1 -1
- package/dist/openbao/mount-wire.d.ts +4 -4
- package/dist/openbao/mount-wire.d.ts.map +1 -1
- package/dist/openbao/mount.d.ts +1 -1
- package/dist/openbao/mount.d.ts.map +1 -1
- package/dist/openbao/pki-role.d.ts +1 -1
- package/dist/openbao/pki-role.d.ts.map +1 -1
- package/dist/openbao/plugin-reconcile.d.ts +1 -1
- package/dist/openbao/plugin-reconcile.d.ts.map +1 -1
- package/dist/openbao/plugin-wire.d.ts +1 -1
- package/dist/openbao/plugin-wire.d.ts.map +1 -1
- package/dist/openbao/plugin.d.ts +1 -1
- package/dist/openbao/plugin.d.ts.map +1 -1
- package/dist/openbao/policy-identity.d.ts +1 -1
- package/dist/openbao/policy-identity.d.ts.map +1 -1
- package/dist/openbao/policy-wire.d.ts +4 -4
- package/dist/openbao/policy-wire.d.ts.map +1 -1
- package/dist/openbao/policy.d.ts +1 -1
- package/dist/openbao/policy.d.ts.map +1 -1
- package/dist/openbao/proxmox-role-wire.d.ts +1 -1
- package/dist/openbao/proxmox-role-wire.d.ts.map +1 -1
- package/dist/openbao/proxmox-role.d.ts +1 -1
- package/dist/openbao/proxmox-role.d.ts.map +1 -1
- package/dist/openbao/remount-wire.d.ts +1 -1
- package/dist/openbao/remount-wire.d.ts.map +1 -1
- package/dist/openbao/rename-identity.d.ts +1 -1
- package/dist/openbao/rename-identity.d.ts.map +1 -1
- package/dist/openbao/rename.d.ts +1 -1
- package/dist/openbao/rename.d.ts.map +1 -1
- package/dist/openbao/role-reconcile.d.ts +1 -1
- package/dist/openbao/role-reconcile.d.ts.map +1 -1
- package/dist/openbao/ssh-role.d.ts +1 -1
- package/dist/openbao/ssh-role.d.ts.map +1 -1
- package/dist/opnsense/alias.d.ts +5 -5
- package/dist/opnsense/alias.d.ts.map +1 -1
- package/dist/opnsense/category.d.ts +5 -5
- package/dist/opnsense/category.d.ts.map +1 -1
- package/dist/opnsense/fake-opnsense.d.ts +1 -1
- package/dist/opnsense/fake-opnsense.d.ts.map +1 -1
- package/dist/opnsense/group.d.ts +5 -5
- package/dist/opnsense/group.d.ts.map +1 -1
- package/dist/opnsense/index.js.map +1 -1
- package/dist/opnsense/providers.d.ts +1 -1
- package/dist/opnsense/providers.d.ts.map +1 -1
- package/dist/opnsense/resource.d.ts +1 -1
- package/dist/opnsense/resource.d.ts.map +1 -1
- package/dist/ownership/probe.d.ts.map +1 -1
- package/dist/paperless/custom-field.d.ts +5 -5
- package/dist/paperless/custom-field.d.ts.map +1 -1
- package/dist/paperless/document-type.d.ts +5 -5
- package/dist/paperless/document-type.d.ts.map +1 -1
- package/dist/paperless/fake-paperless.d.ts +1 -1
- package/dist/paperless/fake-paperless.d.ts.map +1 -1
- package/dist/paperless/matching-types.d.ts +1 -1
- package/dist/paperless/matching-types.d.ts.map +1 -1
- package/dist/paperless/matching.d.ts +4 -4
- package/dist/paperless/providers.d.ts +1 -1
- package/dist/paperless/providers.d.ts.map +1 -1
- package/dist/paperless/storage-path.d.ts +5 -5
- package/dist/paperless/storage-path.d.ts.map +1 -1
- package/dist/paperless/tag.d.ts +5 -5
- package/dist/paperless/tag.d.ts.map +1 -1
- package/dist/postgres/connection.d.ts +2 -2
- package/dist/postgres/connection.d.ts.map +1 -1
- package/dist/postgres/database-sql.d.ts +1 -1
- 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-read.d.ts +1 -1
- package/dist/postgres/fake-grants-read.d.ts.map +1 -1
- package/dist/postgres/fake-grants-write.d.ts +1 -1
- package/dist/postgres/fake-grants-write.d.ts.map +1 -1
- package/dist/postgres/fake-role-sql.d.ts +1 -1
- package/dist/postgres/fake-role-sql.d.ts.map +1 -1
- package/dist/postgres/fake-schema-drop.d.ts +1 -1
- package/dist/postgres/fake-schema-drop.d.ts.map +1 -1
- package/dist/postgres/fake-schema-sql.d.ts +1 -1
- package/dist/postgres/fake-schema-sql.d.ts.map +1 -1
- package/dist/postgres/grants-existence.d.ts +1 -1
- package/dist/postgres/grants-existence.d.ts.map +1 -1
- package/dist/postgres/grants-ops.d.ts +1 -1
- package/dist/postgres/grants-ops.d.ts.map +1 -1
- package/dist/postgres/grants-ownership.d.ts +1 -1
- package/dist/postgres/grants-ownership.d.ts.map +1 -1
- package/dist/postgres/grants-read-defaults.d.ts +1 -1
- package/dist/postgres/grants-read-defaults.d.ts.map +1 -1
- package/dist/postgres/grants-read.d.ts +1 -1
- package/dist/postgres/grants-read.d.ts.map +1 -1
- package/dist/postgres/index.js +93 -77
- package/dist/postgres/index.js.map +23 -23
- package/dist/postgres/installed-classifier.d.ts +1 -1
- package/dist/postgres/installed-classifier.d.ts.map +1 -1
- package/dist/postgres/psql-executor.d.ts.map +1 -1
- package/dist/postgres/role-membership-sql.d.ts +1 -1
- package/dist/postgres/role-membership-sql.d.ts.map +1 -1
- package/dist/postgres/role-sql.d.ts +1 -1
- package/dist/postgres/role-sql.d.ts.map +1 -1
- package/dist/postgres/role.d.ts +1 -1
- package/dist/postgres/role.d.ts.map +1 -1
- package/dist/postgres/schema-assert.d.ts +1 -1
- package/dist/postgres/schema-assert.d.ts.map +1 -1
- package/dist/postgres/schema-delete.d.ts +1 -1
- package/dist/postgres/schema-delete.d.ts.map +1 -1
- package/dist/postgres/schema-drop-sql.d.ts +1 -1
- package/dist/postgres/schema-drop-sql.d.ts.map +1 -1
- package/dist/postgres/schema-reconcile.d.ts +1 -1
- package/dist/postgres/schema-reconcile.d.ts.map +1 -1
- package/dist/postgres/schema-sql.d.ts +1 -1
- package/dist/postgres/schema-sql.d.ts.map +1 -1
- package/dist/postgres/schema.d.ts +1 -1
- package/dist/postgres/schema.d.ts.map +1 -1
- package/dist/postgres/search-path.d.ts +1 -1
- package/dist/postgres/search-path.d.ts.map +1 -1
- package/dist/proxmox/acl.d.ts +1 -1
- package/dist/proxmox/acl.d.ts.map +1 -1
- package/dist/proxmox/api-token.d.ts +1 -1
- package/dist/proxmox/api-token.d.ts.map +1 -1
- package/dist/proxmox/backup-job-distilled.d.ts +2 -2
- package/dist/proxmox/backup-job-distilled.d.ts.map +1 -1
- package/dist/proxmox/backup-job.d.ts +1 -1
- package/dist/proxmox/backup-job.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon-wire.d.ts +3 -3
- package/dist/proxmox/ceph-daemon-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-daemon.d.ts +2 -2
- package/dist/proxmox/ceph-daemon.d.ts.map +1 -1
- package/dist/proxmox/ceph-flag-wire.d.ts +3 -3
- package/dist/proxmox/ceph-flag-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-flag.d.ts +1 -1
- package/dist/proxmox/ceph-flag.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs-distilled.d.ts +3 -3
- package/dist/proxmox/ceph-fs-distilled.d.ts.map +1 -1
- package/dist/proxmox/ceph-fs.d.ts +1 -1
- package/dist/proxmox/ceph-fs.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-tree.d.ts +1 -1
- package/dist/proxmox/ceph-osd-tree.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd-write.d.ts +2 -2
- package/dist/proxmox/ceph-osd-write.d.ts.map +1 -1
- package/dist/proxmox/ceph-osd.d.ts +1 -1
- package/dist/proxmox/ceph-osd.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-settle.d.ts +2 -2
- package/dist/proxmox/ceph-pool-settle.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts +1 -1
- package/dist/proxmox/ceph-pool-wire.d.ts.map +1 -1
- package/dist/proxmox/ceph-pool.d.ts +1 -1
- package/dist/proxmox/ceph-pool.d.ts.map +1 -1
- package/dist/proxmox/client.d.ts +1 -1
- package/dist/proxmox/client.d.ts.map +1 -1
- package/dist/proxmox/distilled-pbs.d.ts +1 -1
- package/dist/proxmox/distilled-pbs.d.ts.map +1 -1
- package/dist/proxmox/distilled-pve.d.ts +1 -1
- package/dist/proxmox/distilled-pve.d.ts.map +1 -1
- package/dist/proxmox/fake-pbs-jobs.d.ts +1 -1
- package/dist/proxmox/fake-pve.d.ts +1 -1
- package/dist/proxmox/fake-pve.d.ts.map +1 -1
- package/dist/proxmox/firewall-alias-lifecycle.d.ts +6 -6
- package/dist/proxmox/firewall-alias-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/firewall-alias.d.ts +1 -1
- package/dist/proxmox/firewall-alias.d.ts.map +1 -1
- package/dist/proxmox/group-wire.d.ts +2 -2
- package/dist/proxmox/group-wire.d.ts.map +1 -1
- package/dist/proxmox/group.d.ts +1 -1
- package/dist/proxmox/group.d.ts.map +1 -1
- package/dist/proxmox/ha-resource.d.ts +1 -1
- package/dist/proxmox/ha-resource.d.ts.map +1 -1
- package/dist/proxmox/ha-rule.d.ts +1 -1
- package/dist/proxmox/ha-rule.d.ts.map +1 -1
- package/dist/proxmox/index.js +38 -17
- package/dist/proxmox/index.js.map +9 -9
- package/dist/proxmox/lease-cache.d.ts +2 -2
- package/dist/proxmox/lease-cache.d.ts.map +1 -1
- package/dist/proxmox/live-core-fixtures.d.ts +1 -1
- package/dist/proxmox/live-core-fixtures.d.ts.map +1 -1
- package/dist/proxmox/lxc-lifecycle.d.ts +3 -3
- package/dist/proxmox/lxc-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/lxc-read.d.ts +1 -1
- package/dist/proxmox/lxc-read.d.ts.map +1 -1
- package/dist/proxmox/lxc-task.d.ts +1 -1
- package/dist/proxmox/lxc-task.d.ts.map +1 -1
- package/dist/proxmox/lxc.d.ts +1 -1
- package/dist/proxmox/lxc.d.ts.map +1 -1
- package/dist/proxmox/members.d.ts +3 -3
- package/dist/proxmox/members.d.ts.map +1 -1
- package/dist/proxmox/metric-server-distilled.d.ts +3 -3
- package/dist/proxmox/metric-server-distilled.d.ts.map +1 -1
- package/dist/proxmox/metric-server.d.ts +1 -1
- package/dist/proxmox/metric-server.d.ts.map +1 -1
- package/dist/proxmox/mint.d.ts +1 -1
- package/dist/proxmox/mint.d.ts.map +1 -1
- package/dist/proxmox/network-apply-read.d.ts +3 -3
- package/dist/proxmox/network-apply-read.d.ts.map +1 -1
- package/dist/proxmox/network-apply-run.d.ts +1 -1
- package/dist/proxmox/network-apply-run.d.ts.map +1 -1
- package/dist/proxmox/network-apply.d.ts +1 -1
- package/dist/proxmox/network-apply.d.ts.map +1 -1
- package/dist/proxmox/node-network-wire.d.ts +2 -2
- package/dist/proxmox/node-network-wire.d.ts.map +1 -1
- package/dist/proxmox/node-network.d.ts +1 -1
- package/dist/proxmox/node-network.d.ts.map +1 -1
- package/dist/proxmox/notification-matcher-distilled.d.ts +4 -4
- package/dist/proxmox/notification-matcher-distilled.d.ts.map +1 -1
- package/dist/proxmox/notification-matcher-lifecycle.d.ts +4 -4
- package/dist/proxmox/notification-matcher.d.ts +1 -1
- package/dist/proxmox/notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/notification-target-distilled.d.ts +4 -4
- package/dist/proxmox/notification-target-distilled.d.ts.map +1 -1
- package/dist/proxmox/notification-target-lifecycle.d.ts +4 -4
- package/dist/proxmox/notification-target.d.ts +1 -1
- package/dist/proxmox/notification-target.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-datastore-wire.d.ts +4 -4
- package/dist/proxmox/pbs-datastore-wire.d.ts.map +1 -1
- package/dist/proxmox/pbs-datastore.d.ts +1 -1
- package/dist/proxmox/pbs-datastore.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-matcher-distilled.d.ts +4 -4
- package/dist/proxmox/pbs-notification-matcher-distilled.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-matcher.d.ts +1 -1
- package/dist/proxmox/pbs-notification-matcher.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target-distilled.d.ts +4 -4
- package/dist/proxmox/pbs-notification-target-distilled.d.ts.map +1 -1
- package/dist/proxmox/pbs-notification-target-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-notification-target.d.ts +1 -1
- package/dist/proxmox/pbs-notification-target.d.ts.map +1 -1
- package/dist/proxmox/pbs-prune-job-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-prune-job-wire.d.ts +4 -4
- package/dist/proxmox/pbs-prune-job-wire.d.ts.map +1 -1
- package/dist/proxmox/pbs-prune-job.d.ts +1 -1
- package/dist/proxmox/pbs-prune-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-sync-job-wire.d.ts +4 -4
- package/dist/proxmox/pbs-sync-job-wire.d.ts.map +1 -1
- package/dist/proxmox/pbs-sync-job.d.ts +1 -1
- package/dist/proxmox/pbs-sync-job.d.ts.map +1 -1
- package/dist/proxmox/pbs-verify-job-lifecycle.d.ts +4 -4
- package/dist/proxmox/pbs-verify-job-wire.d.ts +4 -4
- package/dist/proxmox/pbs-verify-job-wire.d.ts.map +1 -1
- package/dist/proxmox/pbs-verify-job.d.ts +1 -1
- package/dist/proxmox/pbs-verify-job.d.ts.map +1 -1
- package/dist/proxmox/pool.d.ts +3 -3
- package/dist/proxmox/pool.d.ts.map +1 -1
- package/dist/proxmox/provision-declare.d.ts +1 -1
- package/dist/proxmox/provision-declare.d.ts.map +1 -1
- package/dist/proxmox/qemu-lifecycle.d.ts +3 -3
- package/dist/proxmox/qemu-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/qemu-read.d.ts +1 -1
- package/dist/proxmox/qemu-read.d.ts.map +1 -1
- package/dist/proxmox/qemu-resize.d.ts +1 -1
- package/dist/proxmox/qemu-resize.d.ts.map +1 -1
- package/dist/proxmox/qemu-task.d.ts +1 -1
- package/dist/proxmox/qemu-task.d.ts.map +1 -1
- package/dist/proxmox/qemu.d.ts +1 -1
- package/dist/proxmox/qemu.d.ts.map +1 -1
- package/dist/proxmox/replication-job-lifecycle.d.ts +6 -6
- package/dist/proxmox/replication-job-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/replication-job.d.ts +1 -1
- package/dist/proxmox/replication-job.d.ts.map +1 -1
- package/dist/proxmox/resource-spec.d.ts +1 -1
- package/dist/proxmox/resource-spec.d.ts.map +1 -1
- package/dist/proxmox/resource.d.ts +8 -8
- package/dist/proxmox/role.d.ts +1 -1
- package/dist/proxmox/role.d.ts.map +1 -1
- package/dist/proxmox/sdn-apply-read.d.ts +1 -1
- package/dist/proxmox/sdn-apply-read.d.ts.map +1 -1
- package/dist/proxmox/sdn-apply.d.ts +1 -1
- package/dist/proxmox/sdn-apply.d.ts.map +1 -1
- package/dist/proxmox/sdn-subnet.d.ts +1 -1
- package/dist/proxmox/sdn-subnet.d.ts.map +1 -1
- package/dist/proxmox/sdn-vnet.d.ts +1 -1
- package/dist/proxmox/sdn-vnet.d.ts.map +1 -1
- package/dist/proxmox/sdn-zone.d.ts +1 -1
- package/dist/proxmox/sdn-zone.d.ts.map +1 -1
- package/dist/proxmox/storage-download-lifecycle.d.ts +6 -6
- package/dist/proxmox/storage-download-lifecycle.d.ts.map +1 -1
- package/dist/proxmox/storage-download-task.d.ts +1 -1
- package/dist/proxmox/storage-download-task.d.ts.map +1 -1
- package/dist/proxmox/storage-download.d.ts +1 -1
- package/dist/proxmox/storage-download.d.ts.map +1 -1
- package/dist/proxmox/storage-wire.d.ts +2 -2
- package/dist/proxmox/storage-wire.d.ts.map +1 -1
- package/dist/proxmox/storage.d.ts +1 -1
- package/dist/proxmox/storage.d.ts.map +1 -1
- package/dist/proxmox/user-wire.d.ts +2 -2
- package/dist/proxmox/user-wire.d.ts.map +1 -1
- package/dist/proxmox/user.d.ts +1 -1
- package/dist/proxmox/user.d.ts.map +1 -1
- package/dist/proxmox/zfs-pool-form.d.ts +2 -2
- package/dist/proxmox/zfs-pool-form.d.ts.map +1 -1
- package/dist/proxmox/zfs-pool-wire.d.ts +2 -2
- package/dist/proxmox/zfs-pool-wire.d.ts.map +1 -1
- package/dist/proxmox/zfs-pool.d.ts +1 -1
- package/dist/proxmox/zfs-pool.d.ts.map +1 -1
- package/dist/release/binary.d.ts +1 -1
- package/dist/release/binary.d.ts.map +1 -1
- package/dist/release/download.d.ts +1 -1
- package/dist/release/download.d.ts.map +1 -1
- package/dist/release/index.js +6 -5
- package/dist/release/index.js.map +5 -5
- package/dist/talos/credentials-write.d.ts +1 -1
- package/dist/talos/credentials-write.d.ts.map +1 -1
- package/dist/talos/credentials.d.ts +1 -1
- package/dist/talos/credentials.d.ts.map +1 -1
- package/dist/talos/fake-process.d.ts +2 -2
- package/dist/talos/fake-process.d.ts.map +1 -1
- package/dist/talos/index.js +7 -7
- package/dist/talos/index.js.map +4 -4
- package/dist/talos/kubeconfig.d.ts +4 -4
- package/dist/talos/kubeconfig.d.ts.map +1 -1
- package/dist/talos/machine-config-fixtures.d.ts +1 -1
- package/dist/talos/machine-config-fixtures.d.ts.map +1 -1
- package/dist/talos/machine-config-read.d.ts +3 -3
- package/dist/talos/machine-config-read.d.ts.map +1 -1
- package/dist/talos/resource.d.ts +1 -1
- package/dist/talos/resource.d.ts.map +1 -1
- package/dist/talos/talos-bootstrap-etcd.d.ts +2 -2
- package/dist/talos/talos-bootstrap-etcd.d.ts.map +1 -1
- package/dist/talos/talos-bootstrap.d.ts +4 -4
- package/dist/talos/talos-bootstrap.d.ts.map +1 -1
- package/dist/talos/talos-cluster-health.d.ts +4 -4
- package/dist/talos/talos-cluster-health.d.ts.map +1 -1
- package/dist/talos/talos-machine-config.d.ts +2 -2
- package/dist/talos/talos-machine-config.d.ts.map +1 -1
- package/dist/talos/talosctl.d.ts +1 -1
- package/dist/talos/talosctl.d.ts.map +1 -1
- package/dist/telemetry/index.js +4 -4
- package/dist/telemetry/index.js.map +3 -3
- package/dist/telemetry/redact-serialization.d.ts +2 -2
- package/dist/telemetry/redact-serialization.d.ts.map +1 -1
- package/dist/unifi/acl-rule-ordering.d.ts +6 -6
- package/dist/unifi/acl-rule-ordering.d.ts.map +1 -1
- package/dist/unifi/acl-rule.d.ts +6 -6
- package/dist/unifi/acl-rule.d.ts.map +1 -1
- package/dist/unifi/dns-policy.d.ts +6 -6
- package/dist/unifi/dns-policy.d.ts.map +1 -1
- package/dist/unifi/fake-unifi.d.ts +1 -1
- package/dist/unifi/fake-unifi.d.ts.map +1 -1
- package/dist/unifi/firewall-policy-ordering.d.ts +6 -6
- package/dist/unifi/firewall-policy-ordering.d.ts.map +1 -1
- package/dist/unifi/firewall-policy.d.ts +6 -6
- package/dist/unifi/firewall-policy.d.ts.map +1 -1
- package/dist/unifi/firewall-zone.d.ts +6 -6
- package/dist/unifi/firewall-zone.d.ts.map +1 -1
- package/dist/unifi/index.js +2 -2
- package/dist/unifi/index.js.map +2 -2
- package/dist/unifi/network.d.ts +6 -6
- package/dist/unifi/network.d.ts.map +1 -1
- package/dist/unifi/providers.d.ts +1 -1
- package/dist/unifi/providers.d.ts.map +1 -1
- package/dist/unifi/resource.d.ts +1 -1
- package/dist/unifi/resource.d.ts.map +1 -1
- package/dist/unifi/traffic-matching-list.d.ts +6 -6
- package/dist/unifi/traffic-matching-list.d.ts.map +1 -1
- package/dist/unifi/wifi-broadcast.d.ts +6 -6
- package/dist/unifi/wifi-broadcast.d.ts.map +1 -1
- package/dist/verify/cli.js.map +1 -1
- package/dist/verify/index.js.map +1 -1
- package/docs/distilled-interim.md +1 -1
- package/docs/mesh-node.md +1 -1
- package/docs/paperless.md +1 -1
- package/docs/peers.md +8 -8
- package/docs/telemetry.md +1 -1
- package/package.json +20 -20
- package/src/argocd/fake-argocd.ts +1 -1
- package/src/argocd/resource.ts +1 -1
- package/src/caddy/admin-transport-scope.test.ts +2 -2
- package/src/caddy/admin.ts +1 -1
- package/src/caddy/caddy-http-client.ts +5 -5
- package/src/caddy/config-adopt.test.ts +2 -2
- package/src/caddy/format.ts +2 -2
- package/src/caddy/local-admin.test.ts +1 -1
- package/src/ceph/auth-entity.ts +1 -1
- package/src/ceph/ceph-auth-reconcile.ts +1 -1
- package/src/cloudflare/fake-mesh.ts +1 -1
- package/src/cloudflare/fake-r2-lock.ts +1 -1
- package/src/cloudflare/mesh-node-harness.ts +1 -1
- package/src/cloudflare/mesh-node.ts +1 -1
- package/src/cloudflare/r2-bucket-lock.ts +1 -1
- package/src/discord/fake-discord.ts +1 -1
- package/src/discord/resource.ts +1 -1
- package/src/forgejo/fake-forgejo.ts +1 -1
- package/src/forgejo/resource.ts +1 -1
- package/src/google-workspace/fake-google-workspace.ts +1 -1
- package/src/google-workspace/resource.ts +1 -1
- package/src/grafana/fake-grafana.ts +1 -1
- package/src/litellm/access-group.test.ts +1 -1
- package/src/litellm/credential-errors.ts +1 -1
- package/src/litellm/credential-guards.test.ts +1 -1
- package/src/litellm/credential-operations.ts +1 -1
- package/src/litellm/credential-rewrite.test.ts +1 -1
- package/src/litellm/fake-stack.ts +1 -1
- package/src/litellm/key-errors.ts +1 -1
- package/src/litellm/key-harness.ts +1 -1
- package/src/litellm/key-operations.ts +1 -1
- package/src/litellm/key.test.ts +2 -1
- package/src/litellm/mcp-server-handlers.test.ts +1 -1
- package/src/litellm/mcp-server-registry.test.ts +1 -1
- package/src/litellm/model-operations.test.ts +1 -1
- package/src/litellm/operations.ts +1 -1
- package/src/litellm/pass-through-endpoint-delete-swallow.test.ts +1 -1
- package/src/litellm/pass-through-endpoint.test.ts +1 -1
- package/src/litellm/pass-through-fetch-client.test.ts +2 -2
- package/src/litellm/policy-attachment.test.ts +1 -1
- package/src/litellm/policy.test.ts +1 -1
- package/src/litellm/team-members.test.ts +1 -1
- package/src/litellm/team-read.test.ts +1 -1
- package/src/litellm/tool-policy.test.ts +1 -1
- package/src/litellm/toolset.test.ts +1 -1
- package/src/netbox/fake-netbox.ts +1 -1
- package/src/netbox/resource.ts +1 -1
- package/src/openbao/adopt-core.test.ts +4 -1
- package/src/openbao/adopt-families.test.ts +4 -1
- package/src/openbao/adopt-holes.test.ts +1 -1
- package/src/openbao/adopt-recovery.test.ts +24 -0
- package/src/openbao/approle-login.ts +2 -2
- package/src/openbao/auth-method-reconcile.ts +1 -1
- package/src/openbao/auth-method.ts +1 -1
- package/src/openbao/auth-role-sdk.test.ts +1 -1
- package/src/openbao/auth-role.ts +1 -1
- package/src/openbao/bao-http.test.ts +3 -3
- package/src/openbao/bao-http.ts +4 -4
- package/src/openbao/bao-identity.ts +2 -2
- package/src/openbao/cloudflare-permission-groups.ts +1 -1
- package/src/openbao/cloudflare-role-wire.ts +1 -1
- package/src/openbao/cloudflare-role.ts +1 -1
- package/src/openbao/distilled-retry.test.ts +3 -3
- package/src/openbao/distilled.test.ts +3 -3
- package/src/openbao/distilled.ts +2 -2
- package/src/openbao/fake-bao.ts +2 -2
- package/src/openbao/fake-core.ts +1 -1
- package/src/openbao/fake-engines.ts +1 -1
- package/src/openbao/fake-families.ts +1 -1
- package/src/openbao/fake-stack.ts +13 -3
- package/src/openbao/jwt-config.ts +1 -1
- package/src/openbao/jwt-role.ts +1 -1
- package/src/openbao/kubernetes-role.ts +1 -1
- package/src/openbao/mfa-enforcement.ts +1 -1
- package/src/openbao/mfa-totp.ts +1 -1
- package/src/openbao/mfa-wire.ts +1 -1
- package/src/openbao/mount-move.ts +1 -1
- package/src/openbao/mount-reconcile.ts +1 -1
- package/src/openbao/mount.ts +1 -1
- package/src/openbao/pki-role.ts +1 -1
- package/src/openbao/plugin-reconcile.ts +1 -1
- package/src/openbao/plugin-wire.ts +1 -1
- package/src/openbao/plugin.ts +1 -1
- package/src/openbao/policy.ts +1 -1
- package/src/openbao/proxmox-role.ts +1 -1
- package/src/openbao/remount-wire.ts +1 -1
- package/src/openbao/rename-occupied.test.ts +1 -1
- package/src/openbao/role-reconcile.ts +1 -1
- package/src/openbao/role-rename.test.ts +1 -1
- package/src/openbao/ssh-role.ts +1 -1
- package/src/opnsense/fake-opnsense.ts +1 -1
- package/src/opnsense/resource.ts +1 -1
- package/src/ownership/probe.ts +51 -2
- package/src/paperless/fake-paperless.ts +1 -1
- package/src/paperless/matching-types.ts +1 -1
- package/src/postgres/connection.ts +1 -1
- package/src/postgres/database-bigint-serialization.test.ts +1 -1
- package/src/postgres/database-sql.ts +1 -1
- package/src/postgres/database.ts +1 -1
- package/src/postgres/fake-grants-read.ts +1 -1
- package/src/postgres/fake-grants-sql.ts +1 -1
- package/src/postgres/fake-grants-write.ts +1 -1
- package/src/postgres/fake-role-sql.ts +1 -1
- package/src/postgres/fake-schema-drop.ts +1 -1
- package/src/postgres/fake-schema-sql.ts +1 -1
- package/src/postgres/fake-sql.ts +1 -1
- package/src/postgres/grants-existence.ts +1 -1
- package/src/postgres/grants-ops.ts +1 -1
- package/src/postgres/grants-ownership.ts +1 -1
- package/src/postgres/grants-read-defaults.ts +1 -1
- package/src/postgres/grants-read.ts +1 -1
- package/src/postgres/grants-relkind-wire.test.ts +6 -4
- package/src/postgres/installed-classifier.ts +1 -1
- package/src/postgres/psql-executor.ts +1 -6
- package/src/postgres/role-membership-sql.ts +1 -1
- package/src/postgres/role-password-transports.test.ts +2 -2
- package/src/postgres/role-sql.ts +1 -1
- package/src/postgres/role.ts +1 -1
- package/src/postgres/schema-assert.ts +1 -1
- package/src/postgres/schema-delete.ts +1 -1
- package/src/postgres/schema-drop-2bp01.test.ts +1 -1
- package/src/postgres/schema-drop-sql.ts +1 -1
- package/src/postgres/schema-drop.test.ts +1 -1
- package/src/postgres/schema-reconcile.ts +1 -1
- package/src/postgres/schema-socket.test.ts +1 -1
- package/src/postgres/schema-sql.ts +1 -1
- package/src/postgres/search-path.ts +1 -1
- package/src/proxmox/ceph-flag-wire.test.ts +1 -1
- package/src/proxmox/ceph-fs-destroy-sdk.test.ts +1 -1
- package/src/proxmox/ceph-pool-write.test.ts +1 -1
- package/src/proxmox/client.test.ts +2 -2
- package/src/proxmox/client.ts +2 -2
- package/src/proxmox/credentials.test.ts +1 -1
- package/src/proxmox/distilled-pbs.test.ts +1 -1
- package/src/proxmox/distilled-pbs.ts +1 -1
- package/src/proxmox/distilled-pve.test.ts +2 -2
- package/src/proxmox/distilled-pve.ts +1 -1
- package/src/proxmox/fake-pbs-jobs.ts +1 -1
- package/src/proxmox/fake-pve.ts +1 -1
- package/src/proxmox/lease-cache-mint.test.ts +1 -1
- package/src/proxmox/live-core-fixtures.ts +1 -1
- package/src/proxmox/lxc-distilled.test.ts +1 -1
- package/src/proxmox/lxc-harness.ts +1 -1
- package/src/proxmox/members-timeout.test.ts +3 -3
- package/src/proxmox/members.test.ts +1 -1
- package/src/proxmox/members.ts +4 -4
- package/src/proxmox/mint.ts +4 -4
- package/src/proxmox/node-network-read-failure.test.ts +1 -1
- package/src/proxmox/qemu-lifecycle.ts +1 -1
- package/src/proxmox/read-failure-propagation.test.ts +1 -1
- package/src/proxmox/resource-spec.ts +1 -1
- package/src/proxmox/storage-read-failure.test.ts +1 -1
- package/src/proxmox/typed-absence.test.ts +2 -2
- package/src/proxmox/unreadable-read.test.ts +1 -1
- package/src/proxmox/user.test.ts +1 -1
- package/src/proxmox/zfs-pool-read-failure.test.ts +1 -1
- package/src/release/adopt-parity.test.ts +3 -1
- package/src/release/apply-pins.test.ts +2 -2
- package/src/release/binary-root.test.ts +2 -2
- package/src/release/binary.ts +9 -2
- package/src/release/download.test.ts +3 -3
- package/src/release/download.ts +1 -1
- package/src/release/fake-deploy.ts +2 -2
- package/src/release/fake-engine.ts +2 -2
- package/src/release/fake-provider.ts +2 -2
- package/src/release/plan.test.ts +2 -2
- package/src/release/providers.ts +1 -1
- package/src/talos/credentials-write.test.ts +1 -1
- package/src/talos/credentials-write.ts +2 -2
- package/src/talos/credentials.test.ts +1 -1
- package/src/talos/credentials.ts +2 -2
- package/src/talos/fake-process.ts +2 -2
- package/src/talos/kubeconfig.test.ts +1 -1
- package/src/talos/machine-config-fixtures.ts +1 -1
- package/src/talos/resource.ts +1 -1
- package/src/talos/talos-bootstrap.test.ts +1 -1
- package/src/talos/talos-cluster-health.test.ts +1 -1
- package/src/talos/talosctl.ts +2 -2
- package/src/telemetry/http-client-sealing.test.ts +2 -2
- package/src/telemetry/layer.test.ts +3 -3
- package/src/telemetry/layer.ts +2 -2
- package/src/telemetry/redact-serialization.ts +2 -2
- package/src/unifi/fake-unifi.ts +1 -1
- package/src/unifi/get-only-guard.test.ts +3 -3
- package/src/unifi/resource.ts +1 -1
- package/src/verify/args.ts +1 -1
|
@@ -2,80 +2,80 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/openbao/approle-login.ts", "../src/openbao/bao-http.ts", "../src/openbao/bao-address.ts", "../src/openbao/bao-status.ts", "../src/openbao/mount-path.ts", "../src/openbao/approle-login-form.ts", "../src/openbao/approle-login-result.ts", "../src/openbao/auth-method.ts", "../src/ownership/adopt.ts", "../src/ownership/resume.ts", "../src/ownership/rows.ts", "../src/ownership/whole.ts", "../src/ownership/probe.ts", "../src/openbao/digest.ts", "../src/openbao/mount-form.ts", "../src/openbao/auth-method-form.ts", "../src/openbao/auth-method-reconcile.ts", "../src/openbao/auth-method-wire.ts", "../src/openbao/mount-move.ts", "../src/openbao/remount-wire.ts", "../src/openbao/auth-role.ts", "../src/openbao/auth-role-form.ts", "../src/openbao/auth-role-wire.ts", "../src/openbao/distilled.ts", "../src/openbao/rename.ts", "../src/openbao/rename-identity.ts", "../src/openbao/auth-role-identity.ts", "../src/openbao/bao-identity.ts", "../src/openbao/bao-namespace.ts", "../src/openbao/cloudflare-role.ts", "../src/openbao/cloudflare-group-scope.ts", "../src/openbao/cloudflare-permission-groups.ts", "../src/openbao/cloudflare-permission-groups-solve.ts", "../src/openbao/cloudflare-policy.ts", "../src/openbao/cloudflare-role-wire.ts", "../src/openbao/cloudflare-role-form.ts", "../src/openbao/cloudflare-roles-expand.ts", "../src/openbao/cloudflare-roles-config.ts", "../src/openbao/host-approles.ts", "../src/openbao/jwt-config.ts", "../src/openbao/jwt-config-form.ts", "../src/openbao/role-reconcile.ts", "../src/openbao/jwt-role.ts", "../src/openbao/auth-token-form.ts", "../src/openbao/jwt-role-form.ts", "../src/openbao/kubernetes-role.ts", "../src/openbao/kubernetes-role-form.ts", "../src/openbao/mfa-enforcement.ts", "../src/openbao/mfa-enforcement-form.ts", "../src/openbao/mfa-wire.ts", "../src/openbao/mfa-totp.ts", "../src/openbao/mfa-totp-form.ts", "../src/openbao/mount.ts", "../src/openbao/mount-reconcile.ts", "../src/openbao/mount-wire.ts", "../src/openbao/pki-role.ts", "../src/openbao/pki-role-canonical.ts", "../src/openbao/pki-role-form.ts", "../src/openbao/plugin.ts", "../src/openbao/plugin-form.ts", "../src/openbao/plugin-reconcile.ts", "../src/openbao/plugin-wire.ts", "../src/openbao/policy.ts", "../src/openbao/policy-assembly.ts", "../src/openbao/policy-wire.ts", "../src/openbao/policy-identity.ts", "../src/openbao/proxmox-role.ts", "../src/openbao/proxmox-role-form.ts", "../src/openbao/proxmox-role-wire.ts", "../src/openbao/ssh-role.ts", "../src/openbao/ssh-role-form.ts", "../src/openbao/ssh-role-erase.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"/**\n * AppRole login and self-revoke for a plain Bun script — the one part of the openbao subpath that is\n * not a Resource.\n *\n * ★ WHY IT LIVES HERE. Wrapper scripts log in with a per-host AppRole and revoke the token on exit.\n * Each one hand-rolling a `fetch` is how two of them end up disagreeing about BAO_ADDR versus\n * BAO_AGENT_ADDR, or dropping the namespace header. This rides the transport every Bao.* family\n * already uses: bao-address.ts resolution (BAO_ADDR, BAO_AGENT_ADDR, BAO_NAMESPACE, the VAULT_*\n * twins, unix sockets), bao-http.ts's in-flight gate, timeout, transport retry and token\n * redaction on spans, and bao-status.ts's status-first classification of the answer.\n * ★ ONE IMPLEMENTATION, TWO SHAPES. `appRoleLoginEffect` and `revokeSelfEffect` are the\n * implementation; `appRoleLogin` and `revokeSelf` run them on the fetch client for a caller with\n * no Effect runtime. Both fail with BaoLoginError and nothing else.\n *\n * ⚠️ SHARING A secret_id ACROSS HOSTS THROUGH A CACHING PROXY SHARES THE TOKEN. Two hosts sending\n * the same AppRole login through a caching OpenBao Proxy get the SAME cached token back, so two\n * hosts become one identity in every audit line (recorded as a trap in the 2026-09-21 vault\n * consolidation plan; not re-measured here). Give each host its own secret_id.\n */\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/
|
|
6
|
-
"/**\n * One call to OpenBao's HTTP API through Effect's `HttpClient` — the transport every Bao.* family\n * uses since it stopped shelling out to `bao`.\n *\n * ★ `HttpClient`, THE SAME PATTERN <estate>/proxmox and <estate>/forgejo USE AGAINST THEIR APIs, decided\n * 2026-09-14. It buys a typed error channel, interruption when a plan is cancelled, the runtime's\n * tracing, and a client a test can point at a fake server — and it needs no Alchemy session, so\n * every call here works from all four operations. (`CommandExecutor.run` was tried on Bao.Policy\n * first and blocked read/diff: Alchemy passes a session to reconcile/delete but NOT to read/diff,\n * Provider.ts:258-289. The ChildProcessSpawner that fixed that is gone with the CLI.)\n * ⚠️ THE STACK MUST PROVIDE `FetchHttpClient.layer`. alchemy.run.ts does, the way\n * <estate>/proxmox/alchemy.run.ts does.\n */\nimport * as Cause from 'effect/Cause';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport * as Schedule from 'effect/Schedule';\nimport * as Semaphore from 'effect/Semaphore';\nimport * as FetchHttpClient from 'effect/unstable/http/FetchHttpClient';\nimport * as Headers from 'effect/unstable/http/Headers';\nimport * as HttpClient from 'effect/unstable/http/HttpClient';\nimport * as HttpClientRequest from 'effect/unstable/http/HttpClientRequest';\nimport { type BaoEnvironment, headersFor, resolveAddress } from './bao-address.ts';\nimport { BaoError, type BaoIntent, settle } from './bao-status.ts';\n\n/**\n * The environment a call resolves BAO_ADDR, BAO_NAMESPACE and BAO_TOKEN from — `process.env`,\n * read at call time, unless a test provides another.\n */\nexport const BaoEnv = Context.Reference<BaoEnvironment>('homeflare/openbao/BaoEnv', {\n defaultValue: () => process.env,\n});\n\n/**\n * ⛔ AT MOST EIGHT EXCHANGES WITH OPENBAO AT ONCE — ACROSS EVERY Bao.* FAMILY, IN ONE PROCESS.\n *\n * 🔴 MEASURED 2026-09-14 10:41: A DEPLOY OF THIS STACK TOOK OPENBAO's API OFF ITS HOST. Alchemy fans\n * resources out with a hard-coded `concurrency: \"unbounded\"` (alchemy Plan.ts:476, Apply.ts:259,\n * :263, :303 — no option reaches it), and 555 Bao.CloudflareRole resources each read, diff,\n * reconcile and read back: well over a thousand requests at one loopback listener within seconds.\n * OpenBao logged\n * HTTP server (listening on 127.0.0.1:8200) exited with error: set tcp\n * 127.0.0.1:8200->127.0.0.1:57974: setsockopt: invalid argument\n * and KEPT RUNNING with 8200 closed. launchd saw a live process and restarted nothing. Everything\n * on the vault host that talks to 127.0.0.1:8200 was cut off, starting with the agent's templates, until\n * a manual restart.\n * ★ THE LISTENER DYING IS A GO-ON-DARWIN FAILURE, NOT OURS TO FIX. Traefik lost its entrypoints the\n * same way on darwin/arm64 (traefik issue 8841). The BURST is ours. The adoption deploy an hour\n * earlier made the same calls and survived, so a cap narrows a race; it does not prove it closed.\n * ★ A SEMAPHORE, NOT `HttpClient.withRateLimiter`. That limits requests per window and needs a\n * RateLimiter service. The failure is simultaneous connections, and only a cap on in-flight\n * exchanges bounds those whatever each one's latency.\n * ⚠️ A Context.Reference SO A TEST CAN PROVIDE ITS OWN GATE. The default is built ONCE and cached on\n * the reference (effect Context.ts:1582-1588), so every call in the process shares one gate.\n * ⚠️ EIGHT IS A CHOICE, NOT A MEASUREMENT OF WHAT THE LISTENER TOLERATES. Nothing here can find that\n * number without re-running the failure against production.\n */\nexport const MAX_IN_FLIGHT = 8;\n\nexport const BaoGate = Context.Reference<Semaphore.Semaphore>('homeflare/openbao/BaoGate', {\n defaultValue: () => Semaphore.makeUnsafe(MAX_IN_FLIGHT),\n});\n\n/**\n * ⚠️ THE CLI's DEFAULT CLIENT TIMEOUT (openbao v2.6.2 api/client.go:324). A hung agent or a server\n * that accepts and never answers would otherwise hang the plan with no line saying why.\n */\nexport const BAO_TIMEOUT = '60 seconds';\n\n/**\n * Mesh in front of a remote OpenBao drops connections under Alchemy's unbounded\n * fan-out. Status 0 is transport, not an OpenBao 4xx — retry twice. Measured\n * 2026-09-16 against bao.example.internal: a 585-role plan died mid-diff with\n * `no response: (no errors given)` while the vault stayed unsealed.\n */\nexport const retryTransport = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.retry(effect, {\n schedule: Schedule.spaced('750 millis'),\n times: 2,\n while: (error) =>\n (error instanceof BaoError && error.status === 0) || Cause.isTimeoutError(error),\n });\n\n/**\n * ⛔ EFFECT RECORDS EVERY REQUEST HEADER ON THE CLIENT SPAN and redacts only the names in\n * `Headers.CurrentRedactedNames` — by default authorization, cookie, set-cookie and x-api-key\n * (effect Headers.ts:753-762; HttpClient.ts:842-849, with `TracerHeaderFilter` defaulting to\n * true). `X-Vault-Token` is not on that list, so under any tracer the token would be exported as\n * a span attribute. It is added for every call made here.\n */\nexport const redactingToken = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.gen(function* () {\n const names = yield* Headers.CurrentRedactedNames;\n return yield* Effect.provideService(effect, Headers.CurrentRedactedNames, [\n ...names,\n 'x-vault-token',\n ]);\n });\n\n/**\n * Route the exchange over a unix socket when the address is one.\n *\n * ★ BUN's `fetch` TAKES A `unix` OPTION (bun-types globals.d.ts BunFetchRequestInit.unix), AND\n * `FetchHttpClient.RequestInit` IS EFFECT'S DOCUMENTED WAY TO PASS FETCH OPTIONS. The fetch client\n * spreads that service into every call (effect FetchHttpClient.ts:59-72), reading it from the\n * CALLING fiber's context — and `layerMergedContext` merges the caller's context over the layer's\n * (HttpClient.ts:2065-2076), so providing it around one call routes that call alone. Any defaults\n * already provided are kept.\n * ⛔ IT ONLY WORKS ON BUN, SO ANYWHERE ELSE IT REFUSES. Node's fetch ignores `unix` and would send\n * the request to http://localhost:80 — a silent wrong server, which is the one outcome this\n * package exists to prevent. It also assumes the provided `HttpClient` is the fetch one.\n */\nexport const overSocket =\n (socket: string | undefined, method: string, path: string) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | BaoError, R> => {\n if (socket === undefined) return effect;\n if (typeof Bun === 'undefined') {\n return Effect.fail(\n new BaoError(0, method, path, ['a unix:// address needs Bun fetch; this is not Bun']),\n );\n }\n return Effect.flatMap(Effect.serviceOption(FetchHttpClient.RequestInit), (defaults) => {\n const init: BunFetchRequestInit = { ...Option.getOrElse(defaults, () => ({})), unix: socket };\n return Effect.provideService(effect, FetchHttpClient.RequestInit, init);\n });\n };\n\n/** One exchange, classified. The body is the parsed JSON object, or undefined for absent / 204. */\nexport const baoCall = (\n intent: BaoIntent,\n method: 'DELETE' | 'GET' | 'POST' | 'PUT',\n path: string,\n body?: Readonly<Record<string, unknown>>,\n) =>\n Effect.gen(function* () {\n const env = yield* BaoEnv;\n const address = resolveAddress(env);\n const client = yield* HttpClient.HttpClient;\n // ⚠️ The content type goes on `bodyText`, never in the header map: `bodyText` overwrites it.\n // <estate>/proxmox/src/client.ts has the scar.\n const request = HttpClientRequest.make(method)(`${address.base}/v1/${path}`).pipe(\n HttpClientRequest.setHeaders(headersFor(address, env)),\n body === undefined\n ? (self) => self\n : HttpClientRequest.bodyText(JSON.stringify(body), 'application/json'),\n );\n // ★ Status first, body read exactly once, as text — an error body is not reliably JSON.\n const exchange = client.execute(request).pipe(\n Effect.flatMap((response) =>\n Effect.map(response.text, (text) => ({ status: response.status, text })),\n ),\n Effect.timeout(BAO_TIMEOUT),\n // ⛔ `.message` ONLY: the HttpClientError message is the reason, method and URL. The error\n // object itself holds the request, whose headers hold the token.\n Effect.mapError((cause) => new BaoError(0, method, path, [cause.message])),\n );\n // ★ THE PERMIT WRAPS THE TIMEOUT, NOT THE REVERSE: a call queued behind the gate is not yet\n // talking to OpenBao, so its wait must not count against the 60 seconds.\n const gate = yield* BaoGate;\n const { status, text } = yield* retryTransport(\n exchange.pipe(\n overSocket(address.socket, method, path),\n redactingToken,\n Semaphore.withPermits(gate, 1),\n ),\n );\n const outcome = settle(intent, method, path, status, text);\n return 'error' in outcome ? yield* Effect.fail(outcome.error) : outcome.body;\n });\n\n/**\n * The `data` of a read, or undefined when OpenBao says the object is ABSENT (404).\n *\n * ★ `bao read -format=json` printed this same response body; the old helper took `data` when it was\n * an object and the whole body otherwise, and so does this.\n */\nexport const baoRead = (path: string) =>\n Effect.map(baoCall('read', 'GET', path), (body) => {\n if (body === undefined) return undefined;\n const data = body['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)\n : (body as Record<string, unknown>);\n });\n\n/**\n * A write whose SUCCESS MATTERS. Any non-2xx fails, 404 included.\n *\n * ★ `PUT` IS WHAT `bao write` SENT (openbao v2.6.2 api/logical.go Write); `sys/mounts` enable and\n * tune are `POST` in the same client (api/sys_mounts.go:57, :201).\n * ⚠️ ROLE BODIES STAY ALL-STRING ON PURPOSE. `bao write k=v` put every value in the JSON body as a\n * string — MEASURED with `-output-curl-string`, see ssh-role-form.ts — and the form files still\n * build exactly that body, so the server parses the same request it was always sent.\n * ⛔ EXCEPT A MAP FIELD: sdk v2.6.2 refuses a string for a TypeMap with a 400, so Bao.SshRole\n * sends its two maps as objects (the ⛔ on mapValue in ssh-role-form.ts, measured 2026-09-21).\n */\nexport const baoWrite = (\n method: 'POST' | 'PUT',\n path: string,\n body: Readonly<Record<string, unknown>>,\n) => Effect.asVoid(baoCall('write', method, path, body));\n\n/** A delete: idempotent — already gone (404) is success — and refused (403, 5xx) is a failure. */\nexport const baoDelete = (path: string) => Effect.asVoid(baoCall('delete', 'DELETE', path));\n",
|
|
5
|
+
"/**\n * AppRole login and self-revoke for a plain Bun script — the one part of the openbao subpath that is\n * not a Resource.\n *\n * ★ WHY IT LIVES HERE. Wrapper scripts log in with a per-host AppRole and revoke the token on exit.\n * Each one hand-rolling a `fetch` is how two of them end up disagreeing about BAO_ADDR versus\n * BAO_AGENT_ADDR, or dropping the namespace header. This rides the transport every Bao.* family\n * already uses: bao-address.ts resolution (BAO_ADDR, BAO_AGENT_ADDR, BAO_NAMESPACE, the VAULT_*\n * twins, unix sockets), bao-http.ts's in-flight gate, timeout, transport retry and token\n * redaction on spans, and bao-status.ts's status-first classification of the answer.\n * ★ ONE IMPLEMENTATION, TWO SHAPES. `appRoleLoginEffect` and `revokeSelfEffect` are the\n * implementation; `appRoleLogin` and `revokeSelf` run them on the fetch client for a caller with\n * no Effect runtime. Both fail with BaoLoginError and nothing else.\n *\n * ⚠️ SHARING A secret_id ACROSS HOSTS THROUGH A CACHING PROXY SHARES THE TOKEN. Two hosts sending\n * the same AppRole login through a caching OpenBao Proxy get the SAME cached token back, so two\n * hosts become one identity in every audit line (recorded as a trap in the 2026-09-21 vault\n * consolidation plan; not re-measured here). Give each host its own secret_id.\n */\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { BaoEnvironment } from './bao-address.ts';\nimport { BaoEnv, baoCall } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n BaoLoginError,\n failureOf,\n loginPath,\n mountProblem,\n redact,\n refusal,\n} from './approle-login-form.ts';\nimport { type AppRoleLogin, loginOf } from './approle-login-result.ts';\n\nexport type { BaoLoginFailure } from './approle-login-form.ts';\nexport type { AppRoleLogin } from './approle-login-result.ts';\nexport { BaoLoginError };\n\nexport interface AppRoleLoginInput {\n /** The role_id. Not a secret on its own, but half of one — it is redacted from errors too. */\n readonly roleId: string;\n /** ⛔ The secret_id. Never logged, never in an error — see `redact`. */\n readonly secretId: string;\n /** The AppRole auth mount, e.g. `approle` (the default) — no `.`/`..` segments, `?` or `#`. */\n readonly mount?: string;\n}\n\nconst LOGIN = 'OpenBao AppRole login';\nconst REVOKE = 'OpenBao revoke-self';\n\nconst failed =\n (operation: string, secrets: readonly string[]) =>\n (error: BaoError): BaoLoginError =>\n new BaoLoginError(\n failureOf(error.status),\n error.status,\n redact(error.errors, secrets),\n operation,\n );\n\n/**\n * Log in with a role_id and secret_id, under BaoEnv (process.env unless a caller provides one).\n *\n * ⛔ THE LOGIN SENDS NO TOKEN, WHATEVER THE ENVIRONMENT HOLDS. BAO_TOKEN is overridden with a\n * PRESENT-BUT-EMPTY value for this one call, which bao-address.ts readBaoVariable treats as\n * winning over VAULT_TOKEN, so headersFor omits X-Vault-Token entirely. A script that already\n * had an operator token exported must not send it along with a machine login.\n * ⚠️ A DROPPED TRANSPORT IS RETRIED TWICE (bao-http.ts retryTransport, status 0 only). If the first\n * request reached OpenBao and only the answer was lost, the retry is a second login: one extra\n * token that lives until its TTL, and — for a secret_id with `secret_id_num_uses` — one extra use.\n * A single-use secret_id can therefore come back \"invalid\" on a flaky path.\n * ★ `PUT`, THE METHOD api/logical.go:325 WriteWithContext SENDS, which is what the official Go helper\n * calls (api/auth/approle/approle.go:146). The docs show POST; both are the update operation.\n */\nexport const appRoleLoginEffect = (\n input: AppRoleLoginInput,\n): Effect.Effect<AppRoleLogin, BaoLoginError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const problems = [\n refusal('roleId', input.roleId),\n refusal('secretId', input.secretId),\n mountProblem(input.mount),\n ].filter((problem): problem is string => problem !== undefined);\n if (problems.length > 0)\n return yield* Effect.fail(new BaoLoginError('input', 0, problems, LOGIN));\n const env = yield* BaoEnv;\n const body = yield* baoCall('write', 'PUT', loginPath(input.mount), {\n role_id: input.roleId,\n secret_id: input.secretId,\n }).pipe(\n Effect.provideService(BaoEnv, { ...env, BAO_TOKEN: '' }),\n Effect.mapError(failed(LOGIN, [input.roleId, input.secretId])),\n );\n const read = loginOf(body);\n if ('problem' in read) {\n return yield* Effect.fail(new BaoLoginError('response', 0, [read.problem], LOGIN));\n }\n return read.login;\n });\n\n/**\n * Revoke `token` itself — what a wrapper runs on exit, so a login does not outlive its job.\n *\n * ★ `PUT auth/token/revoke-self`, READ FROM openbao v2.6.2 api/auth_token.go:318-330: the token\n * revoked is the one in X-Vault-Token, and the body is empty. `token` rides in that header for\n * this call only (BAO_TOKEN is overridden), whatever the environment holds.\n * ⚠️ AN ALREADY-REVOKED OR EXPIRED TOKEN IS A FAILURE, NOT A NO-OP. OpenBao refuses a token it no\n * longer knows (permission denied — not measured here), and a refusal from the wrong server looks\n * the same; \"I could not tell\" stays an error. A wrapper that only wants best-effort cleanup on\n * exit can catch BaoLoginError with reason `refused`.\n * ⚠️ NEVER THROUGH AN AGENT OR PROXY IN `use_auto_auth_token = \"force\"` MODE. Force overwrites the\n * request's token with the agent's own (bao-address.ts headersFor cites apiproxy.mdx), so this\n * would revoke the AGENT's token. The estate's LAN proxy runs with no auto-auth at all.\n */\nexport const revokeSelfEffect = (\n token: string,\n): Effect.Effect<void, BaoLoginError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const problem = refusal('token', token);\n if (problem !== undefined) {\n return yield* Effect.fail(new BaoLoginError('input', 0, [problem], REVOKE));\n }\n const env = yield* BaoEnv;\n yield* baoCall('write', 'PUT', 'auth/token/revoke-self').pipe(\n Effect.provideService(BaoEnv, { ...env, BAO_TOKEN: token }),\n Effect.mapError(failed(REVOKE, [token])),\n );\n });\n\n/**\n * ★ `Effect.runPromise` REJECTS WITH THE FAILURE ITSELF on this Effect line (measured on\n * effect 4.0.0-rc.115: the rejection is `instanceof` the failed class), so a script catches\n * BaoLoginError directly.\n */\nconst runWith = <A>(\n env: BaoEnvironment | undefined,\n effect: Effect.Effect<A, BaoLoginError, HttpClient.HttpClient>,\n): Promise<A> => {\n const scoped = env === undefined ? effect : Effect.provideService(effect, BaoEnv, env);\n return Effect.runPromise(scoped.pipe(Effect.provide(FetchHttpClient.layer)));\n};\n\n/**\n * `appRoleLoginEffect` for a plain script. `env` defaults to `process.env`, read at call time.\n *\n * const login = await appRoleLogin({ roleId, secretId });\n * try { … login.clientToken … } finally { await revokeSelf(login.clientToken); }\n */\nexport const appRoleLogin = (\n input: AppRoleLoginInput & { readonly env?: BaoEnvironment },\n): Promise<AppRoleLogin> => runWith(input.env, appRoleLoginEffect(input));\n\n/** `revokeSelfEffect` for a plain script. `env` defaults to `process.env`, read at call time. */\nexport const revokeSelf = (token: string, env?: BaoEnvironment): Promise<void> =>\n runWith(env, revokeSelfEffect(token));\n",
|
|
6
|
+
"/**\n * One call to OpenBao's HTTP API through Effect's `HttpClient` — the transport every Bao.* family\n * uses since it stopped shelling out to `bao`.\n *\n * ★ `HttpClient`, THE SAME PATTERN <estate>/proxmox and <estate>/forgejo USE AGAINST THEIR APIs, decided\n * 2026-09-14. It buys a typed error channel, interruption when a plan is cancelled, the runtime's\n * tracing, and a client a test can point at a fake server — and it needs no Alchemy session, so\n * every call here works from all four operations. (`CommandExecutor.run` was tried on Bao.Policy\n * first and blocked read/diff: Alchemy passes a session to reconcile/delete but NOT to read/diff,\n * Provider.ts:258-289. The ChildProcessSpawner that fixed that is gone with the CLI.)\n * ⚠️ THE STACK MUST PROVIDE `FetchHttpClient.layer`. alchemy.run.ts does, the way\n * <estate>/proxmox/alchemy.run.ts does.\n */\nimport * as Cause from 'effect/Cause';\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport * as Schedule from 'effect/Schedule';\nimport * as Semaphore from 'effect/Semaphore';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport * as Headers from 'effect/http/Headers';\nimport * as HttpClient from 'effect/http/HttpClient';\nimport * as HttpClientRequest from 'effect/http/HttpClientRequest';\nimport { type BaoEnvironment, headersFor, resolveAddress } from './bao-address.ts';\nimport { BaoError, type BaoIntent, settle } from './bao-status.ts';\n\n/**\n * The environment a call resolves BAO_ADDR, BAO_NAMESPACE and BAO_TOKEN from — `process.env`,\n * read at call time, unless a test provides another.\n */\nexport const BaoEnv = Context.Reference<BaoEnvironment>('homeflare/openbao/BaoEnv', {\n defaultValue: () => process.env,\n});\n\n/**\n * ⛔ AT MOST EIGHT EXCHANGES WITH OPENBAO AT ONCE — ACROSS EVERY Bao.* FAMILY, IN ONE PROCESS.\n *\n * 🔴 MEASURED 2026-09-14 10:41: A DEPLOY OF THIS STACK TOOK OPENBAO's API OFF ITS HOST. Alchemy fans\n * resources out with a hard-coded `concurrency: \"unbounded\"` (alchemy Plan.ts:476, Apply.ts:259,\n * :263, :303 — no option reaches it), and 555 Bao.CloudflareRole resources each read, diff,\n * reconcile and read back: well over a thousand requests at one loopback listener within seconds.\n * OpenBao logged\n * HTTP server (listening on 127.0.0.1:8200) exited with error: set tcp\n * 127.0.0.1:8200->127.0.0.1:57974: setsockopt: invalid argument\n * and KEPT RUNNING with 8200 closed. launchd saw a live process and restarted nothing. Everything\n * on the vault host that talks to 127.0.0.1:8200 was cut off, starting with the agent's templates, until\n * a manual restart.\n * ★ THE LISTENER DYING IS A GO-ON-DARWIN FAILURE, NOT OURS TO FIX. Traefik lost its entrypoints the\n * same way on darwin/arm64 (traefik issue 8841). The BURST is ours. The adoption deploy an hour\n * earlier made the same calls and survived, so a cap narrows a race; it does not prove it closed.\n * ★ A SEMAPHORE, NOT `HttpClient.withRateLimiter`. That limits requests per window and needs a\n * RateLimiter service. The failure is simultaneous connections, and only a cap on in-flight\n * exchanges bounds those whatever each one's latency.\n * ⚠️ A Context.Reference SO A TEST CAN PROVIDE ITS OWN GATE. The default is built ONCE and cached on\n * the reference (effect Context.ts:1582-1588), so every call in the process shares one gate.\n * ⚠️ EIGHT IS A CHOICE, NOT A MEASUREMENT OF WHAT THE LISTENER TOLERATES. Nothing here can find that\n * number without re-running the failure against production.\n */\nexport const MAX_IN_FLIGHT = 8;\n\nexport const BaoGate = Context.Reference<Semaphore.Semaphore>('homeflare/openbao/BaoGate', {\n defaultValue: () => Semaphore.makeUnsafe(MAX_IN_FLIGHT),\n});\n\n/**\n * ⚠️ THE CLI's DEFAULT CLIENT TIMEOUT (openbao v2.6.2 api/client.go:324). A hung agent or a server\n * that accepts and never answers would otherwise hang the plan with no line saying why.\n */\nexport const BAO_TIMEOUT = '60 seconds';\n\n/**\n * Mesh in front of a remote OpenBao drops connections under Alchemy's unbounded\n * fan-out. Status 0 is transport, not an OpenBao 4xx — retry twice. Measured\n * 2026-09-16 against bao.example.internal: a 585-role plan died mid-diff with\n * `no response: (no errors given)` while the vault stayed unsealed.\n */\nexport const retryTransport = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.retry(effect, {\n schedule: Schedule.spaced('750 millis'),\n times: 2,\n while: (error) =>\n (error instanceof BaoError && error.status === 0) || Cause.isTimeoutError(error),\n });\n\n/**\n * ⛔ EFFECT RECORDS EVERY REQUEST HEADER ON THE CLIENT SPAN and redacts only the names in\n * `Headers.CurrentRedactedNames` — by default authorization, cookie, set-cookie and x-api-key\n * (effect Headers.ts:753-762; HttpClient.ts:842-849, with `TracerHeaderFilter` defaulting to\n * true). `X-Vault-Token` is not on that list, so under any tracer the token would be exported as\n * a span attribute. It is added for every call made here.\n */\nexport const redactingToken = <A, E, R>(effect: Effect.Effect<A, E, R>) =>\n Effect.gen(function* () {\n const names = yield* Headers.CurrentRedactedNames;\n return yield* Effect.provideService(effect, Headers.CurrentRedactedNames, [\n ...names,\n 'x-vault-token',\n ]);\n });\n\n/**\n * Route the exchange over a unix socket when the address is one.\n *\n * ★ BUN's `fetch` TAKES A `unix` OPTION (bun-types globals.d.ts BunFetchRequestInit.unix), AND\n * `FetchHttpClient.RequestInit` IS EFFECT'S DOCUMENTED WAY TO PASS FETCH OPTIONS. The fetch client\n * spreads that service into every call (effect FetchHttpClient.ts:59-72), reading it from the\n * CALLING fiber's context — and `layerMergedContext` merges the caller's context over the layer's\n * (HttpClient.ts:2065-2076), so providing it around one call routes that call alone. Any defaults\n * already provided are kept.\n * ⛔ IT ONLY WORKS ON BUN, SO ANYWHERE ELSE IT REFUSES. Node's fetch ignores `unix` and would send\n * the request to http://localhost:80 — a silent wrong server, which is the one outcome this\n * package exists to prevent. It also assumes the provided `HttpClient` is the fetch one.\n */\nexport const overSocket =\n (socket: string | undefined, method: string, path: string) =>\n <A, E, R>(effect: Effect.Effect<A, E, R>): Effect.Effect<A, E | BaoError, R> => {\n if (socket === undefined) return effect;\n if (typeof Bun === 'undefined') {\n return Effect.fail(\n new BaoError(0, method, path, ['a unix:// address needs Bun fetch; this is not Bun']),\n );\n }\n return Effect.flatMap(Effect.serviceOption(FetchHttpClient.RequestInit), (defaults) => {\n const init: BunFetchRequestInit = { ...Option.getOrElse(defaults, () => ({})), unix: socket };\n return Effect.provideService(effect, FetchHttpClient.RequestInit, init);\n });\n };\n\n/** One exchange, classified. The body is the parsed JSON object, or undefined for absent / 204. */\nexport const baoCall = (\n intent: BaoIntent,\n method: 'DELETE' | 'GET' | 'POST' | 'PUT',\n path: string,\n body?: Readonly<Record<string, unknown>>,\n) =>\n Effect.gen(function* () {\n const env = yield* BaoEnv;\n const address = resolveAddress(env);\n const client = yield* HttpClient.HttpClient;\n // ⚠️ The content type goes on `bodyText`, never in the header map: `bodyText` overwrites it.\n // <estate>/proxmox/src/client.ts has the scar.\n const request = HttpClientRequest.make(method)(`${address.base}/v1/${path}`).pipe(\n HttpClientRequest.setHeaders(headersFor(address, env)),\n body === undefined\n ? (self) => self\n : HttpClientRequest.bodyText(JSON.stringify(body), 'application/json'),\n );\n // ★ Status first, body read exactly once, as text — an error body is not reliably JSON.\n const exchange = client.execute(request).pipe(\n Effect.flatMap((response) =>\n Effect.map(response.text, (text) => ({ status: response.status, text })),\n ),\n Effect.timeout(BAO_TIMEOUT),\n // ⛔ `.message` ONLY: the HttpClientError message is the reason, method and URL. The error\n // object itself holds the request, whose headers hold the token.\n Effect.mapError((cause) => new BaoError(0, method, path, [cause.message])),\n );\n // ★ THE PERMIT WRAPS THE TIMEOUT, NOT THE REVERSE: a call queued behind the gate is not yet\n // talking to OpenBao, so its wait must not count against the 60 seconds.\n const gate = yield* BaoGate;\n const { status, text } = yield* retryTransport(\n exchange.pipe(\n overSocket(address.socket, method, path),\n redactingToken,\n Semaphore.withPermits(gate, 1),\n ),\n );\n const outcome = settle(intent, method, path, status, text);\n return 'error' in outcome ? yield* Effect.fail(outcome.error) : outcome.body;\n });\n\n/**\n * The `data` of a read, or undefined when OpenBao says the object is ABSENT (404).\n *\n * ★ `bao read -format=json` printed this same response body; the old helper took `data` when it was\n * an object and the whole body otherwise, and so does this.\n */\nexport const baoRead = (path: string) =>\n Effect.map(baoCall('read', 'GET', path), (body) => {\n if (body === undefined) return undefined;\n const data = body['data'];\n return typeof data === 'object' && data !== null\n ? (data as Record<string, unknown>)\n : (body as Record<string, unknown>);\n });\n\n/**\n * A write whose SUCCESS MATTERS. Any non-2xx fails, 404 included.\n *\n * ★ `PUT` IS WHAT `bao write` SENT (openbao v2.6.2 api/logical.go Write); `sys/mounts` enable and\n * tune are `POST` in the same client (api/sys_mounts.go:57, :201).\n * ⚠️ ROLE BODIES STAY ALL-STRING ON PURPOSE. `bao write k=v` put every value in the JSON body as a\n * string — MEASURED with `-output-curl-string`, see ssh-role-form.ts — and the form files still\n * build exactly that body, so the server parses the same request it was always sent.\n * ⛔ EXCEPT A MAP FIELD: sdk v2.6.2 refuses a string for a TypeMap with a 400, so Bao.SshRole\n * sends its two maps as objects (the ⛔ on mapValue in ssh-role-form.ts, measured 2026-09-21).\n */\nexport const baoWrite = (\n method: 'POST' | 'PUT',\n path: string,\n body: Readonly<Record<string, unknown>>,\n) => Effect.asVoid(baoCall('write', method, path, body));\n\n/** A delete: idempotent — already gone (404) is success — and refused (403, 5xx) is a failure. */\nexport const baoDelete = (path: string) => Effect.asVoid(baoCall('delete', 'DELETE', path));\n",
|
|
7
7
|
"/**\n * Where an OpenBao call goes and which headers it carries — resolved from the environment the way\n * the `bao` CLI resolves it, so the provider and `bao kv get` can never disagree about which server\n * or namespace this machine is talking to.\n *\n * ★ READ FROM openbao v2.6.2, NOT RECALLED:\n * · api/client.go:34-66 — BAO_ADDR, BAO_AGENT_ADDR, BAO_NAMESPACE, BAO_TOKEN, and the header\n * names `X-Vault-Namespace` and `X-Vault-Token`.\n * · api/client.go:370 — the default address, `https://127.0.0.1:8200`.\n * · api/client.go:503-507, 617-618, 761-762 — BAO_AGENT_ADDR, when set, WINS over BAO_ADDR.\n * · api/env.go:22-34 — every BAO_* falls back to its VAULT_* twin, but a BAO_* that is present\n * and EMPTY still wins over the VAULT_* one.\n * · api/client.go:776-785 — the token and namespace are applied only when non-empty, and every\n * request carries `X-Vault-Request: true`.\n * · api/client.go:1349-1354 — the request path is joined onto the address's own path.\n *\n * ⛔ WHAT THE CLI DOES AND THIS DELIBERATELY DOES NOT: with BAO_TOKEN unset, `bao` falls back to its\n * token helper (a token file in $HOME). This never reads that file. No BAO_TOKEN means AGENT\n * MODE — see `headersFor`.\n * ⚠️ NOT CARRIED OVER: BAO_CACERT / BAO_SKIP_VERIFY / client certificates, SRV lookup, and the CLI's\n * retries on 5xx. An https address needs a certificate the runtime already trusts; a TLS failure\n * fails the call loudly rather than being skipped.\n */\n\nexport type BaoEnvironment = Readonly<Record<string, string | undefined>>;\n\nexport type BaoAddress = {\n /** Scheme, host and any path prefix, no trailing slash. `http://localhost` for a socket. */\n readonly base: string;\n /** The socket path when the address is `unix:///path`, otherwise undefined. */\n readonly socket: string | undefined;\n /** The namespace to send, when there is one. */\n readonly namespace: string | undefined;\n};\n\nexport const DEFAULT_ADDRESS = 'https://127.0.0.1:8200';\n\nconst UNIX = 'unix://';\n\n/** api/env.go ReadBaoVariable: present (even empty) BAO_* wins, else the VAULT_* twin. */\nexport const readBaoVariable = (env: BaoEnvironment, name: `BAO_${string}`): string =>\n env[name] ?? env[`VAULT_${name.slice('BAO_'.length)}`] ?? '';\n\n/**\n * The address and namespace for this environment. Carries no token, so it is safe to log.\n *\n * ★ UNIX SOCKETS, BECAUSE AN AGENT LISTENER CAN BE ONE. OpenBao Agent's `listener \"unix\"` serves\n * the same API on a socket (website/content/docs/agent-and-proxy/agent/index.mdx:382-384), and the\n * agent advertises such a listener as `unix://<path>` (command/agent.go:565-566). The CLI handles\n * that address by dialling the socket and speaking plain HTTP to host `localhost`\n * (api/client.go:654-667); `base` and `socket` are exactly those two halves.\n */\nexport const resolveAddress = (env: BaoEnvironment): BaoAddress => {\n const agent = readBaoVariable(env, 'BAO_AGENT_ADDR');\n const direct = readBaoVariable(env, 'BAO_ADDR');\n const raw = agent !== '' ? agent : direct !== '' ? direct : DEFAULT_ADDRESS;\n const namespace = readBaoVariable(env, 'BAO_NAMESPACE');\n const socket = raw.startsWith(UNIX) ? raw.slice(UNIX.length) : undefined;\n return {\n base: socket === undefined ? raw.replace(/\\/+$/, '') : 'http://localhost',\n namespace: namespace === '' ? undefined : namespace,\n socket,\n };\n};\n\n/**\n * The headers one call sends.\n *\n * ★ AGENT MODE IS \"NO TOKEN HEADER AT ALL\", AND THAT IS THE AGENT'S OWN CONTRACT. Read in openbao\n * v2.6.2 command/agentproxyshared/cache/handler.go:29-38: the proxy handler takes the request's\n * `X-Vault-Token`, and only when it is EMPTY and an auto-auth sink exists does it substitute the\n * agent's own token. command/agent.go:517-541 creates that sink exactly when\n * `api_proxy { use_auto_auth_token = true }` is set; command/agent/config/config.go:288-292 and\n * 635-637 map the older `cache { use_auto_auth_token }` onto the same setting; and\n * command/proxy.go:495-518 wires OpenBao Proxy identically. The docs say the same in words\n * (website/content/docs/agent-and-proxy/agent/apiproxy.mdx:57-62): a request without a token is\n * forwarded with the auto-auth token, a request that bears one keeps its own, and `\"force\"`\n * overwrites it.\n * ⛔ SO AN EMPTY `X-Vault-Token: ` WOULD BE WRONG IN BOTH DIRECTIONS: harmless to the agent,\n * which reads empty as absent, but an explicit unauthenticated request to a server. The header\n * is omitted, never blanked.\n * ★ THE NAMESPACE RIDES THROUGH THE AGENT UNTOUCHED. The proxy clones its client and replaces that\n * client's headers with the incoming request's (cache/api_proxy.go:50-54 and :78), so the\n * `X-Vault-Namespace` sent here is the one OpenBao sees.\n * ⚠️ `X-Vault-Request: true` IS NOT DECORATION. An agent listener with `require_request_header`\n * refuses any request without it (command/agent.go:544-548); the CLI always sends it.\n *\n * ⛔ THE RETURN VALUE HOLDS THE TOKEN. Hand it to the request and nowhere else: never to an error,\n * a log line, an attribute, or a span — bao-http.ts adds the header to the redacted names.\n */\nexport const headersFor = (address: BaoAddress, env: BaoEnvironment): Record<string, string> => {\n const headers: Record<string, string> = { 'X-Vault-Request': 'true' };\n if (address.namespace !== undefined) headers['X-Vault-Namespace'] = address.namespace;\n const token = readBaoVariable(env, 'BAO_TOKEN');\n if (token !== '') headers['X-Vault-Token'] = token;\n return headers;\n};\n",
|
|
8
8
|
"/**\n * How a finished OpenBao HTTP exchange reads: a body, a genuinely absent object, or an error.\n *\n * ★ STATUS CODES, NEVER WORDS. The `bao` CLI this replaced reported every outcome as stderr text,\n * and deciding by that text broke twice: every failure once read as absent (a bad token planned 33\n * updates), and then `bao policy read` turned out to say \"absent\" in different words from\n * `bao read`, so a new policy could not be created (b3c18a33e). The API itself answers 404 for\n * absent, 403 for denied and 503 for sealed — openbao v2.6.2 sdk/logical/response_util.go:\n * RespondErrorCommon (a read that finds nothing is 404; ErrPermissionDenied is 403) and\n * AdjustErrorStatusCode (ErrSealed is 503).\n */\n\nexport type BaoIntent = 'read' | 'write' | 'delete';\n\n/**\n * A failed call, naming the method, the path and OpenBao's own `errors` array.\n *\n * ⛔ IT NEVER CARRIES THE TOKEN, AND IT NEVER CARRIES A RESPONSE BODY IT DID NOT PARSE. It is built\n * from the method, the API path and OpenBao's error strings only — no request, no headers, no\n * `cause` — because an Effect `HttpClientRequest` inspects its headers through a redaction list\n * that does not name `x-vault-token`. A 2xx body can hold a credential, and a foreign error page\n * can echo the request back, so a body that is not OpenBao's is described, never quoted.\n */\nexport class BaoError extends Error {\n constructor(\n readonly status: number,\n readonly method: string,\n readonly path: string,\n readonly errors: readonly string[],\n ) {\n const code = status === 0 ? 'no response' : String(status);\n super(`OpenBao ${method} /v1/${path} -> ${code}: ${errors.join('; ') || '(no errors given)'}`);\n this.name = 'BaoError';\n }\n}\n\nexport type Settled =\n | { readonly body: Record<string, unknown> | undefined }\n | { readonly error: BaoError };\n\nconst objectOf = (text: string): Record<string, unknown> | undefined => {\n try {\n const parsed: unknown = JSON.parse(text);\n return typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)\n ? (parsed as Record<string, unknown>)\n : undefined;\n } catch {\n return undefined;\n }\n};\n\n/**\n * OpenBao's `errors` array, or undefined for a body that is not OpenBao's.\n *\n * ★ EVERY ERROR OPENBAO WRITES IS `{\"errors\": [...]}` WITH A JSON CONTENT TYPE, 404 included —\n * sdk/logical/response_util.go RespondError:180-196 — and every entry is a STRING.\n * ⛔ AN ARRAY WITH ANY NON-STRING ENTRY IS NOT OPENBAO. The first version filtered the non-strings\n * out, which turned a JSON gateway's `{\"errors\":[{\"code\":1000,\"message\":\"Not Found\"}]}` into an\n * empty OpenBao error list — and a 404 carrying it into \"absent\" on a read and \"done\" on a delete,\n * the plan-CREATE-over-something-that-exists failure arriving through a wrong BAO_ADDR. Found by\n * grok's review on 2026-09-14. An EMPTY array is still OpenBao's: a plain 404 carries exactly that.\n */\nconst errorsOf = (text: string): readonly string[] | undefined => {\n const raw = objectOf(text)?.['errors'];\n return Array.isArray(raw) && raw.every((entry) => typeof entry === 'string')\n ? (raw as string[])\n : undefined;\n};\n\n/**\n * Classify one exchange.\n *\n * ★ PURE AND EXPORTED SO THE ONE DECISION EVERY READ AND DELETE HERE RESTS ON CAN BE TESTED WITHOUT\n * A VAULT. It has been wrong in both directions already — every failure once read as absent, and\n * one command's absence wording was assumed for another's — see bao-status.test.ts.\n *\n * ⛔ 404 IS ABSENCE ONLY ON A READ, AND ONLY WHEN OPENBAO SAID IT. MEASURED 2026-09-13 with the CLI,\n * and the discriminator is real but NARROW: a genuinely absent object, read by a token that IS\n * allowed to read that path, is a 404. ⛔ AND THE SAME READ UNDER A NARROWER TOKEN IS A DENIAL:\n * under the agent lane the identical read answered `Code: 403 … permission denied`, because the\n * policy grants named paths and an unnamed one is refused rather than reported missing. So\n * \"absent\" is only knowable to a caller that could have read it — which is exactly why 403 is an\n * ERROR rather than a shrug. A resource that cannot tell absence from denial plans CREATE for\n * something that exists, which is the failure this estate has now found four separate times.\n * ⚠️ A 404 WHOSE BODY IS NOT `{\"errors\": […strings]}` IS NOT OPENBAO. A BAO_ADDR pointing at the\n * wrong server — a reverse proxy's HTML 404, a gateway's JSON one — must not read as \"nothing\".\n *\n * 🔴 THE SHELL HELPER USED TO RETURN `''` FOR EVERY NON-ZERO EXIT, AND THAT IS A LIE WITH\n * CONSEQUENCES. An expired BAO_TOKEN, a sealed server or a missing grant all came back as \"the\n * mount is not there\", so `diff` answered `update`, `reconcile` ran `secrets enable`, and the plan\n * reported a CREATE on infrastructure that exists. The failure the operator sees is about the\n * wrong thing entirely, at the worst possible moment — a sealed vault. ⚠️ SO 403, 5xx AND ANYTHING\n * ELSE THAT IS NOT 2xx FAILS. The cost is that a genuinely-absent read under a too-narrow token\n * becomes an error instead of a create, and that is the right way round: \"I could not tell\" is a\n * true statement, and \"it is not there\" was not.\n *\n * 🔴 THE DELETES ALL USED THE READ HELPER, WHICH DISCARDED THE EXIT CODE. A refused\n * `secrets disable` was reported as a successful delete: the resource left Alchemy's state while\n * the mount stayed live, so the next plan showed nothing and the object was orphaned in silence.\n * ⚠️ ABSENCE IS STILL NOT AN ERROR FOR A DELETE, because a delete must be idempotent: Alchemy\n * retries, and the second attempt legitimately finds nothing. So a delete's 404 is success and\n * its 403 is not.\n * ★ DISABLING A MOUNT THAT IS ALREADY GONE IS NOT EVEN A 404. A review on 2026-09-14 said it failed\n * with `no matching mount` and would wedge a retried delete. The server says otherwise: it answers\n * success for a missing mount so as not to reveal whether one existed — openbao v2.6.2\n * vault/logical_system.go:1211-1216 — and the CLI printed \"Disabled the secrets engine (if it\n * existed)\" (command/secrets_disable.go:87).\n */\nexport const settle = (\n intent: BaoIntent,\n method: string,\n path: string,\n status: number,\n text: string,\n): Settled => {\n const fail = (errors: readonly string[]) => ({\n error: new BaoError(status, method, path, errors),\n });\n if (status < 200 || status >= 300) {\n const errors = errorsOf(text);\n if (errors === undefined) {\n // ⛔ DESCRIBED, NEVER QUOTED. A proxy or gateway error page can echo the request back, headers\n // and all, so quoting it could carry X-Vault-Token into an error that Alchemy logs (grok,\n // 2026-09-14). mint in <estate>/proxmox/src/credentials.ts already did it this way.\n return fail([`not an OpenBao error body (${String(text.length)} bytes)`]);\n }\n if (status === 404 && intent !== 'write') return { body: undefined };\n return fail(errors);\n }\n // ★ A write or delete answering 204 has nothing to say. A READ with no body has told us nothing,\n // and OpenBao never does that — a read that finds nothing is a 404 (RespondErrorCommon).\n if (text.trim() === '') {\n return intent === 'read' ? fail(['a successful read with an empty body']) : { body: undefined };\n }\n const body = objectOf(text);\n return body === undefined ? fail(['a success body that is not a JSON object']) : { body };\n};\n",
|
|
9
9
|
"/**\n * Trimming runs of one character from caller-supplied paths and names.\n *\n * ★ LOOPS, NOT `/^\\/+|\\/+$/g`, `/\\/+$/` OR `/^-+|-+$/g`. A trailing `x+$` backtracks polynomially\n * on a long run of `x` followed by anything else (CodeQL js/polynomial-redos), and mount paths,\n * namespaces and slugs are caller input. Every loop here is linear in the input length.\n */\n\n/** `text` without a trailing run of `char` (one UTF-16 unit). */\nexport const trimTrailing = (text: string, char: string): string => {\n let end = text.length;\n while (end > 0 && text[end - 1] === char) end -= 1;\n return text.slice(0, end);\n};\n\n/** `text` without a leading or trailing run of `char` (one UTF-16 unit). */\nexport const trimRuns = (text: string, char: string): string => {\n let start = 0;\n while (start < text.length && text[start] === char) start += 1;\n return trimTrailing(text.slice(start), char);\n};\n\n/** `text` without trailing `/`. */\nexport const trimTrailingSlashes = (text: string): string => trimTrailing(text, '/');\n\n/** `text` without leading or trailing `/`. */\nexport const trimSlashes = (text: string): string => trimRuns(text, '/');\n\n/** SSH mount path without a trailing slash; `ssh` when the caller did not say. */\nexport const sshMountOf = (mount: string | undefined): string =>\n trimTrailingSlashes(mount ?? 'ssh');\n",
|
|
10
10
|
"/**\n * The pure half of an AppRole login's INPUT and FAILURE: what counts as a usable input, and how a\n * failure is described without the credential in it. Split from approle-login.ts so each decision\n * is testable without a server; what a success hands back is approle-login-result.ts.\n *\n * ★ READ FROM openbao v2.6.2, NOT RECALLED:\n * · docs/api/auth/approle.mdx \"Login with AppRole\" — `role_id` and `secret_id` in, an `auth` block\n * out.\n * · api/auth/approle/approle.go:145-146 — the official Go helper writes `auth/<mount>/login`, and\n * the mount is `approle` unless the caller says otherwise. (api/*.go cited here diffed identical\n * between v2.6.0 and v2.6.2.)\n */\nimport { trimSlashes } from './mount-path.ts';\n\n/** Why a login or a revoke failed. */\nexport type BaoLoginFailure =\n /** Refused before any request was sent: an empty or padded value, or a mount that is not a path. */\n | 'input'\n /** OpenBao (or something at BAO_ADDR) answered with a non-2xx status. */\n | 'refused'\n /** No answer at all — transport, timeout, or an address nothing listens on. */\n | 'unreachable'\n /** A 2xx that is not a usable answer: not JSON, no auth block, or MFA still required. */\n | 'response';\n\n/**\n * The failure a transport-level BaoError stands for.\n *\n * ⚠️ A 2xx CAN FAIL TOO, AND IT IS NOT A REFUSAL. bao-status.ts settle fails a success whose body is\n * not a JSON object — the shape of a BAO_ADDR that points at some other web server. The first\n * version mapped every non-zero status to `refused`, so that read as `refused 200`: a server that\n * said yes, reported as one that said no.\n */\nexport const failureOf = (status: number): BaoLoginFailure =>\n status === 0 ? 'unreachable' : status >= 200 && status < 300 ? 'response' : 'refused';\n\n/**\n * A failed login or revoke.\n *\n * ⛔ IT NEVER CARRIES A CREDENTIAL. It is built from the operation name, a status and a list of\n * strings that have been through `redact` — never from the request, a header, or a `cause`, for\n * the reason bao-status.ts gives for BaoError.\n */\nexport class BaoLoginError extends Error {\n constructor(\n readonly reason: BaoLoginFailure,\n /** The HTTP status, or 0 when none applies (input, unreachable, an unusable auth block). */\n readonly status: number,\n readonly errors: readonly string[],\n operation: string,\n ) {\n const code = status === 0 ? reason : `${reason} ${String(status)}`;\n super(`${operation}: ${code}: ${errors.join('; ') || '(no errors given)'}`);\n this.name = 'BaoLoginError';\n }\n}\n\n/**\n * Why a value cannot be sent, or undefined when it can.\n *\n * ⚠️ PADDING IS REFUSED, NOT TRIMMED. `await Bun.file(path).text()` keeps a secret_id file's trailing\n * newline, and OpenBao answers that with \"invalid role or secret ID\" — the same words it uses for\n * a revoked or expired credential, so the real cause is invisible from the error. Trimming quietly\n * would send a different value from the one the caller holds; refusing names the problem.\n * ⚠️ `unknown`, NOT `string`: a plain script passes `process.env.X`, which is `undefined` when unset.\n */\nexport const refusal = (label: string, value: unknown): string | undefined => {\n if (typeof value !== 'string' || value === '') return `${label} is empty`;\n if (value.trim() === '') return `${label} is only whitespace`;\n if (value.trim() !== value) {\n return `${label} has leading or trailing whitespace (a file read keeps its newline; trim it)`;\n }\n return undefined;\n};\n\n/** The auth mount without slashes; `approle` when the caller did not say. */\nexport const loginMount = (mount: string | undefined): string => trimSlashes(mount ?? 'approle');\n\n/**\n * Why `mount` cannot name an auth mount, or undefined when it can.\n *\n * ⛔ THE MOUNT IS SPLICED INTO A URL, AND THE URL PARSER RESOLVES `..` AND ENDS THE PATH AT `?` OR\n * `#`. `new URL('…/v1/auth/../sys/x/login')` is `…/v1/sys/x/login` — the role_id and secret_id\n * would be sent to a path the caller never named. Refused rather than escaped, like padding.\n */\nexport const mountProblem = (mount: string | undefined): string | undefined => {\n const path = loginMount(mount);\n if (path === '') return 'mount is empty';\n const segments = path.split('/');\n if (\n /[\\s?#%\\\\]/.test(path) ||\n segments.some((part) => part === '' || part === '.' || part === '..')\n ) {\n return `mount ${JSON.stringify(path)} is not a plain mount path`;\n }\n return undefined;\n};\n\n/** `auth/<mount>/login` — what api/auth/approle/approle.go:145 writes. */\nexport const loginPath = (mount: string | undefined): string => `auth/${loginMount(mount)}/login`;\n\n/** strconv.Quote's single-letter escapes, by code point. */\nconst GO_ESCAPES: Readonly<Record<number, string>> = {\n 7: 'a',\n 8: 'b',\n 9: 't',\n 10: 'n',\n 11: 'v',\n 12: 'f',\n 13: 'r',\n};\n\n/**\n * `value` as it appears between the quotes of Go's `%q` (strconv.Quote) — ASCII escapes only.\n * ⚠️ Non-ASCII passes through as-is, which is what strconv.Quote does for PRINTABLE runes; a\n * non-printable non-ASCII rune in a secret would escape differently and is not covered.\n */\nconst goQuoted = (value: string): string =>\n [...value]\n .map((char) => {\n const code = char.codePointAt(0) ?? 0;\n const named = GO_ESCAPES[code];\n if (char === '\"' || char === '\\\\') return `\\\\${char}`;\n if (named !== undefined) return `\\\\${named}`;\n if (code < 0x20 || code === 0x7f) return `\\\\x${code.toString(16).padStart(2, '0')}`;\n return char;\n })\n .join('');\n\n/**\n * Every string in `errors` with each credential replaced by `[redacted]`.\n *\n * ⛔ OPENBAO CAN ECHO THE SECRET_ID BACK, SO THIS IS NOT DEFENCE IN DEPTH — IT IS THE DEFENCE.\n * openbao v2.6.2 builtin/credential/approle/path_login.go:291 answers a limited-use secret_id\n * whose storage entry vanished between two reads with `invalid secret_id \"<the secret_id>\"`.\n * BaoError keeps OpenBao's `errors` verbatim (that is its job), so every string that leaves the\n * login or revoke passes through here first.\n * ⚠️ THAT ECHO IS `%q`, SO THE RAW VALUE IS NOT ENOUGH. A custom secret_id holding `\"` or `\\` comes\n * back escaped (`\\\"`, `\\\\`) and would slip past a raw match; the Go-quoted form is redacted too.\n * ⚠️ LONGEST FIRST. Were one value a substring of another, redacting the shorter first would break\n * the longer one's match and leave the rest of it in the message.\n */\nexport const redact = (\n errors: readonly string[],\n secrets: readonly string[],\n): readonly string[] => {\n const forms = [...new Set(secrets.flatMap((secret) => [secret, goQuoted(secret)]))]\n .filter((form) => form !== '')\n .sort((a, b) => b.length - a.length);\n return errors.map((entry) =>\n forms.reduce((text, form) => text.split(form).join('[redacted]'), entry),\n );\n};\n",
|
|
11
11
|
"/**\n * What a successful AppRole login hands back, and how it is read out of a 2xx body. Split from\n * approle-login-form.ts, which decides what goes IN; this decides what comes OUT and how the token\n * stays out of every log line that prints the result.\n *\n * ★ READ FROM openbao v2.6.2 api/secret.go:304-318 SecretAuth — `client_token`, `accessor`,\n * `policies`, `lease_duration` and `mfa_requirement`. (api/*.go cited here diffed identical\n * between v2.6.0 and v2.6.2.)\n */\n\n/** What a successful login hands back. */\nexport interface AppRoleLogin {\n /**\n * The token. ⛔ A GETTER OVER A PRIVATE FIELD, NEVER AN OWN PROPERTY — see LoginResult below.\n * `console.log(login)` prints `clientToken: [Getter]` at most, and `JSON.stringify(login)`,\n * `{ ...login }` and `structuredClone(login)` carry no token at all. Read it by name.\n */\n readonly clientToken: string;\n /** The token's accessor — safe to log, and what revoke-accessor and audit lines name. */\n readonly accessor: string;\n /** Every policy on the token: the role's token_policies plus identity policies. */\n readonly policies: readonly string[];\n /** The token TTL in seconds, from the role's `token_ttl`. */\n readonly leaseDurationSeconds: number;\n}\n\n/**\n * ⛔ A PRIVATE FIELD BEHIND A PROTOTYPE GETTER, BECAUSE A NON-ENUMERABLE PROPERTY DID NOT HIDE THE\n * TOKEN UNDER BUN. MEASURED 2026-09-21 on bun 1.4.0: `console.log` of an object whose token was a\n * non-enumerable OWN property printed `clientToken: \"<the token>\"` in full — node's util.inspect\n * hid it, bun's formatter did not — and this helper exists for Bun scripts. The first version\n * shipped exactly that shape, with a test that checked JSON and Object.keys but never a print.\n * This shape prints `clientToken: [Getter]` under bun's console.log and Bun.inspect, and nothing\n * at all under node's default inspect.\n * ⚠️ `util.inspect(login, { getters: true })` DOES evaluate the getter. That is an explicit request\n * for the value, not an accident of logging the result.\n */\nclass LoginResult implements AppRoleLogin {\n readonly #token: string;\n readonly accessor: string;\n readonly policies: readonly string[];\n readonly leaseDurationSeconds: number;\n\n constructor(token: string, accessor: string, policies: readonly string[], lease: number) {\n this.#token = token;\n this.accessor = accessor;\n this.policies = Object.freeze([...policies]);\n this.leaseDurationSeconds = lease;\n Object.freeze(this);\n }\n\n get clientToken(): string {\n return this.#token;\n }\n}\n\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\n/**\n * The login in a 2xx body, or the reason there is none.\n *\n * ⚠️ AN EMPTY `client_token` WITH A `mfa_requirement` IS AN UNFINISHED LOGIN, NOT A BROKEN ONE. The\n * auth block carries that field for a login that still owes an MFA step (api/secret.go:317). A\n * script cannot complete that step, so it is named rather than reported as a missing field.\n * REASONED FROM THE CLIENT TYPE — no MFA-enforced login was run.\n * ⛔ THE BODY IS NEVER QUOTED. It holds the token on success and is not OpenBao's on a wrong address.\n */\nexport const loginOf = (\n body: Record<string, unknown> | undefined,\n): { readonly login: AppRoleLogin } | { readonly problem: string } => {\n const auth = body?.['auth'];\n if (typeof auth !== 'object' || auth === null || Array.isArray(auth)) {\n return { problem: 'the answer carried no auth block' };\n }\n const fields = auth as Record<string, unknown>;\n const token = fields['client_token'];\n if (typeof token !== 'string' || token === '') {\n const mfa = fields['mfa_requirement'];\n return {\n problem:\n mfa !== undefined && mfa !== null\n ? 'the login requires MFA, which this helper does not complete'\n : 'the auth block carried no client_token',\n };\n }\n const lease = fields['lease_duration'];\n return {\n login: new LoginResult(\n token,\n typeof fields['accessor'] === 'string' ? fields['accessor'] : '',\n strings(fields['policies']),\n typeof lease === 'number' && Number.isFinite(lease) ? lease : 0,\n ),\n };\n};\n",
|
|
12
|
-
"/**\n * An OpenBao auth method — path, type, description and lease TTLs.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. This enables `approle` (or jwt/oidc)\n * as a mount. Role ids, OIDC client secrets, and secret_ids are out of scope.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — disabling a method destroys every role under it\n * and revokes tokens minted through those roles. Opt in with\n * `.pipe(RemovalPolicy.destroy())`.\n *\n * ★ REPLACE SEMANTICS (audited 2026-09-21, see REPLACE.md): `type` changed → plans `replace`, whose\n * create half dies on the still-occupied path before any write, so the apply fails and nothing is\n * disabled (auth-method-reconcile.ts); `path` changed → FAILS unless `remountFrom` names the old\n * path (then an in-place move). It used to plan `update` and enable an empty method at the new\n * path, exactly as Bao.Mount did.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
12
|
+
"/**\n * An OpenBao auth method — path, type, description and lease TTLs.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. This enables `approle` (or jwt/oidc)\n * as a mount. Role ids, OIDC client secrets, and secret_ids are out of scope.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — disabling a method destroys every role under it\n * and revokes tokens minted through those roles. Opt in with\n * `.pipe(RemovalPolicy.destroy())`.\n *\n * ★ REPLACE SEMANTICS (audited 2026-09-21, see REPLACE.md): `type` changed → plans `replace`, whose\n * create half dies on the still-occupied path before any write, so the apply fails and nothing is\n * disabled (auth-method-reconcile.ts); `path` changed → FAILS unless `remountFrom` names the old\n * path (then an in-place move). It used to plan `update` and enable an empty method at the new\n * path, exactly as Bao.Mount did.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport {\n type BaoAuthMethodAttributes,\n type BaoAuthMethodProps,\n matches,\n} from './auth-method-form.ts';\nimport { readMethod, reconcileAuthMethod } from './auth-method-reconcile.ts';\nimport { disableAuthMethod } from './auth-method-wire.ts';\nimport { planMove } from './mount-move.ts';\n\nexport type { BaoAuthMethodAttributes, BaoAuthMethodProps };\n\nexport interface BaoAuthMethod extends Resource<\n 'Bao.AuthMethod',\n BaoAuthMethodProps,\n BaoAuthMethodAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoAuthMethod = Resource<BaoAuthMethod>('Bao.AuthMethod', {\n defaultRemovalPolicy: 'retain',\n});\n\nexport const BaoAuthMethodProvider = () =>\n Provider.effect(\n BaoAuthMethod,\n Effect.succeed(\n BaoAuthMethod.Provider.of({\n /**\n * ⛔ `bao auth list` IS NOT A LIST OF THINGS THIS OWNS. `token/` is always\n * present. Returning it would invite Alchemy to adopt — and then disable —\n * methods it never created.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readMethod(olds);\n const ours = Effect.sync(() => found !== undefined && matches(found, olds));\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n diff: Effect.fn(function* ({ news, output }) {\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (!isResolved(news)) return undefined;\n /**\n * ⛔ A CHANGED PATH FAILS HERE unless `remountFrom` names the old one — the same trap\n * Bao.Mount had: reading the new path finds nothing, plans `update`, and enables an\n * EMPTY method beside the retained one, with every role left behind (mount-move.ts).\n */\n const move = planMove('Bao.AuthMethod', output.path, news.path, news.remountFrom);\n if (move.kind === 'refuse') return yield* Effect.die(new Error(move.message));\n if (move.kind === 'move') return { action: 'update' } as const;\n const live = yield* readMethod(news);\n if (live === undefined) return { action: 'update' } as const;\n /**\n * ⛔ A CHANGED `type` IS A REPLACE. Delete is an auth disable — every role\n * under the method dies. `retain` guards both orphan-delete and replace\n * (same Alchemy Apply.ts path Bao.Mount documents).\n */\n if (live.type !== news.type) return { action: 'replace' } as const;\n if (matches(live, news)) return { action: 'noop' } as const;\n return { action: 'update' } as const;\n }),\n\n /** The body, and the move, live in auth-method-reconcile.ts. */\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const claim = claimFor({ fqn, instanceId, output });\n return yield* reconcileAuthMethod(news, output?.path, undefined, claim);\n }),\n\n /**\n * ⛔ DISABLING A METHOD DESTROYS EVERY ROLE UNDER IT. Idempotent as Alchemy\n * requires — already gone is success — but retain is the default for a reason.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* disableAuthMethod(output.path);\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
13
13
|
"/**\n * Whether a live object this stack holds no state for may be written — the apply-time half of the\n * house rule that NOTHING IS ADOPTED WITHOUT `--adopt` (decided 2026-09-21 for HostFile, LaunchdJob,\n * CaddyConfig and every Bao.* family). probe.ts is the plan-time half.\n *\n * ★ FAMILY-NEUTRAL ON PURPOSE. The engine questions here — what `--adopt` resolves to for one FQN,\n * whether this apply resumes the resource's own interrupted create — are the same for a vault\n * role, a launchd plist and a Caddy config, so they live once, outside every subpath's directory.\n */\nimport { AdoptPolicy } from 'alchemy/AdoptPolicy';\nimport { AlchemyContext } from 'alchemy/AlchemyContext';\nimport { Stack } from 'alchemy/Stack';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport { resumes, unfinished } from './resume.ts';\nimport { forgetRefusedCreate, isCreate } from './rows.ts';\n\n/**\n * Whether the resource at `fqn` may be adopted, resolved exactly as the planner resolves it (alchemy\n * beta.79 Plan.ts: `resource.Adopt ?? shouldAdopt`): a resource-scoped `adopt(…)`, else the\n * `AdoptPolicy` service, else `AlchemyContext.adopt`, else off.\n * ★ FOR A CREATE THE ENGINE NEVER PROBED. Alchemy skips the adoption probe while `news` holds an\n * Output, so an ownership check that must still honour `--adopt` can only run at apply. All three\n * reach the apply: Alchemist runs plan AND apply under the session context, which provides the\n * services from the CLI flag and the Stack the resources registered on (Alchemist/Session.ts,\n * routes/stack.ts; Apply.ts reads the same Stack).\n * ⛔ THE RESOURCE-SCOPED SETTING WINS, BOTH WAYS. The engine captures `adopt(…)` on the resource at\n * registration (Resource.ts `Adopt`, into `Stack.resources[fqn]`) and never hands it to a\n * provider. Reading only the deploy-wide flag let `--adopt` take over a resource declared\n * `.pipe(adopt(false))` — which the planner refuses — and refused one declared `adopt(true)`.\n * ⚠️ `resources` carries an `@internal` comment in Alchemy's source, but it is in the published types\n * and the planner reads `Adopt` from it. caddy/adopt-scope.test.ts registers through the real\n * `Resource`, so an upgrade that stops recording it there fails the suite.\n */\nexport const adoptEnabled = (fqn: string): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n const stack = yield* Effect.serviceOption(Stack);\n const scoped = Option.isSome(stack) ? stack.value.resources[fqn]?.Adopt : undefined;\n if (scoped !== undefined) return scoped;\n const policy = yield* Effect.serviceOption(AdoptPolicy);\n if (Option.isSome(policy)) return policy.value;\n const context = yield* Effect.serviceOption(AlchemyContext);\n return Option.isSome(context) ? context.value.adopt : false;\n });\n\n/** The three fields of a `reconcile` (or `read`) call that say whose object this is. */\nexport type Owner = {\n readonly fqn: string;\n readonly instanceId: string;\n /** The attributes state holds; `undefined` on a create. */\n readonly output: unknown;\n};\n\n/**\n * Whether `--adopt` may speak for this apply's generation: a CREATE (rows.ts isCreate), or an\n * UNFINISHED generation whose row this plan's diff saw with no attributes (resume.ts) — the\n * resume Alchemy itself offers `--adopt` for (\"Cannot resume creating … Re-run with --adopt\").\n * ⛔ NOT A FRESH REPLACE'S NEW GENERATION. The planner never probes it and never offers it adoption,\n * so the identity it moves to was never asked about under `--adopt`: 🔴 MEASURED 2026-09-21\n * (launchd/adopt-apply.test.ts), a HostFile whose path changed onto a file it did not own\n * overwrote that file under a deploy-wide `--adopt` meant for something else. A Bao rename onto a\n * taken identity already fails the plan, `--adopt` or not (rename.ts judgeMove); this keeps the\n * apply to the same answer.\n */\nconst adoptable = (owner: Owner): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n if (yield* isCreate(owner.fqn, owner.instanceId)) return true;\n return yield* unfinished(owner.instanceId);\n });\n\n/** Whether a stateless `reconcile` may take over a live object: adoption on, for an adoptable one. */\nexport const adoptsAtApply = (owner: Owner): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n if (!(yield* adoptEnabled(owner.fqn))) return false;\n return yield* adoptable(owner);\n });\n\n/** A lifecycle helper's hook for refuseTakeover, bound to one call's Owner: `(what) => …`. */\nexport type Claim = (what: string) => Effect.Effect<void>;\n\n/**\n * `reconcile`'s check, called with the live object it found BEFORE any write: dies unless that\n * object may be written. It may when state already vouches for it (`output`), when this apply\n * resumes the resource's own interrupted create or replace and its diff proved the object that\n * generation's (resume.ts), or when adoption is on for a create or an unfinished generation\n * (adoptable).\n * ⛔ WHY IT EXISTS AT ALL: THE PROBE DOES NOT GUARD EVERY CREATE. Alchemy skips it while `news` holds\n * an Output (Plan.ts), a new generation of a replace is never probed, and an object can appear\n * between plan and apply. Each of those used to be a silent takeover: written over, then recorded\n * as ours, and deleted with the stack under `destroy`.\n * ⚠️ A CHECK, THEN A WRITE — NOT A LOCK. Two creates of one name in the same deploy run\n * concurrently, both read nothing, and both write (measured with the fakes, 2026-09-21). Nothing\n * between a read and a write can close that; declare each name once.\n * ⚠️ AN IDENTICAL OBJECT IS STILL A TAKEOVER (decided 2026-09-21). Nothing would be written, but the\n * state row would claim it, and a later delete would remove what another owner still relies on.\n * ⛔ A REFUSED CREATE FORGETS ITS `creating` ROW (rows.ts forgetRefusedCreate), or the next plan's\n * recovery read would adopt the very object this refused.\n */\nexport const refuseTakeover = (owner: Owner, what: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n if (owner.output !== undefined) return;\n if (yield* resumes(owner.instanceId)) return;\n const may = yield* adoptable(owner);\n if (may && (yield* adoptEnabled(owner.fqn))) return;\n yield* forgetRefusedCreate(owner.fqn, owner.instanceId);\n const remedy = may\n ? 'Deploy with --adopt (or wrap the resource in adopt(true)) to take it over, or remove it first.'\n : 'It is the new identity of a replace, which --adopt does not cover: remove it first.';\n return yield* Effect.die(\n new Error(\n `${what}: already exists, and this stack holds no state for it — the plan could not ask ` +\n 'first (a prop was still an Output, a replace moved onto it, or it appeared after the ' +\n `plan). Nothing was written. ${remedy}`,\n ),\n );\n });\n\n/** refuseTakeover bound to one call's Owner, for a lifecycle helper that finds the live object. */\nexport const claimFor =\n (owner: Owner): Claim =>\n (what) =>\n refuseTakeover(owner, what);\n",
|
|
14
14
|
"/**\n * Whether this apply RESUMES a create or replace the engine already started for this resource AND\n * the live object it will find is proven that generation's own — the one case in which a stateless\n * `reconcile` may write over a live object without `--adopt`.\n *\n * ★ HOW THE ENGINE TELLS US. Alchemy calls `diff` whenever a state row exists, and hands it `output`\n * = that row's attributes (alchemy beta.79 Plan.ts). A row with NO attributes is exactly an\n * unfinished generation: `creating` (a create interrupted after its write, before its commit),\n * `replacing` (the same for a replace), or `deleting` re-driven as a create. A fresh create is\n * never diffed at all. So the diff of such a row decides, and the apply that follows (the same\n * instance id: Apply.ts reuses the row's) finds the note.\n * ⛔ A ROW PROVES NOTHING BY ITSELF (red team, 2026-09-21). Apply commits it BEFORE reconcile runs, so\n * a deploy killed before the claim — an upstream that failed, a Ctrl-C — leaves a row whose create\n * never asked whose object sat at its identity. 🔴 MEASURED (openbao/adopt-holes.test.ts): with the\n * name an Output, the next deploy \"resumed\" that create and wrote over another owner's role, in\n * every family that had a note on the row alone. So the note is left only when the family's own\n * `read`, asked as the recovery read (probe.ts ownedRead: a recorded instance, a row carrying the\n * whole declaration, and a live object that matches it), answers \"ours\". For a `creating` row\n * that is the question Plan.ts already asked; for a `replacing` row it is the only time it is asked.\n * ⚠️ WHY NOT THE STATE STORE ALONE. At reconcile both look the same: Apply commits the fresh create's\n * `creating` row before calling reconcile, so a row with this instance id is always there.\n * ★ THE CHANNEL IS ALCHEMY'S OWN: `Artifacts`, the per-FQN bag the engine shares between one plan\n * and its apply (Artifacts.ts: \"diff computes … create / update reads the same artifact\").\n * Deploy.ts and the Alchemist session both hold one store across the pair.\n * ⚠️ IT FAILS CLOSED. No bag, a bag the plan never wrote, or an object the read cannot prove ours\n * reads as a fresh create, and adopt.ts then asks for `--adopt` — the safe direction.\n * ★ AN UNPROVEN RESUME IS STILL MARKED UNFINISHED (`noteUnfinished`), so `--adopt` can take it over\n * the way Alchemy's own \"Cannot resume creating … Re-run with --adopt\" offers for a create — while\n * a FRESH replace's new generation, which no diff ever saw without attributes, stays unadoptable.\n */\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport { Artifacts } from 'alchemy/Artifacts';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nconst PROVEN = 'homeflare/ownership/resumes';\nconst UNFINISHED = 'homeflare/ownership/unfinished';\n\nconst note = (key: string, instanceId: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n const bag = yield* Effect.serviceOption(Artifacts);\n if (Option.isSome(bag)) yield* bag.value.set(key, instanceId);\n });\n\nconst noted = (key: string, instanceId: string): Effect.Effect<boolean> =>\n Effect.gen(function* () {\n const bag = yield* Effect.serviceOption(Artifacts);\n if (Option.isNone(bag)) return false;\n return (yield* bag.value.get<string>(key)) === instanceId;\n });\n\n/**\n * `diff`'s note for a row with no attributes: `instanceId` is an unfinished generation of this\n * resource's own, which `--adopt` may resume when nothing proves it (adopt.ts adoptable). Returns\n * `undefined`, a diff's \"defer to the engine\".\n */\nexport const noteUnfinished = (instanceId: string): Effect.Effect<undefined> =>\n Effect.as(note(UNFINISHED, instanceId), undefined);\n\n/**\n * Note `instanceId` unfinished, and a proven resume when `recovered` — the family's `read` of the\n * row's props, asked with no attributes — answers a plain object: ours. `Unowned`, nothing, or a\n * read that fails or dies proves nothing. ⚠️ Never fails the plan: an unproven resume is refused\n * at apply instead, unless `--adopt`.\n */\nexport const noteResume = <R>(\n instanceId: string,\n recovered: Effect.Effect<unknown, unknown, R>,\n): Effect.Effect<void, never, R> =>\n Effect.gen(function* () {\n yield* noteUnfinished(instanceId);\n const unproven = () => Effect.succeed(undefined);\n const found = yield* recovered.pipe(Effect.catch(unproven), Effect.catchDefect(unproven));\n if (found === undefined || found === null || Unowned.is(found)) return;\n yield* note(PROVEN, instanceId);\n });\n\n/** Whether the plan for this apply noted `instanceId` as a proven resumed create or replace. */\nexport const resumes = (instanceId: string): Effect.Effect<boolean> => noted(PROVEN, instanceId);\n\n/** Whether the plan for this apply saw `instanceId` as an unfinished generation (proven or not). */\nexport const unfinished = (instanceId: string): Effect.Effect<boolean> =>\n noted(UNFINISHED, instanceId);\n\n/** The fields of a `read` or `diff` call provingResumes uses; a family's own input carries more. */\ntype Ask = {\n readonly id: string;\n readonly fqn: string;\n readonly instanceId: string;\n readonly olds: unknown;\n readonly output: unknown;\n};\ntype Hook = Effect.Effect<unknown, unknown, unknown>;\n\n/** The two hooks provingResumes wraps, as Alchemy's ProviderService declares them. */\ninterface Resumable {\n read?(input: Ask): Hook;\n diff?(input: Ask): Hook;\n}\n\n/**\n * A provider whose `diff`, for a row with no attributes, first asks the provider's own `read` whether\n * the live object is that unfinished generation's (noteResume), then runs as written. Every Bao.*\n * family is built through it, so their diffs answer such a row with a plain `undefined`.\n */\nexport const provingResumes = <S extends Resumable>(service: S): S => {\n const { diff, read } = service;\n if (diff === undefined || read === undefined) return service;\n const proving: Resumable['diff'] = (input) =>\n Effect.gen(function* () {\n if (input.output === undefined) {\n yield* noteResume(input.instanceId, read({ ...input, output: undefined }));\n }\n return yield* diff(input);\n });\n // ⚠️ The one cast: `diff` keeps the family's own signature — it is the family's diff, run after.\n return { ...service, diff: proving } as S;\n};\n",
|
|
15
15
|
"/**\n * The questions ownership/ asks of Alchemy's state store: does a row record this instance, and with\n * its whole declaration (probe.ts); is this apply a create rather than a replace's new generation\n * (adopt.ts); and — when reconcile refuses a create — forget the row Apply committed for it\n * (adopt.ts). Alchemy's own AWS.EC2.SecurityGroup provider reads the store the same way: the Stack\n * service names the stack and stage, and `State` yields the store.\n *\n * ⚠️ WITHOUT A STACK OR STATE IN CONTEXT, or with a store that errors, a row reads as \"not\n * recorded\" — the object is then `Unowned`, the safe answer — and nothing is forgotten, which\n * leaves the one gap forgetRefusedCreate exists to close. `alchemy deploy` and the Alchemist\n * session provide both.\n */\nimport { Stack } from 'alchemy/Stack';\nimport { State, type StateService, isActionState } from 'alchemy/State/State';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport { wholeDeclaration } from './whole.ts';\n\ntype Where = { readonly stack: string; readonly stage: string };\n\n/** The store, where this stack lives, and what it declares — or undefined outside a stack. */\nconst storeOf = Effect.gen(function* () {\n const stack = yield* Effect.serviceOption(Stack);\n const state = yield* Effect.serviceOption(State);\n if (Option.isNone(stack) || Option.isNone(state)) return undefined;\n const store: StateService = yield* state.value;\n const where: Where = { stack: stack.value.name, stage: stack.value.stage };\n return { resources: stack.value.resources, store, where };\n});\n\nconst rowAt = (store: StateService, where: Where, fqn: string) =>\n store.get({ ...where, fqn }).pipe(Effect.orElseSucceed(() => undefined));\n\n/** One generation of a persisted row, as far as ownership/ reads it. */\nexport type Generation = {\n readonly instanceId?: unknown;\n readonly status?: unknown;\n readonly props?: unknown;\n readonly attr?: unknown;\n readonly old?: unknown;\n /** Set by Apply on the `updating` row of an adoption, until that update commits (Apply.ts). */\n readonly adopting?: unknown;\n};\n\n/** The generation of a persisted row that carries `instanceId`: the row itself, or one in `old`. */\nconst generationOf = (row: unknown, instanceId: string): Generation | undefined => {\n let at = row;\n while (typeof at === 'object' && at !== null && !isActionState(at as never)) {\n const generation = at as Generation;\n if (generation.instanceId === instanceId) return generation;\n at = generation.old;\n }\n return undefined;\n};\n\n/** The generation `instanceId` names — at the FQN, or at a former FQN `renamedFrom` names. */\nexport const recordedGeneration = (\n fqn: string,\n instanceId: string,\n): Effect.Effect<Generation | undefined> =>\n Effect.gen(function* () {\n const found = yield* storeOf;\n if (found === undefined) return undefined;\n for (const at of [fqn, ...(found.resources[fqn]?.FormerFqns ?? [])]) {\n const generation = generationOf(yield* rowAt(found.store, found.where, at), instanceId);\n if (generation !== undefined) return generation;\n }\n return undefined;\n });\n\n/**\n * What the state store says of `instanceId` for this resource (at its FQN, or at a former FQN its\n * `renamedFrom` names — the planner migrates that row before it recovers it):\n * · `absent` — no row holds it. ★ This is what separates the probe from the recovery read: the\n * probe's instance id is minted for the probe (Plan.ts `generateInstanceId()`), 128 random bits\n * no row can hold.\n * · `partial` — a row holds it, but its props lack part of the declaration: a prop stripped at\n * commit because it was still an Output (whole.ts). Those props cannot prove an object ours.\n * · `whole` — a row holds it with every prop the declaration names.\n */\nexport type Recorded = 'absent' | 'partial' | 'whole';\n\nexport const recordedInstance = (fqn: string, instanceId: string): Effect.Effect<Recorded> =>\n Effect.gen(function* () {\n const generation = yield* recordedGeneration(fqn, instanceId);\n if (generation === undefined) return 'absent';\n return (yield* wholeDeclaration(fqn, generation.props)) ? 'whole' : 'partial';\n });\n\n/**\n * Whether this apply's `instanceId` is a CREATE: the row Apply committed for it is `creating`.\n * ⛔ A REPLACE'S NEW GENERATION IS NOT ONE. Apply commits it as `replacing`, and the planner never\n * offers it adoption — the probe runs only for a resource with no state — so `--adopt` must not\n * let it write over whatever sits at its new identity (adopt.ts adoptsAtApply).\n */\nexport const isCreate = (fqn: string, instanceId: string): Effect.Effect<boolean> =>\n Effect.map(\n recordedGeneration(fqn, instanceId),\n (generation) => generation?.status === 'creating',\n );\n\nconst idOf = (attr: unknown): string | undefined => {\n if (typeof attr !== 'object' || attr === null) return undefined;\n const id = (attr as { readonly id?: unknown }).id;\n return typeof id === 'string' && id !== '' ? id : undefined;\n};\n\n/**\n * `attr.id` on every generation OLDER than `instanceId` in this FQN's state chain (and a former\n * FQN `renamedFrom` names). Walks `old` the way {@link generationOf} does, and skips the current\n * generation itself.\n * ⛔ THOSE IDS ARE NOT THIS GENERATION'S. A `replacing` row's reconcile runs with no attributes, so\n * a live row found by name can be the previous generation's own deployment. Recording that id on\n * the new generation makes both the same id, and `destroy()` then deletes the old generation by\n * it (Apply.ts, the retain check near 2168 and the provider delete that follows when the policy\n * is not `retain`). A same-instance `old` snapshot (an `updating` row) is not one of these.\n */\nexport const olderGenerationIds = (\n fqn: string,\n instanceId: string,\n): Effect.Effect<readonly string[]> =>\n Effect.gen(function* () {\n const found = yield* storeOf;\n if (found === undefined) return [];\n const ids: string[] = [];\n for (const at of [fqn, ...(found.resources[fqn]?.FormerFqns ?? [])]) {\n collectOlder(yield* rowAt(found.store, found.where, at), instanceId, ids);\n }\n return ids;\n });\n\n/**\n * Once `instanceId` has been seen, collect `attr.id` from generations with a DIFFERENT instance\n * id. An `updating` row's `old` is the same instance's pre-update snapshot (Apply.ts), not a\n * replacement generation — that snapshot's id is the row this apply is already writing.\n */\nconst collectOlder = (row: unknown, instanceId: string, ids: string[]): void => {\n let at = row;\n let seen = false;\n while (typeof at === 'object' && at !== null && !isActionState(at as never)) {\n const generation = at as Generation;\n if (!seen) {\n seen = generation.instanceId === instanceId;\n at = generation.old;\n continue;\n }\n if (generation.instanceId !== instanceId) {\n const id = idOf(generation.attr);\n if (id !== undefined) ids.push(id);\n }\n at = generation.old;\n }\n};\n\n/**\n * ⛔ A REFUSED CREATE MUST NOT LEAVE A ROW THAT CLAIMS THE OBJECT IT REFUSED. Apply commits a\n * `creating` row for this instance before it calls reconcile, and a failed reconcile leaves it\n * there. The next plan's recovery read would then find our instance id and an object that can\n * match its props — a prop that was an Output is stripped from the row, and an omitted prop is\n * \"not managed\" — and adopt exactly what this apply refused. 🔴 MEASURED 2026-09-21: Bao.Mount\n * and Bao.AuthMethod did (openbao/adopt-core.test.ts). So the row goes, and state reads as if\n * the create never started: the next plan probes, and the probe answers `Unowned`.\n * ⚠️ ONLY a `creating` row of THIS instance with no attributes — the one Apply just wrote. A\n * `replacing` row carries the previous generation in `old` and is never touched.\n */\nexport const forgetRefusedCreate = (fqn: string, instanceId: string): Effect.Effect<void> =>\n Effect.gen(function* () {\n const found = yield* storeOf;\n if (found === undefined) return;\n const row = yield* rowAt(found.store, found.where, fqn);\n const mine = row as { status?: unknown; instanceId?: unknown; attr?: unknown } | undefined;\n if (mine?.status !== 'creating' || mine.instanceId !== instanceId || mine.attr !== undefined) {\n return;\n }\n yield* found.store.delete({ ...found.where, fqn }).pipe(Effect.ignore);\n });\n",
|
|
16
16
|
"/**\n * Whether a state row's props say everything the declaration says — the test that separates a row\n * whose props can prove an object ours from one that cannot (probe.ts, rows.ts).\n *\n * ★ WHY A ROW CAN BE MISSING PART OF ITS DECLARATION. Apply commits the `creating` (or `replacing`)\n * row BEFORE reconcile runs, and strips every prop still an Output at that moment (alchemy\n * beta.79 Apply.ts `commit` → Diff.ts `stripUnresolved`); a JSON store then drops the key. So a\n * row written while an upstream was still being created carries a HOLE where that prop was.\n * ⛔ A HOLE IS \"UNKNOWN\", NOT \"UNMANAGED\". Most families read an absent prop as \"not managed\", so a\n * recovery read comparing the live object with holed props proves nothing: 🔴 MEASURED 2026-09-21\n * (openbao/adopt-holes.test.ts), a Bao.Mount whose `defaultLeaseTtl` was an Output, killed before\n * its reconcile ran, adopted — and tuned — another owner's mount on the next deploy; with the\n * NAME an Output, every role family read an empty name, found nothing, and the resumed create\n * wrote over another owner's role. Neither deploy had ever asked whose object it was.\n * ★ THE DECLARATION IS WHAT TELLS A HOLE FROM AN OMISSION. It still holds the Output (or the literal)\n * the row lacks, while an optional prop left out is absent from both.\n * ⚠️ CONSERVATIVE BY DESIGN: a prop added to the declaration after the crash also reads as a hole.\n * That costs one `--adopt`, never a takeover.\n */\nimport { Stack } from 'alchemy/Stack';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\n\nconst absent = (value: unknown): boolean => value === undefined || value === null;\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return false;\n const proto: unknown = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n};\n\n/**\n * Whether `recorded` carries a value everywhere `declared` does. Plain objects and arrays are\n * walked; any other declared value — a literal, an Output, an Effect — needs a value in the row.\n */\nexport const carries = (declared: unknown, recorded: unknown): boolean => {\n if (absent(declared)) return true;\n if (absent(recorded)) return false;\n if (Array.isArray(declared)) {\n if (!Array.isArray(recorded)) return false;\n return declared.every((each, index) => carries(each, recorded[index]));\n }\n if (isPlainObject(declared)) {\n if (!isPlainObject(recorded)) return false;\n return Object.entries(declared).every(([key, each]) => carries(each, recorded[key]));\n }\n return true;\n};\n\n/**\n * Whether `props` — one generation's, from the state store — carry the whole declaration of the\n * resource at `fqn`. ⛔ FALSE WITH NOTHING TO COMPARE: no Stack in context, or a resource no longer\n * declared (an orphan's delete). That object then reads as `Unowned` and Apply leaves it in place\n * with a note, rather than deleting what it cannot prove it made.\n */\nexport const wholeDeclaration = (fqn: string, props: unknown): Effect.Effect<boolean> =>\n Effect.map(Effect.serviceOption(Stack), (stack) => {\n const declared = Option.isSome(stack) ? stack.value.resources[fqn] : undefined;\n return declared !== undefined && carries(declared.Props, props);\n });\n",
|
|
17
|
-
"/**\n * `read` with no attributes — the plan-time half of \"nothing is adopted without `--adopt`\"\n * (adopt.ts has the apply-time half). Alchemy asks it in two situations and passes `output:\n * undefined` in both (alchemy beta.79 Plan.ts):\n * · THE ADOPTION PROBE — no state row at all; `olds` is the declaration, `instanceId` fresh.\n * · THE RECOVERY READ — a `creating` row whose create was interrupted after its write and before\n * its commit; `olds` is that row's props, `instanceId` the row's. (Apply.ts asks the same for a\n * row it must delete that never recorded attributes.)\n * The answer routes the plan: `undefined` → create; plain attributes → ours; `Unowned(…)` → the\n * plan fails with OwnedBySomeoneElse unless `--adopt` / `adopt(true)` (AdoptPolicy.ts).\n *\n * ⛔ THE PROBE ALWAYS ANSWERS `Unowned` FOR A LIVE OBJECT, EVEN ONE IDENTICAL TO THE DECLARATION\n * (decided 2026-09-21). Identical is not ours: a name another stack, a person or an old script put\n * there reads the same, and once state claims it, a delete under `destroy` removes it from its\n * real owner. 🔴 Measured before the change (openbao/rename-adoption.test.ts): a new logical id\n * for a live Bao name adopted it silently, and the old id's delete then removed it, green.\n * ★ THE RECOVERY READ STILL ADOPTS WHAT THE INTERRUPTED CREATE MADE — the instance is ours by the\n * state row, and the object is proven ours when it matches that row's props (`settled`). One that\n * does not match may have lost a race to someone else: `Unowned`, as Plan.ts itself asks.\n * ⛔ ONLY WHEN THE ROW'S PROPS ARE THE WHOLE DECLARATION (whole.ts). A row written while a prop was\n * still an Output has a hole there, and \"matches\" against a hole proves nothing — nor had that\n * deploy's plan ever asked whose object it was, because Alchemy skips the probe for an Output.\n * Such a create resumes with `--adopt`.\n */\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport * as Effect from 'effect/Effect';\nimport type { Owner } from './adopt.ts';\nimport { recordedInstance } from './rows.ts';\n\n/**\n * Whether the state store proves the live object this instance's own: a row records `ask.instanceId`\n * with its whole declaration (whole.ts) AND `settled` — the family's own \"live matches these props\"\n * — says so. The one proof ownership/ accepts for a live object state holds no attributes for; the\n * recovery read (`ownedRead`) and an adoption check (adopting.ts) both ask it.\n * ⛔ `settled` NEVER FAILS THE CALLER. The recovery read runs with the INTERRUPTED deploy's props, so\n * a declaration that cannot be evaluated any more (a fragments directory since moved, a group\n * name since renamed) would fail every later plan, the fix included. It reads as \"not proven\n * ours\" instead, with the reason logged.\n */\nexport const provenOurs = <E, R>(\n ask: { readonly fqn: string; readonly instanceId: string },\n settled: Effect.Effect<boolean, E, R>,\n): Effect.Effect<boolean, never, R> =>\n Effect.gen(function* () {\n const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);\n if (recorded === 'absent') return false;\n if (recorded === 'partial') {\n yield* Effect.logWarning(\n `${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` +\n 'was still an Output when it was written), so the live object is not proven ours',\n );\n return false;\n }\n const unproven = (reason: unknown) =>\n Effect.as(\n Effect.logWarning(\n `${ask.fqn}: the interrupted create's object could not be compared with its props ` +\n `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`,\n ),\n false,\n );\n return yield* settled.pipe(Effect.catch(unproven), Effect.catchDefect(unproven));\n });\n\n/**\n * A family's `read` answer. With attributes in state it is `found` as is. Without, it is the probe\n * or the recovery read (header): `found` is ours only when `provenOurs` says so, else `Unowned`,\n * which `--adopt` resolves.\n */\nexport const ownedRead = <A extends object, E, R>(\n ask: Owner,\n found: A | undefined,\n settled: Effect.Effect<boolean, E, R>,\n): Effect.Effect<A | undefined, never, R> =>\n Effect.gen(function* () {\n if (found === undefined || ask.output !== undefined) return found;\n
|
|
17
|
+
"/**\n * `read` with no attributes — the plan-time half of \"nothing is adopted without `--adopt`\"\n * (adopt.ts has the apply-time half). Alchemy asks it in two situations and passes `output:\n * undefined` in both (alchemy beta.79 Plan.ts):\n * · THE ADOPTION PROBE — no state row at all; `olds` is the declaration, `instanceId` fresh.\n * · THE RECOVERY READ — a `creating` row whose create was interrupted after its write and before\n * its commit; `olds` is that row's props, `instanceId` the row's. (Apply.ts asks the same for a\n * row it must delete that never recorded attributes.)\n * The answer routes the plan: `undefined` → create; plain attributes → ours; `Unowned(…)` → the\n * plan fails with OwnedBySomeoneElse unless `--adopt` / `adopt(true)` (AdoptPolicy.ts).\n *\n * ⛔ THE PROBE ALWAYS ANSWERS `Unowned` FOR A LIVE OBJECT, EVEN ONE IDENTICAL TO THE DECLARATION\n * (decided 2026-09-21). Identical is not ours: a name another stack, a person or an old script put\n * there reads the same, and once state claims it, a delete under `destroy` removes it from its\n * real owner. 🔴 Measured before the change (openbao/rename-adoption.test.ts): a new logical id\n * for a live Bao name adopted it silently, and the old id's delete then removed it, green.\n * ★ THE RECOVERY READ STILL ADOPTS WHAT THE INTERRUPTED CREATE MADE — the instance is ours by the\n * state row, and the object is proven ours when it matches that row's props (`settled`). One that\n * does not match may have lost a race to someone else: `Unowned`, as Plan.ts itself asks.\n * ⛔ ONLY WHEN THE ROW'S PROPS ARE THE WHOLE DECLARATION (whole.ts). A row written while a prop was\n * still an Output has a hole there, and \"matches\" against a hole proves nothing — nor had that\n * deploy's plan ever asked whose object it was, because Alchemy skips the probe for an Output.\n * Such a create resumes with `--adopt`.\n */\nimport { Unowned } from 'alchemy/AdoptPolicy';\nimport * as Effect from 'effect/Effect';\nimport * as Option from 'effect/Option';\nimport type * as Tracer from 'effect/Tracer';\nimport type { Owner } from './adopt.ts';\nimport { resumes } from './resume.ts';\nimport { forgetRefusedCreate, recordedInstance } from './rows.ts';\n\n/**\n * Whether this read is APPLY's own (Apply.ts `instrumentLifecycle` wraps every apply-time lifecycle\n * call in a `provider.read` span; the plan's reads run outside one).\n * ⛔ AN APPLY-TIME READ WITH NO ATTRIBUTES PROVES NOTHING. 🔴 MEASURED 2026-10-06 (alchemy\n * 2.0.0-beta.81, openbao/adopt-core.test.ts and nine more suites): beta.81 asks the provider to\n * read at APPLY for a create whose props were still Outputs at plan (Plan.ts `deferredAdoption`),\n * and first overwrites the `creating` row with the NOW-RESOLVED props (Apply.ts `checkpoint`). That\n * row is whole, so `provenOurs` read the live object as matching it, and another owner's object\n * was taken over with no `--adopt`. Answering `Unowned` here hands the decision back to the engine,\n * which refuses it (\"Cannot adopt resource … Re-run with `--adopt`\") unless adoption is on.\n * ★ THE ONE PROOF AN APPLY-TIME READ MAY USE IS THE PLAN'S: the diff's own recovery read noted this\n * instance as a proven resume (resume.ts), and that note is what `resumes` answers.\n * ⛔ ONLY THE CREATE'S OWN READ, NOT THE DELETE PATH'S. beta.81 wraps BOTH in a `provider.read`\n * span: the deferred-adoption read runs inside `apply.resource` (the create's span), while the\n * deletion recovery read (Apply.ts, a row to delete that never recorded attributes) runs in\n * collectGarbage, under no such span. 🔴 Treating the second as the first answered `Unowned` for\n * our own interrupted create: the engine skipped `provider.delete` and erased the row, leaving a\n * live object nothing tracked (red team, kit PR 359, 2026-10-06; adopt-recovery.test.ts). The\n * delete's recovery read keeps the state-row proof (`recordedInstance` + `settled`), as before.\n */\nconst inApplyResource = (span: Tracer.AnySpan | undefined): boolean => {\n let at = span;\n while (at !== undefined && at._tag === 'Span') {\n if (at.name === 'apply.resource') return true;\n at = Option.getOrUndefined(at.parent);\n }\n return false;\n};\n\nconst isCreatesRead = (span: Option.Option<Tracer.Span>): boolean => {\n const current = Option.getOrUndefined(span);\n return current?.name === 'provider.read' && inApplyResource(current);\n};\n\nconst readsAtApply: Effect.Effect<boolean> = Effect.map(\n Effect.option(Effect.currentSpan),\n isCreatesRead,\n);\n\n/**\n * Whether the state store proves the live object this instance's own: a row records `ask.instanceId`\n * with its whole declaration (whole.ts) AND `settled` — the family's own \"live matches these props\"\n * — says so. The one proof ownership/ accepts for a live object state holds no attributes for; the\n * recovery read (`ownedRead`) and an adoption check (adopting.ts) both ask it.\n * ⛔ `settled` NEVER FAILS THE CALLER. The recovery read runs with the INTERRUPTED deploy's props, so\n * a declaration that cannot be evaluated any more (a fragments directory since moved, a group\n * name since renamed) would fail every later plan, the fix included. It reads as \"not proven\n * ours\" instead, with the reason logged.\n */\nexport const provenOurs = <E, R>(\n ask: { readonly fqn: string; readonly instanceId: string },\n settled: Effect.Effect<boolean, E, R>,\n): Effect.Effect<boolean, never, R> =>\n Effect.gen(function* () {\n if (yield* readsAtApply) return yield* resumes(ask.instanceId);\n const recorded = yield* recordedInstance(ask.fqn, ask.instanceId);\n if (recorded === 'absent') return false;\n if (recorded === 'partial') {\n yield* Effect.logWarning(\n `${ask.fqn}: the interrupted create's state row lacks part of the declaration (a prop ` +\n 'was still an Output when it was written), so the live object is not proven ours',\n );\n return false;\n }\n const unproven = (reason: unknown) =>\n Effect.as(\n Effect.logWarning(\n `${ask.fqn}: the interrupted create's object could not be compared with its props ` +\n `(${reason instanceof Error ? reason.message : String(reason)}), so it is not treated as ours`,\n ),\n false,\n );\n return yield* settled.pipe(Effect.catch(unproven), Effect.catchDefect(unproven));\n });\n\n/**\n * A family's `read` answer. With attributes in state it is `found` as is. Without, it is the probe\n * or the recovery read (header): `found` is ours only when `provenOurs` says so, else `Unowned`,\n * which `--adopt` resolves.\n */\nexport const ownedRead = <A extends object, E, R>(\n ask: Owner,\n found: A | undefined,\n settled: Effect.Effect<boolean, E, R>,\n): Effect.Effect<A | undefined, never, R> =>\n Effect.gen(function* () {\n if (found === undefined || ask.output !== undefined) return found;\n if (yield* provenOurs(ask, settled)) return found;\n // ⛔ THE ENGINE'S OWN REFUSAL LEAVES ITS `creating` CHECKPOINT BEHIND (Apply.ts), now holding the\n // RESOLVED props: a whole row, which the next plan's recovery read would take as proof and\n // adopt exactly what was refused. Forgotten here, as adopt.ts refuseTakeover does for its own\n // refusal; under --adopt the engine's later `created` commit writes the row again.\n if (yield* readsAtApply) yield* forgetRefusedCreate(ask.fqn, ask.instanceId);\n return Unowned(found);\n });\n",
|
|
18
18
|
"/**\n * The digest every Bao.* family persists instead of a value — moved here from the retired\n * bao-shell.ts, unchanged, when the package stopped shelling out to `bao`.\n */\n\n/** ⚠️ Bun's hasher, not node:crypto — this runs under `bun --bun alchemy`. */\n/**\n * The only form a policy body may be hashed or compared in.\n *\n * ⛔ OPENBAO STRIPS THE TRAILING NEWLINE AND THAT ALONE WAS A FOREVER-DIFF. MEASURED on the live\n * server: the assembler emits each fragment followed by a newline, so `app-llm` goes in as\n * 41 lines and `bao policy read` hands back 40 — identical text, one `\\n` apart, two different\n * digests. Every plan therefore reported `update`, every deploy rewrote the same policy, and the\n * stack could never settle. It was invisible until the stack planned for the first time today.\n * ★ THE HTTP API HANDS BACK THE SAME STRIPPED TEXT. `bao policy read` printed `data.policy` of\n * `GET /v1/sys/policies/acl/<name>` (openbao v2.6.2 api/sys_policy.go:60-81), which is what\n * policy-wire.ts now reads directly — so the canonicalisation is still load-bearing.\n *\n * ⚠️ `trimEnd` ONLY. Leading and interior whitespace are part of the HCL and must not be touched —\n * a policy that differs by an indent really is a different document, and quietly folding that\n * away would hide an edit rather than a formatting artifact.\n */\nexport const canonical = (text: string) => text.trimEnd();\n\nexport const sha256 = (text: string) =>\n new Bun.CryptoHasher('sha256').update(canonical(text)).digest('hex');\n",
|
|
19
19
|
"import { sha256 } from './digest.ts';\nimport { trimTrailingSlashes } from './mount-path.ts';\n\n/** Mount path without a trailing slash — props and `sys/mounts/<path>` use this shape. */\nexport const mountPath = (path: string) => trimTrailingSlashes(path);\n\nconst DURATION = /^(\\d+)([smhd])$/;\n\n/** Parse a Vault duration string (`15m`, `768h`, `0`) to seconds. */\nexport const parseDuration = (text: string): number | undefined => {\n const trimmed = text.trim();\n if (trimmed === '0') return 0;\n const match = DURATION.exec(trimmed);\n if (match === null) return undefined;\n const amount = Number(match[1]);\n switch (match[2]) {\n case 's':\n return amount;\n case 'm':\n return amount * 60;\n case 'h':\n return amount * 3600;\n case 'd':\n return amount * 86400;\n default:\n return undefined;\n }\n};\n\n/** Seconds from live JSON (`2764800`) or a duration prop (`768h`). */\nexport const ttlSeconds = (value: unknown): number | undefined => {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string') return parseDuration(value);\n return undefined;\n};\n\nexport interface BaoMountProps {\n /** Mount path without trailing slash, as `sys/mounts/<path>` takes it. */\n path: string;\n /** Secrets engine type, e.g. `kv`, `pki`, `openbao-plugin-secrets-cloudflare`. */\n type: string;\n /** Human description — tuned via `sys/mounts/<path>/tune`, as apply-roles.py describe_mounts does. */\n description?: string;\n /** Default lease TTL, e.g. `768h`. */\n defaultLeaseTtl?: string;\n /** Max lease TTL, e.g. `8760h`. */\n maxLeaseTtl?: string;\n /** KV only — sent as `options.version` on enable, as `-version=2` was. Immutable after create. */\n version?: 1 | 2;\n /**\n * The path this mount lives at NOW, when `path` is where it should move to. Moves it with\n * `sys/remount`, keeping every secret. Without it, a changed `path` fails the plan — see\n * mount-move.ts. ⛔ Every lease under the old path is revoked, and policies are not rewritten.\n * Harmless to leave declared after the move: once state holds `path`, it is ignored.\n */\n remountFrom?: string;\n}\n\nexport interface BaoMountAttributes {\n path: string;\n type: string;\n description: string;\n defaultLeaseTtl: string;\n maxLeaseTtl: string;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\nconst configOf = (live: Record<string, unknown>) =>\n typeof live['config'] === 'object' && live['config'] !== null\n ? (live['config'] as Record<string, unknown>)\n : {};\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\nconst ttlProp = (seconds: number | undefined, fallback = '') => {\n if (seconds === undefined) return fallback;\n if (seconds % 86400 === 0) return `${String(seconds / 86400)}d`;\n if (seconds % 3600 === 0) return `${String(seconds / 3600)}h`;\n if (seconds % 60 === 0) return `${String(seconds / 60)}m`;\n return `${String(seconds)}s`;\n};\n\nexport const attributesOf = (\n props: BaoMountProps,\n live: Record<string, unknown>,\n): BaoMountAttributes => {\n const config = configOf(live);\n const defaultLeaseTtl = ttlProp(ttlSeconds(config['default_lease_ttl']));\n const maxLeaseTtl = ttlProp(ttlSeconds(config['max_lease_ttl']));\n const attrs = {\n path: mountPath(props.path),\n type: text(live['type']) || props.type,\n description: text(live['description']),\n defaultLeaseTtl,\n maxLeaseTtl,\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\n/** `sys/mounts/<path>` — read, enable and disable all address the mount here. */\nexport const readPath = (path: string) => `sys/mounts/${mountPath(path)}`;\n\n/**\n * ★ NO TRAILING SLASH NEEDED ON THE WIRE. `bao secrets tune` appended one itself; the server's\n * route `mounts/(?P<path>.+?)/tune$` captures the bare path and `sanitizePath` appends the slash\n * OpenBao stores in sys/mounts (openbao v2.6.2 vault/logical_system_paths.go:4248,\n * vault/logical_system.go:4825-4833).\n */\nexport const tunePath = (path: string) => `${readPath(path)}/tune`;\n\n/**\n * The enable body. `-version=2` on the CLI became `options.version = \"2\"` (openbao v2.6.2\n * command/secrets_enable.go:278 into api MountInput.Options), so that is what is sent.\n *\n * ⚠️ DESCRIPTION AND TTLs ARE NOT SENT HERE. reconcile tunes them straight after the enable,\n * exactly as the CLI path did, so a create and an update converge through the same call.\n */\nexport const enableBody = (props: BaoMountProps): Record<string, unknown> =>\n props.version === 2 ? { options: { version: '2' }, type: props.type } : { type: props.type };\n\n/**\n * The tune body — only the fields the declaration names.\n *\n * ★ AN OMITTED FIELD IS LEFT ALONE. The server reads an absent TTL as \"\" and keeps the mount's\n * current value for \"\" (vault/logical_system.go:1614-1630), and applies `description` only when\n * present (:1725). The CLI sent unset TTL flags as \"\" and set description only when given\n * (command/secrets_tune.go Visit), so omitting them is the same request.\n */\nexport const tuneBody = (props: BaoMountProps): Record<string, string> => {\n const body: Record<string, string> = {};\n if (props.description !== undefined) body['description'] = props.description;\n if (props.defaultLeaseTtl !== undefined) body['default_lease_ttl'] = props.defaultLeaseTtl;\n if (props.maxLeaseTtl !== undefined) body['max_lease_ttl'] = props.maxLeaseTtl;\n return body;\n};\n\nconst sameTtl = (want: string | undefined, have: string) => {\n if (want === undefined) return true;\n const wantSeconds = ttlSeconds(want);\n const haveSeconds = ttlSeconds(have);\n return wantSeconds !== undefined && wantSeconds === haveSeconds;\n};\n\n/** True when live already matches the declaration on every managed field. */\nexport const matches = (attributes: BaoMountAttributes, props: BaoMountProps) =>\n attributes.type === props.type &&\n (props.description === undefined || attributes.description === props.description) &&\n sameTtl(props.defaultLeaseTtl, attributes.defaultLeaseTtl) &&\n sameTtl(props.maxLeaseTtl, attributes.maxLeaseTtl);\n\nexport const wantsTune = (props: BaoMountProps) =>\n props.description !== undefined ||\n props.defaultLeaseTtl !== undefined ||\n props.maxLeaseTtl !== undefined;\n",
|
|
20
20
|
"/**\n * Auth-method shape — path, type, description, lease TTLs. METADATA ONLY.\n *\n * ⛔ NO SECRET IN PROPS. Enabling `approle` (or jwt/oidc) is a mount, not a credential.\n * Role ids, OIDC client secrets, and secret_ids stay out of Alchemy state.\n */\nimport { sha256 } from './digest.ts';\nimport { mountPath, ttlSeconds } from './mount-form.ts';\n\nexport interface BaoAuthMethodProps {\n /** Auth path without trailing slash, as `sys/auth/<path>` takes it. */\n path: string;\n /** Auth method type, e.g. `approle`, `jwt`, `oidc`. */\n type: string;\n /** Human description — sent on enable and on tune, as configure-engines does. */\n description?: string;\n /** Default lease TTL, e.g. `768h`. */\n defaultLeaseTtl?: string;\n /** Max lease TTL, e.g. `8760h`. */\n maxLeaseTtl?: string;\n /**\n * The path this method lives at NOW, when `path` is where it should move to — `sys/remount`\n * from `auth/<remountFrom>`, keeping every role. Without it a changed `path` fails the plan\n * (mount-move.ts). ⚠️ Every token issued through the method is revoked by the move, and login\n * URLs, policies and MFA enforcements by accessor are not rewritten (the accessor is kept).\n */\n remountFrom?: string;\n}\n\nexport interface BaoAuthMethodAttributes {\n path: string;\n type: string;\n description: string;\n defaultLeaseTtl: string;\n maxLeaseTtl: string;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\n/** Auth path without a trailing slash — listing keys are `${path}/`. */\nexport const authPath = (path: string) => mountPath(path);\n\nconst configOf = (live: Record<string, unknown>) =>\n typeof live['config'] === 'object' && live['config'] !== null\n ? (live['config'] as Record<string, unknown>)\n : {};\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\nconst ttlProp = (seconds: number | undefined, fallback = '') => {\n if (seconds === undefined) return fallback;\n if (seconds % 86400 === 0) return `${String(seconds / 86400)}d`;\n if (seconds % 3600 === 0) return `${String(seconds / 3600)}h`;\n if (seconds % 60 === 0) return `${String(seconds / 60)}m`;\n return `${String(seconds)}s`;\n};\n\nexport const attributesOf = (\n props: BaoAuthMethodProps,\n live: Record<string, unknown>,\n): BaoAuthMethodAttributes => {\n const config = configOf(live);\n const attrs = {\n path: authPath(props.path),\n type: text(live['type']) || props.type,\n description: text(live['description']),\n defaultLeaseTtl: ttlProp(ttlSeconds(config['default_lease_ttl'])),\n maxLeaseTtl: ttlProp(ttlSeconds(config['max_lease_ttl'])),\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\n/** `sys/auth/<path>` — read, enable and disable all address the method here. */\nexport const readPath = (path: string) => `sys/auth/${authPath(path)}`;\n\n/**\n * ★ SAME TUNE ROUTE SHAPE AS SECRETS MOUNTS. `bao auth tune` hits\n * `sys/auth/<path>/tune` (openbao v2.6.2 api/sys_auth.go TuneAuth).\n */\nexport const tunePath = (path: string) => `${readPath(path)}/tune`;\n\n/**\n * The enable body. configure-engines POSTed `{ type, description }` for approle.\n *\n * ⚠️ TTLs ARE NOT SENT HERE. reconcile tunes them after enable, same as Bao.Mount.\n */\nexport const enableBody = (props: BaoAuthMethodProps): Record<string, string> => {\n const body: Record<string, string> = { type: props.type };\n if (props.description !== undefined) body['description'] = props.description;\n return body;\n};\n\n/** Tune body — only the fields the declaration names. An omitted field is left alone. */\nexport const tuneBody = (props: BaoAuthMethodProps): Record<string, string> => {\n const body: Record<string, string> = {};\n if (props.description !== undefined) body['description'] = props.description;\n if (props.defaultLeaseTtl !== undefined) body['default_lease_ttl'] = props.defaultLeaseTtl;\n if (props.maxLeaseTtl !== undefined) body['max_lease_ttl'] = props.maxLeaseTtl;\n return body;\n};\n\nconst sameTtl = (want: string | undefined, have: string) => {\n if (want === undefined) return true;\n const wantSeconds = ttlSeconds(want);\n const haveSeconds = ttlSeconds(have);\n return wantSeconds !== undefined && wantSeconds === haveSeconds;\n};\n\n/** True when live already matches the declaration on every managed field. */\nexport const matches = (attributes: BaoAuthMethodAttributes, props: BaoAuthMethodProps) =>\n attributes.type === props.type &&\n (props.description === undefined || attributes.description === props.description) &&\n sameTtl(props.defaultLeaseTtl, attributes.defaultLeaseTtl) &&\n sameTtl(props.maxLeaseTtl, attributes.maxLeaseTtl);\n\nexport const wantsTune = (props: BaoAuthMethodProps) =>\n props.description !== undefined ||\n props.defaultLeaseTtl !== undefined ||\n props.maxLeaseTtl !== undefined;\n",
|
|
21
|
-
"/**\n * Bao.AuthMethod's read and reconcile as plain effects — split from auth-method.ts so the move runs\n * against a fake server. Same shape as mount-reconcile.ts; the one difference that matters is the\n * `auth/` prefix sys/remount needs (vault/logical_system.go:1295-1310 refuses to move an auth mount\n * to a non-auth path, and `token/` cannot move at all).\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
21
|
+
"/**\n * Bao.AuthMethod's read and reconcile as plain effects — split from auth-method.ts so the move runs\n * against a fake server. Same shape as mount-reconcile.ts; the one difference that matters is the\n * `auth/` prefix sys/remount needs (vault/logical_system.go:1295-1310 refuses to move an auth mount\n * to a non-auth path, and `token/` cannot move at all).\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { Claim } from '../ownership/adopt.ts';\nimport {\n type BaoAuthMethodAttributes,\n type BaoAuthMethodProps,\n attributesOf,\n authPath,\n matches,\n wantsTune,\n} from './auth-method-form.ts';\nimport { enableAuthMethod, readAuthMethodData, tuneAuthMethod } from './auth-method-wire.ts';\nimport type { BaoError } from './bao-status.ts';\nimport { type MoveTarget, performMove, planMove } from './mount-move.ts';\nimport type { RemountError, RemountOptions } from './remount-wire.ts';\n\nexport const readMethod = (\n props: BaoAuthMethodProps,\n): Effect.Effect<BaoAuthMethodAttributes | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const live = yield* readAuthMethodData(props.path);\n if (live === undefined) return undefined;\n return attributesOf(props, live);\n });\n\nconst moveTarget = (props: BaoAuthMethodProps): MoveTarget => ({\n family: 'Bao.AuthMethod',\n path: props.path,\n read: (path) => readMethod({ ...props, path }),\n type: props.type,\n wire: (path) => `auth/${authPath(path)}`,\n});\n\n/**\n * Converge one auth method. `stated` is the path in Alchemy's state, if any.\n * ⛔ `claim`: the same first-reconcile takeover refusal as reconcileMount's (auth-method.ts passes it).\n */\nexport const reconcileAuthMethod = (\n news: BaoAuthMethodProps,\n stated: string | undefined,\n options?: RemountOptions,\n claim?: Claim,\n): Effect.Effect<BaoAuthMethodAttributes, BaoError | RemountError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const move = planMove('Bao.AuthMethod', stated, news.path, news.remountFrom);\n if (move.kind === 'refuse') return yield* Effect.die(new Error(move.message));\n const first = stated === undefined ? claim : undefined;\n if (first !== undefined && move.kind === 'move') {\n const source = yield* readMethod({ ...news, path: move.from });\n if (source !== undefined)\n yield* first(`Bao.AuthMethod ${move.from} (the remountFrom source)`);\n }\n if (move.kind === 'move') yield* performMove(moveTarget(news), move.from, options);\n\n let live = yield* readMethod(news);\n if (live === undefined) {\n yield* enableAuthMethod(news);\n if (wantsTune(news)) yield* tuneAuthMethod(news);\n } else {\n if (live.type !== news.type) {\n return yield* Effect.die(\n new Error(\n `Bao.AuthMethod ${authPath(news.path)}: live type ${live.type} != ${news.type}. ` +\n 'Auth method type is immutable — replace manually.',\n ),\n );\n }\n if (first !== undefined) yield* first(`Bao.AuthMethod ${authPath(news.path)}`);\n if (!matches(live, news)) yield* tuneAuthMethod(news);\n }\n live = yield* readMethod(news);\n if (live === undefined) {\n return yield* Effect.die(\n new Error(\n `Bao.AuthMethod ${authPath(news.path)}: write returned no error but the method is still absent.`,\n ),\n );\n }\n return live;\n });\n",
|
|
22
22
|
"/**\n * The OpenBao calls Bao.AuthMethod makes — read one method, enable, tune, disable.\n *\n * ★ ENDPOINTS, READ FROM openbao v2.6.2 api/sys_auth.go — the client configure-engines\n * used via curl:\n * read GET sys/auth/<path>\n * enable POST sys/auth/<path> — `bao auth enable`\n * tune POST sys/auth/<path>/tune — `bao auth tune`\n * disable DELETE sys/auth/<path> — `bao auth disable`\n * table GET sys/auth\n */\nimport * as Effect from 'effect/Effect';\nimport {\n type BaoAuthMethodProps,\n authPath,\n enableBody,\n readPath,\n tuneBody,\n tunePath,\n} from './auth-method-form.ts';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport { BaoError } from './bao-status.ts';\n\n/**\n * Confirm a method is absent from the auth table, or give back the error that asked.\n *\n * ⛔ A MISSING AUTH METHOD IS NOT A 404, IT IS A 400 — THE SAME TRAP AS SECRETS MOUNTS\n * (mount-wire.ts). `handleReadAuth` answers an empty path with a bare error; the CLI\n * therefore failed and never reached `auth enable`. REASONED FROM THE MOUNT ANALOG\n * AND PINNED AGAINST A FAKE — a live missing-method read was not measured.\n * ★ SO A 400 IS SETTLED BY GET sys/auth. Only a 200 table WITHOUT the `${path}/` key\n * is absence. A listed method, a refused listing, or a 404 listing leaves the 400.\n */\nconst absentFromTable = (path: string, asked: BaoError) =>\n baoRead('sys/auth').pipe(\n Effect.mapError(\n (listing) =>\n new BaoError(asked.status, asked.method, asked.path, [\n ...asked.errors,\n `sys/auth could not confirm the method is absent: ${listing.message}`,\n ]),\n ),\n Effect.flatMap((table) =>\n table !== undefined && !Object.hasOwn(table, `${authPath(path)}/`)\n ? Effect.succeed(undefined)\n : Effect.fail(asked),\n ),\n );\n\n/** One method's config (`type`, `description`, `config.*_lease_ttl`), or undefined when absent. */\nexport const readAuthMethodData = (path: string) =>\n baoRead(readPath(path)).pipe(\n Effect.catchIf(\n (error) => error.status === 400,\n (error) => absentFromTable(path, error),\n ),\n );\n\nexport const enableAuthMethod = (props: BaoAuthMethodProps) =>\n baoWrite('POST', readPath(props.path), enableBody(props));\n\nexport const tuneAuthMethod = (props: BaoAuthMethodProps) =>\n baoWrite('POST', tunePath(props.path), tuneBody(props));\n\n/** ⚠️ THERE IS NO FORCE. Disable is a plain DELETE, same as `bao auth disable`. */\nexport const disableAuthMethod = (path: string) => baoDelete(readPath(path));\n",
|
|
23
|
-
"/**\n * What a changed path means for Bao.Mount and Bao.AuthMethod — and the move, when one is declared.\n *\n * ⛔ A CHANGED PATH USED TO PLAN `update` AND ENABLE AN EMPTY MOUNT AT THE NEW PATH. diff read the\n * new path, found nothing, answered `update`, and reconcile ran `enable` there: a fresh, empty\n * `kv2/` beside the retained `kv/` that still held every secret, with Alchemy's state now naming\n * only the empty one. Nothing failed, so nothing said so (site-config plan, Guards).\n * ★ NOW A CHANGED PATH FAILS AT PLAN TIME, unless the declaration says where it came from:\n * `remountFrom: '<old path>'` moves the mount with `sys/remount` (remount-wire.ts), which keeps\n * every secret. A genuinely new, empty mount is a new resource id, never an edited path.\n * ★ THE MOVE IS DECIDED BY LIVE STATE, SO A RE-RUN CONVERGES. Source present and target absent is\n * a move; target present and source absent is a move that already happened; both present, or\n * neither, is a refusal — \"neither\" in particular is exactly the empty-mount failure above.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
24
|
-
"/**\n * `sys/remount` — move a secrets engine or auth method to a new path WITH its data — and the status\n * polling it needs, because the move finishes after the call returns.\n *\n * ★ READ FROM openbao v2.6.2, NOT RECALLED:\n * · api/sys_mounts.go:95-191 — the CLI's `bao secrets move` POSTs `{from, to}` to sys/remount,\n * takes `data.migration_id`, then GETs sys/remount/status/<id> once a second until\n * `migration_info.status` is `success` or `failure`. This is that loop, bounded.\n * · vault/logical_system.go:1257-1357 — the handler validates, records the migration and\n * answers AT ONCE; a goroutine does the move. So a 200 means \"queued\", never \"moved\".\n * · vault/mount.go:630-735 — the mount keeps its UUID, and storage lives under the UUID, so every\n * secret stays. ⛔ BUT EVERY LEASE UNDER THE SOURCE IS REVOKED (`RevokePrefix`, :684): a move of\n * a dynamic-secrets mount kills every credential it has issued. KV has no leases.\n * · vault/logical_system.go:67-69 — `remount` is a sudo path. The status path is not.\n * ⚠️ THE STATUS TRACKER IS IN MEMORY (vault/mount.go:2303-2336, a sync.Map on the active node). A\n * restart or leader change mid-move loses it, and the status read then answers 404. That is not a\n * failure and not a success; `confirm` settles it from the mount tables, or the call fails.\n * ⛔ POLICIES ARE NOT REWRITTEN. Every ACL path naming the old mount keeps naming it.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
25
|
-
"/**\n * An OpenBao AppRole auth role — token_policies, TTLs and bind flags. METADATA ONLY.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for why. `role_id` and `secret_id`\n * are credential issuance, not configuration, and are OUT OF SCOPE. This declares the\n * role shape an approle login inherits — policy names and TTL strings only.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role locks out every host that logs in with it:\n * its secret_ids go with it (the ⚠️ on `delete` below). Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
23
|
+
"/**\n * What a changed path means for Bao.Mount and Bao.AuthMethod — and the move, when one is declared.\n *\n * ⛔ A CHANGED PATH USED TO PLAN `update` AND ENABLE AN EMPTY MOUNT AT THE NEW PATH. diff read the\n * new path, found nothing, answered `update`, and reconcile ran `enable` there: a fresh, empty\n * `kv2/` beside the retained `kv/` that still held every secret, with Alchemy's state now naming\n * only the empty one. Nothing failed, so nothing said so (site-config plan, Guards).\n * ★ NOW A CHANGED PATH FAILS AT PLAN TIME, unless the declaration says where it came from:\n * `remountFrom: '<old path>'` moves the mount with `sys/remount` (remount-wire.ts), which keeps\n * every secret. A genuinely new, empty mount is a new resource id, never an edited path.\n * ★ THE MOVE IS DECIDED BY LIVE STATE, SO A RE-RUN CONVERGES. Source present and target absent is\n * a move; target present and source absent is a move that already happened; both present, or\n * neither, is a refusal — \"neither\" in particular is exactly the empty-mount failure above.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { BaoError } from './bao-status.ts';\nimport { mountPath } from './mount-form.ts';\nimport { type RemountError, type RemountOptions, remountAndWait } from './remount-wire.ts';\n\nexport type Move =\n | { readonly kind: 'stay' }\n | { readonly kind: 'move'; readonly from: string }\n | { readonly kind: 'refuse'; readonly message: string };\n\n/**\n * @param family `Bao.Mount` or `Bao.AuthMethod`, for the message.\n * @param stated the path Alchemy's state holds, or undefined on a first reconcile.\n * @param path the declared path.\n * @param remountFrom the declared source, if any.\n */\nexport const planMove = (\n family: string,\n stated: string | undefined,\n path: string,\n remountFrom: string | undefined,\n): Move => {\n const to = mountPath(path);\n const from = remountFrom === undefined ? undefined : mountPath(remountFrom);\n if (stated === undefined) {\n return from === undefined || from === to ? { kind: 'stay' } : { kind: 'move', from };\n }\n const was = mountPath(stated);\n if (was === to) return { kind: 'stay' };\n if (from === undefined) {\n return {\n kind: 'refuse',\n message:\n `${family}: path changed from ${was} to ${to}. That would enable an EMPTY mount at ${to} ` +\n `and strand everything under ${was}. To move it with its data, declare ` +\n `\\`remountFrom: '${was}'\\` (leases under it are revoked; policies are not rewritten). ` +\n 'For a new, empty mount, give it a new resource id instead.',\n };\n }\n if (from !== was) {\n return {\n kind: 'refuse',\n message: `${family}: remountFrom is ${from}, but the mount in state is ${was}.`,\n };\n }\n return { kind: 'move', from };\n};\n\nexport interface MoveTarget {\n readonly family: string;\n /** Declared path, bare. */\n readonly path: string;\n readonly type: string;\n /** Read one path's live entry — undefined when absent. */\n readonly read: (\n path: string,\n ) => Effect.Effect<{ readonly type: string } | undefined, BaoError, HttpClient.HttpClient>;\n /** The path as sys/remount takes it: the bare path for secrets, `auth/<path>` for auth. */\n readonly wire: (path: string) => string;\n}\n\nconst refuse = (message: string) => Effect.die(new Error(message));\n\n/** Perform a planned move, deciding by live state. Returns once the target is in place. */\nexport const performMove = (\n target: MoveTarget,\n from: string,\n options?: RemountOptions,\n): Effect.Effect<void, BaoError | RemountError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const to = mountPath(target.path);\n const source = yield* target.read(from);\n const landed = yield* target.read(to);\n if (source !== undefined && landed !== undefined) {\n return yield* refuse(\n `${target.family}: both ${from} and ${to} exist, so remountFrom cannot move one onto the ` +\n 'other. Decide which holds the data, and retire the other by hand.',\n );\n }\n if (source === undefined && landed === undefined) {\n return yield* refuse(\n `${target.family}: remountFrom ${from} names no mount, and ${to} does not exist either. ` +\n 'Refusing to enable an empty mount where data was expected.',\n );\n }\n if (source === undefined) return; // ★ Already moved — an interrupted apply re-running.\n if (source.type !== target.type) {\n return yield* refuse(\n `${target.family}: ${from} is type ${source.type}, not ${target.type}. A remount keeps the ` +\n 'type; fix the declaration first.',\n );\n }\n const confirm = Effect.map(\n Effect.all([target.read(from), target.read(to)]),\n ([gone, there]) => gone === undefined && there !== undefined,\n );\n yield* remountAndWait(target.wire(from), target.wire(to), confirm, options);\n });\n",
|
|
24
|
+
"/**\n * `sys/remount` — move a secrets engine or auth method to a new path WITH its data — and the status\n * polling it needs, because the move finishes after the call returns.\n *\n * ★ READ FROM openbao v2.6.2, NOT RECALLED:\n * · api/sys_mounts.go:95-191 — the CLI's `bao secrets move` POSTs `{from, to}` to sys/remount,\n * takes `data.migration_id`, then GETs sys/remount/status/<id> once a second until\n * `migration_info.status` is `success` or `failure`. This is that loop, bounded.\n * · vault/logical_system.go:1257-1357 — the handler validates, records the migration and\n * answers AT ONCE; a goroutine does the move. So a 200 means \"queued\", never \"moved\".\n * · vault/mount.go:630-735 — the mount keeps its UUID, and storage lives under the UUID, so every\n * secret stays. ⛔ BUT EVERY LEASE UNDER THE SOURCE IS REVOKED (`RevokePrefix`, :684): a move of\n * a dynamic-secrets mount kills every credential it has issued. KV has no leases.\n * · vault/logical_system.go:67-69 — `remount` is a sudo path. The status path is not.\n * ⚠️ THE STATUS TRACKER IS IN MEMORY (vault/mount.go:2303-2336, a sync.Map on the active node). A\n * restart or leader change mid-move loses it, and the status read then answers 404. That is not a\n * failure and not a success; `confirm` settles it from the mount tables, or the call fails.\n * ⛔ POLICIES ARE NOT REWRITTEN. Every ACL path naming the old mount keeps naming it.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { baoCall, baoRead } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\n\n/** A move OpenBao reported failed, or one this could not confirm. Never carries a token. */\nexport class RemountError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RemountError';\n }\n}\n\nexport interface RemountOptions {\n /** Milliseconds between status reads. Default 1000 — the CLI's own pace. */\n readonly intervalMillis?: number;\n /** Status reads before giving up. Default 120, so about two minutes. */\n readonly attempts?: number;\n}\n\nconst record = (value: unknown): Record<string, unknown> | undefined =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n\n/** POST sys/remount and return the migration id. `from`/`to` are full paths (`auth/x` for auth). */\nexport const startRemount = (\n from: string,\n to: string,\n): Effect.Effect<string, BaoError | RemountError, HttpClient.HttpClient> =>\n Effect.flatMap(baoCall('write', 'POST', 'sys/remount', { from, to }), (body) => {\n const id = record(body?.['data'])?.['migration_id'];\n return typeof id === 'string' && id !== ''\n ? Effect.succeed(id)\n : Effect.fail(new RemountError(`sys/remount ${from} -> ${to} answered no migration_id.`));\n });\n\n/** `in-progress`, `success`, `failure` — or undefined when the server no longer knows the id. */\nexport const remountStatus = (\n id: string,\n): Effect.Effect<string | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.map(baoRead(`sys/remount/status/${encodeURIComponent(id)}`), (data) => {\n if (data === undefined) return undefined;\n const status = record(data['migration_info'])?.['status'];\n return typeof status === 'string' ? status : 'unknown';\n });\n\n/**\n * Move `from` to `to` and wait until OpenBao says it is done.\n *\n * @param confirm answers \"does the mount table show the move finished?\" — asked only when the\n * status tracker has forgotten the id. True is success; false fails.\n */\nexport const remountAndWait = (\n from: string,\n to: string,\n confirm: Effect.Effect<boolean, BaoError, HttpClient.HttpClient>,\n options: RemountOptions = {},\n): Effect.Effect<void, BaoError | RemountError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const interval = options.intervalMillis ?? 1000;\n const attempts = Math.max(1, options.attempts ?? 120);\n const id = yield* startRemount(from, to);\n const named = `sys/remount ${from} -> ${to} (migration ${id})`;\n for (let attempt = 1; attempt <= attempts; attempt += 1) {\n const status = yield* remountStatus(id);\n if (status === 'success') return;\n if (status === 'failure') {\n return yield* Effect.fail(\n new RemountError(\n `${named} FAILED. The server log carries the reason, tagged with that migration_id. ` +\n 'Read sys/mounts (or sys/auth) before retrying: the source may be tainted.',\n ),\n );\n }\n if (status === undefined) {\n if (yield* confirm) return;\n return yield* Effect.fail(\n new RemountError(\n `${named}: the server no longer knows the migration (its tracker is in memory, lost ` +\n 'on a restart or leader change), and the mount table does not show the move done.',\n ),\n );\n }\n if (attempt < attempts) yield* Effect.sleep(interval);\n }\n return yield* Effect.fail(\n new RemountError(\n `${named} is still in progress after ${String(attempts)} status reads. Do not re-run ` +\n `until sys/remount/status/${id} settles.`,\n ),\n );\n });\n",
|
|
25
|
+
"/**\n * An OpenBao AppRole auth role — token_policies, TTLs and bind flags. METADATA ONLY.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for why. `role_id` and `secret_id`\n * are credential issuance, not configuration, and are OUT OF SCOPE. This declares the\n * role shape an approle login inherits — policy names and TTL strings only.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role locks out every host that logs in with it:\n * its secret_ids go with it (the ⚠️ on `delete` below). Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport {\n type BaoAuthRoleAttributes,\n type BaoAuthRoleProps,\n attributesOf,\n matches,\n readPath,\n} from './auth-role-form.ts';\nimport { authRoleIdentity, judgeAuthRoleRename } from './auth-role-identity.ts';\nimport { deleteAuthRole, readAuthRole, writeAuthRole } from './auth-role-wire.ts';\nimport { guardRename } from './rename-identity.ts';\n\nexport type { BaoAuthRoleAttributes, BaoAuthRoleProps };\n\nexport interface BaoAuthRole extends Resource<\n 'Bao.AuthRole',\n BaoAuthRoleProps,\n BaoAuthRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoAuthRole = Resource<BaoAuthRole>('Bao.AuthRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/**\n * ⚠️ CASE-INSENSITIVELY, BECAUSE THE SERVER IS. AppRole stores `role/<lowercased name>` (openbao\n * v2.6.2 builtin/credential/approle/path_role.go:1485, and roleEntry reads the same key,\n * :1537), so `Host` → `host` is the SAME role: a `replace` there would write it, then — under\n * `destroy` — delete the old generation, which is that same role.\n */\nconst IDENTITY = authRoleIdentity;\n\nconst readRole = (props: BaoAuthRoleProps) =>\n Effect.gen(function* () {\n const live = yield* readAuthRole(props.name);\n if (live === undefined) return undefined;\n return attributesOf(props, { ...live });\n });\n\nexport const BaoAuthRoleProvider = () =>\n Provider.effect(\n BaoAuthRole,\n Effect.succeed(\n BaoAuthRole.Provider.of({\n /**\n * ⛔ `bao list auth/approle/role` IS NOT A LIST OF THINGS THIS OWNS. Every role\n * in the namespace answers, including break-glass and bootstrap ones. Returning\n * them would invite Alchemy to adopt — and then delete — roles it never created.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(olds);\n const ours = Effect.sync(() => found !== undefined && matches(found, olds));\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A role edited in the OpenBao\n * UI is exactly the drift the check-* gates exist to catch.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A RENAMED ROLE IS A NEW ROLE — NEW role_id, NEW secret_ids — SO IT IS A `replace`,\n * judged before `isResolved(news)` (rename-identity.ts). Until 2026-09-21 a new `name`\n * read nothing, planned `update` and wrote the new role, leaving the old one live\n * under no state record: its secret_ids kept logging in for their whole TTL, and no\n * plan would ever mention it again (REPLACE.md). ⛔ A rename onto a role that exists\n * fails the plan.\n * ⚠️ UNDER THE DEFAULT `retain` THE OLD ROLE STILL STAYS LIVE — retain keeps the old\n * generation of a replace (Apply.ts:2164-2173). For per-host roles (host-approles.ts),\n * opt into `RemovalPolicy.destroy()` or destroy the old role's accessors by hand.\n */\n const move = yield* judgeAuthRoleRename(olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n const live = yield* readRole(news);\n if (live === undefined) return { action: 'update' } as const;\n if (matches(live, news)) return { action: 'noop' } as const;\n return { action: 'update' } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a rename the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n const live = yield* readRole(news);\n const path = readPath(news.name);\n if (live !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.AuthRole ${path}`);\n if (live === undefined || !matches(live, news)) {\n yield* writeAuthRole(news);\n }\n const after = yield* readRole(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(\n `Bao.AuthRole ${news.name}: write returned no error but the role is still absent.`,\n ),\n );\n }\n return after;\n }),\n\n /**\n * ⚠️ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ISSUED. openbao v2.6.2 pathRoleDelete\n * (builtin/credential/approle/path_role.go:1858-1902) deletes every secret_id\n * (flushRoleSecrets, validation.go:420-446), the role_id mapping and the role, so no new\n * login succeeds, and it revokes nothing. A token already issued lives to its TTL; only\n * its renewal fails, because pathLoginRenew (path_login.go:414-438) refuses once the role\n * is gone. So this is not a containment action: to contain a leaked token, revoke it or\n * its accessor. (Corrected 2026-09-21: this said the delete revoked every token.)\n * Idempotent as Alchemy requires — already gone is success — but retain is the default,\n * because every host logging in with the role is locked out at the delete.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* deleteAuthRole(output.name);\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
26
26
|
"import { sha256 } from './digest.ts';\nimport { parseDuration, ttlSeconds } from './mount-form.ts';\n\nexport interface BaoAuthRoleProps {\n /** AppRole name, as `auth/approle/role/{name}` takes it. */\n name: string;\n /** Policies bound to tokens minted through this role. Names only — never a secret. */\n tokenPolicies: readonly string[];\n /** Token TTL, e.g. `15m`. */\n tokenTtl: string;\n /** Token max TTL, e.g. `1h`. */\n tokenMaxTtl: string;\n /** Secret ID TTL — `0` means non-expiring, as reconcile.sh and apply-consumers.py set. */\n secretIdTtl: string;\n /** Whether login requires a secret_id. Defaults to true when omitted on write. */\n bindSecretId?: boolean;\n /** `0` means unlimited uses — the shape reconcile.sh writes for headless roles. */\n secretIdNumUses?: number;\n /**\n * Token period, e.g. `24h` — set only for a periodic (forever-renewable) role, where\n * `tokenTtl`/`tokenMaxTtl` are conventionally `'0'`. Omitted means this declaration does not\n * manage the field: a live role's `token_period` (however it got set) is left untouched, the\n * same way an omitted `bindSecretId` is. See house `openbao/approles.ts` for the role this\n * unblocks — a periodic agent token that was inexpressible with these props.\n */\n tokenPeriod?: string;\n}\n\nexport interface BaoAuthRoleAttributes {\n name: string;\n tokenPolicies: readonly string[];\n tokenTtl: string;\n tokenMaxTtl: string;\n secretIdTtl: string;\n bindSecretId: boolean;\n secretIdNumUses: number;\n tokenPeriod: string;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\nconst policiesOf = (live: Record<string, unknown>): readonly string[] => {\n const raw = live['token_policies'];\n if (!Array.isArray(raw)) return [];\n return raw\n .filter((entry): entry is string => typeof entry === 'string')\n .slice()\n .sort();\n};\n\nconst bool = (value: unknown, fallback: boolean) => (typeof value === 'boolean' ? value : fallback);\n\nconst int = (value: unknown, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n\nconst ttlText = (seconds: number | undefined, fallback = '') => {\n if (seconds === undefined) return fallback;\n if (seconds % 86400 === 0) return `${String(seconds / 86400)}d`;\n if (seconds % 3600 === 0) return `${String(seconds / 3600)}h`;\n if (seconds % 60 === 0) return `${String(seconds / 60)}m`;\n return `${String(seconds)}s`;\n};\n\nexport const attributesOf = (\n props: BaoAuthRoleProps,\n live: Record<string, unknown>,\n): BaoAuthRoleAttributes => {\n const attrs = {\n name: props.name,\n tokenPolicies: policiesOf(live),\n tokenTtl: ttlText(ttlSeconds(live['token_ttl'])),\n tokenMaxTtl: ttlText(ttlSeconds(live['token_max_ttl'])),\n secretIdTtl: ttlText(ttlSeconds(live['secret_id_ttl']), '0'),\n bindSecretId: bool(live['bind_secret_id'], true),\n secretIdNumUses: int(live['secret_id_num_uses'], 0),\n tokenPeriod: ttlText(ttlSeconds(live['token_period']), '0'),\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\nexport const readPath = (name: string) => `auth/approle/role/${name}`;\n\nconst samePolicies = (want: readonly string[], have: readonly string[]) =>\n want.length === have.length && want.every((policy, index) => policy === have[index]);\n\nconst sameTtl = (want: string, have: string) => {\n const wantSeconds = parseDuration(want);\n const haveSeconds = ttlSeconds(have);\n return wantSeconds !== undefined && wantSeconds === haveSeconds;\n};\n\n/** True when live already matches the declaration on every managed field. */\nexport const matches = (attributes: BaoAuthRoleAttributes, props: BaoAuthRoleProps) => {\n const wantPolicies = props.tokenPolicies.slice().sort();\n return (\n samePolicies(wantPolicies, attributes.tokenPolicies) &&\n sameTtl(props.tokenTtl, attributes.tokenTtl) &&\n sameTtl(props.tokenMaxTtl, attributes.tokenMaxTtl) &&\n sameTtl(props.secretIdTtl, attributes.secretIdTtl) &&\n (props.bindSecretId === undefined || attributes.bindSecretId === props.bindSecretId) &&\n (props.secretIdNumUses === undefined || attributes.secretIdNumUses === props.secretIdNumUses) &&\n (props.tokenPeriod === undefined || sameTtl(props.tokenPeriod, attributes.tokenPeriod))\n );\n};\n",
|
|
27
27
|
"/**\n * AppRole METADATA through the named SDK operations (OpenBao 2.6.2 generated schema).\n * ★ pathRoleRead returns nil for absence; logical.RespondErrorCommon turns that read into\n * 404. pathRoleDelete returns nil for an already absent role (204). Reasoned from v2.6.2\n * builtin/credential/approle/path_role.go:1758-1904 and sdk/logical/response_util.go:21-26.\n * ⛔ No role-id, secret-id or login request belongs in this configuration lifecycle.\n */\nimport {\n type AppRoleReadRoleResponse,\n type AppRoleWriteRoleRequest,\n appRoleDeleteRole,\n appRoleReadRole,\n appRoleWriteRole,\n} from '@distilled.cloud/openbao/approle';\nimport * as Effect from 'effect/Effect';\nimport { type BaoAuthRoleProps, readPath } from './auth-role-form.ts';\nimport { BaoError } from './bao-status.ts';\nimport { runBao, runBaoRead, runBaoWrite } from './distilled.ts';\nimport { parseDuration } from './mount-form.ts';\n\nconst identity = (name: string) => ({ approle_mount_path: 'approle', role_name: name });\nconst seconds = (value: unknown): value is number =>\n typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n\n/**\n * The vendor always returns these managed fields (pathRoleRead + tokenutil.PopulateTokenData).\n * Generated response fields are optional, so a proxy's 200 {} must not supply default values.\n * Ignore unmanaged fields: secret_id_bound_cidrs can legitimately be null in the vendor response.\n */\nconst completeRole = (live: AppRoleReadRoleResponse): boolean =>\n live !== null &&\n typeof live === 'object' &&\n typeof live.bind_secret_id === 'boolean' &&\n seconds(live.secret_id_num_uses) &&\n seconds(live.secret_id_ttl) &&\n seconds(live.token_ttl) &&\n seconds(live.token_max_ttl) &&\n seconds(live.token_period) &&\n Array.isArray(live.token_policies) &&\n live.token_policies.every((policy) => typeof policy === 'string');\n\nexport const readAuthRole = (name: string) =>\n runBaoRead(appRoleReadRole(identity(name))).pipe(\n Effect.flatMap((live) =>\n completeRole(live)\n ? Effect.succeed(live)\n : Effect.fail(new BaoError(200, 'GET', readPath(name), ['incomplete role metadata'])),\n ),\n Effect.catchTag('NotFound', () => Effect.succeed(undefined)),\n );\n\nexport const authRoleExists = (name: string) =>\n readAuthRole(name).pipe(Effect.map((live) => live !== undefined));\n\nexport const authRoleRequest = (props: BaoAuthRoleProps) =>\n Effect.gen(function* () {\n const tokenTtl = parseDuration(props.tokenTtl);\n const tokenMaxTtl = parseDuration(props.tokenMaxTtl);\n const secretIdTtl = parseDuration(props.secretIdTtl);\n const tokenPeriod =\n props.tokenPeriod === undefined ? undefined : parseDuration(props.tokenPeriod);\n if (\n !seconds(tokenTtl) ||\n !seconds(tokenMaxTtl) ||\n !seconds(secretIdTtl) ||\n (props.tokenPeriod !== undefined && !seconds(tokenPeriod))\n ) {\n return yield* Effect.fail(\n new BaoError(0, 'POST', readPath(props.name), ['invalid role TTL duration']),\n );\n }\n // ★ The former CLI-style body used strings for every k=v. The SDK schema uses seconds,\n // booleans and arrays; omitted knobs stay omitted on update.\n // pathRoleCreateUpdate preserves absent bind_secret_id/secret_id_num_uses on existing roles.\n // ⛔ token_period, not period — the vendor doc on both fields says period is legacy and loses\n // to token_period when both are set (approle.ts AppRoleWriteRoleRequest); this Resource only\n // ever emits the modern field.\n const request: AppRoleWriteRoleRequest = {\n ...identity(props.name),\n token_policies: [...props.tokenPolicies],\n token_ttl: tokenTtl,\n token_max_ttl: tokenMaxTtl,\n secret_id_ttl: secretIdTtl,\n ...(props.bindSecretId === undefined ? {} : { bind_secret_id: props.bindSecretId }),\n ...(props.secretIdNumUses === undefined ? {} : { secret_id_num_uses: props.secretIdNumUses }),\n ...(tokenPeriod === undefined ? {} : { token_period: tokenPeriod }),\n };\n return request;\n });\n\n/**\n * ★ A FULL-REPLACE WRITE, like the policy write: every managed field travels in the request\n * every time (only genuinely omitted knobs stay omitted), so a transport failure is safe to\n * retry through `runBaoWrite` — the replay sends the identical desired state.\n */\nexport const writeAuthRole = (props: BaoAuthRoleProps) =>\n authRoleRequest(props).pipe(Effect.flatMap((request) => runBaoWrite(appRoleWriteRole(request))));\n\n/** Other typed SDK failures, including denied deletes, propagate unchanged. */\nexport const deleteAuthRole = (name: string) =>\n runBao(appRoleDeleteRole(identity(name))).pipe(Effect.catchTag('NotFound', () => Effect.void));\n",
|
|
28
|
-
"/**\n * The SDK shares Bao's existing call-time environment and process-wide concurrency gate.\n * Merely supplying HttpClient does not apply that gate: legacy calls acquire it in baoCall.\n * ⛔ `runBao` ITSELF NEVER RETRIES: an interrupted call may already have reached the vault, and\n * replaying a non-idempotent operation (a delete whose 404-is-success path already ran, a login,\n * a credential issuance) could repeat a side effect. `runBaoRead` and `runBaoWrite` opt specific,\n * known-idempotent call shapes back into the bounded transport retry baoCall always had.\n */\nimport { Credentials, normalizeBaseUrl } from '@distilled.cloud/openbao/Credentials';\nimport type { OpenBaoOpContext } from '@distilled.cloud/openbao/Protocol';\nimport * as Retry from '@distilled.cloud/openbao/Retry';\nimport type * as Cause from 'effect/Cause';\nimport type * as Duration from 'effect/Duration';\nimport * as Effect from 'effect/Effect';\nimport * as Redacted from 'effect/Redacted';\nimport * as Semaphore from 'effect/Semaphore';\nimport type * as HttpClient from 'effect/
|
|
28
|
+
"/**\n * The SDK shares Bao's existing call-time environment and process-wide concurrency gate.\n * Merely supplying HttpClient does not apply that gate: legacy calls acquire it in baoCall.\n * ⛔ `runBao` ITSELF NEVER RETRIES: an interrupted call may already have reached the vault, and\n * replaying a non-idempotent operation (a delete whose 404-is-success path already ran, a login,\n * a credential issuance) could repeat a side effect. `runBaoRead` and `runBaoWrite` opt specific,\n * known-idempotent call shapes back into the bounded transport retry baoCall always had.\n */\nimport { Credentials, normalizeBaseUrl } from '@distilled.cloud/openbao/Credentials';\nimport type { OpenBaoOpContext } from '@distilled.cloud/openbao/Protocol';\nimport * as Retry from '@distilled.cloud/openbao/Retry';\nimport type * as Cause from 'effect/Cause';\nimport type * as Duration from 'effect/Duration';\nimport * as Effect from 'effect/Effect';\nimport * as Redacted from 'effect/Redacted';\nimport * as Semaphore from 'effect/Semaphore';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { isHttpClientError } from 'effect/http/HttpClientError';\nimport { readBaoVariable, resolveAddress } from './bao-address.ts';\nimport {\n BAO_TIMEOUT,\n BaoEnv,\n BaoGate,\n overSocket,\n redactingToken,\n retryTransport,\n} from './bao-http.ts';\nimport { BaoError } from './bao-status.ts';\n\nexport const runBao = <A, E>(\n operation: Effect.Effect<A, E, OpenBaoOpContext>,\n timeout: Duration.Input = BAO_TIMEOUT,\n): Effect.Effect<A, E | BaoError | Cause.TimeoutError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const env = yield* BaoEnv;\n const address = resolveAddress(env);\n const token = readBaoVariable(env, 'BAO_TOKEN');\n const gate = yield* BaoGate;\n return yield* operation.pipe(\n Effect.provideService(\n Credentials,\n Effect.succeed({\n apiBaseUrl: normalizeBaseUrl(address.base),\n ...(address.namespace === undefined ? {} : { namespace: address.namespace }),\n ...(token === '' ? {} : { token: Redacted.make(token) }),\n }),\n ),\n Retry.none,\n // ⛔ HttpClientError holds the request, including X-Vault-Token. Trace redaction is\n // fiber-local and gone when an error is serialized later; keep only its safe message,\n // as baoCall does. SDK status/resource errors retain their original typed identity.\n Effect.mapError((cause) =>\n isHttpClientError(cause) ? new BaoError(0, 'SDK', 'operation', [cause.message]) : cause,\n ),\n // ★ A queued call has not reached the server: acquire the shared permit outside the timeout.\n Effect.timeout(timeout),\n overSocket(address.socket, 'SDK', 'operation'),\n redactingToken,\n Semaphore.withPermits(gate, 1),\n );\n });\n\n/**\n * Reads use the existing two transport retries (750 ms between attempts). Each attempt\n * reacquires the shared permit and its own bounded timeout. Typed SDK status and decoding\n * failures still propagate immediately; a read is always safe to replay because it never\n * changes vault state.\n */\nexport const runBaoRead = <A, E>(\n operation: Effect.Effect<A, E, OpenBaoOpContext>,\n timeout: Duration.Input = BAO_TIMEOUT,\n): Effect.Effect<A, E | BaoError | Cause.TimeoutError, HttpClient.HttpClient> =>\n retryTransport(runBao(operation, timeout));\n\n/**\n * The pre-PR `baoCall()` retried every call, writes included; that bound was lost when the\n * distilled SDK path landed with `Retry.none` on `runBao`. Restore it for the writes where\n * replaying is safe: a FULL-REPLACE, idempotent write (an OpenBao policy PUT, an AppRole\n * write) sends the complete desired state every time, so retrying an uncertain transport\n * failure converges on the same result rather than compounding a partial change. A create\n * that mints a new identifier, or any operation whose second attempt could do something the\n * first did not, must keep calling `runBao` directly and make one attempt.\n */\nexport const runBaoWrite = <A, E>(\n operation: Effect.Effect<A, E, OpenBaoOpContext>,\n timeout: Duration.Input = BAO_TIMEOUT,\n): Effect.Effect<A, E | BaoError | Cause.TimeoutError, HttpClient.HttpClient> =>\n retryTransport(runBao(operation, timeout));\n",
|
|
29
29
|
"/**\n * Rename safety for the families whose identity is a name, a mount and a name, or a catalog key:\n * the primitives. rename-identity.ts builds each family's diff and reconcile step from them, and\n * REPLACE.md has the audit and what each answer does.\n *\n * ⛔ THE BUG THIS CLOSES, REPRODUCED 2026-09-21 AGAINST alchemy@2.0.0-beta.79's OWN PLAN AND APPLY\n * (fake-stack.ts): a Bao.Policy deployed as `old`, then redeclared as `new` under\n * `RemovalPolicy.destroy()`, planned `update` and left BOTH policies live. diff read the NEW\n * path, found nothing, answered `update`, and reconcile wrote the new object. The old one stayed\n * live under no state record, so no later plan would mention it, and not even `destroy` could\n * remove it.\n * ★ A CHANGED IDENTITY IS A DIFFERENT OBJECT, SO THE ANSWER IS `replace`. Create-first\n * (`deleteFirst` false): the new path never collides with the old, the new generation is written,\n * dependents are updated in the same graph, and only then is the old generation deleted. The\n * engine hands that delete the OLD generation's attributes (Apply.ts deleteOldGenerations and the\n * GC pass both pass `output: old.attr`), and every delete here reads `output`, never `news`.\n * ⛔ A new path that collides with ANOTHER live object is refused at plan instead (`judgeMove`).\n * ⚠️ UNDER `retain` THE OLD OBJECT STAYS LIVE. Apply.ts:2164-2173 skips the old generation's delete\n * and logs \"Retaining replaced resource (removal policy: retain)\". The plan still says `replace`\n * and the apply says what it kept, so it is no longer silent, but the old object is unmanaged\n * from then on. Remove it by hand, or opt into `RemovalPolicy.destroy()`.\n */\nimport * as Effect from 'effect/Effect';\nimport { baoRead } from './bao-http.ts';\n\nconst exact = (identity: string): string => identity;\n\n/**\n * A string prop of a diff's `news`, once that one prop is resolved; `undefined` while it is still an\n * Output of a changing upstream (a function-typed proxy) or an Effect.\n *\n * ★ THE IDENTITY IS JUDGED BEFORE `isResolved(news)`. That guard returns `undefined` when ANY prop is\n * pending, and the engine then falls back to `update` (Plan.ts, `havePropsChanged`). A rename that\n * lands in the same deploy as a pending `fragments` or `policies` Output would slip through as\n * `update`, which is the orphan again. launchd/host-effect.ts reads its identity the same way.\n */\nexport const declaredString = (news: unknown, key: string): string | undefined => {\n if (typeof news !== 'object' || news === null) return undefined;\n const value: unknown = (news as Record<string, unknown>)[key];\n return typeof value === 'string' ? value : undefined;\n};\n\n/** True while an optional prop is declared but is not yet a value: an Output of a changing upstream. */\nexport const isPendingProp = (news: unknown, key: string): boolean => {\n if (typeof news !== 'object' || news === null) return false;\n const value: unknown = (news as Record<string, unknown>)[key];\n return value !== undefined && typeof value !== 'string';\n};\n\n/**\n * An optional string prop: `fallback` when it is absent, undefined while it is still an Output.\n * ⚠️ Not `declaredString(…) ?? fallback`, which would read a pending mount as the default mount.\n */\nexport const declaredOr = (news: unknown, key: string, fallback: string): string | undefined =>\n isPendingProp(news, key) ? undefined : (declaredString(news, key) ?? fallback);\n\n/**\n * A role's API path from a diff's `news`, once both `mount` and `name` are resolved. `defaultMount`\n * is what an absent `mount` means; without one, an absent mount is unknown.\n */\nexport const declaredRolePath = (\n news: unknown,\n rolePath: (mount: string, name: string) => string,\n defaultMount?: string,\n): string | undefined => {\n const mount =\n defaultMount === undefined\n ? declaredString(news, 'mount')\n : declaredOr(news, 'mount', defaultMount);\n const name = declaredString(news, 'name');\n return mount === undefined || name === undefined ? undefined : rolePath(mount, name);\n};\n\n/**\n * How OpenBao keys an ACL policy: trimmed and lowercased. openbao v2.6.2\n * vault/policy/policy_store.go:698-700 (`sanitizeName`), applied by SetPolicy (:268), GetPolicy\n * (:378) and DeletePolicy (:562).\n *\n * ⛔ SO `Admin` → `admin` IS THE SAME POLICY, NOT A RENAME. A `replace` there would write it, and then,\n * under `destroy`, delete the old generation, which is that same policy. Every grant it carries\n * would be revoked by a change of case.\n */\nexport const policyKey = (name: string): string => name.trim().toLowerCase();\n\n/**\n * Whether the declared identity names a different object than the one in state: `true` → moved (the\n * diff asks `judgeMove`, which also reads the target); `false` → the same object; `undefined` → not\n * knowable yet, because the declared side is still an Output. `key` is how the SERVER keys the object (`policyKey`); the default is exact,\n * which is right for a mount path (vault/routing/router.go folds no case) and for both plugins'\n * roles (each stores `roles/<name>` verbatim).\n *\n * ⛔ NEVER `replace` ON AN UNKNOWN IDENTITY. The Output may resolve to the same path, and a replace\n * onto the same path deletes, under `destroy`, the object it has just written. The diff defers\n * instead. If the engine then plans `update` and the identity turns out to have changed,\n * `refuseMovedUpdate` stops reconcile before it writes anything.\n */\nexport const isMoved = (\n stored: string,\n declared: string | undefined,\n key: (identity: string) => string = exact,\n): boolean | undefined => (declared === undefined ? undefined : key(stored) !== key(declared));\n\n/**\n * The diff's first question, asked before `isResolved(news)`: the move from the identity this\n * resource last wrote or tried (`tried`) to the declared one, or undefined when both name the same\n * object or either is still unknown. `pathOf` is the API path an identity is read at.\n *\n * ⛔ A MOVE ONTO AN OBJECT THAT ALREADY EXISTS FAILS THE PLAN. MEASURED 2026-09-21 through the engine\n * (rename-occupied.test.ts): two policies that swapped names under `RemovalPolicy.destroy()` each\n * planned `replace`, each new generation wrote over the other's live policy, and each old\n * generation's delete then removed the name the other had just written. The deploy was green and\n * both policies were gone, every grant revoked. A shift (a → b while b → c), and a move onto the\n * name of a resource leaving the stack, were measured ending the same way. So was reverting a\n * move whose new generation failed: the old generation still holds the name, and its delete runs\n * after the revert has rewritten it. That is why `tried` falls back to the props of an unfinished\n * write.\n * ⚠️ THE DIFF CANNOT SEE THE REMOVAL POLICY, SO THIS REFUSES UNDER `retain` TOO, where a swap, or a\n * move back onto a retained old generation, would have been harmless. The cost is a move in two\n * deploys through a free name, or removing the target by hand. The alternative is a green deploy\n * that deletes what it has just written.\n * ★ ONE PLAN-TIME READ, OF A PATH THE NEW GENERATION'S RECONCILE READS ANYWAY. A 404, a missing mount\n * included, is free; a refused read fails the plan, as any other diff read does.\n */\nexport const judgeMove = (\n family: string,\n tried: string | undefined,\n declared: string | undefined,\n pathOf: (identity: string) => string,\n key: (identity: string) => string = exact,\n) =>\n judgeMoveWith(\n family,\n tried,\n declared,\n (identity) => Effect.map(baoRead(pathOf(identity)), (value) => value !== undefined),\n key,\n );\n\n/** SDK families supply their own typed read so a rename cannot fall back to raw HTTP. */\nexport const judgeMoveWith = <E, R>(\n family: string,\n tried: string | undefined,\n declared: string | undefined,\n occupied: (identity: string) => Effect.Effect<boolean, E, R>,\n key: (identity: string) => string = exact,\n) =>\n Effect.gen(function* () {\n if (tried === undefined || declared === undefined || key(tried) === key(declared)) {\n return undefined;\n }\n if (!(yield* occupied(declared))) return { from: tried, to: declared };\n return yield* Effect.die(\n new Error(\n `${family}: ${tried} → ${declared} would land on an object that already exists at ` +\n `${declared}. Under RemovalPolicy.destroy() a resource moving off that name (a swap, a ` +\n 'shift, or a reverted move that did not finish) deletes it after this one writes it. ' +\n 'Nothing was written. Move through a name nothing holds, in two deploys, or remove ' +\n `${declared} by hand first.`,\n ),\n );\n });\n\n/**\n * Reconcile's guard: an `update` whose prior attributes name another object.\n *\n * ★ REACHED ONLY WHEN THE DIFF COULD NOT SEE THE NEW IDENTITY at plan time. A fresh create, and the\n * new generation of a `replace`, both reach reconcile with `output` undefined (Apply.ts passes\n * `output: attr`, which is empty for a new generation). An `update` reaches it with the previous\n * generation's attributes.\n * ★ THE FAILED DEPLOY SETTLES ITSELF. Apply has already committed the row as `updating`, with the new\n * props and the OLD attributes. By the next plan the upstream Output has landed, so the diff sees\n * both names and answers `replace` (or refuses, if the new name is already taken: `judgeMove`).\n * The old object is then deleted, or retained, by the removal policy, with no hand repair.\n */\nexport const refuseMovedUpdate = (family: string, from: string, to: string) =>\n Effect.die(\n new Error(\n `${family}: planned as an update, but its identity moved from ${from} to ${to}. Writing ` +\n `${to} now would leave ${from} live with no state record. Nothing was written. Run the ` +\n 'deploy again: once the value resolves at plan time it plans as a replace.',\n ),\n );\n",
|
|
30
30
|
"/**\n * The rename guard every Bao.* family whose identity is a name, a mount, or a catalog key shares:\n * one `Identity` per family, and two steps built from rename.ts, `judgeRename` at the top of `diff`\n * and `guardRename` at the top of `reconcile`. REPLACE.md has the audit behind both.\n *\n * ★ ONE DESCRIPTION OF \"WHICH OBJECT\", NOT TWELVE COPIES OF THE CHECK. The rename-safety fix went\n * in family by family, and the families it skipped were the ones that kept the bug: nine of them\n * judged the identity only after `isResolved(news)` and never asked whether the new path was\n * taken. 🔴 MEASURED 2026-09-21 through the engine (rename-families.test.ts): two Bao.AuthRole,\n * Bao.PkiRole, Bao.JwtRole, Bao.KubernetesRole, Bao.SshRole or Bao.Plugin resources that swapped\n * names under `RemovalPolicy.destroy()` both planned `replace`, each wrote over the other, and\n * both old deletes then removed what had just been written: a green deploy, both objects gone.\n * With any other prop still an Output, all nine planned `update` and left the old object live\n * under no state record; for Bao.MfaTotpMethod that wrote a second method and stranded every\n * enrolment.\n */\nimport * as Effect from 'effect/Effect';\nimport {\n declaredRolePath,\n declaredString,\n isMoved,\n judgeMove,\n refuseMovedUpdate,\n} from './rename.ts';\n\n/** How one family names the object it manages — the thing a rename changes. */\nexport interface Identity<A> {\n /** `Bao.JwtRole` etc., for messages. */\n readonly family: string;\n /** The identity a set of props declares; undefined while any part of it is still an Output. */\n readonly declared: (props: unknown) => string | undefined;\n /** The identity a generation's attributes record. */\n readonly recorded: (output: A) => string;\n /** The API path an identity is read at, for the occupied check. Default: the identity. */\n readonly pathOf?: ((identity: string) => string) | undefined;\n /** How the server keys it (`policyKey`). Default: exact. */\n readonly key?: ((identity: string) => string) | undefined;\n}\n\n/** A family keyed by `name` alone, read at `pathOf(name)`. */\nexport const nameIdentity = <A extends { readonly name: string }>(\n family: string,\n pathOf: (name: string) => string,\n key?: (name: string) => string,\n): Identity<A> => ({\n declared: (props) => declaredString(props, 'name'),\n family,\n key,\n pathOf,\n recorded: (output) => output.name,\n});\n\n/**\n * A role at `rolePath(mount, name)`; the identity is that path. `defaultMount` is what an absent\n * `mount` prop means — undefined when `mount` is required.\n */\nexport const roleIdentity = <A extends { readonly mount: string; readonly name: string }>(\n family: string,\n rolePath: (mount: string, name: string) => string,\n defaultMount?: string,\n key?: (path: string) => string,\n): Identity<A> => ({\n declared: (props) => declaredRolePath(props, rolePath, defaultMount),\n family,\n key,\n recorded: (output) => rolePath(output.mount, output.name),\n});\n\n/**\n * ⚠️ THE LAST SEGMENT LOWERCASED: a role store that folds the name and not the mount. openbao v2.6.2\n * AppRole (builtin/credential/approle/path_role.go:1485, :1537) and Kubernetes\n * (builtin/credential/kubernetes/backend.go:362, path_role.go:396) both store `role/<lowercased\n * name>`, and JWT reads its `name` as a TypeLowerCaseString (builtin/credential/jwt/path_role.go:77),\n * while the router folds no case in a mount path. So `Host` → `host` is the same role, never a\n * replace that would delete, under `destroy`, the role it had just written.\n */\nexport const foldName = (path: string): string =>\n path.replace(/[^/]+$/, (name) => name.toLowerCase());\n\n/**\n * `diff`'s first step, before `isResolved(news)`: the move from the identity this resource last\n * wrote or tried to the declared one, or undefined when both name the same object or either is not\n * known yet. ⛔ Fails the plan when the new identity is already taken (`judgeMove`).\n *\n * ★ `olds` STANDS IN FOR `output` WHILE A CREATE OR A REPLACEMENT IS UNFINISHED, which is what\n * catches reverting a move whose new generation failed (rename.ts, `judgeMove`).\n */\nexport const judgeRename = <A>(\n identity: Identity<A>,\n olds: unknown,\n news: unknown,\n output: A | undefined,\n) =>\n judgeMove(\n identity.family,\n output === undefined ? identity.declared(olds) : identity.recorded(output),\n identity.declared(news),\n identity.pathOf ?? ((path) => path),\n identity.key,\n );\n\n/**\n * `reconcile`'s first step: an `update` whose prior attributes name another object dies before any\n * read or write (`refuseMovedUpdate`). Only reached when the diff could not see the new identity.\n */\nexport const guardRename = <A>(\n identity: Identity<A>,\n news: unknown,\n output: A | undefined,\n): Effect.Effect<void> => {\n if (output === undefined) return Effect.void;\n const from = identity.recorded(output);\n const to = identity.declared(news);\n return to !== undefined && isMoved(from, to, identity.key) === true\n ? refuseMovedUpdate(identity.family, from, to)\n : Effect.void;\n};\n",
|
|
31
31
|
"import { readPath } from './auth-role-form.ts';\nimport { authRoleExists } from './auth-role-wire.ts';\nimport { declaredString, judgeMoveWith } from './rename.ts';\nimport { foldName, nameIdentity } from './rename-identity.ts';\n\nexport const authRoleIdentity = nameIdentity<{ readonly name: string }>(\n 'Bao.AuthRole',\n readPath,\n foldName,\n);\n\n/** All occupied-name reads share the SDK's typed absence and refusal behavior. */\nexport const judgeAuthRoleRename = (\n olds: unknown,\n news: unknown,\n output: { readonly name: string } | undefined,\n) =>\n judgeMoveWith(\n 'Bao.AuthRole',\n output === undefined ? declaredString(olds, 'name') : output.name,\n declaredString(news, 'name'),\n authRoleExists,\n foldName,\n );\n",
|
|
32
|
-
"/**\n * Refuse to plan against the wrong vault: assert the `cluster_name` and namespace a stack expects\n * BEFORE any Bao.* resource reads or writes.\n *\n * ⛔ WHY IT EXISTS. A `BAO_ADDR` left exported for one vault (or a `BAO_AGENT_ADDR`, which wins)\n * would otherwise apply a stack written for another vault to it, and every family here would\n * plan CREATEs against the wrong server with a clean conscience (the estate's site-config plan,\n * \"Identity checks on every live plan\").\n * A missing `BAO_NAMESPACE` does the same thing one level down: the stack lands in root.\n *\n * ★ `sys/health`, UNAUTHENTICATED, WITH NO TOKEN AND NO NAMESPACE HEADER. READ FROM openbao v2.6.2:\n * · http/sys_health.go:143-165 — `cluster_name` and `cluster_id` are filled ONLY while unsealed,\n * and the body is top-level JSON, not wrapped in `data`.\n * · http/handler.go:108-124, :405-411 — `health` is a root-only API: a request carrying\n * `X-Vault-Namespace` is answered 400 \"operation unavailable in namespaces\". So the header is\n * stripped for this one call, whatever BAO_NAMESPACE says.\n * · The query asks for 200 when sealed, uninitialised or standby (`sealedcode`, `uninitcode`,\n * `standbyok`, :78-110), so the body is always there to read and the refusal can say WHICH.\n * ⛔ NO TOKEN IS SENT. Until this check passes, the server has not even claimed to be ours, and a\n * token sent to the wrong server is a token handed over.\n * ⚠️ IT CATCHES A MISTARGET, NOT AN IMPOSTOR (review 2026-09-21). `cluster_name` is answered to\n * anyone, unauthenticated, so a hostile server can echo the expected one; passing proves the\n * address is configured right, never who answers. TLS to a trusted certificate is what\n * authenticates the server — keep an https BAO_ADDR on anything that is not loopback or a socket.\n * ★ THE NAMESPACE IS CHECKED TWICE. Locally first: the namespace every later call will send (the\n * same bao-address.ts resolution) must BE the expected one. Then remotely: unauthenticated\n * `sys/internal/ui/mounts` with that namespace header answers 200 when the namespace exists and\n * 404 \"namespace not found\" when it does not (vault/request_handling.go:607-612; the path is in\n * the system backend's Unauthenticated list, vault/logical_system.go:95). Only the status is read.\n * REASONED FROM SOURCE, not measured against a live server.\n * ⚠️ IT PROVES THE CLUSTER, NOT THE NODE. A standby answers with the cluster's name, which is the\n * point: a standby forwards to the same vault.\n */\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/
|
|
32
|
+
"/**\n * Refuse to plan against the wrong vault: assert the `cluster_name` and namespace a stack expects\n * BEFORE any Bao.* resource reads or writes.\n *\n * ⛔ WHY IT EXISTS. A `BAO_ADDR` left exported for one vault (or a `BAO_AGENT_ADDR`, which wins)\n * would otherwise apply a stack written for another vault to it, and every family here would\n * plan CREATEs against the wrong server with a clean conscience (the estate's site-config plan,\n * \"Identity checks on every live plan\").\n * A missing `BAO_NAMESPACE` does the same thing one level down: the stack lands in root.\n *\n * ★ `sys/health`, UNAUTHENTICATED, WITH NO TOKEN AND NO NAMESPACE HEADER. READ FROM openbao v2.6.2:\n * · http/sys_health.go:143-165 — `cluster_name` and `cluster_id` are filled ONLY while unsealed,\n * and the body is top-level JSON, not wrapped in `data`.\n * · http/handler.go:108-124, :405-411 — `health` is a root-only API: a request carrying\n * `X-Vault-Namespace` is answered 400 \"operation unavailable in namespaces\". So the header is\n * stripped for this one call, whatever BAO_NAMESPACE says.\n * · The query asks for 200 when sealed, uninitialised or standby (`sealedcode`, `uninitcode`,\n * `standbyok`, :78-110), so the body is always there to read and the refusal can say WHICH.\n * ⛔ NO TOKEN IS SENT. Until this check passes, the server has not even claimed to be ours, and a\n * token sent to the wrong server is a token handed over.\n * ⚠️ IT CATCHES A MISTARGET, NOT AN IMPOSTOR (review 2026-09-21). `cluster_name` is answered to\n * anyone, unauthenticated, so a hostile server can echo the expected one; passing proves the\n * address is configured right, never who answers. TLS to a trusted certificate is what\n * authenticates the server — keep an https BAO_ADDR on anything that is not loopback or a socket.\n * ★ THE NAMESPACE IS CHECKED TWICE. Locally first: the namespace every later call will send (the\n * same bao-address.ts resolution) must BE the expected one. Then remotely: unauthenticated\n * `sys/internal/ui/mounts` with that namespace header answers 200 when the namespace exists and\n * 404 \"namespace not found\" when it does not (vault/request_handling.go:607-612; the path is in\n * the system backend's Unauthenticated list, vault/logical_system.go:95). Only the status is read.\n * REASONED FROM SOURCE, not measured against a live server.\n * ⚠️ IT PROVES THE CLUSTER, NOT THE NODE. A standby answers with the cluster's name, which is the\n * point: a standby forwards to the same vault.\n */\nimport * as Effect from 'effect/Effect';\nimport * as FetchHttpClient from 'effect/http/FetchHttpClient';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { type BaoEnvironment, resolveAddress } from './bao-address.ts';\nimport { BaoEnv, baoCall } from './bao-http.ts';\nimport { canonicalNamespace, envNamespace, namespaceLabel } from './bao-namespace.ts';\nimport type { BaoError } from './bao-status.ts';\n\n/** `input` a blank expectation · `mismatch` the wrong vault · `unconfirmed` could not tell · `unreachable` no answer. */\nexport type BaoIdentityFailure = 'input' | 'mismatch' | 'unconfirmed' | 'unreachable';\n\n/** ⛔ Every message starts `REFUSING:`, and none carries a token — only the address and names. */\nexport class BaoIdentityError extends Error {\n constructor(\n readonly reason: BaoIdentityFailure,\n detail: string,\n ) {\n super(`REFUSING: ${detail}`);\n this.name = 'BaoIdentityError';\n }\n}\n\nexport interface BaoIdentityExpected {\n /** The vault's `cluster_name` (server config `cluster_name`, or the one generated at init). */\n readonly clusterName: string;\n /** The namespace the stack targets: `team-a`, or `''` / `root` for the root namespace. */\n readonly namespace: string;\n}\n\n/** What the vault said about itself once every check passed. */\nexport interface BaoIdentity {\n /** The resolved address, without any token. */\n readonly address: string;\n readonly clusterName: string;\n readonly clusterId: string;\n readonly version: string;\n /** Canonical: `''` is root. */\n readonly namespace: string;\n}\n\nexport const HEALTH_PATH = 'sys/health?standbyok=true&sealedcode=200&uninitcode=200';\nexport const NAMESPACE_PROBE_PATH = 'sys/internal/ui/mounts';\n\nconst addressOf = (env: BaoEnvironment) => {\n const address = resolveAddress(env);\n return address.socket === undefined ? address.base : `unix://${address.socket}`;\n};\n\nconst unreachable =\n (address: string, what: string) =>\n (error: BaoError): BaoIdentityError =>\n new BaoIdentityError('unreachable', `${address} did not answer ${what}: ${error.message}`);\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\n/** Read a health body into the one question asked of it. Pure, for the tests. */\nexport const checkHealth = (\n address: string,\n expectedCluster: string,\n body: Record<string, unknown> | undefined,\n): { readonly clusterId: string; readonly version: string } | BaoIdentityError => {\n if (body === undefined || typeof body['sealed'] !== 'boolean') {\n return new BaoIdentityError(\n 'unconfirmed',\n `${address} answered sys/health, but not as OpenBao.`,\n );\n }\n if (body['initialized'] === false) {\n return new BaoIdentityError('unconfirmed', `${address} is not initialised.`);\n }\n if (body['sealed'] === true) {\n return new BaoIdentityError(\n 'unconfirmed',\n `${address} is sealed, and a sealed vault does not report its cluster_name.`,\n );\n }\n const clusterName = text(body['cluster_name']);\n if (clusterName !== expectedCluster) {\n return new BaoIdentityError(\n 'mismatch',\n `${address} answers as cluster \\`${clusterName || '(none)'}\\`, but this stack expects ` +\n `\\`${expectedCluster}\\`. Check BAO_ADDR and BAO_AGENT_ADDR (the agent address wins).`,\n );\n }\n return { clusterId: text(body['cluster_id']), version: text(body['version']) };\n};\n\n/**\n * The check, as an Effect under BaoEnv (process.env unless provided). Fails with BaoIdentityError\n * and nothing else.\n */\nexport const assertBaoIdentityEffect = (\n expected: BaoIdentityExpected,\n): Effect.Effect<BaoIdentity, BaoIdentityError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const env = yield* BaoEnv;\n const address = addressOf(env);\n const clusterName = expected.clusterName.trim();\n if (clusterName === '') {\n return yield* Effect.fail(\n new BaoIdentityError('input', 'clusterName is empty, so there is nothing to compare.'),\n );\n }\n const namespace = canonicalNamespace(expected.namespace);\n const sent = envNamespace(env);\n if (sent !== namespace) {\n return yield* Effect.fail(\n new BaoIdentityError(\n 'mismatch',\n `BAO_NAMESPACE resolves to \\`${namespaceLabel(sent)}\\`, but this stack expects ` +\n `\\`${namespaceLabel(namespace)}\\`.`,\n ),\n );\n }\n\n const anonymous = { ...env, BAO_NAMESPACE: '', BAO_TOKEN: '' };\n const body = yield* baoCall('read', 'GET', HEALTH_PATH).pipe(\n Effect.provideService(BaoEnv, anonymous),\n Effect.mapError(unreachable(address, 'sys/health')),\n );\n const health = checkHealth(address, clusterName, body);\n if (health instanceof BaoIdentityError) return yield* Effect.fail(health);\n\n if (namespace !== '') {\n const scoped = { ...env, BAO_NAMESPACE: namespace, BAO_TOKEN: '' };\n const probe = yield* baoCall('read', 'GET', NAMESPACE_PROBE_PATH).pipe(\n Effect.provideService(BaoEnv, scoped),\n Effect.mapError(unreachable(address, `the namespace probe for \\`${namespace}\\``)),\n );\n if (probe === undefined) {\n return yield* Effect.fail(\n new BaoIdentityError(\n 'mismatch',\n `cluster \\`${clusterName}\\` at ${address} has no namespace \\`${namespace}\\`.`,\n ),\n );\n }\n }\n return { address, clusterName, namespace, ...health };\n });\n\n/**\n * `assertBaoIdentityEffect` for a plain script. `env` defaults to `process.env`, read at call time.\n * ★ Rejects with the BaoIdentityError itself (Effect.runPromise, as in approle-login.ts).\n *\n * await assertBaoIdentity({ clusterName: 'vault-example', namespace: 'team-a' });\n */\nexport const assertBaoIdentity = (\n input: BaoIdentityExpected & { readonly env?: BaoEnvironment },\n): Promise<BaoIdentity> => {\n const effect = assertBaoIdentityEffect(input);\n const scoped =\n input.env === undefined ? effect : Effect.provideService(effect, BaoEnv, input.env);\n return Effect.runPromise(scoped.pipe(Effect.provide(FetchHttpClient.layer)));\n};\n",
|
|
33
33
|
"/**\n * Namespace spellings, made comparable. `homeflare`, `/homeflare/` and `homeflare/` are one\n * namespace to OpenBao, and `root` (or nothing) is the root namespace.\n *\n * ★ READ FROM openbao v2.6.2: namespace.Canonicalize trims the leading slash and appends a trailing\n * one, and ResolveNamespaceFromRequest (vault/namespace_store.go:1573-1598) re-routes a header\n * that is literally `root/` to the root namespace. A namespace's own `namespace_path` in an API\n * answer is that canonical form: `''` for root, `a/b/` below it (vault/login_mfa.go\n * mfaConfigToMap and mfaLoginEnforcementConfigToMap).\n */\nimport { type BaoEnvironment, resolveAddress } from './bao-address.ts';\nimport { trimSlashes } from './mount-path.ts';\n\n/** The bare name: no leading or trailing slash, and `''` for the root namespace. */\nexport const canonicalNamespace = (namespace: string | undefined): string => {\n const bare = trimSlashes((namespace ?? '').trim());\n return bare === 'root' ? '' : bare;\n};\n\n/** OpenBao's `namespace_path` rendering of the same namespace: `''` or `a/b/`. */\nexport const namespacePath = (namespace: string | undefined): string => {\n const bare = canonicalNamespace(namespace);\n return bare === '' ? '' : `${bare}/`;\n};\n\n/** The namespace every call under `env` targets, canonical. */\nexport const envNamespace = (env: BaoEnvironment): string =>\n canonicalNamespace(resolveAddress(env).namespace);\n\n/** How a namespace reads in a message: `root` rather than an empty pair of backticks. */\nexport const namespaceLabel = (namespace: string): string =>\n namespace === '' ? 'root' : namespace;\n",
|
|
34
|
-
"/**\n * A role on one of the six Cloudflare secrets-engine mounts — what one consumer may mint: the\n * Cloudflare policy its tokens carry and the lease bounds they get. METADATA ONLY.\n *\n * ★ THE PORT OF apply-roles.py's WRITE. roles.yaml expands to these (cloudflare-roles-expand.ts),\n * and what used to be `bao write <mount>/roles/<name> ttl= max_ttl= description= policies=` is\n * reconcile below. The props name permission groups; CloudflarePermissionGroups turns them into\n * IDs at diff and reconcile time.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see cloudflare-role-form.ts. ⛔ AND ISSUANCE IS NOT THIS\n * RESOURCE: `<mount>/creds/<name>` returns a LIVE Cloudflare token, and a token declared as a\n * resource would outlive its lease in Alchemy's unencrypted state (proxmox-role.ts has the four\n * places it would land). This declares the door; minting is a runtime call.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from it,\n * and apply-roles.py never deleted one either: an unexplained role was reported UNTRACKED and\n * left alone (apply-roles.py:190-196). Opt in with `.pipe(RemovalPolicy.destroy())`.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { groupKey, scopeOfResource } from './cloudflare-group-scope.ts';\nimport { CloudflarePermissionGroups, type GroupRef } from './cloudflare-permission-groups.ts';\nimport { resolvePolicies } from './cloudflare-policy.ts';\nimport {\n type BaoCloudflareRoleAttributes,\n type BaoCloudflareRoleProps,\n attributesOf,\n differences,\n refusalOf,\n rolePath,\n writeBody,\n} from './cloudflare-role-form.ts';\nimport {\n deleteCloudflareRole,\n readCloudflareRole,\n writeCloudflareRole,\n} from './cloudflare-role-wire.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoCloudflareRoleAttributes, BaoCloudflareRoleProps };\n\n/**\n * ⚠️ CloudflarePermissionGroups IS NOT A REQUIREMENT OF THE RESOURCE. The provider takes it once, when\n * it is built (`yield* CloudflarePermissionGroups` below), and alchemy.run.ts supplies it to the\n * provider layer with `Layer.provide`. Listing it here as well made it a requirement of the STACK\n * body, which Alchemy only lets name its own provider and stack services — tsc refused the wiring.\n */\nexport interface BaoCloudflareRole extends Resource<\n 'Bao.CloudflareRole',\n BaoCloudflareRoleProps,\n BaoCloudflareRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoCloudflareRole = Resource<BaoCloudflareRole>('Bao.CloudflareRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: a trailing `/` on the mount is the same path (`rolePath` trims it). */\nconst IDENTITY = roleIdentity<BaoCloudflareRoleAttributes>('Bao.CloudflareRole', rolePath);\n\nexport const BaoCloudflareRoleProvider = () =>\n Provider.effect(\n BaoCloudflareRole,\n Effect.gen(function* () {\n const groups = yield* CloudflarePermissionGroups;\n\n /**\n * The declaration with IDs. ⛔ A name that does not resolve fails here — never a guess.\n *\n * ⛔ ONE REF PER (NAME, SCOPE), NOT PER NAME. The entry's resource is what says which scope\n * its groups are gated at, so a role whose zone entry and account entry name one group asks\n * for both ids; deduplicating by name alone would ask for one and use it for both.\n */\n const resolved = (props: BaoCloudflareRoleProps) =>\n Effect.gen(function* () {\n const refs = new Map<string, GroupRef>();\n for (const policy of props.policies) {\n /** ⛔ THE SAME PREFERENCE resolvePolicies MAKES — ask for the id the entry will use. */\n const scope = policy.scope ?? scopeOfResource(policy.resource);\n for (const name of policy.groups) refs.set(groupKey(name, scope), { name, scope });\n }\n const ids = yield* groups.resolve(props.mount, [...refs.values()]);\n const { missing, policies } = resolvePolicies(props.policies, ids);\n if (missing.length > 0) {\n return yield* Effect.die(\n new Error(\n `Bao.CloudflareRole ${rolePath(props.mount, props.name)}: groups ` +\n `${missing.join(', ')} came back unresolved from a lookup that reported success.`,\n ),\n );\n }\n return policies;\n });\n\n return BaoCloudflareRole.Provider.of({\n /**\n * ⛔ `<mount>/roles` IS NOT A LIST OF THINGS THIS OWNS. MEASURED 2026-09-14: 586 live roles,\n * 585 of which roles.yaml declares — and the 586th, cloudflare-<account>-platform/\n * alchemy-os-create, is exactly the role nobody has decided about. Returning it would\n * invite Alchemy to adopt, then delete, a role that may be someone's live credential.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const live = yield* readCloudflareRole(olds.mount, olds.name);\n const found = live === undefined ? undefined : attributesOf(olds, live);\n const ours = Effect.gen(function* () {\n if (live === undefined || refusalOf(olds) !== undefined) return false;\n return differences(olds, yield* resolved(olds), live).length === 0;\n });\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A policy widened by hand in the\n * OpenBao UI changes what every future token can do while the digest in Postgres still\n * says everything is fine.\n *\n * ⛔ A NEW `mount` OR `name` IS A `replace`, DECIDED BEFORE ANY OTHER READ (rename.ts). Until\n * 2026-09-21 this read the new path, found it absent and planned `update`: reconcile wrote\n * the new role and the old one stayed live and mintable under no state record. ⛔ A move\n * onto a role that already exists fails the plan (`judgeMove`).\n * ⚠️ UNDER THE DEFAULT `retain` THE OLD ROLE STILL MINTS for any token whose policy reaches its\n * `creds/<name>`. Under `destroy` every consumer still minting from the old path fails at\n * the delete, so move them in the same PR (REPLACE.md).\n * ★ A STACK THAT PUTS mount AND name IN THE LOGICAL ID never reaches this branch\n * (homeflare-openbao's declareCloudflareRoles does). There a rename is a new logical id,\n * and the old id leaves the stack as an orphan delete, which `retain` keeps live.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n /**\n * ⚠️ A DECLARATION reconcile WOULD REFUSE MUST NEVER PLAN AS noop — route it to reconcile,\n * which says why (pki-role.ts has the same guard).\n */\n if (refusalOf(news) !== undefined) return { action: 'update' } as const;\n const policies = yield* resolved(news);\n const live = yield* readCloudflareRole(news.mount, news.name);\n if (live === undefined) return { action: 'update' } as const;\n return differences(news, policies, live).length === 0\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news.mount, news.name);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n const refusal = refusalOf(news);\n if (refusal !== undefined) {\n return yield* Effect.die(new Error(`Bao.CloudflareRole ${path}: ${refusal}.`));\n }\n const policies = yield* resolved(news);\n const live = yield* readCloudflareRole(news.mount, news.name);\n if (live !== undefined) {\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.CloudflareRole ${path}`);\n }\n /**\n * ⛔ ADOPTING A ROLE THAT ALREADY MATCHES MUST NOT REWRITE IT. Alchemy's `adopted` action\n * routes through reconcile (policy.ts has the Apply.ts reading), so without this guard\n * the first deploy would PUT all 585 roles — byte-identical in the happy case, and a\n * silent rewrite of live grants the moment the port disagreed with production.\n */\n if (live === undefined || differences(news, policies, live).length > 0) {\n yield* writeCloudflareRole(news.mount, news.name, writeBody(news, policies));\n }\n const after = yield* readCloudflareRole(news.mount, news.name);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`),\n );\n }\n /**\n * ⛔ THE WRITE IS NOT TRUSTED, IT IS RE-READ. The engine re-marshals `policies` from structs\n * (path_roles.go:199-207), so a document it stored differently from what was sent — a\n * dropped group, a merged resource — shows up here as a named field, not as a green\n * deploy followed by a 403 at mint time.\n */\n const left = differences(news, policies, after);\n if (left.length > 0) {\n return yield* Effect.die(\n new Error(\n `Bao.CloudflareRole ${path}: wrote cleanly but reads back different in ` +\n `${left.map((d) => d.field).join(', ')}. Inspect the role before retrying.`,\n ),\n );\n }\n return attributesOf(news, after);\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT MINTED. They are leases on Cloudflare API\n * tokens and live to their own expiry, so this is an availability change for every\n * consumer of `creds/<name>`, never a containment action — to contain a leak, revoke the\n * lease. Idempotent: already gone is success (bao-status.ts).\n */\n delete: Effect.fn(function* ({ output }) {\n yield* deleteCloudflareRole(output.mount, output.name);\n return undefined;\n }),\n });\n }).pipe(Effect.map(provingResumes)),\n );\n",
|
|
34
|
+
"/**\n * A role on one of the six Cloudflare secrets-engine mounts — what one consumer may mint: the\n * Cloudflare policy its tokens carry and the lease bounds they get. METADATA ONLY.\n *\n * ★ THE PORT OF apply-roles.py's WRITE. roles.yaml expands to these (cloudflare-roles-expand.ts),\n * and what used to be `bao write <mount>/roles/<name> ttl= max_ttl= description= policies=` is\n * reconcile below. The props name permission groups; CloudflarePermissionGroups turns them into\n * IDs at diff and reconcile time.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see cloudflare-role-form.ts. ⛔ AND ISSUANCE IS NOT THIS\n * RESOURCE: `<mount>/creds/<name>` returns a LIVE Cloudflare token, and a token declared as a\n * resource would outlive its lease in Alchemy's unencrypted state (proxmox-role.ts has the four\n * places it would land). This declares the door; minting is a runtime call.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from it,\n * and apply-roles.py never deleted one either: an unexplained role was reported UNTRACKED and\n * left alone (apply-roles.py:190-196). Opt in with `.pipe(RemovalPolicy.destroy())`.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { groupKey, scopeOfResource } from './cloudflare-group-scope.ts';\nimport { CloudflarePermissionGroups, type GroupRef } from './cloudflare-permission-groups.ts';\nimport { resolvePolicies } from './cloudflare-policy.ts';\nimport {\n type BaoCloudflareRoleAttributes,\n type BaoCloudflareRoleProps,\n attributesOf,\n differences,\n refusalOf,\n rolePath,\n writeBody,\n} from './cloudflare-role-form.ts';\nimport {\n deleteCloudflareRole,\n readCloudflareRole,\n writeCloudflareRole,\n} from './cloudflare-role-wire.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoCloudflareRoleAttributes, BaoCloudflareRoleProps };\n\n/**\n * ⚠️ CloudflarePermissionGroups IS NOT A REQUIREMENT OF THE RESOURCE. The provider takes it once, when\n * it is built (`yield* CloudflarePermissionGroups` below), and alchemy.run.ts supplies it to the\n * provider layer with `Layer.provide`. Listing it here as well made it a requirement of the STACK\n * body, which Alchemy only lets name its own provider and stack services — tsc refused the wiring.\n */\nexport interface BaoCloudflareRole extends Resource<\n 'Bao.CloudflareRole',\n BaoCloudflareRoleProps,\n BaoCloudflareRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoCloudflareRole = Resource<BaoCloudflareRole>('Bao.CloudflareRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: a trailing `/` on the mount is the same path (`rolePath` trims it). */\nconst IDENTITY = roleIdentity<BaoCloudflareRoleAttributes>('Bao.CloudflareRole', rolePath);\n\nexport const BaoCloudflareRoleProvider = () =>\n Provider.effect(\n BaoCloudflareRole,\n Effect.gen(function* () {\n const groups = yield* CloudflarePermissionGroups;\n\n /**\n * The declaration with IDs. ⛔ A name that does not resolve fails here — never a guess.\n *\n * ⛔ ONE REF PER (NAME, SCOPE), NOT PER NAME. The entry's resource is what says which scope\n * its groups are gated at, so a role whose zone entry and account entry name one group asks\n * for both ids; deduplicating by name alone would ask for one and use it for both.\n */\n const resolved = (props: BaoCloudflareRoleProps) =>\n Effect.gen(function* () {\n const refs = new Map<string, GroupRef>();\n for (const policy of props.policies) {\n /** ⛔ THE SAME PREFERENCE resolvePolicies MAKES — ask for the id the entry will use. */\n const scope = policy.scope ?? scopeOfResource(policy.resource);\n for (const name of policy.groups) refs.set(groupKey(name, scope), { name, scope });\n }\n const ids = yield* groups.resolve(props.mount, [...refs.values()]);\n const { missing, policies } = resolvePolicies(props.policies, ids);\n if (missing.length > 0) {\n return yield* Effect.die(\n new Error(\n `Bao.CloudflareRole ${rolePath(props.mount, props.name)}: groups ` +\n `${missing.join(', ')} came back unresolved from a lookup that reported success.`,\n ),\n );\n }\n return policies;\n });\n\n return BaoCloudflareRole.Provider.of({\n /**\n * ⛔ `<mount>/roles` IS NOT A LIST OF THINGS THIS OWNS. MEASURED 2026-09-14: 586 live roles,\n * 585 of which roles.yaml declares — and the 586th, cloudflare-<account>-platform/\n * alchemy-os-create, is exactly the role nobody has decided about. Returning it would\n * invite Alchemy to adopt, then delete, a role that may be someone's live credential.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const live = yield* readCloudflareRole(olds.mount, olds.name);\n const found = live === undefined ? undefined : attributesOf(olds, live);\n const ours = Effect.gen(function* () {\n if (live === undefined || refusalOf(olds) !== undefined) return false;\n return differences(olds, yield* resolved(olds), live).length === 0;\n });\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A policy widened by hand in the\n * OpenBao UI changes what every future token can do while the digest in Postgres still\n * says everything is fine.\n *\n * ⛔ A NEW `mount` OR `name` IS A `replace`, DECIDED BEFORE ANY OTHER READ (rename.ts). Until\n * 2026-09-21 this read the new path, found it absent and planned `update`: reconcile wrote\n * the new role and the old one stayed live and mintable under no state record. ⛔ A move\n * onto a role that already exists fails the plan (`judgeMove`).\n * ⚠️ UNDER THE DEFAULT `retain` THE OLD ROLE STILL MINTS for any token whose policy reaches its\n * `creds/<name>`. Under `destroy` every consumer still minting from the old path fails at\n * the delete, so move them in the same PR (REPLACE.md).\n * ★ A STACK THAT PUTS mount AND name IN THE LOGICAL ID never reaches this branch\n * (homeflare-openbao's declareCloudflareRoles does). There a rename is a new logical id,\n * and the old id leaves the stack as an orphan delete, which `retain` keeps live.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n /**\n * ⚠️ A DECLARATION reconcile WOULD REFUSE MUST NEVER PLAN AS noop — route it to reconcile,\n * which says why (pki-role.ts has the same guard).\n */\n if (refusalOf(news) !== undefined) return { action: 'update' } as const;\n const policies = yield* resolved(news);\n const live = yield* readCloudflareRole(news.mount, news.name);\n if (live === undefined) return { action: 'update' } as const;\n return differences(news, policies, live).length === 0\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news.mount, news.name);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n const refusal = refusalOf(news);\n if (refusal !== undefined) {\n return yield* Effect.die(new Error(`Bao.CloudflareRole ${path}: ${refusal}.`));\n }\n const policies = yield* resolved(news);\n const live = yield* readCloudflareRole(news.mount, news.name);\n if (live !== undefined) {\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.CloudflareRole ${path}`);\n }\n /**\n * ⛔ ADOPTING A ROLE THAT ALREADY MATCHES MUST NOT REWRITE IT. Alchemy's `adopted` action\n * routes through reconcile (policy.ts has the Apply.ts reading), so without this guard\n * the first deploy would PUT all 585 roles — byte-identical in the happy case, and a\n * silent rewrite of live grants the moment the port disagreed with production.\n */\n if (live === undefined || differences(news, policies, live).length > 0) {\n yield* writeCloudflareRole(news.mount, news.name, writeBody(news, policies));\n }\n const after = yield* readCloudflareRole(news.mount, news.name);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(`Bao.CloudflareRole ${path}: the write succeeded but the role is absent.`),\n );\n }\n /**\n * ⛔ THE WRITE IS NOT TRUSTED, IT IS RE-READ. The engine re-marshals `policies` from structs\n * (path_roles.go:199-207), so a document it stored differently from what was sent — a\n * dropped group, a merged resource — shows up here as a named field, not as a green\n * deploy followed by a 403 at mint time.\n */\n const left = differences(news, policies, after);\n if (left.length > 0) {\n return yield* Effect.die(\n new Error(\n `Bao.CloudflareRole ${path}: wrote cleanly but reads back different in ` +\n `${left.map((d) => d.field).join(', ')}. Inspect the role before retrying.`,\n ),\n );\n }\n return attributesOf(news, after);\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT MINTED. They are leases on Cloudflare API\n * tokens and live to their own expiry, so this is an availability change for every\n * consumer of `creds/<name>`, never a containment action — to contain a leak, revoke the\n * lease. Idempotent: already gone is success (bao-status.ts).\n */\n delete: Effect.fn(function* ({ output }) {\n yield* deleteCloudflareRole(output.mount, output.name);\n return undefined;\n }),\n });\n }).pipe(Effect.map(provingResumes)),\n );\n",
|
|
35
35
|
"/**\n * The three resources a Cloudflare policy entry can name, and the SCOPE its permission groups are\n * looked up at — one vocabulary, both directions.\n *\n * ★ EXTRACTED FROM cloudflare-roles-expand.ts 2026-09-15, which had reached 270 lines (AGENTS.md\n * rule 5, code ≤250). The split is by CONCERN, not by size: expand.ts turns roles.yaml into\n * roles, this answers \"which of the two ids named `Logs Read` does this entry mean\".\n */\n\n/** cfhf.py:172-173. */\nexport const zoneResource = (zoneId: string) => `com.cloudflare.api.account.zone.${zoneId}`;\nexport const accountResource = (accountId: string) => `com.cloudflare.api.account.${accountId}`;\n\n/**\n * One R2 bucket, which is a DIFFERENT RESOURCE NAMESPACE from the two above.\n *\n * ⛔ `com.cloudflare.edge.r2.bucket.…`, NOT `com.cloudflare.api.account.…`, and the three parts are\n * joined by UNDERSCORES inside the last segment — `<accountId>_<jurisdiction>_<bucket>`. Getting\n * the separator wrong produces a syntactically fine resource that matches no bucket, and the\n * token mints successfully and is refused on first use, which reads exactly like a missing\n * permission group. Per Cloudflare's R2 API-token documentation, read 2026-09-15.\n * ⚠️ AND IT ONLY BINDS THE `Bucket Item` GROUPS. `Workers R2 Storage Write` / `… Read` are gated at\n * the ACCOUNT scope; the bucket-scoped pair is `Workers R2 Storage Bucket Item Write` / `… Read`.\n * Pairing an account group with this resource is the same silent 403.\n */\nexport const bucketResource = (accountId: string, jurisdiction: string, bucket: string) =>\n `com.cloudflare.edge.r2.bucket.${accountId}_${jurisdiction}_${bucket}`;\n\n/**\n * The three scopes this expansion can ask for — the namespaces of the three resources above, which\n * is exactly what the engine reports as a group's `scopes`.\n *\n * ★ MEASURED on `cloudflare-<account>-platform/permission-groups`, 2026-09-15 12:10: 401 groups,\n * every one with exactly ONE scope, over five values — 297 `com.cloudflare.api.account`, 94\n * `com.cloudflare.api.account.zone`, 2 `com.cloudflare.edge.r2.bucket` and four each of\n * `…account.flagship.app` and `com.cloudflare.edge.worker.script`, which no resource here builds.\n * The testing account's list is byte-identical, so the ids are Cloudflare's, not an account's.\n */\nexport const GROUP_SCOPES = {\n account: 'com.cloudflare.api.account',\n bucket: 'com.cloudflare.edge.r2.bucket',\n zone: 'com.cloudflare.api.account.zone',\n} as const;\n\n/**\n * The short word roles.yaml writes in `groups_scope:` → the namespace: `zone` becomes\n * `com.cloudflare.api.account.zone`. Undefined for a word that is not one of the three KEYS above.\n *\n * ⛔ THE yaml SAYS THE SHORT WORD AND NEVER THE NAMESPACE. A namespace typed into roles.yaml would\n * be accepted by any check that only asked for a string, and a misspelt one resolves no group at\n * all — an unknown-group failure naming a scope nobody wrote on purpose, instead of the line.\n * ⚠️ `Object.entries(…).find`, NOT an index with a narrowing `as`: codex standard 2 bans the cast,\n * and the lookup has three entries.\n */\nexport const groupScopeNamed = (word: string): string | undefined =>\n Object.entries(GROUP_SCOPES).find(([name]) => name === word)?.[1];\n\n/**\n * The scope the groups of one policy entry are gated at: its resource namespace, the instance id\n * dropped. A zone entry asks for zone groups, an account entry for account groups, a bucket entry\n * for the two `com.cloudflare.edge.r2.bucket` ones.\n *\n * ⛔ ZONE IS TESTED BEFORE ACCOUNT, because `com.cloudflare.api.account.zone.<id>` also starts with\n * the account namespace, and the wrong order would call every zone entry an account one.\n * ⚠️ A RESOURCE IN NO KNOWN NAMESPACE BECOMES ITS OWN SCOPE, which matches no group, so it fails as\n * an unresolvable name naming the scope it asked for — never by borrowing another scope's id.\n * ⚠️ IT IS THE DEFAULT, NOT THE LAST WORD. An entry carrying an explicit `scope` overrides it —\n * see DeclaredPolicy.scope (cloudflare-roles-expand.ts) and resolvePolicies.\n */\nexport const scopeOfResource = (resource: string) => {\n const scopes = [GROUP_SCOPES.zone, GROUP_SCOPES.bucket, GROUP_SCOPES.account];\n return scopes.find((scope) => resource.startsWith(`${scope}.`)) ?? resource;\n};\n\n/**\n * What a resolved group is filed under.\n *\n * ⛔ A NAME ALONE IS NOT A KEY. MEASURED 2026-09-15 on the live list: SEVEN names are listed twice,\n * once at `com.cloudflare.api.account` and once at `com.cloudflare.api.account.zone` — `Access:\n * Apps and Policies Read` / `… Revoke` / `… Write`, `Disable ESC Read` / `… Write`, `Logs Read`\n * and `Logs Write`. cfhf.py:148 keyed by name and the last one read won in silence.\n */\nexport const groupKey = (name: string, scope: string) => `${scope} ${name}`;\n",
|
|
36
|
-
"/**\n * Permission-group (name, SCOPE) → ID, behind ONE interface with two sources.\n *\n * ⛔ THE KEY IS THE PAIR, AND THAT IS NOT PEDANTRY. MEASURED 2026-09-15 the hour the grant went\n * live: of the account's 401 groups, SEVEN names are listed twice — `Access: Apps and Policies\n * Read`/`Revoke`/`Write`, `Disable ESC Read`/`Write`, `Logs Read`/`Write` — each pair one id\n * scoped `com.cloudflare.api.account` and one scoped `com.cloudflare.api.account.zone`. Keyed by\n * name alone the whole plan fails as ambiguous; keyed by name alone and forgiving, cfhf.py:148's\n * last-one-wins picks a group gated at the wrong scope and the token is refused at first use.\n * The asking ENTRY says which: its `scope` (roles.yaml `groups_scope:`), else its resource.\n *\n * ★ A SERVICE, NOT A TABLE. roles.yaml names groups (`DNS Read`); a role stores IDs. apply-roles.py\n * resolved them per account with a Cloudflare parent credential (cfhf.py:147-148), which agents\n * may not use. So Bao.CloudflareRole asks this service, and the stack chooses the source:\n *\n * a) `permissionGroupsFromEngine` — `GET <mount>/permission-groups` on the Cloudflare engine,\n * answered under the mount's own parent. ★ DEPLOYED AND WIRED 2026-09-15: `bao path-help\n * cloudflare-<account>-platform` lists `^permission-groups$` on plugin v0.0.0-dev, and\n * cloudflare-roles.ts now provides this source to the stack.\n * b) `permissionGroupsFromLiveRoles` — ⚠️ TEMPORARY, AND STILL HERE ON PURPOSE. 2026-09-15: no\n * longer the stack's source, and NOT yet deletable. Two things gate that — (1) the live\n * `result_info` envelope pinned in ../../platform/secrets/vault/plugin/cloudflare/\n * client_result_info.go, whose own header names this deletion as what it gates, and (2)\n * cloudflare-parity.ts, which calls cloudflare-permission-groups-solve.ts directly for the\n * OFFLINE proof against a production export and has no engine to ask. So (b) and the solver\n * stay, one import from being the layer again (cloudflare-roles.ts), until the last step of\n * docs/ledger/openbao-permission-groups-engine-2026-09-15.md is done.\n *\n * ⛔ AN UNKNOWN NAME FAILS THE OPERATION. Dropping it would write a policy one group short, and the\n * engine refuses an empty ID (path_roles.go:181-185) but not a SHORTER list: the minted token is\n * quietly narrower than declared, and the consumer finds out at 403.\n */\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { baoRead } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\nimport { groupKey } from './cloudflare-group-scope.ts';\nimport {\n describeProblems,\n observationsOf,\n solveGroups,\n} from './cloudflare-permission-groups-solve.ts';\nimport { type WirePolicy, atEveryScope } from './cloudflare-policy.ts';\nimport { readCloudflareRole } from './cloudflare-role-wire.ts';\nimport type { ExpandedRole } from './cloudflare-roles-expand.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport class CloudflareGroupsError extends Error {\n constructor(\n readonly scope: string,\n readonly problems: readonly string[],\n ) {\n super(`Cloudflare permission groups for ${scope}: ${problems.join('; ')}`);\n this.name = 'CloudflareGroupsError';\n }\n}\n\n/** ⛔ Keyed by `groupKey(name, scope)` throughout — see cloudflare-group-scope.ts. */\ntype Groups = ReadonlyMap<string, string>;\ntype Lookup = Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;\n\n/** One group a role asks for: its name, and the scope the entry naming it is gated at. */\nexport interface GroupRef {\n readonly name: string;\n readonly scope: string;\n}\n\nexport class CloudflarePermissionGroups extends Context.Service<\n CloudflarePermissionGroups,\n {\n /** The ID of every ref, keyed by `groupKey` — or a failure naming what did not resolve. */\n readonly resolve: (\n mount: string,\n refs: readonly GroupRef[],\n ) => Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;\n }\n>()('homeflare/openbao/CloudflarePermissionGroups') {}\n\nconst pick = (mount: string, groups: Groups, refs: readonly GroupRef[], hint: string) => {\n const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));\n if (unknown.length > 0) {\n const problems = unknown.map(\n (ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`,\n );\n return Effect.fail(new CloudflareGroupsError(mount, problems));\n }\n return Effect.succeed(\n new Map(\n refs.flatMap((ref) => {\n const key = groupKey(ref.name, ref.scope);\n const id = groups.get(key);\n return id === undefined ? [] : [[key, id] as const];\n }),\n ),\n );\n};\n\nconst isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * ⛔ A 403 IS A MISSING GRANT, AND IT SAYS SO. `BaoError` alone reports `GET /v1/<mount>/\n * permission-groups -> 403: permission denied` — true, and it points nowhere: the path is\n * deployed, the token is valid, and the one thing to change is a policy file. MEASURED 2026-09-15\n * 10:19 on the host's admin lane, where `bao write sys/capabilities-self` answered `[deny]` on\n * this exact path. bao-status.ts argues that a failure must name what it is; this is that\n * argument one level up.\n */\nconst deniedHint = (mount: string) =>\n `GET ${mountPath(mount)}/permission-groups answered 403 — this token's policy carries no ` +\n `\\`path \"${mountPath(mount)}/permission-groups\" { capabilities = [\"read\"] }\\` grant. ` +\n 'It is declared in ../platform/secrets/vault/policies/homeflare-admin/' +\n '20-cloudflare-permission-groups.hcl and applies with `alchemy deploy` of this stack';\n\nconst deniedNamed = <A, R>(mount: string, read: Effect.Effect<A, BaoError, R>) =>\n Effect.catchIf(\n read,\n (error) => error.status === 403,\n () => Effect.fail(new CloudflareGroupsError(mount, [deniedHint(mount)])),\n );\n\n/**\n * a) The engine's list, parsed.\n *\n * ★ THE SHAPE IS THE PLUGIN'S OWN, READ FROM ITS SOURCE 2026-09-15:\n * `{\"permission_groups\":[{\"id\",\"name\",\"scopes\"}]}` built row by row in\n * ../../platform/secrets/vault/plugin/cloudflare/path_permission_groups.go:42-54. baoRead takes\n * `data` when the body has one and the whole body otherwise (bao-http.ts:160-167), so either\n * envelope parses.\n * ⚠️ PAGINATION IS THE PLUGIN'S PROBLEM, NOT THIS PARSER'S. client_permission_groups.go:52-119 walks\n * Cloudflare's pages and ends every guard in an error rather than a shorter list, so what arrives\n * here is complete or absent. ⛔ ITS `result_info` GUARDS ARE STILL UNMEASURED against a live\n * envelope (client_result_info.go:22-28) — that capture, not this file, is what gates deleting (b).\n * ⛔ ONE NAME WITH TWO IDS IS NOT AN ERROR; ONE (NAME, SCOPE) WITH TWO IDS IS. cfhf.py:148 built\n * `{g[\"name\"]: g[\"id\"]}` and the LAST duplicate won in silence. MEASURED 2026-09-15 on the live\n * list: seven names ARE listed twice, each pair one account-scoped id and one zone-scoped id, so\n * the plugin's \"does not choose between them\" (path_permission_groups.go:69-70) is the shape in\n * front of us, not a hypothetical. `scopes` tells them apart; the header above says who picks.\n * ⚠️ AN EMPTY `scopes` IS NOT AN ERROR. Such a group is reachable only by the one-id rule below —\n * a name nothing else claims answers wherever it is asked — so a group Cloudflare ships without\n * a scope resolves, and never holds the other 398 hostage.\n */\nconst engineGroups = (mount: string): Lookup =>\n Effect.flatMap(deniedNamed(mount, baoRead(`${mountPath(mount)}/permission-groups`)), (data) => {\n const list = data?.['permission_groups'];\n if (data === undefined) {\n // ⚠️ 404 IS NOW A MOUNT-SHAPED ANSWER, NOT THE EXPECTED ONE. The path IS deployed\n // estate-wide (measured 2026-09-15), so a 404 here means this mount is served by an older\n // plugin binary or BAO_ADDR is not the vault host — never \"no groups\".\n const why = 'GET <mount>/permission-groups answered 404 — the endpoint is not deployed here';\n return Effect.fail(new CloudflareGroupsError(mount, [why]));\n }\n if (!Array.isArray(list)) {\n return Effect.fail(new CloudflareGroupsError(mount, ['no permission_groups array in reply']));\n }\n const scoped = new Map<string, string>();\n const idsOf = new Map<string, Set<string>>();\n const problems: string[] = [];\n for (const item of list) {\n const name = isRecord(item) ? item['name'] : undefined;\n const id = isRecord(item) ? item['id'] : undefined;\n const scopes = isRecord(item) ? item['scopes'] : undefined;\n if (\n typeof name !== 'string' ||\n typeof id !== 'string' ||\n !Array.isArray(scopes) ||\n !scopes.every((scope) => typeof scope === 'string')\n ) {\n problems.push('an entry without a string name, id and scopes');\n continue;\n }\n idsOf.set(name, (idsOf.get(name) ?? new Set()).add(id));\n for (const scope of scopes) {\n const key = groupKey(name, scope);\n if (scoped.has(key) && scoped.get(key) !== id) {\n problems.push(\n `ambiguous: ${JSON.stringify(name)} is listed with two ids at scope ${scope}`,\n );\n } else {\n scoped.set(key, id);\n }\n }\n }\n /**\n * ★ A NAME WITH ONE ID NEEDS NO SCOPE, and answers at every scope an entry can ask for: there\n * is nothing to choose between, and 385 of the list's 392 names are in that case. It is only\n * the seven two-id names the asking scope has to separate — and for those, a scope the name\n * is not listed at resolves to nothing and fails by name, never to the other scope's id.\n */\n const sole = new Map(\n [...idsOf].flatMap(([name, ids]) => {\n const only = [...ids];\n return ids.size === 1 && only[0] !== undefined ? [[name, only[0]] as const] : [];\n }),\n );\n return problems.length > 0\n ? Effect.fail(new CloudflareGroupsError(mount, problems))\n : Effect.succeed(new Map([...atEveryScope(sole), ...scoped]));\n });\n\n/**\n * ★ ONE FETCH PER MOUNT PER RUN, not one per role — 586 roles would otherwise ask 586 times.\n * ⚠️ A FAILURE IS CACHED TOO (Effect.cached keeps the Exit), so one sealed-vault 503 fails every\n * role on that mount for the rest of the run. That is the honest outcome for a plan: retrying\n * 586 times against a sealed server would only make the failure slower.\n */\nexport const permissionGroupsFromEngine = () =>\n Effect.sync(() => {\n const cache = new Map<string, Lookup>();\n const cachedFor = (mount: string) =>\n Effect.suspend(() => {\n const hit = cache.get(mountPath(mount));\n if (hit !== undefined) return hit;\n return Effect.flatMap(Effect.cached(engineGroups(mount)), (lookup) => {\n cache.set(mountPath(mount), lookup);\n return lookup;\n });\n });\n return CloudflarePermissionGroups.of({\n resolve: (mount, refs) =>\n Effect.flatMap(cachedFor(mount), (groups) =>\n pick(mount, groups, refs, 'the engine does not list it for this account at that scope'),\n ),\n });\n });\n\n/**\n * b) ⚠️ TEMPORARY, AND NO LONGER THE STACK'S SOURCE SINCE 2026-09-15 — see the header for the two\n * things that gate deleting it. Reads every DECLARED role of an account — no LIST, because an\n * undeclared live role carries IDs with no names to pair them with — and solves the account at\n * once.\n * 🔴 WHAT RETIRED IT, 2026-09-15 10:13: `alchemy deploy` could not create\n * `cloudflare-{<account>,testing}-platform/roles/r2-backup-host` — `unknown group \"Workers R2\n * Storage Bucket Item Write\" — no live role on account <account> carries it; a NEW group needs\n * the engine endpoint`. That is this source's documented blind spot arriving, not a bug in it.\n *\n * ★ PER ACCOUNT, NOT PER MOUNT, BECAUSE ONE MOUNT CANNOT SOLVE ITSELF. MEASURED on the snapshot:\n * `aimto-app-alchemy-os-create` on the platform mount pairs `Email Routing Rules Write` and\n * `DNS Write` with two unknown IDs, and neither group appears alone on that mount. The dns and\n * security mounts of the same account isolate them. apply-roles.py's map was per account too\n * (apply-roles.py:117).\n */\nexport const permissionGroupsFromLiveRoles = (\n declared: ReadonlyMap<string, readonly ExpandedRole[]>,\n) =>\n Effect.gen(function* () {\n const accountOf = new Map<string, string>();\n const byAccount = new Map<string, ExpandedRole[]>();\n for (const [mount, roles] of declared) {\n for (const role of roles) {\n accountOf.set(mount, role.account);\n byAccount.set(role.account, [...(byAccount.get(role.account) ?? []), role]);\n }\n }\n const solved = new Map<string, Lookup>();\n for (const [account, roles] of byAccount) {\n const solve = Effect.gen(function* () {\n const live = new Map<string, readonly WirePolicy[]>();\n // ★ `Effect.all` over mapped reads, not `Effect.forEach`: oxlint's unicorn/no-array-for-each\n // matches the method NAME and cannot tell Effect's from Array's.\n yield* Effect.all(\n roles.map((role) =>\n Effect.map(readCloudflareRole(role.mount, role.name), (read) => {\n if (read?.policies !== undefined) {\n live.set(`${role.mount}/${role.name}`, read.policies);\n }\n }),\n ),\n { concurrency: 8, discard: true },\n );\n const result = solveGroups(observationsOf(roles, live));\n const problems = describeProblems(result);\n if (problems.length > 0) {\n return yield* Effect.fail(new CloudflareGroupsError(`account ${account}`, problems));\n }\n /**\n * ⚠️ IT ANSWERS AT EVERY SCOPE BECAUSE IT CANNOT SEE ONE. A live role carries ids and no\n * scopes, so the solver learns `name → id` and nothing more; the seven two-id names\n * resolve here to whichever id the estate happens to carry, at whatever scope is asked.\n * That is this source's blind spot, not a second opinion — (a) keys by (name, scope).\n */\n return atEveryScope(result.groups);\n });\n solved.set(account, yield* Effect.cached(solve));\n }\n return CloudflarePermissionGroups.of({\n resolve: (mount, refs) => {\n const account = accountOf.get(mountPath(mount));\n const lookup = account === undefined ? undefined : solved.get(account);\n if (account === undefined || lookup === undefined) {\n const why = 'no declared role on this mount, so no live role can vouch for its groups';\n return Effect.fail(new CloudflareGroupsError(mount, [why]));\n }\n const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;\n return Effect.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));\n },\n });\n });\n",
|
|
36
|
+
"/**\n * Permission-group (name, SCOPE) → ID, behind ONE interface with two sources.\n *\n * ⛔ THE KEY IS THE PAIR, AND THAT IS NOT PEDANTRY. MEASURED 2026-09-15 the hour the grant went\n * live: of the account's 401 groups, SEVEN names are listed twice — `Access: Apps and Policies\n * Read`/`Revoke`/`Write`, `Disable ESC Read`/`Write`, `Logs Read`/`Write` — each pair one id\n * scoped `com.cloudflare.api.account` and one scoped `com.cloudflare.api.account.zone`. Keyed by\n * name alone the whole plan fails as ambiguous; keyed by name alone and forgiving, cfhf.py:148's\n * last-one-wins picks a group gated at the wrong scope and the token is refused at first use.\n * The asking ENTRY says which: its `scope` (roles.yaml `groups_scope:`), else its resource.\n *\n * ★ A SERVICE, NOT A TABLE. roles.yaml names groups (`DNS Read`); a role stores IDs. apply-roles.py\n * resolved them per account with a Cloudflare parent credential (cfhf.py:147-148), which agents\n * may not use. So Bao.CloudflareRole asks this service, and the stack chooses the source:\n *\n * a) `permissionGroupsFromEngine` — `GET <mount>/permission-groups` on the Cloudflare engine,\n * answered under the mount's own parent. ★ DEPLOYED AND WIRED 2026-09-15: `bao path-help\n * cloudflare-<account>-platform` lists `^permission-groups$` on plugin v0.0.0-dev, and\n * cloudflare-roles.ts now provides this source to the stack.\n * b) `permissionGroupsFromLiveRoles` — ⚠️ TEMPORARY, AND STILL HERE ON PURPOSE. 2026-09-15: no\n * longer the stack's source, and NOT yet deletable. Two things gate that — (1) the live\n * `result_info` envelope pinned in ../../platform/secrets/vault/plugin/cloudflare/\n * client_result_info.go, whose own header names this deletion as what it gates, and (2)\n * cloudflare-parity.ts, which calls cloudflare-permission-groups-solve.ts directly for the\n * OFFLINE proof against a production export and has no engine to ask. So (b) and the solver\n * stay, one import from being the layer again (cloudflare-roles.ts), until the last step of\n * docs/ledger/openbao-permission-groups-engine-2026-09-15.md is done.\n *\n * ⛔ AN UNKNOWN NAME FAILS THE OPERATION. Dropping it would write a policy one group short, and the\n * engine refuses an empty ID (path_roles.go:181-185) but not a SHORTER list: the minted token is\n * quietly narrower than declared, and the consumer finds out at 403.\n */\nimport * as Context from 'effect/Context';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { baoRead } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\nimport { groupKey } from './cloudflare-group-scope.ts';\nimport {\n describeProblems,\n observationsOf,\n solveGroups,\n} from './cloudflare-permission-groups-solve.ts';\nimport { type WirePolicy, atEveryScope } from './cloudflare-policy.ts';\nimport { readCloudflareRole } from './cloudflare-role-wire.ts';\nimport type { ExpandedRole } from './cloudflare-roles-expand.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport class CloudflareGroupsError extends Error {\n constructor(\n readonly scope: string,\n readonly problems: readonly string[],\n ) {\n super(`Cloudflare permission groups for ${scope}: ${problems.join('; ')}`);\n this.name = 'CloudflareGroupsError';\n }\n}\n\n/** ⛔ Keyed by `groupKey(name, scope)` throughout — see cloudflare-group-scope.ts. */\ntype Groups = ReadonlyMap<string, string>;\ntype Lookup = Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;\n\n/** One group a role asks for: its name, and the scope the entry naming it is gated at. */\nexport interface GroupRef {\n readonly name: string;\n readonly scope: string;\n}\n\nexport class CloudflarePermissionGroups extends Context.Service<\n CloudflarePermissionGroups,\n {\n /** The ID of every ref, keyed by `groupKey` — or a failure naming what did not resolve. */\n readonly resolve: (\n mount: string,\n refs: readonly GroupRef[],\n ) => Effect.Effect<Groups, BaoError | CloudflareGroupsError, HttpClient.HttpClient>;\n }\n>()('homeflare/openbao/CloudflarePermissionGroups') {}\n\nconst pick = (mount: string, groups: Groups, refs: readonly GroupRef[], hint: string) => {\n const unknown = refs.filter((ref) => !groups.has(groupKey(ref.name, ref.scope)));\n if (unknown.length > 0) {\n const problems = unknown.map(\n (ref) => `unknown group ${JSON.stringify(ref.name)} at scope ${ref.scope} — ${hint}`,\n );\n return Effect.fail(new CloudflareGroupsError(mount, problems));\n }\n return Effect.succeed(\n new Map(\n refs.flatMap((ref) => {\n const key = groupKey(ref.name, ref.scope);\n const id = groups.get(key);\n return id === undefined ? [] : [[key, id] as const];\n }),\n ),\n );\n};\n\nconst isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\n/**\n * ⛔ A 403 IS A MISSING GRANT, AND IT SAYS SO. `BaoError` alone reports `GET /v1/<mount>/\n * permission-groups -> 403: permission denied` — true, and it points nowhere: the path is\n * deployed, the token is valid, and the one thing to change is a policy file. MEASURED 2026-09-15\n * 10:19 on the host's admin lane, where `bao write sys/capabilities-self` answered `[deny]` on\n * this exact path. bao-status.ts argues that a failure must name what it is; this is that\n * argument one level up.\n */\nconst deniedHint = (mount: string) =>\n `GET ${mountPath(mount)}/permission-groups answered 403 — this token's policy carries no ` +\n `\\`path \"${mountPath(mount)}/permission-groups\" { capabilities = [\"read\"] }\\` grant. ` +\n 'It is declared in ../platform/secrets/vault/policies/homeflare-admin/' +\n '20-cloudflare-permission-groups.hcl and applies with `alchemy deploy` of this stack';\n\nconst deniedNamed = <A, R>(mount: string, read: Effect.Effect<A, BaoError, R>) =>\n Effect.catchIf(\n read,\n (error) => error.status === 403,\n () => Effect.fail(new CloudflareGroupsError(mount, [deniedHint(mount)])),\n );\n\n/**\n * a) The engine's list, parsed.\n *\n * ★ THE SHAPE IS THE PLUGIN'S OWN, READ FROM ITS SOURCE 2026-09-15:\n * `{\"permission_groups\":[{\"id\",\"name\",\"scopes\"}]}` built row by row in\n * ../../platform/secrets/vault/plugin/cloudflare/path_permission_groups.go:42-54. baoRead takes\n * `data` when the body has one and the whole body otherwise (bao-http.ts:160-167), so either\n * envelope parses.\n * ⚠️ PAGINATION IS THE PLUGIN'S PROBLEM, NOT THIS PARSER'S. client_permission_groups.go:52-119 walks\n * Cloudflare's pages and ends every guard in an error rather than a shorter list, so what arrives\n * here is complete or absent. ⛔ ITS `result_info` GUARDS ARE STILL UNMEASURED against a live\n * envelope (client_result_info.go:22-28) — that capture, not this file, is what gates deleting (b).\n * ⛔ ONE NAME WITH TWO IDS IS NOT AN ERROR; ONE (NAME, SCOPE) WITH TWO IDS IS. cfhf.py:148 built\n * `{g[\"name\"]: g[\"id\"]}` and the LAST duplicate won in silence. MEASURED 2026-09-15 on the live\n * list: seven names ARE listed twice, each pair one account-scoped id and one zone-scoped id, so\n * the plugin's \"does not choose between them\" (path_permission_groups.go:69-70) is the shape in\n * front of us, not a hypothetical. `scopes` tells them apart; the header above says who picks.\n * ⚠️ AN EMPTY `scopes` IS NOT AN ERROR. Such a group is reachable only by the one-id rule below —\n * a name nothing else claims answers wherever it is asked — so a group Cloudflare ships without\n * a scope resolves, and never holds the other 398 hostage.\n */\nconst engineGroups = (mount: string): Lookup =>\n Effect.flatMap(deniedNamed(mount, baoRead(`${mountPath(mount)}/permission-groups`)), (data) => {\n const list = data?.['permission_groups'];\n if (data === undefined) {\n // ⚠️ 404 IS NOW A MOUNT-SHAPED ANSWER, NOT THE EXPECTED ONE. The path IS deployed\n // estate-wide (measured 2026-09-15), so a 404 here means this mount is served by an older\n // plugin binary or BAO_ADDR is not the vault host — never \"no groups\".\n const why = 'GET <mount>/permission-groups answered 404 — the endpoint is not deployed here';\n return Effect.fail(new CloudflareGroupsError(mount, [why]));\n }\n if (!Array.isArray(list)) {\n return Effect.fail(new CloudflareGroupsError(mount, ['no permission_groups array in reply']));\n }\n const scoped = new Map<string, string>();\n const idsOf = new Map<string, Set<string>>();\n const problems: string[] = [];\n for (const item of list) {\n const name = isRecord(item) ? item['name'] : undefined;\n const id = isRecord(item) ? item['id'] : undefined;\n const scopes = isRecord(item) ? item['scopes'] : undefined;\n if (\n typeof name !== 'string' ||\n typeof id !== 'string' ||\n !Array.isArray(scopes) ||\n !scopes.every((scope) => typeof scope === 'string')\n ) {\n problems.push('an entry without a string name, id and scopes');\n continue;\n }\n idsOf.set(name, (idsOf.get(name) ?? new Set()).add(id));\n for (const scope of scopes) {\n const key = groupKey(name, scope);\n if (scoped.has(key) && scoped.get(key) !== id) {\n problems.push(\n `ambiguous: ${JSON.stringify(name)} is listed with two ids at scope ${scope}`,\n );\n } else {\n scoped.set(key, id);\n }\n }\n }\n /**\n * ★ A NAME WITH ONE ID NEEDS NO SCOPE, and answers at every scope an entry can ask for: there\n * is nothing to choose between, and 385 of the list's 392 names are in that case. It is only\n * the seven two-id names the asking scope has to separate — and for those, a scope the name\n * is not listed at resolves to nothing and fails by name, never to the other scope's id.\n */\n const sole = new Map(\n [...idsOf].flatMap(([name, ids]) => {\n const only = [...ids];\n return ids.size === 1 && only[0] !== undefined ? [[name, only[0]] as const] : [];\n }),\n );\n return problems.length > 0\n ? Effect.fail(new CloudflareGroupsError(mount, problems))\n : Effect.succeed(new Map([...atEveryScope(sole), ...scoped]));\n });\n\n/**\n * ★ ONE FETCH PER MOUNT PER RUN, not one per role — 586 roles would otherwise ask 586 times.\n * ⚠️ A FAILURE IS CACHED TOO (Effect.cached keeps the Exit), so one sealed-vault 503 fails every\n * role on that mount for the rest of the run. That is the honest outcome for a plan: retrying\n * 586 times against a sealed server would only make the failure slower.\n */\nexport const permissionGroupsFromEngine = () =>\n Effect.sync(() => {\n const cache = new Map<string, Lookup>();\n const cachedFor = (mount: string) =>\n Effect.suspend(() => {\n const hit = cache.get(mountPath(mount));\n if (hit !== undefined) return hit;\n return Effect.flatMap(Effect.cached(engineGroups(mount)), (lookup) => {\n cache.set(mountPath(mount), lookup);\n return lookup;\n });\n });\n return CloudflarePermissionGroups.of({\n resolve: (mount, refs) =>\n Effect.flatMap(cachedFor(mount), (groups) =>\n pick(mount, groups, refs, 'the engine does not list it for this account at that scope'),\n ),\n });\n });\n\n/**\n * b) ⚠️ TEMPORARY, AND NO LONGER THE STACK'S SOURCE SINCE 2026-09-15 — see the header for the two\n * things that gate deleting it. Reads every DECLARED role of an account — no LIST, because an\n * undeclared live role carries IDs with no names to pair them with — and solves the account at\n * once.\n * 🔴 WHAT RETIRED IT, 2026-09-15 10:13: `alchemy deploy` could not create\n * `cloudflare-{<account>,testing}-platform/roles/r2-backup-host` — `unknown group \"Workers R2\n * Storage Bucket Item Write\" — no live role on account <account> carries it; a NEW group needs\n * the engine endpoint`. That is this source's documented blind spot arriving, not a bug in it.\n *\n * ★ PER ACCOUNT, NOT PER MOUNT, BECAUSE ONE MOUNT CANNOT SOLVE ITSELF. MEASURED on the snapshot:\n * `aimto-app-alchemy-os-create` on the platform mount pairs `Email Routing Rules Write` and\n * `DNS Write` with two unknown IDs, and neither group appears alone on that mount. The dns and\n * security mounts of the same account isolate them. apply-roles.py's map was per account too\n * (apply-roles.py:117).\n */\nexport const permissionGroupsFromLiveRoles = (\n declared: ReadonlyMap<string, readonly ExpandedRole[]>,\n) =>\n Effect.gen(function* () {\n const accountOf = new Map<string, string>();\n const byAccount = new Map<string, ExpandedRole[]>();\n for (const [mount, roles] of declared) {\n for (const role of roles) {\n accountOf.set(mount, role.account);\n byAccount.set(role.account, [...(byAccount.get(role.account) ?? []), role]);\n }\n }\n const solved = new Map<string, Lookup>();\n for (const [account, roles] of byAccount) {\n const solve = Effect.gen(function* () {\n const live = new Map<string, readonly WirePolicy[]>();\n // ★ `Effect.all` over mapped reads, not `Effect.forEach`: oxlint's unicorn/no-array-for-each\n // matches the method NAME and cannot tell Effect's from Array's.\n yield* Effect.all(\n roles.map((role) =>\n Effect.map(readCloudflareRole(role.mount, role.name), (read) => {\n if (read?.policies !== undefined) {\n live.set(`${role.mount}/${role.name}`, read.policies);\n }\n }),\n ),\n { concurrency: 8, discard: true },\n );\n const result = solveGroups(observationsOf(roles, live));\n const problems = describeProblems(result);\n if (problems.length > 0) {\n return yield* Effect.fail(new CloudflareGroupsError(`account ${account}`, problems));\n }\n /**\n * ⚠️ IT ANSWERS AT EVERY SCOPE BECAUSE IT CANNOT SEE ONE. A live role carries ids and no\n * scopes, so the solver learns `name → id` and nothing more; the seven two-id names\n * resolve here to whichever id the estate happens to carry, at whatever scope is asked.\n * That is this source's blind spot, not a second opinion — (a) keys by (name, scope).\n */\n return atEveryScope(result.groups);\n });\n solved.set(account, yield* Effect.cached(solve));\n }\n return CloudflarePermissionGroups.of({\n resolve: (mount, refs) => {\n const account = accountOf.get(mountPath(mount));\n const lookup = account === undefined ? undefined : solved.get(account);\n if (account === undefined || lookup === undefined) {\n const why = 'no declared role on this mount, so no live role can vouch for its groups';\n return Effect.fail(new CloudflareGroupsError(mount, [why]));\n }\n const hint = `no live role on account ${account} carries it; a NEW group needs the engine endpoint`;\n return Effect.flatMap(lookup, (groups) => pick(mount, groups, refs, hint));\n },\n });\n });\n",
|
|
37
37
|
"/**\n * ⚠️ TEMPORARY — DELETE WITH `permissionGroupsFromLiveRoles` (cloudflare-permission-groups.ts) ONCE\n * `GET <mount>/permission-groups` IS DEPLOYED ON THE CLOUDFLARE ENGINE.\n *\n * The pure half of the bootstrap: recover permission-group name → ID from roles whose names are\n * declared (roles.yaml) and whose IDs are live (the engine).\n *\n * ★ WHY IT EXISTS AT ALL. apply-roles.py resolved names with\n * `GET /accounts/<id>/tokens/permission_groups` (cfhf.py:147-148) under a Cloudflare parent\n * credential, which agents may not use. The engine is gaining an endpoint that answers under its\n * own credential; until it ships, the only other witness is the roles apply-roles.py already\n * wrote, each pairing a list of names with a list of IDs.\n *\n * ⛔ NEVER A GUESS.\n * 1. Every entry with exactly one name and one ID binds that pair.\n * 2. Then, until nothing changes: an entry left with exactly ONE name and ONE ID not yet known\n * binds those two.\n * 3. Once settled, every entry is checked against the map: one that declares a known name without\n * carrying that name's ID CONTRADICTS it.\n * POSITIONS ARE NEVER USED, even where the Python kept yaml order — a hand-edited role would\n * otherwise teach the map a wrong pair in silence. A name bound to two IDs, or an ID bound to two\n * names, is AMBIGUOUS; a name nothing isolates is UNRESOLVED; and a contradiction is exactly\n * that. Each is an error for the whole account, not a best effort.\n *\n * ⛔ THE CONTRADICTION CHECK IS THE ONE THAT BITES, AND IT WAS FOUND BY A TEST, NOT BY DESIGN. When a\n * name has ONE single-group witness and that role was edited by hand, step 1 learns the edited ID,\n * and the multi-group roles carrying the real one merely fail to eliminate. Unchecked, diff would\n * then plan every one of those roles as an update TO THE EDITED ID — a hand edit propagated by the\n * tool meant to catch it. Which side is wrong is unknowable here; only Cloudflare knows.\n * ⚠️ THE PRICE: SOURCE (b) CANNOT PLAN A GROUP ADDED TO, OR SWAPPED IN, AN EXISTING ROLE. That edit\n * looks exactly like the hand edit above — declared names disagreeing with live IDs — so it fails\n * the account. New roles and removed groups still plan. (b) is for ADOPTION; changes wait for (a).\n *\n * ⛔ IT KEYS BY NAME AND THE ENGINE SOURCE KEYS BY (NAME, SCOPE) — DELIBERATELY UNCHANGED, 2026-09-15.\n * A live role is a list of ids with no scopes, so a name is all this can key on; seven names the\n * engine lists TWICE (once account-scoped, once zone-scoped) are one entry here, holding whichever\n * id the estate happens to carry. cloudflare-policy.ts `atEveryScope` is where that map is widened\n * to the scoped key the resolver now uses, and it is the honest shape of this blind spot: this file\n * is the OFFLINE PARITY PROOF against a production export, and rewriting it to a key it cannot\n * observe would make it agree with the engine by construction instead of by measurement.\n *\n * ⚠️ WHAT IT CANNOT CATCH. The names come from roles.yaml itself, so a group misnamed CONSISTENTLY\n * — every use of `DNS Read` spelled `DNS Reed` — pairs the wrong name with the right ID and\n * resolves cleanly, where Cloudflare would have refused it. cloudflare/parity.ts cross-checks the\n * catalog documents apply-roles.py wrote, which hold names that DID resolve against Cloudflare at\n * the last apply, for exactly that reason. The engine endpoint has no such blind spot.\n */\nimport type { WirePolicy } from './cloudflare-policy.ts';\nimport type { ExpandedRole } from './cloudflare-roles-expand.ts';\n\nexport interface Observation {\n /** `<mount>/<role>[<entry>]`, for messages. */\n readonly where: string;\n readonly names: readonly string[];\n readonly ids: readonly string[];\n}\n\nexport interface Conflict {\n /** `name` bound to several IDs, or `id` bound to several names. */\n readonly kind: 'id' | 'name';\n readonly value: string;\n readonly bound: readonly string[];\n}\n\n/** An entry declaring `name`, whose ID the map knows as `id`, without carrying `id`. */\nexport interface Contradiction {\n readonly where: string;\n readonly name: string;\n readonly id: string;\n}\n\nexport interface Solved {\n readonly groups: ReadonlyMap<string, string>;\n readonly ambiguous: readonly Conflict[];\n readonly unresolved: readonly string[];\n readonly contradicted: readonly Contradiction[];\n}\n\n/**\n * One observation per declared entry whose resource matches exactly one live entry of that role.\n *\n * ★ PAIRED BY RESOURCE, NOT BY POSITION. A zone role's account groups sit on the account resource\n * and nowhere else, whatever order the entries were stored in. An entry that shares its resource\n * with a sibling, or finds no single live match, observes nothing — the diff reports it instead.\n */\nexport const observationsOf = (\n declared: readonly ExpandedRole[],\n live: ReadonlyMap<string, readonly WirePolicy[]>,\n): Observation[] =>\n declared.flatMap((role) => {\n const entries = live.get(`${role.mount}/${role.name}`);\n if (entries === undefined) return [];\n return role.policies.flatMap((policy, i) => {\n const twins = role.policies.filter((other) => other.resource === policy.resource);\n const matching = entries.filter(\n (entry) => Object.keys(entry.resources).length === 1 && policy.resource in entry.resources,\n );\n const [only] = matching;\n if (twins.length !== 1 || matching.length !== 1 || only === undefined) return [];\n return [\n {\n ids: only.groupIds,\n names: policy.groups,\n where: `${role.mount}/${role.name}[${String(i)}]`,\n },\n ];\n });\n });\n\nconst unique = (items: readonly string[]) => [...new Set(items)];\n\nexport const solveGroups = (observations: readonly Observation[]): Solved => {\n const idsOf = new Map<string, Set<string>>();\n const namesOf = new Map<string, Set<string>>();\n const bind = (name: string, id: string) => {\n const ids = idsOf.get(name) ?? new Set<string>();\n const fresh = !ids.has(id);\n idsOf.set(name, ids.add(id));\n namesOf.set(id, (namesOf.get(id) ?? new Set<string>()).add(name));\n return fresh;\n };\n /** Known only while the name has one ID and that ID has only this name. */\n const known = (name: string) => {\n const ids = idsOf.get(name);\n const [id] = ids ?? [];\n return ids?.size === 1 && id !== undefined && namesOf.get(id)?.size === 1 ? id : undefined;\n };\n\n const shaped = observations.map((o) => ({ ids: unique(o.ids), names: unique(o.names) }));\n // 1. Every single-group entry binds, unconditionally — so a contradicting one is RECORDED as a\n // conflict rather than skipped because its name happened to be learned first.\n for (const { ids, names } of shaped) {\n const [name] = names;\n const [id] = ids;\n if (names.length === 1 && ids.length === 1 && name !== undefined && id !== undefined) {\n bind(name, id);\n }\n }\n // 2. Elimination. ⚠️ A count mismatch proves nothing about which name is which ID, so it is skipped.\n for (let changed = true; changed;) {\n changed = false;\n for (const { ids, names } of shaped) {\n if (names.length !== ids.length) continue;\n const knownIds = new Set(names.map(known));\n const openNames = names.filter((name) => known(name) === undefined);\n const openIds = ids.filter((id) => !knownIds.has(id));\n const [name] = openNames;\n const [id] = openIds;\n if (\n openNames.length === 1 &&\n openIds.length === 1 &&\n name !== undefined &&\n id !== undefined\n ) {\n changed = bind(name, id) || changed;\n }\n }\n }\n // 3. Contradictions — including entries step 2 skipped for a count mismatch.\n const contradicted: Contradiction[] = [];\n for (const o of observations) {\n for (const name of unique(o.names)) {\n const id = known(name);\n if (id !== undefined && !o.ids.includes(id)) contradicted.push({ id, name, where: o.where });\n }\n }\n\n const groups = new Map<string, string>();\n const ambiguous: Conflict[] = [];\n const unresolved: string[] = [];\n for (const name of unique(observations.flatMap((o) => o.names)).sort()) {\n const ids = idsOf.get(name);\n const id = known(name);\n if (ids === undefined) unresolved.push(name);\n else if (ids.size > 1) ambiguous.push({ bound: [...ids].sort(), kind: 'name', value: name });\n else if (id !== undefined) groups.set(name, id);\n }\n for (const [id, names] of [...namesOf].sort(([a], [b]) => (a < b ? -1 : 1))) {\n if (names.size > 1) ambiguous.push({ bound: [...names].sort(), kind: 'id', value: id });\n }\n return { ambiguous, contradicted, groups, unresolved };\n};\n\n/** Every conflict, unresolved name and contradiction, one line each. */\nexport const describeProblems = (solved: Solved): string[] => [\n ...solved.ambiguous.map((c) =>\n c.kind === 'name'\n ? `ambiguous: name ${JSON.stringify(c.value)} is bound to ids ${c.bound.join(', ')}`\n : `ambiguous: id ${c.value} is bound to names ${c.bound.map((n) => JSON.stringify(n)).join(', ')}`,\n ),\n ...solved.unresolved.map(\n (name) => `unresolved: no live role isolates ${JSON.stringify(name)} to one id`,\n ),\n ...solved.contradicted.map(\n (c) => `contradicted: ${c.where} declares ${JSON.stringify(c.name)} but lacks its id ${c.id}`,\n ),\n];\n",
|
|
38
38
|
"/**\n * A Cloudflare policy document as the engine stores it — resolution from names, parsing from a\n * read, and the one comparison every Bao.CloudflareRole plan rests on.\n *\n * MEASURED from the engine source (<estate>/platform/secrets/vault/plugin/cloudflare/path_roles.go)\n * and the 2026-09-14 snapshot of all 586 live roles:\n * • `policies` is a STRING field holding a JSON array (path_roles.go:67-72). Each entry is\n * `{effect, resources: map[string]string, permission_groups: [{id}]}` (:25-33).\n * • A read hands back `json.Marshal` of the stored slice (:199-207): no whitespace, entry and\n * group order preserved (Go slices), resource keys sorted (Go maps). Every snapshot role has\n * exactly that shape.\n */\nimport { GROUP_SCOPES, groupKey, scopeOfResource } from './cloudflare-group-scope.ts';\nimport type { DeclaredPolicy } from './cloudflare-roles-expand.ts';\n\nexport interface WirePolicy {\n readonly effect: string;\n readonly resources: Readonly<Record<string, string>>;\n readonly groupIds: readonly string[];\n}\n\n/** A declared entry with its IDs, still carrying how its group order is to be compared. */\nexport interface ResolvedPolicy extends WirePolicy {\n readonly groupOrder: DeclaredPolicy['groupOrder'];\n}\n\n/**\n * One name at every scope — what a source that cannot see scopes can honestly offer.\n *\n * ⚠️ IT IS A WIDENING, AND IT IS THE ASYMMETRY BETWEEN THE TWO SOURCES. The live-roles bootstrap\n * and cloudflare-permission-groups-solve.ts recover `name → id` from roles that carry ids and no\n * scopes, so they cannot tell the seven two-id names apart; the id they learned is offered for\n * whatever scope an entry asks. The engine source keys by (name, scope) and never does this.\n */\nexport const atEveryScope = (byName: ReadonlyMap<string, string>): ReadonlyMap<string, string> =>\n new Map(\n [...byName].flatMap(([name, id]) =>\n Object.values(GROUP_SCOPES).map((scope) => [groupKey(name, scope), id] as const),\n ),\n );\n\n/**\n * Declared names to IDs, or the names `ids` lacks.\n *\n * ⛔ AN ENTRY LOOKS ITS GROUPS UP AT ITS OWN SCOPE (`groupKey`), not by name: a zone entry and an\n * account entry of the same role can name one group and mean two different ids.\n * ★ THE ACCOUNT ENTRY IS SORTED BY ID, EXACTLY AS cfhf.py:180 DID. ⚠️ Plain `sort()`, never\n * `localeCompare`: Python's `sorted()` on str is codepoint order, and JavaScript's default sort\n * is UTF-16 code-unit order, which agree on the lowercase hex these IDs are made of.\n */\nexport const resolvePolicies = (\n declared: readonly DeclaredPolicy[],\n ids: ReadonlyMap<string, string>,\n): { readonly policies: ResolvedPolicy[]; readonly missing: string[] } => {\n const missing = new Set<string>();\n const policies = declared.map((policy) => {\n /**\n * ⛔ THE ENTRY'S OWN WORD BEATS ITS RESOURCE. `scope` is roles.yaml `groups_scope:` reaching\n * here unchanged; `scopeOfResource` is the default for the 639 of 643 references that say\n * nothing. The four that do are `logs`/`logs-read` on both security mounts — ACCOUNT roles\n * whose live entry carries the ZONE-scoped `Logs` ids, which is how Cloudflare writes \"all\n * zones from an account\" (cf-mint-analytics-tokens.py:155-158).\n */\n const scope = policy.scope ?? scopeOfResource(policy.resource);\n const groupIds = policy.groups.flatMap((name) => {\n const id = ids.get(groupKey(name, scope));\n if (id === undefined) missing.add(name);\n return id === undefined ? [] : [id];\n });\n return {\n effect: policy.effect,\n groupIds: policy.groupOrder === 'by-id' ? [...groupIds].sort() : groupIds,\n groupOrder: policy.groupOrder,\n resources: { [policy.resource]: '*' },\n };\n });\n return { missing: [...missing].sort(), policies };\n};\n\nconst isRecord = (value: unknown): value is Readonly<Record<string, unknown>> =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst stringMap = (value: unknown): Readonly<Record<string, string>> | undefined => {\n if (!isRecord(value)) return undefined;\n const out: Record<string, string> = {};\n for (const [key, item] of Object.entries(value)) {\n if (typeof item !== 'string') return undefined;\n out[key] = item;\n }\n return out;\n};\n\nconst entryOf = (entry: unknown): WirePolicy | undefined => {\n if (!isRecord(entry) || typeof entry['effect'] !== 'string') return undefined;\n const resources = stringMap(entry['resources']);\n const groups = entry['permission_groups'];\n if (resources === undefined || !Array.isArray(groups)) return undefined;\n const groupIds = groups.flatMap((group) =>\n isRecord(group) && typeof group['id'] === 'string' ? [group['id']] : [],\n );\n return groupIds.length === groups.length\n ? { effect: entry['effect'], groupIds, resources }\n : undefined;\n};\n\n/**\n * The live `policies` string parsed, or undefined when it is not a policy document.\n *\n * ⚠️ UNDEFINED IS NOT ABSENCE. It means the role exists and its policies could not be read, which\n * compares unequal to every declaration — so it plans `update`, and reconcile's re-read refuses\n * to call a write that still reads back like that a success.\n */\nexport const parseLivePolicies = (raw: unknown): WirePolicy[] | undefined => {\n if (typeof raw !== 'string') return undefined;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return undefined;\n }\n if (!Array.isArray(parsed)) return undefined;\n const policies = parsed.map(entryOf);\n return policies.every((policy): policy is WirePolicy => policy !== undefined)\n ? policies\n : undefined;\n};\n\n/**\n * The `policies` field for a write — the array cfhf.py:174-180 built, serialized.\n *\n * ⚠️ NOT BYTE-IDENTICAL TO WHAT PYTHON SENT, AND IT NEED NOT BE. `json.dumps` put a space after\n * every `:` and `,`; this emits none. The engine unmarshals the string into structs\n * (path_roles.go:161-166) and stores those, never the text, so the stored role and the read\n * that diff compares are the same either way.\n */\nexport const policiesJson = (policies: readonly WirePolicy[]) =>\n JSON.stringify(\n policies.map((policy) => ({\n effect: policy.effect,\n resources: policy.resources,\n permission_groups: policy.groupIds.map((id) => ({ id })),\n })),\n );\n\nconst sameList = (a: readonly string[], b: readonly string[]) =>\n a.length === b.length && a.every((item, i) => item === b[i]);\n\nconst sameResources = (\n a: Readonly<Record<string, string>>,\n b: Readonly<Record<string, string>>,\n) => {\n const keys = Object.keys(a);\n return keys.length === Object.keys(b).length && keys.every((key) => a[key] === b[key]);\n};\n\n/**\n * ⛔ THE POLICY EQUALITY.\n *\n * • Entry count and entry ORDER must match: cfhf.py always wrote the scope entry first and the\n * account entry second (cfhf.py:174-180).\n * • Within an entry: effect, the resource map, and the group IDs — IN ORDER for a `declared`\n * entry, because cfhf.py:175 kept yaml order; AS A SORTED LIST for a `by-id` entry, because\n * cfhf.py:180 sorted it, so its order never carried meaning.\n *\n * ⚠️ NOT ORDER-INSENSITIVE EVERYWHERE, ON PURPOSE. Cloudflare treats a group list as a set, so a\n * reordered `declared` entry mints an identical token — and still plans `update` here. The\n * Python would have rewritten it as well, and an adoption that is noop only up to reordering\n * would not prove the port exact.\n */\nexport const samePolicies = (want: readonly ResolvedPolicy[], have: readonly WirePolicy[]) =>\n want.length === have.length &&\n want.every((w, i) => {\n const h = have[i];\n if (h === undefined || w.effect !== h.effect || !sameResources(w.resources, h.resources)) {\n return false;\n }\n return w.groupOrder === 'by-id'\n ? sameList([...w.groupIds].sort(), [...h.groupIds].sort())\n : sameList(w.groupIds, h.groupIds);\n });\n",
|
|
39
|
-
"/**\n * The OpenBao calls Bao.CloudflareRole and the live-roles bootstrap make — read, write and delete\n * of `<mount>/roles/<name>`. Split out so each can be tested against fake-bao.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
39
|
+
"/**\n * The OpenBao calls Bao.CloudflareRole and the live-roles bootstrap make — read, write and delete\n * of `<mount>/roles/<name>`. Split out so each can be tested against fake-bao.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\nimport { type LiveCloudflareRole, liveRoleOf, rolePath } from './cloudflare-role-form.ts';\n\n/**\n * The live role, or undefined when the engine answers 404.\n *\n * ⚠️ A MISSING MOUNT AND A MISSING ROLE BOTH READ AS UNDEFINED — both are a 404 from OpenBao, the\n * first as \"no handler for route\". That is proxmox-role.ts's ⚠️ in full: the WRITE is what tells\n * them apart, and it lets OpenBao's own `errors` through. A 403 or 503 is never absence\n * (bao-status.ts).\n */\nexport const readCloudflareRole = (\n mount: string,\n name: string,\n): Effect.Effect<LiveCloudflareRole | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.map(baoRead(rolePath(mount, name)), (data) =>\n data === undefined ? undefined : liveRoleOf(data),\n );\n\n/** ★ `PUT`, which is what `bao write` sent (bao-http.ts). A 404 here fails — see readCloudflareRole. */\nexport const writeCloudflareRole = (\n mount: string,\n name: string,\n body: Readonly<Record<string, string>>,\n) => baoWrite('PUT', rolePath(mount, name), body);\n\n/**\n * Idempotent as Alchemy requires — already gone (404) is success, a refusal is not.\n *\n * ⚠️ THE ENGINE'S DELETE IS ONE STORAGE DELETE (path_roles.go:214-216). Tokens the role already\n * minted are leases, and they live to their own expiry.\n */\nexport const deleteCloudflareRole = (mount: string, name: string) =>\n baoDelete(rolePath(mount, name));\n",
|
|
40
40
|
"/**\n * Props, attributes and field comparison for Bao.CloudflareRole — the resource is\n * cloudflare-role.ts, the policy document rules are cloudflare-policy.ts.\n *\n * MEASURED from the engine (<estate>/platform/secrets/vault/plugin/cloudflare/path_roles.go) and the\n * 2026-09-14 snapshot of all 586 live roles:\n * • A role is name, description, policies, ttl and max_ttl AND NOTHING ELSE (path_roles.go:14-20\n * stores those; :204-210 returns them). Every snapshot read carries exactly those five keys, so\n * `differences` below covers the whole server-side object — no unmanaged field can drift\n * behind a green plan.\n * • ttl and max_ttl are TypeDurationSecond (:73-80) and read back as integer seconds.\n * • ⚠️ A WRITE MERGES, IT DOES NOT REPLACE (:117-146). The handler loads the stored role and\n * overwrites only the fields present — the opposite of the proxmox engine, where an omitted\n * field is zeroed. writeBody sends all four anyway, so a write always lands the whole\n * declaration and can never leave an old description behind a new policy.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES, AND THERE IS NONE TO LEAK. A role is permission-group IDs, a\n * zone or account resource, a sentence and two TTLs. The parent token lives at `<mount>/config`\n * and a minted token at `<mount>/creds/<name>`; nothing in this family reads either path. Keep\n * it that way — Alchemy persists attributes unencrypted (see policy.ts).\n */\nimport {\n type ResolvedPolicy,\n type WirePolicy,\n parseLivePolicies,\n policiesJson,\n samePolicies,\n} from './cloudflare-policy.ts';\nimport type { DeclaredPolicy } from './cloudflare-roles-expand.ts';\nimport { sha256 } from './digest.ts';\nimport { mountPath, parseDuration } from './mount-form.ts';\n\nexport interface BaoCloudflareRoleProps {\n /** Mount of the Cloudflare secrets engine, e.g. `cloudflare-<account>-dns`. */\n mount: string;\n /** Role name. ⛔ Consumers mint by it — see cloudflare-roles-expand.ts before changing one. */\n name: string;\n /** The description as written: a zone role's carries its ` (zone: <name>)` suffix. */\n description: string;\n /** Default lease TTL, e.g. `5m`. */\n ttl: string;\n /** Maximum lease TTL, e.g. `1h`. */\n maxTtl: string;\n /**\n * Policy entries, groups by NAME. The provider resolves them through CloudflarePermissionGroups\n * at diff and reconcile time; an ID is never a prop, so a plan can never persist a guessed one.\n */\n policies: DeclaredPolicy[];\n}\n\nexport interface BaoCloudflareRoleAttributes {\n mount: string;\n name: string;\n description: string;\n /** Live ttl in seconds, as the engine stores it. */\n ttl: number;\n /** Live max_ttl in seconds. */\n maxTtl: number;\n /** Live `policies` JSON — group IDs and a resource, never a credential. */\n policies: string;\n /** SHA-256 of the fields above — safe to persist; see policy.ts. */\n digest: string;\n}\n\n/** One live role, as a read returns it. */\nexport interface LiveCloudflareRole {\n readonly name: string;\n readonly description: string;\n readonly ttl: number | undefined;\n readonly maxTtl: number | undefined;\n readonly policiesText: string;\n /** Undefined when `policies` is not a policy document — see parseLivePolicies. */\n readonly policies: readonly WirePolicy[] | undefined;\n}\n\nexport interface RoleDifference {\n readonly field: 'description' | 'max_ttl' | 'policies' | 'ttl';\n readonly want: string;\n readonly have: string;\n}\n\n/** `cloudflare-<account>-dns/roles/example-dns-read` — read, write and delete use it. */\nexport const rolePath = (mount: string, name: string) => `${mountPath(mount)}/roles/${name}`;\n\nconst seconds = (value: unknown) =>\n typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n\n/** A read's `data`, shaped. Lenient on purpose: a malformed field compares unequal, loudly. */\nexport const liveRoleOf = (data: Readonly<Record<string, unknown>>): LiveCloudflareRole => ({\n description: typeof data['description'] === 'string' ? data['description'] : '',\n maxTtl: seconds(data['max_ttl']),\n name: typeof data['name'] === 'string' ? data['name'] : '',\n policies: parseLivePolicies(data['policies']),\n policiesText: typeof data['policies'] === 'string' ? data['policies'] : '',\n ttl: seconds(data['ttl']),\n});\n\n/**\n * ⚠️ Every value is taken from `live`, the prop only standing in for a missing `name` — the same\n * split the sibling families use, so a read never launders the declaration back as \"current\".\n */\nexport const attributesOf = (\n props: Pick<BaoCloudflareRoleProps, 'mount' | 'name'>,\n live: LiveCloudflareRole,\n): BaoCloudflareRoleAttributes => {\n const attrs = {\n description: live.description,\n maxTtl: live.maxTtl ?? 0,\n mount: mountPath(props.mount),\n name: live.name || props.name,\n policies: live.policiesText,\n ttl: live.ttl ?? 0,\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\n/**\n * Why reconcile must refuse this declaration, or undefined.\n *\n * ⛔ AN UNPARSEABLE TTL IS A REFUSAL, NOT A ZERO: it can never equal the live seconds, so it would\n * plan `update` forever. ⛔ AN EMPTY POLICY LIST OR AN ENTRY WITH NO GROUPS IS A REFUSAL TOO — the\n * engine rejects both (path_roles.go:147-149, :175-180), and saying so before the write names the\n * declaration instead of quoting the server.\n */\nexport const refusalOf = (props: BaoCloudflareRoleProps): string | undefined => {\n const bad = [\n ...(parseDuration(props.ttl) === undefined ? [`ttl=${props.ttl}`] : []),\n ...(parseDuration(props.maxTtl) === undefined ? [`maxTtl=${props.maxTtl}`] : []),\n ];\n if (bad.length > 0) return `unparseable duration ${bad.join(', ')} (use 30s / 5m / 1h / 1d)`;\n if (props.policies.length === 0) return 'no policy entries';\n if (props.policies.some((policy) => policy.groups.length === 0)) return 'a policy with no groups';\n return undefined;\n};\n\n/**\n * The body for `PUT <mount>/roles/<name>` — the four `k=v` pairs apply-roles.py:157-162 sent.\n *\n * ★ THE TTLs GO AS THE DECLARED TEXT (`5m`), which is what `bao write ttl=5m` put in the JSON body,\n * and TypeDurationSecond parses it server-side. `policies` is a string because the field is a\n * string (path_roles.go:67-68), not because the engine wants the whole body stringly-typed.\n */\nexport const writeBody = (props: BaoCloudflareRoleProps, policies: readonly WirePolicy[]) => ({\n description: props.description,\n max_ttl: props.maxTtl,\n policies: policiesJson(policies),\n ttl: props.ttl,\n});\n\nconst sameTtl = (want: string, have: number | undefined) => {\n const wantSeconds = parseDuration(want);\n return wantSeconds !== undefined && wantSeconds === have;\n};\n\n/**\n * Every field where live differs from the resolved declaration. Empty means noop.\n *\n * ⛔ apply-roles.py --verify COMPARED NONE OF THESE. It lists `<mount>/roles` and reports names\n * only: MISSING when roles.yaml has a role the vault lacks, UNTRACKED for the reverse\n * (apply-roles.py:136-141, :167-173, :179-185). It never read a role. So this equality is new: the\n * four fields --apply WRITES (apply-roles.py:157-162), compared the way the engine reads them back\n * — durations as seconds, description exactly, policies by the rules in samePolicies.\n */\nexport const differences = (\n props: Pick<BaoCloudflareRoleProps, 'description' | 'maxTtl' | 'ttl'>,\n policies: readonly ResolvedPolicy[],\n live: LiveCloudflareRole,\n): RoleDifference[] => {\n const out: RoleDifference[] = [];\n if (props.description !== live.description) {\n out.push({ field: 'description', have: live.description, want: props.description });\n }\n if (!sameTtl(props.ttl, live.ttl)) {\n out.push({ field: 'ttl', have: String(live.ttl), want: props.ttl });\n }\n if (!sameTtl(props.maxTtl, live.maxTtl)) {\n out.push({ field: 'max_ttl', have: String(live.maxTtl), want: props.maxTtl });\n }\n if (live.policies === undefined || !samePolicies(policies, live.policies)) {\n out.push({ field: 'policies', have: live.policiesText, want: policiesJson(policies) });\n }\n return out;\n};\n",
|
|
41
41
|
"/**\n * The roles.yaml expansion — surfaces × accounts × zones into concrete roles — ported from\n * cfroles.py `expand` and cfhf.py `policy_for`, with permission groups still by NAME.\n *\n * ★ PURE, AND NAMES STAY NAMES. The Python resolved names to IDs in the same pass\n * (apply-roles.py:144-150), with a Cloudflare credential in hand. Agents may not hold that\n * credential, so resolution is a separate step behind one interface\n * (cloudflare-permission-groups.ts) and nothing here knows where IDs come from.\n *\n * ⛔ THE NAMING AND THE ZONE RULES ARE CONTRACTS WITH EVERY CONSUMER. apply-consumers.py grants\n * `creds/<slug(zone)>-*` by zone (apply-consumers.py:117-120) and agents mint by role name, so a\n * role a port renames is a role nothing can mint. Each rule cites the line it came from, and\n * cloudflare/parity.ts proves the whole expansion against production.\n */\nimport { accountResource, bucketResource, zoneResource } from './cloudflare-group-scope.ts';\nimport type { AccountSpec, RoleTemplate, RolesConfig } from './cloudflare-roles-config.ts';\nimport { trimRuns } from './mount-path.ts';\n\n/** A zone as the expansion needs it — what cfhf.py load_account listed (cfhf.py:134-146). */\nexport interface CloudflareZone {\n readonly name: string;\n readonly id: string;\n /** From the `type=internal` listing. ⚠️ Shares its NAME with the public zone, never its id. */\n readonly internal: boolean;\n}\n\n/**\n * One policy entry, groups by name.\n *\n * ★ `groupOrder` CARRIES A PYTHON RULE THAT ONLY EXISTS AFTER RESOLUTION. cfhf.py:180 sorts the\n * account entry's group IDS — not its names — so that order cannot be computed here, only\n * promised. A `declared` entry keeps roles.yaml order, exactly as cfhf.py:175 emitted it.\n */\nexport interface DeclaredPolicy {\n readonly effect: 'allow';\n readonly resource: string;\n readonly groups: readonly string[];\n readonly groupOrder: 'declared' | 'by-id';\n /**\n * The scope these NAMES resolve at, when it is not this entry's own resource namespace —\n * roles.yaml `groups_scope:`, already a GROUP_SCOPES value. Undefined on every entry that does\n * not say otherwise, which is 639 of the estate's 643 group references.\n *\n * ⛔ IT MOVES THE LOOKUP, NEVER THE RESOURCE. The entry still binds the groups to the resource\n * above; only the id chosen for each name changes. That is the shape Cloudflare calls \"all\n * zones from an account\" — the ACCOUNT resource carrying ZONE-scoped groups\n * (<estate>/nix/scripts/cf-mint-analytics-tokens.py:155-158, beside a working\n * token). Without this field the resource is the only witness, and it says `account`.\n */\n readonly scope?: string;\n}\n\n/** What apply-roles.py wrote to the KV catalog for one role (apply-roles.py:58-62). */\nexport interface CatalogView {\n readonly description: string;\n readonly zone: string | null;\n readonly ttl: string;\n readonly maxTtl: string;\n readonly permissions: readonly string[];\n}\n\nexport interface ExpandedRole {\n readonly account: string;\n readonly accountId: string;\n readonly mount: string;\n readonly surface: string;\n readonly name: string;\n /** Exactly what apply-roles.py:160-161 wrote — the zone suffix included. */\n readonly description: string;\n readonly ttl: string;\n readonly maxTtl: string;\n readonly policies: readonly DeclaredPolicy[];\n readonly catalog: CatalogView;\n}\n\n/** cfroles.py:18-20 — `example.com` → `homeflare-dev`. */\nexport const slug = (name: string) => trimRuns(name.toLowerCase().replace(/[^a-z0-9]+/g, '-'), '-');\n\n/**\n * cfroles.py:23-38. ⛔ THE `-internal` SUFFIX IS WHAT KEEPS TWO ZONES OF ONE NAME APART. Slugging\n * both example.com zones alike would leave two roles fighting for one name, and whichever\n * wrote last would silently own it.\n */\nexport const zoneSlug = (zone: CloudflareZone) =>\n `${slug(zone.name)}${zone.internal ? '-internal' : ''}`;\n\n/** cfroles.py:46-47 — one mount, and so one parent token, per (account, surface). */\nexport const mountName = (account: string, surface: string) => `cloudflare-${account}-${surface}`;\n\n/**\n * cfhf.py:151-181. ⛔ ONE ENTRY PER SCOPE, NEVER MERGED: Cloudflare gates a permission at one\n * scope only, so a zone role that also needs account groups gets a SECOND entry on the account\n * resource. ⚠️ `if account_group_ids:` — an empty list emits no second entry (cfhf.py:176).\n */\nconst policiesFor = (\n tpl: RoleTemplate,\n accountId: string,\n zone: CloudflareZone | null,\n accountGroups: readonly string[],\n): DeclaredPolicy[] => {\n /**\n * ⛔ A BUCKET NARROWS THE ACCOUNT RESOURCE; IT NEVER NARROWS A ZONE. A zone role scoped to an R2\n * bucket is not a narrower grant, it is an incoherent one — the groups a zone role carries are\n * gated at the zone and would be refused against a bucket resource. Refusing here is the only\n * place that can tell the difference; roles.yaml cannot express the contradiction as a type.\n */\n if (tpl.bucket !== undefined && zone !== null) {\n throw new Error(`${tpl.name}: a zone role cannot be scoped to R2 bucket ${tpl.bucket}`);\n }\n const accountScoped =\n tpl.bucket === undefined\n ? accountResource(accountId)\n : bucketResource(accountId, tpl.bucketJurisdiction, tpl.bucket);\n const resource = zone === null ? accountScoped : zoneResource(zone.id);\n const first: DeclaredPolicy = {\n effect: 'allow',\n groupOrder: 'declared',\n groups: tpl.groups,\n resource,\n /**\n * ⚠️ `groups_scope:` GOVERNS `groups:` AND NOTHING ELSE. The second entry below exists because\n * `account_groups` are account-scoped BY CONSTRUCTION (cfhf.py:176-180) — overriding its\n * scope from the same key would make one word mean two things in one template.\n * ★ OMITTED, NOT SET TO THE DEFAULT, WHEN THE yaml IS SILENT: an always-present field would\n * rewrite the stored props of all 594 declared roles to say what the resource already said.\n */\n ...(tpl.groupsScope === undefined ? {} : { scope: tpl.groupsScope }),\n };\n if (accountGroups.length === 0) return [first];\n const second: DeclaredPolicy = {\n effect: 'allow',\n groupOrder: 'by-id',\n groups: accountGroups,\n resource: accountResource(accountId),\n };\n return [first, second];\n};\n\nconst build = (\n account: AccountSpec,\n surface: string,\n tpl: RoleTemplate,\n zone: CloudflareZone | null,\n accountGroups: readonly string[],\n): ExpandedRole => ({\n account: account.key,\n accountId: account.id,\n catalog: {\n description: tpl.desc,\n maxTtl: tpl.maxTtl,\n // apply-roles.py:61 — groups then account_groups, names, in file order.\n permissions: [...tpl.groups, ...accountGroups],\n ttl: tpl.ttl,\n zone: zone === null ? null : zone.name,\n },\n /**\n * apply-roles.py:160-161. ⚠️ THE ZONE NAME, NOT ITS SLUG, so a public zone and its internal\n * twin describe alike, and an empty `desc` still gains the suffix after a leading space.\n */\n description: zone === null ? tpl.desc : `${tpl.desc} (zone: ${zone.name})`,\n maxTtl: tpl.maxTtl,\n mount: mountName(account.key, surface),\n // cfroles.py:84 for zone roles, :98 for account roles.\n name: zone === null ? tpl.name : `${zoneSlug(zone)}-${tpl.name}`,\n policies: policiesFor(tpl, account.id, zone, accountGroups),\n surface,\n ttl: tpl.ttl,\n});\n\n/** cfroles.py:50-104 for one account, in the Python's order: per surface, zone roles first. */\nexport const expandAccount = (\n config: RolesConfig,\n account: AccountSpec,\n zones: readonly CloudflareZone[],\n): ExpandedRole[] => {\n const roles: ExpandedRole[] = [];\n for (const surface of account.surfaces) {\n const spec = config.surfaces[surface];\n if (spec === undefined) throw new Error(`surface ${surface} is not defined`);\n for (const tpl of spec.zoneRoles) {\n const only = tpl.zones;\n /**\n * ⛔ INTERNAL ZONES ARE OPT-IN PER TEMPLATE AND THE DEFAULT IS NO (cfroles.py:68-74). Only the\n * word `internal` in zone_types matters; `full` and `secondary` are never checked, so a\n * public zone of any type expands.\n */\n const internalOk = tpl.zoneTypes.includes('internal');\n for (const zone of zones) {\n if (account.zones !== 'all' && !account.zones.includes(zone.name)) continue; // :76\n if (only !== undefined && only.length > 0 && !only.includes(zone.name)) continue; // :78\n if (zone.internal && !internalOk) continue; // :80\n roles.push(build(account, surface, tpl, zone, tpl.accountGroups));\n }\n }\n // cfroles.py:96-103 — `account_groups` is [] on an account role, whatever the yaml says.\n for (const tpl of spec.accountRoles) roles.push(build(account, surface, tpl, null, []));\n }\n return roles;\n};\n\n/**\n * Every account's roles, grouped by mount.\n *\n * ⛔ A DUPLICATE ROLE ON ONE MOUNT IS AN ERROR HERE. apply-roles.py wrote both and the last write\n * won in silence (apply-roles.py:157-162); declared, they are two resources fighting over one\n * object. ⚠️ A MISSING ZONE INVENTORY IS AN ERROR TOO — an empty one is not, because an account\n * with no zones is real, and the Python expanded it to account roles only.\n */\nexport const expandAll = (\n config: RolesConfig,\n zonesByAccount: Readonly<Record<string, readonly CloudflareZone[]>>,\n): ReadonlyMap<string, readonly ExpandedRole[]> => {\n const byMount = new Map<string, ExpandedRole[]>();\n const seen = new Set<string>();\n for (const account of config.accounts) {\n const zones = zonesByAccount[account.key];\n if (zones === undefined) throw new Error(`no zone inventory for account ${account.key}`);\n for (const role of expandAccount(config, account, zones)) {\n const key = `${role.mount}/roles/${role.name}`;\n if (seen.has(key)) throw new Error(`roles.yaml expands ${key} twice`);\n seen.add(key);\n const mount = byMount.get(role.mount) ?? [];\n mount.push(role);\n byMount.set(role.mount, mount);\n }\n }\n return byMount;\n};\n",
|
|
42
42
|
"/**\n * roles.yaml, parsed and checked — the input half of the Cloudflare role expansion. The expansion\n * itself is cloudflare-roles-expand.ts.\n *\n * ★ BUN's OWN PARSER, NO DEPENDENCY. `Bun.YAML.parse` ships in Bun 1.4 — MEASURED on 1.4.0:\n * `typeof Bun.YAML` is `object` with `parse` and `stringify`, typed in bun-types 1.4.2\n * (bun.d.ts:1479). The Python read the same file with PyYAML's `safe_load` (cfroles.py:41-43).\n * ⚠️ THEY ARE DIFFERENT PARSERS, SO THE SHAPE IS CHECKED, NOT TRUSTED. The file leans on flow\n * mappings (`- { name: dns-edit, groups: [DNS Write] }`), and a bare `5m` must stay a string.\n * MEASURED against roles.yaml: both parsers give `ttl` as the string `5m`, and both keep\n * `'Access: Apps and Policies Write'` as one name. parity.ts against the live snapshot is the\n * end-to-end proof; a field of the wrong type fails loudly here instead of expanding to nonsense.\n *\n * ⛔ A MISSING FIELD IS AN ERROR, NEVER A DEFAULT — except exactly where the Python defaulted:\n * `desc` to '' (cfroles.py:86, :100), an account's `zones` to \"all\" (:57), `surfaces`,\n * `zone_roles` and `account_roles` to empty (:59, :62, :96), `zone_types` to empty (:74) and\n * `account_groups` to empty (:90). Everywhere else the Python raised KeyError, and so does this.\n *\n * ⚠️ `consumers:` IS NOT READ HERE. It belongs to apply-consumers.py, and declaring it is the next\n * phase — see the report that came with this file.\n */\nimport { GROUP_SCOPES, groupScopeNamed } from './cloudflare-group-scope.ts';\n\n/** One `zone_roles` or `account_roles` entry. */\nexport interface RoleTemplate {\n readonly name: string;\n readonly groups: readonly string[];\n /** Duration text exactly as written (`5m`), which is what apply-roles.py sent. */\n readonly ttl: string;\n readonly maxTtl: string;\n readonly desc: string;\n /** `zones:` narrowing. Undefined or empty narrows nothing — `if only and …` (cfroles.py:78). */\n readonly zones: readonly string[] | undefined;\n readonly zoneTypes: readonly string[];\n /** Account-scoped groups on a ZONE role. Ignored on account roles, as cfroles.py:101 ignores it. */\n readonly accountGroups: readonly string[];\n /**\n * One R2 bucket NAME, narrowing an account role's resource to that bucket alone.\n *\n * ⛔ BUCKET IS THE FINEST GRAIN R2 HAS — A PREFIX CANNOT BE SCOPED. So one repository per\n * instance in its own bucket is the only least-privilege shape for a backup credential, and\n * this field is what expresses it. Undefined leaves the role account-wide, which is what every\n * role declared before 2026-09-15 is.\n * ⚠️ IT ONLY MEANS ANYTHING WITH THE `Bucket Item` GROUPS. `Workers R2 Storage Write` is gated at\n * the ACCOUNT scope, so pairing it with a bucket resource is a token Cloudflare will mint and\n * that will then be refused on every call. roles.yaml says which pair goes with which.\n */\n readonly bucket: string | undefined;\n /**\n * The bucket's jurisdiction, which is part of its resource id and not cosmetic — a bucket\n * created in `default` is a different resource from the same name under `eu`. Defaults to\n * `default`, which is what every bucket in this estate is (measured: `r2_bucket_get` reports\n * `jurisdiction default` on all 34).\n */\n readonly bucketJurisdiction: string;\n /**\n * roles.yaml `groups_scope:` — the scope this template's `groups:` NAMES resolve at, as a\n * GROUP_SCOPES value. Undefined means the entry's own resource namespace, which is every\n * template written before 2026-09-15.\n *\n * ⛔ IT SAYS WHICH ID, NOT WHICH RESOURCE. `groups_scope: zone` on an ACCOUNT role keeps the\n * account resource and takes the zone-scoped id of each name — Cloudflare's \"all zones from\n * this account\" (cf-mint-analytics-tokens.py:155-158). It is meaningful only for the seven\n * names the engine lists at two scopes; anywhere else the name has one id and answers alike.\n */\n readonly groupsScope: string | undefined;\n}\n\nexport interface SurfaceSpec {\n readonly zoneRoles: readonly RoleTemplate[];\n readonly accountRoles: readonly RoleTemplate[];\n}\n\nexport interface AccountSpec {\n /** The key under `accounts:` — the `<account>` in `cloudflare-<account>-<surface>`. */\n readonly key: string;\n readonly id: string;\n readonly zones: 'all' | readonly string[];\n readonly surfaces: readonly string[];\n}\n\nexport interface RolesConfig {\n readonly namespace: string;\n readonly surfaces: Readonly<Record<string, SurfaceSpec>>;\n /** In file order, which is the order apply-roles.py walked them (apply-roles.py:111). */\n readonly accounts: readonly AccountSpec[];\n}\n\nexport class RolesConfigError extends Error {\n constructor(where: string, problem: string) {\n super(`roles.yaml ${where}: ${problem}`);\n this.name = 'RolesConfigError';\n }\n}\n\ntype Raw = Readonly<Record<string, unknown>>;\n\nconst isRaw = (value: unknown): value is Raw =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst record = (value: unknown, where: string): Raw => {\n if (!isRaw(value)) throw new RolesConfigError(where, 'expected a mapping');\n return value;\n};\n\nconst text = (raw: Raw, key: string, where: string): string => {\n const value = raw[key];\n if (typeof value === 'string') return value;\n /**\n * ⚠️ STRICTER THAN THE PYTHON FOR A NUMBER. `ttl: 300` would have reached `bao write` as `300`\n * and been read as seconds. Every duration in roles.yaml is unit-suffixed, and the comparison\n * in cloudflare-role-form.ts only parses unit-suffixed text, so a bare number is refused here\n * rather than planning an update that can never settle.\n */\n throw new RolesConfigError(`${where}.${key}`, `expected a string, got ${JSON.stringify(value)}`);\n};\n\nconst texts = (raw: Raw, key: string, where: string): readonly string[] | undefined => {\n const value = raw[key];\n if (value === undefined || value === null) return undefined;\n if (Array.isArray(value) && value.every((item): item is string => typeof item === 'string')) {\n return value;\n }\n throw new RolesConfigError(`${where}.${key}`, 'expected a list of strings');\n};\n\nconst entries = (raw: Raw, key: string, where: string): readonly unknown[] => {\n const value = raw[key];\n if (value === undefined || value === null) return [];\n if (!Array.isArray(value)) throw new RolesConfigError(`${where}.${key}`, 'expected a list');\n return value;\n};\n\nconst template = (value: unknown, where: string): RoleTemplate => {\n const raw = record(value, where);\n const groups = texts(raw, 'groups', where);\n if (groups === undefined) throw new RolesConfigError(`${where}.groups`, 'is required');\n /**\n * ⚠️ `bucket` IS OPTIONAL BUT NEVER EMPTY. `bucket: ''` would expand to the resource\n * `…r2.bucket.<acct>_default_`, which is not a bucket and not the account either — a policy\n * that names nothing. A missing key means account-wide; a present one must name a bucket.\n */\n const bucket = raw['bucket'] === undefined ? undefined : text(raw, 'bucket', where);\n if (bucket !== undefined && bucket.length === 0) {\n throw new RolesConfigError(`${where}.bucket`, 'is empty; omit it to stay account-wide');\n }\n /**\n * ⛔ AN UNKNOWN WORD IS AN ERROR, NEVER A PASS-THROUGH. A scope roles.yaml invents matches no\n * group at all, so accepting it would turn a typo into \"unknown group X at scope zonee\" at\n * deploy time — a failure naming the group rather than the line that is wrong.\n */\n const groupsScope =\n raw['groups_scope'] === undefined\n ? undefined\n : groupScopeNamed(text(raw, 'groups_scope', where));\n if (raw['groups_scope'] !== undefined && groupsScope === undefined) {\n throw new RolesConfigError(\n `${where}.groups_scope`,\n `expected one of ${Object.keys(GROUP_SCOPES).join(', ')}`,\n );\n }\n return {\n accountGroups: texts(raw, 'account_groups', where) ?? [],\n bucket,\n bucketJurisdiction:\n raw['bucket_jurisdiction'] === undefined\n ? 'default'\n : text(raw, 'bucket_jurisdiction', where),\n desc: raw['desc'] === undefined ? '' : text(raw, 'desc', where),\n groups,\n groupsScope,\n maxTtl: text(raw, 'max_ttl', where),\n name: text(raw, 'name', where),\n ttl: text(raw, 'ttl', where),\n zoneTypes: texts(raw, 'zone_types', where) ?? [],\n zones: texts(raw, 'zones', where),\n };\n};\n\nconst surface = (name: string, value: unknown): SurfaceSpec => {\n const where = `surfaces.${name}`;\n const raw = record(value, where);\n return {\n accountRoles: entries(raw, 'account_roles', where).map((item, i) =>\n template(item, `${where}.account_roles[${String(i)}]`),\n ),\n zoneRoles: entries(raw, 'zone_roles', where).map((item, i) =>\n template(item, `${where}.zone_roles[${String(i)}]`),\n ),\n };\n};\n\nconst account = (\n key: string,\n value: unknown,\n surfaces: Readonly<Record<string, SurfaceSpec>>,\n): AccountSpec => {\n const where = `accounts.${key}`;\n const raw = record(value, where);\n const names = texts(raw, 'surfaces', where) ?? [];\n for (const name of names) {\n /** ⚠️ cfroles.py:60 would raise KeyError at expansion; this says which account named it. */\n if (surfaces[name] === undefined) {\n throw new RolesConfigError(\n `${where}.surfaces`,\n `names ${name}, which surfaces: never defines`,\n );\n }\n }\n const zones =\n raw['zones'] === undefined || raw['zones'] === 'all' ? 'all' : texts(raw, 'zones', where);\n return { id: text(raw, 'id', where), key, surfaces: names, zones: zones ?? 'all' };\n};\n\n/** Parse and check roles.yaml. Throws RolesConfigError naming the first bad field. */\nexport const parseRolesConfig = (yaml: string): RolesConfig => {\n const root = record(Bun.YAML.parse(yaml), '(document)');\n const surfaces: Record<string, SurfaceSpec> = {};\n for (const [name, spec] of Object.entries(record(root['surfaces'], 'surfaces'))) {\n surfaces[name] = surface(name, spec);\n }\n const accounts = Object.entries(record(root['accounts'], 'accounts')).map(([key, value]) =>\n account(key, value, surfaces),\n );\n return {\n accounts,\n namespace: text(record(root['defaults'], 'defaults'), 'namespace', 'defaults'),\n surfaces,\n };\n};\n",
|
|
43
43
|
"/**\n * One AppRole role per host, generated from a host list and a few class definitions — pure, so a\n * scaffold test can render every role from one site config and assert on it without a vault.\n *\n * ★ WHY PER HOST, NOT PER CLASS. OpenBao sets an AppRole login's entity alias to the role_id, so\n * every host sharing a class role is ONE identity: one entity in every audit line, and one cached\n * token when two hosts send the same login through a caching proxy (vault consolidation plan,\n * decision 8 as amended 2026-09-21; not re-measured here). The CLASS carries the policies and\n * TTLs; the ROLE carries the host.\n *\n * ★ THE NAMING RULE: `<class>--<host>`, e.g. `pve-node--node-a`.\n * · Class and host names are lowercase letters, digits and SINGLE hyphens, so `--` can only ever\n * be the separator and a name splits back into exactly one (class, host) pair.\n * · Class first, so one class's roles share a prefix a reader (or a policy path glob,\n * `auth/approle/role/pve-node--*`) can select — and no hand-made role (`deploy`,\n * `approle-rotator`) can match it, because none of them contains `--`.\n * · Lowercase because AppRole stores role names lowercased (builtin/credential/approle stores\n * `role/<lowercased name>`); a mixed-case name would read back as a different string.\n *\n * ⛔ NO ROLE WITHOUT AN EXPIRING SECRET_ID. `secretIdTtl` must parse to MORE than zero: `0` is a\n * secret_id that never expires, which is the `deploy` credential the plan is retiring. The plan's\n * class default is 90 days (`2160h`, which auth-role-form.test.ts shows OpenBao accepts).\n * ⛔ `bindSecretId` IS ALWAYS TRUE. A role that logs in on role_id alone makes the role_id — which\n * is not treated as a secret — the whole credential.\n * ⚠️ A RENAMED HOST OR CLASS IS A NEW ROLE: a new role_id, and a new secret_id to push to the host\n * in the same change. What Alchemy calls it depends on the logical id. Keyed by the role name (as\n * the README does), the old id VANISHES from the stack, so it is an orphan delete, not a\n * `replace`. Keyed by something stable, Bao.AuthRole plans a `replace`. Either way the default\n * `retain` leaves the old role LIVE, its secret_ids still logging in (alchemy Plan.ts:2040 and\n * Apply.ts:2152-2173 honour retain on both paths) — see the ⚠️ in auth-role.ts before renaming.\n */\nimport type { BaoAuthRoleProps } from './auth-role-form.ts';\nimport { parseDuration } from './mount-form.ts';\n\n/** What every host of one class gets. */\nexport interface HostRoleClass {\n /** Policy names. ⛔ Never empty, never `root`. */\n readonly policies: readonly string[];\n readonly tokenTtl: string;\n readonly tokenMaxTtl: string;\n /** ⛔ Must be more than zero — e.g. `2160h` (90 days). */\n readonly secretIdTtl: string;\n /** `0` (the default) means unlimited uses, which a host that logs in repeatedly needs. */\n readonly secretIdNumUses?: number;\n}\n\nexport interface HostRoleHost {\n /** Short host name, e.g. `node-a`. */\n readonly name: string;\n /** Key into `classes`. */\n readonly class: string;\n}\n\nexport interface HostAppRolesInput {\n readonly hosts: readonly HostRoleHost[];\n readonly classes: Readonly<Record<string, HostRoleClass>>;\n}\n\n/** Lowercase letters and digits, single hyphens between them. */\nconst NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\nexport const HOST_ROLE_SEPARATOR = '--';\n\n/** The naming rule, in one place: `<class>--<host>`. */\nexport const hostRoleName = (className: string, host: string): string =>\n `${className}${HOST_ROLE_SEPARATOR}${host}`;\n\nconst classProblems = (name: string, spec: HostRoleClass): string[] => {\n const found: string[] = [];\n if (!NAME.test(name))\n found.push(`class \\`${name}\\` is not lowercase letters, digits, single hyphens`);\n if (spec.policies.length === 0) found.push(`class \\`${name}\\` has no policies`);\n if (spec.policies.includes('root')) found.push(`class \\`${name}\\` grants \\`root\\``);\n const secretId = parseDuration(spec.secretIdTtl);\n if (secretId === undefined || secretId <= 0) {\n found.push(\n `class \\`${name}\\` secretIdTtl \\`${spec.secretIdTtl}\\` must be a duration above zero ` +\n '(0 never expires)',\n );\n }\n const ttl = parseDuration(spec.tokenTtl);\n const max = parseDuration(spec.tokenMaxTtl);\n if (ttl === undefined || max === undefined) {\n found.push(`class \\`${name}\\` token TTLs must be durations like 15m or 1h`);\n } else if (max > 0 && ttl > max) {\n found.push(`class \\`${name}\\` tokenTtl is longer than tokenMaxTtl`);\n }\n return found;\n};\n\n/**\n * Every host's role props, sorted by role name. Throws, naming every problem at once, on a class or\n * host that breaks a rule above — this runs when a stack is defined, so a throw stops the plan.\n */\nexport const hostAppRoles = (input: HostAppRolesInput): readonly BaoAuthRoleProps[] => {\n const problems = Object.entries(input.classes).flatMap(([name, spec]) =>\n classProblems(name, spec),\n );\n /**\n * ⛔ DEDUPED ON THE ROLE NAME, NOT THE HOST NAME. A host may sit in several classes (one machine\n * that is both a signer and a node), and each class gives it its own role: `<class>--<host>`\n * differs, so nothing collides. Until 2026-09-21 this keyed on the host alone and refused that\n * estate outright. What it must still refuse is the same host twice in ONE class: two\n * declarations of one role name, so one AppRole that two resources would each claim.\n */\n const seen = new Set<string>();\n const roles: BaoAuthRoleProps[] = [];\n for (const host of input.hosts) {\n if (!NAME.test(host.name)) {\n problems.push(`host \\`${host.name}\\` is not lowercase letters, digits, single hyphens`);\n }\n const name = hostRoleName(host.class, host.name);\n if (seen.has(name)) {\n problems.push(`host \\`${host.name}\\` is listed twice in class \\`${host.class}\\``);\n }\n seen.add(name);\n /**\n * ⛔ OWN KEYS ONLY. `classes['constructor']` is Object's constructor, not undefined, so a host\n * naming it passed as a class with no policies and no secretIdTtl, never checked by\n * classProblems, and wrote a role whose secret_id never expires.\n */\n const spec = Object.hasOwn(input.classes, host.class) ? input.classes[host.class] : undefined;\n if (spec === undefined) {\n problems.push(`host \\`${host.name}\\` names unknown class \\`${host.class}\\``);\n continue;\n }\n roles.push({\n bindSecretId: true,\n name,\n secretIdNumUses: spec.secretIdNumUses ?? 0,\n secretIdTtl: spec.secretIdTtl,\n tokenMaxTtl: spec.tokenMaxTtl,\n tokenPolicies: [...new Set(spec.policies)].sort(),\n tokenTtl: spec.tokenTtl,\n });\n }\n if (problems.length > 0) {\n throw new Error(`hostAppRoles refused the input: ${problems.join('; ')}.`);\n }\n return roles.sort((a, b) => a.name.localeCompare(b.name));\n};\n",
|
|
44
|
-
"/**\n * `auth/<mount>/config` for a JWT-validating mount — the issuer, keys and algorithms a login token\n * is checked against. OPTIONAL, NON-SECRET, and deliberately unable to configure an OIDC browser\n * login: read the ⛔ in jwt-config-form.ts for why `oidc_client_secret` stays out of Alchemy.\n *\n * ⚠️ THERE IS NO DELETE. openbao v2.6.2 path_config.go:126-141 defines read and update only; the\n * config lives exactly as long as its mount. So `delete` here writes nothing and says so in its\n * comment — it cannot be made to \"remove\" a config, and refusing would wedge every destroy. The\n * `retain` default means it only runs when a stack opted into destroy.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` changed → `replace`: the new mount gets the config;\n * the old one keeps its own until that mount is disabled. There is no identity but the mount.\n * ⛔ A MOVE ONTO A MOUNT WHOSE CONFIG EXISTS FAILS THE PLAN, like every other family's move onto an\n * occupied path (rename-identity.ts). With no delete, nothing is lost to a swap, which MEASURED\n * 2026-09-21 ended with each config where it was declared. But the new generation writes over\n * the config it lands on, which changes who can log in on that mount: an issuer or key set\n * someone else manages, silently replaced. Move through a mount with no config instead.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
44
|
+
"/**\n * `auth/<mount>/config` for a JWT-validating mount — the issuer, keys and algorithms a login token\n * is checked against. OPTIONAL, NON-SECRET, and deliberately unable to configure an OIDC browser\n * login: read the ⛔ in jwt-config-form.ts for why `oidc_client_secret` stays out of Alchemy.\n *\n * ⚠️ THERE IS NO DELETE. openbao v2.6.2 path_config.go:126-141 defines read and update only; the\n * config lives exactly as long as its mount. So `delete` here writes nothing and says so in its\n * comment — it cannot be made to \"remove\" a config, and refusing would wedge every destroy. The\n * `retain` default means it only runs when a stack opted into destroy.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` changed → `replace`: the new mount gets the config;\n * the old one keeps its own until that mount is disabled. There is no identity but the mount.\n * ⛔ A MOVE ONTO A MOUNT WHOSE CONFIG EXISTS FAILS THE PLAN, like every other family's move onto an\n * occupied path (rename-identity.ts). With no delete, nothing is lost to a swap, which MEASURED\n * 2026-09-21 ended with each config where it was declared. But the new generation writes over\n * the config it lands on, which changes who can log in on that mount: an issuer or key set\n * someone else manages, silently replaced. Move through a mount with no config instead.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport {\n type BaoJwtAuthConfigAttributes,\n type BaoJwtAuthConfigProps,\n attributesOf,\n configPath,\n matches,\n problems,\n wouldErase,\n writeBody,\n} from './jwt-config-form.ts';\nimport { declaredOr } from './rename.ts';\nimport { type Identity, guardRename, judgeRename } from './rename-identity.ts';\nimport { type RoleSpec, planRole, readOwnedRole, reconcileRole } from './role-reconcile.ts';\n\nexport type { BaoJwtAuthConfigAttributes, BaoJwtAuthConfigProps } from './jwt-config-form.ts';\n\nexport interface BaoJwtAuthConfig extends Resource<\n 'Bao.JwtAuthConfig',\n BaoJwtAuthConfigProps,\n BaoJwtAuthConfigAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoJwtAuthConfig = Resource<BaoJwtAuthConfig>('Bao.JwtAuthConfig', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** The identity is the mount alone; a trailing `/` is the same mount (`configPath` trims it). */\nconst IDENTITY: Identity<BaoJwtAuthConfigAttributes> = {\n declared: (props) => {\n const mount = declaredOr(props, 'mount', 'jwt');\n return mount === undefined ? undefined : configPath({ mount });\n },\n family: 'Bao.JwtAuthConfig',\n recorded: (output) => configPath(output),\n};\n\nexport const jwtConfigSpec = (\n props: BaoJwtAuthConfigProps,\n): RoleSpec<BaoJwtAuthConfigAttributes> => ({\n attributesOf: (live) => attributesOf(props, live),\n body: writeBody(props),\n family: 'Bao.JwtAuthConfig',\n matches: (attributes) => matches(attributes, props),\n path: configPath(props),\n problems: problems(props),\n wouldErase,\n});\n\nexport const BaoJwtAuthConfigProvider = () =>\n Provider.effect(\n BaoJwtAuthConfig,\n Effect.succeed(\n BaoJwtAuthConfig.Provider.of({\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n return yield* readOwnedRole({ fqn, instanceId, output }, jwtConfigSpec(olds));\n }),\n\n diff: Effect.fn(function* ({ news, olds, output }) {\n // ⛔ The mount first, before isResolved; onto a mount with a config fails the plan.\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n return { action: yield* planRole(jwtConfigSpec(news)) } as const;\n }),\n\n /** ⛔ Refuses, before writing, a live config that carries an OIDC client (wouldErase). */\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n return yield* reconcileRole(jwtConfigSpec(news), claimFor({ fqn, instanceId, output }));\n }),\n\n /** ⚠️ Writes nothing — there is no delete endpoint (header). */\n delete: () => Effect.void,\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
45
45
|
"/**\n * The form half of Bao.JwtAuthConfig — `auth/<mount>/config` for a mount that VALIDATES JWTs\n * (GitHub Actions OIDC, a Kubernetes issuer, a JWKS endpoint). NON-SECRET FIELDS ONLY.\n *\n * ⛔ `oidc_client_secret` IS NOT A PROP, AND THIS RESOURCE REFUSES TO TOUCH A MOUNT THAT HAS ONE.\n * Three reasons, each sufficient:\n * 1. Alchemy stores props and attributes UNENCRYPTED in its state store (policy.ts), which is\n * dumped nightly to another host. A client secret there outlives the vault that guards it.\n * 2. The read never returns it (path_config.go:266-315 lists every field it answers; the secret\n * is not one, and it is `Sensitive`, :62-68), so a diff could never see it drift.\n * 3. THE WRITE IS A FULL REPLACE. pathConfigWrite (:321-345) builds the whole config from\n * `d.Get`, so a write that leaves the secret out ERASES it — and with `oidc_client_id` still\n * set the server refuses, while with both gone (:382-386) every OIDC browser login breaks.\n * So a mount whose live config carries `oidc_client_id` is refused by `wouldErase`: configure\n * an OIDC login mount by hand, or by a tool that reads the secret from KV at apply time.\n * ⚠️ THE WRITE CALLS OUT. With a discovery URL or JWKS URL the SERVER fetches it during the write\n * (:387-420) and refuses on failure (\"error checking oidc discovery URL\"): the vault must reach\n * the issuer, not only the machine running the plan.\n */\nimport { sha256 } from './digest.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport interface BaoJwtAuthConfigProps {\n /** Auth mount path. Default `jwt`. */\n mount?: string;\n /** Issuer base URL, WITHOUT `/.well-known/openid-configuration` (the server refuses that). */\n oidcDiscoveryUrl?: string;\n /** PEM CA for the discovery URL, when its certificate is not publicly trusted. */\n oidcDiscoveryCaPem?: string;\n /** A JWKS URL, instead of discovery. */\n jwksUrl?: string;\n /** PEM CA for the JWKS URL. */\n jwksCaPem?: string;\n /** PEM PUBLIC keys, instead of either URL. */\n jwtValidationPubkeys?: readonly string[];\n /** Algorithms accepted. Default none — which the server reads as RS256. */\n jwtSupportedAlgs?: readonly string[];\n /** The `iss` a token must carry. */\n boundIssuer?: string;\n /** Role used when a login names none. Lower case. */\n defaultRole?: string;\n}\n\nexport interface BaoJwtAuthConfigCanonical {\n boundIssuer: string;\n defaultRole: string;\n jwksCaPem: string;\n jwksUrl: string;\n jwtSupportedAlgs: readonly string[];\n jwtValidationPubkeys: readonly string[];\n oidcDiscoveryCaPem: string;\n oidcDiscoveryUrl: string;\n}\n\n/** ⛔ No secret — URLs, public keys, CA certificates, names. */\nexport interface BaoJwtAuthConfigAttributes extends BaoJwtAuthConfigCanonical {\n mount: string;\n digest: string;\n}\n\nconst text = (value: unknown) => (typeof value === 'string' ? value.trim() : '');\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\nconst sortedSet = (values: readonly string[]) =>\n [...new Set(values.map((value) => value.trim()))].sort();\n\nconst canonical = (input: BaoJwtAuthConfigCanonical): BaoJwtAuthConfigCanonical => ({\n boundIssuer: input.boundIssuer.trim(),\n defaultRole: input.defaultRole.trim(),\n jwksCaPem: input.jwksCaPem.trim(),\n jwksUrl: input.jwksUrl.trim(),\n jwtSupportedAlgs: sortedSet(input.jwtSupportedAlgs),\n jwtValidationPubkeys: sortedSet(input.jwtValidationPubkeys),\n oidcDiscoveryCaPem: input.oidcDiscoveryCaPem.trim(),\n oidcDiscoveryUrl: input.oidcDiscoveryUrl.trim(),\n});\n\nexport const canonicalFromProps = (props: BaoJwtAuthConfigProps): BaoJwtAuthConfigCanonical =>\n canonical({\n boundIssuer: props.boundIssuer ?? '',\n defaultRole: props.defaultRole ?? '',\n jwksCaPem: props.jwksCaPem ?? '',\n jwksUrl: props.jwksUrl ?? '',\n jwtSupportedAlgs: props.jwtSupportedAlgs ?? [],\n jwtValidationPubkeys: props.jwtValidationPubkeys ?? [],\n oidcDiscoveryCaPem: props.oidcDiscoveryCaPem ?? '',\n oidcDiscoveryUrl: props.oidcDiscoveryUrl ?? '',\n });\n\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoJwtAuthConfigCanonical =>\n canonical({\n boundIssuer: text(live['bound_issuer']),\n defaultRole: text(live['default_role']),\n jwksCaPem: text(live['jwks_ca_pem']),\n jwksUrl: text(live['jwks_url']),\n jwtSupportedAlgs: strings(live['jwt_supported_algs']),\n jwtValidationPubkeys: strings(live['jwt_validation_pubkeys']),\n oidcDiscoveryCaPem: text(live['oidc_discovery_ca_pem']),\n oidcDiscoveryUrl: text(live['oidc_discovery_url']),\n });\n\nexport const mountOf = (props: { mount?: string }): string => mountPath(props.mount ?? 'jwt');\n\nexport const configPath = (props: { mount?: string }): string => `auth/${mountOf(props)}/config`;\n\nexport const attributesOf = (\n props: BaoJwtAuthConfigProps,\n live: Record<string, unknown>,\n): BaoJwtAuthConfigAttributes => {\n const form = canonicalFromLive(live);\n return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf(props) };\n};\n\nexport const matches = (attributes: BaoJwtAuthConfigAttributes, props: BaoJwtAuthConfigProps) =>\n attributes.digest === sha256(JSON.stringify(canonicalFromProps(props)));\n\n/** Every non-secret field — the write is a full replace, so what is left out is reset. */\nexport const writeBody = (props: BaoJwtAuthConfigProps): Record<string, unknown> => ({\n bound_issuer: props.boundIssuer ?? '',\n default_role: props.defaultRole ?? '',\n jwks_ca_pem: props.jwksCaPem ?? '',\n jwks_url: props.jwksUrl ?? '',\n jwt_supported_algs: [...(props.jwtSupportedAlgs ?? [])],\n jwt_validation_pubkeys: [...(props.jwtValidationPubkeys ?? [])],\n oidc_discovery_ca_pem: props.oidcDiscoveryCaPem ?? '',\n oidc_discovery_url: props.oidcDiscoveryUrl ?? '',\n});\n\n/** Live fields the full-replace write would reset, which this resource deliberately does not model. */\nexport const wouldErase = (live: Record<string, unknown>): readonly string[] => {\n const lost: string[] = [];\n if (text(live['oidc_client_id']) !== '') lost.push('oidc_client_id (and its unreadable secret)');\n const provider = live['provider_config'];\n if (typeof provider === 'object' && provider !== null && Object.keys(provider).length > 0) {\n lost.push('provider_config');\n }\n if (text(live['oidc_response_mode']) !== '') lost.push('oidc_response_mode');\n if (strings(live['oidc_response_types']).length > 0) lost.push('oidc_response_types');\n if (strings(live['override_allowed_server_names']).length > 0) {\n lost.push('override_allowed_server_names');\n }\n return lost;\n};\n\nexport const problems = (props: BaoJwtAuthConfigProps): readonly string[] => {\n const found: string[] = [];\n const sources = [\n (props.oidcDiscoveryUrl ?? '') !== '',\n (props.jwksUrl ?? '') !== '',\n (props.jwtValidationPubkeys?.length ?? 0) > 0,\n ].filter(Boolean).length;\n if (sources !== 1) {\n found.push('exactly one of oidcDiscoveryUrl, jwksUrl or jwtValidationPubkeys must be set');\n }\n if ((props.oidcDiscoveryUrl ?? '').includes('.well-known')) {\n found.push('oidcDiscoveryUrl must be the issuer, without /.well-known/openid-configuration');\n }\n const role = props.defaultRole ?? '';\n if (role !== role.toLowerCase()) found.push(`defaultRole \\`${role}\\` must be lower case`);\n return found;\n};\n",
|
|
46
|
-
"/**\n * The read / plan / reconcile loop the newer role families share (Bao.JwtRole, Bao.KubernetesRole,\n * Bao.JwtAuthConfig): one path, one body, one comparison. Each family supplies its own form; this\n * owns the order of operations, which is where the estate's providers have gone wrong before.\n *\n * ★ THE ORDER, AND WHY EACH STEP IS THERE:\n * 1. Refuse a declaration the family knows is wrong, before any call (`problems`).\n * 2. Read live. Write only when it differs — an identical write is still an audit line.\n * 3. Before writing over a live object, refuse if the write would silently destroy something\n * this resource does not model (`wouldErase`, the ssh-role.ts pattern).\n * 4. Re-read, and refuse unless live now MATCHES. A 2xx is not proof: the server can accept a\n * field and store something else (pki-role.ts has the history).\n * ⛔ A DECLARATION reconcile WOULD REFUSE NEVER PLANS `noop` — `planRole` routes it to `update`,\n * so the refusal is seen at the next deploy instead of hiding behind a clean plan.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
47
|
-
"/**\n * A role on a `jwt` or `oidc` auth mount — `auth/<mount>/role/<name>`: which tokens may log in,\n * how the entity is named, and what the resulting OpenBao token carries. METADATA ONLY.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. A role holds claim names, audiences, redirect\n * URIs and policy names. The mount's OIDC client secret is config, not role, and stays out of\n * Alchemy entirely (the ⛔ in jwt-config.ts).\n * ⛔ HUMANS GET A NON-ADMIN DEFAULT (machine-access plan, \"Admin boundary\"): a human role's\n * `tokenPolicies` should not include an admin policy, and admin needs login MFA\n * (mfa-enforcement.ts). This resource does not know which policy is admin, so it cannot refuse —\n * the stack that declares the role owns that line.\n * ⚠️ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ISSUED. path_role.go:478 pathRoleDelete removes the\n * storage entry and nothing else; those tokens live to their TTL.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first. The new\n * path cannot collide with the old, so no `deleteFirst`. Under the default `retain` the old role\n * stays live, and still admits logins, until removed by hand. ⛔ A move onto a role that already\n * exists fails the plan (rename-identity.ts).\n * ★ `defaultRemovalPolicy: 'retain'`, like every Bao.* family.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
46
|
+
"/**\n * The read / plan / reconcile loop the newer role families share (Bao.JwtRole, Bao.KubernetesRole,\n * Bao.JwtAuthConfig): one path, one body, one comparison. Each family supplies its own form; this\n * owns the order of operations, which is where the estate's providers have gone wrong before.\n *\n * ★ THE ORDER, AND WHY EACH STEP IS THERE:\n * 1. Refuse a declaration the family knows is wrong, before any call (`problems`).\n * 2. Read live. Write only when it differs — an identical write is still an audit line.\n * 3. Before writing over a live object, refuse if the write would silently destroy something\n * this resource does not model (`wouldErase`, the ssh-role.ts pattern).\n * 4. Re-read, and refuse unless live now MATCHES. A 2xx is not proof: the server can accept a\n * field and store something else (pki-role.ts has the history).\n * ⛔ A DECLARATION reconcile WOULD REFUSE NEVER PLANS `noop` — `planRole` routes it to `update`,\n * so the refusal is seen at the next deploy instead of hiding behind a clean plan.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { Claim, Owner } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { baoRead, baoWrite } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\n\nexport interface RoleSpec<A> {\n /** `Bao.JwtRole` etc., for messages. */\n readonly family: string;\n /** The API path, e.g. `auth/jwt/role/humans`. */\n readonly path: string;\n readonly problems: readonly string[];\n readonly attributesOf: (live: Record<string, unknown>) => A;\n readonly matches: (attributes: A) => boolean;\n readonly body: Readonly<Record<string, unknown>>;\n /** Live fields a write would reset that the declaration does not model. */\n readonly wouldErase?: (live: Record<string, unknown>) => readonly string[];\n}\n\ntype Found<A> = { readonly attributes: A; readonly live: Record<string, unknown> };\n\nexport const readRoleAt = <A>(\n spec: RoleSpec<A>,\n): Effect.Effect<Found<A> | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.map(baoRead(spec.path), (live) =>\n live === undefined ? undefined : { attributes: spec.attributesOf(live), live },\n );\n\n/**\n * `read`: the live attributes — `Unowned` with no state unless our own interrupted create wrote\n * them, which is `planRole`'s `noop` against that create's props (ownership/probe.ts).\n */\nexport const readOwnedRole = <A extends object>(\n ask: Owner,\n spec: RoleSpec<A>,\n): Effect.Effect<A | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.flatMap(readRoleAt(spec), (found) => {\n const ours = Effect.sync(\n () => found !== undefined && spec.problems.length === 0 && spec.matches(found.attributes),\n );\n return ownedRead(ask, found?.attributes, ours);\n });\n\n/** `update` or `noop` — the part of a diff after the identity checks. */\nexport const planRole = <A>(\n spec: RoleSpec<A>,\n): Effect.Effect<'noop' | 'update', BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n if (spec.problems.length > 0) return 'update';\n const found = yield* readRoleAt(spec);\n return found !== undefined && spec.matches(found.attributes) ? 'noop' : 'update';\n });\n\nconst refuse = (spec: { readonly family: string; readonly path: string }, message: string) =>\n Effect.die(new Error(`${spec.family} ${spec.path}: ${message}`));\n\n/**\n * ⛔ `claim` — every provider passes it — refuses, before any write, a create that finds a live\n * object this stack holds no state for (ownership/adopt.ts).\n */\nexport const reconcileRole = <A>(\n spec: RoleSpec<A>,\n claim?: Claim,\n): Effect.Effect<A, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n if (spec.problems.length > 0) return yield* refuse(spec, spec.problems.join('; '));\n const found = yield* readRoleAt(spec);\n if (found !== undefined && claim !== undefined) yield* claim(`${spec.family} ${spec.path}`);\n if (found === undefined || !spec.matches(found.attributes)) {\n const lost = found === undefined ? [] : (spec.wouldErase?.(found.live) ?? []);\n if (lost.length > 0) {\n return yield* refuse(\n spec,\n `live carries ${lost.join(', ')}, which this resource does not declare and the write ` +\n 'would reset. Fold it into the declaration, or clear it by hand first.',\n );\n }\n // ★ PUT, as `bao write` sends (api/logical.go); http/logical.go maps PUT and POST alike.\n yield* baoWrite('PUT', spec.path, spec.body);\n }\n const after = yield* readRoleAt(spec);\n if (after === undefined) return yield* refuse(spec, 'write reported success but it is absent.');\n if (!spec.matches(after.attributes)) {\n return yield* refuse(\n spec,\n 'wrote cleanly but read back different — OpenBao stored something other than what was ' +\n 'declared. Read it by hand before retrying.',\n );\n }\n return after.attributes;\n });\n",
|
|
47
|
+
"/**\n * A role on a `jwt` or `oidc` auth mount — `auth/<mount>/role/<name>`: which tokens may log in,\n * how the entity is named, and what the resulting OpenBao token carries. METADATA ONLY.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. A role holds claim names, audiences, redirect\n * URIs and policy names. The mount's OIDC client secret is config, not role, and stays out of\n * Alchemy entirely (the ⛔ in jwt-config.ts).\n * ⛔ HUMANS GET A NON-ADMIN DEFAULT (machine-access plan, \"Admin boundary\"): a human role's\n * `tokenPolicies` should not include an admin policy, and admin needs login MFA\n * (mfa-enforcement.ts). This resource does not know which policy is admin, so it cannot refuse —\n * the stack that declares the role owns that line.\n * ⚠️ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ISSUED. path_role.go:478 pathRoleDelete removes the\n * storage entry and nothing else; those tokens live to their TTL.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first. The new\n * path cannot collide with the old, so no `deleteFirst`. Under the default `retain` the old role\n * stays live, and still admits logins, until removed by hand. ⛔ A move onto a role that already\n * exists fails the plan (rename-identity.ts).\n * ★ `defaultRemovalPolicy: 'retain'`, like every Bao.* family.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete } from './bao-http.ts';\nimport {\n type BaoJwtRoleAttributes,\n type BaoJwtRoleProps,\n attributesOf,\n matches,\n problems,\n rolePath,\n writeBody,\n} from './jwt-role-form.ts';\nimport { foldName, guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\nimport { type RoleSpec, planRole, readOwnedRole, reconcileRole } from './role-reconcile.ts';\n\nexport type {\n BaoJwtCallbackMode,\n BaoJwtRoleAttributes,\n BaoJwtRoleProps,\n BaoJwtRoleType,\n} from './jwt-role-form.ts';\n\nexport interface BaoJwtRole extends Resource<\n 'Bao.JwtRole',\n BaoJwtRoleProps,\n BaoJwtRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoJwtRole = Resource<BaoJwtRole>('Bao.JwtRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/**\n * The name folded, as the server keys it (`foldName`): `name` is a TypeLowerCaseString\n * (builtin/credential/jwt/path_role.go:77), so the handler reads it lowercased before it ever builds\n * `role/<name>` (:289). `App` → `app` is the same role, never a move; `problems` refuses the case.\n */\nconst IDENTITY = roleIdentity<BaoJwtRoleAttributes>(\n 'Bao.JwtRole',\n (mount, name) => rolePath({ mount, name }),\n 'jwt',\n foldName,\n);\n\nexport const jwtRoleSpec = (props: BaoJwtRoleProps): RoleSpec<BaoJwtRoleAttributes> => ({\n attributesOf: (live) => attributesOf(props, live),\n body: writeBody(props),\n family: 'Bao.JwtRole',\n matches: (attributes) => matches(attributes, props),\n path: rolePath(props),\n problems: problems(props),\n});\n\nexport const BaoJwtRoleProvider = () =>\n Provider.effect(\n BaoJwtRole,\n Effect.succeed(\n BaoJwtRole.Provider.of({\n /**\n * ⛔ `bao list auth/<mount>/role` IS NOT A LIST OF THINGS THIS OWNS — every role answers,\n * including the hand-made admin lanes. Returning them invites adopt-then-delete.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n return yield* readOwnedRole({ fqn, instanceId, output }, jwtRoleSpec(olds));\n }),\n\n /** ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST — a hand-widened audience is drift. */\n diff: Effect.fn(function* ({ news, olds, output }) {\n // ⛔ The identity first, before isResolved; onto a role that exists fails the plan.\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n return { action: yield* planRole(jwtRoleSpec(news)) } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n return yield* reconcileRole(jwtRoleSpec(news), claimFor({ fqn, instanceId, output }));\n }),\n\n /** Idempotent as Alchemy requires — a missing role deletes as success. */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
48
48
|
"/**\n * The `token_*` fields every auth role shares — read once here for Bao.JwtRole and\n * Bao.KubernetesRole, so the two cannot disagree about what a token TTL is.\n *\n * ★ READ FROM openbao v2.6.2 sdk/helper/tokenutil/tokenutil.go:\n * · TokenFields (:80-170) — `token_policies`, `token_bound_cidrs` are comma-string slices;\n * `token_ttl`, `token_max_ttl`, `token_explicit_max_ttl`, `token_period` are duration-seconds;\n * `token_no_default_policy` bool; `token_num_uses` int; `token_type` a string.\n * · ParseTokenFields (:176-262) — EVERY field is `GetOk`: an omitted field KEEPS its stored value.\n * So an update is a merge, and the only way to clear a stale value is to send the default.\n * That is why every field below is sent on every write, resolved to its default.\n * · PopulateTokenData (:265-284) — the read answers seconds for durations, `[]` for empty lists,\n * and `token_type` as a word (sdk/logical/token.go: `default`, `service`, `batch`).\n * ⛔ NO SECRET HERE: policy names, CIDRs, TTLs.\n */\nimport { parseDuration, ttlSeconds } from './mount-form.ts';\n\nexport type BaoTokenType = 'batch' | 'default' | 'service';\n\nexport interface BaoTokenProps {\n /** Policies on tokens this role issues. Names only. */\n tokenPolicies: readonly string[];\n /** Token TTL (`15m`). Default `0` — the mount's default. */\n tokenTtl?: string;\n /** Token max TTL (`1h`). Default `0` — the mount's max. */\n tokenMaxTtl?: string;\n /** Hard ceiling that renewal cannot pass. Default `0` (none). */\n tokenExplicitMaxTtl?: string;\n /** Periodic tokens renew forever within this period. Default `0` (not periodic). */\n tokenPeriod?: string;\n /** Leave the `default` policy off. Default false. */\n tokenNoDefaultPolicy?: boolean;\n /** CIDRs a token may be USED from. Default none. */\n tokenBoundCidrs?: readonly string[];\n /** Uses before the token dies; `0` is unlimited. Default 0. */\n tokenNumUses?: number;\n /** Default `default` — the mount decides, which means service tokens unless it says otherwise. */\n tokenType?: BaoTokenType;\n}\n\n/** The token fields as seconds and sorted sets — both sides of a diff are built by `tokenForm`. */\nexport interface BaoTokenForm {\n tokenBoundCidrs: readonly string[];\n tokenExplicitMaxTtlSeconds: number;\n tokenMaxTtlSeconds: number;\n tokenNoDefaultPolicy: boolean;\n tokenNumUses: number;\n tokenPeriodSeconds: number;\n tokenPolicies: readonly string[];\n tokenTtlSeconds: number;\n tokenType: string;\n}\n\nconst sortedSet = (values: readonly string[]) => [...new Set(values)].sort();\n\n/**\n * ⚠️ A HOST CIDR READS BACK BARE. token_bound_cidrs is stored as sockaddr values, and a `/32` (or\n * `/128`) host address renders without its mask. REASONED from go-sockaddr's String(), not\n * measured — so the mask is dropped on BOTH sides, which can only hide a spelling difference.\n */\nconst cidr = (value: string) => value.trim().replace(/\\/(32|128)$/, '');\n\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\nconst seconds = (text: string | undefined) => parseDuration(text ?? '0') ?? -1;\n\n/**\n * The token fields of an already-normalised form, in one fixed key order — what a role family's own\n * canonical literal spreads, so its digest cannot depend on how the object was assembled.\n */\nexport const tokenFields = (input: BaoTokenForm): BaoTokenForm => ({\n tokenBoundCidrs: input.tokenBoundCidrs,\n tokenExplicitMaxTtlSeconds: input.tokenExplicitMaxTtlSeconds,\n tokenMaxTtlSeconds: input.tokenMaxTtlSeconds,\n tokenNoDefaultPolicy: input.tokenNoDefaultPolicy,\n tokenNumUses: input.tokenNumUses,\n tokenPeriodSeconds: input.tokenPeriodSeconds,\n tokenPolicies: input.tokenPolicies,\n tokenTtlSeconds: input.tokenTtlSeconds,\n tokenType: input.tokenType,\n});\n\n/** The key order is fixed here, once, for both sides. */\nconst tokenForm = (input: BaoTokenForm): BaoTokenForm => ({\n tokenBoundCidrs: sortedSet(input.tokenBoundCidrs.map(cidr)),\n tokenExplicitMaxTtlSeconds: input.tokenExplicitMaxTtlSeconds,\n tokenMaxTtlSeconds: input.tokenMaxTtlSeconds,\n tokenNoDefaultPolicy: input.tokenNoDefaultPolicy,\n tokenNumUses: input.tokenNumUses,\n tokenPeriodSeconds: input.tokenPeriodSeconds,\n tokenPolicies: sortedSet(input.tokenPolicies),\n tokenTtlSeconds: input.tokenTtlSeconds,\n tokenType: input.tokenType,\n});\n\nexport const tokenFormOfProps = (props: BaoTokenProps): BaoTokenForm =>\n tokenForm({\n tokenBoundCidrs: props.tokenBoundCidrs ?? [],\n tokenExplicitMaxTtlSeconds: seconds(props.tokenExplicitMaxTtl),\n tokenMaxTtlSeconds: seconds(props.tokenMaxTtl),\n tokenNoDefaultPolicy: props.tokenNoDefaultPolicy ?? false,\n tokenNumUses: props.tokenNumUses ?? 0,\n tokenPeriodSeconds: seconds(props.tokenPeriod),\n tokenPolicies: props.tokenPolicies,\n tokenTtlSeconds: seconds(props.tokenTtl),\n tokenType: props.tokenType ?? 'default',\n });\n\nexport const tokenFormOfLive = (live: Record<string, unknown>): BaoTokenForm =>\n tokenForm({\n tokenBoundCidrs: strings(live['token_bound_cidrs']),\n tokenExplicitMaxTtlSeconds: ttlSeconds(live['token_explicit_max_ttl']) ?? -1,\n tokenMaxTtlSeconds: ttlSeconds(live['token_max_ttl']) ?? -1,\n tokenNoDefaultPolicy: live['token_no_default_policy'] === true,\n tokenNumUses: typeof live['token_num_uses'] === 'number' ? live['token_num_uses'] : -1,\n tokenPeriodSeconds: ttlSeconds(live['token_period']) ?? -1,\n tokenPolicies: strings(live['token_policies']),\n tokenTtlSeconds: ttlSeconds(live['token_ttl']) ?? -1,\n tokenType: typeof live['token_type'] === 'string' ? live['token_type'] : '',\n });\n\n/**\n * The token half of a role write — every field, defaults included (the merge ⚠️ above). Durations\n * go over as the author's own strings; lists as JSON arrays, which a comma-string-slice accepts.\n */\nexport const tokenBody = (props: BaoTokenProps): Record<string, unknown> => ({\n token_bound_cidrs: [...(props.tokenBoundCidrs ?? [])],\n token_explicit_max_ttl: props.tokenExplicitMaxTtl ?? '0',\n token_max_ttl: props.tokenMaxTtl ?? '0',\n token_no_default_policy: props.tokenNoDefaultPolicy ?? false,\n token_num_uses: props.tokenNumUses ?? 0,\n token_period: props.tokenPeriod ?? '0',\n token_policies: [...props.tokenPolicies],\n token_ttl: props.tokenTtl ?? '0',\n token_type: props.tokenType ?? 'default',\n});\n\n/** Refusals the token half can know without a server. */\nexport const tokenProblems = (props: BaoTokenProps): readonly string[] => {\n const found: string[] = [];\n const durations = {\n tokenExplicitMaxTtl: props.tokenExplicitMaxTtl,\n tokenMaxTtl: props.tokenMaxTtl,\n tokenPeriod: props.tokenPeriod,\n tokenTtl: props.tokenTtl,\n };\n for (const [field, text] of Object.entries(durations)) {\n if (seconds(text) < 0) found.push(`${field}=${text ?? ''} is not a duration (0 or <n>s|m|h|d)`);\n }\n const ttl = seconds(props.tokenTtl);\n const max = seconds(props.tokenMaxTtl);\n if (ttl > 0 && max > 0 && ttl > max) found.push('tokenTtl is longer than tokenMaxTtl');\n if (\n props.tokenType === 'batch' &&\n (seconds(props.tokenPeriod) > 0 || (props.tokenNumUses ?? 0) > 0)\n ) {\n found.push('a batch token cannot be periodic or use-limited (tokenutil.go:234-241)');\n }\n return found;\n};\n",
|
|
49
49
|
"/**\n * The form half of Bao.JwtRole — a role on a `jwt` or `oidc` auth mount (one plugin, two names).\n *\n * ★ READ FROM openbao v2.6.2 builtin/credential/jwt/path_role.go, NOT RECALLED:\n * · The write MERGES (pathRoleCreateUpdate :494-720): almost every field is `GetOk`, so an\n * omitted one keeps its stored value — EXCEPT four that are rebuilt from `data.Get` on every\n * write and so RESET when omitted: `role_type` (to `oidc`! :520-526), `bound_claims_type`\n * (`string`), `callback_mode` (`client`) and `oidc_disable_confirmation` (false). All four are\n * managed here, and every managed field is sent on every write, defaults included, so a value\n * set by hand cannot survive behind a green plan.\n * · `name` is a lower-case string (:77): `Admins` and `admins` are one role. Refused, not folded.\n * · A `jwt` role needs one bound constraint (audiences, subject, claims or token CIDRs) and an\n * `oidc` role needs allowed_redirect_uris (:694-709) — refused here with the same rule.\n * · `bound_claims` is a TypeMap and `claim_mappings` a TypeKVPairs: sent as JSON OBJECTS. A JSON\n * string is refused for a map (the ⛔ on mapValue in ssh-role-form.ts, measured 2026-09-21).\n * ⛔ `verbose_oidc_logging` AND `oidc_disable_confirmation` ARE ALWAYS SENT FALSE, and a live true\n * plans `update`. The first logs received tokens and claims at debug level (:189-194); the second\n * removes the confirmation page that guards direct-callback logins against token hijacking\n * (RFC 8628 5.4, :205-210). Neither is a prop.\n * ⚠️ LEFT ALONE (merged, never sent): the three leeways, `oauth2_metadata`, `max_age`,\n * `poll_interval`, `user_claim_json_pointer`, `token_policies_template_claims`,\n * `token_strictly_bind_ip`. A hand-set value there survives, and is not compared.\n */\nimport {\n type BaoTokenForm,\n type BaoTokenProps,\n tokenBody,\n tokenFields,\n tokenFormOfLive,\n tokenFormOfProps,\n tokenProblems,\n} from './auth-token-form.ts';\nimport { sha256 } from './digest.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport type BaoJwtRoleType = 'jwt' | 'oidc';\nexport type BaoJwtCallbackMode = 'client' | 'device' | 'direct';\n\nexport interface BaoJwtRoleProps extends BaoTokenProps {\n /** Auth mount path, no trailing slash. Default `jwt`; an OIDC mount is often `oidc`. */\n mount?: string;\n /** Role name — lower case, as the server stores it. */\n name: string;\n /** ⛔ REQUIRED ON PURPOSE: the server's default is `oidc`, even when re-writing a `jwt` role. */\n roleType: BaoJwtRoleType;\n /** The claim that names the entity alias, e.g. `sub` or `email`. */\n userClaim: string;\n /** `aud` values; any one must match. */\n boundAudiences?: readonly string[];\n /** The `sub` a token must carry. */\n boundSubject?: string;\n /** How `boundClaims` values match. Default `string`. */\n boundClaimsType?: 'glob' | 'string';\n /** Claims that must match, each a value or a list of acceptable values. */\n boundClaims?: Readonly<Record<string, string | readonly string[]>>;\n /** Claim → alias metadata key. `role` is reserved, and two claims may not share a key. */\n claimMappings?: Readonly<Record<string, string>>;\n /** The claim that names identity group aliases. */\n groupsClaim?: string;\n /** OIDC only: the redirect URIs a login may return to. Required for `oidc`. */\n allowedRedirectUris?: readonly string[];\n /** OIDC only: scopes to request beyond `openid`. */\n oidcScopes?: readonly string[];\n /** OIDC only. Default `client`. */\n callbackMode?: BaoJwtCallbackMode;\n}\n\n/** Every managed field, normalised. Both sides are built by `canonical`, so key order matches. */\nexport interface BaoJwtRoleCanonical extends BaoTokenForm {\n allowedRedirectUris: readonly string[];\n boundAudiences: readonly string[];\n boundClaims: Readonly<Record<string, readonly string[]>>;\n boundClaimsType: string;\n boundSubject: string;\n callbackMode: string;\n claimMappings: Readonly<Record<string, string>>;\n groupsClaim: string;\n oidcDisableConfirmation: boolean;\n oidcScopes: readonly string[];\n roleType: string;\n userClaim: string;\n verboseOidcLogging: boolean;\n}\n\n/** ⛔ No secret: claim names, audiences, URIs, policy names and TTLs. */\nexport interface BaoJwtRoleAttributes extends BaoJwtRoleCanonical {\n mount: string;\n name: string;\n digest: string;\n}\n\nconst sortedSet = (values: readonly string[]) => [...new Set(values)].sort();\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\nconst record = (value: unknown): Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : {};\n\n/** ⚠️ A claim value and a one-element list match alike (claims.go normalizeList), so both → list. */\nconst claimsOf = (value: unknown): Record<string, readonly string[]> => {\n const source = record(value);\n const out: Record<string, readonly string[]> = {};\n for (const key of Object.keys(source).sort()) {\n const raw = source[key];\n out[key] = sortedSet(typeof raw === 'string' ? [raw] : strings(raw));\n }\n return out;\n};\n\nconst mappingsOf = (value: unknown): Record<string, string> => {\n const source = record(value);\n const out: Record<string, string> = {};\n for (const key of Object.keys(source).sort()) out[key] = text(source[key]);\n return out;\n};\n\nconst canonical = (input: BaoJwtRoleCanonical): BaoJwtRoleCanonical => ({\n allowedRedirectUris: sortedSet(input.allowedRedirectUris),\n boundAudiences: sortedSet(input.boundAudiences),\n boundClaims: claimsOf(input.boundClaims),\n boundClaimsType: input.boundClaimsType,\n boundSubject: input.boundSubject,\n callbackMode: input.callbackMode,\n claimMappings: mappingsOf(input.claimMappings),\n groupsClaim: input.groupsClaim,\n oidcDisableConfirmation: input.oidcDisableConfirmation,\n oidcScopes: sortedSet(input.oidcScopes),\n roleType: input.roleType,\n userClaim: input.userClaim,\n verboseOidcLogging: input.verboseOidcLogging,\n ...tokenFields(input),\n});\n\nexport const canonicalFromProps = (props: BaoJwtRoleProps): BaoJwtRoleCanonical =>\n canonical({\n ...tokenFormOfProps(props),\n allowedRedirectUris: props.allowedRedirectUris ?? [],\n boundAudiences: props.boundAudiences ?? [],\n boundClaims: claimsOf(props.boundClaims ?? {}),\n boundClaimsType: props.boundClaimsType ?? 'string',\n boundSubject: props.boundSubject ?? '',\n callbackMode: props.callbackMode ?? 'client',\n claimMappings: props.claimMappings ?? {},\n groupsClaim: props.groupsClaim ?? '',\n oidcDisableConfirmation: false,\n oidcScopes: props.oidcScopes ?? [],\n roleType: props.roleType,\n userClaim: props.userClaim,\n verboseOidcLogging: false,\n });\n\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoJwtRoleCanonical =>\n canonical({\n ...tokenFormOfLive(live),\n allowedRedirectUris: strings(live['allowed_redirect_uris']),\n boundAudiences: strings(live['bound_audiences']),\n boundClaims: claimsOf(live['bound_claims']),\n boundClaimsType: text(live['bound_claims_type']),\n boundSubject: text(live['bound_subject']),\n callbackMode: text(live['callback_mode']),\n claimMappings: mappingsOf(live['claim_mappings']),\n groupsClaim: text(live['groups_claim']),\n oidcDisableConfirmation: live['oidc_disable_confirmation'] === true,\n oidcScopes: strings(live['oidc_scopes']),\n roleType: text(live['role_type']),\n userClaim: text(live['user_claim']),\n verboseOidcLogging: live['verbose_oidc_logging'] === true,\n });\n\nexport const mountOf = (props: { mount?: string }): string => mountPath(props.mount ?? 'jwt');\n\nexport const rolePath = (props: { mount?: string; name: string }): string =>\n `auth/${mountOf(props)}/role/${props.name}`;\n\nexport const attributesOf = (\n props: BaoJwtRoleProps,\n live: Record<string, unknown>,\n): BaoJwtRoleAttributes => {\n const form = canonicalFromLive(live);\n return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf(props), name: props.name };\n};\n\nexport const matches = (attributes: BaoJwtRoleAttributes, props: BaoJwtRoleProps): boolean =>\n attributes.digest === sha256(JSON.stringify(canonicalFromProps(props)));\n\n/** The PUT body — every managed field, the two fixed-false ones included (the ⛔ above). */\nexport const writeBody = (props: BaoJwtRoleProps): Record<string, unknown> => ({\n allowed_redirect_uris: [...(props.allowedRedirectUris ?? [])],\n bound_audiences: [...(props.boundAudiences ?? [])],\n bound_claims: { ...props.boundClaims },\n bound_claims_type: props.boundClaimsType ?? 'string',\n bound_subject: props.boundSubject ?? '',\n callback_mode: props.callbackMode ?? 'client',\n claim_mappings: { ...props.claimMappings },\n groups_claim: props.groupsClaim ?? '',\n oidc_disable_confirmation: false,\n oidc_scopes: [...(props.oidcScopes ?? [])],\n role_type: props.roleType,\n user_claim: props.userClaim,\n verbose_oidc_logging: false,\n ...tokenBody(props),\n});\n\nconst NAME = /^[a-z0-9_](?:[a-z0-9_.-]*[a-z0-9_])?$/;\n\nexport const problems = (props: BaoJwtRoleProps): readonly string[] => {\n const found = [...tokenProblems(props)];\n if (!NAME.test(props.name))\n found.push(`name \\`${props.name}\\` must be lower case (the server folds it)`);\n if (props.userClaim.trim() === '') found.push('userClaim is empty; the server requires one');\n const bound =\n (props.boundAudiences?.length ?? 0) > 0 ||\n (props.boundSubject ?? '') !== '' ||\n Object.keys(props.boundClaims ?? {}).length > 0 ||\n (props.tokenBoundCidrs?.length ?? 0) > 0;\n if (props.roleType === 'jwt' && !bound) {\n found.push(\n 'a jwt role needs a bound constraint: boundAudiences, boundSubject, boundClaims or tokenBoundCidrs',\n );\n }\n if (props.roleType === 'oidc' && (props.allowedRedirectUris?.length ?? 0) === 0) {\n found.push('an oidc role needs allowedRedirectUris');\n }\n const targets = Object.values(props.claimMappings ?? {});\n if (targets.includes('role')) found.push('claimMappings may not map to the reserved key `role`');\n if (new Set(targets).size !== targets.length)\n found.push('claimMappings maps two claims to one key');\n return found;\n};\n",
|
|
50
|
-
"/**\n * A role on a `kubernetes` auth mount — `auth/<mount>/role/<name>`: which service accounts may log\n * in and what their token carries. METADATA ONLY. The machine-access plan gives k8s pods this\n * instead of AppRole: one role per namespace/service account.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. The mount's own config (the cluster's CA and\n * the token reviewer JWT) is not declared here, and the reviewer JWT must never be.\n * ⚠️ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ISSUED — pathRoleDelete removes the storage entry\n * and nothing else (path_role.go:239-256).\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first (the new\n * path cannot collide with the old). Under the default `retain` the old role stays live until\n * removed by hand. ⛔ A move onto a role that already exists fails the plan (rename-identity.ts).\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
50
|
+
"/**\n * A role on a `kubernetes` auth mount — `auth/<mount>/role/<name>`: which service accounts may log\n * in and what their token carries. METADATA ONLY. The machine-access plan gives k8s pods this\n * instead of AppRole: one role per namespace/service account.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts. The mount's own config (the cluster's CA and\n * the token reviewer JWT) is not declared here, and the reviewer JWT must never be.\n * ⚠️ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ISSUED — pathRoleDelete removes the storage entry\n * and nothing else (path_role.go:239-256).\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `mount` or `name` changed → `replace`, create-first (the new\n * path cannot collide with the old). Under the default `retain` the old role stays live until\n * removed by hand. ⛔ A move onto a role that already exists fails the plan (rename-identity.ts).\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete } from './bao-http.ts';\nimport {\n type BaoKubernetesRoleAttributes,\n type BaoKubernetesRoleProps,\n attributesOf,\n matches,\n problems,\n rolePath,\n writeBody,\n} from './kubernetes-role-form.ts';\nimport { foldName, guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\nimport { type RoleSpec, planRole, readOwnedRole, reconcileRole } from './role-reconcile.ts';\n\nexport type {\n BaoKubernetesAliasSource,\n BaoKubernetesRoleAttributes,\n BaoKubernetesRoleProps,\n} from './kubernetes-role-form.ts';\n\nexport interface BaoKubernetesRole extends Resource<\n 'Bao.KubernetesRole',\n BaoKubernetesRoleProps,\n BaoKubernetesRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoKubernetesRole = Resource<BaoKubernetesRole>('Bao.KubernetesRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** The name folded, as the server stores it (`foldName`). */\nconst IDENTITY = roleIdentity<BaoKubernetesRoleAttributes>(\n 'Bao.KubernetesRole',\n (mount, name) => rolePath({ mount, name }),\n 'kubernetes',\n foldName,\n);\n\nexport const kubernetesRoleSpec = (\n props: BaoKubernetesRoleProps,\n): RoleSpec<BaoKubernetesRoleAttributes> => ({\n attributesOf: (live) => attributesOf(props, live),\n body: writeBody(props),\n family: 'Bao.KubernetesRole',\n matches: (attributes) => matches(attributes, props),\n path: rolePath(props),\n problems: problems(props),\n});\n\nexport const BaoKubernetesRoleProvider = () =>\n Provider.effect(\n BaoKubernetesRole,\n Effect.succeed(\n BaoKubernetesRole.Provider.of({\n /** ⛔ The mount's role listing is not a list of things this owns. */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n return yield* readOwnedRole({ fqn, instanceId, output }, kubernetesRoleSpec(olds));\n }),\n\n /** ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. */\n diff: Effect.fn(function* ({ news, olds, output }) {\n // ⛔ The identity first, before isResolved; onto a role that exists fails the plan.\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n return { action: yield* planRole(kubernetesRoleSpec(news)) } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n return yield* reconcileRole(\n kubernetesRoleSpec(news),\n claimFor({ fqn, instanceId, output }),\n );\n }),\n\n /** Idempotent as Alchemy requires — a missing role deletes as success. */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
51
51
|
"/**\n * The form half of Bao.KubernetesRole — `auth/<mount>/role/<name>` on a `kubernetes` auth mount:\n * which service accounts, in which namespaces, may log in, and what their token carries.\n *\n * ★ READ FROM openbao v2.6.2 builtin/credential/kubernetes/path_role.go, NOT RECALLED:\n * · The write MERGES for names, namespaces, audience and alias source (`GetOk`, :335-392), but\n * `bound_service_account_namespace_selector` is `data.Get` — RESET when omitted (:353). Every\n * field is therefore sent on every write, defaults included.\n * · Names may not be empty, and `*` may not be mixed with other names; namespaces may be empty\n * only when a selector is set, with the same `*` rule (:335-372). Refused here first.\n * · Roles are stored under the LOWER-CASED name (:396, backend.go:361), so a mixed-case name\n * would read back as a different string. Refused, not folded.\n * · `audience` is omitted from a read when empty (:206-208); read as `''`.\n * ⚠️ `aliasNameSource` DECIDES WHO A POD IS. `serviceaccount_uid` (OpenBao's default) names the\n * entity alias by the service account's UID; `serviceaccount_name` by `<namespace>/<name>`\n * (backend.go:30-34). Changing it on a live role re-names every pod's alias, so their next logins\n * land on NEW entities and attribution splits.\n * ⛔ SO IT IS REQUIRED, NOT DEFAULTED (review 2026-09-21). Every field is sent on every write, so a\n * default here would be WRITTEN: adopting a hand-made `serviceaccount_name` role with the prop\n * left out would plan a bare `update` and silently re-key every pod onto new entities. The\n * machine-access plan chose `serviceaccount_name`; the server's default is the other one — a\n * choice this important is made in the declaration, the way Bao.JwtRole's `roleType` is.\n */\nimport {\n type BaoTokenForm,\n type BaoTokenProps,\n tokenBody,\n tokenFields,\n tokenFormOfLive,\n tokenFormOfProps,\n tokenProblems,\n} from './auth-token-form.ts';\nimport { sha256 } from './digest.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport type BaoKubernetesAliasSource = 'serviceaccount_name' | 'serviceaccount_uid';\n\nexport interface BaoKubernetesRoleProps extends BaoTokenProps {\n /** Auth mount path. Default `kubernetes`. */\n mount?: string;\n /** Role name — lower case, as the server stores it. */\n name: string;\n /** Service account names; `['*']` for any. Never empty. */\n boundServiceAccountNames: readonly string[];\n /** Namespaces; `['*']` for any. May be empty only with a selector. */\n boundServiceAccountNamespaces?: readonly string[];\n /** A label selector (JSON or YAML) for namespaces, ORed with the list. */\n boundServiceAccountNamespaceSelector?: string;\n /** The `aud` a service account token must carry. Default none. */\n audience?: string;\n /** ⛔ Required — read the ⚠️ and ⛔ above before changing it on a live role. */\n aliasNameSource: BaoKubernetesAliasSource;\n}\n\nexport interface BaoKubernetesRoleCanonical extends BaoTokenForm {\n aliasNameSource: string;\n audience: string;\n boundServiceAccountNames: readonly string[];\n boundServiceAccountNamespaceSelector: string;\n boundServiceAccountNamespaces: readonly string[];\n}\n\n/** ⛔ No secret: account names, namespaces, policy names, TTLs. */\nexport interface BaoKubernetesRoleAttributes extends BaoKubernetesRoleCanonical {\n mount: string;\n name: string;\n digest: string;\n}\n\nconst sortedSet = (values: readonly string[]) => [...new Set(values)].sort();\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\nconst canonical = (input: BaoKubernetesRoleCanonical): BaoKubernetesRoleCanonical => ({\n aliasNameSource: input.aliasNameSource,\n audience: input.audience,\n boundServiceAccountNames: sortedSet(input.boundServiceAccountNames),\n boundServiceAccountNamespaceSelector: input.boundServiceAccountNamespaceSelector.trim(),\n boundServiceAccountNamespaces: sortedSet(input.boundServiceAccountNamespaces),\n ...tokenFields(input),\n});\n\nexport const canonicalFromProps = (props: BaoKubernetesRoleProps): BaoKubernetesRoleCanonical =>\n canonical({\n ...tokenFormOfProps(props),\n aliasNameSource: props.aliasNameSource,\n audience: props.audience ?? '',\n boundServiceAccountNames: props.boundServiceAccountNames,\n boundServiceAccountNamespaceSelector: props.boundServiceAccountNamespaceSelector ?? '',\n boundServiceAccountNamespaces: props.boundServiceAccountNamespaces ?? [],\n });\n\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoKubernetesRoleCanonical =>\n canonical({\n ...tokenFormOfLive(live),\n aliasNameSource: text(live['alias_name_source']),\n audience: text(live['audience']),\n boundServiceAccountNames: strings(live['bound_service_account_names']),\n boundServiceAccountNamespaceSelector: text(live['bound_service_account_namespace_selector']),\n boundServiceAccountNamespaces: strings(live['bound_service_account_namespaces']),\n });\n\nexport const mountOf = (props: { mount?: string }): string =>\n mountPath(props.mount ?? 'kubernetes');\n\nexport const rolePath = (props: { mount?: string; name: string }): string =>\n `auth/${mountOf(props)}/role/${props.name}`;\n\nexport const attributesOf = (\n props: BaoKubernetesRoleProps,\n live: Record<string, unknown>,\n): BaoKubernetesRoleAttributes => {\n const form = canonicalFromLive(live);\n return { ...form, digest: sha256(JSON.stringify(form)), mount: mountOf(props), name: props.name };\n};\n\nexport const matches = (\n attributes: BaoKubernetesRoleAttributes,\n props: BaoKubernetesRoleProps,\n): boolean => attributes.digest === sha256(JSON.stringify(canonicalFromProps(props)));\n\nexport const writeBody = (props: BaoKubernetesRoleProps): Record<string, unknown> => ({\n alias_name_source: props.aliasNameSource,\n audience: props.audience ?? '',\n bound_service_account_names: [...props.boundServiceAccountNames],\n bound_service_account_namespace_selector: props.boundServiceAccountNamespaceSelector ?? '',\n bound_service_account_namespaces: [...(props.boundServiceAccountNamespaces ?? [])],\n ...tokenBody(props),\n});\n\nconst NAME = /^[a-z0-9_](?:[a-z0-9_.-]*[a-z0-9_])?$/;\n\nconst starMixed = (values: readonly string[]) => values.length > 1 && values.includes('*');\n\nexport const problems = (props: BaoKubernetesRoleProps): readonly string[] => {\n const found = [...tokenProblems(props)];\n const namespaces = props.boundServiceAccountNamespaces ?? [];\n const selector = (props.boundServiceAccountNamespaceSelector ?? '').trim();\n if (!NAME.test(props.name))\n found.push(`name \\`${props.name}\\` must be lower case (stored folded)`);\n if (props.boundServiceAccountNames.length === 0) found.push('boundServiceAccountNames is empty');\n if (starMixed(props.boundServiceAccountNames)) found.push('`*` mixed with other account names');\n if (namespaces.length === 0 && selector === '') {\n found.push('boundServiceAccountNamespaces is empty and no namespace selector is set');\n }\n if (starMixed(namespaces)) found.push('`*` mixed with other namespaces');\n return found;\n};\n",
|
|
52
|
-
"/**\n * A login-MFA enforcement — `identity/mfa/login-enforcement/<name>`: logins through these mounts\n * (or by these groups/entities) must also pass one of these MFA methods. The machine-access plan's\n * \"admin requires OpenBao login MFA\" is this resource.\n *\n * ⛔ ENROL BEFORE YOU ENFORCE. A login the enforcement matches, by an entity with no secret for any\n * listed method, FAILS (login_mfa.go validateLoginMFAInternal: \"MFA secret … not present\"). Enrol\n * every admin (`identity/mfa/method/totp/admin-generate`, which RETURNS the secret — never through\n * Alchemy) before the first deploy of this, or the admin lane locks itself out.\n * ⚠️ IT MATCHES MOUNTS, GROUPS AND ENTITIES — NEVER ROLES. An enforcement on the `jwt/` accessor\n * covers every role on that mount (login_mfa.go buildMFAEnforcementConfigList :932-1017). To put\n * MFA on admin only, give admin its own auth mount, or target an identity group of admins.\n * ⛔ THE DELETE IS REFUSED: IN 2.6.2 IT DOES NOT STICK. DeleteMFALoginEnforcementConfigByNameAndNamespace\n * (login_mfa.go:1879-1902) removes the entry from memory and never from storage, so it RETURNS on the\n * next unseal — tracked upstream as openbao/openbao#4030, open on 2026-09-21. Worse, a method\n * deleted in between leaves the resurrected enforcement naming an id that no longer exists, and\n * every login it matches then fails (\"MFA method configuration not present\", :871-877). A delete\n * that reports success and quietly comes back is the lie this package refuses to tell. Under the\n * default `retain` it never runs; with `destroy`, set `retain` to drop it from state and leave it\n * live — which is what the server would do anyway.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `name` changed → `replace`, create-first. Under `retain` BOTH\n * enforcements then apply — fail closed. Under `destroy` the old one's delete is refused, so the\n * deploy stops after creating. ⛔ A rename onto an enforcement that exists fails the plan\n * (rename-identity.ts): the upsert by name would otherwise rewrite, in place, what someone else's\n * enforcement demands. MEASURED 2026-09-21: a swap of two under `destroy` wrote each over the\n * other, then stopped on the two refused deletes.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
52
|
+
"/**\n * A login-MFA enforcement — `identity/mfa/login-enforcement/<name>`: logins through these mounts\n * (or by these groups/entities) must also pass one of these MFA methods. The machine-access plan's\n * \"admin requires OpenBao login MFA\" is this resource.\n *\n * ⛔ ENROL BEFORE YOU ENFORCE. A login the enforcement matches, by an entity with no secret for any\n * listed method, FAILS (login_mfa.go validateLoginMFAInternal: \"MFA secret … not present\"). Enrol\n * every admin (`identity/mfa/method/totp/admin-generate`, which RETURNS the secret — never through\n * Alchemy) before the first deploy of this, or the admin lane locks itself out.\n * ⚠️ IT MATCHES MOUNTS, GROUPS AND ENTITIES — NEVER ROLES. An enforcement on the `jwt/` accessor\n * covers every role on that mount (login_mfa.go buildMFAEnforcementConfigList :932-1017). To put\n * MFA on admin only, give admin its own auth mount, or target an identity group of admins.\n * ⛔ THE DELETE IS REFUSED: IN 2.6.2 IT DOES NOT STICK. DeleteMFALoginEnforcementConfigByNameAndNamespace\n * (login_mfa.go:1879-1902) removes the entry from memory and never from storage, so it RETURNS on the\n * next unseal — tracked upstream as openbao/openbao#4030, open on 2026-09-21. Worse, a method\n * deleted in between leaves the resurrected enforcement naming an id that no longer exists, and\n * every login it matches then fails (\"MFA method configuration not present\", :871-877). A delete\n * that reports success and quietly comes back is the lie this package refuses to tell. Under the\n * default `retain` it never runs; with `destroy`, set `retain` to drop it from state and leave it\n * live — which is what the server would do anyway.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): `name` changed → `replace`, create-first. Under `retain` BOTH\n * enforcements then apply — fail closed. Under `destroy` the old one's delete is refused, so the\n * deploy stops after creating. ⛔ A rename onto an enforcement that exists fails the plan\n * (rename-identity.ts): the upsert by name would otherwise rewrite, in place, what someone else's\n * enforcement demands. MEASURED 2026-09-21: a swap of two under `destroy` wrote each over the\n * other, then stopped on the two refused deletes.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { type Claim, claimFor } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n type BaoMfaLoginEnforcementAttributes,\n type BaoMfaLoginEnforcementProps,\n attributesOf,\n canonicalFromProps,\n matches,\n problems,\n writeBody,\n} from './mfa-enforcement-form.ts';\nimport { authAccessors, enforcementPath, readEnforcement, writeEnforcement } from './mfa-wire.ts';\nimport { guardRename, judgeRename, nameIdentity } from './rename-identity.ts';\n\nexport type {\n BaoMfaLoginEnforcementAttributes,\n BaoMfaLoginEnforcementProps,\n} from './mfa-enforcement-form.ts';\n\nexport interface BaoMfaLoginEnforcement extends Resource<\n 'Bao.MfaLoginEnforcement',\n BaoMfaLoginEnforcementProps,\n BaoMfaLoginEnforcementAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoMfaLoginEnforcement = Resource<BaoMfaLoginEnforcement>('Bao.MfaLoginEnforcement', {\n defaultRemovalPolicy: 'retain',\n});\n\ntype Env = HttpClient.HttpClient;\n\n/** Exact: the identity store indexes enforcements by (namespace, name) as given. */\nconst IDENTITY = nameIdentity<BaoMfaLoginEnforcementAttributes>(\n 'Bao.MfaLoginEnforcement',\n enforcementPath,\n);\n\nconst refuse = (name: string, message: string): Effect.Effect<never> =>\n Effect.die(new Error(`Bao.MfaLoginEnforcement ${name}: ${message}`));\n\n/** Paths resolved to accessors, and what the declaration would be refused for. */\nconst resolveTargets = (props: BaoMfaLoginEnforcementProps) =>\n Effect.map(authAccessors(props.authMethodPaths ?? []), ({ accessors, missing }) => ({\n bad: problems(props, missing),\n resolved: accessors,\n }));\n\nconst readLive = (\n name: string,\n): Effect.Effect<BaoMfaLoginEnforcementAttributes | undefined, BaoError, Env> =>\n Effect.map(readEnforcement(name), (live) =>\n live === undefined ? undefined : attributesOf(name, live),\n );\n\nexport const planEnforcement = (\n props: BaoMfaLoginEnforcementProps,\n): Effect.Effect<'noop' | 'update', BaoError, Env> =>\n Effect.gen(function* () {\n const { bad, resolved } = yield* resolveTargets(props);\n if (bad.length > 0) return 'update';\n const live = yield* readLive(props.name);\n return live !== undefined && matches(live, props, resolved) ? 'noop' : 'update';\n });\n\n/**\n * Write when live differs, then prove it by reading back.\n * ⛔ `claim` (the provider passes it): a create never takes over an enforcement it finds by name.\n */\nexport const reconcileEnforcement = (\n props: BaoMfaLoginEnforcementProps,\n claim?: Claim,\n): Effect.Effect<BaoMfaLoginEnforcementAttributes, BaoError, Env> =>\n Effect.gen(function* () {\n const { bad, resolved } = yield* resolveTargets(props);\n if (bad.length > 0) return yield* refuse(props.name, bad.join('; '));\n const live = yield* readLive(props.name);\n if (live !== undefined && claim !== undefined) {\n yield* claim(`Bao.MfaLoginEnforcement ${props.name}`);\n }\n if (live === undefined || !matches(live, props, resolved)) {\n yield* writeEnforcement(props.name, writeBody(canonicalFromProps(props, resolved)));\n }\n const after = yield* readLive(props.name);\n if (after === undefined)\n return yield* refuse(props.name, 'the write succeeded but it is absent.');\n if (!matches(after, props, resolved)) {\n return yield* refuse(props.name, 'the enforcement read back different.');\n }\n return after;\n });\n\nexport const BaoMfaLoginEnforcementProvider = () =>\n Provider.effect(\n BaoMfaLoginEnforcement,\n Effect.succeed(\n BaoMfaLoginEnforcement.Provider.of({\n /** ⛔ The namespace's enforcement listing is not a list of things this owns. */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readLive(olds.name);\n const ours = Effect.map(planEnforcement(olds), (plan) => plan === 'noop');\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /** ⛔ IT COMPARES THE LIVE ENFORCEMENT — a target removed by hand is drift, not a noop. */\n diff: Effect.fn(function* ({ news, olds, output }) {\n // ⛔ The name first, before isResolved; onto an enforcement that exists fails the plan.\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n return { action: yield* planEnforcement(news) } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a rename the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n return yield* reconcileEnforcement(news, claimFor({ fqn, instanceId, output }));\n }),\n\n /** ⛔ REFUSED — read the header: in 2.6.2 the delete does not survive a restart. */\n delete: Effect.fn(function* ({ output }) {\n return yield* refuse(\n output.name,\n 'REFUSING to delete: OpenBao 2.6.2 drops a login enforcement from memory only, and it ' +\n 'returns on the next unseal (openbao/openbao#4030). Set this resource back to ' +\n 'retain to drop it from state; remove it for good only once the server is fixed.',\n );\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
53
53
|
"/**\n * The form half of Bao.MfaLoginEnforcement — `identity/mfa/login-enforcement/<name>`: which logins\n * must pass which MFA methods.\n *\n * ★ READ FROM openbao v2.6.2 vault/identity/mfa.go handleMFALoginEnforcementUpdate (:511-646):\n * · `mfa_method_ids` is required, and each id must exist in this namespace or a parent.\n * · The four target lists are each `GetOk`: an omitted list KEEPS its stored value, and ANY list\n * that is present — even empty — satisfies \"one of … must be specified\" (:634-636). So every\n * list is sent on every write (a stale target is cleared), and \"all four empty\" — which the\n * server would accept, and which enforces NOTHING — is refused here.\n * · Every field is a TypeStringSlice (store.go:751-772). ⚠️ A comma string there is ONE element\n * (sdk framework/field_data.go:343-356 WeakDecodes a string into a one-item slice), so lists\n * go over as JSON arrays.\n * ⚠️ A TYPE TARGET IS BROAD. `authMethodTypes: ['jwt']` matches EVERY jwt-type mount — including a\n * GitHub Actions or Kubernetes issuer mount, whose logins cannot answer a TOTP prompt. Target\n * mounts by path (resolved to accessors) or by identity group instead.\n */\nimport { sha256 } from './digest.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport interface BaoMfaLoginEnforcementProps {\n /** Enforcement name, unique per namespace. */\n name: string;\n /** Method ids — typically `[totp.methodId]`. Any ONE listed method passing is enough. */\n mfaMethodIds: readonly string[];\n /**\n * Auth mount PATHS (`oidc`, `jwt`), resolved to their accessors at plan and deploy time.\n * ⚠️ A plain string makes no graph edge. When the mount is a BaoAuthMethod in the same stack, pass\n * its output (`[oidc.path]`) so it exists before this resolves — otherwise the deploy can reach\n * this first and refuse with \"no auth mount at …\".\n */\n authMethodPaths?: readonly string[];\n /** Raw accessors (`auth_jwt_…`), for a mount outside this stack. */\n authMethodAccessors?: readonly string[];\n /** Auth mount TYPES — read the ⚠️ above first. */\n authMethodTypes?: readonly string[];\n /** Identity group ids whose members must pass MFA, on any mount. */\n identityGroupIds?: readonly string[];\n /** Identity entity ids, likewise. */\n identityEntityIds?: readonly string[];\n}\n\n/** The live shape, and the declared one once paths are resolved to accessors. */\nexport interface BaoMfaEnforcementCanonical {\n authMethodAccessors: readonly string[];\n authMethodTypes: readonly string[];\n identityEntityIds: readonly string[];\n identityGroupIds: readonly string[];\n mfaMethodIds: readonly string[];\n}\n\n/** ⛔ No secret — ids, accessors and names. */\nexport interface BaoMfaLoginEnforcementAttributes extends BaoMfaEnforcementCanonical {\n name: string;\n /** The server-made id. */\n enforcementId: string;\n namespacePath: string;\n digest: string;\n}\n\nconst sortedSet = (values: readonly string[]) =>\n [...new Set(values.map((value) => value.trim()))].filter((value) => value !== '').sort();\nconst strings = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\nconst canonical = (input: BaoMfaEnforcementCanonical): BaoMfaEnforcementCanonical => ({\n authMethodAccessors: sortedSet(input.authMethodAccessors),\n authMethodTypes: sortedSet(input.authMethodTypes),\n identityEntityIds: sortedSet(input.identityEntityIds),\n identityGroupIds: sortedSet(input.identityGroupIds),\n mfaMethodIds: sortedSet(input.mfaMethodIds),\n});\n\n/** The declaration, with `authMethodPaths` already resolved into `resolved` accessors. */\nexport const canonicalFromProps = (\n props: BaoMfaLoginEnforcementProps,\n resolved: readonly string[],\n): BaoMfaEnforcementCanonical =>\n canonical({\n authMethodAccessors: [...(props.authMethodAccessors ?? []), ...resolved],\n authMethodTypes: props.authMethodTypes ?? [],\n identityEntityIds: props.identityEntityIds ?? [],\n identityGroupIds: props.identityGroupIds ?? [],\n mfaMethodIds: props.mfaMethodIds,\n });\n\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoMfaEnforcementCanonical =>\n canonical({\n authMethodAccessors: strings(live['auth_method_accessors']),\n authMethodTypes: strings(live['auth_method_types']),\n identityEntityIds: strings(live['identity_entity_ids']),\n identityGroupIds: strings(live['identity_group_ids']),\n mfaMethodIds: strings(live['mfa_method_ids']),\n });\n\nexport const attributesOf = (\n name: string,\n live: Record<string, unknown>,\n): BaoMfaLoginEnforcementAttributes => {\n const form = canonicalFromLive(live);\n return {\n ...form,\n digest: sha256(JSON.stringify(form)),\n enforcementId: text(live['id']),\n name,\n namespacePath: text(live['namespace_path']),\n };\n};\n\nexport const matches = (\n attributes: BaoMfaLoginEnforcementAttributes,\n props: BaoMfaLoginEnforcementProps,\n resolved: readonly string[],\n): boolean => attributes.digest === sha256(JSON.stringify(canonicalFromProps(props, resolved)));\n\n/** Every list, as a JSON array, every time — the ⚠️ on GetOk above. */\nexport const writeBody = (form: BaoMfaEnforcementCanonical): Record<string, unknown> => ({\n auth_method_accessors: [...form.authMethodAccessors],\n auth_method_types: [...form.authMethodTypes],\n identity_entity_ids: [...form.identityEntityIds],\n identity_group_ids: [...form.identityGroupIds],\n mfa_method_ids: [...form.mfaMethodIds],\n});\n\nconst NAME = /^\\w(?:[\\w.-]*\\w)?$/;\n\nexport const problems = (\n props: BaoMfaLoginEnforcementProps,\n missingPaths: readonly string[],\n): readonly string[] => {\n const found: string[] = [];\n if (!NAME.test(props.name)) found.push(`name \\`${props.name}\\` is not a valid enforcement name`);\n if (sortedSet(props.mfaMethodIds).length === 0) found.push('mfaMethodIds is empty');\n const targets = [\n props.authMethodPaths,\n props.authMethodAccessors,\n props.authMethodTypes,\n props.identityGroupIds,\n props.identityEntityIds,\n ].some((list) => sortedSet(list ?? []).length > 0);\n if (!targets) found.push('no target: an enforcement with none is accepted and enforces NOTHING');\n if (missingPaths.length > 0) {\n found.push(`no auth mount at ${missingPaths.map((path) => mountPath(path)).join(', ')}`);\n }\n return found;\n};\n",
|
|
54
|
-
"/**\n * The OpenBao calls behind login MFA: TOTP methods under identity/mfa/method/totp, login\n * enforcements under identity/mfa/login-enforcement/<name>, and the auth table that turns a mount\n * path into the accessor an enforcement names.\n *\n * ★ OpenBao 2.6.2 SHIPS LOGIN MFA — confirmed in source before any of this was written:\n * vault/identity/store.go:312-800 (mfaPaths) registers `mfa/method/totp`, `mfa/login-enforcement/\n * <name>` and their listings on the identity backend; vault/identity/mfa.go holds the handlers\n * and vault/login_mfa.go the storage.\n * ★ A TOTP METHOD IS FOUND BY NAME, NOT ID. The id is a server-made UUID; `method_name` is the only\n * thing a declaration can know. An update without `method_id` UPSERTS by name within the request's\n * namespace (identity/mfa.go:159-230, MemDBMFAConfigByName keys on namespace + name), so the same\n * write both creates and updates. The listing (`key_info`, one entry per id, :63-69) answers the\n * methods of this namespace AND its parents (login_mfa.go:652-713), so the match also requires\n * this namespace's `namespace_path`.\n * ⛔ THE NAME INDEX IGNORES THE TYPE, SO THIS LISTS EVERY TYPE. login_mfa.go's `name` index is\n * (namespace_id, name) across all methods (:1642-1655, :1818), and handleMFAMethodUpdateCommon\n * then sets `mConfig.Type = \"totp\"` on whatever it found (identity/mfa.go:228). A TOTP write under\n * the name of a Duo or Okta method would silently CONVERT that method — and every enforcement\n * naming its id would start demanding a TOTP code nobody is enrolled for. The per-type listing\n * (`.../method/totp?list=true`) cannot see the clash, so this reads the global one\n * (`identity/mfa/method?list=true`, store.go:335) and refuses a same-named method of\n * another type. ⚠️ The deploying token needs `list` on `identity/mfa/method`.\n * ⚠️ AN UPDATE BY A STALE `method_id` IS A SILENT NO-OP: the handler returns nil for an unknown id\n * (identity/mfa.go:172-183), which HTTP answers 204. So this never writes by id.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
55
|
-
"/**\n * A TOTP login-MFA method — `identity/mfa/method/totp`, found by `method_name`. The method is\n * policy only: issuer, period, digits. Its `methodId` is what a Bao.MfaLoginEnforcement names.\n *\n * ⛔ A RENAME IS REFUSED, NOT REPLACED. A new name is a new method with a new id, and every entity's\n * enrolled secret belongs to the OLD id (login_mfa.go validateTOTP reads `entity.MFASecrets[id]`).\n * The enforcement would follow the new id in the same deploy, and every enrolled admin would then\n * fail MFA — with nobody left able to log in and re-enrol them. The safe move is additive: declare\n * the new method as a SECOND resource, list both ids on the enforcement (any one method passes,\n * login_mfa.go:831-858), enrol everyone, then drop the old one.\n * ⛔ DELETING THE METHOD DESTROYS EVERY ENROLLED SECRET FOR IT (mfa-wire.ts deleteTotp) — and with\n * openbao/openbao#4030, a deleted enforcement can come back after a restart still naming this id,\n * failing every login it matches. `retain` is the default for exactly that reason.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): never `replace`. `name` changed → the plan FAILS (above); any\n * other field is an in-place `update`, because the upsert keeps the id.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
54
|
+
"/**\n * The OpenBao calls behind login MFA: TOTP methods under identity/mfa/method/totp, login\n * enforcements under identity/mfa/login-enforcement/<name>, and the auth table that turns a mount\n * path into the accessor an enforcement names.\n *\n * ★ OpenBao 2.6.2 SHIPS LOGIN MFA — confirmed in source before any of this was written:\n * vault/identity/store.go:312-800 (mfaPaths) registers `mfa/method/totp`, `mfa/login-enforcement/\n * <name>` and their listings on the identity backend; vault/identity/mfa.go holds the handlers\n * and vault/login_mfa.go the storage.\n * ★ A TOTP METHOD IS FOUND BY NAME, NOT ID. The id is a server-made UUID; `method_name` is the only\n * thing a declaration can know. An update without `method_id` UPSERTS by name within the request's\n * namespace (identity/mfa.go:159-230, MemDBMFAConfigByName keys on namespace + name), so the same\n * write both creates and updates. The listing (`key_info`, one entry per id, :63-69) answers the\n * methods of this namespace AND its parents (login_mfa.go:652-713), so the match also requires\n * this namespace's `namespace_path`.\n * ⛔ THE NAME INDEX IGNORES THE TYPE, SO THIS LISTS EVERY TYPE. login_mfa.go's `name` index is\n * (namespace_id, name) across all methods (:1642-1655, :1818), and handleMFAMethodUpdateCommon\n * then sets `mConfig.Type = \"totp\"` on whatever it found (identity/mfa.go:228). A TOTP write under\n * the name of a Duo or Okta method would silently CONVERT that method — and every enforcement\n * naming its id would start demanding a TOTP code nobody is enrolled for. The per-type listing\n * (`.../method/totp?list=true`) cannot see the clash, so this reads the global one\n * (`identity/mfa/method?list=true`, store.go:335) and refuses a same-named method of\n * another type. ⚠️ The deploying token needs `list` on `identity/mfa/method`.\n * ⚠️ AN UPDATE BY A STALE `method_id` IS A SILENT NO-OP: the handler returns nil for an unknown id\n * (identity/mfa.go:172-183), which HTTP answers 204. So this never writes by id.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { BaoEnv, baoCall, baoDelete, baoRead } from './bao-http.ts';\nimport { envNamespace, namespacePath } from './bao-namespace.ts';\nimport type { BaoError } from './bao-status.ts';\nimport { mountPath } from './mount-form.ts';\n\nexport const TOTP_PATH = 'identity/mfa/method/totp';\n/** Every MFA method of every type — the only listing that can see a name clash across types. */\nexport const METHODS_PATH = 'identity/mfa/method';\nexport const enforcementPath = (name: string): string => `identity/mfa/login-enforcement/${name}`;\n\nconst record = (value: unknown): Record<string, unknown> | undefined =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined;\n\n/** This call's namespace as OpenBao writes `namespace_path`: `''` or `team-a/`. */\nexport const ownNamespacePath: Effect.Effect<string> = Effect.gen(function* () {\n const env = yield* BaoEnv;\n return namespacePath(envNamespace(env));\n});\n\nexport type TotpEntry = { readonly id: string; readonly live: Record<string, unknown> };\n\n/**\n * The TOTP method named `name` in this namespace, or undefined. Dies when the name belongs to a\n * method of ANOTHER type here — writing would convert it (the ⛔ above).\n */\nexport const findTotp = (\n name: string,\n): Effect.Effect<TotpEntry | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const listing = yield* baoRead(`${METHODS_PATH}?list=true`);\n const info = record(listing?.['key_info']) ?? {};\n const own = yield* ownNamespacePath;\n for (const [id, raw] of Object.entries(info)) {\n const live = record(raw);\n if (live === undefined || live['name'] !== name || live['namespace_path'] !== own) continue;\n if (live['type'] !== 'totp') {\n return yield* Effect.die(\n new Error(\n `Bao.MfaTotpMethod ${name}: that name belongs to a ${String(live['type'])} method ` +\n `(${id}) in this namespace, and a TOTP write would convert it. Pick another name.`,\n ),\n );\n }\n return { id, live };\n }\n return undefined;\n });\n\n/** Create-or-update by `method_name` — never by id (the ⚠️ above). */\nexport const writeTotp = (body: Readonly<Record<string, unknown>>) =>\n Effect.asVoid(baoCall('write', 'POST', TOTP_PATH, body));\n\n/**\n * ⛔ DESTROYS EVERY ENTITY'S ENROLLED SECRET FOR THIS METHOD (login_mfa.go:1965-1973 clears the TOTP\n * keys under the method id). OpenBao refuses it while an enforcement in memory still names the id\n * (:1914-1924) — a refusal this passes on.\n */\nexport const deleteTotp = (id: string) => baoDelete(`${TOTP_PATH}/${id}`);\n\nexport const readEnforcement = (name: string) => baoRead(enforcementPath(name));\n\nexport const writeEnforcement = (name: string, body: Readonly<Record<string, unknown>>) =>\n Effect.asVoid(baoCall('write', 'POST', enforcementPath(name), body));\n\n/**\n * Accessors for auth mount paths, from `GET sys/auth` (keys are `<path>/`). A path with no mount\n * comes back in `missing`, never as a guess.\n */\nexport const authAccessors = (\n paths: readonly string[],\n): Effect.Effect<\n { readonly accessors: readonly string[]; readonly missing: readonly string[] },\n BaoError,\n HttpClient.HttpClient\n> =>\n Effect.gen(function* () {\n if (paths.length === 0) return { accessors: [], missing: [] };\n const table = (yield* baoRead('sys/auth')) ?? {};\n const accessors: string[] = [];\n const missing: string[] = [];\n for (const path of paths) {\n const accessor = record(table[`${mountPath(path)}/`])?.['accessor'];\n if (typeof accessor === 'string' && accessor !== '') accessors.push(accessor);\n else missing.push(mountPath(path));\n }\n return { accessors, missing };\n });\n",
|
|
55
|
+
"/**\n * A TOTP login-MFA method — `identity/mfa/method/totp`, found by `method_name`. The method is\n * policy only: issuer, period, digits. Its `methodId` is what a Bao.MfaLoginEnforcement names.\n *\n * ⛔ A RENAME IS REFUSED, NOT REPLACED. A new name is a new method with a new id, and every entity's\n * enrolled secret belongs to the OLD id (login_mfa.go validateTOTP reads `entity.MFASecrets[id]`).\n * The enforcement would follow the new id in the same deploy, and every enrolled admin would then\n * fail MFA — with nobody left able to log in and re-enrol them. The safe move is additive: declare\n * the new method as a SECOND resource, list both ids on the enforcement (any one method passes,\n * login_mfa.go:831-858), enrol everyone, then drop the old one.\n * ⛔ DELETING THE METHOD DESTROYS EVERY ENROLLED SECRET FOR IT (mfa-wire.ts deleteTotp) — and with\n * openbao/openbao#4030, a deleted enforcement can come back after a restart still naming this id,\n * failing every login it matches. `retain` is the default for exactly that reason.\n *\n * ★ REPLACE SEMANTICS (REPLACE.md): never `replace`. `name` changed → the plan FAILS (above); any\n * other field is an in-place `update`, because the upsert keeps the id.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { type Claim, claimFor } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n type BaoMfaTotpMethodAttributes,\n type BaoMfaTotpMethodProps,\n attributesOf,\n matches,\n problems,\n renameProblem,\n writeBody,\n} from './mfa-totp-form.ts';\nimport { deleteTotp, findTotp, writeTotp } from './mfa-wire.ts';\nimport { declaredString } from './rename.ts';\n\nexport type {\n BaoMfaTotpMethodAttributes,\n BaoMfaTotpMethodProps,\n BaoTotpAlgorithm,\n} from './mfa-totp-form.ts';\n\nexport interface BaoMfaTotpMethod extends Resource<\n 'Bao.MfaTotpMethod',\n BaoMfaTotpMethodProps,\n BaoMfaTotpMethodAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoMfaTotpMethod = Resource<BaoMfaTotpMethod>('Bao.MfaTotpMethod', {\n defaultRemovalPolicy: 'retain',\n});\n\nconst refuse = (name: string, message: string): Effect.Effect<never> =>\n Effect.die(new Error(`Bao.MfaTotpMethod ${name}: ${message}`));\n\nexport const readTotp = (\n props: BaoMfaTotpMethodProps,\n): Effect.Effect<BaoMfaTotpMethodAttributes | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.map(findTotp(props.name), (found) =>\n found === undefined ? undefined : attributesOf(found.id, found.live),\n );\n\nexport const planTotp = (\n props: BaoMfaTotpMethodProps,\n): Effect.Effect<'noop' | 'update', BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n if (problems(props).length > 0) return 'update';\n const live = yield* readTotp(props);\n return live !== undefined && matches(live, props) ? 'noop' : 'update';\n });\n\n/**\n * Upsert by name when live differs, then prove it by reading back.\n * ⛔ `claim` (the provider passes it): a create never takes over a method it finds by that name.\n */\nexport const reconcileTotp = (\n props: BaoMfaTotpMethodProps,\n claim?: Claim,\n): Effect.Effect<BaoMfaTotpMethodAttributes, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const bad = problems(props);\n if (bad.length > 0) return yield* refuse(props.name, bad.join('; '));\n const live = yield* readTotp(props);\n if (live !== undefined && claim !== undefined) yield* claim(`Bao.MfaTotpMethod ${props.name}`);\n if (live === undefined || !matches(live, props)) yield* writeTotp(writeBody(props));\n const after = yield* readTotp(props);\n if (after === undefined)\n return yield* refuse(props.name, 'the write succeeded but no method has that name.');\n if (!matches(after, props)) return yield* refuse(props.name, 'the method read back different.');\n return after;\n });\n\nexport const BaoMfaTotpMethodProvider = () =>\n Provider.effect(\n BaoMfaTotpMethod,\n Effect.succeed(\n BaoMfaTotpMethod.Provider.of({\n /** ⛔ The namespace's method listing is not a list of things this owns. */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readTotp(olds);\n const ours = Effect.sync(\n () => found !== undefined && problems(olds).length === 0 && matches(found, olds),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ THE NAME IS JUDGED BEFORE `isResolved(news)`. Until 2026-09-21 it came after, so a\n * rename landing with a pending `issuer` (or any other Output) planned `update`, and the\n * upsert by name wrote a SECOND method: the header's stranding, reached through a green\n * plan. MEASURED through the engine (rename-families.test.ts).\n */\n diff: Effect.fn(function* ({ news, output }) {\n const name = declaredString(news, 'name');\n if (output !== undefined && name !== undefined) {\n const rename = renameProblem(output.name, name);\n if (rename !== undefined) return yield* refuse(name, rename);\n }\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (!isResolved(news)) return undefined;\n return { action: yield* planTotp(news) } as const;\n }),\n\n /** ⛔ A rename the diff could not see (the name was an Output), refused before any write. */\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const rename = output === undefined ? undefined : renameProblem(output.name, news.name);\n if (rename !== undefined) return yield* refuse(news.name, rename);\n return yield* reconcileTotp(news, claimFor({ fqn, instanceId, output }));\n }),\n\n /** ⛔ Read the header first. Idempotent: an unknown id deletes as success. */\n delete: Effect.fn(function* ({ output }) {\n yield* deleteTotp(output.methodId);\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
56
56
|
"/**\n * The form half of Bao.MfaTotpMethod — a TOTP login-MFA method, identified by its `method_name`.\n *\n * ★ READ FROM openbao v2.6.2 vault/identity/store.go:349-427 (fields) and vault/identity/mfa.go\n * parseTOTPConfig (:662-741): `issuer` is required; `algorithm` is SHA1|SHA256|SHA512; `digits`\n * 6|8; `skew` 0|1; `period`, `key_size` above zero; `max_validation_attempts` 0 means the default\n * of 5 (:35). EVERY field is `d.Get`, so a write resets whatever it omits — every one is sent.\n * ★ THE READ (login_mfa.go mfaConfigToMap :775-829) answers `period` in seconds and `algorithm` as\n * its name; `name`, `id` and `namespace_path` ride along.\n * ⚠️ A CHANGED ALGORITHM, DIGITS OR PERIOD APPLIES TO NEW ENROLMENTS ONLY. Validation uses the\n * parameters stored with each entity's own secret (login_mfa.go validateTOTP :1520-1545), so an\n * enrolled admin keeps working — with the old parameters — until re-enrolled.\n * ⛔ NO SECRET: the method holds no key. Each entity's TOTP secret is generated per entity by\n * `.../totp/generate` or `admin-generate`, which RETURNS it; this resource calls neither.\n */\nimport { sha256 } from './digest.ts';\nimport { parseDuration, ttlSeconds } from './mount-form.ts';\n\nexport type BaoTotpAlgorithm = 'SHA1' | 'SHA256' | 'SHA512';\n\nexport interface BaoMfaTotpMethodProps {\n /** `method_name` — the declarative key, unique per namespace. ⛔ A rename is refused (mfa-totp.ts). */\n name: string;\n /** The issuer an authenticator app shows, e.g. `vault-example`. */\n issuer: string;\n /** Code lifetime. Default `30s`. */\n period?: string;\n /** Secret size in bytes. Default 20. */\n keySize?: number;\n /** QR code size in pixels; `0` for none. Default 200. */\n qrSize?: number;\n /** Default `SHA1` — the one every authenticator app supports. */\n algorithm?: BaoTotpAlgorithm;\n /** Default 6. */\n digits?: 6 | 8;\n /** Periods of clock skew accepted. Default 1. */\n skew?: 0 | 1;\n /** Failed codes before the entity is locked out of this method. Default 5. */\n maxValidationAttempts?: number;\n}\n\nexport interface BaoMfaTotpCanonical {\n algorithm: string;\n digits: number;\n issuer: string;\n keySize: number;\n maxValidationAttempts: number;\n periodSeconds: number;\n qrSize: number;\n skew: number;\n}\n\nexport interface BaoMfaTotpMethodAttributes extends BaoMfaTotpCanonical {\n /** The server-made UUID — what a Bao.MfaLoginEnforcement names in `mfaMethodIds`. */\n methodId: string;\n name: string;\n /** `''` for root, `team-a/` below it. */\n namespacePath: string;\n digest: string;\n}\n\nconst canonical = (input: BaoMfaTotpCanonical): BaoMfaTotpCanonical => ({\n algorithm: input.algorithm,\n digits: input.digits,\n issuer: input.issuer,\n keySize: input.keySize,\n maxValidationAttempts: input.maxValidationAttempts,\n periodSeconds: input.periodSeconds,\n qrSize: input.qrSize,\n skew: input.skew,\n});\n\nexport const canonicalFromProps = (props: BaoMfaTotpMethodProps): BaoMfaTotpCanonical =>\n canonical({\n algorithm: props.algorithm ?? 'SHA1',\n digits: props.digits ?? 6,\n issuer: props.issuer,\n keySize: props.keySize ?? 20,\n maxValidationAttempts: props.maxValidationAttempts ?? 5,\n periodSeconds: parseDuration(props.period ?? '30s') ?? -1,\n qrSize: props.qrSize ?? 200,\n skew: props.skew ?? 1,\n });\n\nconst num = (value: unknown) => (typeof value === 'number' && Number.isFinite(value) ? value : -1);\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoMfaTotpCanonical =>\n canonical({\n algorithm: text(live['algorithm']),\n digits: num(live['digits']),\n issuer: text(live['issuer']),\n keySize: num(live['key_size']),\n maxValidationAttempts: num(live['max_validation_attempts']),\n periodSeconds: ttlSeconds(live['period']) ?? -1,\n qrSize: num(live['qr_size']),\n skew: num(live['skew']),\n });\n\nexport const attributesOf = (\n methodId: string,\n live: Record<string, unknown>,\n): BaoMfaTotpMethodAttributes => {\n const form = canonicalFromLive(live);\n return {\n ...form,\n digest: sha256(JSON.stringify(form)),\n methodId,\n name: text(live['name']),\n namespacePath: text(live['namespace_path']),\n };\n};\n\nexport const matches = (attributes: BaoMfaTotpMethodAttributes, props: BaoMfaTotpMethodProps) =>\n attributes.digest === sha256(JSON.stringify(canonicalFromProps(props)));\n\n/** The upsert body — by `method_name`, never `method_id` (mfa-wire.ts). */\nexport const writeBody = (props: BaoMfaTotpMethodProps): Record<string, unknown> => {\n const form = canonicalFromProps(props);\n return {\n algorithm: form.algorithm,\n digits: form.digits,\n issuer: form.issuer,\n key_size: form.keySize,\n max_validation_attempts: form.maxValidationAttempts,\n method_name: props.name,\n period: props.period ?? '30s',\n qr_size: form.qrSize,\n skew: form.skew,\n };\n};\n\n/**\n * The diff's refusal for a changed name, or undefined when the name is unchanged. Never a\n * `replace`: the ⛔ on a rename in mfa-totp.ts says why.\n */\nexport const renameProblem = (from: string, to: string): string | undefined =>\n from === to\n ? undefined\n : `renaming from \\`${from}\\` would strand every enrolled secret. Declare the new method as a ` +\n 'second resource, list both ids on the enforcement, enrol, then remove the old one ' +\n '(mfa-totp.ts).';\n\nexport const problems = (props: BaoMfaTotpMethodProps): readonly string[] => {\n const found: string[] = [];\n const form = canonicalFromProps(props);\n if (props.name.trim() === '') found.push('name is empty; it is the only key a declaration has');\n if (props.issuer.trim() === '') found.push('issuer is empty; the server requires one');\n if (form.periodSeconds <= 0)\n found.push(`period \\`${props.period ?? ''}\\` must be a duration above zero`);\n if (form.keySize <= 0) found.push('keySize must be above zero');\n if (form.maxValidationAttempts < 1)\n found.push('maxValidationAttempts must be at least 1 (0 reads back as 5)');\n return found;\n};\n",
|
|
57
|
-
"/**\n * An OpenBao secrets engine mount — path, type, description and lease TTLs.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for why. This declares mount\n * SHAPE only: names, types, TTL strings and a digest. KV values and CA material live\n * in OpenBao, not Alchemy state.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — disabling a mount destroys every secret under it.\n * Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n *\n * ★ REPLACE SEMANTICS (audited 2026-09-21, see src/openbao/REPLACE.md):\n * · `type` changed → plans `replace`, and the APPLY FAILS, destroying nothing: the new\n * generation's path is the old one's, still occupied, so its reconcile dies \"type is\n * immutable\" before any write (mount-reconcile.ts). Change a type by hand. ⛔ Not `deleteFirst`\n * on purpose — under `destroy` that would disable the mount, every secret with it, on a typo.\n * · `path` changed → FAILS the plan unless `remountFrom` names the old path, which is an\n * in-place `update` that moves the mount and its data (mount-move.ts). It used to be an\n * `update` that enabled an EMPTY mount at the new path.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
58
|
-
"/**\n * Bao.Mount's read and reconcile as plain effects — split from mount.ts so the move (and its\n * refusals) run against a fake server, not only in a reviewer's head.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
57
|
+
"/**\n * An OpenBao secrets engine mount — path, type, description and lease TTLs.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for why. This declares mount\n * SHAPE only: names, types, TTL strings and a digest. KV values and CA material live\n * in OpenBao, not Alchemy state.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — disabling a mount destroys every secret under it.\n * Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n *\n * ★ REPLACE SEMANTICS (audited 2026-09-21, see src/openbao/REPLACE.md):\n * · `type` changed → plans `replace`, and the APPLY FAILS, destroying nothing: the new\n * generation's path is the old one's, still occupied, so its reconcile dies \"type is\n * immutable\" before any write (mount-reconcile.ts). Change a type by hand. ⛔ Not `deleteFirst`\n * on purpose — under `destroy` that would disable the mount, every secret with it, on a typo.\n * · `path` changed → FAILS the plan unless `remountFrom` names the old path, which is an\n * in-place `update` that moves the mount and its data (mount-move.ts). It used to be an\n * `update` that enabled an EMPTY mount at the new path.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { type BaoMountAttributes, type BaoMountProps, matches } from './mount-form.ts';\nimport { planMove } from './mount-move.ts';\nimport { readMount, reconcileMount } from './mount-reconcile.ts';\nimport { disableMount } from './mount-wire.ts';\n\nexport type { BaoMountAttributes, BaoMountProps };\n\nexport interface BaoMount extends Resource<\n 'Bao.Mount',\n BaoMountProps,\n BaoMountAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoMount = Resource<BaoMount>('Bao.Mount', {\n defaultRemovalPolicy: 'retain',\n});\n\nexport const BaoMountProvider = () =>\n Provider.effect(\n BaoMount,\n Effect.succeed(\n BaoMount.Provider.of({\n /**\n * ⛔ `bao secrets list` IS NOT A LIST OF THINGS THIS OWNS. Every mount in the\n * namespace answers, including ones created by hand at bringup. Returning them\n * would invite Alchemy to adopt — and then disable — mounts it never created.\n * ⚠️ mount-wire.ts does read that listing, for one question only: whether a mount a 400\n * named is really absent. It never becomes a list of resources.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readMount(olds);\n const ours = Effect.sync(() => found !== undefined && matches(found, olds));\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n diff: Effect.fn(function* ({ news, output }) {\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (!isResolved(news)) return undefined;\n /**\n * ⛔ A CHANGED PATH IS DECIDED HERE, BEFORE ANY READ OF THE NEW PATH — reading it would\n * find nothing and plan `update`, which is how an empty mount used to get enabled.\n */\n const move = planMove('Bao.Mount', output.path, news.path, news.remountFrom);\n if (move.kind === 'refuse') return yield* Effect.die(new Error(move.message));\n if (move.kind === 'move') return { action: 'update' } as const;\n const live = yield* readMount(news);\n if (live === undefined) return { action: 'update' } as const;\n /**\n * ⛔ A CHANGED `type` IS A REPLACE, AND THIS FAMILY'S DELETE IS A MOUNT DISABLE — the\n * destruction of every secret under the mount. `kv/` is the estate's entire\n * secret shelf, so the question \"does `retain` guard the delete half of a REPLACE, or\n * only an orphan?\" is the difference between a typo and a catastrophe.\n * ★ IT GUARDS BOTH — VERIFIED IN ALCHEMY'S OWN SOURCE, not assumed. Apply.ts:2164-2173:\n * \"Honor `retain` for the old generation of a replacement, mirroring the orphan-delete\n * path above\", with `retainOldGeneration = node.removalPolicy === 'retain'`, and when\n * it is true the engine logs \"Retaining replaced resource (removal policy: retain)\"\n * and skips the delete entirely. Every mount this package declares carries the retain\n * default (see the ★ on the resource below), so a wrong `type` string cannot disable a\n * live mount. What it CAN do is fail: the new generation reads the SAME path, finds the\n * old type there and dies before any write (mount-reconcile.ts) — a failed deploy, not a\n * lost shelf (corrected 2026-09-21; this said OpenBao refused a second enable).\n * ⚠️ THAT SAFETY IS THE DECORATION'S, NOT THIS LINE'S. A caller who opts into\n * `.pipe(RemovalPolicy.destroy())` gets the destructive replace, which is the correct\n * meaning of opting in and is worth knowing before you type it on a mount.\n */\n if (live.type !== news.type) return { action: 'replace' } as const;\n if (matches(live, news)) return { action: 'noop' } as const;\n return { action: 'update' } as const;\n }),\n\n /**\n * ★ A REFUSED ENABLE OR TUNE FAILS THE EFFECT WITH OpenBao's OWN `errors`, naming the\n * method and path — the job the per-command exit-code checks used to do by hand.\n * The body, and the move, live in mount-reconcile.ts.\n */\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const claim = claimFor({ fqn, instanceId, output });\n return yield* reconcileMount(news, output?.path, undefined, claim);\n }),\n\n /**\n * ⛔ DISABLING A MOUNT DESTROYS EVERY SECRET UNDER IT. Idempotent as Alchemy\n * requires — already gone is success — but retain is the default for a reason.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* disableMount(output.path);\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
58
|
+
"/**\n * Bao.Mount's read and reconcile as plain effects — split from mount.ts so the move (and its\n * refusals) run against a fake server, not only in a reviewer's head.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { Claim } from '../ownership/adopt.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n type BaoMountAttributes,\n type BaoMountProps,\n attributesOf,\n matches,\n mountPath,\n wantsTune,\n} from './mount-form.ts';\nimport { type MoveTarget, performMove, planMove } from './mount-move.ts';\nimport { enableMount, readMountData, tuneMount } from './mount-wire.ts';\nimport type { RemountError, RemountOptions } from './remount-wire.ts';\n\nexport const readMount = (\n props: BaoMountProps,\n): Effect.Effect<BaoMountAttributes | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const live = yield* readMountData(props.path);\n if (live === undefined) return undefined;\n return attributesOf(props, live);\n });\n\nconst moveTarget = (props: BaoMountProps): MoveTarget => ({\n family: 'Bao.Mount',\n path: props.path,\n read: (path) => readMount({ ...props, path }),\n type: props.type,\n wire: mountPath,\n});\n\n/**\n * Converge one mount. `stated` is the path in Alchemy's state (undefined on a first reconcile).\n * Dies on a refusal; fails with OpenBao's own error on a refused call.\n * ⛔ `claim` (mount.ts always passes it) refuses, before any write, a first reconcile that would take\n * over a live mount: the one at the path, or the `remountFrom` source it would move\n * (ownership/adopt.ts).\n */\nexport const reconcileMount = (\n news: BaoMountProps,\n stated: string | undefined,\n options?: RemountOptions,\n claim?: Claim,\n): Effect.Effect<BaoMountAttributes, BaoError | RemountError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const move = planMove('Bao.Mount', stated, news.path, news.remountFrom);\n if (move.kind === 'refuse') return yield* Effect.die(new Error(move.message));\n const first = stated === undefined ? claim : undefined;\n if (first !== undefined && move.kind === 'move') {\n const source = yield* readMount({ ...news, path: move.from });\n if (source !== undefined) yield* first(`Bao.Mount ${move.from} (the remountFrom source)`);\n }\n if (move.kind === 'move') yield* performMove(moveTarget(news), move.from, options);\n\n let live = yield* readMount(news);\n if (live === undefined) {\n yield* enableMount(news);\n if (wantsTune(news)) yield* tuneMount(news);\n } else {\n if (live.type !== news.type) {\n return yield* Effect.die(\n new Error(\n `Bao.Mount ${mountPath(news.path)}: live type ${live.type} != ${news.type}. ` +\n 'Secrets engine type is immutable — replace manually.',\n ),\n );\n }\n if (first !== undefined) yield* first(`Bao.Mount ${mountPath(news.path)}`);\n if (!matches(live, news)) yield* tuneMount(news);\n }\n live = yield* readMount(news);\n if (live === undefined) {\n return yield* Effect.die(\n new Error(\n `Bao.Mount ${mountPath(news.path)}: write returned no error but the mount is still absent.`,\n ),\n );\n }\n return live;\n });\n",
|
|
59
59
|
"/**\n * The OpenBao calls Bao.Mount makes — read one mount, enable, tune, disable. Split from mount.ts so\n * the classification of a MISSING mount can be tested against a fake server.\n *\n * ★ ENDPOINTS, READ FROM openbao v2.6.2 api/sys_mounts.go — the client the CLI used:\n * read GET sys/mounts/<path> (MountInfo, :254) — what `bao read sys/mounts/<path>` hit\n * enable POST sys/mounts/<path> (Mount, :57) — `bao secrets enable`\n * tune POST sys/mounts/<path>/tune (TuneMount, :201) — `bao secrets tune`\n * disable DELETE sys/mounts/<path> (Unmount, :79) — `bao secrets disable`\n */\nimport * as Effect from 'effect/Effect';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport { BaoError } from './bao-status.ts';\nimport {\n type BaoMountProps,\n enableBody,\n mountPath,\n readPath,\n tuneBody,\n tunePath,\n} from './mount-form.ts';\n\n/**\n * Confirm a mount is absent from the mount table, or give back the error that asked.\n *\n * ⛔ A MISSING MOUNT IS NOT A 404, IT IS A 400 — AND THAT MADE A NEW MOUNT UNCREATABLE, SILENTLY,\n * THE SAME WAY A NEW POLICY WAS (b3c18a33e). `handleReadMount` answers a path with no mount with a\n * bare error response, \"No secret engine mount at <path>\" (vault/logical_system.go:1171-1178), and\n * RespondErrorCommon turns an error response with no coded error into 400\n * (sdk/logical/response_util.go). The CLI therefore exited 2 with that text, which was not\n * `No value found at`, so every read of an undeclared-yet mount FAILED and reconcile never\n * reached `secrets enable`. All four declared mounts already exist, which is the only reason\n * nothing broke. REASONED FROM SOURCE, NOT MEASURED — no read of a missing mount was run.\n * ★ SO A 400 IS SETTLED BY A SECOND, STATUS-CLASSIFIED QUESTION rather than by matching that text:\n * `GET sys/mounts` lists the namespace's mount table, keyed `<path>/`. Only a 200 table WITHOUT\n * the key is absence. A listed mount, a refused listing, or a 404 listing leaves the original 400\n * standing — \"I could not tell\" is an error, never a create.\n * ⚠️ THE LISTING NEEDS `read` ON `sys/mounts`. The admin lane has it\n * (policies/homeflare-admin/live-captured-2026-09-02.hcl:20). A narrower token still fails, which\n * is what it did before.\n */\nconst absentFromTable = (path: string, asked: BaoError) =>\n baoRead('sys/mounts').pipe(\n // ⚠️ A listing that fails keeps the 400, and says why it could not settle it.\n Effect.mapError(\n (listing) =>\n new BaoError(asked.status, asked.method, asked.path, [\n ...asked.errors,\n `sys/mounts could not confirm the mount is absent: ${listing.message}`,\n ]),\n ),\n Effect.flatMap((table) =>\n table !== undefined && !Object.hasOwn(table, `${mountPath(path)}/`)\n ? Effect.succeed(undefined)\n : Effect.fail(asked),\n ),\n );\n\n/** One mount's config (`type`, `description`, `config.*_lease_ttl`), or undefined when absent. */\nexport const readMountData = (path: string) =>\n baoRead(readPath(path)).pipe(\n Effect.catchIf(\n (error) => error.status === 400,\n (error) => absentFromTable(path, error),\n ),\n );\n\nexport const enableMount = (props: BaoMountProps) =>\n baoWrite('POST', readPath(props.path), enableBody(props));\n\nexport const tuneMount = (props: BaoMountProps) =>\n baoWrite('POST', tunePath(props.path), tuneBody(props));\n\n/**\n * ⚠️ THERE IS NO FORCE. The old delete ran `bao secrets disable -force`, and v2.6.2's\n * command/secrets_disable.go defines no `-force` flag, so that argv would have been refused at\n * flag parsing. `Unmount` is a plain DELETE (api/sys_mounts.go:79); nothing else was ever sent.\n */\nexport const disableMount = (path: string) => baoDelete(readPath(path));\n",
|
|
60
|
-
"/**\n * An OpenBao PKI role — the policy a future issuance is checked against, and nothing else.\n *\n * ⛔ THE ROLE IS THE POLICY, NEVER THE CERTIFICATE. Nothing here touches `pki/issue/*` (which\n * RETURNS a private key) or `pki/root/generate/*` (which CREATES one). Every value this\n * resource stores is a domain name, a flag, a bit count or a TTL — safe to sit in Alchemy's\n * UNENCRYPTED Postgres state. See policy.ts for why that line is load-bearing here.\n *\n * ⛔ `bao write pki/roles/<name>` REPLACES THE WHOLE ROLE — it is not a merge. OpenBao builds\n * a fresh role entry from the request, so every field left out reverts to its SCHEMA\n * DEFAULT. MEASURED 2026-09-13 against the live OpenBao 2.6.2, from its own\n * `sys/internal/specs/openapi` cross-read against all eight live `pki/roles/*`, four of\n * those defaults are WIDER than what this estate actually runs:\n *\n * allow_ip_sans default true — false on 5 of the 8 roles\n * allow_localhost default true — false on 6 of the 8\n * allow_wildcard_certificates default true — false on 6 of the 8\n * cn_validations default [\"email\",\"hostname\"] — [\"hostname\"] on 5 of the 8\n *\n * A resource that managed only the eleven fields the brief named would therefore, on any\n * unrelated TTL edit, silently re-open wildcards and localhost on six production roles.\n * That is why those four are props in pki-role-form.ts though they were not in the brief,\n * and why their default there is the CLOSED value rather than OpenBao's open one.\n *\n * ★ NARROWING IS THE FAIL-SAFE DIRECTION. A default tighter than OpenBao's can only refuse a\n * certificate that should have been issued — loud, and cured by declaring the field. A\n * default looser than OpenBao's issues one that should have been refused, in silence.\n *\n * ⚠️ WHAT WAS NOT MEASURED. Only reads were run against the live engine; no `bao write`\n * happened, so nothing below is a verified round-trip. Two consequences carried into the\n * form file: every live role has `ext_key_usage: []`, so the stored casing of a non-empty\n * list was never observed (the compare folds case because OpenBao matches these\n * case-insensitively at issuance); and every live role has exactly ONE allowed domain, so\n * whether OpenBao preserves list order was never observed either (the compare sorts,\n * because allowed_domains is a set). Both choices can only mask a cosmetic difference,\n * never a policy one — but neither is a measurement.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — see the delete comment below. Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport {\n type BaoPkiRoleAttributes,\n type BaoPkiRoleProps,\n attributesOf,\n matches,\n problems,\n rolePath,\n writeBody,\n} from './pki-role-form.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoPkiRoleAttributes, BaoPkiRoleProps };\n\nexport interface BaoPkiRole extends Resource<\n 'Bao.PkiRole',\n BaoPkiRoleProps,\n BaoPkiRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoPkiRole = Resource<BaoPkiRole>('Bao.PkiRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the engine stores `role/<name>` verbatim (builtin/logical/pki/path_roles.go:963). */\nconst IDENTITY = roleIdentity<BaoPkiRoleAttributes>(\n 'Bao.PkiRole',\n (mount, name) => rolePath({ mount, name }),\n 'pki',\n);\n\nconst readRole = (props: BaoPkiRoleProps) =>\n Effect.gen(function* () {\n const live = yield* baoRead(rolePath(props));\n if (live === undefined) return undefined;\n return attributesOf(props, live);\n });\n\nexport const BaoPkiRoleProvider = () =>\n Provider.effect(\n BaoPkiRole,\n Effect.succeed(\n BaoPkiRole.Provider.of({\n /**\n * ⛔ `bao list pki/roles` IS NOT A LIST OF THINGS THIS OWNS. All eight roles in the\n * live engine answer it, and every one of them predates this resource. Returning\n * them would invite Alchemy to adopt — and then delete — roles it never created.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(olds);\n const ours = Effect.sync(\n () => found !== undefined && problems(olds).length === 0 && matches(found, olds),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES A DIGEST OF THE LIVE ROLE, NOT THE STORED ONE. The attributes fed to\n * `matches` are always freshly derived from a live read in this same operation, so\n * a role widened by hand in the OpenBao UI still reads as drift — which is the\n * whole reason the check-* gates exist. Comparing one digest rather than sixteen\n * fields is also what stops a field being added to props and quietly forgotten in\n * the comparison.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⚠️ A ROLE IS IDENTIFIED BY MOUNT **AND** NAME. Moving a declaration to another\n * engine is a different object under a different CA, never an in-place edit —\n * `replace`, so Alchemy creates the new one and retires the old. Judged before\n * `isResolved(news)`, and ⛔ a move onto a role that exists fails the plan\n * (rename-identity.ts).\n * ⛔ A RENAME WAS NOT CAUGHT UNTIL 2026-09-21 (REPLACE.md): only the mount was compared,\n * so a new `name` read nothing at the new path, planned `update`, wrote the new role,\n * and left the old one issuing certificates under no state record at all.\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n /**\n * ⚠️ A DECLARATION reconcile WOULD REFUSE MUST NEVER PLAN AS noop. An empty\n * allowedDomains, or a duration OpenBao cannot parse, can compare equal to a\n * live role already in that state — and a noop there hides the refusal behind a\n * clean plan until the next deploy. Route it to reconcile, which says why.\n * (The full list is `problems` in pki-role-form.ts.)\n */\n if (problems(news).length > 0) return { action: 'update' } as const;\n const live = yield* readRole(news);\n if (live === undefined) return { action: 'update' } as const;\n return matches(live, news)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n /**\n * ⛔ AN EMPTY allowedDomains IS A REFUSAL, NOT AN EMPTY ROLE. `allow_any_name` is\n * false on every live role, so a role with no allowed domains can issue NOTHING —\n * and an unresolved or mistyped prop reads exactly like an author who meant it.\n * policy.ts refuses an empty fragment directory for the same reason. The other\n * refusals — an unparseable duration, noStore with generateLease — are in `problems`.\n */\n const bad = problems(news);\n if (bad.length > 0) {\n return yield* Effect.die(new Error(`Bao.PkiRole ${path}: ${bad.join(' ')}`));\n }\n const live = yield* readRole(news);\n if (live !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.PkiRole ${path}`);\n if (live === undefined || !matches(live, news)) {\n yield* baoWrite('PUT', path, writeBody(news));\n }\n const after = yield* readRole(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`),\n );\n }\n /**\n * ⛔ THE WRITE IS NOT TRUSTED, IT IS RE-READ AND RE-COMPARED. A write succeeds (2xx)\n * for a field it accepted but stored differently — the live worry being the\n * comma-joined list values in writeBody, whose splitting is documented for\n * allowed_domains and ext_key_usage but NOT for cn_validations. Without this\n * check a role could land with `cn_validations: [\"email,hostname\"]`, report\n * success, and then refuse every renewal at issuance time instead.\n */\n if (!matches(after, news)) {\n return yield* Effect.die(\n new Error(\n `Bao.PkiRole ${path}: wrote cleanly but the role read back different. ` +\n 'OpenBao stored something other than what was declared — inspect with ' +\n `\\`bao read ${path}\\` before retrying.`,\n ),\n );\n }\n return after;\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE CERTIFICATES IT ISSUED — they stay valid to\n * their own expiry, so this is quiet now and loud much later: every renewal through\n * the role fails once the current certificate runs out. MEASURED: the live roles\n * carry ttl 604800 to 31536000 seconds, so the fuse on `rpi5-otel-client` is a full\n * year. Idempotent as Alchemy requires — already gone is success — but retain is\n * the default for exactly this reason.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
60
|
+
"/**\n * An OpenBao PKI role — the policy a future issuance is checked against, and nothing else.\n *\n * ⛔ THE ROLE IS THE POLICY, NEVER THE CERTIFICATE. Nothing here touches `pki/issue/*` (which\n * RETURNS a private key) or `pki/root/generate/*` (which CREATES one). Every value this\n * resource stores is a domain name, a flag, a bit count or a TTL — safe to sit in Alchemy's\n * UNENCRYPTED Postgres state. See policy.ts for why that line is load-bearing here.\n *\n * ⛔ `bao write pki/roles/<name>` REPLACES THE WHOLE ROLE — it is not a merge. OpenBao builds\n * a fresh role entry from the request, so every field left out reverts to its SCHEMA\n * DEFAULT. MEASURED 2026-09-13 against the live OpenBao 2.6.2, from its own\n * `sys/internal/specs/openapi` cross-read against all eight live `pki/roles/*`, four of\n * those defaults are WIDER than what this estate actually runs:\n *\n * allow_ip_sans default true — false on 5 of the 8 roles\n * allow_localhost default true — false on 6 of the 8\n * allow_wildcard_certificates default true — false on 6 of the 8\n * cn_validations default [\"email\",\"hostname\"] — [\"hostname\"] on 5 of the 8\n *\n * A resource that managed only the eleven fields the brief named would therefore, on any\n * unrelated TTL edit, silently re-open wildcards and localhost on six production roles.\n * That is why those four are props in pki-role-form.ts though they were not in the brief,\n * and why their default there is the CLOSED value rather than OpenBao's open one.\n *\n * ★ NARROWING IS THE FAIL-SAFE DIRECTION. A default tighter than OpenBao's can only refuse a\n * certificate that should have been issued — loud, and cured by declaring the field. A\n * default looser than OpenBao's issues one that should have been refused, in silence.\n *\n * ⚠️ WHAT WAS NOT MEASURED. Only reads were run against the live engine; no `bao write`\n * happened, so nothing below is a verified round-trip. Two consequences carried into the\n * form file: every live role has `ext_key_usage: []`, so the stored casing of a non-empty\n * list was never observed (the compare folds case because OpenBao matches these\n * case-insensitively at issuance); and every live role has exactly ONE allowed domain, so\n * whether OpenBao preserves list order was never observed either (the compare sorts,\n * because allowed_domains is a set). Both choices can only mask a cosmetic difference,\n * never a policy one — but neither is a measurement.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — see the delete comment below. Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport {\n type BaoPkiRoleAttributes,\n type BaoPkiRoleProps,\n attributesOf,\n matches,\n problems,\n rolePath,\n writeBody,\n} from './pki-role-form.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoPkiRoleAttributes, BaoPkiRoleProps };\n\nexport interface BaoPkiRole extends Resource<\n 'Bao.PkiRole',\n BaoPkiRoleProps,\n BaoPkiRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoPkiRole = Resource<BaoPkiRole>('Bao.PkiRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the engine stores `role/<name>` verbatim (builtin/logical/pki/path_roles.go:963). */\nconst IDENTITY = roleIdentity<BaoPkiRoleAttributes>(\n 'Bao.PkiRole',\n (mount, name) => rolePath({ mount, name }),\n 'pki',\n);\n\nconst readRole = (props: BaoPkiRoleProps) =>\n Effect.gen(function* () {\n const live = yield* baoRead(rolePath(props));\n if (live === undefined) return undefined;\n return attributesOf(props, live);\n });\n\nexport const BaoPkiRoleProvider = () =>\n Provider.effect(\n BaoPkiRole,\n Effect.succeed(\n BaoPkiRole.Provider.of({\n /**\n * ⛔ `bao list pki/roles` IS NOT A LIST OF THINGS THIS OWNS. All eight roles in the\n * live engine answer it, and every one of them predates this resource. Returning\n * them would invite Alchemy to adopt — and then delete — roles it never created.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(olds);\n const ours = Effect.sync(\n () => found !== undefined && problems(olds).length === 0 && matches(found, olds),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES A DIGEST OF THE LIVE ROLE, NOT THE STORED ONE. The attributes fed to\n * `matches` are always freshly derived from a live read in this same operation, so\n * a role widened by hand in the OpenBao UI still reads as drift — which is the\n * whole reason the check-* gates exist. Comparing one digest rather than sixteen\n * fields is also what stops a field being added to props and quietly forgotten in\n * the comparison.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⚠️ A ROLE IS IDENTIFIED BY MOUNT **AND** NAME. Moving a declaration to another\n * engine is a different object under a different CA, never an in-place edit —\n * `replace`, so Alchemy creates the new one and retires the old. Judged before\n * `isResolved(news)`, and ⛔ a move onto a role that exists fails the plan\n * (rename-identity.ts).\n * ⛔ A RENAME WAS NOT CAUGHT UNTIL 2026-09-21 (REPLACE.md): only the mount was compared,\n * so a new `name` read nothing at the new path, planned `update`, wrote the new role,\n * and left the old one issuing certificates under no state record at all.\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n /**\n * ⚠️ A DECLARATION reconcile WOULD REFUSE MUST NEVER PLAN AS noop. An empty\n * allowedDomains, or a duration OpenBao cannot parse, can compare equal to a\n * live role already in that state — and a noop there hides the refusal behind a\n * clean plan until the next deploy. Route it to reconcile, which says why.\n * (The full list is `problems` in pki-role-form.ts.)\n */\n if (problems(news).length > 0) return { action: 'update' } as const;\n const live = yield* readRole(news);\n if (live === undefined) return { action: 'update' } as const;\n return matches(live, news)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n /**\n * ⛔ AN EMPTY allowedDomains IS A REFUSAL, NOT AN EMPTY ROLE. `allow_any_name` is\n * false on every live role, so a role with no allowed domains can issue NOTHING —\n * and an unresolved or mistyped prop reads exactly like an author who meant it.\n * policy.ts refuses an empty fragment directory for the same reason. The other\n * refusals — an unparseable duration, noStore with generateLease — are in `problems`.\n */\n const bad = problems(news);\n if (bad.length > 0) {\n return yield* Effect.die(new Error(`Bao.PkiRole ${path}: ${bad.join(' ')}`));\n }\n const live = yield* readRole(news);\n if (live !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.PkiRole ${path}`);\n if (live === undefined || !matches(live, news)) {\n yield* baoWrite('PUT', path, writeBody(news));\n }\n const after = yield* readRole(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(`Bao.PkiRole ${path}: write reported success but the role is absent.`),\n );\n }\n /**\n * ⛔ THE WRITE IS NOT TRUSTED, IT IS RE-READ AND RE-COMPARED. A write succeeds (2xx)\n * for a field it accepted but stored differently — the live worry being the\n * comma-joined list values in writeBody, whose splitting is documented for\n * allowed_domains and ext_key_usage but NOT for cn_validations. Without this\n * check a role could land with `cn_validations: [\"email,hostname\"]`, report\n * success, and then refuse every renewal at issuance time instead.\n */\n if (!matches(after, news)) {\n return yield* Effect.die(\n new Error(\n `Bao.PkiRole ${path}: wrote cleanly but the role read back different. ` +\n 'OpenBao stored something other than what was declared — inspect with ' +\n `\\`bao read ${path}\\` before retrying.`,\n ),\n );\n }\n return after;\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE CERTIFICATES IT ISSUED — they stay valid to\n * their own expiry, so this is quiet now and loud much later: every renewal through\n * the role fails once the current certificate runs out. MEASURED: the live roles\n * carry ttl 604800 to 31536000 seconds, so the fuse on `rpi5-otel-client` is a full\n * year. Idempotent as Alchemy requires — already gone is success — but retain is\n * the default for exactly this reason.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
61
61
|
"/**\n * Bao.PkiRole's canonical form — the managed field set, normalised so both sides of a diff are\n * byte-comparable. Split from pki-role-form.ts for the 250-line cap when six fields were added\n * (2026-09-21); the reasoning below moved with the code, unchanged.\n *\n * ★ THE SIX FIELDS ADDED 2026-09-21 — require_cn, enforce_hostnames, key_usage,\n * allowed_domains_template, no_store, generate_lease — WERE ALREADY BEING WRITTEN, just never\n * declared. The role write is a full replace (pki-role.ts), and openbao v2.6.2\n * builtin/logical/pki/path_roles.go pathRoleCreate (:1153-1196) builds each of them from\n * `data.Get`, i.e. its schema default when the request omits it. So every write this resource\n * ever made reset them — a hand-set `no_store` or a narrowed `key_usage` vanished behind a\n * green plan. Their defaults below are OpenBao's own (schema :560-575, :690-720, :800-845), so a\n * role this resource wrote reads back unchanged and plans `noop`.\n */\nimport { sha256 } from './digest.ts';\nimport { parseDuration, ttlSeconds } from './mount-form.ts';\nimport type { BaoPkiRoleProps } from './pki-role-form.ts';\n\n/**\n * The managed field set, normalised so both sides of a diff are byte-comparable.\n *\n * ⚠️ KEY ORDER IS THE DIGEST. The props side and the live side are both built by the single\n * canonical() literal below, so `JSON.stringify` emits the same key order for each. Two\n * hand-written object literals would drift apart and produce a forever-diff nobody could\n * read from the plan output.\n */\nexport interface BaoPkiRoleCanonical {\n allowBareDomains: boolean;\n allowGlobDomains: boolean;\n allowIpSans: boolean;\n allowLocalhost: boolean;\n allowSubdomains: boolean;\n allowWildcardCertificates: boolean;\n allowedDomains: readonly string[];\n allowedDomainsTemplate: boolean;\n clientFlag: boolean;\n cnValidations: readonly string[];\n enforceHostnames: boolean;\n extKeyUsage: readonly string[];\n generateLease: boolean;\n keyBits: number;\n keyType: string;\n keyUsage: readonly string[];\n /** ⚠️ `-1` means the duration prop did not parse — reconcile refuses rather than writing it. */\n maxTtlSeconds: number;\n noStore: boolean;\n requireCn: boolean;\n serverFlag: boolean;\n signatureBits: number;\n ttlSeconds: number;\n}\n\n/** ★ OpenBao's own `key_usage` default (path_roles.go:697-698) — what an omitted field becomes. */\nexport const DEFAULT_KEY_USAGE: readonly string[] = [\n 'DigitalSignature',\n 'KeyAgreement',\n 'KeyEncipherment',\n];\n\nconst sorted = (values: readonly string[]) => [...values].sort();\n\n/** ⚠️ Case-folded for the COMPARE only; the write keeps the author's casing.\n * Why, and what was never measured, is in the pki-role.ts header. `key_usage` gets the same\n * treatment as `ext_key_usage`, for the same reason — REASONED, not measured. */\nconst foldedUsages = (values: readonly string[]) => sorted(values.map((v) => v.toLowerCase()));\n\n/** The one literal that fixes key order for both sides of the diff. */\nconst canonical = (input: BaoPkiRoleCanonical): BaoPkiRoleCanonical => ({\n allowBareDomains: input.allowBareDomains,\n allowGlobDomains: input.allowGlobDomains,\n allowIpSans: input.allowIpSans,\n allowLocalhost: input.allowLocalhost,\n allowSubdomains: input.allowSubdomains,\n allowWildcardCertificates: input.allowWildcardCertificates,\n allowedDomains: sorted(input.allowedDomains),\n allowedDomainsTemplate: input.allowedDomainsTemplate,\n clientFlag: input.clientFlag,\n cnValidations: sorted(input.cnValidations),\n enforceHostnames: input.enforceHostnames,\n extKeyUsage: foldedUsages(input.extKeyUsage),\n generateLease: input.generateLease,\n keyBits: input.keyBits,\n keyType: input.keyType,\n keyUsage: foldedUsages(input.keyUsage),\n maxTtlSeconds: input.maxTtlSeconds,\n noStore: input.noStore,\n requireCn: input.requireCn,\n serverFlag: input.serverFlag,\n signatureBits: input.signatureBits,\n ttlSeconds: input.ttlSeconds,\n});\n\nconst seconds = (text: string) => parseDuration(text) ?? -1;\n\nexport const canonicalFromProps = (props: BaoPkiRoleProps): BaoPkiRoleCanonical =>\n canonical({\n allowBareDomains: props.allowBareDomains ?? false,\n allowGlobDomains: props.allowGlobDomains ?? false,\n allowIpSans: props.allowIpSans ?? false,\n allowLocalhost: props.allowLocalhost ?? false,\n allowSubdomains: props.allowSubdomains ?? false,\n allowWildcardCertificates: props.allowWildcardCertificates ?? false,\n allowedDomains: props.allowedDomains,\n allowedDomainsTemplate: props.allowedDomainsTemplate ?? false,\n clientFlag: props.clientFlag ?? true,\n cnValidations: props.cnValidations ?? ['hostname'],\n enforceHostnames: props.enforceHostnames ?? true,\n extKeyUsage: props.extKeyUsage ?? [],\n generateLease: props.generateLease ?? false,\n keyBits: props.keyBits ?? 0,\n keyType: props.keyType ?? 'rsa',\n keyUsage: props.keyUsage ?? DEFAULT_KEY_USAGE,\n maxTtlSeconds: seconds(props.maxTtl),\n noStore: props.noStore ?? false,\n requireCn: props.requireCn ?? true,\n serverFlag: props.serverFlag ?? true,\n signatureBits: props.signatureBits ?? 0,\n ttlSeconds: seconds(props.ttl),\n });\n\nconst bool = (value: unknown, fallback: boolean) => (typeof value === 'boolean' ? value : fallback);\n\nconst int = (value: unknown, fallback: number) =>\n typeof value === 'number' && Number.isFinite(value) ? value : fallback;\n\nconst list = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\nconst str = (value: unknown, fallback: string) => (typeof value === 'string' ? value : fallback);\n\n/**\n * ⚠️ AN ABSENT NEW FIELD READS AS ITS ZERO VALUE, NOT ITS SCHEMA DEFAULT. A role read always carries\n * the six new fields (ToResponseData, path_roles.go:1720-1780; `generate_lease` only when set,\n * and getRole upgrades a missing one to false at :1034), so the fallback only answers a body\n * that is not OpenBao's — and then \"false\"/\"none\" reads as drift rather than a false noop.\n */\nexport const canonicalFromLive = (live: Record<string, unknown>): BaoPkiRoleCanonical =>\n canonical({\n allowBareDomains: bool(live['allow_bare_domains'], false),\n allowGlobDomains: bool(live['allow_glob_domains'], false),\n allowIpSans: bool(live['allow_ip_sans'], false),\n allowLocalhost: bool(live['allow_localhost'], false),\n allowSubdomains: bool(live['allow_subdomains'], false),\n allowWildcardCertificates: bool(live['allow_wildcard_certificates'], false),\n allowedDomains: list(live['allowed_domains']),\n allowedDomainsTemplate: bool(live['allowed_domains_template'], false),\n clientFlag: bool(live['client_flag'], true),\n cnValidations: list(live['cn_validations']),\n enforceHostnames: bool(live['enforce_hostnames'], false),\n extKeyUsage: list(live['ext_key_usage']),\n generateLease: bool(live['generate_lease'], false),\n keyBits: int(live['key_bits'], 0),\n keyType: str(live['key_type'], 'rsa'),\n keyUsage: list(live['key_usage']),\n maxTtlSeconds: ttlSeconds(live['max_ttl']) ?? -1,\n noStore: bool(live['no_store'], false),\n requireCn: bool(live['require_cn'], false),\n serverFlag: bool(live['server_flag'], true),\n signatureBits: int(live['signature_bits'], 0),\n ttlSeconds: ttlSeconds(live['ttl']) ?? -1,\n });\n\nexport const digestOf = (form: BaoPkiRoleCanonical): string => sha256(JSON.stringify(form));\n",
|
|
62
62
|
"import { mountPath, parseDuration } from './mount-form.ts';\nimport {\n type BaoPkiRoleCanonical,\n DEFAULT_KEY_USAGE,\n canonicalFromLive,\n canonicalFromProps,\n digestOf,\n} from './pki-role-canonical.ts';\n\nexport type { BaoPkiRoleCanonical };\n\n/** ★ MEASURED: the OpenAPI enum for `key_type` is exactly these four, lowercase. */\nexport type BaoPkiKeyType = 'any' | 'ec' | 'ed25519' | 'rsa';\n\n/** ★ MEASURED: live roles carry `[\"hostname\"]` or the default `[\"email\",\"hostname\"]`. */\nexport type BaoPkiCnValidation = 'disabled' | 'email' | 'hostname';\n\nexport interface BaoPkiRoleProps {\n /** Role name, as `pki/roles/{name}` takes it. */\n name: string;\n /** Mount holding the engine. Defaults to `pki` — the only PKI mount live today. */\n mount?: string;\n /**\n * Domains this role may issue for.\n *\n * ⛔ AN EMPTY LIST IS REFUSED IN reconcile, NOT WRITTEN. With `allow_any_name` false — the\n * default, and what all eight live roles use — a role with no allowed domains can issue\n * nothing, so a mistyped or unresolved prop would quietly brick every renewal under it.\n */\n allowedDomains: readonly string[];\n /** Permit `foo.<allowed domain>`. Default false. */\n allowSubdomains?: boolean;\n /** Permit the allowed domain itself as the CN. Default false. */\n allowBareDomains?: boolean;\n /** Treat `*` inside an allowed domain as a glob. Default false. */\n allowGlobDomains?: boolean;\n /**\n * Default certificate lifetime, as a duration string (`720h`).\n *\n * ⚠️ WRITTEN AS A DURATION, READ BACK AS SECONDS — `ttl` and `max_ttl` both carry\n * `format: seconds` in the OpenAPI and come back as integers (`2592000`). The prop\n * string reaches `bao write` verbatim; the compare happens in seconds. See canonical().\n */\n ttl: string;\n /** Ceiling on a requested lifetime, as a duration string (`8760h`). */\n maxTtl: string;\n /** Key algorithm. Default `rsa` — OpenBao's own default. */\n keyType?: BaoPkiKeyType;\n /** Key size; `0` means \"engine default for keyType\". rsa 2048/3072/4096, ec 224/256/384/521. */\n keyBits?: number;\n /** Flag certificates for TLS server auth. ⚠️ OpenBao defaults this TRUE. */\n serverFlag?: boolean;\n /** Flag certificates for TLS client auth. ⚠️ OpenBao defaults this TRUE. */\n clientFlag?: boolean;\n /** Extended key usages minus the `ExtKeyUsage` prefix (`ServerAuth`). Empty on all 8 live roles. */\n extKeyUsage?: readonly string[];\n /** Permit IP SANs. ⚠️ OpenBao defaults TRUE; this resource defaults FALSE — see pki-role.ts. */\n allowIpSans?: boolean;\n /** Permit `localhost`/`localdomain` CNs. ⚠️ OpenBao TRUE, this resource FALSE. */\n allowLocalhost?: boolean;\n /** Permit wildcard CNs. ⚠️ OpenBao TRUE, this resource FALSE. */\n allowWildcardCertificates?: boolean;\n /** CN validations to run. ⚠️ OpenBao `[\"email\",\"hostname\"]`, this resource `[\"hostname\"]`. */\n cnValidations?: readonly BaoPkiCnValidation[];\n /** Signature hash bits; `0` auto-detects from key length. One live role pins 256. */\n signatureBits?: number;\n /**\n * ★ THE SIX BELOW (added 2026-09-21) default to OpenBao's OWN values, not closed ones — a role this\n * resource wrote before they were props carries exactly those, so it still plans `noop`. The\n * write already sent them implicitly; see the header of pki-role-canonical.ts.\n */\n /** A request must carry a common_name. Default true. */\n requireCn?: boolean;\n /** Only valid host names in the CN and DNS SANs. Default true. */\n enforceHostnames?: boolean;\n /**\n * Key usages minus the `KeyUsage` prefix. Default `DigitalSignature, KeyAgreement,\n * KeyEncipherment`. ⚠️ `[]` is a real value — it removes every key usage — and is sent as such.\n */\n keyUsage?: readonly string[];\n /** Allowed domains may use identity templates (`{{identity.entity.name}}`). Default false. */\n allowedDomainsTemplate?: boolean;\n /**\n * Do not store issued certificates. Default false. ⛔ They can then be neither listed nor\n * revoked. ⚠️ Implies `generateLease: false`; declaring both true is refused (see problems).\n */\n noStore?: boolean;\n /** Attach an OpenBao lease to every issued certificate. Default false — leases slow startup. */\n generateLease?: boolean;\n}\n\nexport interface BaoPkiRoleAttributes extends BaoPkiRoleCanonical {\n name: string;\n mount: string;\n /** Human rendering of ttlSeconds — the compare uses the seconds, this is for the plan. */\n ttl: string;\n maxTtl: string;\n /** SHA-256 of the canonical form — safe to persist; see policy.ts. */\n digest: string;\n}\n\n/** ⚠️ Same rendering auth-role-form.ts uses, so `720h` and `2592000` read alike in a plan. */\nconst ttlText = (value: number) => {\n if (value < 0) return '';\n if (value !== 0 && value % 86400 === 0) return `${String(value / 86400)}d`;\n if (value !== 0 && value % 3600 === 0) return `${String(value / 3600)}h`;\n if (value !== 0 && value % 60 === 0) return `${String(value / 60)}m`;\n return `${String(value)}s`;\n};\n\nexport const rolePath = (props: { name: string; mount?: string }) =>\n `${mountPath(props.mount ?? 'pki')}/roles/${props.name}`;\n\nexport const attributesOf = (\n props: BaoPkiRoleProps,\n live: Record<string, unknown>,\n): BaoPkiRoleAttributes => {\n const form = canonicalFromLive(live);\n return {\n ...form,\n name: props.name,\n mount: mountPath(props.mount ?? 'pki'),\n ttl: ttlText(form.ttlSeconds),\n maxTtl: ttlText(form.maxTtlSeconds),\n digest: digestOf(form),\n };\n};\n\n/**\n * ⚠️ ARRAYS GO OVER AS COMMA-JOINED STRINGS. `allowed_domains` and `ext_key_usage` are\n * documented as \"a comma-separated string or list\"; `cn_validations` is not, so its\n * splitting is REASONED, not measured. reconcile re-reads and re-compares after every\n * write, so a value that arrived unsplit fails loudly instead of landing wrong.\n *\n * ⚠️ TTLs GO OVER AS THE AUTHOR'S OWN DURATION STRING, never as a re-rendered one — so this\n * never has to know whether OpenBao's parser accepts the `d` suffix ttlText() produces for\n * display. Rendering is for humans; the wire only ever sees what was declared.\n *\n * ★ `ext_key_usage` is OMITTED when empty rather than sent as `ext_key_usage=`. The write\n * replaces the whole role, so an absent field already lands on the `[]` default, and\n * omitting sidesteps how an empty value would be encoded.\n * ⚠️ `key_usage` CANNOT BE OMITTED THAT WAY — its default is NOT empty — so it is always sent, and\n * an empty declaration goes over as `\"\"`. That encoding is now READ, not guessed: for a\n * comma-string-slice field, go-secure-stdlib parseutil.ParseCommaStringSlice (:389-392)\n * answers `\"\"` with an empty list.\n *\n * ★ THE BODY FOR `PUT <mount>/roles/<name>`, ALL STRINGS — the same `k=v` pairs `bao write` sent.\n */\nexport const writeBody = (props: BaoPkiRoleProps): Record<string, string> => {\n const form = canonicalFromProps(props);\n const body: Record<string, string> = {\n allowed_domains: form.allowedDomains.join(','),\n allow_bare_domains: String(form.allowBareDomains),\n allow_glob_domains: String(form.allowGlobDomains),\n allow_subdomains: String(form.allowSubdomains),\n allow_ip_sans: String(form.allowIpSans),\n allow_localhost: String(form.allowLocalhost),\n allow_wildcard_certificates: String(form.allowWildcardCertificates),\n cn_validations: form.cnValidations.join(','),\n client_flag: String(form.clientFlag),\n server_flag: String(form.serverFlag),\n key_type: form.keyType,\n key_bits: String(form.keyBits),\n signature_bits: String(form.signatureBits),\n ttl: props.ttl,\n max_ttl: props.maxTtl,\n require_cn: String(form.requireCn),\n enforce_hostnames: String(form.enforceHostnames),\n key_usage: (props.keyUsage ?? DEFAULT_KEY_USAGE).join(','),\n allowed_domains_template: String(form.allowedDomainsTemplate),\n no_store: String(form.noStore),\n generate_lease: String(form.generateLease),\n };\n const usages = props.extKeyUsage ?? [];\n if (usages.length > 0) body['ext_key_usage'] = usages.join(',');\n return body;\n};\n\n/** True when live already matches the declaration on every managed field. */\nexport const matches = (attributes: BaoPkiRoleAttributes, props: BaoPkiRoleProps) =>\n attributes.digest === digestOf(canonicalFromProps(props));\n\n/**\n * Declarations reconcile must refuse rather than write. diff routes any of these to `update` so the\n * refusal is seen on the next deploy, never hidden behind a `noop`.\n *\n * ⚠️ `noStore` WITH `generateLease` IS NOT AN ERROR ON THE SERVER — pathRoleCreate stores\n * generate_lease false and adds a warning (path_roles.go:1250-1256) — so the role would read back\n * different from its declaration and plan `update` forever. Refused here instead.\n */\nexport const problems = (props: BaoPkiRoleProps): readonly string[] => {\n const found: string[] = [];\n if (props.allowedDomains.length === 0) {\n found.push(\n 'allowedDomains is empty. With allow_any_name false that role can issue no certificate at all.',\n );\n }\n const bad = [\n ['ttl', props.ttl],\n ['maxTtl', props.maxTtl],\n ].filter(([, text]) => parseDuration(text ?? '') === undefined);\n if (bad.length > 0) {\n found.push(\n `${bad.map(([k, v]) => `${k ?? ''}=${v ?? ''}`).join(', ')} is not a duration OpenBao ` +\n 'parses (expect 30m, 720h, 8760h or 0).',\n );\n }\n if (props.noStore === true && props.generateLease === true) {\n found.push(\n 'noStore and generateLease are both true; OpenBao keeps no_store and drops the lease.',\n );\n }\n return found;\n};\n",
|
|
63
|
-
"/**\n * An OpenBao plugin catalog entry — `sys/plugins/catalog/<type>/<name>`: which binary in\n * plugin_directory, at which SHA-256, may run as a plugin of that name. METADATA ONLY.\n *\n * ⛔ IT REGISTERS; IT DOES NOT DELIVER. The binary must already sit in plugin_directory. Copying it\n * there is a host step.\n * ⚠️ A MISSING FILE FAILS THE WRITE; A WRONG SHA-256 DOES NOT. setInternal (plugin_catalog.go\n * :1150-1230) resolves the path first, which fails loudly, but the run that would notice a\n * checksum mismatch is only the version probe, and that is best-effort: it logs a warning and\n * stores the entry anyway. The mismatch then surfaces when a mount first starts the plugin.\n * ⛔ NO `env` PROP, AND THERE MUST NEVER BE ONE — see registerBody in plugin-form.ts. Alchemy keeps\n * props and attributes UNENCRYPTED in its state store (policy.ts has the reasoning).\n * ⚠️ A NEW SHA-256 DOES NOT RESTART A RUNNING PLUGIN. setInternal writes the catalog entry and\n * reloads nothing, so mounts keep the old process until `sys/plugins/reload/backend` or a\n * restart. Reloading is an operator step, not this resource.\n *\n * ★ `defaultRemovalPolicy: 'retain'`. Deregistering does not check whether a mount still runs the\n * plugin (the ⛔ on deregisterPlugin in plugin-wire.ts), so a destroy would break that mount at its\n * next start. Retain also means a version bump — a REPLACE, below — leaves the old version\n * registered for mounts pinned to it; prune it by hand once nothing uses it.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
63
|
+
"/**\n * An OpenBao plugin catalog entry — `sys/plugins/catalog/<type>/<name>`: which binary in\n * plugin_directory, at which SHA-256, may run as a plugin of that name. METADATA ONLY.\n *\n * ⛔ IT REGISTERS; IT DOES NOT DELIVER. The binary must already sit in plugin_directory. Copying it\n * there is a host step.\n * ⚠️ A MISSING FILE FAILS THE WRITE; A WRONG SHA-256 DOES NOT. setInternal (plugin_catalog.go\n * :1150-1230) resolves the path first, which fails loudly, but the run that would notice a\n * checksum mismatch is only the version probe, and that is best-effort: it logs a warning and\n * stores the entry anyway. The mismatch then surfaces when a mount first starts the plugin.\n * ⛔ NO `env` PROP, AND THERE MUST NEVER BE ONE — see registerBody in plugin-form.ts. Alchemy keeps\n * props and attributes UNENCRYPTED in its state store (policy.ts has the reasoning).\n * ⚠️ A NEW SHA-256 DOES NOT RESTART A RUNNING PLUGIN. setInternal writes the catalog entry and\n * reloads nothing, so mounts keep the old process until `sys/plugins/reload/backend` or a\n * restart. Reloading is an operator step, not this resource.\n *\n * ★ `defaultRemovalPolicy: 'retain'`. Deregistering does not check whether a mount still runs the\n * plugin (the ⛔ on deregisterPlugin in plugin-wire.ts), so a destroy would break that mount at its\n * next start. Retain also means a version bump — a REPLACE, below — leaves the old version\n * registered for mounts pinned to it; prune it by hand once nothing uses it.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { claimFor } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport {\n type BaoPluginAttributes,\n type BaoPluginProps,\n type BaoPluginType,\n matches,\n problems,\n resolve,\n versionedPath,\n} from './plugin-form.ts';\nimport { readEntry, reconcilePlugin } from './plugin-reconcile.ts';\nimport { deregisterPlugin } from './plugin-wire.ts';\nimport { declaredOr, declaredString } from './rename.ts';\nimport { type Identity, guardRename, judgeRename } from './rename-identity.ts';\n\nexport type { BaoPluginAttributes, BaoPluginProps, BaoPluginType } from './plugin-form.ts';\n\nexport interface BaoPlugin extends Resource<\n 'Bao.Plugin',\n BaoPluginProps,\n BaoPluginAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoPlugin = Resource<BaoPlugin>('Bao.Plugin', {\n defaultRemovalPolicy: 'retain',\n});\n\n/**\n * ⛔ NAME, TYPE AND VERSION ARE THE CATALOG KEY, so the identity is the versioned path a read and a\n * delete address. Exact: the catalog stores `<type>/<name>/<version>` as given, and the version\n * is already canonical (`problems`). ⚠️ An unversioned name that is a builtin reads back as\n * present (plugin-wire.ts), so a move onto one fails the plan, as reconcile would refuse anyway.\n */\nconst IDENTITY: Identity<BaoPluginAttributes> = {\n declared: (props) => {\n const type = declaredString(props, 'type') as BaoPluginType | undefined;\n const name = declaredString(props, 'name');\n const version = declaredOr(props, 'version', '');\n if (type === undefined || name === undefined || version === undefined) return undefined;\n return versionedPath(type, name, version);\n },\n family: 'Bao.Plugin',\n recorded: (output) => versionedPath(output.type, output.name, output.version),\n};\n\nexport const BaoPluginProvider = () =>\n Provider.effect(\n BaoPlugin,\n Effect.succeed(\n BaoPlugin.Provider.of({\n /**\n * ⛔ THE CATALOG IS NOT A LIST OF THINGS THIS OWNS. It answers every builtin plugin and\n * every hand registration. Returning them would invite Alchemy to adopt — and then\n * deregister — plugins it never registered.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const form = resolve(olds);\n const found = yield* readEntry(form);\n const ours = Effect.sync(\n () =>\n found !== undefined && problems(form).length === 0 && matches(found.attributes, form),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);\n }),\n\n /** ⛔ IT COMPARES THE LIVE ENTRY, NOT THE STORED DIGEST — a hand re-register is drift. */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A NEW NAME, TYPE OR VERSION IS A DIFFERENT ENTRY, not an edit: `replace`, judged\n * before `isResolved(news)`. Writing the new key in place would leave the old\n * registration under a state record that no longer names it. ⛔ A move onto an entry\n * that is already registered fails the plan (rename-identity.ts).\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n const form = resolve(news);\n const found = yield* readEntry(form);\n if (found === undefined) return { action: 'update' } as const;\n return matches(found.attributes, form)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n /** The refusals — declarative, builtin, self-reported version — live in plugin-reconcile.ts. */\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n return yield* reconcilePlugin(news, claimFor({ fqn, instanceId, output }));\n }),\n\n /**\n * ⛔ READ THE ⛔ ON deregisterPlugin FIRST: nothing checks that a mount still runs this.\n * Idempotent as Alchemy requires — already gone is success on the server.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* deregisterPlugin(output.type, output.name, output.version);\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
64
64
|
"/**\n * The form half of Bao.Plugin: props, the paths, the register body, and the equality that decides\n * whether a plan says `noop`. Split from plugin.ts the way mount-form.ts is.\n *\n * ★ THE CATALOG API, READ FROM openbao v2.6.2 — the docs AND the server, because they disagree:\n * · docs/api/system/plugins-catalog.mdx — `POST sys/plugins/catalog/:type/:name` registers with\n * `sha256`, `command`, `args`, `env`, `version`, `oci`; `GET` and `DELETE` take `?version=`, which\n * is REQUIRED to read a plugin registered with one. All three need `sudo`.\n * · vault/logical_system.go:515-576 handlePluginCatalogRead — answers `name`, `args`, `command`\n * (relative to plugin_directory), `sha256`, `builtin`, `version`, `oci`, `declarative`. ⚠️ The\n * docs' sample shows sha256 as BASE64; the server writes `hex.EncodeToString` (:561). Hex wins.\n * · vault/logical_system.go:441-513 handlePluginCatalogUpdate, and :615-628 getVersion — the\n * version is canonicalised to `\"v\" + semver.String()` before it is stored.\n */\nimport { sha256 as digestOf } from './digest.ts';\n\nexport type BaoPluginType = 'auth' | 'database' | 'secret';\n\nexport interface BaoPluginProps {\n /** Catalog name — what a mount's `type` names, e.g. `openbao-plugin-secrets-cloudflare`. */\n name: string;\n /** Catalog type. `secret` for a secrets engine, `auth` for an auth method. */\n type: BaoPluginType;\n /** Hex SHA-256 of the binary already sitting in plugin_directory. Case is normalised. */\n sha256: string;\n /** The binary's file name inside plugin_directory — a bare name, no path, no arguments. */\n command: string;\n /**\n * Canonical semver with its `v`, e.g. `v0.1.2`. ⚠️ When the binary reports its own version,\n * declare EXACTLY that one: any other is refused at write (\"plugin version mismatch\",\n * plugin_catalog.go setInternal), and none at all is filed under the reported one — see the ⚠️\n * on SELF_REPORTED in plugin-reconcile.ts.\n */\n version?: string;\n /** Arguments, in order. ⛔ Never a secret: they land in Alchemy state and in every catalog read. */\n args?: readonly string[];\n}\n\n/** ⛔ NO SECRET HERE — names, a hash, a file name, arguments and a digest. */\nexport interface BaoPluginAttributes {\n name: string;\n type: BaoPluginType;\n /** The canonical version the catalog stored, `''` when unversioned. Delete needs it. */\n version: string;\n sha256: string;\n command: string;\n args: readonly string[];\n /** True when the catalog answered with OpenBao's own builtin rather than a registration. */\n builtin: boolean;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\n/** Every prop resolved to what the register call will store. */\nexport type BaoPluginForm = Required<BaoPluginProps>;\n\nexport const resolve = (props: BaoPluginProps): BaoPluginForm => ({\n args: props.args ?? [],\n command: props.command,\n name: props.name,\n sha256: props.sha256.toLowerCase(),\n type: props.type,\n version: props.version ?? '',\n});\n\n/**\n * ⛔ THE VERSION MUST ALREADY BE CANONICAL, OR THE PLAN NEVER GOES GREEN. The server stores\n * `\"v\" + semver.String()` (getVersion, :615-628), so `1.2.0`, `v1.2` and `v01.2.0` are all\n * written as `v1.2.0`, read back as `v1.2.0`, and compared unequal to the declaration forever.\n * Refusing anything but the canonical spelling is cheaper than reimplementing go-version.\n */\nconst CANONICAL_VERSION =\n /^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(-[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?(\\+[0-9A-Za-z-]+(\\.[0-9A-Za-z-]+)*)?$/;\n\n/** Everything wrong with the declaration, or `[]`. Checked before any request. */\nexport const problems = (form: BaoPluginForm): readonly string[] => {\n const found: string[] = [];\n // ⚠️ The route is `(?P<name>.+)` (logical_system_paths.go:1697), so a `/` would nest the storage\n // key; the server refuses `..` in a name (plugin_catalog.go Set).\n if (!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(form.name) || form.name.includes('..')) {\n found.push(`name ${JSON.stringify(form.name)} is not a plain catalog name`);\n }\n if (!/^[0-9a-f]{64}$/.test(form.sha256)) found.push('sha256 is not 64 hex characters');\n /**\n * ⛔ A BARE FILE NAME. The server splits `command` on spaces and keeps the rest as args\n * (handlePluginCatalogUpdate :487-495), and refuses a binary whose directory is not\n * plugin_directory itself (plugin_catalog.go setInternal, `symAbs != c.directory`) — so a\n * path or an argument here either fails the write or reads back as something else.\n */\n if (!/^[A-Za-z0-9][A-Za-z0-9._+-]*$/.test(form.command) || form.command.includes('..')) {\n found.push(`command ${JSON.stringify(form.command)} is not a bare file name`);\n }\n if (form.version !== '' && !CANONICAL_VERSION.test(form.version)) {\n found.push(`version ${JSON.stringify(form.version)} is not canonical semver like v1.2.0`);\n }\n // ⚠️ `+builtin` metadata is reserved; the server refuses it (handlePluginCatalogUpdate :462-464).\n if (/\\+builtin/.test(form.version)) found.push('version metadata `builtin` is reserved');\n return found;\n};\n\n/** `?version=` only when there is one — an unversioned plugin is read without it. */\nconst versionQuery = (version: string) =>\n version === '' ? '' : `?version=${encodeURIComponent(version)}`;\n\n/** `sys/plugins/catalog/<type>/<name>` — register addresses the plugin here. */\nexport const catalogPath = (type: BaoPluginType, name: string): string =>\n `sys/plugins/catalog/${type}/${name}`;\n\n/** Read and delete address one VERSION of the plugin. */\nexport const versionedPath = (type: BaoPluginType, name: string, version: string): string =>\n `${catalogPath(type, name)}${versionQuery(version)}`;\n\n/**\n * The register body — the fields RegisterPluginInput sends (api v2.6.0 sys_plugins.go:186-204),\n * which is what `bao plugin register` sends.\n *\n * ★ `type` IS LEFT OUT OF THE BODY ON PURPOSE. The Go client puts it there as a NUMBER (PluginType\n * has no MarshalJSON), and the route's `type` capture is what the handler reads. The path says it.\n * ⛔ NO `env`, EVER. The catalog read never returns env (handlePluginCatalogRead's data map has no\n * such key), so a declared env could not be diffed, and what env exists to carry into a plugin\n * process is exactly what must not sit in Alchemy's unencrypted state. ⚠️ The register call is a\n * FULL REPLACE (setInternal builds a fresh entry), so an env someone set by hand is dropped by\n * the next write — which only happens when a managed field has drifted.\n */\nexport const registerBody = (form: BaoPluginForm): Record<string, unknown> => ({\n command: form.command,\n sha256: form.sha256,\n ...(form.args.length > 0 ? { args: form.args } : {}),\n ...(form.version === '' ? {} : { version: form.version }),\n});\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\n/** ⚠️ `args` is a Go slice, so an entry stored without any can read back `null` — the same as `[]`. */\nconst list = (value: unknown): readonly string[] =>\n Array.isArray(value) ? value.filter((entry): entry is string => typeof entry === 'string') : [];\n\nexport const attributesOf = (\n form: BaoPluginForm,\n live: Record<string, unknown>,\n): BaoPluginAttributes => {\n const attrs = {\n name: form.name,\n type: form.type,\n version: text(live['version']),\n sha256: text(live['sha256']).toLowerCase(),\n command: text(live['command']),\n args: list(live['args']),\n builtin: live['builtin'] === true,\n };\n return { ...attrs, digest: digestOf(JSON.stringify(attrs)) };\n};\n\n/** ⚠️ ORDER MATTERS for args — they are an argv, not a set. */\nconst sameArgs = (want: readonly string[], have: readonly string[]) =>\n want.length === have.length && want.every((entry, index) => entry === have[index]);\n\n/** True when the catalog already holds exactly this registration. A builtin never matches. */\nexport const matches = (attributes: BaoPluginAttributes, form: BaoPluginForm): boolean =>\n !attributes.builtin &&\n attributes.version === form.version &&\n attributes.sha256 === form.sha256 &&\n attributes.command === form.command &&\n sameArgs(form.args, attributes.args);\n",
|
|
65
|
-
"/**\n * Bao.Plugin's read and reconcile, as plain effects — split from plugin.ts so the refusals below can\n * be run against a fake server rather than only reasoned about.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
66
|
-
"/**\n * The OpenBao calls Bao.Plugin makes — read one catalog entry, register, deregister. Split from\n * plugin.ts so the calls can be pinned against a fake server, the way mount-wire.ts is.\n *\n * ★ ENDPOINTS, READ FROM openbao v2.6.2 api/sys_plugins.go (the client `bao plugin` uses) and the\n * handlers in vault/logical_system.go:\n * read GET sys/plugins/catalog/<type>/<name>[?version=] (GetPlugin, :159-183)\n * register PUT sys/plugins/catalog/<type>/<name> (RegisterPlugin, :212-228)\n * deregister DELETE sys/plugins/catalog/<type>/<name>[?version=] (DeregisterPlugin, :249-261)\n * (api/sys_plugins.go diffed identical between v2.6.0 and v2.6.2.)\n * ⚠️ ALL THREE NEED `sudo` ON THE PATH, not just the verb (docs/api/system/plugins-catalog.mdx). A\n * token without it reads as 403, which is an error here, never \"absent\".\n */\nimport type * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/
|
|
67
|
-
"import { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport * as FileSystem from 'effect/FileSystem';\nimport * as Path from 'effect/Path';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { sha256 } from './digest.ts';\nimport { isEmptyAssembly } from './policy-assembly.ts';\nimport { judgePolicyRename, policyIdentity } from './policy-identity.ts';\nimport { deletePolicy, readPolicy, writePolicy } from './policy-wire.ts';\nimport { guardRename } from './rename-identity.ts';\n\n/**\n * An OpenBao ACL policy, assembled from the HCL fragments that declare it.\n *\n * ★ WHY THIS EXISTS. The estate already hand-rolled both halves of what Alchemy provides:\n * five `apply-*.sh`/`apply-*.py` scripts converge OpenBao, and separate `check-*.sh`\n * gates compare live to repo and refuse on drift. That is `reconcile` and `diff` written\n * twice, in two languages, with nothing recording what was applied — and one of those\n * gates blocked a deploy today because its own path had rotted.\n *\n * ⛔ THERE IS NO `Bao.Secret`, AND THERE MUST NEVER BE ONE. Alchemy persists attributes to\n * its state store and does NOT encrypt them: StateEncoding.ts unwraps `Redacted` to\n * plaintext under a marker key, and nothing under alchemy/src/State encrypts. This\n * estate's state store is the `alchemy` Postgres database, which a nightly job dumps\n * (it enumerates EVERY non-template database), copies to a backup guest, and PBS backs up\n * from there. A KV value here would exist in four places, none of them OpenBao.\n *\n * So this declares the SHAPE AROUND secrets. Every attribute it stores is a name, a\n * count, or a hash.\n *\n * ⛔ EVERY PRIMITIVE IS ALCHEMY'S OR EFFECT'S, NOT NODE'S. An earlier cut of this file used\n * `node:child_process` + `promisify(execFile)` and `node:fs/promises`, which is\n * hand-rolling inside a bun + Effect codebase: it loses the Scope, the typed\n * PlatformError, and the Layer that makes the provider testable without a real vault.\n * ★ `CommandExecutor.run` was tried first and blocked read/diff: Alchemy passes a session\n * to reconcile/delete but NOT to read/diff (Provider.ts:258-289), so the fix was Alchemy's\n * OWN Docker pattern — `ChildProcessSpawner` + `ChildProcess.make`, which needs only a\n * Scope (Docker.ts:476-553). ★ SINCE 2026-09-14 THE CALLS ARE OpenBao's HTTP API through\n * Effect's `HttpClient` (bao-http.ts), which needs no session either, so read/diff still work.\n * FileSystem and Path come from `effect/*` directly — in Effect 4 they moved into core.\n */\nexport interface BaoPolicyProps {\n /** Policy name, as `sys/policies/acl/<name>` takes it. */\n name: string;\n /**\n * Directory of `*.hcl` fragments.\n *\n * ⚠️ CONCATENATED IN SORTED ORDER, EACH FOLLOWED BY A NEWLINE — byte-identical to\n * apply-agent-policy.sh, which is what wrote the live policy. Any other joining makes\n * the first plan report an update on a policy nobody changed.\n */\n fragments: string;\n}\n\nexport interface BaoPolicyAttributes {\n /** Policy name. */\n name: string;\n /** SHA-256 of the assembled HCL. The whole diff, and safe to persist. */\n digest: string;\n /** `path \"...\"` grants — the number apply-agent-policy.sh prints. */\n grants: number;\n /** Fragment files that produced it, so a plan reads like the directory. */\n parts: number;\n}\n\nexport interface BaoPolicy extends Resource<\n 'Bao.Policy',\n BaoPolicyProps,\n BaoPolicyAttributes,\n never,\n HttpClient.HttpClient | FileSystem.FileSystem | Path.Path\n> {}\n\n/**\n * ⛔ `retain` — DELETING A POLICY REVOKES EVERY GRANT IT CARRIES, and this is the ONLY family in\n * this package with live instances, so it is the only one where the default could ever fire.\n *\n * 🔴 IT WAS THE ONLY FAMILY WITHOUT IT. Every sibling passes `{ defaultRemovalPolicy: 'retain' }`\n * — auth-role.ts:37, mount.ts:40, pki-role.ts, proxmox-role.ts, ssh-role.ts — each with a ★\n * explaining what deletion destroys. This file has the same warning on its own `delete` handler\n * and did not carry the option, which is the worst possible combination: the danger is\n * documented and the guard is missing.\n * ⛔ WHAT THAT MEANT IN PRACTICE, on 2026-09-13: ten live policies are named in a `const` array\n * in alchemy.run.ts. Removing a name from that array orphans the resource, and without\n * `retain` the next deploy calls `bao policy delete` on it — including the 86-line policy that\n * decides what the agent working in this repo can reach. A one-word edit, no plan line saying\n * \"revoke\", and the grants are gone. The array grew from four names to ten that same day,\n * which multiplied the blast radius of a mistake nobody had guarded against.\n *\n * ⚠️ `retain` DOES NOT WEAKEN `delete`, WHICH STAYS FULLY IMPLEMENTED. The engine skips it for an\n * orphaned resource; a caller that means it opts in with `.pipe(RemovalPolicy.destroy())`. This\n * is Terraform's `prevent_destroy`, not a stubbed operation — a delete that silently did nothing\n * would lie to whoever read the plan.\n * ⚠️ `retain` ALSO KEEPS THE OLD GENERATION OF A RENAME. A new `name` plans `replace`, and under\n * `retain` the old policy is left live and unmanaged (rename.ts, REPLACE.md).\n */\nexport const BaoPolicy = Resource<BaoPolicy>('Bao.Policy', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** `path \"...\"` grant count — the same number the apply script prints. */\nconst grantsOf = (hcl: string) => (hcl.match(/^path /gm) ?? []).length;\n\nconst attributesOf = (name: string, hcl: string, parts: number): BaoPolicyAttributes => ({\n name,\n digest: sha256(hcl),\n grants: grantsOf(hcl),\n parts,\n});\n\nexport const BaoPolicyProvider = () =>\n Provider.effect(\n BaoPolicy,\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n /** Assemble fragments exactly as apply-agent-policy.sh does. */\n const assemble = (dir: string) =>\n Effect.gen(function* () {\n const entries = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith('.hcl')).sort();\n let joined = '';\n for (const f of entries) joined += `${yield* fs.readFileString(path.join(dir, f))}\\n`;\n return { joined, parts: entries.length };\n });\n\n return BaoPolicy.Provider.of({\n /**\n * ⛔ `bao policy list` IS NOT A LIST OF THINGS THIS OWNS. Every policy in the\n * namespace answers, including ones written by hand years ago. Returning them\n * would invite Alchemy to adopt — and then delete — policies it never created.\n */\n list: () => Effect.succeed([]),\n\n // ★ Only undefined means absent (a typed 404); even a live empty policy occupies its name.\n // ⛔ With no attributes in state, a live policy is `Unowned` unless it is the one our own\n // interrupted create wrote: these fragments, byte for byte (ownership/probe.ts).\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const live = yield* readPolicy(olds.name);\n const found = live === undefined ? undefined : attributesOf(olds.name, live, 0);\n const ours = Effect.map(\n assemble(olds.fragments),\n (a) => sha256(a.joined) === found?.digest,\n );\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE POLICY, NOT THE STORED DIGEST. A policy edited in the\n * OpenBao UI is exactly the drift the check-* gates exist to catch, and a\n * provider that trusted its own state would report `noop` straight through it.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A RENAMED POLICY IS A `replace`, DECIDED BEFORE ANY OTHER READ (rename.ts). Until\n * 2026-09-21 this read the new name, found nothing and planned `update`: the new policy\n * was written and the old one kept every grant under no state record. Names compare as\n * OpenBao keys them (`policyKey`), so a change of case is the same policy, never a\n * replace. ⛔ A rename onto a policy that already exists fails the plan (`judgeMove`).\n * ⚠️ UNDER THE DEFAULT `retain` THE OLD POLICY STAYS LIVE, GRANTS AND ALL, for every token,\n * role and group that still names it. Under `destroy` they lose those grants at the\n * delete, so a role outside this graph that names the old policy must move in the same\n * PR (REPLACE.md).\n */\n const move = yield* judgePolicyRename(olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n // ⚠️ A prop can still be an unresolved Output or Config at plan time. Docker's\n // own providers guard with isResolved and skip rather than guess; a diff that\n // read a Config as a string would compare a placeholder to real HCL.\n if (!isResolved(news)) return undefined;\n const { joined } = yield* assemble(news.fragments);\n const live = yield* readPolicy(news.name);\n return live !== undefined && sha256(live) === sha256(joined)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const name = news.name;\n // ⛔ An `update` across a rename the diff could not see — refused before any write.\n yield* guardRename(policyIdentity, news, output);\n const { joined, parts } = yield* assemble(news.fragments);\n /**\n * ⛔ AN EMPTY ASSEMBLY IS A REFUSAL, NOT AN EMPTY POLICY. `bao policy write` with\n * no paths SILENTLY REVOKES every grant the policy carries, for every token\n * bound to it — and a mistyped or moved fragments directory reads exactly like\n * a policy with nothing in it. This estate lost a deploy today to a directory\n * that moved; it must not lose a vault to one.\n */\n // ⛔ No FILES was the first guard; no GRANT is the real one — see policy-assembly.ts.\n if (isEmptyAssembly(parts, joined))\n return yield* Effect.die(\n new Error(\n `Bao.Policy ${name}: the fragments under ${news.fragments} carry no path grant ` +\n `(${String(parts)} file(s)). Writing it would revoke every grant the policy carries.`,\n ),\n );\n /**\n * ⛔ ADOPTING A POLICY THAT ALREADY MATCHES MUST NOT REWRITE IT. Alchemy's `adopted`\n * action is NOT a read — Apply.ts routes it down the same branch as `update` and calls\n * reconcile — so the first deploy after declaring the four policies this estate\n * already has would have run `bao policy write` over all four. Byte-identical in the\n * happy case, and a SILENT REWRITE OF LIVE GRANTS the moment the repo fragments have\n * drifted from what is deployed.\n *\n * ★ THE GUARD IS THE SAME EXPRESSION `diff` USES, deliberately: one definition of\n * \"settled\" for this resource, so the plan and the write can never disagree. The\n * sibling PVE provider does exactly this in pveOperations.reconcile.\n */\n const current = yield* readPolicy(name);\n if (current !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.Policy ${name}`);\n if (current !== undefined && sha256(current) === sha256(joined)) {\n return attributesOf(name, joined, parts);\n }\n // ⚠️ In the request body, never on argv — see `writePolicy` for why the temp file went.\n yield* writePolicy(name, joined);\n return attributesOf(name, joined, parts);\n }),\n\n /**\n * ⛔ DELETING A POLICY REVOKES EVERY GRANT IT CARRIES. Idempotent as Alchemy\n * requires — already gone is success — but this is the one operation with teeth.\n */\n delete: Effect.fn(function* ({ output }) {\n /**\n * ⛔ A REFUSED DELETE FAILS. This is \"the one operation with teeth\" the note above\n * names, and it used to run through the read helper, which discarded the exit code —\n * so a REFUSED policy delete reported success and the row left Alchemy's state while\n * every grant it carried stayed live. Idempotence is preserved: a 404 is still\n * success, and a 403 is not (bao-status.ts).\n */\n yield* deletePolicy(output.name);\n return undefined;\n }),\n });\n }).pipe(Effect.map(provingResumes)),\n );\n",
|
|
65
|
+
"/**\n * Bao.Plugin's read and reconcile, as plain effects — split from plugin.ts so the refusals below can\n * be run against a fake server rather than only reasoned about.\n */\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport type { Claim } from '../ownership/adopt.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n type BaoPluginAttributes,\n type BaoPluginForm,\n type BaoPluginProps,\n attributesOf,\n matches,\n problems,\n resolve,\n versionedPath,\n} from './plugin-form.ts';\nimport { readPluginData, registerPlugin } from './plugin-wire.ts';\n\ntype Entry = { readonly attributes: BaoPluginAttributes; readonly live: Record<string, unknown> };\n\n/** Live entry, plus the raw body — reconcile needs the raw half for `oci` and `declarative`. */\nexport const readEntry = (\n form: BaoPluginForm,\n): Effect.Effect<Entry | undefined, BaoError, HttpClient.HttpClient> =>\n Effect.map(readPluginData(form), (live) =>\n live === undefined ? undefined : { attributes: attributesOf(form, live), live },\n );\n\nconst refuse = (form: BaoPluginForm, message: string) =>\n Effect.die(\n new Error(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}: ${message}`),\n );\n\n/**\n * ⚠️ AN UNVERSIONED REGISTRATION OF A BINARY THAT REPORTS ITS OWN VERSION IS FILED UNDER THAT\n * VERSION. setInternal (plugin_catalog.go:1222-1228) takes the self-reported version when the\n * request names none, and the storage key carries it — so the unversioned read that follows finds\n * nothing, or finds an OLDER genuinely-unversioned entry. The Cloudflare engine reports one\n * (`framework.Backend.RunningVersion`). REASONED FROM SOURCE, not measured against a server.\n * ⚠️ THE WRITE HAS ALREADY LANDED when this fires, so the catalog holds a registration no state\n * record names. Declaring the reported version and deploying once with `--adopt` adopts it (same\n * sha256 and command, so reconcile matches and writes nothing); declaring a DIFFERENT version is\n * refused by the server itself (setInternal :1219-1221, \"plugin version mismatch\").\n * ⚠️ `--adopt`, NOT A SILENT RESUME (2026-09-21): the row this create left names the UNVERSIONED\n * entry, so it cannot prove the versioned one ours (docs/ownership.md).\n */\nconst SELF_REPORTED =\n 'the write succeeded but the read-back does not match. If the binary reports its own version, ' +\n 'OpenBao filed the registration under it (plugin_catalog.go setInternal) — declare `version` ' +\n 'as exactly the version the binary reports, and deploy once with --adopt: that adopts the ' +\n 'entry this write just made.';\n\n/**\n * Register when the live entry differs, then prove it by reading back. Dies on a refusal.\n * ⛔ `claim` (the provider passes it): a create never takes over an entry already registered.\n */\nexport const reconcilePlugin = (\n props: BaoPluginProps,\n claim?: Claim,\n): Effect.Effect<BaoPluginAttributes, BaoError, HttpClient.HttpClient> =>\n Effect.gen(function* () {\n const form = resolve(props);\n const bad = problems(form);\n if (bad.length > 0) return yield* refuse(form, bad.join('; '));\n\n const found = yield* readEntry(form);\n if (found !== undefined && claim !== undefined) {\n yield* claim(`Bao.Plugin ${versionedPath(form.type, form.name, form.version)}`);\n }\n if (found !== undefined && !matches(found.attributes, form)) {\n /**\n * ⛔ A DECLARATIVE OR OCI ENTRY BELONGS TO THE SERVER'S CONFIG FILE (`plugin` stanzas with\n * plugin_auto_register), which re-registers it on every plugin reload. An API write turns\n * it non-declarative, and the next reload then REFUSES the config entry: \"conflicts with\n * existing non-declarative plugin\" (plugin_catalog.go:333-336).\n */\n if (found.live['declarative'] === true || found.live['oci'] === true) {\n return yield* refuse(\n form,\n 'the live entry is declarative/OCI; manage it in server config.',\n );\n }\n /**\n * ⛔ AN UNVERSIONED WRITE OVER A BUILTIN SHADOWS IT FOR EVERY MOUNT OF THAT TYPE. The catalog\n * answered with OpenBao's own builtin (`builtin: true`), and get() returns an external entry\n * before it ever looks at builtins (plugin_catalog.go:982-1036). Register a versioned plugin\n * instead, which leaves the builtin where it is.\n */\n if (found.attributes.builtin) {\n return yield* refuse(form, 'this name is a builtin; an unversioned write would shadow it.');\n }\n }\n if (found === undefined || !matches(found.attributes, form)) yield* registerPlugin(form);\n\n // ⚠️ RE-READ AND COMPARE, never echo the declaration — see SELF_REPORTED above.\n const after = yield* readEntry(form);\n if (after === undefined || !matches(after.attributes, form)) {\n return yield* refuse(form, SELF_REPORTED);\n }\n return after.attributes;\n });\n",
|
|
66
|
+
"/**\n * The OpenBao calls Bao.Plugin makes — read one catalog entry, register, deregister. Split from\n * plugin.ts so the calls can be pinned against a fake server, the way mount-wire.ts is.\n *\n * ★ ENDPOINTS, READ FROM openbao v2.6.2 api/sys_plugins.go (the client `bao plugin` uses) and the\n * handlers in vault/logical_system.go:\n * read GET sys/plugins/catalog/<type>/<name>[?version=] (GetPlugin, :159-183)\n * register PUT sys/plugins/catalog/<type>/<name> (RegisterPlugin, :212-228)\n * deregister DELETE sys/plugins/catalog/<type>/<name>[?version=] (DeregisterPlugin, :249-261)\n * (api/sys_plugins.go diffed identical between v2.6.0 and v2.6.2.)\n * ⚠️ ALL THREE NEED `sudo` ON THE PATH, not just the verb (docs/api/system/plugins-catalog.mdx). A\n * token without it reads as 403, which is an error here, never \"absent\".\n */\nimport type * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport type { BaoError } from './bao-status.ts';\nimport {\n type BaoPluginForm,\n type BaoPluginType,\n catalogPath,\n registerBody,\n versionedPath,\n} from './plugin-form.ts';\n\n/**\n * One catalog entry, or undefined when the catalog has none at that name, type and version.\n *\n * ★ UNLIKE A MOUNT, A MISSING PLUGIN REALLY IS A 404. handlePluginCatalogRead returns `nil, nil` when\n * the catalog lookup finds nothing (vault/logical_system.go:545-547), and RespondErrorCommon turns\n * a nil READ response into 404 (sdk v2.6.2 logical/response_util.go:23-26). No second question is\n * needed, unlike the mount-table check in mount-wire.ts.\n * ⚠️ A BUILTIN ANSWERS TOO. With no external registration at an unversioned name, the catalog falls\n * through to OpenBao's own builtin of that name and type (plugin_catalog.go get, :1016-1036), which\n * reads back with `builtin: true` — present, but not a registration. plugin.ts decides what that\n * means.\n */\nexport const readPluginData = (\n form: BaoPluginForm,\n): Effect.Effect<Record<string, unknown> | undefined, BaoError, HttpClient.HttpClient> =>\n baoRead(versionedPath(form.type, form.name, form.version));\n\nexport const registerPlugin = (\n form: BaoPluginForm,\n): Effect.Effect<void, BaoError, HttpClient.HttpClient> =>\n baoWrite('PUT', catalogPath(form.type, form.name), registerBody(form));\n\n/**\n * ★ IDEMPOTENT ON THE SERVER. deleteInternal deletes the storage key whether or not it exists\n * (plugin_catalog.go:1272-1284) and the handler answers with no body, so a retried delete succeeds.\n * ⚠️ BUT A MISSING TYPED KEY FALLS BACK TO THE BARE NAME. When `<type>/<name>[/<version>]` is not\n * in storage, the same function deletes the key `<name>` instead — where registrations made\n * before plugin types existed live, whatever their type. A fresh 2.x vault has none; one\n * migrated from an old Vault may. REASONED FROM SOURCE, not run.\n * ⛔ AND THAT IS THE DANGER: NOTHING CHECKS WHETHER A MOUNT STILL USES THE PLUGIN. The same function\n * has no mount lookup at all, so deregistering the plugin a live mount runs succeeds. The running\n * process is not killed by it; the mount breaks the next time OpenBao has to START the plugin — a\n * reload, a restart, an unseal — long after the plan that did it. REASONED FROM SOURCE, not run.\n */\nexport const deregisterPlugin = (\n type: BaoPluginType,\n name: string,\n version: string,\n): Effect.Effect<void, BaoError, HttpClient.HttpClient> =>\n baoDelete(versionedPath(type, name, version));\n",
|
|
67
|
+
"import { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport * as FileSystem from 'effect/FileSystem';\nimport * as Path from 'effect/Path';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { sha256 } from './digest.ts';\nimport { isEmptyAssembly } from './policy-assembly.ts';\nimport { judgePolicyRename, policyIdentity } from './policy-identity.ts';\nimport { deletePolicy, readPolicy, writePolicy } from './policy-wire.ts';\nimport { guardRename } from './rename-identity.ts';\n\n/**\n * An OpenBao ACL policy, assembled from the HCL fragments that declare it.\n *\n * ★ WHY THIS EXISTS. The estate already hand-rolled both halves of what Alchemy provides:\n * five `apply-*.sh`/`apply-*.py` scripts converge OpenBao, and separate `check-*.sh`\n * gates compare live to repo and refuse on drift. That is `reconcile` and `diff` written\n * twice, in two languages, with nothing recording what was applied — and one of those\n * gates blocked a deploy today because its own path had rotted.\n *\n * ⛔ THERE IS NO `Bao.Secret`, AND THERE MUST NEVER BE ONE. Alchemy persists attributes to\n * its state store and does NOT encrypt them: StateEncoding.ts unwraps `Redacted` to\n * plaintext under a marker key, and nothing under alchemy/src/State encrypts. This\n * estate's state store is the `alchemy` Postgres database, which a nightly job dumps\n * (it enumerates EVERY non-template database), copies to a backup guest, and PBS backs up\n * from there. A KV value here would exist in four places, none of them OpenBao.\n *\n * So this declares the SHAPE AROUND secrets. Every attribute it stores is a name, a\n * count, or a hash.\n *\n * ⛔ EVERY PRIMITIVE IS ALCHEMY'S OR EFFECT'S, NOT NODE'S. An earlier cut of this file used\n * `node:child_process` + `promisify(execFile)` and `node:fs/promises`, which is\n * hand-rolling inside a bun + Effect codebase: it loses the Scope, the typed\n * PlatformError, and the Layer that makes the provider testable without a real vault.\n * ★ `CommandExecutor.run` was tried first and blocked read/diff: Alchemy passes a session\n * to reconcile/delete but NOT to read/diff (Provider.ts:258-289), so the fix was Alchemy's\n * OWN Docker pattern — `ChildProcessSpawner` + `ChildProcess.make`, which needs only a\n * Scope (Docker.ts:476-553). ★ SINCE 2026-09-14 THE CALLS ARE OpenBao's HTTP API through\n * Effect's `HttpClient` (bao-http.ts), which needs no session either, so read/diff still work.\n * FileSystem and Path come from `effect/*` directly — in Effect 4 they moved into core.\n */\nexport interface BaoPolicyProps {\n /** Policy name, as `sys/policies/acl/<name>` takes it. */\n name: string;\n /**\n * Directory of `*.hcl` fragments.\n *\n * ⚠️ CONCATENATED IN SORTED ORDER, EACH FOLLOWED BY A NEWLINE — byte-identical to\n * apply-agent-policy.sh, which is what wrote the live policy. Any other joining makes\n * the first plan report an update on a policy nobody changed.\n */\n fragments: string;\n}\n\nexport interface BaoPolicyAttributes {\n /** Policy name. */\n name: string;\n /** SHA-256 of the assembled HCL. The whole diff, and safe to persist. */\n digest: string;\n /** `path \"...\"` grants — the number apply-agent-policy.sh prints. */\n grants: number;\n /** Fragment files that produced it, so a plan reads like the directory. */\n parts: number;\n}\n\nexport interface BaoPolicy extends Resource<\n 'Bao.Policy',\n BaoPolicyProps,\n BaoPolicyAttributes,\n never,\n HttpClient.HttpClient | FileSystem.FileSystem | Path.Path\n> {}\n\n/**\n * ⛔ `retain` — DELETING A POLICY REVOKES EVERY GRANT IT CARRIES, and this is the ONLY family in\n * this package with live instances, so it is the only one where the default could ever fire.\n *\n * 🔴 IT WAS THE ONLY FAMILY WITHOUT IT. Every sibling passes `{ defaultRemovalPolicy: 'retain' }`\n * — auth-role.ts:37, mount.ts:40, pki-role.ts, proxmox-role.ts, ssh-role.ts — each with a ★\n * explaining what deletion destroys. This file has the same warning on its own `delete` handler\n * and did not carry the option, which is the worst possible combination: the danger is\n * documented and the guard is missing.\n * ⛔ WHAT THAT MEANT IN PRACTICE, on 2026-09-13: ten live policies are named in a `const` array\n * in alchemy.run.ts. Removing a name from that array orphans the resource, and without\n * `retain` the next deploy calls `bao policy delete` on it — including the 86-line policy that\n * decides what the agent working in this repo can reach. A one-word edit, no plan line saying\n * \"revoke\", and the grants are gone. The array grew from four names to ten that same day,\n * which multiplied the blast radius of a mistake nobody had guarded against.\n *\n * ⚠️ `retain` DOES NOT WEAKEN `delete`, WHICH STAYS FULLY IMPLEMENTED. The engine skips it for an\n * orphaned resource; a caller that means it opts in with `.pipe(RemovalPolicy.destroy())`. This\n * is Terraform's `prevent_destroy`, not a stubbed operation — a delete that silently did nothing\n * would lie to whoever read the plan.\n * ⚠️ `retain` ALSO KEEPS THE OLD GENERATION OF A RENAME. A new `name` plans `replace`, and under\n * `retain` the old policy is left live and unmanaged (rename.ts, REPLACE.md).\n */\nexport const BaoPolicy = Resource<BaoPolicy>('Bao.Policy', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** `path \"...\"` grant count — the same number the apply script prints. */\nconst grantsOf = (hcl: string) => (hcl.match(/^path /gm) ?? []).length;\n\nconst attributesOf = (name: string, hcl: string, parts: number): BaoPolicyAttributes => ({\n name,\n digest: sha256(hcl),\n grants: grantsOf(hcl),\n parts,\n});\n\nexport const BaoPolicyProvider = () =>\n Provider.effect(\n BaoPolicy,\n Effect.gen(function* () {\n const fs = yield* FileSystem.FileSystem;\n const path = yield* Path.Path;\n\n /** Assemble fragments exactly as apply-agent-policy.sh does. */\n const assemble = (dir: string) =>\n Effect.gen(function* () {\n const entries = (yield* fs.readDirectory(dir)).filter((f) => f.endsWith('.hcl')).sort();\n let joined = '';\n for (const f of entries) joined += `${yield* fs.readFileString(path.join(dir, f))}\\n`;\n return { joined, parts: entries.length };\n });\n\n return BaoPolicy.Provider.of({\n /**\n * ⛔ `bao policy list` IS NOT A LIST OF THINGS THIS OWNS. Every policy in the\n * namespace answers, including ones written by hand years ago. Returning them\n * would invite Alchemy to adopt — and then delete — policies it never created.\n */\n list: () => Effect.succeed([]),\n\n // ★ Only undefined means absent (a typed 404); even a live empty policy occupies its name.\n // ⛔ With no attributes in state, a live policy is `Unowned` unless it is the one our own\n // interrupted create wrote: these fragments, byte for byte (ownership/probe.ts).\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const live = yield* readPolicy(olds.name);\n const found = live === undefined ? undefined : attributesOf(olds.name, live, 0);\n const ours = Effect.map(\n assemble(olds.fragments),\n (a) => sha256(a.joined) === found?.digest,\n );\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE POLICY, NOT THE STORED DIGEST. A policy edited in the\n * OpenBao UI is exactly the drift the check-* gates exist to catch, and a\n * provider that trusted its own state would report `noop` straight through it.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A RENAMED POLICY IS A `replace`, DECIDED BEFORE ANY OTHER READ (rename.ts). Until\n * 2026-09-21 this read the new name, found nothing and planned `update`: the new policy\n * was written and the old one kept every grant under no state record. Names compare as\n * OpenBao keys them (`policyKey`), so a change of case is the same policy, never a\n * replace. ⛔ A rename onto a policy that already exists fails the plan (`judgeMove`).\n * ⚠️ UNDER THE DEFAULT `retain` THE OLD POLICY STAYS LIVE, GRANTS AND ALL, for every token,\n * role and group that still names it. Under `destroy` they lose those grants at the\n * delete, so a role outside this graph that names the old policy must move in the same\n * PR (REPLACE.md).\n */\n const move = yield* judgePolicyRename(olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n // ⚠️ A prop can still be an unresolved Output or Config at plan time. Docker's\n // own providers guard with isResolved and skip rather than guess; a diff that\n // read a Config as a string would compare a placeholder to real HCL.\n if (!isResolved(news)) return undefined;\n const { joined } = yield* assemble(news.fragments);\n const live = yield* readPolicy(news.name);\n return live !== undefined && sha256(live) === sha256(joined)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const name = news.name;\n // ⛔ An `update` across a rename the diff could not see — refused before any write.\n yield* guardRename(policyIdentity, news, output);\n const { joined, parts } = yield* assemble(news.fragments);\n /**\n * ⛔ AN EMPTY ASSEMBLY IS A REFUSAL, NOT AN EMPTY POLICY. `bao policy write` with\n * no paths SILENTLY REVOKES every grant the policy carries, for every token\n * bound to it — and a mistyped or moved fragments directory reads exactly like\n * a policy with nothing in it. This estate lost a deploy today to a directory\n * that moved; it must not lose a vault to one.\n */\n // ⛔ No FILES was the first guard; no GRANT is the real one — see policy-assembly.ts.\n if (isEmptyAssembly(parts, joined))\n return yield* Effect.die(\n new Error(\n `Bao.Policy ${name}: the fragments under ${news.fragments} carry no path grant ` +\n `(${String(parts)} file(s)). Writing it would revoke every grant the policy carries.`,\n ),\n );\n /**\n * ⛔ ADOPTING A POLICY THAT ALREADY MATCHES MUST NOT REWRITE IT. Alchemy's `adopted`\n * action is NOT a read — Apply.ts routes it down the same branch as `update` and calls\n * reconcile — so the first deploy after declaring the four policies this estate\n * already has would have run `bao policy write` over all four. Byte-identical in the\n * happy case, and a SILENT REWRITE OF LIVE GRANTS the moment the repo fragments have\n * drifted from what is deployed.\n *\n * ★ THE GUARD IS THE SAME EXPRESSION `diff` USES, deliberately: one definition of\n * \"settled\" for this resource, so the plan and the write can never disagree. The\n * sibling PVE provider does exactly this in pveOperations.reconcile.\n */\n const current = yield* readPolicy(name);\n if (current !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.Policy ${name}`);\n if (current !== undefined && sha256(current) === sha256(joined)) {\n return attributesOf(name, joined, parts);\n }\n // ⚠️ In the request body, never on argv — see `writePolicy` for why the temp file went.\n yield* writePolicy(name, joined);\n return attributesOf(name, joined, parts);\n }),\n\n /**\n * ⛔ DELETING A POLICY REVOKES EVERY GRANT IT CARRIES. Idempotent as Alchemy\n * requires — already gone is success — but this is the one operation with teeth.\n */\n delete: Effect.fn(function* ({ output }) {\n /**\n * ⛔ A REFUSED DELETE FAILS. This is \"the one operation with teeth\" the note above\n * names, and it used to run through the read helper, which discarded the exit code —\n * so a REFUSED policy delete reported success and the row left Alchemy's state while\n * every grant it carried stayed live. Idempotence is preserved: a 404 is still\n * success, and a 403 is not (bao-status.ts).\n */\n yield* deletePolicy(output.name);\n return undefined;\n }),\n });\n }).pipe(Effect.map(provingResumes)),\n );\n",
|
|
68
68
|
"/**\n * Whether an assembled policy would carry NO GRANT — the one write `Bao.Policy` must refuse.\n *\n * ⛔ EMPTY MEANS NO `path` GRANT, NOT NO FILES. Writing `sys/policies/acl/<name>` with nothing in it\n * SILENTLY REVOKES every grant the policy carries, for every token bound to it. The first guard\n * only counted fragment files, so a directory whose one fragment was empty, whitespace or\n * comments — a truncated edit, a bad checkout — assembled to text with no grant in it, passed,\n * and would have replaced the live policy with nothing. Found by grok's review on 2026-09-14.\n * ★ A GRANT IS A `path \"…\"` STANZA, the unit apply-agent-policy.sh counts and `grantsOf` in\n * policy.ts reports. Leading whitespace is allowed here, so an indented stanza still counts.\n */\nexport const isEmptyAssembly = (parts: number, joined: string): boolean =>\n parts === 0 || !/^\\s*path\\s+\"/m.test(joined);\n",
|
|
69
69
|
"/**\n * The three OpenBao calls Bao.Policy makes — read, write and delete of `sys/policies/acl/<name>`.\n * Split from policy.ts so the trailing-newline round trip can be tested against a fake server.\n */\nimport {\n policiesDeleteAclPolicy,\n policiesReadAclPolicy,\n policiesWriteAclPolicy,\n} from '@distilled.cloud/openbao/policies';\nimport * as Effect from 'effect/Effect';\nimport { BaoError } from './bao-status.ts';\nimport { runBao, runBaoRead, runBaoWrite } from './distilled.ts';\n\n/** The endpoint the CLI's policy commands used — openbao v2.6.2 api/sys_policy.go:60, :100, :122. */\nexport const policyPath = (name: string) => `sys/policies/acl/${name}`;\n\n/**\n * The live policy text, or undefined only when the SDK reports PolicyNotFound. Other errors FAIL.\n *\n * 🔴 THE ABSENCE WORDING WAS THE POLICY COMMAND'S OWN, AND ASSUMING OTHERWISE MADE A NEW POLICY\n * UNCREATABLE. `No value found at` was measured for `bao read`; `bao policy read` never printed\n * it. Its API client turned a 404 into an empty string and the CLI reported that in its own\n * words — openbao v2.6.2 api/sys_policy.go:65-67 and command/policy_read.go:85-87:\n *\n * No policy named: <name> exit 2\n *\n * So `read` on a policy that did not exist yet FAILED instead of answering absent, and\n * `reconcile` failed at its own pre-write read. Every policy declared so far already existed,\n * which is the only reason nothing broke. MEASURED 2026-09-14 under the admin lane —\n * `bao policy read zz-probe-absent-policy-4c1e` printed exactly that line and exited 2. (The\n * agent lane cannot measure it: it is refused `sys/policies/acl` with a 403 first.)\n * ★ THE WORDING PROBLEM IS GONE WITH THE CLI. The line above was the CLI's rendering of the 404 that\n * the server returns for a missing policy (vault/logical_system.go handlePoliciesRead returns no\n * response, which RespondErrorCommon turns into 404). That status is now read directly, and a\n * refused read is a 403 — two codes, no text to confuse.\n *\n * ⚠️ `data.policy` IS THE TEXT, and a 200 without it is a failure, as it was in the CLI's client\n * (\"no policy found in response\", api/sys_policy.go:81-85).\n */\nexport const readPolicy = (name: string) =>\n runBaoRead(policiesReadAclPolicy({ name })).pipe(\n Effect.flatMap((data) => {\n const text = data['policy'];\n return typeof text === 'string'\n ? Effect.succeed(text)\n : Effect.fail(\n new BaoError(200, 'GET', policyPath(name), ['no data.policy in the response']),\n );\n }),\n Effect.catchTag('PolicyNotFound', () => Effect.succeed(undefined)),\n );\n\n/** Even a live empty policy occupies its name; rename guards must not overwrite it. */\nexport const policyExists = (name: string) =>\n Effect.map(readPolicy(name), (policy) => policy !== undefined);\n\n/**\n * ★ THE HCL TRAVELS IN THE REQUEST BODY (`{\"policy\": …}`, api/sys_policy.go:96-101). The CLI path\n * needed a scoped temp file because passing HCL on argv would have put every grant in the process\n * list; a JSON body never reaches argv, so the temp file is gone with it.\n * ★ A FULL-REPLACE WRITE: the whole policy text is sent every time, so it is safe to retry a\n * transport failure through `runBaoWrite` — a replayed attempt converges on the same policy\n * rather than compounding a partial one.\n */\nexport const writePolicy = (name: string, hcl: string) =>\n runBaoWrite(policiesWriteAclPolicy({ name, policy: hcl })).pipe(Effect.asVoid);\n\n/** Deleting a policy that is already gone answers success (handlePoliciesDelete returns nothing). */\nexport const deletePolicy = (name: string) =>\n runBao(policiesDeleteAclPolicy({ name })).pipe(\n Effect.catchTag('NotFound', () => Effect.void),\n Effect.asVoid,\n );\n",
|
|
70
70
|
"import { policyExists, policyPath } from './policy-wire.ts';\nimport { declaredString, judgeMoveWith, policyKey } from './rename.ts';\nimport { nameIdentity } from './rename-identity.ts';\n\n/** A policy is its name, keyed as OpenBao keys it (`policyKey`). */\nexport const policyIdentity = nameIdentity<{ readonly name: string }>(\n 'Bao.Policy',\n policyPath,\n policyKey,\n);\n\n/** The occupied-name guard must use the same SDK and refusal semantics as every other read. */\nexport const judgePolicyRename = (\n olds: unknown,\n news: unknown,\n output: { readonly name: string } | undefined,\n) =>\n judgeMoveWith(\n 'Bao.Policy',\n output === undefined ? declaredString(olds, 'name') : output.name,\n declaredString(news, 'name'),\n policyExists,\n policyKey,\n );\n",
|
|
71
|
-
"/**\n * A role on the estate's proxmox secrets plugin — the mapping from one consumer to one PVE\n * mint user, plus the lease ceilings that consumer's tokens get. METADATA ONLY.\n *\n * ★ WHY THIS FAMILY MATTERS MORE THAN IT LOOKS. Declaring these roles is how the estate\n * replaces HAND-MADE PERMANENT PVE TOKENS with short-lived minted ones. On C1, SEVEN tokens\n * carry expire=0 and privsep=0 — root@pam!inventory-sync, agent@pve!executor,\n * metrics@pve!exporter, app@pve!app, iac@pve!ro, iac@pve!apply and\n * mint@pve!engine. Six of those are one Bao.ProxmoxRole plus a scoped PVE user away from\n * being a 5-minute lease instead of a forever key.\n *\n * The seventh cannot be. mint@pve!engine is the credential the ENGINE ITSELF\n * authenticates with in order to mint anything at all: the thing that issues short-lived\n * tokens needs a standing one, and no role can resolve that chicken-and-egg. It stays\n * permanent, which makes it the single most valuable token on the cluster and the one whose\n * rotation must be a deliberate, hand-run procedure rather than a plan.\n *\n * MEASURED here: `bao read proxmox-c1/config` returns parent_token_id\n * `mint@pve!engine`, parent_secret_set true, parent_secret_tail `…eb01` — the engine's\n * own key, present and, by the schema's own \"Write-only: never returned by a read\", not\n * retrievable. The seven-token inventory was handed to this change and NOT re-counted against\n * the PVE API in this session.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for the full reasoning. Every attribute\n * here is a mount path, a role name, a PVE username or a TTL. Nothing this resource stores\n * would help anyone authenticate to anything.\n *\n * ⛔ ISSUANCE IS NOT THIS RESOURCE, AND MUST NEVER BECOME ONE. `<mount>/creds/<name>` returns a\n * LIVE PVE TOKEN. Alchemy persists attributes unencrypted (StateEncoding.ts tags Redacted\n * values rather than encrypting them) into the `alchemy` Postgres, which a nightly job dumps\n * to a backup guest, from where PBS backs it up. A minted token declared as a resource would\n * outlive its own lease in at least four places, none of them OpenBao. This resource declares\n * the DOOR; walking through it is a runtime call, not a plan.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from\n * it. Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoWrite } from './bao-http.ts';\nimport {\n type BaoProxmoxRoleAttributes,\n type BaoProxmoxRoleProps,\n matches,\n rescopeRefusal,\n rolePath,\n writeBody,\n} from './proxmox-role-form.ts';\nimport { readRole } from './proxmox-role-wire.ts';\nimport { declaredString, isPendingProp } from './rename.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoProxmoxRoleAttributes, BaoProxmoxRoleProps };\n\nexport interface BaoProxmoxRole extends Resource<\n 'Bao.ProxmoxRole',\n BaoProxmoxRoleProps,\n BaoProxmoxRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoProxmoxRole = Resource<BaoProxmoxRole>('Bao.ProxmoxRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the plugin stores `roles/<name>` verbatim. */\nconst IDENTITY = roleIdentity<BaoProxmoxRoleAttributes>('Bao.ProxmoxRole', rolePath);\n\nexport const BaoProxmoxRoleProvider = () =>\n Provider.effect(\n BaoProxmoxRole,\n Effect.succeed(\n BaoProxmoxRole.Provider.of({\n /**\n * ⛔ `bao list <mount>/roles` IS NOT A LIST OF THINGS THIS OWNS. MEASURED today:\n * proxmox-c1/roles answers `provision, read` and proxmox-c2/roles answers `read` —\n * four roles created by hand at bringup, none of them declared anywhere yet.\n * Returning them would invite Alchemy to adopt, and then delete, roles it never\n * created, and deleting a role is how every consumer of it stops being able to mint.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(olds);\n const ours = Effect.sync(() => found !== undefined && matches(found, olds));\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A mint_user edited in the\n * OpenBao UI re-scopes every future credential while the digest in Postgres still\n * says everything is fine — exactly the drift the hand-written check-* gates exist to\n * catch, and exactly what a provider that trusted its own state would walk past.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A NEW `mount` OR `name` IS A `replace` (rename.ts). It is a DIFFERENT path, so none of\n * the reasons below apply. Until 2026-09-21 it planned `update` and left the old role\n * minting under no state record. Under the default `retain` the old role still mints;\n * under `destroy` its consumers fail at the delete (REPLACE.md). ⛔ A move onto a role\n * that already exists fails the plan (`judgeMove`).\n * ⛔ THE RE-SCOPE GUARD TRAVELS WITH THE RENAME, checked here because the new generation's\n * reconcile finds no live role to compare. While `mintUser` or `allowMintUserChange` is\n * still an Output it cannot be checked, so the diff defers, and reconcile refuses the\n * resulting `update`.\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) {\n const mintUser = declaredString(news, 'mintUser');\n if (mintUser === undefined || isPendingProp(news, 'allowMintUserChange'))\n return undefined;\n const from = (yield* readRole(output))?.mintUser ?? output.mintUser;\n const allow = declaredString(news, 'allowMintUserChange');\n const refusal = rescopeRefusal(from, mintUser, allow);\n if (refusal === undefined) return { action: 'replace' } as const;\n return yield* Effect.die(\n new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal}`),\n );\n }\n if (!isResolved(news)) return undefined;\n const live = yield* readRole(news);\n if (live === undefined) return { action: 'update' } as const;\n if (matches(live, news)) return { action: 'noop' } as const;\n /**\n * ⛔ NEVER `replace`, NOT EVEN FOR A mint_user CHANGE. A replace deletes the role and\n * writes it back; between those steps `<mount>/creds/<name>` 404s, so anything\n * minting in that window fails. The end state is byte-identical to the in-place\n * write, because the plugin stores name, mint_user, ttl and max_ttl and nothing\n * else — there is no immutable identity a recreate could reset. So a replace here\n * buys an outage window in exchange for a louder-looking plan. The loudness a\n * re-scope deserves comes from reconcile REFUSING it below, which blocks rather\n * than destroys.\n *\n * ⚠️ CONSEQUENCE FOR THE READER OF A PLAN: a mint_user re-scope shows up here as a\n * plain `update`, indistinguishable from a TTL tweak. The refusal lands at DEPLOY,\n * not at plan. That is the safe ordering — nothing is written before the refusal —\n * but do not read a green plan as evidence that a mint_user change is approved.\n */\n return { action: 'update' } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news.mount, news.name);\n // ⛔ An `update` across a move the diff could not see — refused before any read or write.\n yield* guardRename(IDENTITY, news, output);\n const live = yield* readRole(news);\n if (live !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.ProxmoxRole ${path}`);\n /**\n * ⛔ A mint_user CHANGE RE-SCOPES EVERY CREDENTIAL THE ROLE WILL EVER MINT, SILENTLY.\n * The minted token inherits that PVE user's standing ACL and nothing else, so\n * swapping `hf-read@pve` for `hf-provision@pve` turns a read-only consumer into a\n * provisioning one with no other line of the declaration changing. A plan diff of\n * one string is not proportionate warning for that, so an existing role refuses the\n * move unless the declaration NAMES THE VALUE IT IS REPLACING. Creating a role never\n * trips this — there is nothing to re-scope — and the permission expires by itself\n * once the change lands, because live then equals the declaration.\n * ⚠️ A RENAME CREATES A NEW ROLE, SO IT NEVER REACHES THIS CHECK. The diff asks the same\n * question of the role being replaced (`rescopeRefusal`, proxmox-role-form.ts).\n */\n const rescope =\n live === undefined\n ? undefined\n : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);\n if (rescope !== undefined) {\n return yield* Effect.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));\n }\n if (live === undefined || !matches(live, news)) {\n const write = writeBody(news);\n /**\n * ⛔ AN UNPARSEABLE TTL IS A REFUSAL, NOT A ZERO. parseDuration accepts `3600s`,\n * `1h`, `6h`, `1d` and bare `0`, and NOTHING ELSE — a bare `3600` or a compound\n * `1h30m` returns undefined. Left alone that never equals the live value, so the\n * plan would report an update forever and each deploy would write a zero TTL.\n * Die with the offending props named instead.\n */\n if (!write.ok) {\n return yield* Effect.die(\n new Error(\n `Bao.ProxmoxRole ${path}: unparseable duration ` +\n `${write.bad.join(', ')}. Use 30s / 5m / 1h / 1d, or 0.`,\n ),\n );\n }\n yield* baoWrite('PUT', path, write.body);\n }\n const after = yield* readRole(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(\n `Bao.ProxmoxRole ${path}: write returned no error ` +\n 'but the role is still absent.',\n ),\n );\n }\n /**\n * ⚠️ A GREEN RECONCILE DOES NOT MEAN THE ROLE CAN MINT. The engine never grants ACLs\n * — it borrows the mint user's — so declaring `mint_user: hf-read@pve` neither\n * creates that PVE user nor gives it a single permission. If the user does not\n * exist, or exists with no ACL, the role writes and reads back perfectly and the\n * failure surfaces at `creds/<name>` time, in whatever consumer is unlucky. Verify\n * the PVE side out-of-band; this resource cannot and does not.\n */\n return after;\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ALREADY MINTED — it only stops the\n * next mint. Outstanding leases run to their own expiry against the PVE user's ACL.\n * So this is an availability change for every consumer of `creds/<name>` and NOT a\n * containment action: to contain a leaked credential, revoke the lease (which deletes\n * the PVE token) or delete the token in PVE. Deleting the role only hides the door it\n * came through. The plugin's own test pins this (homeflare-openbao-plugins,\n * TestDeletingARoleLeavesItsOutstandingLeasesRevocable): the delete is one storage\n * delete, and each lease stays revocable without the role.\n *\n * ⚠️ IDEMPOTENT AS ALCHEMY REQUIRES — already gone is success. It used to get that by\n * going through `baoReadText`, which discarded the exit code entirely, so a REFUSED\n * delete was reported as a successful one and the resource left Alchemy's state while\n * the role stayed live. `baoDelete` keeps the idempotence — a 404 is success — and\n * fails on everything else, 403 and 503 included.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output.mount, output.name));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
71
|
+
"/**\n * A role on the estate's proxmox secrets plugin — the mapping from one consumer to one PVE\n * mint user, plus the lease ceilings that consumer's tokens get. METADATA ONLY.\n *\n * ★ WHY THIS FAMILY MATTERS MORE THAN IT LOOKS. Declaring these roles is how the estate\n * replaces HAND-MADE PERMANENT PVE TOKENS with short-lived minted ones. On C1, SEVEN tokens\n * carry expire=0 and privsep=0 — root@pam!inventory-sync, agent@pve!executor,\n * metrics@pve!exporter, app@pve!app, iac@pve!ro, iac@pve!apply and\n * mint@pve!engine. Six of those are one Bao.ProxmoxRole plus a scoped PVE user away from\n * being a 5-minute lease instead of a forever key.\n *\n * The seventh cannot be. mint@pve!engine is the credential the ENGINE ITSELF\n * authenticates with in order to mint anything at all: the thing that issues short-lived\n * tokens needs a standing one, and no role can resolve that chicken-and-egg. It stays\n * permanent, which makes it the single most valuable token on the cluster and the one whose\n * rotation must be a deliberate, hand-run procedure rather than a plan.\n *\n * MEASURED here: `bao read proxmox-c1/config` returns parent_token_id\n * `mint@pve!engine`, parent_secret_set true, parent_secret_tail `…eb01` — the engine's\n * own key, present and, by the schema's own \"Write-only: never returned by a read\", not\n * retrievable. The seven-token inventory was handed to this change and NOT re-counted against\n * the PVE API in this session.\n *\n * ⛔ NO SECRET IN PROPS OR ATTRIBUTES — see policy.ts for the full reasoning. Every attribute\n * here is a mount path, a role name, a PVE username or a TTL. Nothing this resource stores\n * would help anyone authenticate to anything.\n *\n * ⛔ ISSUANCE IS NOT THIS RESOURCE, AND MUST NEVER BECOME ONE. `<mount>/creds/<name>` returns a\n * LIVE PVE TOKEN. Alchemy persists attributes unencrypted (StateEncoding.ts tags Redacted\n * values rather than encrypting them) into the `alchemy` Postgres, which a nightly job dumps\n * to a backup guest, from where PBS backs it up. A minted token declared as a resource would\n * outlive its own lease in at least four places, none of them OpenBao. This resource declares\n * the DOOR; walking through it is a runtime call, not a plan.\n *\n * ★ `defaultRemovalPolicy: 'retain'` — deleting a role breaks every consumer that mints from\n * it. Opt in with `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoWrite } from './bao-http.ts';\nimport {\n type BaoProxmoxRoleAttributes,\n type BaoProxmoxRoleProps,\n matches,\n rescopeRefusal,\n rolePath,\n writeBody,\n} from './proxmox-role-form.ts';\nimport { readRole } from './proxmox-role-wire.ts';\nimport { declaredString, isPendingProp } from './rename.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoProxmoxRoleAttributes, BaoProxmoxRoleProps };\n\nexport interface BaoProxmoxRole extends Resource<\n 'Bao.ProxmoxRole',\n BaoProxmoxRoleProps,\n BaoProxmoxRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoProxmoxRole = Resource<BaoProxmoxRole>('Bao.ProxmoxRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the plugin stores `roles/<name>` verbatim. */\nconst IDENTITY = roleIdentity<BaoProxmoxRoleAttributes>('Bao.ProxmoxRole', rolePath);\n\nexport const BaoProxmoxRoleProvider = () =>\n Provider.effect(\n BaoProxmoxRole,\n Effect.succeed(\n BaoProxmoxRole.Provider.of({\n /**\n * ⛔ `bao list <mount>/roles` IS NOT A LIST OF THINGS THIS OWNS. MEASURED today:\n * proxmox-c1/roles answers `provision, read` and proxmox-c2/roles answers `read` —\n * four roles created by hand at bringup, none of them declared anywhere yet.\n * Returning them would invite Alchemy to adopt, and then delete, roles it never\n * created, and deleting a role is how every consumer of it stops being able to mint.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(olds);\n const ours = Effect.sync(() => found !== undefined && matches(found, olds));\n return yield* ownedRead({ fqn, instanceId, output }, found, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A mint_user edited in the\n * OpenBao UI re-scopes every future credential while the digest in Postgres still\n * says everything is fine — exactly the drift the hand-written check-* gates exist to\n * catch, and exactly what a provider that trusted its own state would walk past.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A NEW `mount` OR `name` IS A `replace` (rename.ts). It is a DIFFERENT path, so none of\n * the reasons below apply. Until 2026-09-21 it planned `update` and left the old role\n * minting under no state record. Under the default `retain` the old role still mints;\n * under `destroy` its consumers fail at the delete (REPLACE.md). ⛔ A move onto a role\n * that already exists fails the plan (`judgeMove`).\n * ⛔ THE RE-SCOPE GUARD TRAVELS WITH THE RENAME, checked here because the new generation's\n * reconcile finds no live role to compare. While `mintUser` or `allowMintUserChange` is\n * still an Output it cannot be checked, so the diff defers, and reconcile refuses the\n * resulting `update`.\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) {\n const mintUser = declaredString(news, 'mintUser');\n if (mintUser === undefined || isPendingProp(news, 'allowMintUserChange'))\n return undefined;\n const from = (yield* readRole(output))?.mintUser ?? output.mintUser;\n const allow = declaredString(news, 'allowMintUserChange');\n const refusal = rescopeRefusal(from, mintUser, allow);\n if (refusal === undefined) return { action: 'replace' } as const;\n return yield* Effect.die(\n new Error(`Bao.ProxmoxRole ${move.from} → ${move.to}: the rename ${refusal}`),\n );\n }\n if (!isResolved(news)) return undefined;\n const live = yield* readRole(news);\n if (live === undefined) return { action: 'update' } as const;\n if (matches(live, news)) return { action: 'noop' } as const;\n /**\n * ⛔ NEVER `replace`, NOT EVEN FOR A mint_user CHANGE. A replace deletes the role and\n * writes it back; between those steps `<mount>/creds/<name>` 404s, so anything\n * minting in that window fails. The end state is byte-identical to the in-place\n * write, because the plugin stores name, mint_user, ttl and max_ttl and nothing\n * else — there is no immutable identity a recreate could reset. So a replace here\n * buys an outage window in exchange for a louder-looking plan. The loudness a\n * re-scope deserves comes from reconcile REFUSING it below, which blocks rather\n * than destroys.\n *\n * ⚠️ CONSEQUENCE FOR THE READER OF A PLAN: a mint_user re-scope shows up here as a\n * plain `update`, indistinguishable from a TTL tweak. The refusal lands at DEPLOY,\n * not at plan. That is the safe ordering — nothing is written before the refusal —\n * but do not read a green plan as evidence that a mint_user change is approved.\n */\n return { action: 'update' } as const;\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const path = rolePath(news.mount, news.name);\n // ⛔ An `update` across a move the diff could not see — refused before any read or write.\n yield* guardRename(IDENTITY, news, output);\n const live = yield* readRole(news);\n if (live !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.ProxmoxRole ${path}`);\n /**\n * ⛔ A mint_user CHANGE RE-SCOPES EVERY CREDENTIAL THE ROLE WILL EVER MINT, SILENTLY.\n * The minted token inherits that PVE user's standing ACL and nothing else, so\n * swapping `hf-read@pve` for `hf-provision@pve` turns a read-only consumer into a\n * provisioning one with no other line of the declaration changing. A plan diff of\n * one string is not proportionate warning for that, so an existing role refuses the\n * move unless the declaration NAMES THE VALUE IT IS REPLACING. Creating a role never\n * trips this — there is nothing to re-scope — and the permission expires by itself\n * once the change lands, because live then equals the declaration.\n * ⚠️ A RENAME CREATES A NEW ROLE, SO IT NEVER REACHES THIS CHECK. The diff asks the same\n * question of the role being replaced (`rescopeRefusal`, proxmox-role-form.ts).\n */\n const rescope =\n live === undefined\n ? undefined\n : rescopeRefusal(live.mintUser, news.mintUser, news.allowMintUserChange);\n if (rescope !== undefined) {\n return yield* Effect.die(new Error(`Bao.ProxmoxRole ${path}: ${rescope}`));\n }\n if (live === undefined || !matches(live, news)) {\n const write = writeBody(news);\n /**\n * ⛔ AN UNPARSEABLE TTL IS A REFUSAL, NOT A ZERO. parseDuration accepts `3600s`,\n * `1h`, `6h`, `1d` and bare `0`, and NOTHING ELSE — a bare `3600` or a compound\n * `1h30m` returns undefined. Left alone that never equals the live value, so the\n * plan would report an update forever and each deploy would write a zero TTL.\n * Die with the offending props named instead.\n */\n if (!write.ok) {\n return yield* Effect.die(\n new Error(\n `Bao.ProxmoxRole ${path}: unparseable duration ` +\n `${write.bad.join(', ')}. Use 30s / 5m / 1h / 1d, or 0.`,\n ),\n );\n }\n yield* baoWrite('PUT', path, write.body);\n }\n const after = yield* readRole(news);\n if (after === undefined) {\n return yield* Effect.die(\n new Error(\n `Bao.ProxmoxRole ${path}: write returned no error ` +\n 'but the role is still absent.',\n ),\n );\n }\n /**\n * ⚠️ A GREEN RECONCILE DOES NOT MEAN THE ROLE CAN MINT. The engine never grants ACLs\n * — it borrows the mint user's — so declaring `mint_user: hf-read@pve` neither\n * creates that PVE user nor gives it a single permission. If the user does not\n * exist, or exists with no ACL, the role writes and reads back perfectly and the\n * failure surfaces at `creds/<name>` time, in whatever consumer is unlucky. Verify\n * the PVE side out-of-band; this resource cannot and does not.\n */\n return after;\n }),\n\n /**\n * ⛔ DELETING A ROLE DOES NOT REVOKE THE TOKENS IT ALREADY MINTED — it only stops the\n * next mint. Outstanding leases run to their own expiry against the PVE user's ACL.\n * So this is an availability change for every consumer of `creds/<name>` and NOT a\n * containment action: to contain a leaked credential, revoke the lease (which deletes\n * the PVE token) or delete the token in PVE. Deleting the role only hides the door it\n * came through. The plugin's own test pins this (homeflare-openbao-plugins,\n * TestDeletingARoleLeavesItsOutstandingLeasesRevocable): the delete is one storage\n * delete, and each lease stays revocable without the role.\n *\n * ⚠️ IDEMPOTENT AS ALCHEMY REQUIRES — already gone is success. It used to get that by\n * going through `baoReadText`, which discarded the exit code entirely, so a REFUSED\n * delete was reported as a successful one and the resource left Alchemy's state while\n * the role stayed live. `baoDelete` keeps the idempotence — a 404 is success — and\n * fails on everything else, 403 and 503 included.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(rolePath(output.mount, output.name));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
72
72
|
"/**\n * Wire and comparison half of Bao.ProxmoxRole — the resource itself is proxmox-role.ts.\n *\n * MEASURED 2026-09-13, read-only, against the live server (BAO_ADDR=http://127.0.0.1:8200,\n * BAO_NAMESPACE=homeflare). No write of any kind was issued to a role or a mount:\n *\n * bao read -format=json proxmox-c1/roles/read\n * → { max_ttl: 21600, mint_user: \"hf-read@pve\", name: \"read\", ttl: 3600 }\n * bao read -format=json proxmox-c1/roles/provision\n * → { max_ttl: 1800, mint_user: \"hf-provision@pve\", name: \"provision\", ttl: 300 }\n * GET /v1/proxmox-c1/?help=1 → components.schemas.WriteRolesNameRequest:\n * mint_user string — the ONLY required field, described as \"The `user@realm` whose\n * standing ACL is the minted token's entire privilege set. Created\n * out-of-band; this engine never grants ACLs.\"\n * ttl integer — \"format\": \"seconds\"\n * max_ttl integer — \"format\": \"seconds\", \"Narrows the mount's; can never widen it.\"\n *\n * ★ name + mint_user + ttl + max_ttl IS THE WHOLE ROLE. The plugin stores nothing else, so\n * `matches` below covers 100% of the server-side state: there is no unmanaged field left to\n * drift behind a green plan. That completeness is bought by making the TTLs REQUIRED props\n * rather than the optional-means-unmanaged shape Bao.Mount uses — see the ⛔ on writeBody.\n */\nimport { sha256 } from './digest.ts';\nimport { mountPath, parseDuration, ttlSeconds } from './mount-form.ts';\n\nexport interface BaoProxmoxRoleProps {\n /** Mount path of the proxmox secrets engine, e.g. `proxmox-c1`. A trailing slash is fine. */\n mount: string;\n /**\n * Role name, as `<mount>/roles/<name>` takes it.\n *\n * ⚠️ The plugin's own schema says the name \"Appears in the minted token's id, so keep it\n * short.\" Both live roles are one word (`read`, `provision`). A long name here becomes a\n * long PVE token id on every mint.\n */\n name: string;\n /**\n * ⛔ THE ENTIRE SECURITY BOUNDARY OF THIS RESOURCE. A minted token inherits this PVE user's\n * standing ACL and nothing else — the engine never grants ACLs, it only borrows one. Change\n * this string and every credential the role issues from then on carries a different\n * privilege set, with no other field in the declaration changing to hint at it. That is why\n * it is compared in `matches` below, and why reconcile refuses to move it without\n * `allowMintUserChange`.\n */\n mintUser: string;\n /** Default lease TTL for minted tokens, e.g. `1h`. REQUIRED — see the ⛔ on writeBody. */\n ttl: string;\n /**\n * Maximum lease TTL, e.g. `6h`. REQUIRED — see the ⛔ on writeBody.\n *\n * ⚠️ \"Narrows the mount's; can never widen it.\" A role declaring `6h` under a mount whose\n * max_lease_ttl is `1h` still READS BACK as 21600, so this resource reports noop and the\n * plan is green — while every actual mint is capped at 3600 by the mount. The role is not\n * lying and neither is the plan; the ceiling simply lives one level up. If a consumer gets\n * a shorter lease than declared here, check `bao read sys/mounts/<mount>` before touching\n * the role.\n */\n maxTtl: string;\n /**\n * Permission to re-scope `mintUser` on an EXISTING role: set it to the CURRENT live mint_user\n * that this change is allowed to replace.\n *\n * ★ IT IS A STRING AND NOT A BOOLEAN, AND THAT IS THE WHOLE POINT. A `true` left behind after\n * one legitimate rename would wave through every future re-scope of that role forever —\n * including one pasted in by whoever copies this block as a template. Naming the value being\n * replaced makes the permission SELF-EXPIRING: the moment the change lands, live equals\n * `mintUser`, the guard stops consulting it, and the next re-scope finds a stale string that\n * does not match live and is refused on its own merits.\n *\n * Not persisted, not in attributes, not in `matches` — it describes the operator's intent, not\n * the server, so changing it alone is correctly a noop. See the ⛔ in proxmox-role.ts reconcile.\n */\n allowMintUserChange?: string;\n}\n\nexport interface BaoProxmoxRoleAttributes {\n /** Mount path, trailing slash stripped. */\n mount: string;\n /** Role name. */\n name: string;\n /** The PVE `user@realm` live tokens are minted under. A name, never a credential. */\n mintUser: string;\n /** Live default lease TTL, rendered back into the duration shape props use. */\n ttl: string;\n /** Live maximum lease TTL, same shape. */\n maxTtl: string;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\n/**\n * Seconds back into the duration shape the props use.\n *\n * ⚠️ Third private copy of this function in the package (mount-form.ts and auth-role-form.ts\n * each keep one). Exporting a single copy means editing a file this change does not own, so\n * it is duplicated deliberately rather than silently. Worth collapsing in a follow-up.\n */\nconst ttlText = (seconds: number | undefined, fallback = '0') => {\n if (seconds === undefined) return fallback;\n if (seconds % 86400 === 0) return `${String(seconds / 86400)}d`;\n if (seconds % 3600 === 0) return `${String(seconds / 3600)}h`;\n if (seconds % 60 === 0) return `${String(seconds / 60)}m`;\n return `${String(seconds)}s`;\n};\n\n/** `proxmox-c1/roles/read` — read, write and delete all address the role here. */\nexport const rolePath = (mount: string, name: string) => `${mountPath(mount)}/roles/${name}`;\n\nexport const attributesOf = (\n props: Pick<BaoProxmoxRoleProps, 'mount' | 'name'>,\n live: Record<string, unknown>,\n): BaoProxmoxRoleAttributes => {\n const attrs = {\n mount: mountPath(props.mount),\n // ⚠️ The plugin echoes `name` in a role read, so it is taken from `live` with the prop only\n // as a fallback. Every other value below is live-only: the same split the sibling\n // resources use, so a read never launders a declaration back into itself as \"current\".\n name: text(live['name']) || props.name,\n mintUser: text(live['mint_user']),\n ttl: ttlText(ttlSeconds(live['ttl'])),\n maxTtl: ttlText(ttlSeconds(live['max_ttl'])),\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\n/**\n * The body for `PUT <mount>/roles/<name>` — all strings, the `k=v` pairs `bao write` sent — or\n * the prop names whose duration would not parse.\n *\n * ⛔ EVERY WRITE CARRIES ALL THREE FIELDS, and both TTLs are required props, so `matches` covers\n * the whole role and no field is left unmanaged behind a green plan.\n * ⚠️ CORRECTED 2026-09-21 FROM THE PLUGIN SOURCE. This said a write REPLACES the role and resets an\n * omitted TTL to zero. The port in homeflare-openbao-plugins (secrets/proxmox/path_roles.go,\n * pathRolesWrite, commit 0e79154) MERGES: it loads the stored role and sets only the fields\n * present (`d.GetOk`). An omitted TTL would keep its old value, which is still a value this\n * resource would not be managing. The build running live was not re-checked against that source.\n *\n * ⚠️ Seconds go on the wire as integers, not as `1h`. The schema declares both TTLs\n * `\"format\": \"seconds\"`, and an integer is accepted unambiguously by every path that reads\n * them back — which is what keeps the round-trip through `matches` stable.\n */\nexport const writeBody = (\n props: BaoProxmoxRoleProps,\n): { ok: true; body: Record<string, string> } | { ok: false; bad: string[] } => {\n const ttl = parseDuration(props.ttl);\n const maxTtl = parseDuration(props.maxTtl);\n const bad: string[] = [];\n if (ttl === undefined) bad.push(`ttl=${props.ttl}`);\n if (maxTtl === undefined) bad.push(`maxTtl=${props.maxTtl}`);\n if (ttl === undefined || maxTtl === undefined) return { ok: false, bad };\n return {\n ok: true,\n body: { mint_user: props.mintUser, ttl: String(ttl), max_ttl: String(maxTtl) },\n };\n};\n\n/**\n * ⚠️ An unparseable declaration never equals anything, so it surfaces as an update that will\n * never settle rather than as a false noop. reconcile turns that loop into one named error;\n * see the `writeBody` refusal there.\n */\nconst sameTtl = (want: string, have: string) => {\n const wantSeconds = parseDuration(want);\n const haveSeconds = ttlSeconds(have);\n return wantSeconds !== undefined && wantSeconds === haveSeconds;\n};\n\n/**\n * Why moving the role's mint user from `before` to the declared one must be refused, or undefined.\n * The ⛔ on reconcile in proxmox-role.ts says why a re-scope needs `allowMintUserChange`.\n *\n * ★ ONE DEFINITION FOR BOTH PLACES THAT ASK. Reconcile asks it of the live role at the same path.\n * The diff asks it across a rename, where `before` is the role being replaced: a rename writes a\n * brand-new role, so reconcile alone would see nothing to re-scope, and a rename would become the\n * way around the guard.\n */\nexport const rescopeRefusal = (\n before: string,\n mintUser: string,\n allowMintUserChange: string | undefined,\n): string | undefined =>\n before === mintUser || allowMintUserChange === before\n ? undefined\n : `re-scopes mint_user ${before} → ${mintUser}. Every token this role mints inherits ` +\n `the ACL of that PVE user. To re-scope deliberately, declare allowMintUserChange: '${before}'.`;\n\n/** True when the live role already matches the declaration on every field the plugin stores. */\nexport const matches = (attributes: BaoProxmoxRoleAttributes, props: BaoProxmoxRoleProps) =>\n attributes.mintUser === props.mintUser &&\n sameTtl(props.ttl, attributes.ttl) &&\n sameTtl(props.maxTtl, attributes.maxTtl);\n",
|
|
73
73
|
"/**\n * The read Bao.ProxmoxRole makes of `<mount>/roles/<name>`, split from proxmox-role.ts so the diff,\n * reconcile and the rename's re-scope check share one definition of \"the live role\".\n */\nimport * as Effect from 'effect/Effect';\nimport { baoRead } from './bao-http.ts';\nimport { type BaoProxmoxRoleProps, attributesOf, rolePath } from './proxmox-role-form.ts';\n\n/**\n * The live role, or undefined when OpenBao answers 404.\n *\n * ⚠️ A missing MOUNT and a missing ROLE both read as undefined here, because both answer 404:\n * an absent role is a read that found nothing, and a path under no mount is OpenBao's\n * unsupported-path error, which is also a 404 (sdk/logical/response_util.go). They are not the\n * same failure — one is a typo in `mount`, the other is a role that has yet to be created — so\n * reconcile lets OpenBao's own `errors` through on the write rather than inventing a message.\n * A bad mount says \"no handler for route\".\n */\nexport const readRole = (props: Pick<BaoProxmoxRoleProps, 'mount' | 'name'>) =>\n Effect.gen(function* () {\n const live = yield* baoRead(rolePath(props.mount, props.name));\n if (live === undefined) return undefined;\n return attributesOf(props, live);\n });\n",
|
|
74
|
-
"/**\n * An OpenBao SSH secrets-engine role — `<mount>/roles/{name}`, `key_type=ca`. METADATA ONLY.\n *\n * ⛔ THE SIGNING KEY IS OUT OF SCOPE AND MUST STAY OUT. `ssh/config/ca` holds (or generates)\n * the CA private key and `ssh/sign/<role>` issues certificates. Neither is declarable\n * here, for the reason policy.ts spells out: Alchemy persists attributes to its state\n * store WITHOUT encrypting them, that store is the `alchemy` Postgres, and a nightly job\n * dumps it to a backup guest. A CA key there would outlive the vault that guards it. This\n * resource declares the SHAPE a signature must satisfy — principals, extensions, TTLs.\n *\n * ⛔ THE ROLE WRITE IS A FULL REPLACE, NOT A PATCH. OpenBao rebuilds the role entry from the\n * request body, so any field the write omits reverts to its ZERO value. Two things follow:\n * `resolve` in ssh-role-form.ts fills every optional prop with the default the write would\n * produce and `matches` compares all of it (an omitted prop asserts the default, it never\n * means \"don't care\"); and `wouldErase` below names the fields this resource does NOT\n * declare, so reconcile can REFUSE instead of quietly dropping someone's key-length floor.\n *\n * ⛔ `allowEmptyPrincipals: true` WITH AN EMPTY `allowedUsers` IS A SKELETON KEY. OpenBao\n * will sign a certificate carrying no principals, and OpenSSH accepts such a certificate\n * for ANY user on ANY host that trusts the CA. It defaults to false, and all three roles\n * on the live engine carry false (MEASURED). Do not set it true without pinning\n * `defaultCriticalOptions['force-command']` in the same declaration.\n *\n * ⛔ `ttl: '0'` DOES NOT MEAN \"NO EXPIRY\" AND IT DOES NOT MEAN \"SHORT\". It means the mount's\n * `default_lease_ttl`, and the live `ssh` mount leaves that at 0, which means the SYSTEM\n * default — 768h. A 32-day SSH certificate is the opposite of what an SSH CA is for.\n * State the duration. MEASURED: the live `node-admin` and `tim` roles are ttl 14400 /\n * max_ttl 28800 (4h / 8h); `ssh-host/roles/host` is 31536000 (365d), as a host cert should.\n *\n * ★ `defaultRemovalPolicy: 'retain'`. Deleting this role locks every operator out of the\n * estate — the memory note \"operator SSH is homeflare-bot@<host>\" is this CA. Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/unstable/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport {\n type BaoSshRoleAttributes,\n type BaoSshRoleForm,\n type BaoSshRoleProps,\n attributesOf,\n badDurations,\n matches,\n readPath,\n resolve,\n writeBody,\n} from './ssh-role-form.ts';\nimport { wouldErase } from './ssh-role-erase.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoSshRoleAttributes, BaoSshRoleProps };\n\nexport interface BaoSshRole extends Resource<\n 'Bao.SshRole',\n BaoSshRoleProps,\n BaoSshRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoSshRole = Resource<BaoSshRole>('Bao.SshRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the engine stores `roles/<name>` verbatim (builtin/logical/ssh/path_roles.go:602). */\nconst IDENTITY = roleIdentity<BaoSshRoleAttributes>('Bao.SshRole', readPath, 'ssh');\n\n/** Live role, plus the raw body — reconcile needs the raw half to see what it would erase. */\nconst readRole = (form: BaoSshRoleForm) =>\n Effect.gen(function* () {\n const live = yield* baoRead(readPath(form.mount, form.name));\n if (live === undefined) return undefined;\n return { attributes: attributesOf(form, live), live };\n });\n\nconst refuse = (message: string) => Effect.die(new Error(message));\n\nexport const BaoSshRoleProvider = () =>\n Provider.effect(\n BaoSshRole,\n Effect.succeed(\n BaoSshRole.Provider.of({\n /**\n * ⛔ `bao list ssh/roles` IS NOT A LIST OF THINGS THIS OWNS. Every role on the mount\n * answers, including the break-glass ones cut by hand at bringup. Returning them\n * would invite Alchemy to adopt — and then delete — the role that is the only way\n * back into the estate.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(resolve(olds));\n const ours = Effect.sync(\n () => found !== undefined && matches(found.attributes, resolve(olds)),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A role widened in the OpenBao\n * UI — one extra principal in `allowed_users` — is exactly the drift the check-*\n * gates exist to catch, and a provider that trusted its own state would report\n * `noop` straight through it.\n *\n * ⚠️ `wouldErase` is deliberately NOT consulted here. Extra hand-set fields are only\n * at risk when something actually writes; if every managed field already matches,\n * the honest answer is `noop` and nothing gets destroyed.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A RENAMED ROLE IS A NEW PATH, NOT AN EDIT. `ssh/roles/x` and `ssh-host/roles/x`\n * are different mounts with different CAs. Without this, changing `name` or\n * `mount` would write the new role and leave the old one signing certificates\n * for as long as anyone remembered its name. Judged before `isResolved(news)`, and\n * ⛔ a move onto a role that exists fails the plan (rename-identity.ts).\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n const form = resolve(news);\n const found = yield* readRole(form);\n if (found === undefined) return { action: 'update' } as const;\n return matches(found.attributes, form)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const form = resolve(news);\n const path = readPath(form.mount, form.name);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n\n const bad = badDurations(form);\n if (bad.length > 0) {\n return yield* refuse(\n `Bao.SshRole ${path}: ${bad.join(', ')} is not a duration parseDuration understands ` +\n '(`0` or `<n>s|m|h|d`). It would write, then report update on every plan forever.',\n );\n }\n /**\n * ⛔ A USER-CERT ROLE WITH NO PRINCIPALS SIGNS NOTHING. It is not dangerous — it\n * fails closed at sign time — but it is never what was meant, and the failure\n * surfaces hours later as \"ssh stopped working\" rather than here. The opposite\n * case, empty principals that are ALLOWED, is the skeleton key in the header.\n */\n if (\n form.allowUserCertificates &&\n form.allowedUsers.length === 0 &&\n !form.allowEmptyPrincipals\n ) {\n return yield* refuse(\n `Bao.SshRole ${path}: allowUserCertificates with an empty allowedUsers and ` +\n 'allowEmptyPrincipals false. Every sign request against it would be rejected.',\n );\n }\n\n const found = yield* readRole(form);\n if (found !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.SshRole ${path}`);\n if (found === undefined || !matches(found.attributes, form)) {\n if (found !== undefined) {\n const lost = wouldErase(found.live);\n if (lost.length > 0) {\n return yield* refuse(\n `Bao.SshRole ${path}: live role carries ${lost.join(', ')}, which this ` +\n 'resource does not declare and the full-replace write would ERASE. ' +\n 'Fold those settings into the declaration, or clear them by hand first.',\n );\n }\n }\n yield* baoWrite('PUT', path, writeBody(form));\n }\n /**\n * ⚠️ RE-READ RATHER THAN ECHO THE DECLARATION. The map encoding in the write was\n * wrong once already, unseen until 2026-09-21 (the ⛔ on mapValue), and a provider\n * that returned its own props would record a role it had never confirmed.\n */\n const after = yield* readRole(form);\n if (after === undefined) {\n return yield* refuse(\n `Bao.SshRole ${path}: write returned no error but the role is still absent.`,\n );\n }\n return after.attributes;\n }),\n\n /**\n * ⛔ DELETING THE ROLE DOES NOT REVOKE THE CERTIFICATES IT ALREADY SIGNED. OpenSSH\n * has no CRL here: every outstanding certificate stays valid for the rest of its\n * TTL, on every host trusting the CA, with no way to call it back short of a KRL\n * on each host. On the live `ssh-host` role that TTL is 365 days. Deleting is\n * therefore a change to who gets in NEXT, never a way to lock someone out now.\n * Idempotent as Alchemy requires — already gone is success.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(readPath(output.mount, output.name));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
74
|
+
"/**\n * An OpenBao SSH secrets-engine role — `<mount>/roles/{name}`, `key_type=ca`. METADATA ONLY.\n *\n * ⛔ THE SIGNING KEY IS OUT OF SCOPE AND MUST STAY OUT. `ssh/config/ca` holds (or generates)\n * the CA private key and `ssh/sign/<role>` issues certificates. Neither is declarable\n * here, for the reason policy.ts spells out: Alchemy persists attributes to its state\n * store WITHOUT encrypting them, that store is the `alchemy` Postgres, and a nightly job\n * dumps it to a backup guest. A CA key there would outlive the vault that guards it. This\n * resource declares the SHAPE a signature must satisfy — principals, extensions, TTLs.\n *\n * ⛔ THE ROLE WRITE IS A FULL REPLACE, NOT A PATCH. OpenBao rebuilds the role entry from the\n * request body, so any field the write omits reverts to its ZERO value. Two things follow:\n * `resolve` in ssh-role-form.ts fills every optional prop with the default the write would\n * produce and `matches` compares all of it (an omitted prop asserts the default, it never\n * means \"don't care\"); and `wouldErase` below names the fields this resource does NOT\n * declare, so reconcile can REFUSE instead of quietly dropping someone's key-length floor.\n *\n * ⛔ `allowEmptyPrincipals: true` WITH AN EMPTY `allowedUsers` IS A SKELETON KEY. OpenBao\n * will sign a certificate carrying no principals, and OpenSSH accepts such a certificate\n * for ANY user on ANY host that trusts the CA. It defaults to false, and all three roles\n * on the live engine carry false (MEASURED). Do not set it true without pinning\n * `defaultCriticalOptions['force-command']` in the same declaration.\n *\n * ⛔ `ttl: '0'` DOES NOT MEAN \"NO EXPIRY\" AND IT DOES NOT MEAN \"SHORT\". It means the mount's\n * `default_lease_ttl`, and the live `ssh` mount leaves that at 0, which means the SYSTEM\n * default — 768h. A 32-day SSH certificate is the opposite of what an SSH CA is for.\n * State the duration. MEASURED: the live `node-admin` and `tim` roles are ttl 14400 /\n * max_ttl 28800 (4h / 8h); `ssh-host/roles/host` is 31536000 (365d), as a host cert should.\n *\n * ★ `defaultRemovalPolicy: 'retain'`. Deleting this role locks every operator out of the\n * estate — the memory note \"operator SSH is homeflare-bot@<host>\" is this CA. Opt in with\n * `.pipe(RemovalPolicy.destroy())`; see resource.ts in <estate>/proxmox.\n */\nimport { Resource } from 'alchemy';\nimport { isResolved } from 'alchemy/Diff';\nimport * as Provider from 'alchemy/Provider';\nimport * as Effect from 'effect/Effect';\nimport type * as HttpClient from 'effect/http/HttpClient';\nimport { refuseTakeover } from '../ownership/adopt.ts';\nimport { ownedRead } from '../ownership/probe.ts';\nimport { provingResumes } from '../ownership/resume.ts';\nimport { baoDelete, baoRead, baoWrite } from './bao-http.ts';\nimport {\n type BaoSshRoleAttributes,\n type BaoSshRoleForm,\n type BaoSshRoleProps,\n attributesOf,\n badDurations,\n matches,\n readPath,\n resolve,\n writeBody,\n} from './ssh-role-form.ts';\nimport { wouldErase } from './ssh-role-erase.ts';\nimport { guardRename, judgeRename, roleIdentity } from './rename-identity.ts';\n\nexport type { BaoSshRoleAttributes, BaoSshRoleProps };\n\nexport interface BaoSshRole extends Resource<\n 'Bao.SshRole',\n BaoSshRoleProps,\n BaoSshRoleAttributes,\n never,\n HttpClient.HttpClient\n> {}\n\nexport const BaoSshRole = Resource<BaoSshRole>('Bao.SshRole', {\n defaultRemovalPolicy: 'retain',\n});\n\n/** Exact: the engine stores `roles/<name>` verbatim (builtin/logical/ssh/path_roles.go:602). */\nconst IDENTITY = roleIdentity<BaoSshRoleAttributes>('Bao.SshRole', readPath, 'ssh');\n\n/** Live role, plus the raw body — reconcile needs the raw half to see what it would erase. */\nconst readRole = (form: BaoSshRoleForm) =>\n Effect.gen(function* () {\n const live = yield* baoRead(readPath(form.mount, form.name));\n if (live === undefined) return undefined;\n return { attributes: attributesOf(form, live), live };\n });\n\nconst refuse = (message: string) => Effect.die(new Error(message));\n\nexport const BaoSshRoleProvider = () =>\n Provider.effect(\n BaoSshRole,\n Effect.succeed(\n BaoSshRole.Provider.of({\n /**\n * ⛔ `bao list ssh/roles` IS NOT A LIST OF THINGS THIS OWNS. Every role on the mount\n * answers, including the break-glass ones cut by hand at bringup. Returning them\n * would invite Alchemy to adopt — and then delete — the role that is the only way\n * back into the estate.\n */\n list: () => Effect.succeed([]),\n\n /** ⛔ Stateless: `Unowned` unless our own interrupted create made it (ownership/probe.ts). */\n read: Effect.fn(function* ({ fqn, instanceId, olds, output }) {\n const found = yield* readRole(resolve(olds));\n const ours = Effect.sync(\n () => found !== undefined && matches(found.attributes, resolve(olds)),\n );\n return yield* ownedRead({ fqn, instanceId, output }, found?.attributes, ours);\n }),\n\n /**\n * ⛔ IT COMPARES THE LIVE ROLE, NOT THE STORED DIGEST. A role widened in the OpenBao\n * UI — one extra principal in `allowed_users` — is exactly the drift the check-*\n * gates exist to catch, and a provider that trusted its own state would report\n * `noop` straight through it.\n *\n * ⚠️ `wouldErase` is deliberately NOT consulted here. Extra hand-set fields are only\n * at risk when something actually writes; if every managed field already matches,\n * the honest answer is `noop` and nothing gets destroyed.\n */\n diff: Effect.fn(function* ({ news, olds, output }) {\n /**\n * ⛔ A RENAMED ROLE IS A NEW PATH, NOT AN EDIT. `ssh/roles/x` and `ssh-host/roles/x`\n * are different mounts with different CAs. Without this, changing `name` or\n * `mount` would write the new role and leave the old one signing certificates\n * for as long as anyone remembered its name. Judged before `isResolved(news)`, and\n * ⛔ a move onto a role that exists fails the plan (rename-identity.ts).\n */\n const move = yield* judgeRename(IDENTITY, olds, news, output);\n // ★ No attributes: an unfinished generation, proven ours or not by provingResumes.\n if (output === undefined) return undefined;\n if (move !== undefined) return { action: 'replace' } as const;\n if (!isResolved(news)) return undefined;\n const form = resolve(news);\n const found = yield* readRole(form);\n if (found === undefined) return { action: 'update' } as const;\n return matches(found.attributes, form)\n ? ({ action: 'noop' } as const)\n : ({ action: 'update' } as const);\n }),\n\n reconcile: Effect.fn(function* ({ fqn, instanceId, news, output }) {\n const form = resolve(news);\n const path = readPath(form.mount, form.name);\n // ⛔ An `update` across a move the diff could not see — refused before any write.\n yield* guardRename(IDENTITY, news, output);\n\n const bad = badDurations(form);\n if (bad.length > 0) {\n return yield* refuse(\n `Bao.SshRole ${path}: ${bad.join(', ')} is not a duration parseDuration understands ` +\n '(`0` or `<n>s|m|h|d`). It would write, then report update on every plan forever.',\n );\n }\n /**\n * ⛔ A USER-CERT ROLE WITH NO PRINCIPALS SIGNS NOTHING. It is not dangerous — it\n * fails closed at sign time — but it is never what was meant, and the failure\n * surfaces hours later as \"ssh stopped working\" rather than here. The opposite\n * case, empty principals that are ALLOWED, is the skeleton key in the header.\n */\n if (\n form.allowUserCertificates &&\n form.allowedUsers.length === 0 &&\n !form.allowEmptyPrincipals\n ) {\n return yield* refuse(\n `Bao.SshRole ${path}: allowUserCertificates with an empty allowedUsers and ` +\n 'allowEmptyPrincipals false. Every sign request against it would be rejected.',\n );\n }\n\n const found = yield* readRole(form);\n if (found !== undefined)\n yield* refuseTakeover({ fqn, instanceId, output }, `Bao.SshRole ${path}`);\n if (found === undefined || !matches(found.attributes, form)) {\n if (found !== undefined) {\n const lost = wouldErase(found.live);\n if (lost.length > 0) {\n return yield* refuse(\n `Bao.SshRole ${path}: live role carries ${lost.join(', ')}, which this ` +\n 'resource does not declare and the full-replace write would ERASE. ' +\n 'Fold those settings into the declaration, or clear them by hand first.',\n );\n }\n }\n yield* baoWrite('PUT', path, writeBody(form));\n }\n /**\n * ⚠️ RE-READ RATHER THAN ECHO THE DECLARATION. The map encoding in the write was\n * wrong once already, unseen until 2026-09-21 (the ⛔ on mapValue), and a provider\n * that returned its own props would record a role it had never confirmed.\n */\n const after = yield* readRole(form);\n if (after === undefined) {\n return yield* refuse(\n `Bao.SshRole ${path}: write returned no error but the role is still absent.`,\n );\n }\n return after.attributes;\n }),\n\n /**\n * ⛔ DELETING THE ROLE DOES NOT REVOKE THE CERTIFICATES IT ALREADY SIGNED. OpenSSH\n * has no CRL here: every outstanding certificate stays valid for the rest of its\n * TTL, on every host trusting the CA, with no way to call it back short of a KRL\n * on each host. On the live `ssh-host` role that TTL is 365 days. Deleting is\n * therefore a change to who gets in NEXT, never a way to lock someone out now.\n * Idempotent as Alchemy requires — already gone is success.\n */\n delete: Effect.fn(function* ({ output }) {\n yield* baoDelete(readPath(output.mount, output.name));\n return undefined;\n }),\n }),\n ).pipe(Effect.map(provingResumes)),\n );\n",
|
|
75
75
|
"/**\n * The wire-and-form half of Bao.SshRole: normalisation, argv, and the equality that decides\n * whether a plan says `noop`. Split from ssh-role.ts for the 250-line cap.\n *\n * ⚠️ EVERY FIELD TYPE BELOW WAS MEASURED, not assumed — OpenBao v2.6.2, read from the live\n * engine's own `sys/internal/specs/openapi`, schema `SshWriteRoleRequest`:\n * `allowed_users`, `allowed_extensions`, `allowed_critical_options`, `allowed_domains`\n * → `string`. ONE COMMA-SEPARATED STRING. Not a list, however much it reads like one.\n * `default_extensions`, `default_critical_options`, `allowed_user_key_lengths`\n * → `object`, `format: map`.\n * `ttl`, `max_ttl`, `not_before_duration` → `integer`, SECONDS.\n * A role read echoes exactly those types back, which is why csvList and extMap exist.\n */\nimport { sha256 } from './digest.ts';\nimport { parseDuration, ttlSeconds } from './mount-form.ts';\nimport { sshMountOf as mountOf } from './mount-path.ts';\n\nexport interface BaoSshRoleProps {\n /** Role name, as `<mount>/roles/{name}` takes it. */\n name: string;\n /** Secrets engine mount, no trailing slash. Defaults to `ssh`; `ssh-host` also exists. */\n mount?: string;\n /** Principals a certificate may carry. `['*']` is OpenBao's wildcard. */\n allowedUsers: readonly string[];\n /** Principal used when a sign request does not name one. */\n defaultUser?: string;\n /** Sign user certificates. Defaults to false — OpenBao's own default. */\n allowUserCertificates?: boolean;\n /** Sign host certificates. Defaults to false — OpenBao's own default. */\n allowHostCertificates?: boolean;\n /** Host-cert roles only: the domains a host certificate may claim. */\n allowedDomains?: readonly string[];\n /** Host-cert roles only: allow `host.example.com` under an allowed `example.com`. */\n allowSubdomains?: boolean;\n /** Host-cert roles only: allow the bare allowed domain itself. */\n allowBareDomains?: boolean;\n /**\n * Extensions a REQUESTER may ask for — not the ones that get stamped on. `[]` means none\n * may be requested, which is what all three live roles carry; `['*']` allows any.\n */\n allowedExtensions?: readonly string[];\n /** Extensions stamped on every certificate, e.g. `{ 'permit-pty': '' }`. */\n defaultExtensions?: Readonly<Record<string, string>>;\n /** Critical options a requester may ask for — `force-command`, `source-address`. */\n allowedCriticalOptions?: readonly string[];\n /** Critical options stamped on every certificate. See the ⛔ on erasure in ssh-role.ts. */\n defaultCriticalOptions?: Readonly<Record<string, string>>;\n /** ⛔ Skeleton-key flag — read the ⛔ in ssh-role.ts before setting this true. */\n allowEmptyPrincipals?: boolean;\n /** Certificate lifetime, e.g. `4h`. ⛔ `0` is NOT \"no expiry\" — see ssh-role.ts. */\n ttl: string;\n /** Ceiling on a requested lifetime, e.g. `8h`. */\n maxTtl: string;\n}\n\n/**\n * Every prop resolved to the value the full-replace write will actually produce.\n *\n * ★ Derived rather than retyped: `Required` is the whole difference between the two, and a\n * hand-copied twin is the kind of thing that silently loses a field in review.\n */\nexport type BaoSshRoleForm = Required<BaoSshRoleProps>;\n\n/** ⛔ NO SECRET HERE — names, flags, TTLs and a digest. The CA key is out of scope. */\nexport interface BaoSshRoleAttributes extends Omit<BaoSshRoleForm, 'maxTtl' | 'ttl'> {\n /**\n * ⚠️ SECONDS, NOT A DURATION STRING. OpenBao stores seconds and a plan should show what is\n * stored; `4h` in the props and 14400 here are the same role. Rendering seconds back\n * into `4h` needs a table of unit rules that mount-form.ts and auth-role-form.ts each\n * already carry a private copy of — a third copy is how the three drift apart.\n */\n ttlSeconds: number;\n maxTtlSeconds: number;\n /** Always `ca` on a healthy role. Stored so an otp/dynamic role reads as a mismatch. */\n keyType: string;\n /** SHA-256 of the managed fields — safe to persist; see policy.ts. */\n digest: string;\n}\n\nexport { mountOf };\n\nexport const readPath = (mount: string | undefined, name: string) =>\n `${mountOf(mount)}/roles/${name}`;\n\nconst text = (value: unknown) => (typeof value === 'string' ? value : '');\n\nconst bool = (value: unknown, fallback: boolean) => (typeof value === 'boolean' ? value : fallback);\n\n/**\n * ⚠️ SETS, NOT SEQUENCES. OpenBao stores these as one comma-separated string and promises\n * nothing about the order it hands back. Sorting and de-duplicating on BOTH sides is what\n * stops every plan from reporting an update on a role nobody touched.\n */\nexport const csvList = (value: unknown): readonly string[] => {\n const parts = Array.isArray(value)\n ? value.filter((entry): entry is string => typeof entry === 'string')\n : text(value).split(',');\n return [\n ...new Set(parts.map((entry) => entry.trim()).filter((entry) => entry.length > 0)),\n ].sort();\n};\n\n/**\n * ⚠️ A MAP WITH NO PROMISED ORDER. Key order also decides the digest and the argv, so it is\n * normalised once here and everything else reads the sorted copy.\n */\nexport const extMap = (value: unknown): Record<string, string> => {\n const out: Record<string, string> = {};\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return out;\n const source = value as Record<string, unknown>;\n for (const key of Object.keys(source).sort()) out[key] = text(source[key]);\n return out;\n};\n\n/** ⛔ Every default here is what the WRITE produces, not what felt sensible. */\nexport const resolve = (props: BaoSshRoleProps): BaoSshRoleForm => ({\n name: props.name,\n mount: mountOf(props.mount),\n allowedUsers: csvList(props.allowedUsers),\n defaultUser: props.defaultUser ?? '',\n allowUserCertificates: props.allowUserCertificates ?? false,\n allowHostCertificates: props.allowHostCertificates ?? false,\n allowedDomains: csvList(props.allowedDomains),\n allowSubdomains: props.allowSubdomains ?? false,\n allowBareDomains: props.allowBareDomains ?? false,\n allowedExtensions: csvList(props.allowedExtensions),\n defaultExtensions: extMap(props.defaultExtensions ?? {}),\n allowedCriticalOptions: csvList(props.allowedCriticalOptions),\n defaultCriticalOptions: extMap(props.defaultCriticalOptions ?? {}),\n allowEmptyPrincipals: props.allowEmptyPrincipals ?? false,\n ttl: props.ttl,\n maxTtl: props.maxTtl,\n});\n\nexport const attributesOf = (\n form: BaoSshRoleForm,\n live: Record<string, unknown>,\n): BaoSshRoleAttributes => {\n const attrs = {\n name: form.name,\n mount: form.mount,\n allowedUsers: csvList(live['allowed_users']),\n defaultUser: text(live['default_user']),\n allowUserCertificates: bool(live['allow_user_certificates'], false),\n allowHostCertificates: bool(live['allow_host_certificates'], false),\n allowedDomains: csvList(live['allowed_domains']),\n allowSubdomains: bool(live['allow_subdomains'], false),\n allowBareDomains: bool(live['allow_bare_domains'], false),\n allowedExtensions: csvList(live['allowed_extensions']),\n defaultExtensions: extMap(live['default_extensions']),\n allowedCriticalOptions: csvList(live['allowed_critical_options']),\n defaultCriticalOptions: extMap(live['default_critical_options']),\n allowEmptyPrincipals: bool(live['allow_empty_principals'], false),\n keyType: text(live['key_type']) || 'ca',\n ttlSeconds: ttlSeconds(live['ttl']) ?? 0,\n maxTtlSeconds: ttlSeconds(live['max_ttl']) ?? 0,\n };\n return { ...attrs, digest: sha256(JSON.stringify(attrs)) };\n};\n\n/**\n * ⛔ THE MAPS CROSS THE WIRE AS JSON OBJECTS. A JSON STRING IS REJECTED, SO EVERY WRITE FAILED.\n * History: `bao write -output-curl-string` showed the CLI sending `k=v` values as strings,\n * so this once sent `\"{\\\"permit-pty\\\":\\\"\\\"}\"` on the reasoning that a `framework` TypeMap\n * JSON-decodes a string. ⚠️ IT DOES NOT. MEASURED 2026-09-21 against sdk v2.6.2 itself (a Go\n * probe of framework.FieldData.Validate, no server): TypeMap is `mapstructure.WeakDecode`\n * (framework/field_data.go:271-276), which refuses a string with \"expected type\n * 'map[string]interface {}', got unconvertible type 'string'\" — and framework/backend.go:\n * 281-285 answers that with a 400 before the handler runs. `\"{}\"` fails the same way, so every\n * Bao.SshRole write, not only those with extensions, would have been refused. It went unseen\n * because the adopted roles already matched and no write was ever sent. The same probe\n * accepted the object form and every other field of writeBody as sent.\n */\nconst mapValue = (map: Readonly<Record<string, string>>) => extMap(map);\n\n/**\n * ⛔ EVERY MANAGED FIELD IS SENT ON EVERY WRITE, INCLUDING THE FALSE ONES. The role write is\n * a full replace (see ssh-role.ts), so an omitted field is not \"left alone\" — it is reset.\n * Sending the resolved form makes the body and the declaration the same statement. Strings,\n * exactly the `k=v` pairs `bao write` sent, for `PUT <mount>/roles/<name>` — except the two\n * maps, which must be objects (the ⛔ on mapValue).\n */\nexport const writeBody = (form: BaoSshRoleForm): Record<string, unknown> => ({\n key_type: 'ca',\n allowed_users: form.allowedUsers.join(','),\n default_user: form.defaultUser,\n allow_user_certificates: String(form.allowUserCertificates),\n allow_host_certificates: String(form.allowHostCertificates),\n allowed_domains: form.allowedDomains.join(','),\n allow_subdomains: String(form.allowSubdomains),\n allow_bare_domains: String(form.allowBareDomains),\n allowed_extensions: form.allowedExtensions.join(','),\n default_extensions: mapValue(form.defaultExtensions),\n allowed_critical_options: form.allowedCriticalOptions.join(','),\n default_critical_options: mapValue(form.defaultCriticalOptions),\n allow_empty_principals: String(form.allowEmptyPrincipals),\n ttl: form.ttl,\n max_ttl: form.maxTtl,\n});\n\nconst sameList = (want: readonly string[], have: readonly string[]) =>\n want.length === have.length && want.every((entry, index) => entry === have[index]);\n\nconst sameMap = (\n want: Readonly<Record<string, string>>,\n have: Readonly<Record<string, string>>,\n) => {\n const keys = Object.keys(want);\n return keys.length === Object.keys(have).length && keys.every((key) => have[key] === want[key]);\n};\n\n/**\n * Compare in seconds, never as text — `60m` and `1h` are the same role.\n * ⚠️ An unparseable prop yields undefined, which equals no number, so it reports drift\n * rather than a false noop. `badDurations` is what turns that into a readable refusal.\n */\nconst sameTtl = (want: string, have: number) => parseDuration(want) === have;\n\n/**\n * ⛔ AN UNPARSEABLE TTL IS A PLAN THAT NEVER GOES GREEN. parseDuration understands `0` and\n * `<n>[smhd]` and nothing else. A prop like `4h30m` writes fine, reads back as 16200,\n * fails to parse on the want side, and reports `update` forever — and a resource that is\n * always dirty is one nobody reads the plan for any more.\n */\nexport const badDurations = (form: BaoSshRoleForm): readonly string[] =>\n (['ttl', 'maxTtl'] as const).filter((field) => parseDuration(form[field]) === undefined);\n\n/**\n * True when live already matches the declaration on every managed field.\n * ⛔ NOTHING IS SKIPPED FOR BEING UNDEFINED. mount.ts and auth-role.ts can treat an absent\n * prop as \"don't care\" because their writes are partial tunes; this one cannot, because\n * the write resets whatever it omits. Comparing the resolved form is what keeps a\n * hand-edited role from surviving forever behind a green plan.\n */\nexport const matches = (attributes: BaoSshRoleAttributes, form: BaoSshRoleForm) =>\n attributes.keyType === 'ca' &&\n sameList(form.allowedUsers, attributes.allowedUsers) &&\n attributes.defaultUser === form.defaultUser &&\n attributes.allowUserCertificates === form.allowUserCertificates &&\n attributes.allowHostCertificates === form.allowHostCertificates &&\n sameList(form.allowedDomains, attributes.allowedDomains) &&\n attributes.allowSubdomains === form.allowSubdomains &&\n attributes.allowBareDomains === form.allowBareDomains &&\n sameList(form.allowedExtensions, attributes.allowedExtensions) &&\n sameMap(form.defaultExtensions, attributes.defaultExtensions) &&\n sameList(form.allowedCriticalOptions, attributes.allowedCriticalOptions) &&\n sameMap(form.defaultCriticalOptions, attributes.defaultCriticalOptions) &&\n attributes.allowEmptyPrincipals === form.allowEmptyPrincipals &&\n sameTtl(form.ttl, attributes.ttlSeconds) &&\n sameTtl(form.maxTtl, attributes.maxTtlSeconds);\n",
|
|
76
76
|
"/**\n * Bao.SshRole's guard against its own full-replace write: the live fields a write would reset that\n * the declaration does not model. Split from ssh-role.ts, whose reconcile calls it.\n */\nimport { extMap } from './ssh-role-form.ts';\n\n/**\n * Fields this resource deliberately does not model, mapped to the value OpenBao's own write\n * puts there when nobody says otherwise. The templating flags change how a principal is\n * DERIVED at signing time, which is a different kind of decision from which principals\n * exist; the rest are issuance mechanics. MEASURED against all three live roles — every one\n * of them sits on exactly these values, so the guard below fires on nothing that exists.\n */\nconst UNMANAGED_DEFAULTS: Readonly<Record<string, unknown>> = {\n algorithm_signer: 'default',\n allow_commas_in_identity_templates: false,\n allow_user_key_ids: false,\n allowed_domains_template: false,\n allowed_users_template: false,\n default_extensions_template: false,\n default_user_template: false,\n issuer_ref: 'default',\n key_id_format: '',\n not_before_duration: 30,\n};\n\n/**\n * ⚠️ ABSENT AND EMPTY BOTH COUNT AS \"NEVER SET\". A role this resource wrote omits these\n * fields entirely, so a stricter test would refuse on the provider's own output and\n * deadlock the update after next.\n */\nconst isDefault = (live: Record<string, unknown>, field: string) =>\n live[field] === undefined || live[field] === '' || live[field] === UNMANAGED_DEFAULTS[field];\n\n/**\n * ⛔ THE FIELDS A WRITE WOULD SILENTLY DESTROY. Because the write is a full replace, a role\n * someone tuned by hand — `allowed_user_key_lengths` (a minimum RSA size), a\n * `key_id_format` the audit trail is grepped by, a `not_before_duration` widened to\n * survive clock skew, a non-default issuer — loses all of it the moment this resource\n * decides to update. A vanished key-length floor is a security regression that no plan\n * output would ever mention, and a vanished backdating window breaks signing on exactly\n * the skewed host it was added for. So reconcile refuses instead of writing.\n */\nexport const wouldErase = (live: Record<string, unknown>): readonly string[] => {\n const lost = Object.keys(UNMANAGED_DEFAULTS).filter((field) => !isDefault(live, field));\n if (Object.keys(extMap(live['allowed_user_key_lengths'])).length > 0) {\n lost.push('allowed_user_key_lengths');\n }\n return lost.sort();\n};\n"
|
|
77
77
|
],
|
|
78
|
-
"mappings": "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",
|
|
79
|
-
"debugId": "
|
|
78
|
+
"mappings": "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",
|
|
79
|
+
"debugId": "1C5D517C04F055DD64756E2164756E21",
|
|
80
80
|
"names": []
|
|
81
81
|
}
|