Skip to content

Commit dea160a

Browse files
CR feedback
Co-Authored-By: SteveSandersonMS <[email protected]>
1 parent d16fa87 commit dea160a

File tree

3 files changed

+46
-33
lines changed

3 files changed

+46
-33
lines changed

dotnet/test/SessionFsTests.cs

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,7 @@ public async Task Should_Reject_SetProvider_When_Sessions_Already_Exist()
121121
}
122122
finally
123123
{
124-
try
125-
{
126-
await client2.ForceStopAsync();
127-
}
128-
catch
129-
{
130-
}
124+
await client2.ForceStopAsync();
131125
}
132126
}
133127
finally
@@ -255,15 +249,18 @@ private CopilotClient CreateSessionFsClient(string providerRoot, bool useStdio =
255249
}
256250

257251
private static string CreateProviderRoot()
258-
=> Path.Combine(Path.GetTempPath(), $"copilot-sessionfs-{Guid.NewGuid():N}");
252+
=> Path.Join(Path.GetTempPath(), $"copilot-sessionfs-{Guid.NewGuid():N}");
259253

260254
private static string GetStoredPath(string providerRoot, string sessionId, string sessionPath)
261255
{
256+
var safeSessionId = NormalizeRelativePathSegment(sessionId, nameof(sessionId));
262257
var relativeSegments = sessionPath
263258
.TrimStart('/', '\\')
264-
.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries);
259+
.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries)
260+
.Select(segment => NormalizeRelativePathSegment(segment, nameof(sessionPath)))
261+
.ToArray();
265262

266-
return Path.Combine([providerRoot, sessionId, .. relativeSegments]);
263+
return Path.Join([providerRoot, safeSessionId, .. relativeSegments]);
267264
}
268265

269266
private static async Task WaitForConditionAsync(Func<bool> condition, TimeSpan? timeout = null)
@@ -274,6 +271,7 @@ private static async Task WaitForConditionAsync(Func<bool> condition, TimeSpan?
274271
private static async Task WaitForConditionAsync(Func<Task<bool>> condition, TimeSpan? timeout = null)
275272
{
276273
var deadline = DateTime.UtcNow + (timeout ?? TimeSpan.FromSeconds(30));
274+
Exception? lastException = null;
277275
while (DateTime.UtcNow < deadline)
278276
{
279277
try
@@ -283,17 +281,19 @@ private static async Task WaitForConditionAsync(Func<Task<bool>> condition, Time
283281
return;
284282
}
285283
}
286-
catch (IOException)
284+
catch (IOException ex)
287285
{
286+
lastException = ex;
288287
}
289-
catch (UnauthorizedAccessException)
288+
catch (UnauthorizedAccessException ex)
290289
{
290+
lastException = ex;
291291
}
292292

293293
await Task.Delay(100);
294294
}
295295

296-
throw new TimeoutException("Timed out waiting for condition.");
296+
throw new TimeoutException("Timed out waiting for condition.", lastException);
297297
}
298298

299299
private static async Task<string> ReadAllTextSharedAsync(string path, CancellationToken cancellationToken = default)
@@ -305,16 +305,26 @@ private static async Task<string> ReadAllTextSharedAsync(string path, Cancellati
305305

306306
private static void TryDeleteDirectory(string path)
307307
{
308-
try
308+
if (Directory.Exists(path))
309309
{
310-
if (Directory.Exists(path))
311-
{
312-
Directory.Delete(path, recursive: true);
313-
}
310+
Directory.Delete(path, recursive: true);
314311
}
315-
catch
312+
}
313+
314+
private static string NormalizeRelativePathSegment(string segment, string paramName)
315+
{
316+
if (string.IsNullOrWhiteSpace(segment))
316317
{
318+
throw new InvalidOperationException($"{paramName} must not be empty.");
317319
}
320+
321+
var normalized = segment.TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
322+
if (Path.IsPathRooted(normalized) || normalized.Contains(Path.VolumeSeparatorChar))
323+
{
324+
throw new InvalidOperationException($"{paramName} must be a relative path segment: {segment}");
325+
}
326+
327+
return normalized;
318328
}
319329

320330
private sealed class TestSessionFsHandler(string sessionId, string rootDir) : ISessionFsHandler
@@ -456,12 +466,15 @@ public Task RenameAsync(SessionFsRenameParams request, CancellationToken cancell
456466

457467
private string ResolvePath(string sessionPath)
458468
{
459-
var sessionRoot = Path.GetFullPath(Path.Combine(rootDir, sessionId));
469+
var normalizedSessionId = NormalizeRelativePathSegment(sessionId, nameof(sessionId));
470+
var sessionRoot = Path.GetFullPath(Path.Join(rootDir, normalizedSessionId));
460471
var relativeSegments = sessionPath
461472
.TrimStart('/', '\\')
462-
.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries);
473+
.Split(['/', '\\'], StringSplitOptions.RemoveEmptyEntries)
474+
.Select(segment => NormalizeRelativePathSegment(segment, nameof(sessionPath)))
475+
.ToArray();
463476

464-
var fullPath = Path.GetFullPath(Path.Combine([sessionRoot, .. relativeSegments]));
477+
var fullPath = Path.GetFullPath(Path.Join([sessionRoot, .. relativeSegments]));
465478
if (!fullPath.StartsWith(sessionRoot, StringComparison.Ordinal))
466479
{
467480
throw new InvalidOperationException($"Path escapes session root: {sessionPath}");

python/copilot/generated/rpc.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4068,25 +4068,25 @@ async def log(self, params: SessionLogParams, *, timeout: float | None = None) -
40684068

40694069
class SessionFsHandler(Protocol):
40704070
async def read_file(self, params: SessionFSReadFileParams) -> SessionFSReadFileResult:
4071-
...
4071+
pass
40724072
async def write_file(self, params: SessionFSWriteFileParams) -> None:
4073-
...
4073+
pass
40744074
async def append_file(self, params: SessionFSAppendFileParams) -> None:
4075-
...
4075+
pass
40764076
async def exists(self, params: SessionFSExistsParams) -> SessionFSExistsResult:
4077-
...
4077+
pass
40784078
async def stat(self, params: SessionFSStatParams) -> SessionFSStatResult:
4079-
...
4079+
pass
40804080
async def mkdir(self, params: SessionFSMkdirParams) -> None:
4081-
...
4081+
pass
40824082
async def readdir(self, params: SessionFSReaddirParams) -> SessionFSReaddirResult:
4083-
...
4083+
pass
40844084
async def readdir_with_types(self, params: SessionFSReaddirWithTypesParams) -> SessionFSReaddirWithTypesResult:
4085-
...
4085+
pass
40864086
async def rm(self, params: SessionFSRmParams) -> None:
4087-
...
4087+
pass
40884088
async def rename(self, params: SessionFSRenameParams) -> None:
4089-
...
4089+
pass
40904090

40914091
@dataclass
40924092
class ClientSessionApiHandlers:

scripts/codegen/python.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,7 +509,7 @@ function emitClientSessionHandlerMethod(
509509
if (method.stability === "experimental" && !groupExperimental) {
510510
lines.push(` """.. warning:: This API is experimental and may change or be removed in future versions."""`);
511511
}
512-
lines.push(` ...`);
512+
lines.push(` pass`);
513513
}
514514

515515
function emitClientSessionRegistrationMethod(

0 commit comments

Comments
 (0)