diff --git a/docs/github.md b/docs/github.md index 8665f8fb..0f6c14cd 100644 --- a/docs/github.md +++ b/docs/github.md @@ -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 `/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 diff --git a/nix/templates/harness-base.nix b/nix/templates/harness-base.nix index 13eefd3b..84bc6045 100644 --- a/nix/templates/harness-base.nix +++ b/nix/templates/harness-base.nix @@ -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").