mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-15 15:50:35 -07:00
feat(cli): implement atomic writes and safety checks for trusted folders (#18406)
This commit is contained in:
@@ -149,7 +149,9 @@ describe('useFolderTrust', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_FOLDER);
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.TRUST_FOLDER,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -173,7 +175,9 @@ describe('useFolderTrust', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_PARENT);
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.TRUST_PARENT,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -197,7 +201,9 @@ describe('useFolderTrust', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.DO_NOT_TRUST);
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.DO_NOT_TRUST,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -221,7 +227,7 @@ describe('useFolderTrust', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(
|
||||
await result.current.handleFolderTrustSelect(
|
||||
'invalid_choice' as FolderTrustChoice,
|
||||
);
|
||||
});
|
||||
@@ -253,7 +259,9 @@ describe('useFolderTrust', () => {
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_FOLDER);
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.TRUST_FOLDER,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -272,7 +280,9 @@ describe('useFolderTrust', () => {
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_FOLDER);
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.TRUST_FOLDER,
|
||||
);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
@@ -294,8 +304,10 @@ describe('useFolderTrust', () => {
|
||||
useFolderTrust(mockSettings, onTrustChange, addItem),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.handleFolderTrustSelect(FolderTrustChoice.TRUST_FOLDER);
|
||||
await act(async () => {
|
||||
await result.current.handleFolderTrustSelect(
|
||||
FolderTrustChoice.TRUST_FOLDER,
|
||||
);
|
||||
});
|
||||
|
||||
await vi.runAllTimersAsync();
|
||||
|
||||
@@ -48,7 +48,7 @@ export const useFolderTrust = (
|
||||
}, [folderTrust, onTrustChange, settings.merged, addItem]);
|
||||
|
||||
const handleFolderTrustSelect = useCallback(
|
||||
(choice: FolderTrustChoice) => {
|
||||
async (choice: FolderTrustChoice) => {
|
||||
const trustLevelMap: Record<FolderTrustChoice, TrustLevel> = {
|
||||
[FolderTrustChoice.TRUST_FOLDER]: TrustLevel.TRUST_FOLDER,
|
||||
[FolderTrustChoice.TRUST_PARENT]: TrustLevel.TRUST_PARENT,
|
||||
@@ -62,7 +62,7 @@ export const useFolderTrust = (
|
||||
const trustedFolders = loadTrustedFolders();
|
||||
|
||||
try {
|
||||
trustedFolders.setValue(cwd, trustLevel);
|
||||
await trustedFolders.setValue(cwd, trustLevel);
|
||||
} catch (_e) {
|
||||
coreEvents.emitFeedback(
|
||||
'error',
|
||||
|
||||
@@ -142,7 +142,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
expect(result.current.isInheritedTrustFromParent).toBe(false);
|
||||
});
|
||||
|
||||
it('should set needsRestart but not save when trust changes', () => {
|
||||
it('should set needsRestart but not save when trust changes', async () => {
|
||||
const mockSetValue = vi.fn();
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
@@ -157,15 +157,15 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
});
|
||||
|
||||
expect(result.current.needsRestart).toBe(true);
|
||||
expect(mockSetValue).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should save immediately if trust does not change', () => {
|
||||
it('should save immediately if trust does not change', async () => {
|
||||
const mockSetValue = vi.fn();
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
@@ -181,8 +181,8 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
|
||||
});
|
||||
|
||||
expect(result.current.needsRestart).toBe(false);
|
||||
@@ -193,7 +193,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
expect(mockOnExit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should commit the pending trust level change', () => {
|
||||
it('should commit the pending trust level change', async () => {
|
||||
const mockSetValue = vi.fn();
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
@@ -208,14 +208,14 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
});
|
||||
|
||||
expect(result.current.needsRestart).toBe(true);
|
||||
|
||||
act(() => {
|
||||
result.current.commitTrustLevelChange();
|
||||
await act(async () => {
|
||||
await result.current.commitTrustLevelChange();
|
||||
});
|
||||
|
||||
expect(mockSetValue).toHaveBeenCalledWith(
|
||||
@@ -224,7 +224,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should add warning when setting DO_NOT_TRUST but still trusted by parent', () => {
|
||||
it('should add warning when setting DO_NOT_TRUST but still trusted by parent', async () => {
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
setValue: vi.fn(),
|
||||
@@ -238,8 +238,8 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
});
|
||||
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
@@ -251,7 +251,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
);
|
||||
});
|
||||
|
||||
it('should add warning when setting DO_NOT_TRUST but still trusted by IDE', () => {
|
||||
it('should add warning when setting DO_NOT_TRUST but still trusted by IDE', async () => {
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
setValue: vi.fn(),
|
||||
@@ -265,8 +265,8 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
});
|
||||
|
||||
expect(mockAddItem).toHaveBeenCalledWith(
|
||||
@@ -299,7 +299,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
expect(result.current.isInheritedTrustFromIde).toBe(false);
|
||||
});
|
||||
|
||||
it('should save immediately without needing a restart', () => {
|
||||
it('should save immediately without needing a restart', async () => {
|
||||
const mockSetValue = vi.fn();
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
@@ -314,8 +314,8 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, otherDirectory),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
});
|
||||
|
||||
expect(result.current.needsRestart).toBe(false);
|
||||
@@ -326,7 +326,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
expect(mockOnExit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should not add a warning when setting DO_NOT_TRUST', () => {
|
||||
it('should not add a warning when setting DO_NOT_TRUST', async () => {
|
||||
mockedLoadTrustedFolders.mockReturnValue({
|
||||
user: { config: {} },
|
||||
setValue: vi.fn(),
|
||||
@@ -340,15 +340,15 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, otherDirectory),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.DO_NOT_TRUST);
|
||||
});
|
||||
|
||||
expect(mockAddItem).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit feedback when setValue throws in updateTrustLevel', () => {
|
||||
it('should emit feedback when setValue throws in updateTrustLevel', async () => {
|
||||
const mockSetValue = vi.fn().mockImplementation(() => {
|
||||
throw new Error('test error');
|
||||
});
|
||||
@@ -368,8 +368,8 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_PARENT);
|
||||
});
|
||||
|
||||
expect(emitFeedbackSpy).toHaveBeenCalledWith(
|
||||
@@ -379,7 +379,7 @@ describe('usePermissionsModifyTrust', () => {
|
||||
expect(mockOnExit).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should emit feedback when setValue throws in commitTrustLevelChange', () => {
|
||||
it('should emit feedback when setValue throws in commitTrustLevelChange', async () => {
|
||||
const mockSetValue = vi.fn().mockImplementation(() => {
|
||||
throw new Error('test error');
|
||||
});
|
||||
@@ -398,12 +398,12 @@ describe('usePermissionsModifyTrust', () => {
|
||||
usePermissionsModifyTrust(mockOnExit, mockAddItem, mockedCwd()),
|
||||
);
|
||||
|
||||
act(() => {
|
||||
result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
await act(async () => {
|
||||
await result.current.updateTrustLevel(TrustLevel.TRUST_FOLDER);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
const success = result.current.commitTrustLevelChange();
|
||||
await act(async () => {
|
||||
const success = await result.current.commitTrustLevelChange();
|
||||
expect(success).toBe(false);
|
||||
});
|
||||
|
||||
|
||||
@@ -92,12 +92,12 @@ export const usePermissionsModifyTrust = (
|
||||
settings.merged.security.folderTrust.enabled ?? true;
|
||||
|
||||
const updateTrustLevel = useCallback(
|
||||
(trustLevel: TrustLevel) => {
|
||||
async (trustLevel: TrustLevel) => {
|
||||
// If we are not editing the current workspace, the logic is simple:
|
||||
// just save the setting and exit. No restart or warnings are needed.
|
||||
if (!isCurrentWorkspace) {
|
||||
const folders = loadTrustedFolders();
|
||||
folders.setValue(cwd, trustLevel);
|
||||
await folders.setValue(cwd, trustLevel);
|
||||
onExit();
|
||||
return;
|
||||
}
|
||||
@@ -140,7 +140,7 @@ export const usePermissionsModifyTrust = (
|
||||
} else {
|
||||
const folders = loadTrustedFolders();
|
||||
try {
|
||||
folders.setValue(cwd, trustLevel);
|
||||
await folders.setValue(cwd, trustLevel);
|
||||
} catch (_e) {
|
||||
coreEvents.emitFeedback(
|
||||
'error',
|
||||
@@ -153,11 +153,11 @@ export const usePermissionsModifyTrust = (
|
||||
[cwd, settings.merged, onExit, addItem, isCurrentWorkspace],
|
||||
);
|
||||
|
||||
const commitTrustLevelChange = useCallback(() => {
|
||||
const commitTrustLevelChange = useCallback(async () => {
|
||||
if (pendingTrustLevel) {
|
||||
const folders = loadTrustedFolders();
|
||||
try {
|
||||
folders.setValue(cwd, pendingTrustLevel);
|
||||
await folders.setValue(cwd, pendingTrustLevel);
|
||||
return true;
|
||||
} catch (_e) {
|
||||
coreEvents.emitFeedback(
|
||||
|
||||
Reference in New Issue
Block a user