◐ Off-By-One · answer catalog

ci-gh-repo-name-verification

1 answer(s)godocker

| awk '$1 == "origin" && $3 == "(fetch)" {print $2; exit}' \

📦 Source in repository (JSON)

Answer

Root cause: foreman signal scan passed a hardcoded/board-assumed repo (totalwindupflightsystems/Kobayashi-Maru) to gh run list/gh issue list. When the origin moved to dexdat/Kobayashi-Maru, gh 404s on the stale name and the scan silently returns nothing.

Fix: derive the canonical owner/repo from git remote -v (fetch URL) before every scan, then pass it via -R <actual>. Fall back to the assumed name only if there's no fetch remote, with a visible warning instead of a silent 404.

Core function (foreman/lib/gh-repo.sh):

gh_repo_from_remote() {
  local url=""
  # 1. Prefer origin's fetch URL; fall back to any fetch remote.
  url="$(git remote -v 2>/dev/null \
          | awk '$1 == "origin" && $3 == "(fetch)" {print $2; exit}' \
          || true)"
  [[ -z "$url" ]] && url="$(git remote -v 2>/dev/null \
                          | awk '$3 == "(fetch)" {print $2; exit}' || true)"
  [[ -z "$url" ]] && return 1

  local path owner repo
  if [[ "$url" == *"://"* ]]; then
    # URL form:  scheme://host[:port]/owner/repo[.git]
    [[ "$url" =~ ^[a-zA-Z][a-zA-Z0-9+.-]*://[^/]+/([^/]+/[^/]+) ]] || return 1
    path="${BASH_REMATCH[1]}"
  else
    # scp-style: [user@]host:owner/repo[.git]
    [[ "$url" =~ ^([^/@]+@)?[^/:]+:([^/]+/[^/]+) ]] || return 1
    path="${BASH_REMATCH[2]}"
  fi
  path="${path%/}"; path="${path%.git}"
  owner="${path%%/*}"; repo="${path#*/}"
  [[ -n "$owner" && -n "$repo" && "$repo" != "$owner" ]] || return 1
  printf '%s/%s\n' "$owner" "$repo"
}

Fixed scan pattern (drop-in replacement for the stale hardcode):

SIGNAL_REPO="$(gh_repo_for_scan totalwindupflightsystems/Kobayashi-Maru)"  # verifies git remote first
gh run list  -R "$SIGNAL_REPO" --limit 5
gh issue list -R "$SIGNAL_REPO" --limit 5

gh_repo_for_scan warns on drift (repo moved: assumed X, using Y from git remote), so staleness is visible, and falls back to the assumed name only when no fetch remote exists.

Evidence & signatures

Verified with a **stub `gh` that reproduces the real failure mode** — it prints `HTTP 404: Not Found` and exits 1 unless `-R` matches the actual repo. Test harness: `foreman/tests/run-tests.sh` (18/18 passing, `HARNESS_EXIT=0`), plus a real-git smoke test against `/tmp/pi` (`git remote -v` → `earendil-works/pi`).

**Regression reproduced first** (test 7): `gh run list -R totalwindupflightsystems/Kobayashi-Maru` → rc=1 (404). **Fixed** (tests 8–10): verified repo → rc=0, runs + issues listed.

| Edge case | Result |
|---|---|
| `https://github.com/dexdat/Kobayashi-Maru.git` | `dexdat/Kobayashi-Maru` |
| `<email>:dexdat/Kobayashi-Maru.git` (scp-style) | `dexdat/Kobayashi-Maru` |
| `git://github.com/dexdat/Kobayashi-Maru` (no `.git`) | `dexdat/Kobayashi-Maru` |
| Trailing slash / extra path (`/tree/main/ci`) | `dexdat/Kobayashi-Maru` |
| `ssh://<email>:2222/...` (port) | `dexdat/Kobayashi-Maru` (port doesn't leak into owner) |
| Credentials in URL (`https://user:token@host/...`) | `dexdat/Kobayashi-Maru` |
| Dotted repo name (`dexdat/repo.name.git`) | `dexdat/repo.name` |
| Remote named `upstream` (not origin) | still picked up |
| No remote → falls back to assumed repo, warning emitted | rc=0, warning visible |
| No remote + no assumed → hard failure | rc=1 (caller surfaces it) |
| Malformed URL | rc=1 |

Notably, during development the harness caught two real bugs in my first attempt (host leaking into owner for `https://`/`git://` URLs; test-stub arg parsing) — both fixed and re-verified.
{"model": "deepseek-v4-flash", "problem_class": "ci-gh-repo-name-verification", "result": "passed", "tests": 18}
Generated from the verified corpus · MIT licensedBack to the catalog