Skip to content

Commit 2f2e2c4

Browse files
authored
fix issue (#22)
Co-authored-by: meganrogge <[email protected]>
1 parent 4437686 commit 2f2e2c4

File tree

4 files changed

+86
-62
lines changed

4 files changed

+86
-62
lines changed

src/vs/platform/terminal/node/terminalEnvironment.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import { IShellLaunchConfig, ITerminalEnvironment, ITerminalProcessOptions } fro
1515
import { EnvironmentVariableMutatorType } from '../common/environmentVariable.js';
1616
import { deserializeEnvironmentVariableCollections } from '../common/environmentVariableShared.js';
1717
import { MergedEnvironmentVariableCollection } from '../common/environmentVariableCollection.js';
18+
import { chmod, realpathSync } from 'fs';
19+
import { promisify } from 'util';
1820

1921
export function getWindowsBuildNumber(): number {
2022
const osVersion = (/(\d+)\.(\d+)\.(\d+)/g).exec(os.release());
@@ -49,13 +51,14 @@ export interface IShellIntegrationConfigInjection {
4951
* that creates the process to ensure accuracy. Returns undefined if shell integration cannot be
5052
* enabled.
5153
*/
52-
export function getShellIntegrationInjection(
54+
export async function getShellIntegrationInjection(
5355
shellLaunchConfig: IShellLaunchConfig,
5456
options: ITerminalProcessOptions,
5557
env: ITerminalEnvironment | undefined,
5658
logService: ILogService,
57-
productService: IProductService
58-
): IShellIntegrationConfigInjection | undefined {
59+
productService: IProductService,
60+
skipStickyBit: boolean = false
61+
): Promise<IShellIntegrationConfigInjection | undefined> {
5962
// Conditionally disable shell integration arg injection
6063
// - The global setting is disabled
6164
// - There is no executable (not sure what script to run)
@@ -212,7 +215,27 @@ export function getShellIntegrationInjection(
212215
} catch {
213216
username = 'unknown';
214217
}
215-
const zdotdir = path.join(os.tmpdir(), `${username}-${productService.applicationName}-zsh`);
218+
219+
// Resolve the actual tmp directory so we can set the sticky bit
220+
const realTmpDir = realpathSync(os.tmpdir());
221+
const zdotdir = path.join(realTmpDir, `${username}-${productService.applicationName}-zsh`);
222+
223+
// Set directory permissions using octal notation:
224+
// - 0o1700:
225+
// - Sticky bit is set, preventing non-owners from deleting or renaming files within this directory (1)
226+
// - Owner has full read (4), write (2), execute (1) permissions
227+
// - Group has no permissions (0)
228+
// - Others have no permissions (0)
229+
if (!skipStickyBit) {
230+
// skip for tests
231+
try {
232+
const chmodAsync = promisify(chmod);
233+
await chmodAsync(zdotdir, 0o1700);
234+
} catch (err) {
235+
logService.error(`Failed to set sticky bit on ${zdotdir}: ${err}`);
236+
return undefined;
237+
}
238+
}
216239
envMixin['ZDOTDIR'] = zdotdir;
217240
const userZdotdir = env?.ZDOTDIR ?? os.homedir() ?? `~`;
218241
envMixin['USER_ZDOTDIR'] = userZdotdir;

src/vs/platform/terminal/node/terminalProcess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
210210

211211
let injection: IShellIntegrationConfigInjection | undefined;
212212
if (this._options.shellIntegration.enabled) {
213-
injection = getShellIntegrationInjection(this.shellLaunchConfig, this._options, this._ptyOptions.env, this._logService, this._productService);
213+
injection = await getShellIntegrationInjection(this.shellLaunchConfig, this._options, this._ptyOptions.env, this._logService, this._productService);
214214
if (injection) {
215215
this._onDidChangeProperty.fire({ type: ProcessPropertyType.UsedShellIntegrationInjection, value: true });
216216
if (injection.envMixin) {

0 commit comments

Comments
 (0)