Files
DECNET/DEBT.md
anti c7713c6228 feat(imap,pop3): full IMAP4rev1 + POP3 bait mailbox implementation
IMAP: extended to full IMAP4rev1 — 10 bait emails (AWS keys, DB creds,
tokens, VPN config, root pw etc.), LIST/LSUB/STATUS/FETCH/UID FETCH/
SEARCH/CLOSE/NOOP, proper SELECT untagged responses (EXISTS, UIDNEXT,
FLAGS, PERMANENTFLAGS), CAPABILITY with IDLE/LITERAL+/AUTH=PLAIN.
FETCH correctly handles sequence sets (1:*, 1:3, *), item dispatch
(FLAGS, ENVELOPE, BODY[], RFC822, RFC822.SIZE), and places body literals
last per RFC 3501.

POP3: extended with same 10 bait emails, fixed banner env var key
(POP3_BANNER not IMAP_BANNER), CAPA fully populated (TOP/UIDL/USER/
RESP-CODES/SASL), TOP (headers + N body lines), UIDL (msg-N format),
DELE/RSET with _deleted set tracking, NOOP. _active_messages() helper
excludes DELE'd messages from STAT/LIST/UIDL.

Both: DEBT-026 stub added (_EMAIL_SEED_PATH env var, documented in
DEBT.md for next-session JSON seed file wiring).

Tests: test_imap.py expanded to 27 cases, test_pop3.py to 22 cases —
860 total tests passing.
2026-04-11 03:12:32 -04:00

10 KiB
Raw Blame History

DECNET — Technical Debt Register

Last updated: 2026-04-09 — All addressable debt cleared. Severity: 🔴 Critical · 🟠 High · 🟡 Medium · 🟢 Low


🔴 Critical

DEBT-001 — Hardcoded JWT fallback secret RESOLVED

File: decnet/env.py:15
Fixed in commit b6b046c. DECNET_JWT_SECRET is now required; startup raises ValueError if unset or set to a known-bad value.

DEBT-002 — Default admin credentials in code CLOSED (by design)

DECNET_ADMIN_PASSWORD defaults to "admin" intentionally — the web dashboard enforces a password change on first login (must_change_password=1). Startup enforcement removed as it broke tooling without adding meaningful security.

DEBT-003 — Hardcoded LDAP password placeholder CLOSED (false positive)

templates/ldap/server.py:73"<sasl_or_unknown>" is a log label for SASL auth attempts, not an operational credential. The LDAP template is a honeypot; it has no bind password of its own.

DEBT-004 — Wildcard CORS with no origin restriction RESOLVED

File: decnet/web/api.py:48-54
Fixed in commit b6b046c. allow_origins now uses DECNET_CORS_ORIGINS (env var, defaults to http://localhost:8080). allow_methods and allow_headers tightened to explicit allowlists.


🟠 High

DEBT-005 — Auth module has zero test coverage RESOLVED

File: decnet/web/auth.py
Comprehensive test suite added in tests/api/ covering login, password change, token validation, and JWT edge cases.

DEBT-006 — Database layer has zero test coverage RESOLVED

File: decnet/web/sqlite_repository.py
tests/api/test_repository.py added — covers log insertion, bounty CRUD, histogram queries, stats summary, and fuzz testing of all query paths. In-memory SQLite with StaticPool ensures full isolation.

DEBT-007 — Web API routes mostly untested RESOLVED

Files: decnet/web/router/ (all sub-modules)
Full coverage added across tests/api/ — fleet, logs, bounty, stream, auth all have dedicated test modules with both functional and fuzz test cases.

DEBT-008 — Auth token accepted via query string RESOLVED

File: decnet/web/dependencies.py:33-34
Query-string token fallback removed. get_current_user now accepts only Authorization: Bearer <token> header. Tokens no longer appear in access logs or browser history.

DEBT-009 — Inconsistent and unstructured logging across templates CLOSED (false positive)

All service templates already import from decnet_logging and use syslog_line() for structured output. The print(line, flush=True) present in some templates is the intentional Docker stdout channel for container log forwarding — not unstructured debug output.

DEBT-010 — decnet_logging.py duplicated across all 19 service templates RESOLVED

Files: templates/*/decnet_logging.py
All 22 per-directory copies deleted. Canonical source lives at templates/decnet_logging.py. deployer.py now calls _sync_logging_helper() before docker compose up — it copies the canonical file into each active template build context automatically.


🟡 Medium

DEBT-011 — No database migration system

File: decnet/web/db/sqlite/repository.py
Schema is created during startup via SQLModel.metadata.create_all. There is no Alembic or equivalent migration layer. Schema changes across deployments require manual intervention or silently break existing databases.
Status: Architectural. Deferred — requires Alembic integration and migration history bootstrapping.

DEBT-012 — No environment variable validation schema RESOLVED

File: decnet/env.py
DECNET_API_PORT and DECNET_WEB_PORT now validated via _port() — enforces integer type and 165535 range, raises ValueError with a clear message on bad input.

DEBT-013 — Unvalidated input on decky_name route parameter RESOLVED

File: decnet/web/router/fleet/api_mutate_decky.py:10
decky_name now declared as Path(..., pattern=r"^[a-z0-9\-]{1,64}$") — FastAPI rejects non-matching values with 422 before any downstream processing.

DEBT-014 — Streaming endpoint has no error handling RESOLVED

File: decnet/web/router/stream/api_stream_events.py
event_generator() now wrapped in try/except. asyncio.CancelledError is handled silently (clean disconnect). All other exceptions log server-side via log.exception() and yield an event: error SSE frame to the client.

DEBT-015 — Broad exception detail leaked to API clients RESOLVED

File: decnet/web/router/fleet/api_deploy_deckies.py:78
Raw exception message no longer returned to client. Full exception now logged server-side via log.exception(). Client receives generic "Deployment failed. Check server logs for details.".

DEBT-016 — Unvalidated log query parameters RESOLVED

File: decnet/web/router/logs/api_get_logs.py:12-19
search capped at max_length=512. start_time and end_time validated against ^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}:\d{2}$ regex pattern. FastAPI rejects invalid input with 422.

DEBT-017 — Silent DB lock retry during startup RESOLVED

File: decnet/web/api.py:20-26
Each retry attempt now emits log.warning("DB init attempt %d/5 failed: %s", attempt, exc). After all retries exhausted, log.error() is emitted so degraded startup is always visible in logs.

DEBT-018 — No Docker HEALTHCHECK in any template RESOLVED

Files: All 20 templates/*/Dockerfile
All 24 Dockerfiles updated with:

HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD kill -0 1 || exit 1

DEBT-019 — Most template containers run as root RESOLVED

Files: All templates/*/Dockerfile except Cowrie
All 24 Dockerfiles now create a decnet system user, use setcap cap_net_bind_service+eip on the Python binary (allows binding ports < 1024 without root), and drop to USER decnet before ENTRYPOINT.

DEBT-020 — Swagger/OpenAPI disabled in production RESOLVED

File: decnet/web/api.py:43-45
All route decorators now declare responses={401: {"description": "Not authenticated"}, 422: {"description": "Validation error"}}. OpenAPI schema is complete for all endpoints.

DEBT-021 — sqlite_repository.py is a god module RESOLVED

~File: decnet/web/sqlite_repository.py (400 lines)
Fully refactored to decnet/web/db/ modular layout: models.py (SQLModel schema), repository.py (abstract base), sqlite/repository.py (SQLite implementation), sqlite/database.py (engine/session factory). Commit de84cc6.

DEBT-026 — IMAP/POP3 bait emails not configurable via service config

Files: templates/imap/server.py, templates/pop3/server.py, decnet/services/imap.py, decnet/services/pop3.py
Bait emails are hardcoded. A stub env var IMAP_EMAIL_SEED is read but currently ignored. Full implementation requires:

  1. IMAP_EMAIL_SEED points to a JSON file with a list of {from_, to, subject, date, body} dicts.
  2. templates/imap/server.py loads and merges/replaces _BAIT_EMAILS from that file at startup.
  3. decnet/services/imap.py compose_fragment() reads service_cfg["email_seed"] and injects IMAP_EMAIL_SEED + a bind-mount for the seed file into the compose fragment.
  4. Same pattern for POP3 (POP3_EMAIL_SEED).
    Status: Stub in place — full wiring deferred to next session.

DEBT-027 — Dynamic Bait Store

Files: templates/redis/server.py, templates/ftp/server.py The bait store and honeypot files are hardcoded. A dynamic injection framework should be created to populate this payload across different honeypots. Status: Deferred — out of current scope.


🟢 Low

DEBT-022 — Debug print() in correlation engine CLOSED (false positive)

decnet/correlation/engine.py:20 — The print() call is inside the module docstring as a usage example, not in executable code. No production code path affected.

DEBT-023 — Unpinned base Docker images

Files: All templates/*/Dockerfile
debian:bookworm-slim and similar tags are used without digest pinning. Image contents can silently change on docker pull, breaking reproducibility and supply-chain integrity.
Status: Deferred — requires docker pull access to resolve current digests for each base image.

DEBT-024 — Stale service version hardcoded in Redis template RESOLVED

File: templates/redis/server.py:15
REDIS_VERSION updated from "7.0.12" to "7.2.7" (current stable).

DEBT-025 — No lock file for Python dependencies RESOLVED

Files: Project root
requirements.lock generated via pip freeze. Reproducible installs now available via pip install -r requirements.lock.


Summary

ID Severity Area Status
DEBT-001 Security / Auth resolved b6b046c
DEBT-002 Security / Auth closed (by design)
DEBT-003 Security / Infra closed (false positive)
DEBT-004 Security / API resolved b6b046c
DEBT-005 Testing resolved
DEBT-006 Testing resolved
DEBT-007 Testing resolved
DEBT-008 Security / Auth resolved
DEBT-009 Observability closed (false positive)
DEBT-010 Code Duplication resolved
DEBT-011 🟡 Medium DB / Migrations deferred (Alembic scope)
DEBT-012 Config resolved
DEBT-013 Security / Input resolved
DEBT-014 Reliability resolved
DEBT-015 Security / API resolved
DEBT-016 Security / API resolved
DEBT-017 Reliability resolved
DEBT-018 Infra resolved
DEBT-019 Security / Infra resolved
DEBT-020 Docs resolved
DEBT-021 Architecture resolved de84cc6
DEBT-022 Code Quality closed (false positive)
DEBT-023 🟢 Low Infra deferred (needs docker pull)
DEBT-024 Infra resolved
DEBT-025 Build resolved
DEBT-026 🟡 Medium Features deferred (out of scope)
DEBT-027 🟡 Medium Features deferred (out of scope)

Remaining open: DEBT-011 (Alembic), DEBT-023 (image pinning), DEBT-026 (modular mailboxes), DEBT-027 (Dynamic bait store) Estimated remaining effort: ~10 hours