gcb-client 0.0.0-stage → 0.0.1
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/CHANGELOG.md +9 -0
- package/bin/gcb.js +12 -0
- package/lib/commands/gh.d.ts +13 -0
- package/lib/commands/gh.d.ts.map +1 -0
- package/lib/commands/gh.js +261 -0
- package/lib/commands/gh.js.map +1 -0
- package/lib/commands/logs.d.ts +10 -0
- package/lib/commands/logs.d.ts.map +1 -0
- package/lib/commands/logs.js +94 -0
- package/lib/commands/logs.js.map +1 -0
- package/lib/commands/pr.d.ts +10 -0
- package/lib/commands/pr.d.ts.map +1 -0
- package/lib/commands/pr.js +363 -0
- package/lib/commands/pr.js.map +1 -0
- package/lib/commands/probe.d.ts +10 -0
- package/lib/commands/probe.d.ts.map +1 -0
- package/lib/commands/probe.js +80 -0
- package/lib/commands/probe.js.map +1 -0
- package/lib/commands/remotes.d.ts +56 -0
- package/lib/commands/remotes.d.ts.map +1 -0
- package/lib/commands/remotes.js +157 -0
- package/lib/commands/remotes.js.map +1 -0
- package/lib/commands/setup.d.ts +58 -0
- package/lib/commands/setup.d.ts.map +1 -0
- package/lib/commands/setup.js +178 -0
- package/lib/commands/setup.js.map +1 -0
- package/lib/helper.d.ts +77 -0
- package/lib/helper.d.ts.map +1 -0
- package/lib/helper.js +290 -0
- package/lib/helper.js.map +1 -0
- package/lib/index.d.ts +5 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +83 -0
- package/lib/index.js.map +1 -0
- package/package.json +33 -3
- package/README.md +0 -3
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Let a branch name say *which* repository it is on, by naming a configured remote.
|
|
3
|
+
*
|
|
4
|
+
* `--head feat/x` is a branch in the repository `--repo` names. For a pull request from your fork into an
|
|
5
|
+
* upstream, one of the two has to name the other repository, and the honest way to say it is the remote
|
|
6
|
+
* name you already push to: `--head origin:feat/x --base upstream:main`. A hand-typed `owner/name` is a
|
|
7
|
+
* string that can be wrong in a way that looks right; a remote name is one git already knows, and a typo
|
|
8
|
+
* gets you the list of the ones that exist.
|
|
9
|
+
*
|
|
10
|
+
* Resolved here rather than on the host, because this process runs in the checkout: the wire carries the
|
|
11
|
+
* answer, so the host side needs no git and no repository.
|
|
12
|
+
*/
|
|
13
|
+
import { execFileSync } from 'node:child_process';
|
|
14
|
+
/**
|
|
15
|
+
* Run a git command in a directory, and answer with everything it said.
|
|
16
|
+
*
|
|
17
|
+
* Everything, not the first line: `git remote get-url` answers with one, and `git remote` with all of
|
|
18
|
+
* them, and a helper that quietly dropped the rest would report one remote for a checkout with two.
|
|
19
|
+
*
|
|
20
|
+
* @param args - the arguments, without `git`.
|
|
21
|
+
* @param cwd - where to run it.
|
|
22
|
+
* @returns the output, or undefined when git refused.
|
|
23
|
+
*/
|
|
24
|
+
function git(args, cwd) {
|
|
25
|
+
try {
|
|
26
|
+
const out = execFileSync('git', [...args], { cwd, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
|
|
27
|
+
const trimmed = out.replace(/\s+$/, '');
|
|
28
|
+
return trimmed === '' ? undefined : trimmed;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* The remotes this checkout knows, in the order git lists them.
|
|
36
|
+
*
|
|
37
|
+
* @param cwd - the directory to ask.
|
|
38
|
+
* @returns the names, possibly empty.
|
|
39
|
+
*/
|
|
40
|
+
export function listRemotes(cwd) {
|
|
41
|
+
return (git(['remote'], cwd) ?? '')
|
|
42
|
+
.split('\n')
|
|
43
|
+
.map((line) => line.trim())
|
|
44
|
+
.filter((line) => line !== '');
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* What repository a remote points at.
|
|
48
|
+
*
|
|
49
|
+
* HTTPS and SSH spell the same thing differently, and both end in `owner/repo`, optionally with a `.git`.
|
|
50
|
+
*
|
|
51
|
+
* @param name - the remote name.
|
|
52
|
+
* @param cwd - the directory to ask.
|
|
53
|
+
* @returns the owner, repository and host, or undefined when there is no such remote or the URL is not one.
|
|
54
|
+
*/
|
|
55
|
+
export function remoteRepo(name, cwd, push = false) {
|
|
56
|
+
// `--push` for a head: git lets a remote fetch from one place and push to another, and the branch a
|
|
57
|
+
// pull request comes from lives where it was pushed. The base asks the other question.
|
|
58
|
+
const url = git(['remote', 'get-url', ...(push ? ['--push'] : []), name], cwd);
|
|
59
|
+
if (url === undefined)
|
|
60
|
+
return undefined;
|
|
61
|
+
// A URL has an authority and then a path; the scp form has a host and then one. Anything else — a local
|
|
62
|
+
// path, a `file:` URL, a host with no dot — is refused rather than read as an owner that happens to be a
|
|
63
|
+
// port number or a directory name.
|
|
64
|
+
let path;
|
|
65
|
+
let host;
|
|
66
|
+
const scheme = /^([a-z+]+):\/\//i.exec(url)?.[1]?.toLowerCase();
|
|
67
|
+
if (scheme !== undefined) {
|
|
68
|
+
const rest = url.replace(/^[a-z+]+:\/\//i, '').replace(/^[^@/]*@/, '');
|
|
69
|
+
const slash = rest.indexOf('/');
|
|
70
|
+
const authority = slash < 0 ? '' : rest.slice(0, slash);
|
|
71
|
+
const hostname = authority.split(':')[0] ?? '';
|
|
72
|
+
if (slash >= 0 && hostname.includes('.')) {
|
|
73
|
+
// An HTTP(S) port is part of the host key the broker matches; an SSH or git port is not.
|
|
74
|
+
host = scheme === 'http' || scheme === 'https' ? authority : hostname;
|
|
75
|
+
path = rest.slice(slash + 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const scp = /^(?:[^@/]+@)?([^/:]+\.[^/:]+):(.+)$/.exec(url);
|
|
80
|
+
if (scp !== null && scp[1] !== undefined && scp[2] !== undefined) {
|
|
81
|
+
host = scp[1];
|
|
82
|
+
path = scp[2];
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (path === undefined || host === undefined)
|
|
86
|
+
return undefined;
|
|
87
|
+
const cleaned = path.replace(/^\/+/, '').replace(/\/+$/, '').replace(/\.git$/i, '');
|
|
88
|
+
const [owner, repo, ...rest] = cleaned.split('/').filter((part) => part !== '');
|
|
89
|
+
if (owner === undefined || repo === undefined || rest.length > 0)
|
|
90
|
+
return undefined;
|
|
91
|
+
return { owner, repo, host: host.toLowerCase() };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The URL a remote points at, for saying what was wrong with it.
|
|
95
|
+
*
|
|
96
|
+
* @param name - the remote name.
|
|
97
|
+
* @param cwd - the directory to ask.
|
|
98
|
+
* @returns the URL, or undefined when there is no such remote.
|
|
99
|
+
*/
|
|
100
|
+
export function remoteUrl(name, cwd) {
|
|
101
|
+
return git(['remote', 'get-url', name], cwd);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Turn `remote:branch` into `owner:branch`, and leave a plain branch alone.
|
|
105
|
+
*
|
|
106
|
+
* @param value - what the operator wrote.
|
|
107
|
+
* @param cwd - the directory to resolve remotes in.
|
|
108
|
+
* @returns the value to send.
|
|
109
|
+
* @throws {Error} when the prefix is not a remote this checkout knows, naming the ones it does.
|
|
110
|
+
*/
|
|
111
|
+
export function qualifiedBranch(value, cwd) {
|
|
112
|
+
const colon = value.indexOf(':');
|
|
113
|
+
if (colon < 0)
|
|
114
|
+
return value;
|
|
115
|
+
const name = value.slice(0, colon);
|
|
116
|
+
const branch = value.slice(colon + 1);
|
|
117
|
+
const found = remoteRepo(name, cwd, true);
|
|
118
|
+
if (found === undefined) {
|
|
119
|
+
const known = listRemotes(cwd);
|
|
120
|
+
const url = remoteUrl(name, cwd);
|
|
121
|
+
if (url !== undefined) {
|
|
122
|
+
throw new Error(`remote ${JSON.stringify(name)} points at ${url}, which does not name an owner and a repository`);
|
|
123
|
+
}
|
|
124
|
+
throw new Error(`no remote named ${JSON.stringify(name)} here, so ${JSON.stringify(value)} cannot be resolved` +
|
|
125
|
+
(known.length > 0 ? `; this checkout has: ${known.join(', ')}` : '; this checkout has no remotes'));
|
|
126
|
+
}
|
|
127
|
+
return `${found.owner}:${branch}`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The branch a `--base` means, given the repository the pull request lands in.
|
|
131
|
+
*
|
|
132
|
+
* `--base upstream:main` names the remote for the check and the branch for the wire: a base is a branch of
|
|
133
|
+
* `--repo`, and `owner:branch` is not a branch name anywhere. A remote pointing at a different repository
|
|
134
|
+
* is a mistake worth catching here rather than letting GitHub answer confusingly.
|
|
135
|
+
*
|
|
136
|
+
* @param raw - what the operator wrote.
|
|
137
|
+
* @param repo - the repository `--repo` names, as `owner/name`.
|
|
138
|
+
* @param cwd - the directory to resolve remotes in.
|
|
139
|
+
* @returns the branch to send.
|
|
140
|
+
* @throws {Error} when the remote points at a repository other than `repo`.
|
|
141
|
+
*/
|
|
142
|
+
export function baseBranchFor(raw, repo, cwd) {
|
|
143
|
+
const colon = raw.indexOf(':');
|
|
144
|
+
if (colon < 0)
|
|
145
|
+
return raw;
|
|
146
|
+
const name = raw.slice(0, colon);
|
|
147
|
+
const found = remoteRepo(name, cwd);
|
|
148
|
+
if (found === undefined) {
|
|
149
|
+
// Says what is wrong with the remote rather than pretending the base is the problem.
|
|
150
|
+
throw new Error(`--base names ${JSON.stringify(name)}, which is not a remote this checkout can read`);
|
|
151
|
+
}
|
|
152
|
+
if (`${found.owner}/${found.repo}`.toLowerCase() !== repo.toLowerCase()) {
|
|
153
|
+
throw new Error(`--base names a remote pointing at ${found.owner}/${found.repo}, but --repo is ${repo}: the base is a branch of the repository the pull request lands in`);
|
|
154
|
+
}
|
|
155
|
+
return raw.slice(colon + 1);
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=remotes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remotes.js","sourceRoot":"","sources":["../../src/commands/remotes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { parseArgs } from 'gcb-core';
|
|
2
|
+
/** Everything `setup` needs, resolved. */
|
|
3
|
+
export interface SetupInput {
|
|
4
|
+
/** Credential helper command to record. A bare name is resolved by git through PATH. */
|
|
5
|
+
readonly helper: string;
|
|
6
|
+
/** Socket path in this environment. */
|
|
7
|
+
readonly socket: string;
|
|
8
|
+
/** Git config file to write. */
|
|
9
|
+
readonly gitconfig: string;
|
|
10
|
+
/** Shell snippet recording the environment for interactive shells. */
|
|
11
|
+
readonly envFile: string;
|
|
12
|
+
/** Durable socket-path file, read by the helper when the environment carries nothing. */
|
|
13
|
+
readonly socketFile: string;
|
|
14
|
+
/** Where to write a CA bundle when the image has none. */
|
|
15
|
+
readonly caBundlePath: string;
|
|
16
|
+
/** Host whose ssh remotes are rewritten to https, or null to leave remotes alone. */
|
|
17
|
+
readonly rewriteSshHost: string | null;
|
|
18
|
+
/** Report what would happen without writing anything. */
|
|
19
|
+
readonly dryRun: boolean;
|
|
20
|
+
/** Home whose mounts the config must not be written into; defaults to the real home. */
|
|
21
|
+
readonly home?: string;
|
|
22
|
+
/** The directories the container shares, when the caller already has them. */
|
|
23
|
+
readonly mounts?: readonly string[];
|
|
24
|
+
}
|
|
25
|
+
/** What `setup` did. */
|
|
26
|
+
export interface SetupResult {
|
|
27
|
+
readonly gitconfig: string;
|
|
28
|
+
readonly entries: readonly string[];
|
|
29
|
+
readonly caBundle: string | null;
|
|
30
|
+
readonly socketFile: string;
|
|
31
|
+
readonly envFile: string;
|
|
32
|
+
readonly warnings: readonly string[];
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Apply the configuration.
|
|
36
|
+
*
|
|
37
|
+
* @param input - the resolved options.
|
|
38
|
+
* @returns what was done.
|
|
39
|
+
* @throws {Error} when the target config is a symlink, or inside a directory the container shares.
|
|
40
|
+
*/
|
|
41
|
+
export declare function performSetup(input: SetupInput): Promise<SetupResult>;
|
|
42
|
+
/** Usage text for `setup`. */
|
|
43
|
+
export declare const SETUP_USAGE = "Usage: gcb setup [options]\n\nConfigure this environment's git to obtain credentials from the broker.\n\n --helper <cmd> Credential helper to record (default: !gcb, resolved through PATH)\n --socket <path> Broker socket path (default: $GIT_BROKER_SOCKET, else /run/git-cred-broker/broker.sock)\n --gitconfig <path> Git config to write (default: $HOME/.gitconfig)\n --rewrite-ssh <host> Rewrite git@<host>: remotes to https (default: github.com)\n --no-rewrite-ssh Leave remote URLs alone\n --env-file <path> Where to record the environment (default: $HOME/.git-broker.env)\n --socket-file <path> Durable socket-path file (default: $HOME/.config/git-credential-broker/socket)\n --ca-bundle <path> Where to write a CA bundle if the image has none\n --dry-run Print what would change, write nothing\n -h, --help Show this help\n";
|
|
44
|
+
/**
|
|
45
|
+
* Run the `setup` command.
|
|
46
|
+
*
|
|
47
|
+
* @param argv - arguments after the command name.
|
|
48
|
+
* @returns the process exit code.
|
|
49
|
+
*/
|
|
50
|
+
export declare function runSetup(argv: readonly string[]): Promise<number>;
|
|
51
|
+
/**
|
|
52
|
+
* Collect the repeatable `--allow` flag; exported so `init` and tests share one implementation.
|
|
53
|
+
*
|
|
54
|
+
* @param args - the parsed arguments.
|
|
55
|
+
* @returns the entries.
|
|
56
|
+
*/
|
|
57
|
+
export declare function allowList(args: ReturnType<typeof parseArgs>): string[];
|
|
58
|
+
//# sourceMappingURL=setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"AAqBA,OAAO,EAQL,SAAS,EAKV,MAAM,UAAU,CAAC;AAElB,0CAA0C;AAC1C,MAAM,WAAW,UAAU;IACzB,wFAAwF;IACxF,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,gCAAgC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,yFAAyF;IACzF,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qFAAqF;IACrF,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,wBAAwB;AACxB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,WAAW,CAAC,CA6F1E;AAED,8BAA8B;AAC9B,eAAO,MAAM,WAAW,m3BAcvB,CAAC;AAEF;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqCvE;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,SAAS,CAAC,GAAG,MAAM,EAAE,CAEtE"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `setup` — configure the git in *this* environment to use the broker.
|
|
3
|
+
*
|
|
4
|
+
* This is the container-side half, and it replaces the old `container-setup.sh`. It is written
|
|
5
|
+
* to a git config that belongs to the running user, never to a shared repository or to the
|
|
6
|
+
* host's own configuration.
|
|
7
|
+
*
|
|
8
|
+
* It does four things, each for a reason that was measured rather than assumed:
|
|
9
|
+
* - points `credential.helper` at the installed helper and turns on `credential.useHttpPath`,
|
|
10
|
+
* without which git sends no repository path and the broker can only authorize host-wide;
|
|
11
|
+
* - rewrites the ssh remote to https *in this environment only*, because an App installation
|
|
12
|
+
* token cannot be used over ssh and this container has no ssh key at all;
|
|
13
|
+
* - supplies a CA bundle when the image has none, because git then cannot verify any TLS
|
|
14
|
+
* certificate while Node still can — a pair of symptoms that looks like an application bug;
|
|
15
|
+
* - records the socket path in a file as well as in the environment, because git is often
|
|
16
|
+
* spawned from a non-login shell that never sources a profile.
|
|
17
|
+
*/
|
|
18
|
+
import fs from 'node:fs';
|
|
19
|
+
import os from 'node:os';
|
|
20
|
+
import path from 'node:path';
|
|
21
|
+
import { fail, findSystemCaBundle, gitConfigList, gitConfigSet, insideMountedPath, listFlag, mountedPaths, parseArgs, say, warn, writeNodeCaBundle, writeSecretFile, } from 'gcb-core';
|
|
22
|
+
/**
|
|
23
|
+
* Apply the configuration.
|
|
24
|
+
*
|
|
25
|
+
* @param input - the resolved options.
|
|
26
|
+
* @returns what was done.
|
|
27
|
+
* @throws {Error} when the target config is a symlink, or inside a directory the container shares.
|
|
28
|
+
*/
|
|
29
|
+
export async function performSetup(input) {
|
|
30
|
+
// Writing through a symlink would edit whatever it points at, and a config that lives in a directory
|
|
31
|
+
// the container shares is one the container can rewrite.
|
|
32
|
+
if (fs.existsSync(input.gitconfig) && fs.lstatSync(input.gitconfig).isSymbolicLink()) {
|
|
33
|
+
const target = fs.realpathSync(input.gitconfig);
|
|
34
|
+
throw new Error(`${input.gitconfig} is a symlink to ${target}; refusing to write through it`);
|
|
35
|
+
}
|
|
36
|
+
// The config must not be written into any directory the container can rewrite. Canonical, so the
|
|
37
|
+
// host's spelling of a shared directory and the container's spelling of the same one are one place.
|
|
38
|
+
// `setup` runs in the container by definition, so the mount table it is standing on is the
|
|
39
|
+
// authority. Reading it directly means a container that leaves no marker for `isInsideContainer`
|
|
40
|
+
// (plain containerd, a Kubernetes pod) still gets the right answer instead of hunting for a runtime
|
|
41
|
+
// it does not have.
|
|
42
|
+
const mounts = input.mounts ?? mountedPaths(input.home, { container: true });
|
|
43
|
+
const mounted = insideMountedPath(input.gitconfig, input.home, mounts);
|
|
44
|
+
if (mounted) {
|
|
45
|
+
throw new Error(`${input.gitconfig} is inside ${mounted}, which is mounted into the container; refusing to write ` +
|
|
46
|
+
"this environment's git config where the container can rewrite it");
|
|
47
|
+
}
|
|
48
|
+
const warnings = [];
|
|
49
|
+
if (input.dryRun) {
|
|
50
|
+
return {
|
|
51
|
+
gitconfig: input.gitconfig,
|
|
52
|
+
entries: [
|
|
53
|
+
`credential.helper=${input.helper}`,
|
|
54
|
+
'credential.useHttpPath=true',
|
|
55
|
+
...(input.rewriteSshHost ? [`url.https://${input.rewriteSshHost}/.insteadOf=git@${input.rewriteSshHost}:`] : []),
|
|
56
|
+
],
|
|
57
|
+
caBundle: findSystemCaBundle() ? null : input.caBundlePath,
|
|
58
|
+
socketFile: input.socketFile,
|
|
59
|
+
envFile: input.envFile,
|
|
60
|
+
warnings,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
fs.mkdirSync(path.dirname(input.gitconfig), { recursive: true });
|
|
64
|
+
gitConfigSet(input.gitconfig, 'credential.helper', input.helper);
|
|
65
|
+
gitConfigSet(input.gitconfig, 'credential.useHttpPath', 'true');
|
|
66
|
+
if (input.rewriteSshHost) {
|
|
67
|
+
gitConfigSet(input.gitconfig, `url.https://${input.rewriteSshHost}/.insteadOf`, `git@${input.rewriteSshHost}:`);
|
|
68
|
+
}
|
|
69
|
+
// TLS trust. The image may install git with --no-install-recommends and no ca-certificates,
|
|
70
|
+
// in which case every https operation fails with "CAfile: none" while Node keeps working.
|
|
71
|
+
let caBundle = null;
|
|
72
|
+
const systemBundle = findSystemCaBundle();
|
|
73
|
+
if (systemBundle) {
|
|
74
|
+
say(`TLS : using the system CA bundle (${systemBundle})`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const written = await writeNodeCaBundle(input.caBundlePath);
|
|
78
|
+
gitConfigSet(input.gitconfig, 'http.sslCAInfo', input.caBundlePath);
|
|
79
|
+
caBundle = input.caBundlePath;
|
|
80
|
+
say(`TLS : no system CA bundle; wrote ${written} roots from Node's store`);
|
|
81
|
+
say(` ${input.caBundlePath} (adding ca-certificates to the image would be better)`);
|
|
82
|
+
}
|
|
83
|
+
fs.chmodSync(input.gitconfig, 0o600);
|
|
84
|
+
writeSecretFile(input.socketFile, `${input.socket}\n`);
|
|
85
|
+
writeSecretFile(input.envFile, [
|
|
86
|
+
'# Generated by gcb setup',
|
|
87
|
+
`export GIT_BROKER_SOCKET='${input.socket}'`,
|
|
88
|
+
'# Fail closed: if the socket variable ever goes missing, refuse rather than silently',
|
|
89
|
+
'# falling back to whatever other credential the environment happens to offer.',
|
|
90
|
+
'export GIT_BROKER_REQUIRE=1',
|
|
91
|
+
'',
|
|
92
|
+
].join('\n'));
|
|
93
|
+
if (!fs.existsSync(input.socket)) {
|
|
94
|
+
warnings.push(`no broker socket at ${input.socket} yet; pushes will fail closed until the broker runs`);
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
gitconfig: input.gitconfig,
|
|
98
|
+
entries: gitConfigList(input.gitconfig),
|
|
99
|
+
caBundle,
|
|
100
|
+
socketFile: input.socketFile,
|
|
101
|
+
envFile: input.envFile,
|
|
102
|
+
warnings,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
/** Usage text for `setup`. */
|
|
106
|
+
export const SETUP_USAGE = `Usage: gcb setup [options]
|
|
107
|
+
|
|
108
|
+
Configure this environment's git to obtain credentials from the broker.
|
|
109
|
+
|
|
110
|
+
--helper <cmd> Credential helper to record (default: !gcb, resolved through PATH)
|
|
111
|
+
--socket <path> Broker socket path (default: $GIT_BROKER_SOCKET, else /run/git-cred-broker/broker.sock)
|
|
112
|
+
--gitconfig <path> Git config to write (default: $HOME/.gitconfig)
|
|
113
|
+
--rewrite-ssh <host> Rewrite git@<host>: remotes to https (default: github.com)
|
|
114
|
+
--no-rewrite-ssh Leave remote URLs alone
|
|
115
|
+
--env-file <path> Where to record the environment (default: $HOME/.git-broker.env)
|
|
116
|
+
--socket-file <path> Durable socket-path file (default: $HOME/.config/git-credential-broker/socket)
|
|
117
|
+
--ca-bundle <path> Where to write a CA bundle if the image has none
|
|
118
|
+
--dry-run Print what would change, write nothing
|
|
119
|
+
-h, --help Show this help
|
|
120
|
+
`;
|
|
121
|
+
/**
|
|
122
|
+
* Run the `setup` command.
|
|
123
|
+
*
|
|
124
|
+
* @param argv - arguments after the command name.
|
|
125
|
+
* @returns the process exit code.
|
|
126
|
+
*/
|
|
127
|
+
export async function runSetup(argv) {
|
|
128
|
+
const args = parseArgs(argv, { booleans: ['no-rewrite-ssh', 'dry-run', 'help'] });
|
|
129
|
+
if (args.has('help') || args.has('h')) {
|
|
130
|
+
say(SETUP_USAGE);
|
|
131
|
+
return 0;
|
|
132
|
+
}
|
|
133
|
+
const home = os.homedir();
|
|
134
|
+
const socket = args.value('socket') ?? process.env['GIT_BROKER_SOCKET'] ?? '/run/git-cred-broker/broker.sock';
|
|
135
|
+
try {
|
|
136
|
+
const result = await performSetup({
|
|
137
|
+
// !gcb is a shell command, so the git process that later runs the helper resolves it
|
|
138
|
+
// through its own PATH. setup cannot know that future environment; this is why the
|
|
139
|
+
// README says the installed gcb must be on the PATH of the processes that call git.
|
|
140
|
+
helper: args.value('helper') ?? '!gcb',
|
|
141
|
+
socket,
|
|
142
|
+
gitconfig: args.value('gitconfig') ?? path.join(home, '.gitconfig'),
|
|
143
|
+
envFile: args.value('env-file') ?? path.join(home, '.git-broker.env'),
|
|
144
|
+
socketFile: args.value('socket-file') ?? path.join(home, '.config', 'git-credential-broker', 'socket'),
|
|
145
|
+
caBundlePath: args.value('ca-bundle') ?? path.join(home, '.config', 'git-credential-broker', 'ca-bundle.pem'),
|
|
146
|
+
rewriteSshHost: args.has('no-rewrite-ssh') ? null : (args.value('rewrite-ssh') ?? 'github.com'),
|
|
147
|
+
dryRun: args.has('dry-run'),
|
|
148
|
+
home,
|
|
149
|
+
});
|
|
150
|
+
say(`git config : ${result.gitconfig}${args.has('dry-run') ? ' (dry run)' : ''}`);
|
|
151
|
+
for (const entry of result.entries)
|
|
152
|
+
say(` ${entry}`);
|
|
153
|
+
if (result.caBundle)
|
|
154
|
+
say(`CA bundle : ${result.caBundle}`);
|
|
155
|
+
say(`socket file : ${result.socketFile}`);
|
|
156
|
+
say(`env file : ${result.envFile}`);
|
|
157
|
+
for (const warning of result.warnings)
|
|
158
|
+
warn(`warning: ${warning}`);
|
|
159
|
+
if (args.has('dry-run'))
|
|
160
|
+
say('dry run: nothing was written');
|
|
161
|
+
else
|
|
162
|
+
say('\nnext: start the broker (gcb daemon) and verify with `gcb probe`.');
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
fail(error.message);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Collect the repeatable `--allow` flag; exported so `init` and tests share one implementation.
|
|
171
|
+
*
|
|
172
|
+
* @param args - the parsed arguments.
|
|
173
|
+
* @returns the entries.
|
|
174
|
+
*/
|
|
175
|
+
export function allowList(args) {
|
|
176
|
+
return listFlag(args, 'allow');
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=setup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/commands/setup.ts"],"names":[],"mappings":"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"}
|
package/lib/helper.d.ts
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { Readable, Writable } from 'node:stream';
|
|
2
|
+
import type { WireResponse } from 'gcb-core';
|
|
3
|
+
/** Injectable streams and environment, for tests. */
|
|
4
|
+
export interface HelperIO {
|
|
5
|
+
readonly stdin?: Readable;
|
|
6
|
+
readonly stdout?: Writable;
|
|
7
|
+
readonly stderr?: Writable;
|
|
8
|
+
readonly env?: NodeJS.ProcessEnv;
|
|
9
|
+
}
|
|
10
|
+
/** The helper's parsed command line. */
|
|
11
|
+
export interface HelperArgs {
|
|
12
|
+
readonly operation: string;
|
|
13
|
+
readonly socketPath: string | undefined;
|
|
14
|
+
readonly strict: boolean;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse git's credential description.
|
|
18
|
+
*
|
|
19
|
+
* @param text - the raw stdin contents.
|
|
20
|
+
* @returns the key/value pairs.
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseCredentialInput(text: string): Record<string, string>;
|
|
23
|
+
/**
|
|
24
|
+
* Read a stream to the end, with a size ceiling.
|
|
25
|
+
*
|
|
26
|
+
* Chunks are normalized to `Buffer` rather than assumed: `process.stdin` yields buffers, but
|
|
27
|
+
* any stream in string or object mode yields strings, and `Buffer.concat` rejects those.
|
|
28
|
+
*
|
|
29
|
+
* @param stream - the stream to drain.
|
|
30
|
+
* @param maxBytes - ceiling; exceeding it rejects.
|
|
31
|
+
* @returns the decoded contents.
|
|
32
|
+
*/
|
|
33
|
+
export declare function readAll(stream: Readable, maxBytes?: number): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* Send one request to the broker over its unix socket and await one response.
|
|
36
|
+
*
|
|
37
|
+
* @param socketPath - the broker socket path.
|
|
38
|
+
* @param request - the request payload.
|
|
39
|
+
* @param timeoutMs - how long to wait for an answer.
|
|
40
|
+
* @returns the parsed response.
|
|
41
|
+
*/
|
|
42
|
+
export declare function requestOverSocket(socketPath: string, request: Record<string, unknown>, timeoutMs?: number): Promise<WireResponse>;
|
|
43
|
+
/**
|
|
44
|
+
* Decide where the broker lives, in precedence order:
|
|
45
|
+
*
|
|
46
|
+
* 1. `--socket <path>` on the command line;
|
|
47
|
+
* 2. `GIT_BROKER_SOCKET`;
|
|
48
|
+
* 3. the contents of `GIT_BROKER_SOCKET_FILE`, defaulting to
|
|
49
|
+
* `$HOME/.config/git-credential-broker/socket`.
|
|
50
|
+
*
|
|
51
|
+
* An empty or missing result means "not configured in this environment", which the caller
|
|
52
|
+
* treats as "behave as if not installed".
|
|
53
|
+
*
|
|
54
|
+
* @param explicitSocket - the `--socket` argument, if any.
|
|
55
|
+
* @param env - the environment to read.
|
|
56
|
+
* @returns the resolved socket path, or undefined when nothing is configured.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveSocketPath(explicitSocket: string | undefined, env: NodeJS.ProcessEnv): string | undefined;
|
|
59
|
+
/**
|
|
60
|
+
* Parse the helper's own command line.
|
|
61
|
+
*
|
|
62
|
+
* @param argv - arguments after the script name.
|
|
63
|
+
* @returns the parsed arguments.
|
|
64
|
+
*/
|
|
65
|
+
export declare function parseArgs(argv: readonly string[]): HelperArgs;
|
|
66
|
+
/**
|
|
67
|
+
* Run the helper.
|
|
68
|
+
*
|
|
69
|
+
* Always resolves with an exit code; refusals still exit 0 on purpose (see the module
|
|
70
|
+
* comment) so that git stops instead of falling through to another helper.
|
|
71
|
+
*
|
|
72
|
+
* @param argv - arguments after the script name.
|
|
73
|
+
* @param io - injectable streams and environment.
|
|
74
|
+
* @returns the process exit code.
|
|
75
|
+
*/
|
|
76
|
+
export declare function runHelper(argv: readonly string[], io?: HelperIO): Promise<number>;
|
|
77
|
+
//# sourceMappingURL=helper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helper.d.ts","sourceRoot":"","sources":["../src/helper.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAiB7C,qDAAqD;AACrD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC;IAC3B,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAClC;AAED,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAE,MAAwB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB7F;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAChC,SAAS,GAAE,MAA0B,GACpC,OAAO,CAAC,YAAY,CAAC,CAoCvB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAC/B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,MAAM,GAAG,SAAS,CAcpB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,UAAU,CAqB7D;AAED;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,EAAE,GAAE,QAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CAyF3F"}
|