Skip to content

githubauth follow-ups: unpinned gh callers, config-derived gitea host, scrub/JSON/identity residuals #413

Description

@cameronsjo

#412 made the GitHub host configurable on the projects/review inventory path with the pin total there. This issue collects the seams that PR deliberately left outside its scope, plus residuals from its step-0 security review.

Unpinned gh callers (still github.com-shaped)

These shell out to gh without githubauth.Runner, so they follow ambient GH_HOST (or default to github.com) and ignore [github] host:

  • internal/branch/branch.go:341,364,508
  • internal/pr/ref.go:219 (and ref.go:246-248 has its own github-only URL parse)
  • internal/pr/session.go:195, internal/pr/launch.go:548, internal/pr/search.go:68
  • internal/doctor/doctor.go:195 — also the one seam that renders raw gh stderr into a Check Detail (bounded by termsafe.SafeLine at internal/cli/doctor.go:120; worth an inline comment naming why it is allowed, since doctor is what an operator runs when the new host misbehaves)

Docs after #412 scope the pin claim honestly ("the projects/review inventory path"); this issue is the widen-or-document decision for the rest.

Config-derive the gitea host in canonicalHost

internal/projects/project.go canonicalHost still hardcodes git.sjo.lol"gitea". A personal hostname baked into a public binary; it should derive from [review.gitea].host (or a projects-side equivalent) the same way the GitHub arm now derives from [github].host.

Security-review residuals (step-0 review of #412)

  • Token scrub is empty-string, not unsetexec.RunWithEnv can only add vars, so the scrub sets GH_TOKEN="" etc. gh (2.98.0) treats empty as unset, but that is gh-internal behavior; a filtered-env seam (RunWithEnvFiltered or building cmd.Env from a filtered os.Environ()) would make the scrub a property of the process env. Descendant processes (gh repo clone → git → credential helper) inherit the empty vars today.
  • --json inventory carries no degradation signal — notes are stderr-only and projects list --json emits a bare array, so a wrong-host/degraded run is indistinguishable from a small account to a script. Consider {repos, notes} or a nonzero exit when a host contributed zero rows plus a note.
  • Repo.Host is a token, not a hostname — the clone tree (Dir/github/<owner>/<name>) persists across a [github].host flip; a stale clone whose origin read fails can collide with a new-host clone at the same dest with no operator tooling to resolve it. Stamping the FQDN and deriving the badge for display would fix identity durability.
  • NewGitea renders an invalid host with %q — the one config-value render on a rejection path; make it categorical like githubauth.ResolveHost.
  • Linux noteos.UserConfigDir() honors XDG_CONFIG_HOME, so on Linux the config path (and thus the pinned host) is env-steerable; the token scrub is the bound that covers it, worth a line in the threat-model comment.

Aside

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions