chore(skills): mint gitea-token-out-of-remote-url + record the store-format law

git 2.56 credential-store parses one URL per line (port included), not the
key=value block shape the man page shows for ~/.git-credentials; a block-format
file yields a silent empty get and git dies at askpass.
This commit is contained in:
Frank
2026-10-09 13:21:48 -07:00
parent 07fda88b1d
commit 79e780f280
2 changed files with 53 additions and 0 deletions
@@ -0,0 +1,52 @@
---
name: gitea-token-out-of-remote-url
description: "Move a Gitea/HTTP git token out of remote.origin.url into a credential store file, and verify auth works with prompts disabled."
---
# Move a git token out of the remote URL
A remote URL like `http://user:<token>@host:port/org/repo.git` puts the credential in
`.git/config` (copied by every clone), prints it in `git remote -v`, and git-lfs echoes the
whole URL in its `Locking support detected on remote` warning on every push.
## 1. Capture the token from the existing remote (never paste it into a message)
```bash
url=$(git remote get-url origin)
user=$(printf '%s' "$url" | sed -E 's#^http://([^:]+):[^@]+@.*$#\1#')
tok=$(printf '%s' "$url" | sed -E 's#^http://[^:]+:([^@]+)@.*$#\1#')
```
## 2. Write the credential file (URL form, port included)
```bash
umask 077
printf 'http://%s:%s@HOST:PORT\n' "$user" "$tok" > ~/.config/secrets/gitea
```
Git 2.56 `credential-store` does NOT parse the `protocol=`/`host=`/`password=` block shape
that `git credential fill` accepts on stdin: a block-format file gives a SILENT empty get,
then git falls through to askpass (`could not read Username`). One URL per line, port included.
## 3. Point git at it, strip the URL, silence the LFS echo
```bash
git config --global credential.helper 'store --file ~/.config/secrets/gitea'
git remote set-url origin http://HOST:PORT/org/repo.git
git config lfs.http://HOST:PORT/org/repo.git/info/lfs.locksverify true
```
## 4. Verify with prompts disabled (a hang is a failed credential)
```bash
printf 'protocol=http\nhost=HOST:PORT\n\n' | git credential-store --file ~/.config/secrets/gitea get
GIT_TERMINAL_PROMPT=0 git ls-remote --heads origin main # read auth
GIT_TERMINAL_PROMPT=0 git push --dry-run origin main # write auth
git remote get-url origin # must contain no '@'
grep -l "$tok" ~/.gitconfig */.git/config ~/.zshrc # must find nothing
```
A successful push over the bare URL is the end-to-end proof: the credential came from the file.
## 5. Sweep the leak
Same shape on every clone on the host — loop over `find ~ -maxdepth 4 -path '*/.git/config'`,
read `remote.origin.url`, scrub any URL containing `@`. One credential file serves them all
via the global helper.
## Rotate
Rewrite only the credential file, then delete the old token in the Gitea UI
(Settings → Applications). No remote URL, rc file, or repository changes.
@@ -1,3 +1,4 @@
- Gitea client auth on Frank's workstations (2026-10-09): the HTTP token lives ONLY in ~/.config/secrets/gitea (0600) behind a global helper git config --global credential.helper 'store --file ~/.config/secrets/gitea'. All remote URLs are bare (http://192.168.0.143:3000/dank/repo.git) — a token embedded in remote.origin.url leaks via .git/config, git remote -v, and the git-lfs "Locking support detected on remote" warning, which echoes the full URL on every push (silence it per repo with git config lfs.bare-url/info/lfs.locksverify true). TRAP, measured on git 2.56.0: git credential-store does NOT parse the protocol=/host=/username=/password= block shape in the store file — that shape is only what git credential fill accepts on stdin, and the man page's ~/.git-credentials example is misleading. A block-format file yields a SILENT empty get, git falls through to askpass and dies with "could not read Username for …" (SSH_ASKPASS=/usr/bin/false in the omp harness env). The store file must be one URL per line WITH the port: http://dank:token@192.168.0.143:3000. Verify before trusting it, with prompts disabled so failure is loud: printf 'protocol=http\nhost=192.168.0.143:3000\n\n' | git credential-store --file ~/.config/secrets/gitea get must print username+password; then GIT_TERMINAL_PROMPT=0 git ls-remote --heads origin main and git push --dry-run. Rotation = rewrite that one file, nothing else. Documented in omp-docs/tools/gitea/client-access.md (command-center commit cfed6ef).
- The origin remote of the command-center repo (~/.omp) embeds the Dankclaw Gitea token in plaintext: http://dank:token@192.168.0.143:3000/dank/command-center.git in .git/config. Consequence observed 2026-10-09: git push origin main echoes that URL (the git-lfs "Locking support detected" hint prints the full URL with the token) into stdout, so any transcript/log of a push contains a live credential. Recommended remediation proposed to Frank and NOT yet approved/applied — do not change remote auth unilaterally: git remote set-url origin http://192.168.0.143:3000/dank/command-center.git plus git config credential.helper 'store --file ~/.config/secrets/gitea' (that directory is Frank's existing 600-perm secret convention), and git config lfs.http://192.168.0.143:3000/dank/command-center.git/info/lfs.locksverify true to silence the lock hint. Reuse rule: when a token must be read from this repo, read it from the existing origin URL and reference its location only; never copy it into docs, skills, memory, or commit messages. Repo hooks: core.hooksPath=.githooks → pre-commit secret gate (patterns incl. eyJ… JWT shapes; override ALLOW_SECRETS=1) and pre-push git lfs pre-push, so pushes carry LFS objects.
- Fleet LLM model ids in ~/.omp/agent/models.yml were renamed to the unit-name scheme on 2026-10-08 (committed 0cb021b, pushed 2026-10-09): frank-medium → frank-archon (llamacpp dankserver, 192.168.0.235:7770, ctx 200000 / maxTokens 16384), frank-large → frank-dragoon (dankclaw, 192.168.0.143:7770, 217088 / 45056, text+image), frank-small → frank-zealot (dankclaw-3090, 192.168.0.143:7771, 200704 / 16384). Service/unit/script names are UNCHANGED — /v1/models still advertises frank-primary, frank-large, frank-secondary. LAW (verified live with chat-completion probes on all three): radiance, halogen-flash-server and llama.cpp all accept an arbitrary request model id, so a harness-side id rename needs no endpoint change; the response model field just echoes the served name. Server-side compaction moved from dankserver:7770 to 192.168.0.143:7771 (frank-zealot), thresholdPercent 70 → 85, and every model's compactionModel now points at llamacpp (dankclaw-3090)/frank-zealot so the wire id stays valid at the compaction endpoint. Provider names in models.yml are labels referenced from config.yml (modelRoles, task.agentModelOverrides) and from compactionModel — renaming one requires updating every reference; verify by parsing both YAML files and cross-checking all llamacpp (host)/id tokens (regex must allow the space+parens in the provider label; a naive whitespace split yields false "unresolved" hits). Also: git renders whole-directory renames as mass delete + mass untracked — the 2026-10-09 tree showed 116 D + 73 ?? for the managed-skills consolidation (94 → 25) and the memory-skill re-bucketing (dotfile-git-workflow → ghostty-text-aa + niri-display-rotation + noctalia-theme; handy-service-mgmt → handy-flm-inference; inference-runtime → llama-cpp-parallelism). Nothing was lost: index matched HEAD, so git restore recovers any of it.
- Measuring WHICH card is the bottleneck in a llama.cpp layer-split LLM server on a fleet host (frank-medium, Dankserver 192.168.0.235, 2x R9700 asymmetric PCIe: ROCm0=x16 ~31.5GB/s, ROCm1=x1 ~1.97GB/s) — two traps that produced wrong numbers on 2026-09-18: (1) RUN THE TRANSIENT MEASUREMENT SERVER ON AN ISOLATED PORT, not the production port. If it takes over the prod port (7770), live fleet traffic from other agents hits it and interleaves with your timed request — I measured 35:30 at 2.51 t/s on :7770 vs the true 31.5 t/s; on isolated :7790 (prod stopped to free VRAM, fleet hits the down 7770) it read 31.52 t/s. Override LISTEN_PORT in a temp env copy (sed), point curl at the new port. (2) Use AVERAGE rocm-smi --showuse over a LONG request (2k tokens, ~60s), sampled every 0.5s — PEAK util lies for a layer split because both cards are touched every token and both hit ~100% at peak. Average is the bottleneck indicator. FINDING (durable, specific to frank-medium): the x1 card (ROCm1) is the STRUCTURAL bottleneck at 98% avg util in every config — 35:30/36:29, drafter on ROCm1/ROCm0 all gave util0(x16)=41-43% / util1(x1)=98%, decode ~31.5 t/s in all four. It's COMPUTE-bound, not PCIe-bound (only ~5.2 MB activation crosses the x1 link per 512-token ubatch). The per-step cost is the verify phase (both cards run the full target) + the LOGITS, which are pinned to the card holding the last layers; the MTP drafter is a small nextn head so moving it (SPEC_DRAFT_DEVICE=ROCm0) buys nothing. 35:30 is the optimal split (balanced VRAM 1.27/1.85 GiB free); 36:29 buys 2 util points on the x16 card and erodes its VRAM (fit free 0.45 GiB) for no throughput gain. No llama-server flag moves the lm_head off the last-layer card, so the x1 bottleneck is architectural, not a mis-tune. Recorded in scripts/frank-medium.env (committed 6c6464a).