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

View File

@@ -81,6 +81,7 @@ const mockConfigPlain = {
isTrustedFolder: () => true,
getExtensionRegistryURI: () => undefined,
getContentGeneratorConfig: () => ({ authType: undefined }),
getSandboxEnabled: () => false,
};
const mockConfig = mockConfigPlain as unknown as Config;
@@ -364,7 +365,7 @@ describe('<Footer />', () => {
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');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
config: mockConfig,
@@ -374,12 +375,12 @@ describe('<Footer />', () => {
sessionStats: mockSessionStats,
},
});
expect(lastFrame()).toContain('test');
expect(lastFrame()).toContain('current process');
vi.unstubAllEnvs();
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('SEATBELT_PROFILE', 'test-profile');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {
@@ -387,7 +388,7 @@ describe('<Footer />', () => {
width: 120,
uiState: { isTrustedFolder: true, sessionStats: mockSessionStats },
});
expect(lastFrame()).toMatch(/macOS Seatbelt.*\(test-profile\)/s);
expect(lastFrame()).toContain('current process');
vi.unstubAllEnvs();
unmount();
});
@@ -405,6 +406,24 @@ describe('<Footer />', () => {
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 () => {
vi.stubEnv('SANDBOX', 'gemini-cli-test-sandbox');
const { lastFrame, unmount } = await renderWithProviders(<Footer />, {

View File

@@ -67,26 +67,19 @@ interface SandboxIndicatorProps {
const SandboxIndicator: React.FC<SandboxIndicatorProps> = ({
isTrustedFolder,
}) => {
const config = useConfig();
const sandboxEnabled = config.getSandboxEnabled();
if (isTrustedFolder === false) {
return <Text color={theme.status.warning}>untrusted</Text>;
}
const sandbox = process.env['SANDBOX'];
if (sandbox && sandbox !== 'sandbox-exec') {
return (
<Text color="green">{sandbox.replace(/^gemini-(?:cli-)?/, '')}</Text>
);
if (sandbox) {
return <Text color={theme.status.warning}>current process</Text>;
}
if (sandbox === 'sandbox-exec') {
return (
<Text color={theme.status.warning}>
macOS Seatbelt{' '}
<Text color={theme.ui.comment}>
({process.env['SEATBELT_PROFILE']})
</Text>
</Text>
);
if (sandboxEnabled) {
return <Text color={theme.status.warning}>all tools</Text>;
}
return <Text color={theme.status.error}>no sandbox</Text>;
@@ -311,9 +304,8 @@ export const Footer: React.FC = () => {
let str = 'no sandbox';
const sandbox = process.env['SANDBOX'];
if (isTrustedFolder === false) str = 'untrusted';
else if (sandbox === 'sandbox-exec')
str = `macOS Seatbelt (${process.env['SEATBELT_PROFILE']})`;
else if (sandbox) str = sandbox.replace(/^gemini-(?:cli-)?/, '');
else if (sandbox) str = 'current process';
else if (config.getSandboxEnabled()) str = 'all tools';
addCol(
id,