diff --git a/docs/backlog/P1/B-0835-installer-config-bugs-cluster-hostname-not-unique-gh-auth-not-respected-banner-password-disclosure-empirical-aaron-2026-05-26.md b/docs/backlog/P1/B-0835-installer-config-bugs-cluster-hostname-not-unique-gh-auth-not-respected-banner-password-disclosure-empirical-aaron-2026-05-26.md index adbeaaa8db..b80addc8f9 100644 --- a/docs/backlog/P1/B-0835-installer-config-bugs-cluster-hostname-not-unique-gh-auth-not-respected-banner-password-disclosure-empirical-aaron-2026-05-26.md +++ b/docs/backlog/P1/B-0835-installer-config-bugs-cluster-hostname-not-unique-gh-auth-not-respected-banner-password-disclosure-empirical-aaron-2026-05-26.md @@ -71,6 +71,96 @@ operator's GH user; check `/etc/zeta/operator-ssh-keys.nix` for populated pubkey array; check `git -C /etc/zeta remote -v` for the clone URL + verify it pulls without credentials prompt. +### Bug 2a — git push prompts HTTPS basic-auth despite gh auth login (CRITICAL — blocks self-registration; empirical 2026-05-26) + +Empirical anchor 2026-05-26 (2nd physical hardware-support test on +same hardware, post-Bug-1-fix re-flash): + +``` +[iter-5.4.0] Run gh auth login now? [Y/n]: Y +[iter-5.4.0] running 'gh auth login' (interactive)... +! First copy your one-time code: D30B-468F +Open this URL to continue in your web browser: https://github.com/login/device +■ Authentication complete. +! Authentication credentials saved in plain text +■ Logged in as AceHack +[iter-5.4.0] gh auth login: SUCCESS +... +[iter-5.4.1] ── self-registration commit+push (B-0812) ── +[iter-5.4.1] maintainer: AceHack +[iter-5.4.1] node-name: node-efe404 +Switched to a new branch 'register-node-efe404-20260527T0005332' +Username for 'https://github.com': acehack +Password for 'https://acehack@github.com': +``` + +`gh auth login` SUCCEEDED as AceHack via device flow, but the +subsequent `git push -u origin ` at iter-5.4.1 prompted for +HTTPS basic-auth. Root cause: `gh auth login` stores the token in +its own config but does NOT configure git's credential helper. Git +push goes through the default credential-store chain which doesn't +know about gh's token. + +**Standard fix**: `gh auth setup-git` writes a `credential.helper` +config that delegates to `gh auth git-credential`. Once configured, +all git operations against github.com automatically use the gh token. + +**Implementation**: insert `gh auth setup-git` immediately after a +successful `gh auth login` in `zeta-install.sh` Step 6.8. Failure of +setup-git is non-fatal (warning only); the prompt-for-password +behavior is the symptom indicating it didn't run. + +**Acceptance**: 3rd physical test (Bug 2a fix re-flash) shows +iter-5.4.1 `git push` completes silently without basic-auth prompt; +self-registration PR URL is printed; PR is browseable on github.com. + +### Bug 2b — gh ssh-key list returns empty / fails (degraded; substrate-honest WARN insufficient; empirical 2026-05-26) + +Same empirical anchor 2026-05-26: + +``` +[iter-5.4.0] fetching operator's SSH pubkeys via 'gh ssh-key list'... +[iter-5.4.0] WARN: 'gh ssh-key list' failed; no keys written +[iter-5.4.0] (gh auth succeeded but the user has no SSH keys +[iter-5.4.0] registered with GitHub, OR the jq/tee pipe broke) +``` + +The WARN already covers both candidate causes but doesn't help the +operator recover. Two candidate root causes need discrimination: + +1. **Auth scope missing** (most likely): `gh auth login` default + scopes are `repo, read:org, workflow, gist`. `gh ssh-key list` + requires `admin:public_key` OR `read:public_key`. Device-flow + without explicit `--scopes` will NOT request these. +2. **Operator has no SSH keys at GitHub**: returns empty list (no + error). Operator uses gh CLI auth + signed commits via gh, never + added SSH keys to their account. + +**Fix path**: capture stderr from `gh ssh-key list`; discriminate +between scope-error and empty-list cases; for scope errors, +substrate-honest guidance: + +``` + WARN: 'gh ssh-key list' returned no keys — gh token lacks SSH-key scope + To enable SSH-from-Mac path, run on the installed system: + gh auth refresh -s admin:public_key + gh ssh-key list --json key | jq -r '.[].key' | sudo tee -a /etc/zeta/operator-authorized-keys + sudo nixos-rebuild switch # picks up operator-authorized-keys.nix +``` + +For empty-list (no keys at GH): substrate-honest WARN names +https://github.com/settings/keys as fix surface. + +**Acceptance**: 3rd physical test shows substrate-honest WARN with +specific recovery commands; OR (if scope-mode pursued separately) +default install captures pubkeys without operator intervention. + +**Scope-prompt deferred**: rather than ask for elevated +`admin:public_key` scope by default (security tradeoff), the install +shows substrate-honest fallback. Future B-NNNN candidate: +opt-in flag `--with-ssh-key-scope` for operators who want one-shot +auto-population. + ### CORE REQUIREMENT (operator 2026-05-26 reframing) > "also i should not have to log in for any of this to start that diff --git a/full-ai-cluster/usb-nixos-installer/zeta-install.sh b/full-ai-cluster/usb-nixos-installer/zeta-install.sh index 6d82a31acc..ff84460d69 100755 --- a/full-ai-cluster/usb-nixos-installer/zeta-install.sh +++ b/full-ai-cluster/usb-nixos-installer/zeta-install.sh @@ -636,6 +636,25 @@ if [[ "$GH_AUTH_REPLY" =~ ^[Yy]$ ]]; then GH_AUTH_OK=1 echo echo "[iter-5.4.0] gh auth login: SUCCESS" + + # ── B-0835 Bug 2a fix: wire git to use gh token for HTTPS pushes ── + # `gh auth login` stores the token but does NOT configure git's + # credential helper. Without this step, subsequent `git push` to + # https://github.com/... prompts for HTTPS basic-auth (username + + # password) — empirically observed 2026-05-26 physical hardware- + # support test where iter-5.4.1 self-registration `git push -u + # origin ` prompted operator for "Password for + # 'https://acehack@github.com':" despite gh auth login succeeding + # as AceHack moments earlier. `gh auth setup-git` writes a + # credential.helper entry that delegates to `gh auth git-credential` + # so git push picks up the gh token automatically. + echo "[iter-5.4.0] wiring git credential helper to use gh token..." + if gh auth setup-git 2>&1 | tail -3; then + echo "[iter-5.4.0] git credential helper: configured" + else + echo "[iter-5.4.0] WARN: 'gh auth setup-git' failed; subsequent git push may prompt for password" + fi + echo "[iter-5.4.0] fetching operator's SSH pubkeys via 'gh ssh-key list'..." KEY_DST_DIR=/mnt/etc/zeta sudo mkdir -p "$KEY_DST_DIR" @@ -644,20 +663,45 @@ if [[ "$GH_AUTH_REPLY" =~ ^[Yy]$ ]]; then # the `key` field which contains the standard authorized_keys line # (algo + base64-pubkey; no comment). Each gets a comment appended # so the operator can identify it later: "gh-key-". - if gh ssh-key list --json id,key,title 2>/dev/null \ + # + # B-0835 Bug 2b fix: substrate-honest discrimination of failure modes. + # Capture stderr so we can distinguish (a) auth-scope error from + # (b) empty key list from (c) jq/tee pipe break. Empirically 2026-05-26: + # device-flow `gh auth login` only requests default scopes + # (`repo, read:org, workflow, gist`); `gh ssh-key list` requires + # `admin:public_key` OR `read:public_key` which are NOT in defaults. + # If scope is the issue, the WARN tells operator how to refresh. + SSH_KEY_ERR_FILE=$(mktemp -t zeta-ghkey-err.XXXXXX) + if gh ssh-key list --json id,key,title 2>"$SSH_KEY_ERR_FILE" \ | jq -r '.[] | "\(.key) gh-key-\(.id)-\(.title // "")"' \ | sudo tee "$KEY_DST" >/dev/null; then sudo chmod 0644 "$KEY_DST" GH_KEY_COUNT="$(wc -l < "$KEY_DST" | tr -d ' ')" - echo "[iter-5.4.0] wrote $GH_KEY_COUNT key(s) to $KEY_DST" - echo "[iter-5.4.0] the operator-authorized-keys.nix module will pick" - echo "[iter-5.4.0] them up during nixos-install (next step)" + if [ "$GH_KEY_COUNT" -gt 0 ]; then + echo "[iter-5.4.0] wrote $GH_KEY_COUNT key(s) to $KEY_DST" + echo "[iter-5.4.0] the operator-authorized-keys.nix module will pick" + echo "[iter-5.4.0] them up during nixos-install (next step)" + else + # Empty key list — either no keys at GitHub OR scope missing. + # Check stderr for scope error to discriminate. + if grep -qE "(scope|insufficient|admin:public_key|read:public_key)" "$SSH_KEY_ERR_FILE" 2>/dev/null; then + echo "[iter-5.4.0] WARN: 'gh ssh-key list' returned no keys — gh token lacks SSH-key scope" + echo "[iter-5.4.0] To enable SSH-from-Mac path, run on the installed system:" + echo "[iter-5.4.0] gh auth refresh -s admin:public_key" + echo "[iter-5.4.0] gh ssh-key list --json key | jq -r '.[].key' | sudo tee -a /etc/zeta/operator-authorized-keys" + echo "[iter-5.4.0] sudo nixos-rebuild switch # picks up operator-authorized-keys.nix" + else + echo "[iter-5.4.0] WARN: 'gh ssh-key list' returned no keys — operator has no SSH keys registered at GitHub" + echo "[iter-5.4.0] SSH-from-Mac fallback: add keys at https://github.com/settings/keys" + echo "[iter-5.4.0] then on the installed system, re-run the gh ssh-key list step (see B-0835 Bug 2b)" + fi + fi else echo "[iter-5.4.0] WARN: 'gh ssh-key list' failed; no keys written" - echo "[iter-5.4.0] (gh auth succeeded but the user has no SSH keys" - echo "[iter-5.4.0] registered with GitHub, OR the jq/tee pipe broke)" + echo "[iter-5.4.0] stderr: $(head -3 "$SSH_KEY_ERR_FILE" 2>/dev/null | tr '\n' ' ')" GH_KEY_COUNT=0 fi + rm -f "$SSH_KEY_ERR_FILE" 2>/dev/null || true else echo echo "[iter-5.4.0] gh auth login FAILED or was cancelled; skipping"