2 Commits

Author SHA1 Message Date
Evil0ctal cac61daf2f feat: routes, MCP, CLI, ops, worker and containers; close three integration gaps
Six modules built in parallel, then each reviewed by an independent adversarial
pass. 40 OpenAPI paths, an MCP server, a CLI, the operational features, the task
worker and a multi-stage image with production compose.

Three gaps only visible where the modules meet, all found by running the stack
rather than by reading it:

- MCP was never mounted. register_routes now calls mount(), which also chains
  the streamable-http session manager onto the application lifespan: a mounted
  ASGI app receives no lifespan events of its own, and without that the endpoint
  fails with "Task group is not initialized".
- The worker had no definition for the logical "parse" endpoint, so both
  POST /api/v1/parse and the MCP parse_url tool - the two entry points a
  first-time user is most likely to try - failed with "unknown endpoint".
  dtk.worker.parsing expands the short link, identifies the resource and maps it
  onto a registered endpoint. Expansion is the security-sensitive half: a short
  link cannot be validated before it is followed, so the target is checked
  against the allowlist after every hop and the hop count is bounded. A test
  asserts a short link redirecting to the cloud metadata address is refused.
- The console was not served. The build output is copied to /app/web/dist and
  the image already exported DTK_CONSOLE_DIR; the code simply derived its path
  from __file__, which inside the image points into site-packages. It now reads
  the variable, with fallbacks that keep a source checkout working. The SPA
  fallback declines anything under the API prefixes, so a mistyped endpoint
  still returns a JSON envelope rather than the console's HTML with status 200.

Verified against the real stack, not a mock: docker compose up, all services
healthy, migrations producing 12 tables, 3 hypertables and 2 continuous
aggregates, the setup token read from the container log, the admin created and
the endpoint then permanently closed, login, the error envelope, three rejected
SSRF shapes, both languages, OpenAPI, the docs and the console. 25 of 25.

1316 unit and replay tests pass.
2026-09-07 06:08:08 -07:00
Evil0ctal a64d2e739f test: full-stack smoke script
Brings the compose project up, waits for health, and walks the contract a real
deployment has to satisfy: migrations produce 11 tables, 3 hypertables and both
continuous aggregates; the setup token appears in the container log and the
endpoint closes permanently afterwards; the failure envelope carries a stable
code and a request_id; three SSRF shapes are rejected, including the metadata
address and a lookalike host; messages differ between ?lang=en and ?lang=zh;
OpenAPI, the docs and the console are all served.

It always tears down with -v, including on failure, so a run cannot leave stray
containers or volumes behind. `--keep` opts out for inspection, and `make clean`
removes both the test and the smoke projects.

The setup token is read from the log rather than any HTTP response on purpose:
under Docker's userland proxy every request appears to come from the bridge
gateway, so a source-IP check would admit the whole internet.
2026-09-07 05:16:34 -07:00