molecule-core/workspace/requirements.txt
Hongming Wang d1de330152 feat(workspace): /internal/chat/uploads/ingest endpoint (RFC #2312, PR-B)
Stacked on PR-A (#2313). The platform-side rewrite that actually calls
this endpoint lands in PR-C; this PR adds the workspace-side consumer
+ hardening so PR-C is a small Go-only diff.

What this adds:

  * platform_inbound_auth.py — auth gate mirroring transcript_auth.py.
    Reads /configs/.platform_inbound_secret (delivered by the PR-A
    provisioner). Fail-closed when the file is missing/empty/unreadable.
    Constant-time compare via hmac.compare_digest.

  * internal_chat_uploads.py — POST /internal/chat/uploads/ingest.
    Multipart parse → sanitize each filename → write to
    /workspace/.molecule/chat-uploads/<random>-<name> with
    O_CREAT|O_EXCL|O_NOFOLLOW. Same response shape (uri/name/mimeType/
    size + workspace: URI scheme) as the legacy Go handler — canvas /
    agent code that resolves "workspace:..." paths keeps working.

  * Wired into workspace/main.py via starlette_app.add_route alongside
    the existing /transcript route.

  * python-multipart>=0.0.18 added to requirements.txt (Starlette's
    Request.form() needs it; ≥ 0.0.18 closes CVE-2024-53981).

Test coverage (36 tests, all green; full workspace suite 1266 passed):

  * test_platform_inbound_auth.py — 14 tests:
      happy path, fail-closed on missing file, empty file, whitespace-
      only file, missing/case-wrong/empty Bearer prefix, in-process
      cache, default CONFIGS_DIR fallback, end-to-end file → authorized.

  * test_internal_chat_uploads.py — 22 tests:
      sanitize_filename matrix (incl. ../traversal, CJK chars, length
      truncation), 401 on missing/wrong/no-secret-file bearer, single +
      batch upload happy paths, unique random prefix on duplicate names,
      mimetype guess fallback, 400 on missing files field, 413 on per-
      file + total-body oversize, symlink-at-target refusal (with
      sentinel-content unchanged assertion).

Why this is safe to ship before PR-C:

  * No platform-side caller yet → no behavior change visible to users.
  * Auth fails closed; nothing on the network can hit a write path
    until the platform forwards with the matching bearer.
  * Workspace's existing routes (/health, /transcript, /handle/*) are
    unchanged.

Refs #2312 (parent RFC), #2308 (chat upload 503 incident).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 14:16:32 -07:00

45 lines
1.7 KiB
Plaintext

# Base image — bare minimum for A2A server and adapter loading
# Agent-specific deps are in adapters/<runtime>/requirements.txt
# and installed at container startup via entrypoint.sh
# A2A protocol
# KI-009 a2a-sdk v1 migration (2026-04-24): bumped from ==0.3.25.
# v1.0 removes A2AStarletteApplication → Starlette route factory pattern.
# Rollback: pin ==0.3.25 and revert main.py + executor changes.
a2a-sdk[http-server]>=1.0.0,<2.0
# HTTP / server
httpx>=0.28.1
uvicorn>=0.46.0
starlette>=0.38.0
websockets>=16.0
# multipart/form-data parser — required for Starlette's Request.form() on
# /internal/chat/uploads/ingest. Pinned ≥ 0.0.18 because earlier versions
# had a CVE-2024-53981 (DoS via malformed boundary).
python-multipart>=0.0.18
# Config parsing
pyyaml>=6.0
# Shared tools framework (used by coordinator, delegation, memory, sandbox)
langchain-core>=0.3.0
# OpenTelemetry — workspace-level distributed tracing
# tools/telemetry.py gracefully degrades (noop) when these are absent,
# but they are required for actual trace export.
opentelemetry-api>=1.24.0
opentelemetry-sdk>=1.41.1
# OTLP/HTTP exporter: sends spans to any OTEL collector and to Langfuse ≥4
opentelemetry-exporter-otlp-proto-http>=1.24.0
# SQLAlchemy — used by molecule_audit ledger (EU AI Act Annex III compliance)
sqlalchemy>=2.0.0
# Temporal durable execution (optional)
# tools/temporal_workflow.py wraps task execution in Temporal workflows so
# tasks survive crashes and can resume. The module and TemporalWorkflowWrapper
# load cleanly without this package — all paths fall back to direct execution.
# Requires a running Temporal server; set TEMPORAL_HOST=<host>:7233 to enable.
temporalio>=1.26.0