Skip to content

Commit 27e9922

Browse files
authored
Fix: prevent Git from showing a password prompt (#3633)
**Summary** Fixes #764. Turns out when fetching packages from remote sources via Git, it may ask for a username or password and get stuck there since we run it in the background. This patch passes the following env variables to disable any prompts: 1. `$GIT_ASKPASS=""` This is the command Git runs to get username and pass. Setting it to an empty string disables it and git exits with an error. 2. `$GIT_TERMINAL_PROMPT=0` This is new in Git 2.3 and it prevents git from even trying to ask for a password. Surpasses `$GIT_ASKPASS` above. 3. `$GIT_SSH_COMMAND="ssh -oBatchMode=yes"` This is also new in Git 2.3 and it makes git make the call to ssh via this command. `BatchMode=yes` option tells ssh to not do anything interactive (because batch/script mode) like password prompts in case publickey auth fails etc. **Test plan** Do `yarn add git+https://github.com/Napsty/privrepo.git#1.0.2`. `yarn` hangs before this patch and fails with a "Refusing to download" error after the patch.
1 parent 0361edf commit 27e9922

File tree

1 file changed

+18
-11
lines changed

1 file changed

+18
-11
lines changed

src/util/git.js

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ const supportsArchiveCache: {[key: string]: boolean} = map({
3131
'github.com': false, // not support, doubt they will ever support it
3232
});
3333

34+
// Suppress any password prompts since we run these in the background
35+
const env = {GIT_ASKPASS: '', GIT_TERMINAL_PROMPT: 0, GIT_SSH_COMMAND: 'ssh -oBatchMode=yes'};
36+
3437
// This regex is designed to match output from git of the style:
3538
// ebeb6eafceb61dd08441ffe086c77eb472842494 refs/tags/v0.21.0
3639
// and extract the hash and tag name as capture groups
@@ -87,6 +90,10 @@ export default class Git {
8790
};
8891
}
8992

93+
static spawn(args: Array<string>, opts?: child_process$spawnOpts = {}): Promise<string> {
94+
return child.spawn('git', args, {...opts, env});
95+
}
96+
9097
/**
9198
* Check if the host specified in the input `gitUrl` has archive capability.
9299
*/
@@ -102,7 +109,7 @@ export default class Git {
102109
}
103110

104111
try {
105-
await child.spawn('git', ['archive', `--remote=${ref.repository}`, 'HEAD', Date.now() + '']);
112+
await Git.spawn(['archive', `--remote=${ref.repository}`, 'HEAD', Date.now() + '']);
106113
throw new Error();
107114
} catch (err) {
108115
const supports = err.message.indexOf('did not match any files') >= 0;
@@ -120,7 +127,7 @@ export default class Git {
120127

121128
static async repoExists(ref: GitUrl): Promise<boolean> {
122129
try {
123-
await child.spawn('git', ['ls-remote', '-t', ref.repository]);
130+
await Git.spawn(['ls-remote', '-t', ref.repository]);
124131
return true;
125132
} catch (err) {
126133
return false;
@@ -191,7 +198,7 @@ export default class Git {
191198

192199
async _archiveViaRemoteArchive(dest: string): Promise<string> {
193200
const hashStream = new crypto.HashStream();
194-
await child.spawn('git', ['archive', `--remote=${this.gitUrl.repository}`, this.ref], {
201+
await Git.spawn(['archive', `--remote=${this.gitUrl.repository}`, this.ref], {
195202
process(proc, resolve, reject, done) {
196203
const writeStream = createWriteStream(dest);
197204
proc.on('error', reject);
@@ -208,7 +215,7 @@ export default class Git {
208215

209216
async _archiveViaLocalFetched(dest: string): Promise<string> {
210217
const hashStream = new crypto.HashStream();
211-
await child.spawn('git', ['archive', this.hash], {
218+
await Git.spawn(['archive', this.hash], {
212219
cwd: this.cwd,
213220
process(proc, resolve, reject, done) {
214221
const writeStream = createWriteStream(dest);
@@ -237,7 +244,7 @@ export default class Git {
237244
}
238245

239246
async _cloneViaRemoteArchive(dest: string): Promise<void> {
240-
await child.spawn('git', ['archive', `--remote=${this.gitUrl.repository}`, this.ref], {
247+
await Git.spawn(['archive', `--remote=${this.gitUrl.repository}`, this.ref], {
241248
process(proc, update, reject, done) {
242249
const extractor = tarFs.extract(dest, {
243250
dmode: 0o555, // all dirs should be readable
@@ -253,7 +260,7 @@ export default class Git {
253260
}
254261

255262
async _cloneViaLocalFetched(dest: string): Promise<void> {
256-
await child.spawn('git', ['archive', this.hash], {
263+
await Git.spawn(['archive', this.hash], {
257264
cwd: this.cwd,
258265
process(proc, resolve, reject, done) {
259266
const extractor = tarFs.extract(dest, {
@@ -278,9 +285,9 @@ export default class Git {
278285

279286
return fs.lockQueue.push(gitUrl.repository, async () => {
280287
if (await fs.exists(cwd)) {
281-
await child.spawn('git', ['pull'], {cwd});
288+
await Git.spawn(['pull'], {cwd});
282289
} else {
283-
await child.spawn('git', ['clone', gitUrl.repository, cwd]);
290+
await Git.spawn(['clone', gitUrl.repository, cwd]);
284291
}
285292

286293
this.fetched = true;
@@ -320,7 +327,7 @@ export default class Git {
320327

321328
async _getFileFromArchive(filename: string): Promise<string | false> {
322329
try {
323-
return await child.spawn('git', ['archive', `--remote=${this.gitUrl.repository}`, this.ref, filename], {
330+
return await Git.spawn(['archive', `--remote=${this.gitUrl.repository}`, this.ref, filename], {
324331
process(proc, update, reject, done) {
325332
const parser = tarStream.extract();
326333

@@ -359,7 +366,7 @@ export default class Git {
359366
invariant(this.fetched, 'Repo not fetched');
360367

361368
try {
362-
return await child.spawn('git', ['show', `${this.hash}:${filename}`], {
369+
return await Git.spawn(['show', `${this.hash}:${filename}`], {
363370
cwd: this.cwd,
364371
});
365372
} catch (err) {
@@ -385,7 +392,7 @@ export default class Git {
385392
}
386393

387394
async setRefRemote(): Promise<string> {
388-
const stdout = await child.spawn('git', ['ls-remote', '--tags', '--heads', this.gitUrl.repository]);
395+
const stdout = await Git.spawn(['ls-remote', '--tags', '--heads', this.gitUrl.repository]);
389396
const refs = Git.parseRefs(stdout);
390397
return this.setRef(refs);
391398
}

0 commit comments

Comments
 (0)