fix(coderd/agentapi): trim whitespace from workspace agent metadata values (#23709)

- Trim leading/trailing whitespace from metadata `value` and `error`
fields before storage
- Trimming happens before length validation so whitespace-padded values
are handled correctly
- Add `TrimWhitespace` test covering spaces, tabs, newlines, and
preserved inner whitespace
- No backfill needed (unlogged table, stores only latest value)

> 🤖 Created by a Coder Agent, reviewed by me.
This commit is contained in:
Cian Johnston
2026-03-27 15:08:47 +00:00
committed by GitHub
parent 3f55b35f68
commit a5c72ba396
2 changed files with 35 additions and 4 deletions
+3
View File
@@ -3,6 +3,7 @@ package agentapi
import (
"context"
"fmt"
"strings"
"time"
"github.com/google/uuid"
@@ -60,6 +61,8 @@ func (a *MetadataAPI) BatchUpdateMetadata(ctx context.Context, req *agentproto.B
}
)
for _, md := range req.Metadata {
md.Result.Value = strings.TrimSpace(md.Result.Value)
md.Result.Error = strings.TrimSpace(md.Result.Error)
metadataError := md.Result.Error
allKeysLen += len(md.Key)
+32 -4
View File
@@ -57,16 +57,44 @@ func TestBatchUpdateMetadata(t *testing.T) {
CollectedAt: timestamppb.New(now.Add(-3 * time.Second)),
Age: 3,
Value: "",
Error: "uncool value",
Error: "\t uncool error ",
},
},
},
}
batchSize := len(req.Metadata)
// This test sends 2 metadata entries. With batch size 2, we expect
// exactly 1 capacity flush.
// This test sends 2 metadata entries (one clean, one with
// whitespace padding). With batch size 2 we expect exactly
// 1 capacity flush. The matcher verifies that stored values
// are trimmed while clean values pass through unchanged.
expectedValues := map[string]string{
"awesome key": "awesome value",
"uncool key": "",
}
expectedErrors := map[string]string{
"awesome key": "",
"uncool key": "uncool error",
}
store.EXPECT().
BatchUpdateWorkspaceAgentMetadata(gomock.Any(), gomock.Any()).
BatchUpdateWorkspaceAgentMetadata(
gomock.Any(),
gomock.Cond(func(arg database.BatchUpdateWorkspaceAgentMetadataParams) bool {
if len(arg.Key) != len(expectedValues) {
return false
}
for i, key := range arg.Key {
expVal, ok := expectedValues[key]
if !ok || arg.Value[i] != expVal {
return false
}
expErr, ok := expectedErrors[key]
if !ok || arg.Error[i] != expErr {
return false
}
}
return true
}),
).
Return(nil).
Times(1)