fix(fs): keep list paths in requested space through symlinks
Closes openchamber/openchamber#2627 Listing a directory through a workspace symlink was returning realpath entry paths. The file tree then rejected nested expand toggles because those paths fall outside the workspace root. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
co-authored by
Serhii Dziupin
parent
22766fe0ac
commit
ee57088dfe
@@ -29,6 +29,20 @@ describe('useFilesViewTabsStore', () => {
|
|||||||
expect(useFilesViewTabsStore.getState().byRoot[root]?.expandedPaths).toEqual(['/repo/src']);
|
expect(useFilesViewTabsStore.getState().byRoot[root]?.expandedPaths).toEqual(['/repo/src']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('rejects realpath children of workspace symlinks (issue 2627)', () => {
|
||||||
|
const root = '/workspace';
|
||||||
|
const store = useFilesViewTabsStore.getState();
|
||||||
|
|
||||||
|
store.toggleExpandedPath(root, '/workspace/pkg');
|
||||||
|
store.toggleExpandedPath(root, '/real/pkg/src');
|
||||||
|
store.toggleExpandedPath(root, '/workspace/pkg/src');
|
||||||
|
|
||||||
|
expect(useFilesViewTabsStore.getState().byRoot[root]?.expandedPaths).toEqual([
|
||||||
|
'/workspace/pkg',
|
||||||
|
'/workspace/pkg/src',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
test('removes stale expanded paths by prefix without closing files', () => {
|
test('removes stale expanded paths by prefix without closing files', () => {
|
||||||
const root = '/repo';
|
const root = '/repo';
|
||||||
const store = useFilesViewTabsStore.getState();
|
const store = useFilesViewTabsStore.getState();
|
||||||
|
|||||||
@@ -35,3 +35,4 @@ Own filesystem API behavior for the web server runtime, including workspace-boun
|
|||||||
## Notes for contributors
|
## Notes for contributors
|
||||||
- Keep filesystem policy (workspace root checks, error mapping, exec timeout behavior) inside this module, not in the composition root.
|
- Keep filesystem policy (workspace root checks, error mapping, exec timeout behavior) inside this module, not in the composition root.
|
||||||
- If adding new `/api/fs/*` endpoints, add them in `routes.js` and extend this document.
|
- If adding new `/api/fs/*` endpoints, add them in `routes.js` and extend this document.
|
||||||
|
- `GET /api/fs/list` may resolve symlinks with `realpath` to read directory contents, but the response `path` and each entry `path` must stay in the caller's requested path space (`path.join(requestedPath, name)`). Returning real paths breaks file-tree expansion for directories reached through workspace symlinks.
|
||||||
|
|||||||
@@ -454,7 +454,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|||||||
// Non-cacheable commands always execute and are never stored.
|
// Non-cacheable commands always execute and are never stored.
|
||||||
const runCommandWithGitReadCache = async ({ shell, shellFlag, command, resolvedCwd }) => {
|
const runCommandWithGitReadCache = async ({ shell, shellFlag, command, resolvedCwd }) => {
|
||||||
const cacheable = gitReadCacheTtlMs > 0 && isCacheableGitReadCommand(command);
|
const cacheable = gitReadCacheTtlMs > 0 && isCacheableGitReadCommand(command);
|
||||||
const cacheKey = cacheable ? `${resolvedCwd} | |||||||