Skip to content

Commit b46e863

Browse files
committed
update
Signed-off-by: laurentsimon <[email protected]>
1 parent f0640b1 commit b46e863

File tree

6 files changed

+44
-94
lines changed

6 files changed

+44
-94
lines changed

cli/slsa-verifier/verify/options.go

+1-9
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,11 @@ func (o *VerifyOptions) AddFlags(cmd *cobra.Command) {
7676

7777
// VerifyNpmOptions is the top-level options for the `verifyNpmPackage` command.
7878
type VerifyNpmOptions struct {
79-
/* Source requirements */
80-
SourceURI string
81-
SourceBranch string
82-
SourceTag string
83-
SourceVersionTag string
84-
/* Builder Requirements */
85-
BuildWorkflowInputs workflowInputs
86-
BuilderID string
79+
VerifyOptions
8780
/* Other */
8881
AttestationsPath string
8982
PackageName string
9083
PackageVersion string
91-
PrintProvenance bool
9284
}
9385

9486
var _ Interface = (*VerifyNpmOptions)(nil)

cli/slsa-verifier/verify/verify_npm_package.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,7 @@ func (c *VerifyNpmPackageCommand) Exec(ctx context.Context, tarballs []string) (
8888
fmt.Fprintf(os.Stdout, "%s\n", string(verifiedProvenance))
8989
}
9090

91-
if builderID == nil {
92-
builderID = outBuilderID
93-
} else if *builderID != *outBuilderID {
94-
err := fmt.Errorf("encountered different builderIDs %v %v", builderID, outBuilderID)
95-
fmt.Fprintf(os.Stderr, "Verifying npm package %s: FAILED: %v\n\n", tarball, err)
96-
return nil, err
97-
}
91+
builderID = outBuilderID
9892
fmt.Fprintf(os.Stderr, "Verifying npm package %s: PASSED\n\n", tarball)
9993
}
10094

errors/errors.go

+1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ var (
3636
ErrorInvalidRekorEntry = errors.New("invalid Rekor entry")
3737
ErrorRekorPubKey = errors.New("error retrieving Rekor public keys")
3838
ErrorInvalidPackageName = errors.New("invalid package name")
39+
ErrorInvalidSubject = errors.New("invalid subject")
3940
)

verifiers/internal/gha/builder.go

+20-66
Original file line numberDiff line numberDiff line change
@@ -36,100 +36,54 @@ var defaultBYOBReusableWorkflows = map[string]bool{
3636
trustedBuilderRepository + "/.github/workflows/delegator_generic_slsa3.yml": true,
3737
}
3838

39-
// VerifyWorkflowIdentity verifies the signing certificate information
40-
// Builder IDs are verified against an expected builder ID provided in the
41-
// builerOpts, or against the set of defaultBuilders provided.
42-
func VerifyWorkflowIdentity(id *WorkflowIdentity,
43-
builderOpts *options.BuilderOpts, source string,
44-
defaultBuilders map[string]bool,
45-
) (*utils.TrustedBuilderID, error) {
46-
// cert URI path is /org/repo/path/to/workflow@ref
47-
workflowPath := strings.SplitN(id.JobWobWorkflowRef, "@", 2)
48-
if len(workflowPath) < 2 {
49-
return nil, fmt.Errorf("%w: workflow uri: %s", serrors.ErrorMalformedURI, id.JobWobWorkflowRef)
50-
}
51-
52-
// Verify trusted workflow.
53-
reusableWorkflowPath := strings.Trim(workflowPath[0], "/")
54-
reusableWorkflowTag := strings.Trim(workflowPath[1], "/")
55-
builderID, err := verifyTrustedBuilderID(reusableWorkflowPath, reusableWorkflowTag,
56-
builderOpts.ExpectedID, defaultBuilders)
57-
if err != nil {
58-
return nil, err
59-
}
60-
61-
// Verify the ref is a full semantic version tag.
62-
if err := verifyTrustedBuilderRef(id, reusableWorkflowTag); err != nil {
63-
return nil, err
64-
}
65-
66-
// Issuer verification.
67-
if id.Issuer != certOidcIssuer {
68-
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidOIDCIssuer, id.Issuer)
69-
}
70-
39+
// VerifyCertficateSourceRepository verifies the source repository.
40+
func VerifyCertficateSourceRepository(id *WorkflowIdentity,
41+
sourceRepo string,
42+
) error {
7143
// The caller repository in the x509 extension is not fully qualified. It only contains
7244
// {org}/{repository}.
73-
expectedSource := strings.TrimPrefix(source, "git+https://")
45+
expectedSource := strings.TrimPrefix(sourceRepo, "git+https://")
7446
expectedSource = strings.TrimPrefix(expectedSource, "github.com/")
7547
if id.CallerRepository != expectedSource {
76-
return nil, fmt.Errorf("%w: expected source '%s', got '%s'", serrors.ErrorMismatchSource,
48+
return fmt.Errorf("%w: expected source '%s', got '%s'", serrors.ErrorMismatchSource,
7749
expectedSource, id.CallerRepository)
7850
}
79-
80-
// Return the builder and its tag.
81-
// Note: the tag has the format `refs/tags/v1.2.3`.
82-
return builderID, nil
51+
return nil
8352
}
8453

85-
// VerifyNpmWorkflowIdentity verifies the signing certificate information
86-
// Any builder ID is allowed, but it must match the source repo as well
87-
// in the provenance.
88-
func VerifyNpmWorkflowIdentity(id *WorkflowIdentity, source string,
54+
// VerifyBuilderIdentity verifies the signing certificate information
55+
// Builder IDs are verified against an expected builder ID provided in the
56+
// builerOpts, or against the set of defaultBuilders provided.
57+
func VerifyBuilderIdentity(id *WorkflowIdentity,
58+
builderOpts *options.BuilderOpts,
8959
defaultBuilders map[string]bool,
9060
) (*utils.TrustedBuilderID, error) {
91-
// cert URI path is /org/repo/path/to/workflow@ref
92-
workflowPath := strings.SplitN(id.JobWobWorkflowRef, "@", 2)
93-
if len(workflowPath) < 2 {
94-
return nil, fmt.Errorf("%w: workflow uri: %s", serrors.ErrorMalformedURI, id.JobWobWorkflowRef)
95-
}
96-
9761
// Issuer verification.
98-
if !strings.EqualFold(id.Issuer, certOidcIssuer) {
62+
// NOTE: this is necessary before we do any further verification.
63+
if id.Issuer != certOidcIssuer {
9964
return nil, fmt.Errorf("%w: %s", serrors.ErrorInvalidOIDCIssuer, id.Issuer)
10065
}
10166

102-
// The caller repository in the x509 extension is not fully qualified. It only contains
103-
// {org}/{repository}.
104-
expectedSource := strings.TrimPrefix(source, "git+https://")
105-
expectedSource = strings.TrimPrefix(expectedSource, "github.com/")
106-
if !strings.EqualFold(id.CallerRepository, expectedSource) {
107-
return nil, fmt.Errorf("%w: expected source '%s', got '%s'", serrors.ErrorMismatchSource,
108-
expectedSource, id.CallerRepository)
67+
// cert URI path is /org/repo/path/to/workflow@ref
68+
workflowPath := strings.SplitN(id.JobWobWorkflowRef, "@", 2)
69+
if len(workflowPath) < 2 {
70+
return nil, fmt.Errorf("%w: workflow uri: %s", serrors.ErrorMalformedURI, id.JobWobWorkflowRef)
10971
}
11072

11173
// Verify trusted workflow.
11274
reusableWorkflowPath := strings.Trim(workflowPath[0], "/")
11375
reusableWorkflowTag := strings.Trim(workflowPath[1], "/")
114-
// No expected builder ID verification in the certificate:
115-
// 1. It's either one of our trusted builders.
116-
// 2. Or it's any workflow in a repo.
11776
builderID, err := verifyTrustedBuilderID(reusableWorkflowPath, reusableWorkflowTag,
118-
nil, defaultBuilders)
77+
builderOpts.ExpectedID, defaultBuilders)
11978
if err != nil {
120-
// WARNING: the default npm builder is *not* one of our trusted builders.
121-
// We return success but no trusted builder.
122-
return nil, nil
79+
return nil, err
12380
}
12481

125-
// This is one of our trusted reusable workflows.
12682
// Verify the ref is a full semantic version tag.
12783
if err := verifyTrustedBuilderRef(id, reusableWorkflowTag); err != nil {
12884
return nil, err
12985
}
13086

131-
// Return the builder and its tag.
132-
// Note: the tag has the format `refs/tags/v1.2.3`.
13387
return builderID, nil
13488
}
13589

verifiers/internal/gha/npm.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ func getSubject(att *SignedAttestation) (string, error) {
447447
return "", fmt.Errorf("%w", err)
448448
}
449449
if len(subjects) != 1 {
450-
return "", fmt.Errorf("TODO")
450+
return "", fmt.Errorf("%w: subject length: %v", serrors.ErrorInvalidSubject, len(subjects))
451451
}
452452

453453
// Package name starts with a prefix.

verifiers/internal/gha/verifier.go

+20-11
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,19 @@ func verifyEnvAndCert(env *dsse.Envelope,
5454
return nil, nil, err
5555
}
5656

57-
// Verify the workflow identity.
58-
builderID, err := VerifyWorkflowIdentity(workflowInfo, builderOpts,
59-
provenanceOpts.ExpectedSourceURI, defaultBuilders)
57+
// Verify the builder identity.
58+
builderID, err := VerifyBuilderIdentity(workflowInfo, builderOpts, defaultBuilders)
6059
if err != nil {
6160
return nil, nil, err
6261
}
6362

63+
// Verify the source repository from the certificate.
64+
if err := VerifyCertficateSourceRepository(workflowInfo, provenanceOpts.ExpectedSourceURI); err != nil {
65+
return nil, nil, err
66+
}
67+
6468
// Verify properties of the SLSA provenance.
65-
// Unpack and verify info in the provenance, including the Subject Digest.
69+
// Unpack and verify info in the provenance, including the subject Digest.
6670
provenanceOpts.ExpectedBuilderID = builderID.String()
6771
if err := VerifyProvenance(env, provenanceOpts); err != nil {
6872
return nil, nil, err
@@ -94,27 +98,32 @@ func verifyNpmEnvAndCert(env *dsse.Envelope,
9498
}
9599

96100
// Verify the workflow identity.
97-
trustedBuilderID, err := VerifyNpmWorkflowIdentity(workflowInfo,
101+
trustedBuilderID, err := VerifyBuilderIdentity(workflowInfo,
98102
provenanceOpts.ExpectedSourceURI, defaultBuilders)
99-
if err != nil {
103+
// We accept a non-trusted builder for the default npm builder
104+
// that uses npm CLI.
105+
if err != nil && !errors.Is(err, serrors.ErrorUntrustedReusableWorkflow) {
100106
return nil, err
101107
}
102108

103-
// TODO(#493): verify certificate information matches
104-
// the provenance if possible in the future.
109+
// TODO(#493): retrieve certificate information to match
110+
// with the provenance.
105111
// Today it's not possible due to lack of information in the cert.
112+
// Verify the source repository frmo the certificate.
113+
if err := VerifyCertficateSourceRepository(workflowInfo, provenanceOpts.ExpectedSourceURI); err != nil {
114+
return nil, nil, err
115+
}
106116

107117
// Verify properties of the SLSA provenance.
108118
// Unpack and verify info in the provenance, including the Subject Digest.
109119
// WARNING: builderID may be empty if it's not a reusable builder workflow.
110120
if trustedBuilderID != nil {
111121
provenanceOpts.ExpectedBuilderID = trustedBuilderID.String()
112122
} else {
113-
// TODO(#494): update the builder ID name.
114123
if builderOpts == nil || builderOpts.ExpectedID == nil {
115124
return nil, fmt.Errorf("builder mistmatch. No builder ID provided by user , got '%v'", builderGitHubRunnerID)
116125
}
117-
126+
// TODO(#494): update the builder ID name.
118127
trustedBuilderID, err = utils.TrustedBuilderIDNew(builderGitHubRunnerID)
119128
if err != nil {
120129
return nil, err
@@ -129,7 +138,7 @@ func verifyNpmEnvAndCert(env *dsse.Envelope,
129138
}
130139

131140
fmt.Fprintf(os.Stderr, "Verified build using builder %s at commit %s\n",
132-
provenanceOpts.ExpectedBuilderID,
141+
trustedBuilderID.String(),
133142
workflowInfo.CallerHash)
134143

135144
return trustedBuilderID, nil

0 commit comments

Comments
 (0)