remotecache: honor gha cache transparency log thresholds

Pass explicit cache log thresholds to policy-helpers during signature
verification. Preserve the distinction between an omitted threshold and
zero. Omission uses the bundle-derived default, while zero skips log
verification and requires a verified TSA timestamp.

Remove the local log threshold check, which counted log timestamps rather
than verified logs and could reject valid inclusion-proof-only entries.
Keep timestamp and certificate policy checks in place.

Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
This commit is contained in:
CrazyMax committed 2026-10-22 18:32:57 +02:00
1 parent 7323f74949
commit 08b2acc920
4 files changed
+30 -13

No files matched your search

+6 -11
View File
@@ -364,7 +364,12 @@ func verifySignature(ctx context.Context, dgst digest.Digest, bundle []byte, con
return errors.New("no verifier available for signed github actions cache")
}
sig, err := v.VerifyArtifact(ctx, dgst, bundle, policy.WithSLSANotRequired())
policyRules := config.Verify.Policy
opts := []policy.ArtifactVerifyOpt{policy.WithSLSANotRequired()}
if policyRules.TlogThreshold != nil {
opts = append(opts, policy.WithTlogThreshold(*policyRules.TlogThreshold))
}
sig, err := v.VerifyArtifact(ctx, dgst, bundle, opts...)
if err != nil {
return err
}
@@ -372,19 +377,9 @@ func verifySignature(ctx context.Context, dgst digest.Digest, bundle []byte, con
return errors.New("signature verification failed: no signer found")
}
numTimestamps := len(sig.Timestamps)
numTlog := 0
for _, t := range sig.Timestamps {
if t.Type == "Tlog" {
numTlog++
}
}
policyRules := config.Verify.Policy
if policyRules.TimestampThreshold > numTimestamps {
return errors.Errorf("signature verification failed: not enough timestamp authorities: have %d, need %d", numTimestamps, policyRules.TimestampThreshold)
}
if policyRules.TlogThreshold > numTlog {
return errors.Errorf("signature verification failed: not enough tlog authorities: have %d, need %d", numTlog, policyRules.TlogThreshold)
}
certRules, err := certToStringMap(&config.Verify.Policy.Summary)
if err != nil {
+20
View File
@@ -9,13 +9,33 @@ import (
"testing"
"time"
"github.com/moby/buildkit/cache/remotecache/gha/ghatypes"
"github.com/moby/buildkit/client"
"github.com/moby/buildkit/client/llb"
"github.com/moby/buildkit/util/testutil/integration"
"github.com/moby/buildkit/util/testutil/workers"
policy "github.com/moby/policy-helpers"
digest "github.com/opencontainers/go-digest"
"github.com/stretchr/testify/require"
)
func TestVerifySignatureNegativeTlogThreshold(t *testing.T) {
config := &Config{
CacheConfig: &ghatypes.CacheConfig{
Verify: ghatypes.VerifyConfig{
Policy: ghatypes.VerifyPolicy{
TlogThreshold: new(-1),
},
},
},
verifier: func() (*policy.Verifier, error) {
return &policy.Verifier{}, nil
},
}
err := verifySignature(t.Context(), digest.FromString("cache index"), nil, config)
require.EqualError(t, err, "transparency log threshold must not be negative")
}
func init() {
if workers.IsTestDockerd() {
workers.InitDockerdWorker()
+2 -2
View File
@@ -17,7 +17,7 @@ type VerifyConfig struct {
}
type VerifyPolicy struct {
TimestampThreshold int `toml:"timestampThreshold"`
TlogThreshold int `toml:"tlogThreshold"`
TimestampThreshold int `toml:"timestampThreshold"`
TlogThreshold *int `toml:"tlogThreshold"`
certificate.Summary
}
+2
View File
@@ -267,6 +267,8 @@ provenanceEnvDir = "/etc/buildkit/provenance.d"
#
# [cache.gha.verify.policy]
# timestampThreshold = 1
# # If omitted, require all distinct transparency logs present in the bundle.
# # Zero skips log verification and requires a verified TSA timestamp instead.
# tlogThreshold = 1
# # certificate properties that need to match. Simple wildcards (*) are supported.
# certificateIssuer = ""