fix(#1970): bake token path into gh/git wrappers — env var didn't reach claude's bash-tool context

This commit is contained in:
damocles 2026-07-11 13:02:54 +02:00 committed by mara
commit 46007008a9
2 changed files with 21 additions and 23 deletions

View file

@ -45,12 +45,13 @@ When enabled, the container gets:
`x-access-token` + the PAT (GitHub ignores the username for PAT auth).
Host-scoped, so it never touches the forge (`localhost:3000`) or any
other remote.
- **Env**: `HIVE_GITHUB_TOKEN_FILE` (the token path — never the secret).
Both the wrapper and the credential helper read the token from the file
**at invocation time**, so a PAT written (or rotated) mid-session takes
effect immediately — no container rebuild or restart. Until the file
exists, `gh` / `git push` simply fail unauthenticated.
Both scripts read the token from `<state>/github-token` **at invocation
time**, so a PAT written (or rotated) mid-session takes effect immediately
— no container rebuild or restart. Until the file exists, `gh` / `git push`
simply fail unauthenticated. The token path is baked into the scripts at
build time (not read from an env var), because claude's Bash tool runs in a
minimal environment that wouldn't carry one.
## Provisioning

View file

@ -18,14 +18,17 @@ let
userName = config.hyperhive.user.name;
homeDir = "/home/${userName}";
# GitHub integration (hyperhive.github.enable): a `gh` wrapper + a git
# credential helper, both sourcing the PAT from HIVE_GITHUB_TOKEN_FILE at
# invocation time so a dashboard-pasted token takes effect with no rebuild.
# The scripts are static (they read env at runtime) — the enable flag only
# gates whether they're installed + the env is set, so the token value never
# enters the nix store. github.com only; git auths as `x-access-token` + PAT.
# credential helper, both reading the PAT from the agent's `github-token`
# state file at invocation, so a dashboard-pasted token takes effect with no
# rebuild. The token PATH is baked in at build time (nix knows `userName`) —
# NOT read from `$HIVE_GITHUB_TOKEN_FILE`, because claude's Bash tool runs
# `bash -c` in a minimal env that doesn't source `/etc/set-environment`, so
# the env var isn't present where `gh`/`git` actually run. The token value
# never enters the nix store (only its path). github.com only; git auths as
# `x-access-token` + PAT.
ghWrapper = pkgs.writeShellScriptBin "gh" ''
if [ -n "''${HIVE_GITHUB_TOKEN_FILE:-}" ] && [ -r "''${HIVE_GITHUB_TOKEN_FILE}" ]; then
GH_TOKEN="$(cat "''${HIVE_GITHUB_TOKEN_FILE}")"
if [ -r "/agents/${userName}/state/github-token" ]; then
GH_TOKEN="$(cat "/agents/${userName}/state/github-token")"
export GH_TOKEN
fi
exec ${pkgs.gh}/bin/gh "$@"
@ -33,11 +36,11 @@ let
gitCredHelper = pkgs.writeShellScriptBin "git-credential-hive-github" ''
# git credential-helper protocol: only the `get` action needs an answer.
[ "''${1:-}" = "get" ] || exit 0
if [ -n "''${HIVE_GITHUB_TOKEN_FILE:-}" ] && [ -r "''${HIVE_GITHUB_TOKEN_FILE}" ]; then
if [ -r "/agents/${userName}/state/github-token" ]; then
# GitHub ignores the username for PAT auth — `x-access-token` is the
# conventional placeholder; the PAT is the password.
printf 'username=x-access-token\n'
printf 'password=%s\n' "$(cat "''${HIVE_GITHUB_TOKEN_FILE}")"
printf 'password=%s\n' "$(cat "/agents/${userName}/state/github-token")"
fi
'';
# Hive-wide OpenTelemetry config (host-driven; baked in per-agent by
@ -1536,12 +1539,6 @@ in
# regardless of which profile files are sourced.
NIX_REMOTE = "daemon";
}
// lib.optionalAttrs config.hyperhive.github.enable {
# GitHub integration: point the gh wrapper + git credential helper at the
# agent's PAT file (written by the credentials tab / `hivectl github
# set-token`). Only the path — never the secret (see hyperhive.github.enable).
HIVE_GITHUB_TOKEN_FILE = "/agents/${userName}/state/github-token";
}
// lib.optionalAttrs (!config.hyperhive.autoCompact) {
# Zero watermark disables proactive compaction; the reactive path
# (compact-on-overflow) still fires when the session is truly full.
@ -1670,9 +1667,9 @@ in
# Wire the GitHub credential helper for `git push` over HTTPS. Host-scoped
# to `https://github.com`, so it never touches the forge (localhost:3000)
# or any other remote. Gated on hyperhive.github.enable; the helper reads
# the PAT from HIVE_GITHUB_TOKEN_FILE at invocation and auths as
# `x-access-token` + the PAT. System /etc/gitconfig merges under the agent's
# ~/.gitconfig (safe.directory), so this is additive.
# the PAT from the agent's `github-token` state file at invocation and auths
# as `x-access-token` + the PAT. System /etc/gitconfig merges under the
# agent's ~/.gitconfig (safe.directory), so this is additive.
# Nested-path binding + mkIf (matching the other `environment.etc."…"`
# entries above) — a whole-set `environment.etc = {…}` here would collide
# with them at the nix level ("attribute already defined").