From 432898337071dc71e3efa9012c01c70e4e60b7a4 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 3 Jun 2024 00:42:27 +0000 Subject: [PATCH 1/2] fix: replace invalid utf-8 sequences in agent logs Fixes #13433. --- codersdk/agentsdk/convert.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/codersdk/agentsdk/convert.go b/codersdk/agentsdk/convert.go index adfabd1510768..48a63e53769c0 100644 --- a/codersdk/agentsdk/convert.go +++ b/codersdk/agentsdk/convert.go @@ -348,7 +348,7 @@ func ProtoFromLog(log Log) (*proto.Log, error) { } return &proto.Log{ CreatedAt: timestamppb.New(log.CreatedAt), - Output: log.Output, + Output: strings.ToValidUTF8(log.Output, ""), Level: proto.Log_Level(lvl), }, nil } From 91aff2a0b8093a628e62a41215b0e90ce89d46f7 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Fri, 7 Jun 2024 14:42:39 +0400 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20replace=20invalid=20UTF-8=20with=20?= =?UTF-8?q?=E2=9D=8C,=20add=20regression?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Spike Curtis --- codersdk/agentsdk/convert.go | 2 +- codersdk/agentsdk/logs_internal_test.go | 45 +++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/codersdk/agentsdk/convert.go b/codersdk/agentsdk/convert.go index 48a63e53769c0..e60685d029507 100644 --- a/codersdk/agentsdk/convert.go +++ b/codersdk/agentsdk/convert.go @@ -348,7 +348,7 @@ func ProtoFromLog(log Log) (*proto.Log, error) { } return &proto.Log{ CreatedAt: timestamppb.New(log.CreatedAt), - Output: strings.ToValidUTF8(log.Output, ""), + Output: strings.ToValidUTF8(log.Output, "❌"), Level: proto.Log_Level(lvl), }, nil } diff --git a/codersdk/agentsdk/logs_internal_test.go b/codersdk/agentsdk/logs_internal_test.go index d942689d31465..da2f0dd86dd38 100644 --- a/codersdk/agentsdk/logs_internal_test.go +++ b/codersdk/agentsdk/logs_internal_test.go @@ -231,6 +231,51 @@ func TestLogSender_SkipHugeLog(t *testing.T) { require.ErrorIs(t, err, context.Canceled) } +func TestLogSender_InvalidUTF8(t *testing.T) { + t.Parallel() + testCtx := testutil.Context(t, testutil.WaitShort) + ctx, cancel := context.WithCancel(testCtx) + logger := slogtest.Make(t, nil).Leveled(slog.LevelDebug) + fDest := newFakeLogDest() + uut := NewLogSender(logger) + + t0 := dbtime.Now() + ls1 := uuid.UUID{0x11} + + uut.Enqueue(ls1, + Log{ + CreatedAt: t0, + Output: "test log 0, src 1\xc3\x28", + Level: codersdk.LogLevelInfo, + }, + Log{ + CreatedAt: t0, + Output: "test log 1, src 1", + Level: codersdk.LogLevelInfo, + }) + + loopErr := make(chan error, 1) + go func() { + err := uut.SendLoop(ctx, fDest) + loopErr <- err + }() + + req := testutil.RequireRecvCtx(ctx, t, fDest.reqs) + require.NotNil(t, req) + require.Len(t, req.Logs, 2, "it should sanitize invalid UTF-8, but still send") + // the 0xc3, 0x28 is an invalid 2-byte sequence in UTF-8. The sanitizer replaces 0xc3 with ❌, and then + // interprets 0x28 as a 1-byte sequence "(" + require.Equal(t, "test log 0, src 1❌(", req.Logs[0].GetOutput()) + require.Equal(t, proto.Log_INFO, req.Logs[0].GetLevel()) + require.Equal(t, "test log 1, src 1", req.Logs[1].GetOutput()) + require.Equal(t, proto.Log_INFO, req.Logs[1].GetLevel()) + testutil.RequireSendCtx(ctx, t, fDest.resps, &proto.BatchCreateLogsResponse{}) + + cancel() + err := testutil.RequireRecvCtx(testCtx, t, loopErr) + require.ErrorIs(t, err, context.Canceled) +} + func TestLogSender_Batch(t *testing.T) { t.Parallel() testCtx := testutil.Context(t, testutil.WaitShort)