Skip to content

GITHUB_TOKEN stored as as_needed breaks clone-per-agent for PAT-authenticated repos #1437

Description

@ptone

Bug

When creating a project with GitRemoteURL + GithubToken (no GitHub App), the token is stored as a project secret with InjectionMode: "as_needed" (handlers_projects_core.go:479). The as_needed mode skips injection in the first pass of the two-pass env resolution — secrets are only injected when the broker explicitly requests them in a second pass.

However, the per-agent git clone runs during sciontool init (init.go:1546) — before any second-pass negotiation occurs. The clone reads os.Getenv("GITHUB_TOKEN"), which returns empty because the first pass skipped the as_needed secret. The clone fails:

could not read Username… terminal prompts disabled

Impact

Workspace mode Affected? Why
clone-per-agent Yes In-container clone reads empty GITHUB_TOKEN
worktree-per-agent Yes Falls back to in-container clone, same failure
shared-workspace No Hub-side clone reads token directly from secret backend, bypasses injection mode
GitHub App projects No App mints a fresh token into ResolvedEnv, bypasses stored secret
NoAuth agents No Explicit exemption added in #1165 fetches token directly

Root cause trace

  1. Storagepkg/hub/handlers_projects_core.go:479: Hardcoded InjectionMode: "as_needed" when storing GITHUB_TOKEN during project creation.

  2. First-pass skippkg/hub/httpdispatcher.go:1605-1606: resolveEnvFromStorage skips as_needed secrets. Also httpdispatcher.go:2780: resolveSecrets skips as_needed environment-type secrets.

  3. Second-pass too latepkg/hub/httpdispatcher.go:1073-1089: resolveAsNeededForKeys only runs after broker reports needed keys. The clone happens during sciontool init — before any negotiation.

  4. Clone failscmd/sciontool/commands/init.go:1546,1581: os.Getenv("GITHUB_TOKEN") returns empty → buildAuthenticatedURL produces unauthenticated URL → git prompts for creds → fails (GIT_TERMINAL_PROMPT=0).

Fix

Change line 479 of pkg/hub/handlers_projects_core.go from:

InjectionMode: "as_needed",

to:

InjectionMode: "always",

GITHUB_TOKEN is a git credential needed at container startup before any two-pass negotiation. always is the semantically correct mode. This is consistent with the NoAuth exemption (#1165) which already injects it unconditionally.

Data migration: Existing projects whose GITHUB_TOKEN is stored as as_needed should be updated to always in the secrets table.

No other secrets are affected — all other as_needed secrets are hub-scoped TypeVariable secrets (chat integration keys, GitHub App keys, migrated plugin keys), not project-scoped GITHUB_TOKEN.

Files

  • pkg/hub/handlers_projects_core.go:479 — the hardcoded as_needed (the bug)
  • pkg/hub/httpdispatcher.go:1605-1606,2780 — first-pass skip logic
  • pkg/hub/httpdispatcher.go:616-658 — NoAuth exemption (prior art for the fix)
  • cmd/sciontool/commands/init.go:1546,1581 — per-agent clone reading os.Getenv
  • pkg/hub/handlers_projects_core.go:1215-1247resolveCloneToken (why shared-workspace works)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions