gcb-host 0.8.1 → 0.9.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/CHANGELOG.md +23 -0
- package/lib/commands/authorize.d.ts +1 -1
- package/lib/commands/authorize.d.ts.map +1 -1
- package/lib/commands/authorize.js +23 -11
- package/lib/commands/authorize.js.map +1 -1
- package/lib/commands/compose.d.ts.map +1 -1
- package/lib/commands/compose.js +12 -5
- package/lib/commands/compose.js.map +1 -1
- package/lib/commands/host.d.ts.map +1 -1
- package/lib/commands/host.js +238 -7
- package/lib/commands/host.js.map +1 -1
- package/lib/config.d.ts.map +1 -1
- package/lib/config.js +16 -0
- package/lib/config.js.map +1 -1
- package/lib/providers/github-app.d.ts.map +1 -1
- package/lib/providers/github-app.js +9 -3
- package/lib/providers/github-app.js.map +1 -1
- package/lib/token-lock.d.ts +34 -0
- package/lib/token-lock.d.ts.map +1 -0
- package/lib/token-lock.js +135 -0
- package/lib/token-lock.js.map +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# gcb-host
|
|
2
2
|
|
|
3
|
+
## 0.9.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#142](https://github.com/code-vaults/git-credential-broker/pull/142) [`d26ea16`](https://github.com/code-vaults/git-credential-broker/commit/d26ea16a5c0df22e4865ee3947009a3be1266297) Thanks [@i1stG](https://github.com/i1stG)! - Allow host-broker requests made outside a checkout to use the shared
|
|
8
|
+
`~/.gcb-host/channel`; they still require an explicit `--repo` and the same allowlist and account
|
|
9
|
+
checks. The channel is a pre-created, host-owned 0700 directory; the broker validates it and does
|
|
10
|
+
not create or chmod it.
|
|
11
|
+
|
|
12
|
+
- [#136](https://github.com/code-vaults/git-credential-broker/pull/136) [`bcc1373`](https://github.com/code-vaults/git-credential-broker/commit/bcc1373cedabeca2d267bd07ab85db15e98895a2) Thanks [@JounQin](https://github.com/JounQin)! - Add `gcb push` (explicit host-executed push; a deliberate exception to native Git): the host broker pushes an exact commit with its own gh account, or its SSH
|
|
13
|
+
agent/key when the selected remote uses SSH. A destination fork is allowed when `allowForkPush` verifies its parent/source against the allowlist;
|
|
14
|
+
the command takes a git-style remote and branch, and the request carries the repository, remote,
|
|
15
|
+
branch, exact commit, optional force/lease expectation, account and proxy; `--force` and `--force-with-lease` are explicit. Other push arguments are not passed through; no token or container-controlled remote URL enters the host push.
|
|
16
|
+
The container runs its own `pre-push` hook; the host never runs container-owned hooks.
|
|
17
|
+
|
|
18
|
+
- [#144](https://github.com/code-vaults/git-credential-broker/pull/144) [`e55194f`](https://github.com/code-vaults/git-credential-broker/commit/e55194f7a09fe64edf08f20c4cfff9afa7b13326) Thanks [@JounQin](https://github.com/JounQin)! - Serialize refresh-token renewal and `gcb authorize` with a shared `user.refresh.lock` directory, and
|
|
19
|
+
replace the token under the lock. Re-authorizing a running sidecar no longer requires stopping it.
|
|
20
|
+
|
|
21
|
+
### Patch Changes
|
|
22
|
+
|
|
23
|
+
- Updated dependencies [[`d26ea16`](https://github.com/code-vaults/git-credential-broker/commit/d26ea16a5c0df22e4865ee3947009a3be1266297), [`bcc1373`](https://github.com/code-vaults/git-credential-broker/commit/bcc1373cedabeca2d267bd07ab85db15e98895a2)]:
|
|
24
|
+
- gcb-core@0.9.0
|
|
25
|
+
|
|
3
26
|
## 0.8.1
|
|
4
27
|
|
|
5
28
|
### Patch Changes
|
|
@@ -61,7 +61,7 @@ export declare function openTokenTarget(target: string): number;
|
|
|
61
61
|
* @param input - The configuration path, target override and injectable guards.
|
|
62
62
|
* @returns The target and an optional warning.
|
|
63
63
|
* @throws {Error} When the placement would put the token inside a container mount without the
|
|
64
|
-
*
|
|
64
|
+
* explicit broker-container acknowledgement.
|
|
65
65
|
*/
|
|
66
66
|
export declare function resolveAuthorizationPlacement(input: AuthorizationPlacementInput): AuthorizationPlacement;
|
|
67
67
|
export declare function runAuthorize(argv: readonly string[]): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/commands/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;
|
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/commands/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAYH,kCAAkC;AAClC,eAAO,MAAM,eAAe,mnCAkB3B,CAAA;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAEtF;AAED,oDAAoD;AACpD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAA;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,OAAO,CAAA;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAA;CACzD;AAED,oFAAoF;AACpF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAuBtD;AAaD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,2BAA2B,GACjC,sBAAsB,CAsBxB;AAUD,wBAAsB,YAAY,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAgH3E"}
|
|
@@ -12,12 +12,13 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Exit codes: 0 stored, 1 refused.
|
|
14
14
|
*/
|
|
15
|
-
import { closeSync, constants, fchmodSync, fstatSync,
|
|
15
|
+
import { closeSync, constants, fchmodSync, fstatSync, mkdirSync, openSync } from 'node:fs';
|
|
16
16
|
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
17
17
|
import { fail, insideMountedPath, isInsideContainer, parseArgs, say, warn } from 'gcb-core';
|
|
18
18
|
import { USER_TOKEN_FILE, userTokenPath, loadConfig, resolveConfigPath } from '../config.js';
|
|
19
19
|
import { collectUserToken, startDeviceFlow } from '../device-flow.js';
|
|
20
20
|
import { fetcherFor, parseProxy } from '../http.js';
|
|
21
|
+
import { withTokenLock, writeTokenThrough } from '../token-lock.js';
|
|
21
22
|
/** Usage text for `authorize`. */
|
|
22
23
|
export const AUTHORIZE_USAGE = `Usage: gcb authorize [options]
|
|
23
24
|
|
|
@@ -71,7 +72,10 @@ export function brokerReadsPath(privateKeyPath) {
|
|
|
71
72
|
*/
|
|
72
73
|
export function openTokenTarget(target) {
|
|
73
74
|
mkdirSync(dirname(target), { recursive: true, mode: 0o700 });
|
|
74
|
-
const flags = constants.O_WRONLY |
|
|
75
|
+
const flags = constants.O_WRONLY |
|
|
76
|
+
constants.O_CREAT |
|
|
77
|
+
(constants.O_NOFOLLOW ?? 0) |
|
|
78
|
+
(constants.O_NONBLOCK ?? 0);
|
|
75
79
|
const fd = openSync(target, flags, 0o600);
|
|
76
80
|
try {
|
|
77
81
|
const info = fstatSync(fd);
|
|
@@ -90,12 +94,16 @@ export function openTokenTarget(target) {
|
|
|
90
94
|
throw error;
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
|
-
/**
|
|
94
|
-
function writeToken(fd, token) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
/** Replace the token through the validated descriptor, under its lock. */
|
|
98
|
+
async function writeToken(fd, target, token) {
|
|
99
|
+
try {
|
|
100
|
+
await withTokenLock(target, async () => {
|
|
101
|
+
writeTokenThrough(fd, token);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
finally {
|
|
105
|
+
closeSync(fd);
|
|
106
|
+
}
|
|
99
107
|
}
|
|
100
108
|
/**
|
|
101
109
|
* Decide where the refresh token goes, and whether that placement is allowed.
|
|
@@ -103,7 +111,7 @@ function writeToken(fd, token) {
|
|
|
103
111
|
* @param input - The configuration path, target override and injectable guards.
|
|
104
112
|
* @returns The target and an optional warning.
|
|
105
113
|
* @throws {Error} When the placement would put the token inside a container mount without the
|
|
106
|
-
*
|
|
114
|
+
* explicit broker-container acknowledgement.
|
|
107
115
|
*/
|
|
108
116
|
export function resolveAuthorizationPlacement(input) {
|
|
109
117
|
const target = input.to ?? refreshTokenPath(input.configPath);
|
|
@@ -195,13 +203,17 @@ export async function runAuthorize(argv) {
|
|
|
195
203
|
throw new Error('GitHub returned no refresh token, so the token would expire in eight hours with no way to renew.\n' +
|
|
196
204
|
' Select "Expire user authorization tokens" in the app settings and authorize again.');
|
|
197
205
|
}
|
|
198
|
-
|
|
206
|
+
const fd = tokenFd;
|
|
207
|
+
tokenFd = undefined;
|
|
208
|
+
await writeToken(fd, placement.target, token.refreshToken);
|
|
199
209
|
}
|
|
200
210
|
catch (error) {
|
|
201
211
|
failure = error;
|
|
202
212
|
}
|
|
203
213
|
finally {
|
|
204
|
-
|
|
214
|
+
if (tokenFd !== undefined) {
|
|
215
|
+
closeSync(tokenFd);
|
|
216
|
+
}
|
|
205
217
|
}
|
|
206
218
|
if (failure !== undefined) {
|
|
207
219
|
fail(failure.message);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/commands/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/commands/authorize.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/commands/compose.ts"],"names":[],"mappings":"AAyBA,4CAA4C;AAC5C,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,uDAAuD;AACvD,eAAO,MAAM,QAAQ,aAAa,CAAA;AAsBlC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/commands/compose.ts"],"names":[],"mappings":"AAyBA,4CAA4C;AAC5C,MAAM,WAAW,YAAY;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,0CAA0C;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,uDAAuD;AACvD,eAAO,MAAM,QAAQ,aAAa,CAAA;AAsBlC;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CA0HzD;AAED,gCAAgC;AAChC,eAAO,MAAM,aAAa,88BAezB,CAAA;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CA6D1D"}
|
package/lib/commands/compose.js
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The broker runs in its own container with the private key mounted read-only, no published ports,
|
|
5
5
|
* no capabilities and a read-only root filesystem; the only surface it shares with anything else is
|
|
6
|
-
* the socket directory. The released image contains the package, so there is no checkout to copy
|
|
7
|
-
* nothing to build on the host.
|
|
6
|
+
* the socket directory. The released image contains the package, so there is no checkout to copy
|
|
7
|
+
* and nothing to build on the host.
|
|
8
8
|
*
|
|
9
9
|
* The mount targets are constants from `deployment.ts`, shared with `init --mode sidecar`, so the
|
|
10
10
|
* paths recorded in `broker.config.yml` and the paths this file mounts cannot drift apart.
|
|
@@ -70,9 +70,16 @@ export function renderCompose(input) {
|
|
|
70
70
|
environment:${egress}`;
|
|
71
71
|
// A bind mount for a path that does not exist becomes a directory, and the broker would then read a
|
|
72
72
|
// directory instead of a token — for every action, not only the personal ones. Emit it once `authorize`
|
|
73
|
-
// has written the file, and say what to run until then.
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
// has written the file, and say what to run until then. The lock directory is mounted beside it so
|
|
74
|
+
// the container can serialize a renewal against a host-side `gcb authorize`.
|
|
75
|
+
const token = `${input.dir}/${USER_TOKEN_FILE}`;
|
|
76
|
+
const lock = `${token}.lock`;
|
|
77
|
+
const hasToken = fs.existsSync(token);
|
|
78
|
+
if (hasToken) {
|
|
79
|
+
fs.mkdirSync(lock, { recursive: true, mode: 0o700 });
|
|
80
|
+
}
|
|
81
|
+
const userRefreshMount = hasToken
|
|
82
|
+
? `\n # The authorized person's refresh token: the only secret mounted writable, because GitHub\n # rotates it on every exchange.\n - ${yamlVolume(token, SIDECAR.userTokenPath, 'rw')}\n # The lock directory for that token; both sides must see the same one.\n - ${yamlVolume(lock, `${SIDECAR.userTokenPath}.lock`, 'rw')}`
|
|
76
83
|
: '\n # No user.refresh yet: run `gcb authorize` and render this again. A mount' +
|
|
77
84
|
'\n # for a path that does not exist would become a directory, and the broker would read that.';
|
|
78
85
|
const start = fromCode
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/commands/compose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,UAAU,CAAA;AAEtE,OAAO,EACL,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,aAAa,EACb,OAAO,EACP,eAAe,GAChB,MAAM,cAAc,CAAA;AAwBrB,uDAAuD;AACvD,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,CAAA;AAElC,6EAA6E;AAC7E,SAAS,UAAU,CAAC,IAAY,EAAE,SAAiB,EAAE,IAAa;IAChE,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,SAAS,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,EAAE,CAAA;IACzE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;IAC9C,qGAAqG;IACrG,OAAO,2BAA2B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;AAClF,CAAC;AAED,6EAA6E;AAC7E,SAAS,kBAAkB,CAAC,UAAkB;IAC5C,IAAI,CAAC;QACH,OAAO,EAAE,CAAC,YAAY,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACvD,OAAO,UAAU,CAAA;QACnB,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAmB;IAC/C,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IACrD,MAAM,UAAU,GAAG,KAAK,CAAC,UAAU,IAAI,GAAG,KAAK,CAAC,GAAG,oBAAoB,CAAA;IACvE,2FAA2F;IAC3F,MAAM,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAA;IACjD,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,EACtC,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAC1B,CAAA;IACD,yFAAyF;IACzF,MAAM,gBAAgB,GAAG,IAAI,iBAAiB,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,CAC9E,KAAK,EACL,GAAG,EAAE,CAAC,IAAI,CACX,CAAA;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,KAAK,SAAS,CAAA;IAEzC,MAAM,MAAM,GAAG,QAAQ;QACrB,CAAC,CAAC,6CAA6C,KAAK,CAAC,IAAI;;gGAEmC;QAC5F,CAAC,CAAC;8EACwE,CAAA;IAE5E,qGAAqG;IACrG,oGAAoG;IACpG,MAAM,MAAM,GAAG;;;;;;;;wCAQuB,CAAA;IAEtC,MAAM,WAAW,GAAG;kBACJ,MAAM,EAAE,CAAA;IAExB,oGAAoG;IACpG,wGAAwG;IACxG,
|
|
1
|
+
{"version":3,"file":"compose.js","sourceRoot":"","sources":["../../src/commands/compose.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/commands/host.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../../src/commands/host.ts"],"names":[],"mappings":"AA2EA,kEAAkE;AAClE,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAiBD,gDAAgD;AAChD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CACtB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GACzF,OAAO,CAAC,aAAa,CAAC,CA2GxB;AAED,6BAA6B;AAC7B,eAAO,MAAM,iBAAiB,8oDAwB7B,CAAA;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAO1F;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAkN5E"}
|
package/lib/commands/host.js
CHANGED
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
* shell; the program it calls is configuration, and it is called with an argument list built here.
|
|
13
13
|
*/
|
|
14
14
|
import { execFile, spawn } from 'node:child_process';
|
|
15
|
-
import { existsSync, mkdtempSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
15
|
+
import { existsSync, lstatSync, mkdirSync, mkdtempSync, rmSync, statSync, writeFileSync, } from 'node:fs';
|
|
16
16
|
import { homedir, tmpdir } from 'node:os';
|
|
17
17
|
import { join, resolve } from 'node:path';
|
|
18
18
|
import { StringDecoder } from 'node:string_decoder';
|
|
19
19
|
import { promisify } from 'node:util';
|
|
20
|
-
import { channelDir, clearHostBroker, discoverCheckouts, findGitDir, listRequests, reclaimAbandoned, readHostBroker, claimRequest, removeRequest, requestProblems, writeHostBroker, writeJsonAtomic, readJson, writeResult, PACKAGE_VERSION, canonicalPath, apiBodyJson, HOST, REPOSITORY, ANSWER_TIMEOUT_MS, buildGhArgv, getGhAction, fail, listFlag, parseArgs, say, validateArgs, warn, } from 'gcb-core';
|
|
20
|
+
import { channelDir, clearHostBroker, discoverCheckouts, findGitDir, globalChannelDir, listRequests, reclaimAbandoned, readHostBroker, claimRequest, removeRequest, requestProblems, writeHostBroker, writeJsonAtomic, readJson, writeResult, PACKAGE_VERSION, canonicalPath, apiBodyJson, HOST, REPOSITORY, ANSWER_TIMEOUT_MS, PUSH_TIMEOUT_MS, buildGhArgv, getGhAction, fail, listFlag, parseArgs, say, validateArgs, warn, } from 'gcb-core';
|
|
21
21
|
import { loadConfig, resolveConfigPath } from '../config.js';
|
|
22
22
|
import { applyProxyChoice, fetcherFor, parseProxy } from '../http.js';
|
|
23
23
|
import { hostConfig, parseAllowEntry, repoAllowed } from '../policy.js';
|
|
@@ -294,7 +294,9 @@ export async function runHostBroker(argv) {
|
|
|
294
294
|
/** The checkouts to serve: one named checkout, or everything under the roots. */
|
|
295
295
|
const targets = () => {
|
|
296
296
|
if (single === undefined) {
|
|
297
|
-
|
|
297
|
+
const checkouts = scanned.flatMap(root => discoverCheckouts(root, depth));
|
|
298
|
+
const channel = existingGlobalChannel();
|
|
299
|
+
return channel === undefined ? checkouts : [...checkouts, { repo: channel, dir: channel }];
|
|
298
300
|
}
|
|
299
301
|
const gitDir = findGitDir(single);
|
|
300
302
|
if (gitDir === undefined) {
|
|
@@ -345,7 +347,7 @@ export async function runHostBroker(argv) {
|
|
|
345
347
|
pid: process.pid,
|
|
346
348
|
command,
|
|
347
349
|
startedAt: new Date().toISOString(),
|
|
348
|
-
kinds: ['pull-request', 'review', 'reply', 'edit', 'action', 'fork'],
|
|
350
|
+
kinds: ['pull-request', 'review', 'reply', 'edit', 'action', 'fork', 'push'],
|
|
349
351
|
});
|
|
350
352
|
}
|
|
351
353
|
};
|
|
@@ -371,7 +373,10 @@ export async function runHostBroker(argv) {
|
|
|
371
373
|
say(single === undefined
|
|
372
374
|
? `serving the checkouts under ${scanned.join(', ')}`
|
|
373
375
|
: `serving ${single}`);
|
|
374
|
-
say(`creating pull requests, issues, reviews, replies and
|
|
376
|
+
say(`creating pull requests, issues, reviews, replies, forks and pushes with ${command}${extra.length > 0 ? ` ${extra.join(' ')}` : ''}, as the request's account or this user`);
|
|
377
|
+
if (single === undefined && !existsSync(globalChannelDir())) {
|
|
378
|
+
warn(`not serving the global channel: ${globalChannelDir()} does not exist; create it once with mode 0700`);
|
|
379
|
+
}
|
|
375
380
|
for (;;) {
|
|
376
381
|
for (const { repo, dir } of targets()) {
|
|
377
382
|
// One checkout the container has made hostile — its channel directory replaced by a file, say —
|
|
@@ -432,6 +437,9 @@ async function sweep(dir, repo, command, extra, allowed, blockFor) {
|
|
|
432
437
|
continue;
|
|
433
438
|
}
|
|
434
439
|
const problems = requestProblems(request);
|
|
440
|
+
if (dir === globalChannelDir() && request.repo === undefined) {
|
|
441
|
+
problems.push('the global channel needs an explicit repo');
|
|
442
|
+
}
|
|
435
443
|
if (problems.length > 0) {
|
|
436
444
|
writeResult(dir, id, { error: problems.join('; ') });
|
|
437
445
|
removeRequest(dir, id);
|
|
@@ -461,7 +469,9 @@ async function sweep(dir, repo, command, extra, allowed, blockFor) {
|
|
|
461
469
|
? `edited #${result.number} as ${request.account ?? 'this user'}${result.url === undefined ? '' : `: ${result.url}`}`
|
|
462
470
|
: request.kind === 'action'
|
|
463
471
|
? `ran ${request.action} as ${request.account ?? 'this user'}`
|
|
464
|
-
:
|
|
472
|
+
: request.kind === 'push'
|
|
473
|
+
? `pushed ${request.branch} as ${request.account ?? 'this user'}`
|
|
474
|
+
: `opened #${result.number} as ${request.account ?? 'this user'}: ${result.url}`);
|
|
465
475
|
}
|
|
466
476
|
else {
|
|
467
477
|
warn(`failed to open ${request.kind === 'fork'
|
|
@@ -474,7 +484,9 @@ async function sweep(dir, repo, command, extra, allowed, blockFor) {
|
|
|
474
484
|
? `edit on #${request.number}`
|
|
475
485
|
: request.kind === 'action'
|
|
476
486
|
? request.action
|
|
477
|
-
: request.
|
|
487
|
+
: request.kind === 'push'
|
|
488
|
+
? request.branch
|
|
489
|
+
: request.head}: ${result.error}`);
|
|
478
490
|
}
|
|
479
491
|
answered += 1;
|
|
480
492
|
}
|
|
@@ -586,6 +598,160 @@ async function withBodyFile(body, work, name = 'body.md') {
|
|
|
586
598
|
rmSync(scratch, { recursive: true, force: true });
|
|
587
599
|
}
|
|
588
600
|
}
|
|
601
|
+
/** Drop inherited Git location variables so a caller's GIT_DIR cannot retarget these commands. */
|
|
602
|
+
function withoutGitLocation(env) {
|
|
603
|
+
const copy = { ...env };
|
|
604
|
+
delete copy['GIT_DIR'];
|
|
605
|
+
delete copy['GIT_WORK_TREE'];
|
|
606
|
+
delete copy['GIT_COMMON_DIR'];
|
|
607
|
+
return copy;
|
|
608
|
+
}
|
|
609
|
+
/** Quote one value for the shell git uses to run a credential helper. */
|
|
610
|
+
function shellQuote(value) {
|
|
611
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
612
|
+
}
|
|
613
|
+
/** Resolve the common authorization, transport and credential setup. */
|
|
614
|
+
async function resolvePushTarget(request, context) {
|
|
615
|
+
const host = request.host ?? 'github.com';
|
|
616
|
+
let allowedPush = false;
|
|
617
|
+
try {
|
|
618
|
+
allowedPush = context.allowed(host, request.repo);
|
|
619
|
+
if (!allowedPush && context.blockFor(host)?.allowForkPush === true) {
|
|
620
|
+
let apiEnv;
|
|
621
|
+
try {
|
|
622
|
+
apiEnv = forkEnv(request.proxy, request.account, host);
|
|
623
|
+
}
|
|
624
|
+
catch (error) {
|
|
625
|
+
if (request.account === undefined) {
|
|
626
|
+
return { error: error.message };
|
|
627
|
+
}
|
|
628
|
+
apiEnv = forkEnv(request.proxy, undefined, host);
|
|
629
|
+
}
|
|
630
|
+
const { stdout } = await run(context.command, [...context.extra, 'api', `repos/${request.repo}`], {
|
|
631
|
+
cwd: context.repo,
|
|
632
|
+
timeout: CREATE_TIMEOUT_MS,
|
|
633
|
+
maxBuffer: 1 << 20,
|
|
634
|
+
env: apiEnv,
|
|
635
|
+
});
|
|
636
|
+
const body = JSON.parse(stdout);
|
|
637
|
+
const source = typeof body?.source?.full_name === 'string'
|
|
638
|
+
? body.source.full_name
|
|
639
|
+
: typeof body?.parent?.full_name === 'string'
|
|
640
|
+
? body.parent.full_name
|
|
641
|
+
: undefined;
|
|
642
|
+
allowedPush = body?.fork === true && source !== undefined && context.allowed(host, source);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
catch (error) {
|
|
646
|
+
return { error: error.message };
|
|
647
|
+
}
|
|
648
|
+
if (!allowedPush) {
|
|
649
|
+
return { error: `repository ${request.repo} is not in the allowlist for ${host}` };
|
|
650
|
+
}
|
|
651
|
+
const remote = request.remote ?? 'origin';
|
|
652
|
+
let transport = 'https';
|
|
653
|
+
try {
|
|
654
|
+
const { stdout } = await run('git', ['remote', 'get-url', '--push', remote], {
|
|
655
|
+
cwd: context.repo,
|
|
656
|
+
timeout: CREATE_TIMEOUT_MS,
|
|
657
|
+
maxBuffer: 1 << 20,
|
|
658
|
+
env: { ...withoutGitLocation(process.env), LC_ALL: 'C', LANG: 'C' },
|
|
659
|
+
});
|
|
660
|
+
if (/^(?:ssh:\/\/|[^@/]+@[^/:]+:|[^/:]+\.[^/:]+:)/.test(stdout.trim())) {
|
|
661
|
+
transport = 'ssh';
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
catch (error) {
|
|
665
|
+
const failure = error;
|
|
666
|
+
const reason = (failure.stderr ?? failure.message ?? '').trim();
|
|
667
|
+
if (!/No such remote|does not have a push url|not a git repository/i.test(reason)) {
|
|
668
|
+
return { error: reason.slice(0, 300) || 'could not read the remote push URL' };
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
if (transport === 'ssh' && request.proxy !== undefined) {
|
|
672
|
+
return { error: '--proxy/--no-proxy is not supported for SSH pushes' };
|
|
673
|
+
}
|
|
674
|
+
let sshHost = host;
|
|
675
|
+
if (transport === 'ssh' && request.account !== undefined) {
|
|
676
|
+
let alias;
|
|
677
|
+
try {
|
|
678
|
+
alias = context.blockFor(host)?.sshAccounts?.[request.account.toLowerCase()];
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
return { error: error.message };
|
|
682
|
+
}
|
|
683
|
+
if (alias === undefined) {
|
|
684
|
+
return { error: `no SSH host is configured for account ${request.account} on ${host}` };
|
|
685
|
+
}
|
|
686
|
+
sshHost = alias;
|
|
687
|
+
}
|
|
688
|
+
const url = transport === 'ssh'
|
|
689
|
+
? `ssh://git@${sshHost}/${request.repo}.git`
|
|
690
|
+
: `https://${host}/${request.repo}.git`;
|
|
691
|
+
const helper = `!${[context.command, ...context.extra].map(shellQuote).join(' ')} auth git-credential`;
|
|
692
|
+
const credentials = transport === 'ssh'
|
|
693
|
+
? []
|
|
694
|
+
: [
|
|
695
|
+
'-c',
|
|
696
|
+
'credential.helper=',
|
|
697
|
+
'-c',
|
|
698
|
+
`credential.helper=${helper}`,
|
|
699
|
+
'-c',
|
|
700
|
+
'credential.useHttpPath=true',
|
|
701
|
+
];
|
|
702
|
+
try {
|
|
703
|
+
const cleanEnv = withoutGitLocation({
|
|
704
|
+
...forkEnv(request.proxy, transport === 'ssh' ? undefined : request.account, host),
|
|
705
|
+
GIT_CONFIG_NOSYSTEM: '1',
|
|
706
|
+
GIT_CONFIG_GLOBAL: process.platform === 'win32' ? 'NUL' : '/dev/null',
|
|
707
|
+
GIT_TERMINAL_PROMPT: '0',
|
|
708
|
+
});
|
|
709
|
+
return { target: { url, credentials, cleanEnv } };
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
return { error: error.message };
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
/** Remove this broker's marker from a channel it can no longer serve. */
|
|
716
|
+
function dropOwnMarker(channel) {
|
|
717
|
+
if (readHostBroker(channel)?.pid === process.pid) {
|
|
718
|
+
clearHostBroker(channel);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
/** The last channel problem, so an idle broker does not repeat it every sweep. */
|
|
722
|
+
let lastGlobalChannelWarning;
|
|
723
|
+
function warnGlobalChannel(message) {
|
|
724
|
+
if (message === lastGlobalChannelWarning) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
lastGlobalChannelWarning = message;
|
|
728
|
+
warn(message);
|
|
729
|
+
}
|
|
730
|
+
/** The pre-created shared channel, when it is a real directory. */
|
|
731
|
+
function existingGlobalChannel() {
|
|
732
|
+
const channel = globalChannelDir();
|
|
733
|
+
try {
|
|
734
|
+
const stat = lstatSync(channel);
|
|
735
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
736
|
+
warnGlobalChannel(`not serving the global channel: ${channel} is not a real directory`);
|
|
737
|
+
dropOwnMarker(channel);
|
|
738
|
+
return undefined;
|
|
739
|
+
}
|
|
740
|
+
if ((stat.mode & 0o077) !== 0) {
|
|
741
|
+
warnGlobalChannel(`not serving the global channel: ${channel} is accessible to other users (chmod 700 it)`);
|
|
742
|
+
dropOwnMarker(channel);
|
|
743
|
+
return undefined;
|
|
744
|
+
}
|
|
745
|
+
lastGlobalChannelWarning = undefined;
|
|
746
|
+
return channel;
|
|
747
|
+
}
|
|
748
|
+
catch (error) {
|
|
749
|
+
if (error.code !== 'ENOENT') {
|
|
750
|
+
warnGlobalChannel(`not serving the global channel: ${error.message}`);
|
|
751
|
+
}
|
|
752
|
+
return undefined;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
589
755
|
/**
|
|
590
756
|
* Create one pull request, issue, review, reply, edit or comment.
|
|
591
757
|
*
|
|
@@ -636,6 +802,71 @@ async function openOne(repo, command, extra, request, allowed, blockFor) {
|
|
|
636
802
|
return { error: reason.slice(0, 300) || 'the command failed' };
|
|
637
803
|
}
|
|
638
804
|
}
|
|
805
|
+
if (request.kind === 'push') {
|
|
806
|
+
const resolved = await resolvePushTarget(request, { repo, command, extra, allowed, blockFor });
|
|
807
|
+
if (resolved.error !== undefined || resolved.target === undefined) {
|
|
808
|
+
return { error: resolved.error ?? 'could not resolve the push target' };
|
|
809
|
+
}
|
|
810
|
+
const { url, credentials, cleanEnv } = resolved.target;
|
|
811
|
+
const host = request.host ?? 'github.com';
|
|
812
|
+
let scratch;
|
|
813
|
+
try {
|
|
814
|
+
scratch = mkdtempSync(join(tmpdir(), 'gcb-push-'));
|
|
815
|
+
let objectFormat = 'sha1';
|
|
816
|
+
try {
|
|
817
|
+
const { stdout } = await run('git', ['rev-parse', '--show-object-format'], {
|
|
818
|
+
cwd: repo,
|
|
819
|
+
timeout: CREATE_TIMEOUT_MS,
|
|
820
|
+
maxBuffer: 1 << 20,
|
|
821
|
+
env: withoutGitLocation(process.env),
|
|
822
|
+
});
|
|
823
|
+
const detected = stdout.trim();
|
|
824
|
+
if (detected !== '') {
|
|
825
|
+
objectFormat = detected;
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
catch {
|
|
829
|
+
// Git before 2.29 cannot report or create a SHA-256 repository.
|
|
830
|
+
}
|
|
831
|
+
await run('git', ['init', '--bare', '--quiet', scratch], {
|
|
832
|
+
timeout: CREATE_TIMEOUT_MS,
|
|
833
|
+
maxBuffer: 1 << 20,
|
|
834
|
+
env: { ...cleanEnv, GIT_DEFAULT_HASH: objectFormat },
|
|
835
|
+
});
|
|
836
|
+
const { stdout: objects } = await run('git', ['rev-parse', '--git-path', 'objects'], {
|
|
837
|
+
cwd: repo,
|
|
838
|
+
timeout: CREATE_TIMEOUT_MS,
|
|
839
|
+
maxBuffer: 1 << 20,
|
|
840
|
+
env: withoutGitLocation(process.env),
|
|
841
|
+
});
|
|
842
|
+
mkdirSync(join(scratch, 'objects', 'info'), { recursive: true });
|
|
843
|
+
writeFileSync(join(scratch, 'objects', 'info', 'alternates'), `${resolve(repo, objects.trim())}\n`);
|
|
844
|
+
const { stdout, stderr } = await run('git', [
|
|
845
|
+
'--git-dir',
|
|
846
|
+
scratch,
|
|
847
|
+
...credentials,
|
|
848
|
+
'push',
|
|
849
|
+
...(request.forceWithLease === true
|
|
850
|
+
? [`--force-with-lease=refs/heads/${request.branch}:${request.expected}`]
|
|
851
|
+
: []),
|
|
852
|
+
...(request.force === true ? ['--force'] : []),
|
|
853
|
+
'--no-verify',
|
|
854
|
+
url,
|
|
855
|
+
`${request.commit}:refs/heads/${request.branch}`,
|
|
856
|
+
], { cwd: scratch, timeout: PUSH_TIMEOUT_MS, maxBuffer: 1 << 20, env: cleanEnv });
|
|
857
|
+
return { url: `https://${host}/${request.repo}/tree/${request.branch}`, stdout, stderr };
|
|
858
|
+
}
|
|
859
|
+
catch (error) {
|
|
860
|
+
const failure = error;
|
|
861
|
+
const reason = (failure.stderr ?? failure.message ?? '').trim().slice(0, 300);
|
|
862
|
+
return { error: reason || 'git push failed' };
|
|
863
|
+
}
|
|
864
|
+
finally {
|
|
865
|
+
if (scratch !== undefined) {
|
|
866
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
}
|
|
639
870
|
if (request.kind === 'action') {
|
|
640
871
|
const host = request.host ?? 'github.com';
|
|
641
872
|
let action;
|