Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ jobs:
run: |
npm install -g @anthropic-ai/claude-code
claude plugin validate .

# Reports per-doc verification coverage (date / version / env) and flags
# stale or missing records. Gaps and staleness are informational and do
# not fail the build; a malformed `verified:` block does.
- name: Verification coverage report
run: python3 skills/crowdsec/scripts/check-verification.py
37 changes: 34 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ Conventions for authoring this skill. This governs how skill content is **writte
- **Write only the final, correct information.** Never record self-corrections, dead ends, or
"actually, it turned out…" narration discovered while authoring. The reader gets the conclusion,
not the journey. This applies equally to inline expected-output hints: state the correct
outcome, never the wrong-then-fixed version. Do not annotate content as *verified* (no
"(verified)", "Verified on…", "verified gotcha") verification is guaranteed by this file,
not restated per-doc.
outcome, never the wrong-then-fixed version. Do not annotate verification *inline in prose* (no
"(verified)", "Verified on…", "verified gotcha"). Record verification in the per-file `verified:`
frontmatter block instead — see **Verification tracking** below.
- **Keep `SKILL.md` a router.** It is an index and decision layer that points to `references/`.
Depth and recipes belong in the reference docs, not in `SKILL.md`.
- **Cover every environment.** Each command or recipe carries its systemd / docker / k8s variant,
Expand All @@ -34,4 +34,35 @@ Conventions for authoring this skill. This governs how skill content is **writte
behavior as confirmed.
- **Avoid duplicates** by checking in the existing skill documentation if the information is already present. If it is, ensure it's properly linked/routed, but don't duplicate instruction, code blocks or configurations.

## Verification tracking

Verification is recorded **per reference doc**, in a `verified:` YAML frontmatter block, so freshness
is queryable and drift is visible. A doc with no `verified:` block has never been confirmed against a
real environment.

```yaml
---
verified:
- date: 2026-05-22 # ISO 8601 (YYYY-MM-DD); the day the recipes were run
version: "1.6.5" # CrowdSec engine version, from `cscli version`
env: docker # systemd | docker | k8s (free-form allowed, e.g. opnsense)
notes: "deploy + reload path only" # optional, short scope note
---
```

Rules:

- **One entry per env.** Re-verifying the same env updates that entry in place (bump `date` and
`version`); verifying a new env appends a new entry. This keeps "cover every environment"
auditable.
- **Stamp it when you verify it.** When you run a doc's commands against the real test environment
(see Testing) and observe them work, add or update that doc's `verified:` entry in the same change:
`date` = today, `version` = the output of `cscli version`, `env` = the detected environment. The
record and the verification happen together — never stamp from memory or inference.
- Use ISO 8601 dates so the checker can sort and age them.
- Don't pre-seed unverified docs with empty blocks; absence *is* the "never verified" signal.

`skills/crowdsec/scripts/check-verification.py` (stdlib-only, safe to run locally) reports coverage,
lists docs with no block, flags entries older than 180 days, and fails on a malformed block.


10 changes: 9 additions & 1 deletion skills/crowdsec/references/appsec/configure.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "appsec-configs/rules list+inspect, metrics rules table; fixed eval-time claim"
---

# AppSec — Configure

Canonical docs: <https://docs.crowdsec.net/docs/next/appsec/configuration> · rule management <https://docs.crowdsec.net/docs/next/appsec/configuration_rule_management> · hooks <https://docs.crowdsec.net/docs/next/appsec/hooks> · alerts & scenarios <https://docs.crowdsec.net/docs/next/appsec/alerts_and_scenarios> · API validation <https://docs.crowdsec.net/docs/next/appsec/api_validation>
Expand Down Expand Up @@ -132,7 +140,7 @@ For captcha responses, configuration lives on the **bouncer** (captcha provider
## Performance levers

- `request_body_limit` (engine config) caps how much of the request body AppSec processes — defaults are usually fine; raise for APIs with large legitimate payloads, lower for static-only fronts.
- Rule load order is automatic; per-rule eval time appears in `cscli metrics show appsec` once you generate traffic.
- Rule load order is automatic; per-rule **trigger counts** appear in `cscli metrics show appsec` once you generate traffic (the Rules Metrics table) — useful for spotting hot rules, though `cscli` does not report per-rule eval time.
- Inband evaluation adds latency on the request path. Out-of-band is asynchronous and does not.
- Move expensive rules (large regex, body inspection) to out-of-band if latency matters more than per-request blocking.

Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/appsec/deploy.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-21
version: "1.7.8"
env: systemd
notes: "nginx acquisition + AppSec deploy"
---

# AppSec — Deploy

Canonical docs: <https://docs.crowdsec.net/docs/next/appsec/intro> · quickstart <https://docs.crowdsec.net/docs/next/appsec/quickstart/general> · rules deploy <https://docs.crowdsec.net/docs/next/appsec/rules_deploy> · advanced deployments <https://docs.crowdsec.net/docs/next/appsec/advanced_deployments>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/appsec/overview.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "listener 7422, configs/rules paths, out-of-band scenario→ban path; conceptual doc"
---

# AppSec — Overview

Canonical docs: <https://docs.crowdsec.net/docs/next/appsec/intro> · request lifecycle <https://docs.crowdsec.net/docs/next/appsec/request-lifecycle> · protocol <https://docs.crowdsec.net/docs/next/appsec/protocol> · FAQ <https://docs.crowdsec.net/docs/next/appsec/faq>
Expand Down
10 changes: 9 additions & 1 deletion skills/crowdsec/references/appsec/troubleshoot.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "metrics show appsec, listener on 7422, appsec-rules/configs inspect; fixed eval-time claim"
---

# AppSec — Troubleshoot

Canonical docs: <https://docs.crowdsec.net/docs/next/appsec/troubleshooting> · FAQ <https://docs.crowdsec.net/docs/next/appsec/faq> · benchmark <https://docs.crowdsec.net/docs/next/appsec/benchmark>
Expand Down Expand Up @@ -159,7 +167,7 @@ Inspect the bouncer's own log for `captcha` lines; it should announce when it's
sudo cscli metrics show appsec
```

Per-rule eval time shows up in the rules table. Suspects:
The Rules Metrics table shows a per-rule **Triggered** count (how often each rule matched), not timing — use it to spot a hot rule worth moving out-of-band. `cscli` does not expose per-rule eval time; for actual latency numbers use the benchmark methodology below. Suspects:

- **Expensive regex** in a rule body — move to out-of-band, or replace with a cheaper match.
- **Large request bodies** — raise / lower `request_body_limit` in the engine config; the default is conservative.
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/configure/acquisition.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "config keys, crowdsec -t (clean + FATAL bad-source), appsec listener"
---

# Configure — Acquisition (log sources)

Canonical docs: <https://docs.crowdsec.net/docs/next/getting_started/post_installation/acquisition> · datasources index <https://docs.crowdsec.net/docs/next/data_sources/intro>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/configure/allowlists.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-20
version: "1.7.8"
env: systemd
notes: "allowlists add/check/list"
---

# Configure — Allowlists, whitelist parsers, and postoverflows

Canonical docs: <https://docs.crowdsec.net/docs/next/local_api/centralized_allowlists/>
Expand Down
17 changes: 17 additions & 0 deletions skills/crowdsec/references/configure/bouncers/firewall.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "nftables bouncer v0.0.34 install+register, nft sets/chains (priority filter-10), ban→cscli set→drop; added stale-key recovery note"
---

# Bouncers — Firewall (nftables / iptables / ipset)

Canonical docs: <https://docs.crowdsec.net/u/bouncers/firewall>
Expand Down Expand Up @@ -49,6 +57,15 @@ If you *also* run `cscli bouncers add` you create a second, unused key — skip
Only register manually when the bouncer runs on a **different host** than LAPI
(then set `api_url` to the remote LAPI and paste the manual key into the yaml).

> **Gotcha — reinstall over a stale key.** If a previous
> `/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml` survives a purge/reinstall,
> the postinst may not rewrite the `api_key`, and the service then fails to start with
> `API error: access forbidden` / `bouncer stream halted` in
> `/var/log/crowdsec-firewall-bouncer.log` (and the dpkg `--configure` step errors).
> Re-register: `cscli bouncers delete <name>`, `KEY=$(cscli bouncers add fw-local -o raw)`,
> write it into the yaml's `api_key:`, `systemctl restart crowdsec-firewall-bouncer`.
> See [../../debug/bouncer-not-blocking.md](../../debug/bouncer-not-blocking.md) § 3.

## 3 — What it creates in nftables

The bouncer builds its **own** tables, isolated from your existing ruleset:
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/configure/bouncers/web-servers.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-21
version: "1.7.8"
env: systemd
notes: "nginx bouncer path only"
---

# Bouncers — Web servers (nginx, haproxy, apache, Traefik, Caddy)

Canonical docs: <https://docs.crowdsec.net/u/bouncers/intro> (per-bouncer pages: nginx, haproxy, apache, traefik, caddy)
Expand Down
16 changes: 13 additions & 3 deletions skills/crowdsec/references/configure/hub.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "update/upgrade, list -o raw, collections install+remove, inspect tainted fields"
---

# Configure — Hub management

Canonical docs: <https://docs.crowdsec.net/docs/next/getting_started/post_installation/console_hub> · `cscli hub` reference <https://docs.crowdsec.net/docs/next/cscli/cscli_hub>
Expand All @@ -13,9 +21,11 @@ Install a **collection** and it pulls every item it depends on. Installing

```bash
sudo cscli collections install crowdsecurity/wordpress
# scenarios: crowdsecurity/http-bf-wordpress_bf, crowdsecurity/http-wordpress_user-enum,
# crowdsecurity/http-wordpress_wpconfig
# collections: crowdsecurity/wordpress
# enabling scenarios:crowdsecurity/http-bf-wordpress_bf
# enabling scenarios:crowdsecurity/http-wordpress_wpconfig
# enabling scenarios:crowdsecurity/http-wordpress_user-enum
# enabling collections:crowdsecurity/wordpress
#
# Run 'sudo systemctl reload crowdsec' for the new configuration to be effective.
```

Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/configure/profiles.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "profiles.yaml structure, no cscli profiles cmd, simulation status, decision add/list/delete"
---

# Configure — Profiles (decisions, durations, simulation)

Canonical docs: <https://docs.crowdsec.net/docs/next/local_api/profiles> · post-install profiles <https://docs.crowdsec.net/docs/next/getting_started/post_installation/profiles>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/debug/bouncer-not-blocking.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "allowlists/decisions/bouncers ladder, LAPI curl 200, firewall nft sets/chains/counter"
---

# Debug — Decisions exist but bouncer not blocking

Canonical docs: <https://docs.crowdsec.net/docs/next/troubleshooting/intro> · bouncers index <https://docs.crowdsec.net/u/bouncers/intro>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/debug/common-errors.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "diagnostic commands + ExecStartPre/-t, machines, geoip path; error strings are catalog"
---

# Debug — Common errors (string → cause catalog)

Canonical docs: <https://docs.crowdsec.net/docs/next/troubleshooting/intro>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/debug/no-alerts.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "metrics show scenarios, whitelist RFC1918 ranges, simulation status, explain replay"
---

# Debug — Scenarios not firing (no alerts)

Canonical docs: <https://docs.crowdsec.net/docs/next/troubleshooting/intro> · `cscli metrics` <https://docs.crowdsec.net/docs/next/observability/cscli_metrics>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/debug/parsing.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "metrics show acquisition + explain --log/--file type matching"
---

# Debug — Logs not being parsed

Canonical docs: <https://docs.crowdsec.net/docs/next/troubleshooting/intro> · `cscli metrics` <https://docs.crowdsec.net/docs/next/observability/cscli_metrics>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/debug/triage.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "diagnose.sh support dump + triage funnel commands"
---

# Debug — First-look triage

Use this when the user reports a CrowdSec problem and you don't yet know the shape of it.
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/install/bare-metal.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-21
version: "1.7.8"
env: systemd
notes: "apt + systemd install path"
---

# Install — bare metal (apt/dnf + systemd)

Canonical docs: <https://docs.crowdsec.net/docs/next/getting_started/installation/linux> · post-install <https://docs.crowdsec.net/docs/next/getting_started/post_installation/acquisition>
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/install/docker.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: docker
notes: "compose up, COLLECTIONS install on boot, /logs/auth.log container-path acquisition, 8081:8080 coexistence, bouncers add; teardown -v"
---

# Install — Docker / docker-compose

Canonical docs: <https://docs.crowdsec.net/docs/next/getting_started/installation/docker> · image reference <https://docs.crowdsec.net/u/getting_started/installation/#docker>
Expand Down
12 changes: 10 additions & 2 deletions skills/crowdsec/references/operate/health-check.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "all 3 probes fire (whitelist removed), self-block→403, capi status; fixed remediation:false drift"
---

# Operate — Health-check

Canonical docs: <https://docs.crowdsec.net/u/getting_started/health_check>
Expand Down Expand Up @@ -37,7 +45,7 @@ curl -I https://<your-public-service-url>/crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl
sudo cscli alerts list -s crowdsecurity/http-generic-test
```

Expected: one row with `kind: crowdsec`, scope `Ip:<your-public-ip>`. Then a decision appears in `cscli decisions list` (the default profile bans on this alert, since `Remediation: true`).
Expected: one row with `kind: crowdsec`, scope `Ip:<your-public-ip>`. The test scenarios are deliberately `remediation: false` (`type: trigger`), so they produce an **alert but no ban decision** — the alert itself is the proof the detection chain works, and the probe won't lock you out. End-to-end bouncer enforcement is proven separately in § 5.

**Common failure paths** (in order to check):
1. *No row, no parser hit* → the web server's logs aren't being read. `cscli metrics show acquisition` — does your access log show non-zero "Lines read"? If not, see [../configure/acquisition.md](../configure/acquisition.md).
Expand All @@ -57,7 +65,7 @@ ssh crowdsec-test-NtktlJHV4TfBSK3wvlhiOBnl@<your-public-ip>
sudo cscli alerts list -s crowdsecurity/ssh-generic-test
```

Expected: one row with `kind: crowdsec`, ban decision shortly after.
Expected: one row with `kind: crowdsec`. Like the HTTP probe, `ssh-generic-test` is `remediation: false` — an alert appears, but no ban (by design).

**Common failure paths:**
1. *No row* → check `cscli metrics show acquisition` for `/var/log/auth.log` (or wherever sshd logs land). On systems using journald-only logging, the file source may be empty — switch to a journald acquisition.
Expand Down
8 changes: 8 additions & 0 deletions skills/crowdsec/references/operate/upgrades.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
---
verified:
- date: 2026-05-22
version: "1.7.8"
env: systemd
notes: "apt-cache policy (no-op at latest, packagecloud repo, rollback table), hub upgrade, backup paths; non-destructive"
---

# Operate — Upgrades, backup, rollback

Canonical docs: <https://docs.crowdsec.net/docs/next/configuration/crowdsec_configuration> · `cscli` reference <https://docs.crowdsec.net/docs/next/cscli/>
Expand Down
Loading
Loading