secured-remote-docker-build/app/main.py
Lukas Schaefer 7aeef62a39
Implement auth for git repo
Signed-off-by: Lukas Schaefer <lukas@lschaefer.xyz>
2026-09-03 21:16:26 -04:00

62 lines
2.1 KiB
Python

import logging
from collections.abc import Iterator
from fastapi import FastAPI, HTTPException, Request, status
from fastapi.responses import StreamingResponse
from app.auth import verify_build_token
from app.builder import BuildError, cleanup_build, prepare_build, stream_build_and_push
from app.models import parse_json_build, parse_multipart_build
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
app = FastAPI(title="Docker Build Service", version="0.1.0")
@app.get("/health")
def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/build")
async def build(request: Request) -> StreamingResponse:
content_type = request.headers.get("content-type", "")
if content_type.startswith("multipart/form-data"):
build_request = await parse_multipart_build(request)
elif content_type.startswith("application/json"):
build_request = await parse_json_build(request)
else:
raise HTTPException(
status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
detail="Content-Type must be application/json or multipart/form-data",
)
claims = verify_build_token(build_request.token)
uploads = (
build_request.uploads
if build_request.uploads and claims.uploads_authorized()
else None
)
prepared = prepare_build(
claims,
commit=build_request.commit,
uploads=uploads,
repo_username=build_request.repo_username,
repo_password=build_request.repo_password,
)
def generate() -> Iterator[str]:
try:
yield from stream_build_and_push(
prepared,
tags=build_request.tags,
remote=build_request.remote,
username=build_request.username,
password=build_request.password,
)
except BuildError as exc:
# Headers are already sent as 200 once streaming starts.
yield f"\n[build-service] ERROR: {exc.message}\n"
finally:
cleanup_build(prepared)
return StreamingResponse(generate(), media_type="text/plain; charset=utf-8")