Skip to content

Commit 2baee00

Browse files
committed
fix: reload state after collectors to sync digest for old servers
Servers that don't return digests in Save responses leave the client with a stale UpdateCheckSum. Reloading state after all collectors run ensures the local digest matches the server, preventing OCC conflicts on subsequent writes. Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev>
1 parent 79bf736 commit 2baee00

2 files changed

Lines changed: 11 additions & 5 deletions

File tree

pkg/attestation/crafter/crafter.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,12 @@ func (c *Crafter) RunCollectors(ctx context.Context, attestationID string, casBa
152152
c.Logger.Warn().Err(err).Str("collector", collector.ID()).Msg("collector failed")
153153
}
154154
}
155+
156+
// Reload state to sync the local digest with the server after collectors modified it.
157+
// This is needed for backward compatibility with servers that don't return digests in Save responses.
158+
if err := c.LoadCraftingState(ctx, attestationID); err != nil {
159+
c.Logger.Warn().Err(err).Msg("failed to reload crafting state after running collectors")
160+
}
155161
}
156162

157163
// Create a completely new crafter

pkg/attestation/crafter/runcollectors_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func newSuccessCollector(t *testing.T, id string) *craftermocks.Collector {
5757
}
5858

5959
func TestRunCollectors(t *testing.T) {
60-
t.Run("loads state once before running collectors", func(t *testing.T) {
60+
t.Run("loads state before and after running collectors", func(t *testing.T) {
6161
sm := craftermocks.NewStateManager(t)
6262
setupReadExpectation(sm, "digest-1")
6363
sm.On("Info", mock.Anything, mock.Anything).Return("mock://run-1")
@@ -71,8 +71,8 @@ func TestRunCollectors(t *testing.T) {
7171

7272
cr.RunCollectors(context.Background(), "run-1", nil)
7373

74-
// Single Read before the loop
75-
sm.AssertNumberOfCalls(t, "Read", 1)
74+
// Read before the loop + Read after to sync digest
75+
sm.AssertNumberOfCalls(t, "Read", 2)
7676
c1.AssertCalled(t, "Collect", mock.Anything, mock.Anything, "run-1", mock.Anything)
7777
c2.AssertCalled(t, "Collect", mock.Anything, mock.Anything, "run-1", mock.Anything)
7878
})
@@ -99,7 +99,7 @@ func TestRunCollectors(t *testing.T) {
9999
c2.AssertCalled(t, "Collect", mock.Anything, mock.Anything, mock.Anything, mock.Anything)
100100
})
101101

102-
t.Run("no collectors only reloads state", func(t *testing.T) {
102+
t.Run("no collectors reloads state before and after", func(t *testing.T) {
103103
sm := craftermocks.NewStateManager(t)
104104
setupReadExpectation(sm, "d")
105105
sm.On("Info", mock.Anything, mock.Anything).Return("mock://run-1")
@@ -109,7 +109,7 @@ func TestRunCollectors(t *testing.T) {
109109

110110
cr.RunCollectors(context.Background(), "run-1", nil)
111111

112-
sm.AssertNumberOfCalls(t, "Read", 1)
112+
sm.AssertNumberOfCalls(t, "Read", 2)
113113
})
114114

115115
t.Run("state load failure aborts before running collectors", func(t *testing.T) {

0 commit comments

Comments
 (0)