Developer Guide
How to hack on DECNET. If you just want to deploy it, see Home and INI-Config-Format instead.
Environment setup
DECNET pins its runtime deps in requirements.lock. Always work inside the project virtualenv — do not install into the system interpreter.
cd /path/to/DECNET
python -m venv .venv
source .venv/bin/activate
pip install -e .
Every subsequent shell must source .venv/bin/activate before running pip, pytest, or decnet. The CLI entrypoint is registered in pyproject.toml and resolves to decnet.cli:app.
To confirm the dev install:
decnet services # list registered service plugins
decnet distros # list base-image archetypes
pytest -q # run the suite
Repository layout
High-level tour. Only the directories you will touch often are listed.
| Path | What lives there |
|---|---|
decnet/cli.py |
Typer app. Every decnet <verb> subcommand is defined here. |
decnet/services/ |
Service plugins. One file per honeypot service. See Writing-a-Service-Plugin. |
decnet/services/base.py |
BaseService contract. |
decnet/services/registry.py |
Auto-discovery of BaseService subclasses. |
decnet/composer.py |
Turns a fleet spec into a docker-compose file. |
decnet/fleet.py |
Fleet planning: which decky runs which services on which IP. |
decnet/archetypes.py, decnet/distros.py |
OS personas + base-image selection. |
decnet/os_fingerprint.py |
TCP/IP stack tuning to bend nmap fingerprints toward a chosen persona. |
decnet/env.py |
Central env-var parsing (DECNET_DB_TYPE, DECNET_EMBED_*, …). |
decnet/collector/ |
Syslog / RFC 5424 ingest worker. |
decnet/correlation/ |
Session and attacker correlation worker. |
decnet/profiler/ |
Attacker profiler. Embeddable or standalone — see Design-Overview. |
decnet/sniffer/ |
Passive PCAP sniffer worker. Same embed/standalone split. |
decnet/mutator/ |
Runtime mutation of the decoy fleet. |
decnet/prober/ |
Active probe / realism checker. |
decnet/engine/ |
Deploy / teardown orchestration. |
decnet/web/ |
FastAPI app + dashboard + repository layer. |
decnet/web/db/ |
SQLModelRepository base and sqlite/, mysql/ subclasses. See Database-Drivers. |
decnet/logging/ |
RFC 5424 emitters and the syslog bridge used by service containers. |
templates/<slug>/ |
Dockerfile + service config bundle built into the service image. |
tests/ |
Pytest suite. Mirrors the decnet/ tree loosely. |
development/ |
Low-level design notes and generated graphs. Not shipped. |
Coding conventions
Lint and static checks
- ruff is the single source of truth for style. Config lives in
ruff.toml. Runruff check decnet testsbefore committing. - bandit is used for security linting of
decnet/. Fix findings rather than silencing them; if a silence is unavoidable, scope the# noseccomment to one line and explain why.
Stealth in probes and banners
Never reveal DECNET identity in anything an attacker can see. That means:
- No
User-Agent: DECNET/...in the prober or in any service plugin. - No banners, MOTDs,
/etc/issuecontents, HTTPServer:headers, or SSH version strings that mention DECNET, honeypot, decoy, fake, or any internal codename. - No log filenames or env var names leaking into emitted service output.
This rule is load-bearing. A single leaked banner turns the whole fleet into a well-known signature.
Dependency injection for storage
Do not from decnet.web.db.sqlite.repository import SQLiteRepository in new code. Ever.
- In workers / CLI / library code: call
get_repository()fromdecnet/web/db/factory.py. It readsDECNET_DB_TYPEand returns the right backend, already wrapped with telemetry. - In FastAPI route handlers: take
repo: BaseRepository = Depends(get_repo)— defined indecnet/web/dependencies.py. This keeps the test harness able to swap in an in-memory repo.
The direct-import rule is enforced by convention and by reviewer. If you find an old direct import while working on a file, fix it in the same commit.
See Database-Drivers for how SQLite and MySQL subclasses differ.
Tests
Layout
tests/— fast unit tests. Run by default.tests/api/— FastAPITestClienttests.tests/docker/— integration tests that spin real containers. Opt-in.tests/live/— full end-to-end against a live deploy. Opt-in.tests/perf/,tests/stress/— performance and soak. Opt-in.tests/service_testing/— per-service plugin smoke tests.tests/conftest.py— shared fixtures, including repo factories.
Running
pytest -q # fast suite
pytest tests/api -q # just the API
pytest tests/service_testing -q # plugin smoke
pytest -k ssh # single topic
Rules
- Every new feature ships with pytest coverage. No exceptions.
- Never hand off code that is not running or not 100% green. If you cannot finish the tests, say so — do not push.
- Do not use scapy's
sniff()inside aTestClientlifespan test. The sniff thread hangs pytest teardown. Use static source inspection or a fake socket instead.
Commit style
- Follow the existing log: short imperative subject,
scope:prefix when obvious (feat(sniffer):,fix(web-ui):,test(ssh):,chore:). - Run the relevant
pytestsubset before committing. A broken main is worse than a late commit. - Never add
Co-Authored-By:or any Claude / AI attribution trailer. - Prefer a new commit over
--amend. Hooks that fail leave you in a half-state; amending there hides work.
Related pages
- Design-Overview — why workers are split out and how embed mode works.
- Writing-a-Service-Plugin — step-by-step plugin authoring.
- Database-Drivers — the repository pattern in detail.
- Environment-Variables — every
DECNET_*knob. - INI-Config-Format — declarative deploy specs.
DECNET
User docs
- Quick-Start
- Installation
- Requirements-and-Python-Versions
- CLI-Reference
- INI-Config-Format
- Custom-Services
- Services-Catalog
- Service-Personas
- Archetypes
- Distro-Profiles
- OS-Fingerprint-Spoofing
- Networking-MACVLAN-IPVLAN
- Deployment-Modes
- SWARM-Mode
- MazeNET
- Remote-Updates
- Environment-Variables
- Teardown-and-State
- Database-Drivers
- Systemd-Setup
- Logging-and-Syslog
- Service-Bus
- Web-Dashboard
- REST-API-Reference
- Mutation-and-Randomization
- Troubleshooting
Developer docs
DECNET — honeypot deception-network framework. Pre-1.0, active development — use with caution. See Sponsors to support the project. Contact: samuel@securejump.cl