Frontend baked VITE_API_URL into the bundle at build time, so
published images pointed at whatever URL CI had — "fail to fetch"
for every other deployment. Bundle now defaults to same-origin
relative URLs and the frontend nginx proxies /api/ to the api
service over the Docker network; CORS becomes irrelevant.
- docker-compose.prod.yml: use ghcr images (FLOWSINT_VERSION,
default latest), drop build sections; bind postgres/redis/neo4j/
api ports to 127.0.0.1 — only 5173 faces the network
- nginx: /api/ reverse proxy, request-time DNS resolution, SSE
support (proxy_buffering off)
- Makefile: prod pulls instead of building; remove dead deploy
targets referencing nonexistent docker-compose.deploy.yml
- README: network/server deployment section (secrets checklist,
version pinning, TLS via reverse proxy)
pip-audit reported 27 vulnerabilities across 12 packages, including
cryptography PYSEC-2026-36 (CVSS 9.8) used by the vault, a starlette
Host-header path bypass, and python-multipart arbitrary file write.
- cryptography 45.0.7 -> 46.0.7 (pin was capped at <46)
- fastapi 0.115 -> 0.136, pulling starlette 0.46 -> 1.2
- python-multipart 0.0.20 -> 0.0.32
- pyjwt, urllib3, aiohttp, lxml, idna, mako and transitive bumps
- dev tools: pytest 8 -> 9 (requires pytest-httpx >=0.36), black 25 -> 26
All four module test suites pass (458 tests). pip-audit now reports
no known vulnerabilities.
Windows checkouts with core.autocrlf=true convert entrypoint.sh to
CRLF, which Docker copies into the image. The shebang then reads
#!/bin/sh\r and exec fails with 'no such file or directory'.
Also covers .env.example (trailing \r in env values) and Makefile.
Windows users hit failures with make-based install. Replicate
check-env + build + up targets as plain PowerShell/docker compose
commands for prod and dev.
parse_json unconditionally replaced every single quote with a double
quote (`.replace("'", '"')`) before calling json.loads. This corrupted
any valid JSON string value containing an apostrophe, e.g. a person's
surname "Sarah O'Brien" became "Sarah O"Brien", causing the parse to
fail with "Invalid JSON" and the whole import to be rejected.
Parse strict JSON first so well-formed payloads (including apostrophes
in string values) import correctly, and only fall back to the lenient
single-quote replacement for Python-dict-style payloads that are not
valid JSON on their own.
Adds regression tests covering an apostrophe-bearing JSON value and the
retained single-quoted fallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
FlowsintType declared an inner `class ConfigDict: extra = "allow"`, which
Pydantic v2 treats as an ordinary nested class and ignores entirely. The
base therefore fell back to the default extra="ignore", silently dropping
user-supplied extra properties on every entity type. Replaced with
model_config = ConfigDict(extra="allow"). Extra keys are now retained.
flowsint-types (44), flowsint-enrichers (12) and flowsint-core (390) suites pass.
The Scan model exposes details (JSON) and error (Text) columns, but the
enricher/flow tasks assigned to scan.results — a non-mapped attribute.
SQLAlchemy accepted the assignment silently, so commit() never persisted
it and the data was lost. Success paths now write scan.details; failure
paths write scan.error. ScanCreate.results renamed to details to match.
Scan repository tests pass.
allow_origins was ["*"] together with allow_credentials=True, which is
both insecure and rejected by browsers for credentialed requests. Read a
comma-separated ALLOWED_ORIGINS env var instead, defaulting to the Vite
dev origin http://localhost:5173. Documented in .env.example.
The production stage created the flowsint user and chowned all app
files to it, but the USER directive was commented out, so the API
ran as root. Uncommented it. Verified: image builds, container reports
whoami=flowsint and /health returns 200.
deps.py read AUTH_SECRET via os.getenv() before load_dotenv() ran,
yielding None when the secret was only present in .env. Import the
already-validated AUTH_SECRET from core.auth (loads dotenv first and
raises if unset) instead of re-reading it. Removes the dup + ordering bug.
Project-scoped Claude Code skill guiding enricher and type creation.
Whitelists .claude/skills/flowsint-transform-builder/ in .gitignore so
the skill ships with the repo while keeping the rest of .claude/ ignored.
The celery container builds from flowsint-api/Dockerfile which carries
a HEALTHCHECK directive that does `curl -f http://localhost:5001/health`.
The API container has an HTTP server on 5001 — celery doesn't, it's a
worker. So the inherited healthcheck always fails and `docker ps` shows
celery as (unhealthy) even when the worker is actively processing jobs.
This is cosmetic noise today but bites in two real ways: (1) restart
policies that key off health won't re-up celery on a real failure
because Docker can't tell good unhealthy from bad unhealthy, (2) any
service that adds `depends_on: celery: condition: service_healthy`
will refuse to start.
Fix: add a service-level healthcheck on celery in both compose files
(prod and dev) that uses celery's own `inspect ping` primitive
against the worker's broker. Compose-level healthcheck overrides the
Dockerfile-level one, so no Dockerfile change needed.
Smoke-tested locally: container goes from (unhealthy) to (healthy)
within ~30s of restart with no other changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add useCan hook reading permissions from $investigationId layout route loader
- Add $investigationId layout route to fetch investigation and share data with children
- Add share dialog with user search autocomplete (debounced) for collaborator management
- Add /dashboard/profile page for editing first name, last name, avatar URL
- Gate all edit/create/delete actions based on user role (deny by default)
- Graph: node drag, quick add, link creation, context menus, detail panel editing
- Analysis: editor readonly, title readonly, actions hidden for viewers
- Investigation: delete (owner only), share (admin+), new sketch/analysis (editor+)
- Settings: sketch info readonly, delete sketch and import hidden for viewers
- Selected items panel: enrich, delete, ask AI hidden for viewers
- Fix nav-user to show real user data instead of hardcoded placeholder
- Add user-display utils (getDisplayName, getInitials) shared across components
- Add avatar display in nav-user, case-header collaborators and share dialog
- Add ADMIN role to Role enum (OWNER > ADMIN > EDITOR > VIEWER)
- Update permission matrix: ADMIN can read/create/update/manage
- Fix get_with_relations bug filtering by owner_id (blocked non-owner collaborators)
- Add collaborator management methods to InvestigationRepository and InvestigationService
- Return user profile data in auth response