Allow admin token auth for stream endpoint

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-02 23:37:57 +00:00
parent e6dd6e851c
commit 2d520cf256

View File

@@ -155,7 +155,8 @@ async def create_run(
@router.post("/stream", response_model=RunStatus) @router.post("/stream", response_model=RunStatus)
async def create_stream_run( async def create_stream_run(
request: StreamRequest, request: StreamRequest,
ctx: UserContext = Depends(require_auth), req: Request,
ctx: UserContext = Depends(get_current_user),
): ):
"""Start a streaming video render. """Start a streaming video render.
@@ -163,13 +164,26 @@ async def create_stream_run(
(stream ...) form defining the pipeline. (stream ...) form defining the pipeline.
Assets can be referenced by CID or friendly name in the recipe. Assets can be referenced by CID or friendly name in the recipe.
Requires authentication OR admin token in X-Admin-Token header.
""" """
import uuid import uuid
import tempfile import tempfile
import os
from pathlib import Path from pathlib import Path
import database import database
from tasks.streaming import run_stream from tasks.streaming import run_stream
# Check for admin token if no user auth
admin_token = os.environ.get("ADMIN_TOKEN")
request_token = req.headers.get("X-Admin-Token")
admin_actor_id = req.headers.get("X-Actor-Id", "admin@local")
if not ctx and (not admin_token or request_token != admin_token):
raise HTTPException(401, "Authentication required")
# Use context actor_id or admin actor_id
actor_id = ctx.actor_id if ctx else admin_actor_id
# Generate run ID # Generate run ID
run_id = str(uuid.uuid4()) run_id = str(uuid.uuid4())
@@ -192,7 +206,7 @@ async def create_stream_run(
# Track ownership in item_types # Track ownership in item_types
await database.save_item_metadata( await database.save_item_metadata(
cid=recipe_id, cid=recipe_id,
actor_id=ctx.actor_id, actor_id=actor_id,
item_type="recipe", item_type="recipe",
description=f"Streaming recipe: {recipe_name}", description=f"Streaming recipe: {recipe_name}",
filename=f"{recipe_name}.sexp", filename=f"{recipe_name}.sexp",
@@ -203,7 +217,7 @@ async def create_stream_run(
naming = get_naming_service() naming = get_naming_service()
await naming.assign_name( await naming.assign_name(
cid=recipe_id, cid=recipe_id,
actor_id=ctx.actor_id, actor_id=actor_id,
item_type="recipe", item_type="recipe",
display_name=recipe_name, display_name=recipe_name,
) )
@@ -220,7 +234,7 @@ async def create_stream_run(
output_name=request.output_name, output_name=request.output_name,
duration=request.duration, duration=request.duration,
fps=request.fps, fps=request.fps,
actor_id=ctx.actor_id, actor_id=actor_id,
sources_sexp=request.sources_sexp, sources_sexp=request.sources_sexp,
audio_sexp=request.audio_sexp, audio_sexp=request.audio_sexp,
) )
@@ -231,7 +245,7 @@ async def create_stream_run(
celery_task_id=task.id, celery_task_id=task.id,
recipe=recipe_id or "streaming", # Use recipe CID if available recipe=recipe_id or "streaming", # Use recipe CID if available
inputs=[], # Streaming recipes don't have traditional inputs inputs=[], # Streaming recipes don't have traditional inputs
actor_id=ctx.actor_id, actor_id=actor_id,
dag_json=request.recipe_sexp, # Store recipe content for viewing dag_json=request.recipe_sexp, # Store recipe content for viewing
output_name=request.output_name, output_name=request.output_name,
) )