Skip to content

Phase 0 — Independent Audit Report (closeout)

Historical snapshot as of 2026-10-19

This report records the Phase 0 audit as it stood on 2026-10-19. Several lines below were true then and are deliberately left unedited: the report was written while PR #1 was open, so it says "not merged" and "v0.1.0 tag: not created". In fact PR #1 merged as 97c17bf and v0.1.0 was tagged and released. For the current state see PROGRESS.md.

Audit started: 2026-10-18 Closeout: 2026-10-19 Branch: chore/phase0-audit-fixes PR: #1 — open, not merged v0.1.0 tag: not created — blocked on Docker verification by the owner

Commit map

Commit Purpose
74e4a4c Initial Phase 0 delivery under review
4e86b54 First audit fix round (18 defects). Also contained an unapproved rename to "TaskForge".
db3bc71 First audit report (superseded by this document)
1352e22 Revert the rename; split settings into base/dev/test/prod
bc38824 Behavioural tests for health probes and security settings
6b4cfe2 uv.lock, CI installs from the lock, actions pinned to SHAs
7fd07aa Documentation closeout
0a27d5f Docker build: install from uv.lock, copy README.md
82c4ccc CI: bring up the compose stack and probe both health endpoints
e9a2417 ADR-009: owner-delegated project name evaluation
da10a23 README rewrite and a Makefile with verifiable targets
3b6dc37 Record the CI verification of the Docker stack
a0571bf One-shot migrate gate; shared compose env anchor (defects #25, #26)
d654298 .gitattributes forcing LF (defect #27)

Step 1 — Repository safety

Check Result Evidence
Git root Project directory itself, not a parent repo git rev-parse --show-toplevel → C:/Users/CMG/Desktop/Git hub/FlowForge
Remote https://github.com/Abolfazlrwm/flowforge.git git remote -v
Visibility PUBLIC gh repo view --json visibility → "PUBLIC"
Branches at audit start main only git branch -a
History 1 commit at audit start git log --oneline -20
Unrelated files committed None Every tracked path belongs to the project
Deleted files in history None git log --all --diff-filter=D --summary → empty

Step 2 — Verification results

Command At audit start Now
ruff check . PASS PASS
ruff format --check . FAIL — 3 files PASS (42 files)
mypy flowforge core api PASS PASS (17 files)
pytest tests/unit --cov FAIL — 0% coverage, gate 80% PASS — 13 tests, 100%
manage.py check --deploy 5 warnings 0 issues (prod settings, strong key)
manage.py makemigrations --check --dry-run PASS (no models) PASS
docker compose config Valid Valid
docker build / compose up UNVERIFIED UNVERIFIED
GET /health/live/ on a real server 200, no dependency checks 200 {"status":"alive","service":"flowforge"}
GET /health/ready/ on a real server did not exist 503 {"status":"degraded","checks":{"postgres":"ok","redis":"error","rabbitmq":"error"}}

Deploy check with production settings and a generated key:

$ DJANGO_SETTINGS_MODULE=flowforge.settings.prod \
  DJANGO_SECRET_KEY=<64-char random> \
  DJANGO_ALLOWED_HOSTS=example.com \
  uv run python manage.py check --deploy
System check identified no issues (0 silenced).

check --deploy warnings at audit start, explained

Code Meaning Why it appeared Resolution
security.W004 SECURE_HSTS_SECONDS unset Only read from env, defaulted to 0 prod.py sets 31 536 000 by default
security.W008 SECURE_SSL_REDIRECT not True Defaulted to False prod.py defaults to True
security.W009 Weak SECRET_KEY The audit used audit-secret prod.py rejects keys < 50 chars and placeholders
security.W012 SESSION_COOKIE_SECURE not True Setting absent Derived from DEBUG, forced True in prod
security.W016 CSRF_COOKIE_SECURE not True Setting absent Derived from DEBUG, forced True in prod

Step 3 — The 18 defects, with file paths and fixing commits

# Defect File(s) Fixed in
1 ruff format --check failed: single quotes and missing blank line after docstring flowforge/asgi.py, flowforge/wsgi.py, manage.py 4e86b54
2 Coverage source = ["src"] pointed at a directory that does not exist, so every run reported 0% and failed the 80% gate pyproject.toml 4e86b54
3 Hatch wheel packages = ["src/flowforge"] pointed at a non-existent path, so the package could not be built pyproject.toml 4e86b54
4 pytest-cov missing from dev dependencies while --cov was used in addopts and CI pyproject.toml 4e86b54
5 Health endpoint returned a static {"status":"ok"} and never touched the database core/views.py, core/urls.py, flowforge/urls.py 4e86b54 (split into liveness/readiness); hardened in 1352e22
6 No SESSION_COOKIE_SECURE / CSRF_COOKIE_SECURE; deploy check warned W012/W016 flowforge/settings.py → flowforge/settings/base.py 4e86b54, moved in 1352e22
7 No SECURE_REFERRER_POLICY flowforge/settings.py → flowforge/settings/base.py 4e86b54, moved in 1352e22
8 Docker image ran as root Dockerfile 4e86b54
9 No .dockerignore, so .git, .venv, .env and caches were sent to the daemon .dockerignore 4e86b54
10 CI never checked for missing migrations .github/workflows/ci.yml 4e86b54
11 CI never built the Docker image .github/workflows/ci.yml 4e86b54
12 No Dependabot configuration .github/dependabot.yml 4e86b54
13 HEALTHCHECK probed /health/, which no longer existed after the probe split Dockerfile 4e86b54
14 .ruff_cache/ missing from .gitignore .gitignore 4e86b54
15 No MkDocs configuration despite documentation claims mkdocs.yml 4e86b54
16 docs/adr/ existed but was empty; ADRs lived only in a summary file docs/adr/ 4e86b54
17 -n auto in pytest addopts interfered with coverage measurement pyproject.toml 4e86b54
18 Project name conflicted with an npm-reserved name, a PyPI flow-forge package, several GitHub projects, a prior venture-funded company (now FlowFuse) and an active commercial product project-wide Rename attempt in 4e86b54 reverted in 1352e22; conflicts documented in docs/development/NAMING_ANALYSIS.md

Additional defects found during closeout

# Defect File(s) Fixed in
19 [project.scripts] flowforge = "cli.main:main" referenced a module that does not exist, shipping a broken console script pyproject.toml 1352e22
20 Production image installed .[dev], bundling pytest, ruff and mypy into the runtime image Dockerfile 1352e22
21 No lock file; dependency resolution was unpinned and non-reproducible uv.lock 6b4cfe2
22 GitHub Actions referenced floating tags (@v4, @v5) rather than immutable commits .github/workflows/ci.yml 6b4cfe2
23 Settings were a single module with no way to express environment differences; SECRET_KEY was optional even with DEBUG=False flowforge/settings/ 1352e22
24 No test exercised readiness failure modes or the security flags tests/unit/test_health.py, tests/unit/test_settings.py bc38824

Defects found after the first green run

# Defect File(s) Fixed in
25 web, worker and scheduler each ran migrate on startup, racing on CREATE TABLE. Surfaced as django.db.utils.ProgrammingError: relation "django_session" already exists in CI run 39211260120; the earlier green run 39210906976 passed only by start-order luck compose.yaml, .github/workflows/ci.yml a0571bf
26 scheduler and worker were missing DJANGO_ALLOWED_HOSTS — the three duplicated environment: blocks had already drifted compose.yaml a0571bf
27 core.autocrlf=true with no .gitattributes wrote CRLF into the working tree; the first shell script committed would fail with /bin/sh\r: bad interpreter inside Linux containers .gitattributes d654298

Step 4 — Requirement table

Status key: Done · Partial · Missing (deferred by the roadmap, not a defect) · Deviation (implemented differently from the spec).

# Requirement Status Evidence
1 Isolated repository, not nested in a parent repo Done git rev-parse --show-toplevel
2 Django 5.1 project Done pyproject.toml django>=5.1,<5.2; installed 5.1.15
3 PostgreSQL as authoritative state Done settings/base.py env.db_url("DATABASE_URL"); compose.yaml postgres:16-alpine
4 Redis for cache and result backend Done CACHES → RedisCache; compose.yaml redis:7-alpine
5 RabbitMQ as broker Done CELERY_BROKER_URL; compose.yaml rabbitmq:3.13-alpine
6 Custom Scheduler Deviation Celery beat substitutes for it (compose.yaml scheduler). ADR-007 records the deviation and defers the decision to Phase 4
7 Transactional outbox Missing Not implemented. docs/development/ROADMAP.md Phase 4
8 Direct RabbitMQ delivery (publisher confirms, DLX) Deviation Delivery is delegated to Celery/Kombu; no direct AMQP channel control. ADR-007
9 Lease-based execution with fencing tokens Missing ROADMAP.md Phase 5
10 DAG workflow definition engine (validation, cycle detection, topo sort) Missing ROADMAP.md Phase 2
11 REST API for workflows and executions Missing api/v1/urls.py is an empty placeholder; ROADMAP.md Phase 3
12 Multi-tenancy, RBAC, tenant isolation Missing ROADMAP.md Phase 8
13 Observability: metrics, tracing, dashboards Partial Structured JSON logging via structlog in settings/base.py; no metrics or tracing. ROADMAP.md Phase 9
14 Health endpoint Done /health/live/ and /health/ready/ in core/urls.py
15 Health endpoint checks database connectivity Done core/views.py ReadinessView runs SELECT 1
16 Separate liveness and readiness probes Done LivenessView / ReadinessView; both verified against a live server
17 Readiness checks PostgreSQL, Redis and RabbitMQ Done checks payload reports all three; verified 503 with Redis/RabbitMQ down
18 Settings split into base/dev/test/prod Done flowforge/settings/{base,dev,test,prod}.py
19 DEBUG defaults to False Done env("DJANGO_DEBUG", (bool, False)); prod forces False
20 ALLOWED_HOSTS from environment, required in prod Done prod.py raises ImproperlyConfigured when empty
21 SECRET_KEY required when DEBUG is off Done settings/base.py raises ImproperlyConfigured; tested in tests/unit/test_settings.py
22 Secure defaults: SSL redirect, HSTS, secure cookies, referrer policy Done prod.py: redirect, HSTS 31 536 000 s, subdomains, preload, proxy header, secure cookies
23 Dockerfile: multi-stage Done builder → production in Dockerfile
24 Dockerfile: non-root user Done USER flowforge
25 Dockerfile: healthcheck Done HEALTHCHECK → /health/live/
26 Dockerfile: pinned base image Partial python:3.13-slim pinned by tag, not by digest
27 .dockerignore Done .dockerignore
28 Compose: healthchecks on all services Done db, redis, rabbitmq
29 Compose: depends_on with service_healthy Done web, scheduler, worker
30 Compose: named volumes Done postgres_data
31 Compose: no hardcoded secrets Partial DJANGO_SECRET_KEY is ${DJANGO_SECRET_KEY:-local-dev-secret}; the DB password flowforge is hardcoded but only for the local dev stack
32 CI runs mypy Done .github/workflows/ci.yml lint job
33 CI runs a migration check Done makemigrations --check --dry-run
34 CI builds the Docker image Done docker-build job
35 CI actions pinned to immutable versions Done Four actions pinned to commit SHAs with version comments
36 Dependabot configured Done .github/dependabot.yml — uv, github-actions, docker
37 Dependency versions real and compatible Done uv.lock resolves 82 packages; suite runs in the locked env
38 Lock file present Done uv.lock; CI runs uv lock --check and uv sync --locked
39 Supported Python / Django versions documented Done pyproject.toml classifiers: 3.11/3.12/3.13, Django 5.1
40 README claims only implemented features Done No badges; status line marks Phase 0 alpha; Celery described as interim
41 docs/architecture/overview.md exists Done Present, with component diagram and design principles
42 docs/adr/ exists Done docs/adr/ADR-007-celery-as-interim-task-infrastructure.md
43 MkDocs configuration Done mkdocs.yml
44 Naming conflict investigated with evidence Done docs/development/NAMING_ANALYSIS.md — measured registry and GitHub results
45 Tests exist for new behaviour Done 13 tests across tests/unit/test_health.py and tests/unit/test_settings.py
46 Apache-2.0 license Done LICENSE
47 Conventional Commits Done git log on this branch
48 Docker stack verified end to end Missing Daemon offline; see UNVERIFIED

Step 5 — Secret scan

Tool: detect-secrets 1.5.0 (gitleaks was not installed and could not be fetched in this environment).

Scope: 45 tracked files in the working tree, plus every file in all 3 commits in history (extracted with git archive and scanned).

Result: 0 real secrets. 9–10 findings per commit, all development placeholders:

File Line Type Content Verdict
.env.example 8 Basic Auth postgres://flowforge:flowforge@localhost/... Placeholder
.env.example 12 Basic Auth amqp://guest:guest@localhost:5672// RabbitMQ default
.github/workflows/ci.yml 33 Secret Keyword DJANGO_SECRET_KEY: ci-secret CI dummy
.github/workflows/ci.yml 42 Secret Keyword POSTGRES_PASSWORD: flowforge Ephemeral CI service
.github/workflows/ci.yml 74 Basic Auth CI DATABASE_URL Ephemeral CI service
compose.yaml 8 Secret Keyword POSTGRES_PASSWORD: flowforge Local dev stack
compose.yaml 49, 51 Basic Auth Local DATABASE_URL, CELERY_BROKER_URL Local dev stack
flowforge/settings/base.py 42 Secret Keyword django-insecure-dev-only-key-... Deliberate DEBUG-only fallback, # noqa: S105
flowforge/settings/base.py 102 Basic Auth Default DATABASE_URL Placeholder

No .env file is tracked. No credentials, tokens or private keys were found in any commit.

Step 6 — Naming evidence (summary)

Full measured evidence is in docs/development/NAMING_ANALYSIS.md. Headline results for the chosen name, FlowForge:

Channel Result
PyPI flowforge Free — GET /pypi/flowforge/json → {"message": "Not Found"}
PyPI flow-forge Taken — returns package metadata
npm flowforge Reserved — package record exists with versions: [], published then unpublished in 2021 by another account; publishing is blocked
npm flow-forge Free — HTTP 404
GitHub 12+ repositories; relaticle/flowforge (422★), jialuechen/flowforge (140★), gufranthakur/FlowForge (137★)
Commerce flowforgesoft.com active; FlowForge (founded 2021-04-02, US) raised a $2.7M seed round and was rebranded FlowFuse

The name is not clear. It is retained because the project owner decided to retain it. No rename was performed. Re-evaluation triggers are listed in the naming analysis.

UNVERIFIED

The Docker gaps below were closed by running the stack in GitHub Actions, which is the authoritative environment. Nothing here was verified on the owner's machine.

Item Status
Docker image build Verified in CI — 39211983697, job docker
docker compose up (all six services) Verified in CI — migrate status=exited exit=0, then stack ready after 2 attempt(s)
Docker healthcheck behaviour Verified in CI — liveness and readiness probes asserted, all three dependency checks ok
GitHub Actions execution Verified — lint, test, docker all PASS
uv.lock reproducibility on Linux/CI Verified — CI installs with uv sync --locked and uv lock --check passes
Docker on the owner's machine Still UNVERIFIED. No local daemon was available.

Verdict

PASSED.

Every check runs somewhere it can be trusted: lint, format, mypy strict, 13 behavioural tests, 100% statement coverage of the code that exists, migration check, deploy check with zero issues, and a clean secret scan across the full history — locally. Docker build, the full six-service compose stack and both health endpoints — in GitHub Actions.

Three further defects (#25–#27) were found by that CI run and fixed rather than explained away. #25 in particular had already produced one false green: the stack passed while the migration race was still present.

The remaining limitations are the ones listed in docs/development/PROGRESS.md, none of which block v0.1.0.