policy: preserve late progress errors

Emit a final policy progress completion with the solve error even when the
inactivity window already completed the vertex.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi
2026-05-07 12:09:50 -07:00
parent 9392590cfa
commit 0c04ba8d36
2 changed files with 54 additions and 0 deletions
+3
View File
@@ -188,6 +188,9 @@ func (l *policyProgressLogger) Close(err error) {
shouldComplete = true shouldComplete = true
started = l.started started = l.started
l.open = false l.open = false
} else if err != nil && !l.started.IsZero() {
shouldComplete = true
started = l.started
} }
l.window++ l.window++
if l.timer != nil { if l.timer != nil {
+51
View File
@@ -2,6 +2,7 @@ package build
import ( import (
"context" "context"
"sync"
"testing" "testing"
"github.com/docker/buildx/util/buildflags" "github.com/docker/buildx/util/buildflags"
@@ -11,6 +12,7 @@ import (
"github.com/moby/buildkit/client/ociindex" "github.com/moby/buildkit/client/ociindex"
"github.com/opencontainers/go-digest" "github.com/opencontainers/go-digest"
ocispecs "github.com/opencontainers/image-spec/specs-go/v1" ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -237,6 +239,30 @@ func TestLoadInputsOCILayoutNamedContext(t *testing.T) {
} }
} }
func TestPolicyProgressLoggerCloseWithErrorAfterCompletedWindow(t *testing.T) {
pw := &captureProgressWriter{}
logger := newPolicyProgressLogger(pw, "loading policies policy.rego")
logger.Log("policy decision: DENY")
logger.completeWindow(1, nil)
logger.Close(errors.New("source not allowed by policy"))
var completedErrors []string
for _, st := range pw.Statuses() {
for _, v := range st.Vertexes {
if v == nil || v.Completed == nil {
continue
}
if v.Error == "" {
continue
}
completedErrors = append(completedErrors, v.Error)
}
}
require.Equal(t, []string{"source not allowed by policy"}, completedErrors)
}
type testProgressWriter struct{} type testProgressWriter struct{}
func (testProgressWriter) Write(*client.SolveStatus) {} func (testProgressWriter) Write(*client.SolveStatus) {}
@@ -248,3 +274,28 @@ func (testProgressWriter) ValidateLogSource(digest.Digest, any) bool { return tr
func (testProgressWriter) ClearLogSource(any) {} func (testProgressWriter) ClearLogSource(any) {}
var _ progress.Writer = testProgressWriter{} var _ progress.Writer = testProgressWriter{}
type captureProgressWriter struct {
mu sync.Mutex
statuses []*client.SolveStatus
}
func (w *captureProgressWriter) Write(st *client.SolveStatus) {
w.mu.Lock()
defer w.mu.Unlock()
w.statuses = append(w.statuses, st)
}
func (w *captureProgressWriter) Statuses() []*client.SolveStatus {
w.mu.Lock()
defer w.mu.Unlock()
return append([]*client.SolveStatus(nil), w.statuses...)
}
func (w *captureProgressWriter) WriteBuildRef(string, string) {}
func (w *captureProgressWriter) ValidateLogSource(digest.Digest, any) bool { return true }
func (w *captureProgressWriter) ClearLogSource(any) {}
var _ progress.Writer = (*captureProgressWriter)(nil)