Skip to content

Commit 0b1b5fe

Browse files
authored
Merge pull request cli#11989 from cli/copilot/fix-gh-attestation-verification
Fix gh attestation verify to work when Public Good Instance of Sigstore is unavailable
2 parents b90e39e + b808612 commit 0b1b5fe

2 files changed

Lines changed: 78 additions & 6 deletions

File tree

pkg/cmd/attestation/verification/sigstore.go

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,27 +63,39 @@ func NewLiveSigstoreVerifier(config SigstoreConfig) (*LiveSigstoreVerifier, erro
6363
Logger: config.Logger,
6464
NoPublicGood: config.NoPublicGood,
6565
}
66-
// if a custom trusted root is set, configure custom verifiers
66+
// if a custom trusted root is set, configure custom verifiers and assume no Public Good or GitHub verifiers
67+
// are needed
6768
if config.TrustedRoot != "" {
6869
customVerifiers, err := createCustomVerifiers(config.TrustedRoot, config.NoPublicGood)
6970
if err != nil {
70-
return nil, err
71+
return nil, fmt.Errorf("error creating custom verifiers: %s", err)
7172
}
7273
liveVerifier.Custom = customVerifiers
7374
return liveVerifier, nil
7475
}
76+
77+
// No custom trusted root is set, so configure Public Good and GitHub verifiers
7578
if !config.NoPublicGood {
7679
publicGoodVerifier, err := newPublicGoodVerifier(config.TUFMetadataDir, config.HttpClient)
7780
if err != nil {
78-
return nil, err
81+
// Log warning but continue - PGI unavailability should not block GitHub attestation verification
82+
config.Logger.VerbosePrintf("Warning: failed to initialize Sigstore Public Good verifier: %v\n", err)
83+
config.Logger.VerbosePrintf("Continuing without Public Good Instance verification\n")
84+
} else {
85+
liveVerifier.PublicGood = publicGoodVerifier
7986
}
80-
liveVerifier.PublicGood = publicGoodVerifier
8187
}
88+
8289
github, err := newGitHubVerifier(config.TrustDomain, config.TUFMetadataDir, config.HttpClient)
8390
if err != nil {
84-
return nil, err
91+
config.Logger.VerbosePrintf("Warning: failed to initialize GitHub verifier: %v\n", err)
92+
} else {
93+
liveVerifier.GitHub = github
94+
}
95+
96+
if liveVerifier.noVerifierSet() {
97+
return nil, fmt.Errorf("no valid Sigstore verifiers could be initialized")
8598
}
86-
liveVerifier.GitHub = github
8799

88100
return liveVerifier, nil
89101
}
@@ -206,6 +218,9 @@ func (v *LiveSigstoreVerifier) chooseVerifier(issuer string) (*verify.Verifier,
206218
if v.NoPublicGood {
207219
return nil, fmt.Errorf("detected public good instance but requested verification without public good instance")
208220
}
221+
if v.PublicGood == nil {
222+
return nil, fmt.Errorf("public good verifier is not available (initialization may have failed)")
223+
}
209224
return v.PublicGood, nil
210225
case GitHubIssuerOrg:
211226
return v.GitHub, nil
@@ -372,3 +387,7 @@ func newPublicGoodVerifierWithTrustedRoot(trustedRoot *root.TrustedRoot) (*verif
372387

373388
return sv, nil
374389
}
390+
391+
func (v *LiveSigstoreVerifier) noVerifierSet() bool {
392+
return v.PublicGood == nil && v.GitHub == nil && len(v.Custom) == 0
393+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package verification
2+
3+
import (
4+
"testing"
5+
6+
"github.com/cli/cli/v2/pkg/cmd/attestation/io"
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
// Note: Tests that require network access and TUF client initialization
11+
// are in sigstore_integration_test.go with the //go:build integration tag.
12+
// These unit tests focus on testing the logic without requiring network access.
13+
14+
// TestChooseVerifierWithNilPublicGood tests that chooseVerifier returns an error
15+
// when a PGI attestation is encountered but the PGI verifier is nil (failed initialization).
16+
func TestChooseVerifierWithNilPublicGood(t *testing.T) {
17+
verifier := &LiveSigstoreVerifier{
18+
Logger: io.NewTestHandler(),
19+
NoPublicGood: false,
20+
PublicGood: nil, // Simulate failed PGI initialization
21+
GitHub: nil, // Not needed for this test
22+
}
23+
24+
_, err := verifier.chooseVerifier(PublicGoodIssuerOrg)
25+
26+
require.Error(t, err)
27+
require.ErrorContains(t, err, "public good verifier is not available")
28+
}
29+
30+
// TestChooseVerifierUnrecognizedIssuer tests that an error is returned
31+
// for unrecognized issuers.
32+
func TestChooseVerifierUnrecognizedIssuer(t *testing.T) {
33+
verifier := &LiveSigstoreVerifier{
34+
Logger: io.NewTestHandler(),
35+
NoPublicGood: false,
36+
}
37+
38+
_, err := verifier.chooseVerifier("unknown-issuer")
39+
40+
require.Error(t, err)
41+
require.ErrorContains(t, err, "leaf certificate issuer is not recognized")
42+
}
43+
44+
func TestLiveSigstoreVerifier_noVerifierSet(t *testing.T) {
45+
verifier := &LiveSigstoreVerifier{
46+
Logger: io.NewTestHandler(),
47+
NoPublicGood: true,
48+
PublicGood: nil,
49+
GitHub: nil,
50+
}
51+
52+
require.True(t, verifier.noVerifierSet())
53+
}

0 commit comments

Comments
 (0)