#!/bin/sh
# git credential helper for the ambient GitHub path (github-broker.ts).
#
# git invokes `git-credential-sky get` for https://github.com operations
# (wired via /etc/gitconfig with `useHttpPath = true`, so the `get` request
# on stdin carries protocol/host/path). We answer ONLY for host=github.com
# over https — anything else gets no output, so the token can never be
# handed to a look-alike host. On a match we fetch a short-lived,
# repo-scoped GitHub App installation token from the in-container loopback
# broker and emit it in git's credential protocol, marked `ephemeral=1`
# (never stored) with `password_expiry_utc` so git >=2.34 discards it the
# moment it expires. When no broker is running (channel without the github
# connector), emit nothing and exit 0 — git falls through to anonymous
# access, so public clones still work.
#
# Broker contract: GET http://127.0.0.1:7791/git-credential[?repo=<path>] ->
#   line 1: bare installation token
#   line 2: UNIX-epoch expiry seconds
#
# The `path` git sends (useHttpPath = true) is forwarded as `repo=`, so the
# broker mints a token scoped to THAT repository instead of every repo the
# channel can reach. The broker reads only the first two path segments and
# refuses a repo the channel was not granted (HTTP 403).

# Overridable ONLY so this helper can be tested against a stub broker on an
# ephemeral port; production always uses the loopback default.
# No GitHub on this instance (capability off, or no App secret). Refuse loudly
# rather than emitting nothing, which git would silently retry anonymously.
if [ "${FOUNDATION_GITHUB_DISABLED:-}" = "1" ]; then
  echo "GitHub is not connected on this instance." >&2
  exit 1
fi

BROKER_URL="${FOUNDATION_GH_BROKER_URL:-http://127.0.0.1:7791/git-credential}"

[ "$1" = "get" ] || exit 0

# Parse the credential request (key=value lines, blank-line terminated).
host=""
protocol=""
path=""
while IFS= read -r line; do
  [ -n "$line" ] || break
  case "$line" in
    host=*) host="${line#host=}" ;;
    protocol=*) protocol="${line#protocol=}" ;;
    path=*) path="${line#path=}" ;;
  esac
done
[ "$host" = "github.com" ] || exit 0
[ "$protocol" = "https" ] || exit 0

# Only a plain repo path is forwarded — anything with characters that would
# need URL-escaping is dropped, which costs breadth (a channel-wide token)
# but never sends a malformed scope.
query=""
case "$path" in
  '' | *[!A-Za-z0-9._/-]*) ;;
  *) query="?repo=$path" ;;
esac

response="$(curl -fsS --max-time 25 --retry 2 --retry-connrefused "$BROKER_URL$query" 2>/dev/null)"
rc=$?
# rc=7 (connection refused) = no broker: silent anonymous fallthrough is
# correct (public clones on connector-less channels). ANY other failure is
# a broker that exists but misbehaved: fail LOUDLY (git reports the helper
# error) instead of degrading to anonymous and a misleading 404.
if [ $rc -eq 7 ]; then exit 0; fi
if [ $rc -ne 0 ]; then
  # curl exit 22 = an HTTP error from the broker; the one that is NOT
  # transient is 403 ("repository not granted"), i.e. this repo is not in the
  # channel's grants — ask a human to grant it rather than retrying.
  echo "git-credential-sky: broker error (curl exit $rc) — transient unless this repo is not in the instance's GitHub App installation" >&2
  exit 1
fi
token="$(printf '%s\n' "$response" | head -n 1)"
expiry="$(printf '%s\n' "$response" | sed -n '2p')"
if [ -z "$token" ]; then
  echo "git-credential-sky: broker returned an empty token — transient; retry shortly" >&2
  exit 1
fi
printf 'username=x-access-token\npassword=%s\nephemeral=1\n' "$token"
# Expiry only when the broker sent a well-formed epoch (defense in depth —
# a malformed line 2 must not corrupt the credential answer).
case "$expiry" in
  '' | *[!0-9]*) ;;
  *) printf 'password_expiry_utc=%s\n' "$expiry" ;;
esac
exit 0
