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
-
Storage — pkg/hub/handlers_projects_core.go:479: Hardcoded InjectionMode: "as_needed" when storing GITHUB_TOKEN during project creation.
-
First-pass skip — pkg/hub/httpdispatcher.go:1605-1606: resolveEnvFromStorage skips as_needed secrets. Also httpdispatcher.go:2780: resolveSecrets skips as_needed environment-type secrets.
-
Second-pass too late — pkg/hub/httpdispatcher.go:1073-1089: resolveAsNeededForKeys only runs after broker reports needed keys. The clone happens during sciontool init — before any negotiation.
-
Clone fails — cmd/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:
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-1247 — resolveCloneToken (why shared-workspace works)
Bug
When creating a project with
GitRemoteURL+GithubToken(no GitHub App), the token is stored as a project secret withInjectionMode: "as_needed"(handlers_projects_core.go:479). Theas_neededmode 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 readsos.Getenv("GITHUB_TOKEN"), which returns empty because the first pass skipped theas_neededsecret. The clone fails:Impact
Root cause trace
Storage —
pkg/hub/handlers_projects_core.go:479: HardcodedInjectionMode: "as_needed"when storing GITHUB_TOKEN during project creation.First-pass skip —
pkg/hub/httpdispatcher.go:1605-1606:resolveEnvFromStorageskipsas_neededsecrets. Alsohttpdispatcher.go:2780:resolveSecretsskipsas_neededenvironment-type secrets.Second-pass too late —
pkg/hub/httpdispatcher.go:1073-1089:resolveAsNeededForKeysonly runs after broker reports needed keys. The clone happens duringsciontool init— before any negotiation.Clone fails —
cmd/sciontool/commands/init.go:1546,1581:os.Getenv("GITHUB_TOKEN")returns empty →buildAuthenticatedURLproduces unauthenticated URL → git prompts for creds → fails (GIT_TERMINAL_PROMPT=0).Fix
Change line 479 of
pkg/hub/handlers_projects_core.gofrom:to:
GITHUB_TOKEN is a git credential needed at container startup before any two-pass negotiation.
alwaysis 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_neededshould be updated toalwaysin the secrets table.No other secrets are affected — all other
as_neededsecrets are hub-scopedTypeVariablesecrets (chat integration keys, GitHub App keys, migrated plugin keys), not project-scoped GITHUB_TOKEN.Files
pkg/hub/handlers_projects_core.go:479— the hardcodedas_needed(the bug)pkg/hub/httpdispatcher.go:1605-1606,2780— first-pass skip logicpkg/hub/httpdispatcher.go:616-658— NoAuth exemption (prior art for the fix)cmd/sciontool/commands/init.go:1546,1581— per-agent clone reading os.Getenvpkg/hub/handlers_projects_core.go:1215-1247—resolveCloneToken(why shared-workspace works)