--- 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.