--- name: gitea-token-from-http-credential-store description: Extract the Dankclaw Gitea token from ~/.config/secrets/gitea (a URL-line credential store using http:// and %3a-encoded port) without the empty-token 401; covers the https-only extraction trap and the $$..$$ shell-expansion trap. --- # Gitea token out of the HTTP credential store `~/.config/secrets/gitea` is a git **credential-store file**, not a bare token file. On the Dank boxes it reads: ``` http://dank:b7caa2f689cdc00841854b85cd0173386f707d86@192.168.0.143%3a3000 ``` Three traps, all of which produce a silent **401 Unauthorized** rather than a parse error: 1. **Scheme is `http://`, not `https://`.** An extraction pattern written `s#^https://…#` matches nothing and yields an empty token. GNU BRE has no `?` quantifier — use the `http[s]*://` form or Python `https?://`: ```bash TOK=$(sed -n 's#^http[s]*://[^:]*:\([^@]*\)@.*#\1#p' ~/.config/secrets/gitea) test -n "$TOK" || echo "extraction failed" # never ship an unasserted capture ``` ```py tok = re.search(r"https?://[^:]*:([^@]+)@", pathlib.Path.home().joinpath(".config/secrets/gitea").read_text()).group(1) ``` Always assert non-empty (`test -n`) or print `${#TOK}` once: a correct token here is 40 chars, and the length check catches a wrong pattern without echoing the secret. 2. **The token body contains `$$…$$`.** An omp output token inside a *file* is inert, but pasted literally into a shell script line it expands (`$$` = shell PID). Keep it in a variable or read it from the file — never inline it in command text. 3. **Port is percent-encoded (`%3a3000`).** Don't rebuild the API URL from that line; the working endpoints are `http://192.168.0.143:3000/api/v1/...` and `https://gitea.franksdank.cloud/api/v1/...` — both serve the same API, so a host/port mismatch looks like an auth failure. Auth header for every call: `Authorization: token $TOK` (the `token` keyword is required; a bare value 401s too). **Never print the token.** Extract into a variable, then use `$TOK`; read the file with `read path=...:raw` only when you must inspect the format. Related: `gitea-pr-api-cycle` (POST/PATCH body shapes), `gitea-merge-form-encoded` (merge needs `do=merge&merge_style=no-ff`, answers 200 with an empty body — verify by fetching the PR, not by reading the response), `gitea-credential-store-url-format`.