LetsBeBiz-Redesign/letsbe-orchestrator/app/playbooks/vaultwarden.py

122 lines
3.4 KiB
Python
Raw Permalink Normal View History

"""Vaultwarden password manager deployment playbook.
Defines the steps required to set up Vaultwarden on a tenant server
(ENV_UPDATE + DOCKER_RELOAD). No Playwright setup needed - Vaultwarden
uses a web-based registration flow that doesn't require automation.
Tenant servers must have stacks and env templates under /opt/letsbe.
"""
import uuid
from typing import Any
from pydantic import BaseModel, Field
from sqlalchemy.ext.asyncio import AsyncSession
from app.models.task import Task, TaskStatus
class CompositeStep(BaseModel):
"""A single step in a composite playbook."""
type: str = Field(..., description="Task type (e.g., ENV_UPDATE, DOCKER_RELOAD)")
payload: dict[str, Any] = Field(
default_factory=dict, description="Payload for this step"
)
# LetsBe standard paths
VAULTWARDEN_ENV_PATH = "/opt/letsbe/env/vaultwarden.env"
VAULTWARDEN_STACK_DIR = "/opt/letsbe/stacks/vaultwarden"
def build_vaultwarden_setup_steps(
*,
domain: str,
admin_token: str,
signups_allowed: bool = True,
) -> list[CompositeStep]:
"""
Build the sequence of steps required to set up Vaultwarden.
Assumes the env file already exists at /opt/letsbe/env/vaultwarden.env
(created by provisioning/env_setup.sh).
Args:
domain: The domain for Vaultwarden (e.g., "vault.example.com")
admin_token: Admin panel access token
signups_allowed: Whether new user registration is allowed
Returns:
List of 2 CompositeStep objects:
1. ENV_UPDATE - patches DOMAIN, ADMIN_TOKEN, SIGNUPS_ALLOWED
2. DOCKER_RELOAD - restarts the vaultwarden stack with pull=True
"""
steps = [
# Step 1: Update environment variables
CompositeStep(
type="ENV_UPDATE",
payload={
"path": VAULTWARDEN_ENV_PATH,
"updates": {
"DOMAIN": f"https://{domain}",
"ADMIN_TOKEN": admin_token,
"SIGNUPS_ALLOWED": str(signups_allowed).lower(),
},
},
),
# Step 2: Reload Docker stack
CompositeStep(
type="DOCKER_RELOAD",
payload={
"compose_dir": VAULTWARDEN_STACK_DIR,
"pull": True,
},
),
]
return steps
async def create_vaultwarden_setup_task(
*,
db: AsyncSession,
tenant_id: uuid.UUID,
agent_id: uuid.UUID | None,
domain: str,
admin_token: str,
signups_allowed: bool = True,
) -> Task:
"""
Create and persist a COMPOSITE task for Vaultwarden setup.
Args:
db: Async database session
tenant_id: UUID of the tenant
agent_id: Optional UUID of the agent to assign the task to
domain: The domain for Vaultwarden
admin_token: Admin panel access token
signups_allowed: Whether new user registration is allowed
Returns:
The created Task object with type="COMPOSITE"
"""
steps = build_vaultwarden_setup_steps(
domain=domain,
admin_token=admin_token,
signups_allowed=signups_allowed,
)
task = Task(
tenant_id=tenant_id,
agent_id=agent_id,
type="COMPOSITE",
payload={"steps": [step.model_dump() for step in steps]},
status=TaskStatus.PENDING.value,
)
db.add(task)
await db.commit()
await db.refresh(task)
return task