Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions pkg/cmd/attestation/verification/sigstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,39 @@ func NewLiveSigstoreVerifier(config SigstoreConfig) (*LiveSigstoreVerifier, erro
Logger: config.Logger,
NoPublicGood: config.NoPublicGood,
}
// if a custom trusted root is set, configure custom verifiers
// if a custom trusted root is set, configure custom verifiers and assume no Public Good or GitHub verifiers
// are needed
if config.TrustedRoot != "" {
customVerifiers, err := createCustomVerifiers(config.TrustedRoot, config.NoPublicGood)
if err != nil {
return nil, err
return nil, fmt.Errorf("error creating custom verifiers: %s", err)
}
liveVerifier.Custom = customVerifiers
return liveVerifier, nil
}

// No custom trusted root is set, so configure Public Good and GitHub verifiers
if !config.NoPublicGood {
publicGoodVerifier, err := newPublicGoodVerifier(config.TUFMetadataDir, config.HttpClient)
if err != nil {
return nil, err
// Log warning but continue - PGI unavailability should not block GitHub attestation verification
config.Logger.VerbosePrintf("Warning: failed to initialize Sigstore Public Good verifier: %v\n", err)
config.Logger.VerbosePrintf("Continuing without Public Good Instance verification\n")
} else {
liveVerifier.PublicGood = publicGoodVerifier
}
liveVerifier.PublicGood = publicGoodVerifier
}

github, err := newGitHubVerifier(config.TrustDomain, config.TUFMetadataDir, config.HttpClient)
if err != nil {
return nil, err
config.Logger.VerbosePrintf("Warning: failed to initialize GitHub verifier: %v\n", err)
} else {
liveVerifier.GitHub = github
}

if liveVerifier.noVerifierSet() {
return nil, fmt.Errorf("no valid Sigstore verifiers could be initialized")
}
liveVerifier.GitHub = github

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

return sv, nil
}

func (v *LiveSigstoreVerifier) noVerifierSet() bool {
return v.PublicGood == nil && v.GitHub == nil && len(v.Custom) == 0
}
53 changes: 53 additions & 0 deletions pkg/cmd/attestation/verification/sigstore_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package verification

import (
"testing"

"github.com/cli/cli/v2/pkg/cmd/attestation/io"
"github.com/stretchr/testify/require"
)

// Note: Tests that require network access and TUF client initialization
// are in sigstore_integration_test.go with the //go:build integration tag.
// These unit tests focus on testing the logic without requiring network access.

// TestChooseVerifierWithNilPublicGood tests that chooseVerifier returns an error
// when a PGI attestation is encountered but the PGI verifier is nil (failed initialization).
func TestChooseVerifierWithNilPublicGood(t *testing.T) {
verifier := &LiveSigstoreVerifier{
Logger: io.NewTestHandler(),
NoPublicGood: false,
PublicGood: nil, // Simulate failed PGI initialization
GitHub: nil, // Not needed for this test
}

_, err := verifier.chooseVerifier(PublicGoodIssuerOrg)

require.Error(t, err)
require.ErrorContains(t, err, "public good verifier is not available")
}

// TestChooseVerifierUnrecognizedIssuer tests that an error is returned
// for unrecognized issuers.
func TestChooseVerifierUnrecognizedIssuer(t *testing.T) {
verifier := &LiveSigstoreVerifier{
Logger: io.NewTestHandler(),
NoPublicGood: false,
}

_, err := verifier.chooseVerifier("unknown-issuer")

require.Error(t, err)
require.ErrorContains(t, err, "leaf certificate issuer is not recognized")
}

func TestLiveSigstoreVerifier_noVerifierSet(t *testing.T) {
verifier := &LiveSigstoreVerifier{
Logger: io.NewTestHandler(),
NoPublicGood: true,
PublicGood: nil,
GitHub: nil,
}

require.True(t, verifier.noVerifierSet())
}