Skip to content

symfonic.platform.transport_procedure_update

transport_procedure_update

Native HTTP adapter for a scoped, lifecycle guarded procedure edit.

mount_procedure_update_route

mount_procedure_update_route(router: Any, *, procedures: Any, resolve: Any, scope_resolver: Any = None) -> None

Mount PATCH when a procedure administration port is configured.

Source code in src/symfonic/platform/transport_procedure_update.py
def mount_procedure_update_route(
    router: Any, *, procedures: Any, resolve: Any, scope_resolver: Any = None,
) -> None:
    """Mount PATCH when a procedure administration port is configured."""
    from fastapi import Header, HTTPException, Request

    @router.patch("/procedures/{node_id}")
    async def update_procedure(
        node_id: str,
        request: Request,
        x_tenant_id: str | None = Header(default=None),  # noqa: B008
        authorization: str | None = Header(default=None),  # noqa: B008
    ) -> dict[str, Any]:
        if scope_resolver is None:
            from symfonic.agent.fastapi.identity import request_user_id

            scope = await resolve(x_tenant_id, authorization)
            user_id = request_user_id(request)
        else:
            verified = await verified_principal(
                scope_resolver, x_tenant_id, authorization, request=request,
            )
            scope = verified.scope
            user_id = str(verified.principal_id)
        body = await request.json()
        # Outside the catch-all: a v1-declared router's typed refusal is a 501.
        v0_scope = memory_scope(scope)
        try:
            row = await procedures.amend_procedure(
                v0_scope, node_id,
                steps=body.get("steps"), properties=body.get("properties"),
                active=body.get("active"),
            )
        except Exception as unavailable:  # noqa: BLE001 - stored data stays private
            logger.error("Procedure update failed")
            raise HTTPException(500, "Internal server error") from unavailable
        if row is None:
            raise HTTPException(404, f"Node {node_id} not found")
        fields = sorted(field for field in ("steps", "properties", "active") if field in body)
        emit_audit_event(AuditLogEntry(
            tenant_id=str(scope.tenant_id), user_id=user_id,
            action="update_procedure", resource_type="procedure", resource_id=node_id,
            metadata={"fields": fields},
            ip_address=request.client.host if request.client else None,
            user_agent=request.headers.get("user-agent"),
        ))
        return row