Skip to content

Commit ec0a592

Browse files
committed
feat: add CLAUDE.md for plugin development guidance
1 parent c5f5674 commit ec0a592

1 file changed

Lines changed: 70 additions & 0 deletions

File tree

CLAUDE.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Repository purpose
6+
7+
Official external plugins for [BunkerWeb](https://github.com/bunkerity/bunkerweb). Each top-level directory (`clamav/`, `coraza/`, `discord/`, `slack/`, `virustotal/`, `webhook/`) is an independently-shipped plugin. There is no monorepo build — plugins are consumed by BunkerWeb at runtime by mounting the plugin directory into `/data/plugins` of the `bunkerweb-scheduler` container.
8+
9+
## Plugin anatomy
10+
11+
Every plugin follows the same BunkerWeb-imposed layout:
12+
13+
- `plugin.json` — id, name, version, `stream` (yes/no/partial), and the `settings` schema (each setting has `context` = `global`|`multisite`, `default`, `regex`, UI metadata). BunkerWeb reads this to register settings and render the UI.
14+
- `<plugin>.lua` — main logic; requires `bunkerweb.plugin` and subclasses it via `middleclass`. Hook methods (`init_worker`, `access`, `log`, `preread`, etc.) return via `self:ret(ok, msg, [status])`. Runs inside OpenResty in the BunkerWeb nginx container.
15+
- `ui/actions.py` — optional Python hooks for the BunkerWeb web UI. `pre_render(**kwargs)` returns card data; a function named after the plugin is called for the main page. `kwargs["bw_instances_utils"]` exposes BW helpers like `get_ping(service)`.
16+
- `README.md` — user-facing docs; the settings table is generated from `plugin.json` via `.tests/misc/json2md.py` (run manually when settings change).
17+
- `docs/diagram.drawio` + `docs/diagram.svg` — architecture diagram shipped with each plugin.
18+
19+
Coraza is special: it also ships `coraza/api/` — a standalone Go HTTP service (`main.go`, built by `coraza/api/Dockerfile`) that wraps `corazawaf/coraza/v3` and is called over HTTP by `coraza.lua`. Image is published as `bunkerity/bunkerweb-coraza`. CRS rules are vendored at build time by `crs.sh` (pinned to a commit hash, `.git` stripped).
20+
21+
## Versioning — two different version numbers
22+
23+
There are **two unrelated version streams**, easy to confuse:
24+
25+
1. **Individual plugin version** in each `plugin.json` (currently `1.10`). Bump with `./misc/update_version.sh <new_version>` from the repo root — it rewrites every `plugin.json` and the README badge in place.
26+
2. **Plugins-collection version** in `COMPATIBILITY.json`, which maps a collection version to the BunkerWeb versions it supports (e.g. `"1.8": ["1.6.0", ...]`). This is the version shown in the README badge and controls compatibility gates.
27+
28+
When bumping, check both — the README badge is tied to (2), while `plugin.json` uses (1).
29+
30+
## Testing
31+
32+
There is no unit-test framework. Tests are end-to-end integration tests under `.tests/`:
33+
34+
- `./.tests/bw.sh <bw_tag>` pulls `bunkerity/bunkerweb:<tag>` + `bunkerweb-scheduler:<tag>` and retags them as `bunkerweb:tests` / `bunkerweb-scheduler:tests`. Must run first.
35+
- `./.tests/clamav.sh`, `./.tests/coraza.sh`, `./.tests/virustotal.sh` each: copy the plugin into `/tmp/bunkerweb-plugins/<plugin>/bw-data/plugins` (owned `101:101`), copy `.tests/<plugin>/docker-compose.yml`, `sed` the compose file to use the `:tests` tagged images, then `docker compose up --build -d` and poll with `curl`. EICAR file is downloaded for ClamAV; VirusTotal requires `VIRUSTOTAL_API_KEY` env var.
36+
- `.tests/utils.sh` provides `do_and_check_cmd` (runs a command, echoes output on failure, exits on non-zero) and `git_secure_clone` (pinned-commit clone helper). Source it with `. .tests/utils.sh`.
37+
- Run a single plugin's tests: `./.tests/bw.sh dev && ./.tests/clamav.sh` (or `coraza`/`virustotal`). Pass `verbose` as `$1` to dump compose logs on success.
38+
- Tests need `sudo` (for chowning to BW's uid 101) and a working Docker daemon. They leave state in `/tmp/bunkerweb-plugins/` — the scripts clean it at start, but `docker compose down -v` is the safe manual reset.
39+
40+
Discord, Slack, and Webhook have no automated tests — they're exercised by manually pointing a real BunkerWeb instance at a webhook URL.
41+
42+
## CI/CD (`.github/workflows/tests.yml`)
43+
44+
Runs on push to `dev` and `main`. Picks BW tag from branch: `main``1.6.1`, `dev``dev`. Runs CodeQL, then `bw.sh``clamav.sh``coraza.sh``virustotal.sh` sequentially. On `main` only, `./.tests/build-push.sh 1.6.1` builds and pushes the `bunkerweb-coraza` image. **If you update the pinned BW version, update the hardcoded `1.6.1` in `tests.yml` too** — it is not read from `COMPATIBILITY.json`.
45+
46+
## Linting — pre-commit is the source of truth
47+
48+
`.pre-commit-config.yaml` pins every linter to a frozen SHA. Install once with `pre-commit install`, then `pre-commit run --all-files` before committing. The stack:
49+
50+
- `black` (Python, py3.9) — configured in `pyproject.toml` with `line-length = 160`
51+
- `flake8``--max-line-length=250 --ignore=E266,E402,E722,W503`
52+
- `stylua` — config in `stylua.toml`
53+
- `luacheck` — config in `.luacheckrc`, run with `--std min --codes --ranges --no-cache`
54+
- `prettier`, `shellcheck`, `codespell`, `gitleaks`, standard pre-commit hygiene hooks
55+
56+
`coraza/api/coreruleset/**` and `LICENSE.md` are excluded from all hooks.
57+
58+
## Writing Lua plugin code — conventions to follow
59+
60+
- Always subclass via `local <name> = class("<name>", plugin)` and call `plugin.initialize(self, "<id>", ctx)` in `initialize(self, ctx)`.
61+
- Every hook method returns `self:ret(ok_bool, msg, [http_status])`. To deny a request, return `self:ret(true, "reason", utils.get_deny_status())`.
62+
- Gate expensive work at `init_worker` with `utils.has_variable("USE_<PLUGIN>", "yes")` — avoids connecting to upstream services when the plugin is globally disabled. Skip when `self.is_loading` is true.
63+
- Use `ngx.socket` for TCP (see `clamav.lua` INSTREAM protocol) and `resty.http` for HTTP upstreams. Prefer `resty.upload` for streaming request bodies (`clamav.lua` is the reference).
64+
- Cache API responses (SHA-512 of body for file scans) — `virustotal.lua` is the pattern.
65+
66+
## Pull requests & commits
67+
68+
- Default branch for PRs is `main`; active development lands on `dev` first.
69+
- Commits follow conventional-commits style (`feat:`, `fix:`, `refactor:`, `ci/cd -`). See `git log` for prior examples.
70+
- CONTRIBUTING.md requires an issue before non-trivial PRs.

0 commit comments

Comments
 (0)