Multi-org GitHub credentials: pushed token store, git credential helper, per-session GH_TOKEN#1307
Open
cyrusagent wants to merge 6 commits into
Open
Multi-org GitHub credentials: pushed token store, git credential helper, per-session GH_TOKEN#1307cyrusagent wants to merge 6 commits into
cyrusagent wants to merge 6 commits into
Conversation
…lper, per-session GH_TOKEN (CYHOST-913) - New POST /api/update/github-tokens ConfigUpdater route persists per-installation GitHub App tokens pushed by cyrus-hosted to an atomic 0600 ~/.cyrus/github-tokens.json - Ships a dependency-free git credential helper that resolves the right token per GitHub org (useHttpPath), safe under concurrent sessions - resolveGitHubToken prefers the org-matched pushed token; sessions get GH_TOKEN/CYRUS_GH_TOKEN for their repository's org
Restores droplet-wide gh auth parity with the removed on-droplet refresh service: the github-tokens push now runs 'gh auth login --with-token' with the first pushed token (non-fatal if gh is absent). Per-session GH_TOKEN still provides per-org correctness in sessions.
Customers set their own GH_TOKEN for private npm registries on GitHub Packages; Cyrus must not clobber it. The droplet gh wrapper maps CYRUS_GH_TOKEN to GH_TOKEN inside the gh process only, and bare gh is covered by the hosts.yml auth refreshed on every token push. Learning test: gh does not consult git credential helpers — with a helper configured for github.com but a clean gh config dir and no env, 'gh auth status' reports not logged in. So git auth flows through the credential helper while gh needs hosts.yml or its env vars.
- handleRepository now uses plain 'git clone' whenever cyrus-hosted has pushed installation tokens, so auth flows through the credential helper and resolves the token for the repo's own org. 'gh repo clone' (which authenticates as gh's stored login — the first org) remains only as the self-host fallback when no tokens were pushed. Fixes wrong-token clones when a repo from a second org is added after onboarding. - Token pushes rewrite an old-image ~/.local/bin/gh wrapper to honor CYRUS_GH_TOKEN, so per-org gh in sessions works on existing droplets without an image rebuild.
Multi-repo sessions can span repositories from different GitHub orgs, so a session-wide gh token is not enough. New gh-cyrus.cjs resolver (execed by the droplet gh wrapper) picks the installation token per command: explicit -R/--repo argument, else the cwd's origin remote, then CYRUS_GH_TOKEN, then the single valid token, else gh's own stored auth. Customer GITHUB_TOKEN/GH_TOKEN stay stripped from gh's env only. Installed on token pushes and EdgeWorker startup; wrapper self-heal now upgrades both the original strip-everything wrapper and the interim CYRUS_GH_TOKEN one.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Assignee: @Connoropolous (connor)
Runtime half of CYHOST-913: teams can attach multiple GitHub App installations (multiple orgs), and cyrus-hosted now mints per-installation tokens and pushes them to the runtime instead of the droplet refreshing its own auth with an on-box PEM.
Summary
POST /api/update/github-tokens(new ConfigUpdater route, standard Bearer auth): persists pushed tokens{installationId, organization, accountType, token, expiresAt}to~/.cyrus/github-tokens.json(atomic write, mode 0600) via a newGitHubTokenStoreincyrus-core.git-credential-cyrus.cjs, dependency-free, ships withcyrus-config-updater): installed to<cyrusHome>/scripts/and wired into git withcredential."https://github.com".useHttpPath=true+ a helper-list reset. Resolves the org from the request path and prints the matching token (single-valid-token fallback; silent pass-through otherwise). Reads the store file per git invocation, so many concurrent sessions across different orgs each authenticate correctly.resolveGitHubTokengains a first tier: org-matched pushed token for the session's repository, ahead of the forwarded installation token / self-minted App token /GITHUB_TOKENfallbacks.ghauth: sessions whose repository org matches a stored token getGH_TOKEN+CYRUS_GH_TOKENin their env. No token file → zero behavior change for self-host users.Testing
pnpm typecheckclean;pnpm test:packages:run1537 passed;pnpm lintclean. New suites: token store (atomicity, perms, expiry, URL parsing), handler (payload validation, exact git config invocations, idempotency), the real credential helper script spawned against stdin fixtures, token-resolution precedence, and session-env injection.Deploy ordering
This must be released and rolled out to droplets before the cyrus-hosted PR (cyrusagents/cyrus-hosted#960) deploys, since that deploy starts pushing to the new endpoint.
Related PRs: cyrusagents/cyrus-hosted#960, ceedaragents/cyrus-images (PEM removal).