fix(worker): cap run-log read size and harden run-history tests

- GetTaskLog reads at most last 256 KB; prepends truncation marker if file exceeds cap
- Wrap temp-file cleanup in finally block to prevent leak on assertion failure
- Add GetRun_NotFound_Throws, GetTaskLog_RunExistsButNoLogPath_Throws, and GetTaskLog_LargeFile_ReturnsTruncatedTail tests

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
mika kuns
2026-05-30 14:04:22 +02:00
parent 3afe29d721
commit fec2fe2dda
2 changed files with 77 additions and 3 deletions

View File

@@ -33,6 +33,8 @@ public sealed class RunHistoryMcpTools
return ToDto(run);
}
private const int MaxLogBytes = 256 * 1024;
[McpServerTool, Description("Fetch the raw log output of a task's latest run. Throws if no log is available.")]
public async Task<string> GetTaskLog(string taskId, CancellationToken cancellationToken)
{
@@ -40,7 +42,17 @@ public sealed class RunHistoryMcpTools
?? throw new InvalidOperationException($"No runs found for task {taskId}.");
if (string.IsNullOrWhiteSpace(run.LogPath) || !File.Exists(run.LogPath))
throw new InvalidOperationException("No log available for the latest run.");
return await File.ReadAllTextAsync(run.LogPath, cancellationToken);
var totalBytes = new FileInfo(run.LogPath).Length;
if (totalBytes <= MaxLogBytes)
return await File.ReadAllTextAsync(run.LogPath, cancellationToken);
var buffer = new byte[MaxLogBytes];
await using var fs = new FileStream(run.LogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
fs.Seek(totalBytes - MaxLogBytes, SeekOrigin.Begin);
var read = await fs.ReadAsync(buffer, cancellationToken);
var tail = System.Text.Encoding.UTF8.GetString(buffer, 0, read);
return $"[truncated: showing last {MaxLogBytes} of {totalBytes} bytes]\n{tail}";
}
private static RunDto ToDto(TaskRunEntity r) => new(