feat(cli): minimalist sandbox status labels (#24582)

This commit is contained in:
Gal Zahavi
2026-04-02 22:22:21 -07:00
committed by GitHub
parent 7de3e4dcf9
commit e54eecca51
2 changed files with 31 additions and 20 deletions
+23 -4
View File
@@ -81,6 +81,7 @@ const mockConfigPlain = {
isTrustedFolder: () => true, isTrustedFolder: () => true,
getExtensionRegistryURI: () => undefined, getExtensionRegistryURI: () => undefined,
getContentGeneratorConfig: () => ({ authType: undefined }), getContentGeneratorConfig: () => ({ authType: undefined }),
getSandboxEnabled: () => false,
}; };
const mockConfig = mockConfigPlain as unknown as Config; const mockConfig = mockConfigPlain as unknown as Config;
@@ -364,7 +365,7 @@ describe('<Footer />', () => {
unmount(); unmount();
}); });
it('should display custom sandbox info when SANDBOX env is set', async () => { it('should display "current process" for custom sandbox when SANDBOX env is set', async () => {
vi.stubEnv('SANDBOX', 'gemini-cli-test-sandbox'); vi.stubEnv('SANDBOX', 'gemini-cli-test-sandbox');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, { const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
config: mockConfig, config: mockConfig,
@@ -374,12 +375,12 @@ describe('<Footer />', () => {
sessionStats: mockSessionStats, sessionStats: mockSessionStats,
}, },
}); });
expect(lastFrame()).toContain('test'); expect(lastFrame()).toContain('current process');
vi.unstubAllEnvs(); vi.unstubAllEnvs();
unmount(); unmount();
}); });
it('should display macOS Seatbelt info when SANDBOX is sandbox-exec', async () => { it('should display "current process" for macOS Seatbelt when SANDBOX is sandbox-exec', async () => {
vi.stubEnv('SANDBOX', 'sandbox-exec'); vi.stubEnv('SANDBOX', 'sandbox-exec');
vi.stubEnv('SEATBELT_PROFILE', 'test-profile'); vi.stubEnv('SEATBELT_PROFILE', 'test-profile');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, { const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
@@ -387,7 +388,7 @@ describe('<Footer />', () => {
width: 120, width: 120,
uiState: { isTrustedFolder: true, sessionStats: mockSessionStats }, uiState: { isTrustedFolder: true, sessionStats: mockSessionStats },
}); });
expect(lastFrame()).toMatch(/macOS Seatbelt.*\(test-profile\)/s); expect(lastFrame()).toContain('current process');
vi.unstubAllEnvs(); vi.unstubAllEnvs();
unmount(); unmount();
}); });
@@ -405,6 +406,24 @@ describe('<Footer />', () => {
unmount(); unmount();
}); });
it('should display "all tools" when tool sandboxing is enabled and agent is local', async () => {
vi.stubEnv('SANDBOX', '');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
config: Object.assign(
Object.create(Object.getPrototypeOf(mockConfig)),
mockConfig,
{
getSandboxEnabled: () => true,
},
),
width: 120,
uiState: { isTrustedFolder: true, sessionStats: mockSessionStats },
});
expect(lastFrame()).toContain('all tools');
vi.unstubAllEnvs();
unmount();
});
it('should prioritize untrusted message over sandbox info', async () => { it('should prioritize untrusted message over sandbox info', async () => {
vi.stubEnv('SANDBOX', 'gemini-cli-test-sandbox'); vi.stubEnv('SANDBOX', 'gemini-cli-test-sandbox');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, { const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
+8 -16
View File
@@ -67,26 +67,19 @@ interface SandboxIndicatorProps {
const SandboxIndicator: React.FC<SandboxIndicatorProps> = ({ const SandboxIndicator: React.FC<SandboxIndicatorProps> = ({
isTrustedFolder, isTrustedFolder,
}) => { }) => {
const config = useConfig();
const sandboxEnabled = config.getSandboxEnabled();
if (isTrustedFolder === false) { if (isTrustedFolder === false) {
return <Text color={theme.status.warning}>untrusted</Text>; return <Text color={theme.status.warning}>untrusted</Text>;
} }
const sandbox = process.env['SANDBOX']; const sandbox = process.env['SANDBOX'];
if (sandbox && sandbox !== 'sandbox-exec') { if (sandbox) {
return ( return <Text color={theme.status.warning}>current process</Text>;
<Text color="green">{sandbox.replace(/^gemini-(?:cli-)?/, '')}</Text>
);
} }
if (sandbox === 'sandbox-exec') { if (sandboxEnabled) {
return ( return <Text color={theme.status.warning}>all tools</Text>;
<Text color={theme.status.warning}>
macOS Seatbelt{' '}
<Text color={theme.ui.comment}>
({process.env['SEATBELT_PROFILE']})
</Text>
</Text>
);
} }
return <Text color={theme.status.error}>no sandbox</Text>; return <Text color={theme.status.error}>no sandbox</Text>;
@@ -311,9 +304,8 @@ export const Footer: React.FC = () => {
let str = 'no sandbox'; let str = 'no sandbox';
const sandbox = process.env['SANDBOX']; const sandbox = process.env['SANDBOX'];
if (isTrustedFolder === false) str = 'untrusted'; if (isTrustedFolder === false) str = 'untrusted';
else if (sandbox === 'sandbox-exec') else if (sandbox) str = 'current process';
str = `macOS Seatbelt (${process.env['SEATBELT_PROFILE']})`; else if (config.getSandboxEnabled()) str = 'all tools';
else if (sandbox) str = sandbox.replace(/^gemini-(?:cli-)?/, '');
addCol( addCol(
id, id,