From fa7c367420c17745fa84a67656a874c287fa398e Mon Sep 17 00:00:00 2001 From: Malin Date: Sat, 8 Aug 2026 14:01:43 +0200 Subject: [PATCH] skills: fleet map, default-deny standard, modded-app and vuln-scan skills - server-fleet-map: add gringo row - bastille-jail-provisioning: elevate default-deny-outbound to the standard for every new jail; reference gringo's live pf.conf - modded-app-update-pattern: new skill, fork/rebase pattern for locally patched apps; uses tailnetatlas on gringo as the concrete example - dependency-vuln-scanning: new skill, npm audit / pip-audit / osv-scanner cadence for deployments and monthly thereafter --- skills/bastille-jail-provisioning/SKILL.md | 27 ++++++ skills/dependency-vuln-scanning/SKILL.md | 82 +++++++++++++++++ skills/modded-app-update-pattern/SKILL.md | 100 +++++++++++++++++++++ skills/server-fleet-map/SKILL.md | 1 + 4 files changed, 210 insertions(+) create mode 100644 skills/dependency-vuln-scanning/SKILL.md create mode 100644 skills/modded-app-update-pattern/SKILL.md diff --git a/skills/bastille-jail-provisioning/SKILL.md b/skills/bastille-jail-provisioning/SKILL.md index 79c2561..4290047 100644 --- a/skills/bastille-jail-provisioning/SKILL.md +++ b/skills/bastille-jail-provisioning/SKILL.md @@ -130,6 +130,33 @@ curl -H 'Host: ' http:/// Only switch to testing via the host's `127.0.0.1` (or the public domain) once the `sites-enabled` vhost for this specific site actually exists. +## Default-deny outbound is the standard for every new jail + +**This is no longer an incident workaround — it is the default posture for +any jail created on any Bastille host in this fleet.** Most jails are +reverse-proxied inbound-only services and do not need outbound internet +access. Denying it by default limits blast radius if a jail is compromised +(fewer callback/exfil paths, no unexpected update pings). + +When you finish provisioning a new jail, it must land in the `block out` +ruleset, not the `pass out` ruleset. Only add it to the allowed list if its +actual function genuinely requires external reach, and document the reason +in `pf.conf` next to the IP: + +``` +# Jails that need real outbound internet access (function confirmed): +table { 10.20.0.14, 10.20.0.22, ... } +nat on $ext_if from to any -> ($ext_if) +pass out quick on $ext_if from to any keep state +block out quick on $ext_if from 10.20.0.0/24 to any +``` + +The live reference implementation is gringo's `/etc/pf.conf` (tracked in +`infra/gringo/pf/pf.conf`). Before considering any new jail complete, verify +its IP is either in the deny block or explicitly listed with a comment +explaining why it needs outbound access. "Might need it later" is not a +reason. + ## Every jail needs a dedicated NPM-facing port, not just `listen 80` **Confirmed real gap, 2026-08-07**: on jail hosts fronted by a shared diff --git a/skills/dependency-vuln-scanning/SKILL.md b/skills/dependency-vuln-scanning/SKILL.md new file mode 100644 index 0000000..c55e8de --- /dev/null +++ b/skills/dependency-vuln-scanning/SKILL.md @@ -0,0 +1,82 @@ +--- +name: dependency-vuln-scanning +description: Run dependency vulnerability scans on every new deployment/migration and monthly thereafter. Covers Node, Python, and general OS/library scanning. +--- + +# Dependency Vulnerability Scanning + +Dependency vulnerabilities are not a one-time checklist item. They should be +scanned on every new deployment or migration into the fleet, and then re-scanned +periodically thereafter. For this fleet size, **monthly** is a reasonable +cadence. + +## When to run + +- Before marking a new jail/container/app as "live" after provisioning or + migration. +- Before merging a dependency update. +- Monthly, against every actively maintained app and host. + +This applies to Docker-host deployments too — a container image is just another +artifact with dependencies. Cross-reference the provisioning checklist in +`skills/bastille-jail-provisioning/SKILL.md` and add a vulnerability-scan step +before considering any new jail complete. + +## Tooling by stack + +### Node.js / npm + +```bash +npm audit +``` + +Use `npm audit --audit-level=moderate` to filter noise if the project is large. +For a CI-friendly exit code, `npm audit --audit-level=high` will fail only on +high/critical findings. Always review the full output at least once. + +If the project uses `pnpm` or `yarn`, use their equivalents (`pnpm audit`, +`yarn audit`). The Node ecosystem is common on this fleet — expect to use this +one often. + +### Python + +```bash +pip-audit +``` + +Run inside the project's virtualenv so it sees the same packages the app will +actually use. If `pip-audit` is not installed, add it to the dev tooling in the +virtualenv rather than the system Python. + +### General / OS / multi-ecosystem fallback + +```bash +osv-scanner -r /path/to/project +``` + +`osv-scanner` is the best general fallback: it understands lockfiles from npm, +PyPI, Go, Rust, Maven, and others, and queries the OSV database. Use it when a +project mixes ecosystems or when you want a single scanner across a whole host. + +## What to do with findings + +1. **Triage, do not blindly upgrade.** A CVE in a dev-only dependency is not the + same as one in the runtime path of a public-facing service. +2. **Patch or pin.** Prefer a real upstream upgrade. If the upstream fix is not + available yet and the risk is real, consider pinning, removing the dependency, + or a temporary local patch (tracked via `skills/modded-app-update-pattern`). +3. **Re-scan after the fix.** A green `npm audit` or `pip-audit` output is the + only proof the finding is resolved. +4. **Record exceptions.** If a finding is accepted (e.g. internal-only tool, + no reachable attack path), write the justification down in the deployment + notes or the issue tracker, not just in someone's memory. + +## What not to do + +- Do not treat vulnerability scanning as optional for "internal-only" tools. + Internal tools often have the same dependencies and the same CVEs. +- Do not run a scan and ignore the output because it is long. Parse it, triage + it, file issues for anything that needs follow-up. +- Do not rely solely on the language-specific scanner when the project also + pulls in OS packages or container base-image packages; add `osv-scanner` or + the image scanner as a second opinion. diff --git a/skills/modded-app-update-pattern/SKILL.md b/skills/modded-app-update-pattern/SKILL.md new file mode 100644 index 0000000..81427a7 --- /dev/null +++ b/skills/modded-app-update-pattern/SKILL.md @@ -0,0 +1,100 @@ +--- +name: modded-app-update-pattern +description: How to keep a vendor app that has been locally patched update-safe, using a fork or two-branch local repo so upstream updates can be merged/rebased instead of becoming a forgotten, untracked diff. +--- + +# Modded App Update Pattern + +When an app or library has been custom-patched to work in this fleet, future +upstream updates must not silently overwrite those patches, and the patches +themselves must not become an undocumented, forgotten diff. The safe pattern is +to keep two distinct lines of history: + +- `upstream-vendor` — tracks exactly what was shipped by the vendor, with no + local changes. +- `main` / `deployed` — the running version, with local patches as clean + commits on top of `upstream-vendor`. + +This lets you merge or rebase the next upstream release onto `main` deliberately, +reviewing each local patch for conflicts and relevance rather than re-applying a +mystery diff by hand. + +## When to use this + +Use this whenever you modify source code, config templates, or package files +inside an app that came from upstream (GitHub, npm, PyPI, a vendor tarball). +Pure runtime secrets or host-specific `.env` files do not count — keep those +outside the repo entirely. But changes like these do: + +- Patching `requirements.txt` because the upstream pins break on FreeBSD. +- Adding a local `run.sh` or rc.d script that the vendor does not provide. +- Modifying source to fix a FreeBSD path, disable a broken widget, or adapt an + API endpoint. + +## Local-only version (no public fork) + +If the repo is already cloned on the deployment host and you do not need a +public fork: + +```bash +cd /app +git checkout -b upstream-vendor +git branch -m main deployed # or keep main +git checkout deployed +git rebase upstream-vendor # apply local commits on top of clean vendor state +``` + +After that: + +1. Fetch the new upstream tag into `upstream-vendor` and reset that branch to + it: `git checkout upstream-vendor && git reset --hard v2.3.4`. +2. `git checkout deployed && git rebase upstream-vendor`. +3. Resolve conflicts one patch at a time; each local change stays a separate + commit with a clear message. +4. Deploy and test. + +## Public-fork version + +If multiple hosts or people will deploy the app, create a fork on the internal +Gitea instance: + +1. Fork `vendor/app` to `CloudHost/app-deployed`. +2. Add the original repo as an additional remote in your local clone: + `git remote add vendor https://github.com/vendor/app.git`. +3. Keep `upstream-vendor` tracking the vendor remote and `main`/`deployed` + tracking the fork remote. +4. Push local patches to the fork. + +This makes the running version auditable and reusable without relying on one +host's working copy. + +## Concrete fleet example: tailnetatlas on gringo + +The `tailnetatlas` jail runs `crazyhoesl/tailnet-atlas`, cloned into `/app`. +The deployment has real local changes: + +- `app/requirements.txt` was modified for this environment. +- `run.sh` was added because the project ships no rc.d-friendly entrypoint. +- `venv/` exists as an untracked build artifact. + +If the upstream repo releases a new version, a plain `git pull` would either +merge the local changes blindly or fail with conflicts in `requirements.txt`. +The safer state is: + +``` +upstream-vendor -> commit matching the upstream release that was deployed +main/deployed -> upstream-vendor + "adapt requirements.txt for FreeBSD" + + "add run.sh for rc.d" + "ignore venv/" +``` + +Updating then becomes `git rebase upstream-vendor` on `main`, not a manual diff +rescue. + +## What not to do + +- Do not leave local changes uncommitted in a clone and hope you remember them + before the next update. +- Do not `git pull` upstream into the same branch that carries local patches + without reviewing the merge. +- Do not commit secrets into either branch. Runtime secrets belong in root-only + `.env` files or the secret store, never in the app repo. diff --git a/skills/server-fleet-map/SKILL.md b/skills/server-fleet-map/SKILL.md index ddf423f..dff9fbf 100644 --- a/skills/server-fleet-map/SKILL.md +++ b/skills/server-fleet-map/SKILL.md @@ -16,6 +16,7 @@ whichever host you happen to already be connected to. | **venus** | `100.109.251.127` (LAN `192.168.0.33`) | Corporate — internal business sites/tools, the iWP.es plugin-subscription platform, and other CloudHost-org first-party projects | Bastille jails, combined web+db (local MariaDB, no shared external DB host). New jails typically created via `bastille clone -a ` rather than from scratch. | | **granja** | `100.98.197.28` | Affiliate network — the travel/tourism site network (menorca.ro, palma.ro, and similar) | No public interface configured directly; sits behind a reverse-proxy manager (NPM) over Tailscale. See `docs/server-granja.md` for the local-curl-simulates-NPM testing trick. | | **funky** | `100.127.21.100` (LAN `192.168.0.218`) | Customers — sites migrated from the old Linux affiliate fleet, actual paying-customer properties (e.g. news.easycut.es, photomouse.ro) | Combined web+db+valkey, bastille jails. Migration target that absorbed several now-decommissioned Linux hosts (maagar, shoe, proton). | +| **gringo** | `100.95.46.79` (LAN `192.168.168.68`) | Internal apps/tools host — replacement for the old Linux Docker host barky-1 | ~45 Bastille VNET jails on `10.20.0.0/24` (APIs, dashboards, Gitea, analytics, productivity tools). Default-deny outbound pf model; NPM dedicated ports `8000 + last octet`. See `docs/server-gringo.md`. | | **zamolxis** | `100.115.128.41` | Standalone (non-jailed) FreeBSD site host | Not part of the granja/external-fleet jail families — a single site (Newspaper/tagDiv theme, PHP 8.5) running directly on the host, not in a jail. | | **cabrera** | `100.100.108.19`, SSH port `79` | External Linux affiliate-network host (BTPanel-style) | Part of the older Linux fleet (alongside raptor/maagar/formentor/moonie/spunky/proton/shoe — several since decommissioned/migrated to funky). Hosts easycut.es's main WooCommerce e-commerce site directly (not jailed). |