Files
agent-skills/skills/modded-app-update-pattern/SKILL.md
T
Malin fa7c367420 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
2026-08-08 14:01:43 +02:00

3.9 KiB

name, description
name description
modded-app-update-pattern 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:

cd /app
git checkout -b upstream-vendor <upstream-tag-or-commit>
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.