cyrus-config-updater 0.2.71 → 0.2.72-test.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ConfigUpdater.d.ts +4 -0
- package/dist/ConfigUpdater.d.ts.map +1 -1
- package/dist/ConfigUpdater.js +8 -0
- package/dist/ConfigUpdater.js.map +1 -1
- package/dist/handlers/githubTokens.d.ts +70 -0
- package/dist/handlers/githubTokens.d.ts.map +1 -0
- package/dist/handlers/githubTokens.js +220 -0
- package/dist/handlers/githubTokens.js.map +1 -0
- package/dist/handlers/repository.d.ts.map +1 -1
- package/dist/handlers/repository.js +19 -5
- package/dist/handlers/repository.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +18 -0
- package/dist/types.js.map +1 -1
- package/package.json +4 -3
- package/scripts/gh-cyrus.cjs +142 -0
- package/scripts/git-credential-cyrus.cjs +84 -0
package/dist/ConfigUpdater.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigUpdater.d.ts","sourceRoot":"","sources":["../src/ConfigUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"ConfigUpdater.d.ts","sourceRoot":"","sources":["../src/ConfigUpdater.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAiC/C;;;;;;;GAOG;AACH,qBAAa,aAAa;IACzB,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAe;gBAG/B,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,MAAM;IAOxB;;OAEG;IACH,QAAQ,IAAI,IAAI;IAyBhB;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IA4B3B;;OAEG;IACH,OAAO,CAAC,gBAAgB;IA4BxB;;OAEG;IACH,OAAO,CAAC,UAAU;IAUlB;;OAEG;YACW,sBAAsB;IAapC;;OAEG;YACW,mBAAmB;IAajC;;OAEG;YACW,qBAAqB;IAMnC;;OAEG;YACW,kBAAkB;IAMhC;;OAEG;YACW,uBAAuB;IAMrC;;OAEG;YACW,uBAAuB;IAMrC;;OAEG;YACW,kBAAkB;IAMhC;;OAEG;YACW,oBAAoB;IAMlC;;OAEG;YACW,2BAA2B;IAMzC;;OAEG;YACW,sBAAsB;IAMpC;;OAEG;YACW,sBAAsB;IAMpC;;OAEG;YACW,qBAAqB;CAKnC"}
|
package/dist/ConfigUpdater.js
CHANGED
|
@@ -3,6 +3,7 @@ import { handleCheckGlab } from "./handlers/checkGlab.js";
|
|
|
3
3
|
import { handleConfigureMcp } from "./handlers/configureMcp.js";
|
|
4
4
|
import { handleCyrusConfig } from "./handlers/cyrusConfig.js";
|
|
5
5
|
import { handleCyrusEnv } from "./handlers/cyrusEnv.js";
|
|
6
|
+
import { handleGitHubTokens } from "./handlers/githubTokens.js";
|
|
6
7
|
import { handleRepository, handleRepositoryDelete, } from "./handlers/repository.js";
|
|
7
8
|
import { handleDeleteSkill, handleListSkills, handleUpdateSkill, } from "./handlers/skills.js";
|
|
8
9
|
import { handleTestMcp } from "./handlers/testMcp.js";
|
|
@@ -34,6 +35,7 @@ export class ConfigUpdater {
|
|
|
34
35
|
this.registerDeleteRoute("/api/update/repository", this.handleRepositoryDeleteRoute);
|
|
35
36
|
this.registerRoute("/api/update/test-mcp", this.handleTestMcpRoute);
|
|
36
37
|
this.registerRoute("/api/update/configure-mcp", this.handleConfigureMcpRoute);
|
|
38
|
+
this.registerRoute("/api/update/github-tokens", this.handleGitHubTokensRoute);
|
|
37
39
|
this.registerRoute("/api/check-gh", this.handleCheckGhRoute);
|
|
38
40
|
this.registerRoute("/api/check-glab", this.handleCheckGlabRoute);
|
|
39
41
|
this.registerRoute("/api/update/skill", this.handleUpdateSkillRoute);
|
|
@@ -172,6 +174,12 @@ export class ConfigUpdater {
|
|
|
172
174
|
async handleConfigureMcpRoute(payload) {
|
|
173
175
|
return handleConfigureMcp(payload, this.cyrusHome);
|
|
174
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Handle GitHub installation tokens push
|
|
179
|
+
*/
|
|
180
|
+
async handleGitHubTokensRoute(payload) {
|
|
181
|
+
return handleGitHubTokens(payload, this.cyrusHome);
|
|
182
|
+
}
|
|
175
183
|
/**
|
|
176
184
|
* Handle GitHub CLI check
|
|
177
185
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigUpdater.js","sourceRoot":"","sources":["../src/ConfigUpdater.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EACN,gBAAgB,EAChB,sBAAsB,GACtB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACN,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,GACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"ConfigUpdater.js","sourceRoot":"","sources":["../src/ConfigUpdater.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { type ApiResponse } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Install the per-invocation gh token resolver to
|
|
4
|
+
* `<cyrusHome>/scripts/gh-cyrus.cjs`. The droplet's `~/.local/bin/gh`
|
|
5
|
+
* wrapper execs into it so each gh command authenticates with the
|
|
6
|
+
* installation token for the org it targets (explicit -R/--repo arg, else
|
|
7
|
+
* the cwd's origin remote) — required for multi-repo sessions that span
|
|
8
|
+
* GitHub orgs. Idempotent.
|
|
9
|
+
*/
|
|
10
|
+
export declare function ensureGhTokenResolver(cyrusHome: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Install the Cyrus git credential helper and wire it into the global git
|
|
13
|
+
* config for github.com. Idempotent — safe to run on every token push and
|
|
14
|
+
* on EdgeWorker startup.
|
|
15
|
+
*
|
|
16
|
+
* - Copies the self-contained helper script to
|
|
17
|
+
* `<cyrusHome>/scripts/git-credential-cyrus.cjs` (executable).
|
|
18
|
+
* - Enables `credential."https://github.com".useHttpPath` so git passes the
|
|
19
|
+
* repo path (and thus the org) to the helper.
|
|
20
|
+
* - Replaces any inherited helpers for github.com (e.g. gh's keyring helper)
|
|
21
|
+
* with an empty entry followed by the Cyrus helper. Helper values must be
|
|
22
|
+
* prefixed with `!` to invoke an arbitrary command — without it git would
|
|
23
|
+
* look for a `git credential-<name>` binary.
|
|
24
|
+
*
|
|
25
|
+
* Returns the absolute path of the installed helper script.
|
|
26
|
+
*/
|
|
27
|
+
export declare function ensureGitHubCredentialHelper(cyrusHome: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Self-heal the droplet's `~/.local/bin/gh` wrapper to exec the Cyrus gh
|
|
30
|
+
* token resolver.
|
|
31
|
+
*
|
|
32
|
+
* Droplet images bake a gh wrapper that strips injected GH_TOKEN /
|
|
33
|
+
* GITHUB_TOKEN env vars. The current design routes gh through
|
|
34
|
+
* `<cyrusHome>/scripts/gh-cyrus.cjs`, which resolves the installation
|
|
35
|
+
* token PER INVOCATION for the org the command targets (multi-repo
|
|
36
|
+
* sessions span orgs, so a session-wide token is not enough). Droplets
|
|
37
|
+
* provisioned from older images keep their baked wrapper until rebuilt;
|
|
38
|
+
* since the wrapper lives in the cyrus user's home, rewrite it here on
|
|
39
|
+
* token pushes — making per-org gh independent of the image rollout.
|
|
40
|
+
* No-op when no wrapper exists (self-host), it already execs the
|
|
41
|
+
* resolver, or it has an unrecognized shape.
|
|
42
|
+
*/
|
|
43
|
+
export declare function ensureGhWrapperSupportsCyrusToken(homeDir?: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Authenticate the `gh` CLI with a pushed installation token.
|
|
46
|
+
*
|
|
47
|
+
* The droplet-local token refresh service used to run `gh auth login` every
|
|
48
|
+
* 20 minutes; with refresh moved to cyrus-hosted, this keeps bare `gh`
|
|
49
|
+
* usage (outside sessions, and sessions on droplet images whose gh wrapper
|
|
50
|
+
* strips GH_TOKEN) authenticated. Multi-org correctness comes from the
|
|
51
|
+
* per-session GH_TOKEN env var; this default uses the first token, which is
|
|
52
|
+
* exact for single-installation teams. Refreshed on every token push.
|
|
53
|
+
*
|
|
54
|
+
* Non-fatal by design — self-host machines may not have `gh` installed.
|
|
55
|
+
*/
|
|
56
|
+
export declare function configureGhCliAuth(token: string): void;
|
|
57
|
+
/**
|
|
58
|
+
* Handle a GitHub installation tokens push from cyrus-hosted.
|
|
59
|
+
*
|
|
60
|
+
* Persists the per-installation tokens to `<cyrusHome>/github-tokens.json`
|
|
61
|
+
* (atomically, mode 0600), ensures the git credential helper is installed
|
|
62
|
+
* so concurrent git operations against different GitHub orgs each
|
|
63
|
+
* authenticate with the right token, and refreshes the `gh` CLI's stored
|
|
64
|
+
* auth with the first pushed token.
|
|
65
|
+
*
|
|
66
|
+
* @param rawPayload - Unvalidated payload from the request
|
|
67
|
+
* @param cyrusHome - Path to the Cyrus home directory
|
|
68
|
+
*/
|
|
69
|
+
export declare function handleGitHubTokens(rawPayload: unknown, cyrusHome: string): Promise<ApiResponse>;
|
|
70
|
+
//# sourceMappingURL=githubTokens.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githubTokens.d.ts","sourceRoot":"","sources":["../../src/handlers/githubTokens.ts"],"names":[],"mappings":"AAaA,OAAO,EACN,KAAK,WAAW,EAGhB,MAAM,aAAa,CAAC;AAUrB;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAO/D;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,4BAA4B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA6BtE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iCAAiC,CAChD,OAAO,GAAE,MAAkB,GACzB,OAAO,CA2BT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKtD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACvC,UAAU,EAAE,OAAO,EACnB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAqFtB"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { chmodSync, copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { GitHubTokenStore } from "cyrus-core";
|
|
7
|
+
import { GitHubTokensPayloadSchema, } from "../types.js";
|
|
8
|
+
/** Path of a bundled script within this package's scripts/ directory */
|
|
9
|
+
function bundledScriptPath(scriptName) {
|
|
10
|
+
// Resolves from both src/handlers (tests) and dist/handlers (published)
|
|
11
|
+
// to <package root>/scripts/<scriptName>.
|
|
12
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
return join(here, "..", "..", "scripts", scriptName);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Install the per-invocation gh token resolver to
|
|
17
|
+
* `<cyrusHome>/scripts/gh-cyrus.cjs`. The droplet's `~/.local/bin/gh`
|
|
18
|
+
* wrapper execs into it so each gh command authenticates with the
|
|
19
|
+
* installation token for the org it targets (explicit -R/--repo arg, else
|
|
20
|
+
* the cwd's origin remote) — required for multi-repo sessions that span
|
|
21
|
+
* GitHub orgs. Idempotent.
|
|
22
|
+
*/
|
|
23
|
+
export function ensureGhTokenResolver(cyrusHome) {
|
|
24
|
+
const scriptDir = join(cyrusHome, "scripts");
|
|
25
|
+
const scriptDest = join(scriptDir, "gh-cyrus.cjs");
|
|
26
|
+
mkdirSync(scriptDir, { recursive: true });
|
|
27
|
+
copyFileSync(bundledScriptPath("gh-cyrus.cjs"), scriptDest);
|
|
28
|
+
chmodSync(scriptDest, 0o755);
|
|
29
|
+
return scriptDest;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Install the Cyrus git credential helper and wire it into the global git
|
|
33
|
+
* config for github.com. Idempotent — safe to run on every token push and
|
|
34
|
+
* on EdgeWorker startup.
|
|
35
|
+
*
|
|
36
|
+
* - Copies the self-contained helper script to
|
|
37
|
+
* `<cyrusHome>/scripts/git-credential-cyrus.cjs` (executable).
|
|
38
|
+
* - Enables `credential."https://github.com".useHttpPath` so git passes the
|
|
39
|
+
* repo path (and thus the org) to the helper.
|
|
40
|
+
* - Replaces any inherited helpers for github.com (e.g. gh's keyring helper)
|
|
41
|
+
* with an empty entry followed by the Cyrus helper. Helper values must be
|
|
42
|
+
* prefixed with `!` to invoke an arbitrary command — without it git would
|
|
43
|
+
* look for a `git credential-<name>` binary.
|
|
44
|
+
*
|
|
45
|
+
* Returns the absolute path of the installed helper script.
|
|
46
|
+
*/
|
|
47
|
+
export function ensureGitHubCredentialHelper(cyrusHome) {
|
|
48
|
+
const scriptDir = join(cyrusHome, "scripts");
|
|
49
|
+
const scriptDest = join(scriptDir, "git-credential-cyrus.cjs");
|
|
50
|
+
mkdirSync(scriptDir, { recursive: true });
|
|
51
|
+
copyFileSync(bundledScriptPath("git-credential-cyrus.cjs"), scriptDest);
|
|
52
|
+
chmodSync(scriptDest, 0o755);
|
|
53
|
+
const credentialKey = "credential.https://github.com";
|
|
54
|
+
const git = (args) => {
|
|
55
|
+
execFileSync("git", args, { stdio: "ignore" });
|
|
56
|
+
};
|
|
57
|
+
// Pass the repo path to the helper so it can resolve the org.
|
|
58
|
+
git(["config", "--global", `${credentialKey}.useHttpPath`, "true"]);
|
|
59
|
+
// Clear inherited helpers (an empty value resets git's helper list for
|
|
60
|
+
// this key). --replace-all also makes repeated runs idempotent: every
|
|
61
|
+
// call ends with exactly ["", "!node <script>"].
|
|
62
|
+
git(["config", "--global", "--replace-all", `${credentialKey}.helper`, ""]);
|
|
63
|
+
// Quote the script path — helper commands are run through the shell.
|
|
64
|
+
git([
|
|
65
|
+
"config",
|
|
66
|
+
"--global",
|
|
67
|
+
"--add",
|
|
68
|
+
`${credentialKey}.helper`,
|
|
69
|
+
`!node "${scriptDest}"`,
|
|
70
|
+
]);
|
|
71
|
+
return scriptDest;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Self-heal the droplet's `~/.local/bin/gh` wrapper to exec the Cyrus gh
|
|
75
|
+
* token resolver.
|
|
76
|
+
*
|
|
77
|
+
* Droplet images bake a gh wrapper that strips injected GH_TOKEN /
|
|
78
|
+
* GITHUB_TOKEN env vars. The current design routes gh through
|
|
79
|
+
* `<cyrusHome>/scripts/gh-cyrus.cjs`, which resolves the installation
|
|
80
|
+
* token PER INVOCATION for the org the command targets (multi-repo
|
|
81
|
+
* sessions span orgs, so a session-wide token is not enough). Droplets
|
|
82
|
+
* provisioned from older images keep their baked wrapper until rebuilt;
|
|
83
|
+
* since the wrapper lives in the cyrus user's home, rewrite it here on
|
|
84
|
+
* token pushes — making per-org gh independent of the image rollout.
|
|
85
|
+
* No-op when no wrapper exists (self-host), it already execs the
|
|
86
|
+
* resolver, or it has an unrecognized shape.
|
|
87
|
+
*/
|
|
88
|
+
export function ensureGhWrapperSupportsCyrusToken(homeDir = homedir()) {
|
|
89
|
+
const wrapperPath = join(homeDir, ".local", "bin", "gh");
|
|
90
|
+
if (!existsSync(wrapperPath))
|
|
91
|
+
return false;
|
|
92
|
+
const current = readFileSync(wrapperPath, "utf8");
|
|
93
|
+
// Only rewrite the known droplet wrapper shapes (the original
|
|
94
|
+
// strip-everything wrapper and the interim CYRUS_GH_TOKEN one), and
|
|
95
|
+
// only when they predate the resolver.
|
|
96
|
+
if (current.includes("gh-cyrus.cjs") || !current.includes("/usr/bin/gh")) {
|
|
97
|
+
return false;
|
|
98
|
+
}
|
|
99
|
+
const updated = `#!/usr/bin/env bash
|
|
100
|
+
# Cyrus-managed gh wrapper. The resolver picks the GitHub App installation
|
|
101
|
+
# token for the org each command targets (multi-org support); without it,
|
|
102
|
+
# strip injected tokens so gh falls back to its own stored auth.
|
|
103
|
+
RESOLVER="$HOME/.cyrus/scripts/gh-cyrus.cjs"
|
|
104
|
+
if [ -f "$RESOLVER" ]; then
|
|
105
|
+
exec node "$RESOLVER" "$@"
|
|
106
|
+
fi
|
|
107
|
+
if [ -n "\${CYRUS_GH_TOKEN:-}" ]; then
|
|
108
|
+
exec env -u GITHUB_TOKEN GH_TOKEN="$CYRUS_GH_TOKEN" /usr/bin/gh "$@"
|
|
109
|
+
fi
|
|
110
|
+
exec env -u GITHUB_TOKEN -u GH_TOKEN /usr/bin/gh "$@"
|
|
111
|
+
`;
|
|
112
|
+
writeFileSync(wrapperPath, updated, { mode: 0o755 });
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Authenticate the `gh` CLI with a pushed installation token.
|
|
117
|
+
*
|
|
118
|
+
* The droplet-local token refresh service used to run `gh auth login` every
|
|
119
|
+
* 20 minutes; with refresh moved to cyrus-hosted, this keeps bare `gh`
|
|
120
|
+
* usage (outside sessions, and sessions on droplet images whose gh wrapper
|
|
121
|
+
* strips GH_TOKEN) authenticated. Multi-org correctness comes from the
|
|
122
|
+
* per-session GH_TOKEN env var; this default uses the first token, which is
|
|
123
|
+
* exact for single-installation teams. Refreshed on every token push.
|
|
124
|
+
*
|
|
125
|
+
* Non-fatal by design — self-host machines may not have `gh` installed.
|
|
126
|
+
*/
|
|
127
|
+
export function configureGhCliAuth(token) {
|
|
128
|
+
execFileSync("gh", ["auth", "login", "--with-token"], {
|
|
129
|
+
input: token,
|
|
130
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Handle a GitHub installation tokens push from cyrus-hosted.
|
|
135
|
+
*
|
|
136
|
+
* Persists the per-installation tokens to `<cyrusHome>/github-tokens.json`
|
|
137
|
+
* (atomically, mode 0600), ensures the git credential helper is installed
|
|
138
|
+
* so concurrent git operations against different GitHub orgs each
|
|
139
|
+
* authenticate with the right token, and refreshes the `gh` CLI's stored
|
|
140
|
+
* auth with the first pushed token.
|
|
141
|
+
*
|
|
142
|
+
* @param rawPayload - Unvalidated payload from the request
|
|
143
|
+
* @param cyrusHome - Path to the Cyrus home directory
|
|
144
|
+
*/
|
|
145
|
+
export async function handleGitHubTokens(rawPayload, cyrusHome) {
|
|
146
|
+
const parseResult = GitHubTokensPayloadSchema.safeParse(rawPayload);
|
|
147
|
+
if (!parseResult.success) {
|
|
148
|
+
const firstIssue = parseResult.error.issues[0];
|
|
149
|
+
const path = firstIssue?.path.join(".") || "unknown";
|
|
150
|
+
const message = firstIssue?.message || "Invalid payload";
|
|
151
|
+
return {
|
|
152
|
+
success: false,
|
|
153
|
+
error: "GitHub tokens payload validation failed",
|
|
154
|
+
details: `${path}: ${message}`,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
const payload = parseResult.data;
|
|
158
|
+
// Persist the tokens first — even if git configuration fails below, the
|
|
159
|
+
// EdgeWorker can still resolve tokens from the store for API calls.
|
|
160
|
+
try {
|
|
161
|
+
new GitHubTokenStore(cyrusHome).save(payload.tokens);
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
return {
|
|
165
|
+
success: false,
|
|
166
|
+
error: "Failed to save GitHub tokens",
|
|
167
|
+
details: error instanceof Error ? error.message : String(error),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
ensureGitHubCredentialHelper(cyrusHome);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
return {
|
|
175
|
+
success: false,
|
|
176
|
+
error: "Failed to configure git credential helper",
|
|
177
|
+
details: error instanceof Error ? error.message : String(error),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
ensureGhTokenResolver(cyrusHome);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
// Non-fatal: gh falls back to CYRUS_GH_TOKEN / hosts.yml auth.
|
|
185
|
+
console.warn("[githubTokens] gh token resolver install failed:", error instanceof Error ? error.message : String(error));
|
|
186
|
+
}
|
|
187
|
+
try {
|
|
188
|
+
// cyrusHome is <home>/.cyrus on droplets, so the wrapper lives at
|
|
189
|
+
// <parent of cyrusHome>/.local/bin/gh. Using the parent (rather than
|
|
190
|
+
// os.homedir()) keeps this no-op for custom cyrus-home layouts and
|
|
191
|
+
// hermetic in tests.
|
|
192
|
+
ensureGhWrapperSupportsCyrusToken(dirname(cyrusHome));
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
// Non-fatal: the wrapper rewrite is a droplet-only nicety.
|
|
196
|
+
console.warn("[githubTokens] gh wrapper self-heal failed:", error instanceof Error ? error.message : String(error));
|
|
197
|
+
}
|
|
198
|
+
let ghAuthConfigured = false;
|
|
199
|
+
const firstToken = payload.tokens[0]?.token;
|
|
200
|
+
if (firstToken) {
|
|
201
|
+
try {
|
|
202
|
+
configureGhCliAuth(firstToken);
|
|
203
|
+
ghAuthConfigured = true;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
// Non-fatal: gh may not be installed (self-host), and git auth via
|
|
207
|
+
// the credential helper is unaffected.
|
|
208
|
+
console.warn("[githubTokens] gh CLI auth refresh failed:", error instanceof Error ? error.message : String(error));
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return {
|
|
212
|
+
success: true,
|
|
213
|
+
message: "GitHub installation tokens updated successfully",
|
|
214
|
+
data: {
|
|
215
|
+
tokensCount: payload.tokens.length,
|
|
216
|
+
ghAuthConfigured,
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=githubTokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"githubTokens.js","sourceRoot":"","sources":["../../src/handlers/githubTokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/handlers/repository.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,WAAW,EACX,uBAAuB,EACvB,iBAAiB,EACjB,MAAM,aAAa,CAAC;AA4BrB;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CA+
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/handlers/repository.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACX,WAAW,EACX,uBAAuB,EACvB,iBAAiB,EACjB,MAAM,aAAa,CAAC;AA4BrB;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACrC,OAAO,EAAE,iBAAiB,EAC1B,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CA+GtB;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC3C,OAAO,EAAE,uBAAuB,EAChC,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CA+EtB"}
|
|
@@ -2,7 +2,7 @@ import { exec } from "node:child_process";
|
|
|
2
2
|
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
3
3
|
import { basename, join } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
-
import { getDefaultReposDir } from "cyrus-core";
|
|
5
|
+
import { GitHubTokenStore, getDefaultReposDir } from "cyrus-core";
|
|
6
6
|
const execAsync = promisify(exec);
|
|
7
7
|
/**
|
|
8
8
|
* Check if a directory contains a git repository
|
|
@@ -81,16 +81,27 @@ export async function handleRepository(payload, cyrusHome) {
|
|
|
81
81
|
details: `A non-Git directory already exists at ${repoPath}. Please remove it manually or choose a different repository name.`,
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
|
-
// Clone the repository
|
|
84
|
+
// Clone the repository. When cyrus-hosted has pushed per-installation
|
|
85
|
+
// GitHub tokens (cloud runtime), use plain `git clone` so auth flows
|
|
86
|
+
// through the Cyrus git credential helper, which resolves the token
|
|
87
|
+
// for the repo's OWN org — `gh repo clone` would authenticate with
|
|
88
|
+
// gh's stored login (the first org's token) and fail for repos added
|
|
89
|
+
// from a different org. Without pushed tokens (self-host), fall back
|
|
90
|
+
// to `gh repo clone` using the user's own gh authentication.
|
|
91
|
+
const tokenStore = new GitHubTokenStore(cyrusHome);
|
|
92
|
+
const usePushedTokens = Boolean(tokenStore.getTokenForRepoUrl(payload.repository_url) ??
|
|
93
|
+
tokenStore.getFallbackToken());
|
|
85
94
|
try {
|
|
86
|
-
const cloneCmd =
|
|
95
|
+
const cloneCmd = usePushedTokens
|
|
96
|
+
? `git clone "${payload.repository_url}" "${repoPath}"`
|
|
97
|
+
: `gh repo clone "${payload.repository_url}" "${repoPath}"`;
|
|
87
98
|
await execAsync(cloneCmd);
|
|
88
99
|
// Verify the clone was successful
|
|
89
100
|
if (!isGitRepository(repoPath)) {
|
|
90
101
|
return {
|
|
91
102
|
success: false,
|
|
92
103
|
error: "Repository clone verification failed",
|
|
93
|
-
details: `
|
|
104
|
+
details: `Clone command completed, but the cloned directory at ${repoPath} does not appear to be a valid Git repository.`,
|
|
94
105
|
};
|
|
95
106
|
}
|
|
96
107
|
return {
|
|
@@ -106,10 +117,13 @@ export async function handleRepository(payload, cyrusHome) {
|
|
|
106
117
|
}
|
|
107
118
|
catch (error) {
|
|
108
119
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
120
|
+
const authHint = usePushedTokens
|
|
121
|
+
? "The pushed GitHub credentials may not include this repository's org — check the team's GitHub installations."
|
|
122
|
+
: "Please verify the URL is correct, you have access to the repository, and gh is authenticated.";
|
|
109
123
|
return {
|
|
110
124
|
success: false,
|
|
111
125
|
error: "Failed to clone repository",
|
|
112
|
-
details: `Could not clone repository from ${payload.repository_url}
|
|
126
|
+
details: `Could not clone repository from ${payload.repository_url}: ${errorMessage}. ${authHint}`,
|
|
113
127
|
};
|
|
114
128
|
}
|
|
115
129
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/handlers/repository.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/handlers/repository.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EACN,qBAAqB,EACrB,4BAA4B,EAC5B,kBAAkB,GAClB,MAAM,4BAA4B,CAAC;AACpC,cAAc,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,cAAc,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EACN,qBAAqB,EACrB,4BAA4B,EAC5B,kBAAkB,GAClB,MAAM,4BAA4B,CAAC;AACpC,cAAc,YAAY,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -284,6 +284,24 @@ export interface CheckGlabData {
|
|
|
284
284
|
isInstalled: boolean;
|
|
285
285
|
isAuthenticated: boolean;
|
|
286
286
|
}
|
|
287
|
+
/**
|
|
288
|
+
* GitHub installation tokens push payload schema.
|
|
289
|
+
* Sent by cyrus-hosted with one short-lived GitHub App installation token
|
|
290
|
+
* per installation (org or user account) the team has attached.
|
|
291
|
+
*/
|
|
292
|
+
export declare const GitHubTokensPayloadSchema: z.ZodObject<{
|
|
293
|
+
tokens: z.ZodArray<z.ZodObject<{
|
|
294
|
+
installationId: z.ZodString;
|
|
295
|
+
organization: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodString>>>;
|
|
296
|
+
accountType: z.ZodDefault<z.ZodOptional<z.ZodNullable<z.ZodEnum<{
|
|
297
|
+
Organization: "Organization";
|
|
298
|
+
User: "User";
|
|
299
|
+
}>>>>;
|
|
300
|
+
token: z.ZodString;
|
|
301
|
+
expiresAt: z.ZodString;
|
|
302
|
+
}, z.core.$strip>>;
|
|
303
|
+
}, z.core.$strip>;
|
|
304
|
+
export type GitHubTokensPayload = z.infer<typeof GitHubTokensPayloadSchema>;
|
|
287
305
|
/**
|
|
288
306
|
* Error response to send back to cyrus-hosted
|
|
289
307
|
*/
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -10,4 +10,22 @@ export const CyrusConfigPayloadSchema = EdgeConfigPayloadSchema.extend({
|
|
|
10
10
|
restartCyrus: z.boolean().optional(),
|
|
11
11
|
backupConfig: z.boolean().optional(),
|
|
12
12
|
});
|
|
13
|
+
/**
|
|
14
|
+
* GitHub installation tokens push payload schema.
|
|
15
|
+
* Sent by cyrus-hosted with one short-lived GitHub App installation token
|
|
16
|
+
* per installation (org or user account) the team has attached.
|
|
17
|
+
*/
|
|
18
|
+
export const GitHubTokensPayloadSchema = z.object({
|
|
19
|
+
tokens: z.array(z.object({
|
|
20
|
+
installationId: z.string().min(1),
|
|
21
|
+
organization: z.string().nullable().optional().default(null),
|
|
22
|
+
accountType: z
|
|
23
|
+
.enum(["Organization", "User"])
|
|
24
|
+
.nullable()
|
|
25
|
+
.optional()
|
|
26
|
+
.default(null),
|
|
27
|
+
token: z.string().min(1),
|
|
28
|
+
expiresAt: z.string().min(1),
|
|
29
|
+
})),
|
|
30
|
+
});
|
|
13
31
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IACtE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACpC,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAsBxB;;;;;GAKG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,uBAAuB,CAAC,MAAM,CAAC;IACtE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IACpC,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;CACpC,CAAC,CAAC;AAwEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjD,MAAM,EAAE,CAAC,CAAC,KAAK,CACd,CAAC,CAAC,MAAM,CAAC;QACR,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACjC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QAC5D,WAAW,EAAE,CAAC;aACZ,IAAI,CAAC,CAAC,cAAc,EAAE,MAAM,CAAC,CAAC;aAC9B,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,OAAO,CAAC,IAAI,CAAC;QACf,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;KAC5B,CAAC,CACF;CACD,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyrus-config-updater",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.72-test.0",
|
|
4
4
|
"description": "Configuration update handlers for Cyrus agent",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,13 +17,14 @@
|
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
"files": [
|
|
20
|
-
"dist"
|
|
20
|
+
"dist",
|
|
21
|
+
"scripts"
|
|
21
22
|
],
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
24
25
|
"fastify": "^5.12.1",
|
|
25
26
|
"zod": "^4.3.6",
|
|
26
|
-
"cyrus-core": "0.2.
|
|
27
|
+
"cyrus-core": "0.2.72-test.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@types/node": "^20.12.7",
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* gh-cyrus — per-invocation GitHub token resolution for the `gh` CLI.
|
|
4
|
+
*
|
|
5
|
+
* Installed by Cyrus at `<cyrusHome>/scripts/gh-cyrus.cjs`; the droplet's
|
|
6
|
+
* `~/.local/bin/gh` wrapper execs into it. Multi-repo agent sessions can
|
|
7
|
+
* span repositories from DIFFERENT GitHub orgs, so a session-wide token is
|
|
8
|
+
* not enough — each gh invocation must authenticate with the installation
|
|
9
|
+
* token for the org it actually targets, mirroring how the Cyrus git
|
|
10
|
+
* credential helper resolves tokens per git invocation.
|
|
11
|
+
*
|
|
12
|
+
* Resolution order for the target org:
|
|
13
|
+
* 1. An explicit `-R` / `--repo` argument (strongest signal).
|
|
14
|
+
* 2. The cwd's `remote.origin.url` (how gh itself infers "the current
|
|
15
|
+
* repository").
|
|
16
|
+
* Then the token, from `<cyrusHome>/github-tokens.json` (pushed by
|
|
17
|
+
* cyrus-hosted):
|
|
18
|
+
* 3. The org-matched token.
|
|
19
|
+
* 4. `CYRUS_GH_TOKEN` from the session env (set to the session's primary
|
|
20
|
+
* repository's org token — covers repo-less commands like `gh api`).
|
|
21
|
+
* 5. The single valid token, when exactly one exists.
|
|
22
|
+
* 6. No token: fall through to gh's own stored auth (hosts.yml).
|
|
23
|
+
*
|
|
24
|
+
* In every case the customer-controlled GITHUB_TOKEN / GH_TOKEN env vars
|
|
25
|
+
* are removed from gh's environment (the wrapper's historical contract);
|
|
26
|
+
* they remain untouched for every other tool in the session.
|
|
27
|
+
*/
|
|
28
|
+
"use strict";
|
|
29
|
+
|
|
30
|
+
const { spawnSync } = require("node:child_process");
|
|
31
|
+
const fs = require("node:fs");
|
|
32
|
+
const os = require("node:os");
|
|
33
|
+
const path = require("node:path");
|
|
34
|
+
|
|
35
|
+
/** Extract the owner/org from common GitHub repo references. */
|
|
36
|
+
function ownerFromRepoRef(ref) {
|
|
37
|
+
if (!ref || typeof ref !== "string") return "";
|
|
38
|
+
let rest = ref.trim();
|
|
39
|
+
// Full URLs: https://github.com/owner/repo(.git), ssh://git@github.com/...
|
|
40
|
+
const urlMatch = rest.match(/^[a-z+]+:\/\/[^/]*github\.com\/(.+)$/i);
|
|
41
|
+
if (urlMatch) rest = urlMatch[1];
|
|
42
|
+
// scp-style: git@github.com:owner/repo.git
|
|
43
|
+
const scpMatch = rest.match(/^git@github\.com:(.+)$/i);
|
|
44
|
+
if (scpMatch) rest = scpMatch[1];
|
|
45
|
+
// HOST/OWNER/REPO form accepted by --repo
|
|
46
|
+
const hostMatch = rest.match(/^github\.com\/(.+)$/i);
|
|
47
|
+
if (hostMatch) rest = hostMatch[1];
|
|
48
|
+
const segments = rest.split("/").filter(Boolean);
|
|
49
|
+
// OWNER/REPO (or deeper); a bare OWNER is not a repo reference.
|
|
50
|
+
if (segments.length >= 2) return segments[0];
|
|
51
|
+
return "";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Find an explicit -R/--repo argument in the gh arg list. */
|
|
55
|
+
function ownerFromArgs(args) {
|
|
56
|
+
for (let i = 0; i < args.length; i++) {
|
|
57
|
+
const arg = args[i];
|
|
58
|
+
if (arg === "--") break;
|
|
59
|
+
if (arg === "-R" || arg === "--repo") {
|
|
60
|
+
return ownerFromRepoRef(args[i + 1]);
|
|
61
|
+
}
|
|
62
|
+
if (arg.startsWith("--repo=")) {
|
|
63
|
+
return ownerFromRepoRef(arg.slice("--repo=".length));
|
|
64
|
+
}
|
|
65
|
+
if (arg.startsWith("-R=")) {
|
|
66
|
+
return ownerFromRepoRef(arg.slice("-R=".length));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Owner of the cwd's origin remote, or "" when not in a GitHub repo. */
|
|
73
|
+
function ownerFromCwd() {
|
|
74
|
+
const result = spawnSync(
|
|
75
|
+
"git",
|
|
76
|
+
["config", "--get", "remote.origin.url"],
|
|
77
|
+
{ encoding: "utf8" },
|
|
78
|
+
);
|
|
79
|
+
if (result.status !== 0) return "";
|
|
80
|
+
return ownerFromRepoRef((result.stdout || "").trim());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Non-expired tokens from the Cyrus token store file. */
|
|
84
|
+
function loadValidTokens() {
|
|
85
|
+
const cyrusHome =
|
|
86
|
+
process.env.CYRUS_HOME || path.join(os.homedir(), ".cyrus");
|
|
87
|
+
const tokensFile = path.join(cyrusHome, "github-tokens.json");
|
|
88
|
+
let tokens = [];
|
|
89
|
+
try {
|
|
90
|
+
const parsed = JSON.parse(fs.readFileSync(tokensFile, "utf8"));
|
|
91
|
+
if (Array.isArray(parsed.tokens)) tokens = parsed.tokens;
|
|
92
|
+
} catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const now = Date.now();
|
|
96
|
+
return tokens.filter((t) => {
|
|
97
|
+
if (!t || typeof t.token !== "string" || t.token.length === 0)
|
|
98
|
+
return false;
|
|
99
|
+
const expiresAt = Date.parse(t.expiresAt);
|
|
100
|
+
return !Number.isNaN(expiresAt) && expiresAt > now;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function resolveToken(args) {
|
|
105
|
+
const owner = ownerFromArgs(args) || ownerFromCwd();
|
|
106
|
+
const valid = loadValidTokens();
|
|
107
|
+
|
|
108
|
+
if (owner) {
|
|
109
|
+
const lowered = owner.toLowerCase();
|
|
110
|
+
const match = valid.find(
|
|
111
|
+
(t) =>
|
|
112
|
+
typeof t.organization === "string" &&
|
|
113
|
+
t.organization.toLowerCase() === lowered,
|
|
114
|
+
);
|
|
115
|
+
if (match) return match.token;
|
|
116
|
+
}
|
|
117
|
+
if (process.env.CYRUS_GH_TOKEN) return process.env.CYRUS_GH_TOKEN;
|
|
118
|
+
if (valid.length === 1) return valid[0].token;
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function main() {
|
|
123
|
+
const args = process.argv.slice(2);
|
|
124
|
+
|
|
125
|
+
// Strip the customer-controlled token vars from gh's env (historical
|
|
126
|
+
// wrapper contract); set GH_TOKEN only when Cyrus resolved a token.
|
|
127
|
+
const env = { ...process.env };
|
|
128
|
+
delete env.GITHUB_TOKEN;
|
|
129
|
+
delete env.GH_TOKEN;
|
|
130
|
+
const token = resolveToken(args);
|
|
131
|
+
if (token) env.GH_TOKEN = token;
|
|
132
|
+
|
|
133
|
+
const ghBin = process.env.CYRUS_GH_REAL_BIN || "/usr/bin/gh";
|
|
134
|
+
const result = spawnSync(ghBin, args, { stdio: "inherit", env });
|
|
135
|
+
if (result.error) {
|
|
136
|
+
console.error(`gh-cyrus: failed to run ${ghBin}: ${result.error.message}`);
|
|
137
|
+
process.exit(127);
|
|
138
|
+
}
|
|
139
|
+
process.exit(result.status ?? 1);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
main();
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* git-credential-cyrus — git credential helper for multi-org GitHub access.
|
|
4
|
+
*
|
|
5
|
+
* Self-contained Node script (no dependencies). Installed by Cyrus at
|
|
6
|
+
* `<cyrusHome>/scripts/git-credential-cyrus.cjs` and wired into git via:
|
|
7
|
+
*
|
|
8
|
+
* git config --global credential."https://github.com".useHttpPath true
|
|
9
|
+
* git config --global --replace-all credential."https://github.com".helper ""
|
|
10
|
+
* git config --global --add credential."https://github.com".helper "!node <this file>"
|
|
11
|
+
*
|
|
12
|
+
* For `get` operations against github.com it looks up the org (first path
|
|
13
|
+
* segment) in `<cyrusHome>/github-tokens.json` — the per-installation
|
|
14
|
+
* GitHub App tokens pushed by cyrus-hosted — and prints credentials for a
|
|
15
|
+
* case-insensitive org match. If no org matches but exactly one non-expired
|
|
16
|
+
* token exists, that token is used. Otherwise it prints nothing and exits 0
|
|
17
|
+
* so git falls through to other helpers / prompts.
|
|
18
|
+
*/
|
|
19
|
+
"use strict";
|
|
20
|
+
|
|
21
|
+
const fs = require("node:fs");
|
|
22
|
+
const os = require("node:os");
|
|
23
|
+
const path = require("node:path");
|
|
24
|
+
|
|
25
|
+
function main() {
|
|
26
|
+
// Only the `get` operation produces credentials; `store`/`erase` are no-ops.
|
|
27
|
+
if (process.argv[2] !== "get") return;
|
|
28
|
+
|
|
29
|
+
let input = "";
|
|
30
|
+
try {
|
|
31
|
+
input = fs.readFileSync(0, "utf8");
|
|
32
|
+
} catch {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const attrs = {};
|
|
37
|
+
for (const line of input.split("\n")) {
|
|
38
|
+
const idx = line.indexOf("=");
|
|
39
|
+
if (idx > 0) {
|
|
40
|
+
attrs[line.slice(0, idx)] = line.slice(idx + 1);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ((attrs.host || "").toLowerCase() !== "github.com") return;
|
|
45
|
+
|
|
46
|
+
// With credential.useHttpPath=true git sends e.g. path=owner/repo.git
|
|
47
|
+
const org = (attrs.path || "").split("/")[0] || "";
|
|
48
|
+
|
|
49
|
+
const cyrusHome = process.env.CYRUS_HOME || path.join(os.homedir(), ".cyrus");
|
|
50
|
+
const tokensFile = path.join(cyrusHome, "github-tokens.json");
|
|
51
|
+
|
|
52
|
+
let tokens = [];
|
|
53
|
+
try {
|
|
54
|
+
const parsed = JSON.parse(fs.readFileSync(tokensFile, "utf8"));
|
|
55
|
+
if (Array.isArray(parsed.tokens)) tokens = parsed.tokens;
|
|
56
|
+
} catch {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const now = Date.now();
|
|
61
|
+
const valid = tokens.filter((t) => {
|
|
62
|
+
if (!t || typeof t.token !== "string" || t.token.length === 0) return false;
|
|
63
|
+
const expiresAt = Date.parse(t.expiresAt);
|
|
64
|
+
return !Number.isNaN(expiresAt) && expiresAt > now;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
let match;
|
|
68
|
+
if (org) {
|
|
69
|
+
const lowered = org.toLowerCase();
|
|
70
|
+
match = valid.find(
|
|
71
|
+
(t) =>
|
|
72
|
+
typeof t.organization === "string" &&
|
|
73
|
+
t.organization.toLowerCase() === lowered,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
if (!match && valid.length === 1) {
|
|
77
|
+
match = valid[0];
|
|
78
|
+
}
|
|
79
|
+
if (!match) return;
|
|
80
|
+
|
|
81
|
+
process.stdout.write(`username=x-access-token\npassword=${match.token}\n`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
main();
|