Skip to content

Commit c51d7a6

Browse files
committed
review(lifecycle): drop double-truncation of persisted hook output
stdoutBuf and stderrBuf are each lifecycleCappedBuffer-backed and already append "\n...<truncated>" when they hit lifecycleMaxOutputBytes, so the combined string is already bounded. The outer truncateLifecycleOutputInternal call sliced at a fixed byte boundary, which could land mid-UTF-8 codepoint and corrupt the persisted output. Drop the call (and the now-unused helper + its test); rely on the buffers. The combined ceiling is now ~2× lifecycleMaxOutputBytes (stdout + separator + stderr) which is fine — pre_deploy_last_run_output is TEXT in both Postgres and SQLite. Greptile review on getarcaneapp#2782.
1 parent ca9dd56 commit c51d7a6

2 files changed

Lines changed: 5 additions & 19 deletions

File tree

backend/internal/services/lifecycle_service.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,11 @@ func (s *LifecycleService) executePreDeployInternal(ctx context.Context, project
173173
durationMs := time.Since(start).Milliseconds()
174174

175175
status := lifecycleStatusForResultInternal(exitCode, runErr)
176-
persistedOutput := truncateLifecycleOutputInternal(combineLifecycleOutputInternal(stdoutContent, stderrContent), lifecycleMaxOutputBytes)
176+
// stdoutBuf/stderrBuf already enforce lifecycleMaxOutputBytes each with a
177+
// proper "...<truncated>" marker, so the combined string is already
178+
// bounded and we don't slice again here — a second byte-boundary cut
179+
// could land mid-UTF-8 codepoint and produce garbled output.
180+
persistedOutput := combineLifecycleOutputInternal(stdoutContent, stderrContent)
177181
s.persistLastRunInternal(ctx, sync.ID, status, persistedOutput, start)
178182
s.emitLifecycleEventInternal(ctx, project, sync, status, exitCode, durationMs, runErr, actor)
179183

@@ -673,13 +677,6 @@ func combineLifecycleOutputInternal(stdout, stderr string) string {
673677
}
674678
}
675679

676-
func truncateLifecycleOutputInternal(content string, maxBytes int) string {
677-
if maxBytes <= 0 || len(content) <= maxBytes {
678-
return content
679-
}
680-
return content[:maxBytes] + "\n...<truncated>"
681-
}
682-
683680
func removeLifecycleContainerInternal(ctx context.Context, dockerClient *client.Client, containerID string, apiTimeoutSec int) {
684681
if dockerClient == nil || containerID == "" {
685682
return

backend/internal/services/lifecycle_service_test.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"os"
77
"path/filepath"
8-
"strings"
98
"testing"
109
"time"
1110

@@ -218,16 +217,6 @@ func TestCombineLifecycleOutput(t *testing.T) {
218217
}
219218
}
220219

221-
func TestTruncateLifecycleOutput(t *testing.T) {
222-
short := "hello"
223-
assert.Equal(t, short, truncateLifecycleOutputInternal(short, 1024))
224-
225-
long := strings.Repeat("a", 200)
226-
got := truncateLifecycleOutputInternal(long, 100)
227-
require.True(t, strings.HasPrefix(got, strings.Repeat("a", 100)))
228-
require.Contains(t, got, "<truncated>")
229-
}
230-
231220
func TestRunPreDeploy_NilProject(t *testing.T) {
232221
db := setupLifecycleTestDB(t)
233222
svc, _ := newLifecycleTestService(t, db)

0 commit comments

Comments
 (0)