From 28eced2a256c832f142acf4f265eec6c59df805a Mon Sep 17 00:00:00 2001 From: jokob-sk Date: Sat, 26 Sep 2026 08:58:46 +1000 Subject: [PATCH] DOCS: skill updates, WIFICANARY updates --- .claude/skills/plugin-readme/SKILL.md | 1 + .claude/skills/plugin-review/SKILL.md | 2 ++ .../plugin-readme/plugin-readme-skill.md | 1 + .gemini/skills/plugin-review/SKILL.md | 2 ++ .github/skills/plugin-readme/SKILL.md | 1 + .github/skills/plugin-review/SKILL.md | 2 ++ docs/PLUGINS_OVERVIEW.md | 1 + mkdocs.yml | 1 + server/plugins/wificanary/README.md | 25 ++++++++++++------- 9 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.claude/skills/plugin-readme/SKILL.md b/.claude/skills/plugin-readme/SKILL.md index 743ef082c..4a52e0296 100644 --- a/.claude/skills/plugin-readme/SKILL.md +++ b/.claude/skills/plugin-readme/SKILL.md @@ -41,6 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/.claude/skills/plugin-review/SKILL.md b/.claude/skills/plugin-review/SKILL.md index c1ef061f6..8fbf0880f 100644 --- a/.claude/skills/plugin-review/SKILL.md +++ b/.claude/skills/plugin-review/SKILL.md @@ -9,6 +9,8 @@ description: Read when reviewing a plugin PR or auditing an existing plugin scri This is a reviewer-facing checklist, complementary to [[plugin-development]] (which is author-facing). For `config.json` conventions already covered there and mechanically checked by `test/plugins/test_plugin_conventions.py`, defer to that skill's "Before Opening a PR" checklist and run that test rather than re-deriving the list here - it grows as new checks get added, so a copy of it here would go stale. +If the PR adds or changes `server/plugins//README.md`, also apply [[plugin-readme]] - none of the checks below touch README structure, "Other info" attribution, or markdown that only breaks once rendered on the docs site (e.g. a table nested inside a list item, which MkDocs' Python-Markdown parser terminates the list on - GitHub's renderer is more forgiving, so this passes a casual look at the PR diff and only breaks on the published page). A plugin PR without a reviewed README is only half-reviewed. + ## The check this skill adds: no raw SQL in a plugin script Plugin scripts write their results to `RESULT_FILE` via `plugin_helper.Plugin_Objects` — the framework inserts those rows into the DB. A plugin that also runs its own `SELECT`/`INSERT`/`UPDATE` (via `sqlite3` directly or `database.get_temp_db_connection()`) is bypassing that contract, usually to read existing data before deciding what to write. diff --git a/.gemini/skills/plugin-readme/plugin-readme-skill.md b/.gemini/skills/plugin-readme/plugin-readme-skill.md index 35e2dee4a..8eb6e9f6b 100644 --- a/.gemini/skills/plugin-readme/plugin-readme-skill.md +++ b/.gemini/skills/plugin-readme/plugin-readme-skill.md @@ -41,6 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/.gemini/skills/plugin-review/SKILL.md b/.gemini/skills/plugin-review/SKILL.md index c1ef061f6..8fbf0880f 100644 --- a/.gemini/skills/plugin-review/SKILL.md +++ b/.gemini/skills/plugin-review/SKILL.md @@ -9,6 +9,8 @@ description: Read when reviewing a plugin PR or auditing an existing plugin scri This is a reviewer-facing checklist, complementary to [[plugin-development]] (which is author-facing). For `config.json` conventions already covered there and mechanically checked by `test/plugins/test_plugin_conventions.py`, defer to that skill's "Before Opening a PR" checklist and run that test rather than re-deriving the list here - it grows as new checks get added, so a copy of it here would go stale. +If the PR adds or changes `server/plugins//README.md`, also apply [[plugin-readme]] - none of the checks below touch README structure, "Other info" attribution, or markdown that only breaks once rendered on the docs site (e.g. a table nested inside a list item, which MkDocs' Python-Markdown parser terminates the list on - GitHub's renderer is more forgiving, so this passes a casual look at the PR diff and only breaks on the published page). A plugin PR without a reviewed README is only half-reviewed. + ## The check this skill adds: no raw SQL in a plugin script Plugin scripts write their results to `RESULT_FILE` via `plugin_helper.Plugin_Objects` — the framework inserts those rows into the DB. A plugin that also runs its own `SELECT`/`INSERT`/`UPDATE` (via `sqlite3` directly or `database.get_temp_db_connection()`) is bypassing that contract, usually to read existing data before deciding what to write. diff --git a/.github/skills/plugin-readme/SKILL.md b/.github/skills/plugin-readme/SKILL.md index c96284ffc..48d860db8 100644 --- a/.github/skills/plugin-readme/SKILL.md +++ b/.github/skills/plugin-readme/SKILL.md @@ -41,6 +41,7 @@ Before concluding a plugin has no attribution to record, grep its script for a c - `TBC` or similarly empty content, especially for a prominent feature. - Duplicate or orphaned sections (e.g. two `### Usage` headings) - usually a merge/edit artifact. - Sibling non-README files (a provider-specific sub-guide, a translated `README_.md`) that aren't linked from the plugin's own `README.md` - `docs/gen_plugin_pages.py` generates a page for every `*.md` in the plugin folder, but only reachable if something links to it. +- A table (or any multi-line block) indented under a bullet as that list item's continuation. GitHub's renderer tolerates this, but the docs site (`mkdocs`, Python-Markdown) terminates the list right there - the table and everything after it fall out as orphaned paragraphs, and the *next* bullet renders as a literal `-`-prefixed line of text instead of a list item. Looks fine in the PR diff on GitHub, breaks only once published. Fix: de-nest it - end the bullet's text, blank line, then the table/block as top-level (unindented) content, blank line, then resume the list as a fresh block. ## Reference diff --git a/.github/skills/plugin-review/SKILL.md b/.github/skills/plugin-review/SKILL.md index 7c2bdcb51..ea7a5d4b9 100644 --- a/.github/skills/plugin-review/SKILL.md +++ b/.github/skills/plugin-review/SKILL.md @@ -9,6 +9,8 @@ description: Read when reviewing a plugin PR or auditing an existing plugin scri This is a reviewer-facing checklist, complementary to [[plugin-development]] (which is author-facing). For `config.json` conventions already covered there and mechanically checked by `test/plugins/test_plugin_conventions.py`, defer to that skill's "Before Opening a PR" checklist and run that test rather than re-deriving the list here - it grows as new checks get added, so a copy of it here would go stale. +If the PR adds or changes `server/plugins//README.md`, also apply [[plugin-readme]] - none of the checks below touch README structure, "Other info" attribution, or markdown that only breaks once rendered on the docs site (e.g. a table nested inside a list item, which MkDocs' Python-Markdown parser terminates the list on - GitHub's renderer is more forgiving, so this passes a casual look at the PR diff and only breaks on the published page). A plugin PR without a reviewed README is only half-reviewed. + ## The check this skill adds: no raw SQL in a plugin script Plugin scripts write their results to `RESULT_FILE` via `plugin_helper.Plugin_Objects` — the framework inserts those rows into the DB. A plugin that also runs its own `SELECT`/`INSERT`/`UPDATE` (via `sqlite3` directly or `database.get_temp_db_connection()`) is bypassing that contract, usually to read existing data before deciding what to write. diff --git a/docs/PLUGINS_OVERVIEW.md b/docs/PLUGINS_OVERVIEW.md index 7afcd1b82..dd379b061 100644 --- a/docs/PLUGINS_OVERVIEW.md +++ b/docs/PLUGINS_OVERVIEW.md @@ -95,6 +95,7 @@ The **Plugin docs** links below open each plugin's README rendered as part of th | `VNDRPDT` | [vendor_update](plugins/vendor_update.md) | ⚙ | Vendor database update | | | | `WEBHOOK` | [_publisher_webhook](plugins/_publisher_webhook.md) | ▶️ | Webhook notifications | | | | `WEBMON` | [website_monitor](plugins/website_monitor.md) | ♻ | Website down monitoring | | | +| `WIFICANARY` | [wificanary](plugins/wificanary.md) | ♻ | Passive WiFi rogue-AP / evil-twin detection | | | | `WOL` | [wake_on_lan](plugins/wake_on_lan.md) | ♻ | Automatic wake-on-lan | | | diff --git a/mkdocs.yml b/mkdocs.yml index 3c1f98324..996910109 100755 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -207,6 +207,7 @@ theme: icon: material/lightbulb-outline name: Switch to dark mode markdown_extensions: + - tables - admonition - pymdownx.superfences - pymdownx.highlight diff --git a/server/plugins/wificanary/README.md b/server/plugins/wificanary/README.md index 146f59fbc..e0113143d 100644 --- a/server/plugins/wificanary/README.md +++ b/server/plugins/wificanary/README.md @@ -21,17 +21,24 @@ Runs a periodic passive WiFi scan (`iw scan`, no monitor mode) and flags rogue A - Vendor names for a rogue device do show up in the GUI, but not from this plugin - a `Devices` row it creates gets its `Vendor` field filled in by core's own `VNDRPDT` (vendor_update) plugin on its next run, same as any other device. That lookup is a local OUI-database match, not a network call, so it's deliberately kept out of the scan step itself. - The duplicate-SSID/different-vendor check only looks at SSIDs you've listed in `WIFICANARY_trusted_aps` - an untracked network's own AP diversity (e.g. a cafe chain) is never flagged. For a tracked SSID, every explicitly-trusted BSSID's OUI is whitelisted (see the range-extender note above) - only an OUI that matches *none* of them gets flagged. "Vendor" here means OUI (BSSID's first 3 octets) compared directly between the APs sharing an SSID, not a vendor-name lookup. -- `WIFICANARY_TRUSTED_SECURITY` is multi-select. An observed encryption exactly matching any selected value is always accepted; otherwise it's flagged if it's weaker than the *strongest* value you selected - deliberately, not a typo: comparing against the weakest would make selecting more than one value pointless (anything at or above the weakest would silently pass either way, making the rest of the selection meaningless). Worked example for `wep` + `wpa2` selected: +- `WIFICANARY_TRUSTED_SECURITY` is multi-select. An observed encryption exactly matching any selected value is always accepted; otherwise it's flagged if it's weaker than the *strongest* value you selected - deliberately, not a typo: comparing against the weakest would make selecting more than one value pointless (anything at or above the weakest would silently pass either way, making the rest of the selection meaningless). - | Observed | Result | - |---|---| - | `wep` | OK (listed) | - | `wpa2` | OK (listed) | - | `wpa` | **Alert** - not listed, and weaker than `wpa2` | - | `open` | **Alert** - weaker than everything | +Worked example for `wep` + `wpa2` selected: + +| Observed | Result | +|---|---| +| `wep` | OK (listed) | +| `wpa2` | OK (listed) | +| `wpa` | **Alert** - not listed, and weaker than `wpa2` | +| `open` | **Alert** - weaker than everything | + +Select `open` here only for a network you intend to run unencrypted on purpose (e.g. a guest SSID) - otherwise leave it out so an unexpected open clone or downgrade still trips an alert. - Select `open` here only for a network you intend to run unencrypted on purpose (e.g. a guest SSID) - otherwise leave it out so an unexpected open clone or downgrade still trips an alert. - Encryption is classified from the `iw scan` IEs into `open` / `wep` / `wpa` / `wpa2` / `wpa3`. A `Privacy`-flagged AP with neither an `RSN` nor a `WPA` information element is reported as `wep` - the closest reasonable guess for that combination, not a certainty. - See the [WIFICANARY addendum on issue #1789](https://github.com/netalertx/NetAlertX/issues/1789#issuecomment-5777023835) for the reasoning behind creating a device for never-associated attacker BSSIDs, and for the "known device turned rogue" idea. The implemented version above only covers the BSSID-identity angle (is the radio itself a device you already trust?) - the addendum's original, richer version (cross-referencing the *source MAC of attack traffic* like deauth/probe floods) still needs monitor-mode data this plugin doesn't have. -- Author: `mauricio-camayo` +## Other info + +- Version: 1.0.0 +- Author: [mauricio-camayo](https://github.com/mauricio-camayo/) +- Release Date: `2026-09-26`