Skip to content

Commit cc70220

Browse files
authored
feat: create the spawnOptions plugin to allow setting uid / gid owner for the spawned git child processes.
2 parents 8603971 + 116374d commit cc70220

File tree

11 files changed

+80
-3
lines changed

11 files changed

+80
-3
lines changed

docs/PLUGIN-SPAWN-OPTIONS.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
## Process Owner User / Group
2+
3+
To set the user identity or group identity of the spawned git commands to something other than the owner of
4+
the current Node process, supply a `spawnOptions` option with a `uid`, a `gid`, or both:
5+
6+
```typescript
7+
const git: SimpleGit = simpleGit('/some/path', { spawnOptions: { gid: 20 } });
8+
9+
// any command executed will belong to system group 20
10+
await git.pull();
11+
```
12+
13+
```typescript
14+
const git: SimpleGit = simpleGit('/some/path', { spawnOptions: { uid: 1000 } });
15+
16+
// any command executed will belong to system user 1000
17+
await git.pull();
18+
```

readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ await git.pull();
8585
- [Progress Events](./docs/PLUGIN-PROGRESS-EVENTS.md)
8686
Receive progress events as `git` works through long-running processes.
8787

88+
- [Spawned Process Ownership](./docs/PLUGIN-SPAWN-OPTIONS.md)
89+
Configure the system `uid` / `gid` to use for spawned `git` processes.
90+
8891
- [Timeout](./docs/PLUGIN-TIMEOUT.md)
8992
Automatically kill the wrapped `git` process after a rolling timeout.
9093

src/lib/git-factory.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
errorDetectionPlugin,
88
PluginStore,
99
progressMonitorPlugin,
10+
spawnOptionsPlugin,
1011
timeoutPlugin
1112
} from './plugins';
1213
import { createInstanceConfig, folderExists } from './utils';
@@ -53,6 +54,7 @@ export function gitInstanceFactory(baseDir?: string | Partial<SimpleGitOptions>,
5354

5455
config.progress && plugins.add(progressMonitorPlugin(config.progress));
5556
config.timeout && plugins.add(timeoutPlugin(config.timeout));
57+
config.spawnOptions && plugins.add(spawnOptionsPlugin(config.spawnOptions));
5658

5759
plugins.add(errorDetectionPlugin(errorDetectionHandler(true)));
5860
config.errors && plugins.add(errorDetectionPlugin(config.errors));

src/lib/plugins/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ export * from './error-detection.plugin';
33
export * from './plugin-store';
44
export * from './progress-monitor-plugin';
55
export * from './simple-git-plugin';
6+
export * from './spawn-options-plugin';
67
export * from './timout-plugin';

src/lib/plugins/simple-git-plugin.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ChildProcess } from 'child_process';
1+
import { ChildProcess, SpawnOptions } from 'child_process';
22
import { GitExecutorResult } from '../types';
33

44
type SimpleGitTaskPluginContext = {
@@ -11,6 +11,10 @@ export interface SimpleGitPluginTypes {
1111
data: string[];
1212
context: SimpleGitTaskPluginContext & {};
1313
};
14+
'spawn.options': {
15+
data: Partial<SpawnOptions>;
16+
context: SimpleGitTaskPluginContext & {};
17+
};
1418
'spawn.after': {
1519
data: void;
1620
context: SimpleGitTaskPluginContext & {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { SpawnOptions } from 'child_process';
2+
import { pick } from '../utils';
3+
import { SimpleGitPlugin } from './simple-git-plugin';
4+
5+
export function spawnOptionsPlugin(spawnOptions: Partial<SpawnOptions>): SimpleGitPlugin<'spawn.options'> {
6+
const options = pick(spawnOptions, ['uid', 'gid']);
7+
8+
return {
9+
type: 'spawn.options',
10+
action(data) {
11+
return {...options, ...data};
12+
},
13+
};
14+
}

src/lib/runners/git-executor-chain.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,11 @@ export class GitExecutorChain implements SimpleGitExecutor {
150150

151151
private async gitResponse<R>(task: SimpleGitTask<R>, command: string, args: string[], outputHandler: Maybe<outputHandler>, logger: OutputLogger): Promise<GitExecutorResult> {
152152
const outputLogger = logger.sibling('output');
153-
const spawnOptions: SpawnOptions = {
153+
const spawnOptions: SpawnOptions = this._plugins.exec('spawn.options', {
154154
cwd: this.cwd,
155155
env: this.env,
156156
windowsHide: true,
157-
};
157+
}, pluginContext(task, task.commands));
158158

159159
return new Promise((done) => {
160160
const stdOut: Buffer[] = [];

src/lib/types/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SpawnOptions } from 'child_process';
2+
13
import { SimpleGitTask } from './tasks';
24
import { SimpleGitProgressEvent } from './handlers';
35

@@ -85,6 +87,8 @@ export interface SimpleGitPluginConfig {
8587
*/
8688
block: number;
8789
};
90+
91+
spawnOptions: Pick<SpawnOptions, 'uid' | 'gid'>;
8892
}
8993

9094
/**

src/lib/utils/util.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,10 @@ export function prefixedArray<T>(input: T[], prefix: T): T[] {
141141
export function bufferToString (input: Buffer | Buffer[]): string {
142142
return (Array.isArray(input) ? Buffer.concat(input) : input).toString('utf-8');
143143
}
144+
145+
/**
146+
* Get a new object from a source object with only the listed properties.
147+
*/
148+
export function pick (source: Record<string, any>, properties: string[]) {
149+
return Object.assign({}, ...properties.map((property) => property in source ? {[property]: source[property]} : {}));
150+
}

test/unit/__fixtures__/expectations.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,7 @@ export function assertChildProcessEnvironmentVariables(env: any) {
3535
expect(mockChildProcessModule.$mostRecent()).toHaveProperty('$env', env);
3636
}
3737

38+
export function assertChildProcessSpawnOptions(options: any) {
39+
expect(mockChildProcessModule.$mostRecent().$options).toMatchObject(options);
40+
}
41+

0 commit comments

Comments
 (0)