Imported from NethServer/nethsecurity (
AGENTS.md). Install upstream withnpx skills add NethServer/nethsecurity. Copyright stays with the author.
AGENTS.md
Project Overview
NethSecurity is an OpenWrt-based Linux firewall, built inside a rootless Podman container. Read build.conf.example for the current versions — OWRT_VERSION (OpenWrt) and NETHSECURITY_VERSION (NethSecurity). Never assume either from memory or from versions quoted elsewhere; check upstream sources against the tag OWRT_VERSION names.
Skills Activation
This project has domain-specific skills available. You MUST activate the relevant skill whenever you work in that domain—don't wait until you're stuck.
netifyd— ACTIVATE when working with the netifyd DPI daemon. Triggers:/etc/netifydconfig,plugins.dloaders,netify-proc-*/netify-sink-*plugins, flow-actions rules, criteria/flow expressions, address groups, nfqueue capture, DPI conntrack labels, netify telemetry, or when user mentions netifyd, netify, DPI or flow actions. Fetches the live Netify v5 docs index; covers the config graph, plugin wiring, and which files are generated.ns-api— ACTIVATE when writing, modifying, or reviewing Python RPCD API scripts. Triggers: creating or updatingns.*RPCD API endpoints, handling UCI configuration changes, managing pre/post-commit hooks, defining ACL permissions, documenting methods in OpenAPI 3.1.0, or when user mentions ns-api, API endpoints, hooks, or references/usr/libexec/rpcd/ns.files. Covers stdin/stdout JSON protocol, error handling, naming conventions, code style, and spec file updates.openwrt-package— ACTIVATE when creating or modifying OpenWrtns-*packages. Triggers: building new packages for NethSecurity, managing package dependencies, patching upstream feeds, modifying Makefiles, or when user mentions Makefile, package structure, config fragments, or upstream patches. Covers naming conventions, required Makefile fields, architecture selection, external version management, and patch workflows.openwrt-package-update— ACTIVATE when updating forked OpenWrt packages from the upstream feed (adblock, mwan3, banip, etc.). Triggers: updating non-ns- packages, comparing local forks against openwrt/packages, merging upstream improvements, or when user mentions upstream package updates. Auto-discovers packages; extracts old/new snapshots for side-by-side comparison; guides cross-package impact detection.python-nethsecurity— ACTIVATE when writing or modifying Python scripts for NethSecurity packages. Triggers: creating new Python scripts, configuring package build systems, writing utilities, or when user mentions Python code in packages/ns-* or references Python scripts in the NethSecurity package tree. Covers shebang, license headers, extension handling, ruff compliance, available modules, and UCI commit conventions.
Build System
Do not commit build.conf — it is git-ignored. Copy from build.conf.example and populate locally.
For build verification, prefer GitHub Actions — inspect CI status and logs via the GitHub MCP server (github-mcp-server-actions_list, github-mcp-server-actions_get, github-mcp-server-get_job_logs). Only run a local build if explicitly required.
# Full image build
./build-nethsec.sh
# Interactive shell inside the build container
./build-nethsec.sh bash
# Run single package compilation
# (Inside container shell:)
make package/feeds/nethsecurity/ns-<name>/{download,compile} V=sc
# Interactive menuconfig
./build-nethsec.sh make menuconfig
Output: bin/ (image + packages) and build-logs/.
Build system is pure OpenWrt make — no npm, pip, go build, or other language-specific tooling. All derivation runs inside the container.
Docs preview (only when a local docs build is explicitly needed): see
docs/README.md. The github-pages gems do not build on
recent host Ruby (4.x), so the site is built in a ruby:3.3 container and the
python3-nethsec API docs are generated on top with pydoctor; the built
_site is then served statically.
High-level Architecture
build-nethsec.shbuilds a Podman-based builder image frombuilder/Containerfile, clones OpenWrt, injects the localpackages/tree as thenethsecurityfeed, copiesconfig/,files/, andpatches/, then runs the OpenWrt build.builder/configure-build.shassembles the final.configby concatenating everyconfig/*.conffragment, appendingconfig/targets/<target>.conf, writing version metadata, and runningmake defconfig.builder/apply-patches.shstrips thepatches/prefix and applies each patch into the matching upstream source directory.files/is the rootfs overlay for the final image.files/etc/uci-defaultsholds first-boot defaults.- Runtime web stack: nginx serves
ns-uifrom/www-nsand proxies/api/→ ns-api-server on127.0.0.1:8090;ns-api-serverhandles auth/JWT and forwards calls to ubus/rpcd handlers. - System monitoring alerts, including HA alerts, follow the Telegraf → Victoria Metrics/vmalert →
ns-plug-alert-proxypath rather than sending legacy portal alerts directly from service scripts. - Many local packages are thin wrappers around upstream code. When changing behavior in one of those areas, inspect the matching upstream repo first and treat the local package as integration glue.
Repository Structure
| Directory | Content |
|---|---|
packages/ |
Custom OpenWrt feed; 37 ns-* packages |
config/ |
Diffconfig fragments per feature; config/targets/<arch>.conf for arch-specific config |
files/ |
Filesystem overlay copied verbatim into image |
patches/ |
Patches applied to upstream OpenWrt feeds |
.github/workflows/ |
CI/CD (build-image, cleanup, docs, etc.) |
.agents/skills/ |
Agent skills (<name>/SKILL.md) |
tools/ |
Maintenance helpers, e.g. netifyd-update/netifyd-update.py |
Package Conventions
- All custom packages use
ns-prefix (e.g.,ns-firewall,ns-api). - Set
CATEGORY:=NethSecurityandSECTION:=basein Makefile. - Use
PKGARCH:=allfor architecture-independent packages (pure Python, shell scripts, etc.). - Do not set
PKG_SOURCE_URLwhen package code lives in this repo. Set it only when fetching from external GitHub releases. - To add a package to the image, create a corresponding
config/<feature>.conffragment that enables it at build time. - Renovate manages external package versions via magic comments in Makefiles:
# renovate: datasource=github-tags depName=Org/Repo packages/netifydis download-only: prebuilt per-arch binaries, filenames and hashes innetify-dist.mk, regenerated bytools/netifyd-update/netifyd-update.py. No compile step.
ns-api (Python3 RPCD Scripts)
APIs are Python 3 scripts placed at /usr/libexec/rpcd/ns.<name> on the device.
Protocol:
- Called with
listargument → print JSON listing all methods and parameter schemas. - Called with
call <method>→ read JSON from stdin, write JSON to stdout. - APIs must not commit UCI changes — callers invoke
ns.commitseparately.
Error format:
{ "error": "snake_case_error_code" }
Validation error format:
{ "validation": { "errors": [{ "parameter": "field", "message": "code", "value": "..." }] } }
Hooks:
- Pre-commit hooks:
/usr/libexec/ns-api/pre-commit/ - Post-commit hooks:
/usr/libexec/ns-api/post-commit/ - Hooks run as part of
ns.commit commitbut do not abort on failure; errors returned in response JSON.
ACL files:
- Paired with each handler:
ns.NAME.jsoninstalled to/usr/share/rpcd/acl.d/. - Consistently leave
"write": {}empty and declare ubus permissions under"read": { "ubus": ... }.
UCI conventions:
- Zones:
ns_<zonename>(e.g.,ns_lan,ns_guest). - Firewall rule IDs: prefix
ns_(e.g.,ns_206325d3); system rules flaggedsystem_rule: true.
Testing
No automated test suite. Testing is manual on a live device:
# Via api-cli (default creds: root / Nethesis,1234):
api-cli ns.dashboard system-info
api-cli ns.dashboard counter --data '{"service":"hosts"}'
api-cli ns.firewall list-forward-rules
# Via ubus:
ubus call ns.firewall list-zones
For UI development against a live device, enable CORS by changing /etc/init.d/ns-api-server:
GIN_MODE=debug # (instead of release)
# Then restart: /etc/init.d/ns-api-server restart
Release & CI
| Trigger | Channel | Version |
|---|---|---|
Push to main |
dev |
<base>-dev.<run>.<timestamp>.<hash> |
Push to staging |
staging |
<base> |
Push to release |
stable |
<base> |
| PR branch | branch-named | <base>-PR<pr_number>.<run>.<timestamp>.<hash> |
Package/Image release:
- Bump
PKG_VERSIONorPKG_RELEASEinpackages/<name>/Makefile. - Merge the tested change to
release. - The
releasebranch push publishes the stable channel automatically.
Build volumes (persistent, deleted weekly): nethsecurity_builder_${OWRT_VERSION}_{build,staging,cache,downloads,dl}.
License Header
Every Nethesis-authored source file must include:
#
# Copyright (C) <YEAR> Nethesis S.r.l.
# SPDX-License-Identifier: GPL-2.0-only
#
This applies to all source files: Python scripts, shell scripts, Makefiles, Go code, and any other authored source.
Code Quality
Python linting and formatting: New Python files must pass ruff check and ruff format --check. See ruff.toml for configuration.
ruff check packages/ns-api/files/my_script.py
ruff format --check packages/ns-api/files/my_script.py
Existing Python files (listed in ruff.toml under extend-exclude) are grandfathered in and exempt from checking. Fix them incrementally as desired.
API Documentation
After any API change, update packages/ns-api/README.md to reflect new or modified methods and schemas. The README is the canonical API reference for all ns.* methods.
Key External Repositories
| Repo | Purpose |
|---|---|
| NethServer/python3-nethsec | Python utility library for APIs; used by all Python API scripts |
| NethServer/nethsecurity-ui | Vue 3 + Tailwind CSS management UI (standalone + controller modes); built as ns-ui package |
| NethServer/nethsecurity-monitoring | Go monitoring tools (ns-flows); reads netifyd flows, exposes REST API on localhost:8080 |
| openwrt/openwrt | OpenWrt base |
| openwrt/packages | OpenWrt package repository |
| NethServer/nethsecurity-controller | Firewall registration, VPN/proxy routing, and how the firewall connects to and calls the controller. |
| NethServer/ns8-nethsecurity-controller | NS8 deployment details, extra Loki/Grafana/Prometheus/WebSSH components, and controller packaging. |
| Netify Agent v5 docs index | Machine-readable link map for netifyd: plugins, telemetry, expression engine, JSON schemas. Prefer over netify.ai/documentation/… HTML |
NethServer shared handbook (follow for all contributions):
| Document | When to consult |
|---|---|
| Commit messages | Before writing commits; follow Conventional Commits and issue-reference guidance. |
| Pull requests | Before opening or updating PRs. |
| Best practices | Before larger implementation decisions or security-sensitive changes. |
| Issues | Before opening, classifying, or triaging new work. |
Key Conventions
- Before changing behavior in UI/API/monitoring/controller code, inspect the matching upstream repo; the local package usually just wires that code into the OpenWrt image.
- When changing behavior, update the developer documentation under
docs/in the same change. - When changing user-facing behavior or adding a new feature, check whether the frontend needs updates so the UI/API contract stays aligned, and update the administrator manual in
nethsecurity-docsas part of the change. - When changing current behavior or configuration, verify the change against both the firewall system and the controller so upgrades stay seamless and regressions are avoided on both sides.
- When implementing new things, check
system_requirements.rstto keep the result suitable for older x86 hardware. - Avoid growing the built image unnecessarily; if size increases are unavoidable, evaluate alternatives before committing to the change.
- Use live repository files as the source of truth when docs disagree with the code.
- Keep
AGENTS.mdupdated alongside code changes.