live: heartbeat sync 2026-10-21T17:49:41-07:00 (Refs #11)
This commit is contained in:
1 parent
c0d840a8bb
commit
017404aa51
30 files changed
+568
-109
No files matched your search
@@ -1,47 +1,49 @@
|
||||
---
|
||||
name: gitea-token-from-http-credential-store
|
||||
description: "Extract the Dankclaw Gitea token from ~/.config/secrets/gitea (it is the URL password, not key=value lines) for API calls, and diagnose the silent empty-token trap that makes public-repo reads pass while writes fail."
|
||||
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.
|
||||
---
|
||||
|
||||
The Gitea credential store line on Frank's boxes is **http** (not https) with a percent-encoded port, and the **token is the URL password** — there are NO `username=`/`password=` lines:
|
||||
# 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:<40-char-token>@192.168.0.143%3a3000
|
||||
http://dank:b7caa2f689cdc00841854b85cd0173386f707d86@192.168.0.143%3a3000
|
||||
```
|
||||
|
||||
## Extraction that actually works
|
||||
Three traps, all of which produce a silent **401 Unauthorized** rather than a parse error:
|
||||
|
||||
```bash
|
||||
tok=$(sed -nE 's#^[a-z]+://[^:]+:([^@]+)@.*#\1#p' ~/.config/secrets/gitea | head -1)
|
||||
echo "tok len ${#tok}" # must be 40 — assert before any call
|
||||
cfg=$(mktemp); chmod 600 "$cfg"; printf 'header = "Authorization: token %s"\n' "$tok" > "$cfg"
|
||||
curl -s -K "$cfg" http://192.168.0.143:3000/api/v1/<path>
|
||||
rm -f "$cfg" # in the SAME session: the file holds a live token
|
||||
```
|
||||
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?://`:
|
||||
|
||||
## `git credential-store --file … fill` answers EMPTY — do not debug it
|
||||
```bash
|
||||
TOK=$(sed -n 's#^http[s]*://[^:]*:\([^@]*\)@.*#\1#p' ~/.config/secrets/gitea)
|
||||
test -n "$TOK" || echo "extraction failed" # never ship an unasserted capture
|
||||
```
|
||||
|
||||
Tried 2026-10-21 while opening `dank/command-center` PR #61: the obvious extraction
|
||||
```py
|
||||
tok = re.search(r"https?://[^:]*:([^@]+)@", pathlib.Path.home().joinpath(".config/secrets/gitea").read_text()).group(1)
|
||||
```
|
||||
|
||||
```bash
|
||||
printf 'protocol=http\nhost=192.168.0.143\nport=3000\n\n' | git credential-store --file ~/.config/secrets/gitea fill
|
||||
```
|
||||
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.
|
||||
|
||||
prints **nothing**, with no error. Not permissions, not a wrong path: the stored line encodes the port inside the host field (`@192.168.0.143%3a3000`), so a `host=`+`port=` query can never match it. Add `path=` or drop `port=` and it still answers empty. Read the file with `sed` (recipe above) and move on — the chain `TOKEN=$(…) && [ -n "$TOKEN" ] && …` fails silently at the test, which reads like a curl failure because the `&&` hides which link broke.
|
||||
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.
|
||||
|
||||
## The silent-empty-token trap (bit 2026-10-21, cost a debug detour)
|
||||
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.
|
||||
|
||||
An `awk -F= '/^username=/{...}'` parse of this file yields `tok=""` **silently** — and reads still appear to work when the repo is **public**: `dank/serverAppConfigs` and `dank/command-center` return real issue/label data unauthenticated, so every census "passes" until the first **write** (issue comment, label, PR create/merge) fails with `{"message":"token is always required"}`-style errors or 404s (private repos 404 on an empty token — that is an auth problem, NOT a missing repo).
|
||||
Auth header for every call: `Authorization: token $TOK` (the `token` keyword is required; a bare
|
||||
value 401s too).
|
||||
|
||||
- `echo "tok len ${#tok}"` (must be 40) before believing ANY API result — reads included.
|
||||
- Prove auth once per session: `GET /api/v1/user` → `"login":"dank"`.
|
||||
- `curl -s -K <600-perm file>` carrying `header = "Authorization: token $tok"` — never `-H` on argv (`/proc/<pid>/cmdline` is world-readable; this leaked an HF token once).
|
||||
- `jq -n --arg t … --arg h … --arg b "$(/bin/cat /tmp/pr.md)" '{…}'` — `$(cat file)` gets optimised away in this harness, so use `--rawfile b /tmp/pr.md` instead.
|
||||
**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.
|
||||
|
||||
## Other notes
|
||||
|
||||
- `git credential fill` fails headless here (`could not read Username … terminal prompts disabled`); read the store file directly instead.
|
||||
- Never print the token: mask when inspecting the file —
|
||||
`sed -E 's#(://[^:]+:)[^@]+@#\1REDACTED@#' ~/.config/secrets/gitea`
|
||||
- Merge writes need form-encoded fields, not JSON — see `gitea-pr-api-cycle`.
|
||||
- Issue/PR numbers are **per repo**: `dank/dankvoice` #8–#11 (refactor, hardening, AbortError fix, menu defects) are unrelated to `dank/command-center` #8–#11 (SDLC, trunk-law). Read the body from the repo the work targets before referencing an issue in a commit message.
|
||||
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`.
|
||||
Reference in new issue
Block a user