Files
pm3py/docs/plans/2026-07-05-firmware-fork-dt-migration.md
2026-07-05 18:29:18 -07:00

5.4 KiB

Firmware fork → DT Gitea migration + clean RRG-tracking model

Status: Planned, not started · Date: 2026-07-05 · Related: 2026-07-03-firmware-upstream-rebase-plan.md

Goal

Host pm3py and its Proxmark3 firmware fork on the DT Gitea, customize the firmware, and pull RRG (RfidResearchGroup/proxmark3) updates without ever touching the RRG version — via the standard rebase-fork model.

The model

One firmware repo, <dt-org>/proxmark3, with a strict branch split:

Branch Role
master pristine RRG mirror — only ever fast-forwarded from upstream, never our commits
pm3py our customizations (atomic single-file commits) on top of master; the submodule pins this

Remotes: origin = <dt-org>/proxmark3 (SSH), upstream = RRG (already configured). pm3py itself moves to <dt-org>/pm3py; its .gitmodules points at the pm3py branch.

Why rebase-fork (not merge / subtree / quilt): our ~33 patches already are a hand-managed atomic-commit patch queue; rebase is the native git form. It keeps git diff master..pm3py a clean picture of exactly our changes, and resolves the recurring iso15693.c conflict (24/33 commits touch it) once per update instead of on every merge.

The three real gotchas (all handled)

  1. Gitlink must be published or fresh clones dangle. The firmware pm3py tip must be pushed before pm3py's gitlink references it (Phase 6 before 7).
  2. The uncommitted EML host-poll change is in no ref — it would be silently lost on any checkout/reclone. Backed up (scratchpad/eml-hostpoll.patch) and committed on pm3py in Phase 5.
  3. Our history is intermixed with upstream mergesmerge-base(main, upstream/master) is only 11 commits below HEAD, so 48 of our 59 commits sit below it in the upstream DAG. A naive rebase --onto master $MB pm3py would carry only the top 11 and drop 48. So the migration does not rebase — it mirrors everything verbatim and defers the clean split to the first upstream pull (see Ongoing).

Migration runbook (no rewrite, no data loss)

Split by who: [A] = I do it locally (offline); [U] = you run it (Gitea web / pushes, since my sandbox can't reach :20022).

  • Phase 0 [A] — safety net: back up the EML diff (done); tag every must-preserve head bak/<name>; git bundle create --all for both repos.
  • Phase 1 [U] — create EMPTY DT repos <dt-org>/proxmark3 and <dt-org>/pm3py (no README/license — a first commit blocks a mirror push).
  • Phase 2 [A] — materialize local heads: git branch pm3py main (verbatim), and local branches for the 6 feature branches. No rebase.
  • Phase 3 [U] — mirror-push firmware: git fetch upstream master then git push --mirror ssh://git@git.dngr.us:20022/<dt-org>/proxmark3.git (safe: target empty).
  • Phase 4 [U] — seed master: git push <dt> refs/remotes/upstream/master:refs/heads/master.
  • Phase 5 [A] — commit EML on pm3py, repoint config, bump gitlink: commit the EML host-poll; rename firmware originmikefaith-backup, add DT origin; set .gitmodules url=DT SSH + branch=pm3py, submodule sync; git add .gitmodules firmware + commit.
  • Phase 6 [U] — publish the firmware tip (CRITICAL): git push origin pm3py.
  • Phase 7 [U] — mirror-push pm3py + repoint origin to <dt-org>/pm3py.
  • Phase 8 [U] — VERIFY a fresh git clone --recurse-submodules of <dt-org>/pm3py: submodule resolves (no "reference is not a tree"), make PLATFORM=PM3GENERIC + pytest pass, then a hardware smoke test.
  • Phase 9 [U] — retire old repos (ARCHIVE read-only, never delete) only after Phase 8.

Rollback at any point: nothing is rewritten/deleted, so git remote rename mikefaith-backup origin restores the pre-migration state; the old repos and the Phase-0 bundles are the backstop until Phase 8 passes.

Ongoing: pull RRG updates without impacting RRG

git -C firmware fetch upstream master
git -C firmware push origin refs/remotes/upstream/master:refs/heads/master   # ff-only, pristine
# rebase our patches onto the new base in an isolated worktree, build+test, then:
git -C firmware push origin rebase-wip:pm3py --force-with-lease   # only our branch, leased
cd <pm3py> && git add firmware && git commit -m "chore(firmware): rebase onto RRG <tip>, bump gitlink"

master is append-only (never rewritten); only pm3py is force-pushed, always with a lease. The first pull also does the deferred clean split: enumerate our commits (git log --author=michael --author=dangerous-tac0s upstream/master..pm3py), skip already-upstreamed ones (hf-mfu-esetblk PR #3404), and rebuild pm3py as an explicit patch series onto fresh master — validate git diff <rebuilt> pm3py shows only deltas upstream lacks. Later pulls are the simple linear rebase --onto case. See the 2026-07-03 plan for the per-file conflict detail (iso15693.c hot spot).

Inputs needed from you

  • The DT org name on git.dngr.us (substitutes <dt-org>).
  • Fork default branch: recommend master (matches RRG).
  • Confirm your SSH key has write in the <dt-org> namespace.

Provenance

Multi-agent workflow (strategy eval + state audit + topology design → synthesized runbook). The adversarial data-loss verify pass was cut short by a rate limit; the mirror-to-empty-repo safety, publish-before-reference ordering, and EML backup were re-checked by hand.