Skip to content

Commit fd425bf

Browse files
committed
fix: address review feedback for in-toto-golang removal
Signed-off-by: Abhishek <abhishekup082@gmail.com>
1 parent bc2eefb commit fd425bf

6 files changed

Lines changed: 171 additions & 87 deletions

File tree

pkg/handler/processor/guesser/type_ite6.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,32 @@ type ite6Statement struct {
3535
}
3636

3737
// getType returns the statement type from whichever format was used.
38+
// in-toto v1 is the current standard; v0.1 is supported for backwards
39+
// compatibility. A document that populates both _type and type is malformed.
3840
func (s *ite6Statement) getType() string {
39-
if s.TypeV01 != "" {
40-
return s.TypeV01
41+
if s.TypeV1 != "" && s.TypeV01 != "" {
42+
// Both fields set: reject the ambiguous/malformed document.
43+
return ""
4144
}
42-
return s.TypeV1
45+
if s.TypeV1 != "" {
46+
return s.TypeV1
47+
}
48+
return s.TypeV01
4349
}
4450

4551
// getPredicateType returns the predicate type from whichever format was used.
52+
// in-toto v1 is the current standard; v0.1 is supported for backwards
53+
// compatibility. A document that populates both predicateType and predicate_type
54+
// is malformed.
4655
func (s *ite6Statement) getPredicateType() string {
47-
if s.PredicateTypeV01 != "" {
48-
return s.PredicateTypeV01
56+
if s.PredicateTypeV1 != "" && s.PredicateTypeV01 != "" {
57+
// Both fields set: reject the ambiguous/malformed document.
58+
return ""
59+
}
60+
if s.PredicateTypeV1 != "" {
61+
return s.PredicateTypeV1
4962
}
50-
return s.PredicateTypeV1
63+
return s.PredicateTypeV01
5164
}
5265

5366
type ite6TypeGuesser struct{}

pkg/handler/processor/guesser/type_ite6_test.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,29 @@ func Test_Ite6TypeGuesser(t *testing.T) {
3535
name: "valid ITE6 Document",
3636
blob: []byte(`{"_type": "https://in-toto.io/Statement/v0.1"}`),
3737
expected: processor.DocumentITE6Generic,
38+
}, {
39+
name: "valid ITE6 v1 Document",
40+
blob: []byte(`{"type": "https://in-toto.io/Statement/v1"}`),
41+
expected: processor.DocumentITE6Generic,
3842
}, {
3943
name: "valid SLSA ITE6 Document",
4044
blob: []byte(`{"_type": "https://in-toto.io/Statement/v0.1", "predicateType": "https://slsa.dev/provenance/v0.2"}`),
4145
expected: processor.DocumentITE6SLSA,
46+
}, {
47+
name: "valid SLSA ITE6 v1 Document",
48+
blob: []byte(`{"type": "https://in-toto.io/Statement/v1", "predicate_type": "https://slsa.dev/provenance/v0.2"}`),
49+
expected: processor.DocumentITE6SLSA,
4250
}, {
4351
name: "valid SLSA ITE6 Document with different versions",
4452
blob: []byte(`{"_type": "https://in-toto.io/Statement/v1.1", "predicateType": "https://slsa.dev/provenance/v1.0"}`),
4553
expected: processor.DocumentITE6SLSA,
54+
}, {
55+
// A document that populates both v0.1 and v1 type fields is malformed and
56+
// must be rejected (returns DocumentUnknown) rather than silently
57+
// preferring one format over the other.
58+
name: "ambiguous ITE6 Document with both _type and type fields",
59+
blob: []byte(`{"_type": "https://in-toto.io/Statement/v0.1", "type": "https://in-toto.io/Statement/v1", "predicateType": "https://slsa.dev/provenance/v0.2", "predicate_type": "https://slsa.dev/provenance/v0.2"}`),
60+
expected: processor.DocumentUnknown,
4661
}, {
4762
name: "valid CREV ITE6 Document",
4863
blob: testdata.ITE6CREVExample,

pkg/handler/processor/ite6/ite6.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ import (
2626
var json = jsoniter.ConfigCompatibleWithStandardLibrary
2727

2828
// ite6Statement is used for unmarshalling in-toto statement headers.
29+
// It handles both v0.1 (_type/predicateType) and v1 (type/predicate_type)
30+
// in-toto statement formats. Exactly one set of fields should be populated;
31+
// if neither is set after unmarshalling, the document is rejected with an error.
2932
type ite6Statement struct {
30-
Type string `json:"_type"`
31-
PredicateType string `json:"predicateType"`
33+
TypeV01 string `json:"_type"`
34+
PredicateTypeV01 string `json:"predicateType"`
35+
TypeV1 string `json:"type"`
36+
PredicateTypeV1 string `json:"predicate_type"`
3237
}
3338

3439
type ITE6Processor struct {
@@ -63,5 +68,9 @@ func parseStatement(p []byte) (*ite6Statement, error) {
6368
if err := json.Unmarshal(p, &ps); err != nil {
6469
return nil, err
6570
}
71+
// Reject documents where neither format's fields are populated.
72+
if ps.TypeV01 == "" && ps.TypeV1 == "" {
73+
return nil, fmt.Errorf("in-toto statement has neither v0.1 (_type) nor v1 (type) statement type field")
74+
}
6675
return &ps, nil
6776
}

pkg/ingestor/parser/slsa/parser_slsa.go

Lines changed: 6 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,7 @@ import (
1919
"context"
2020
"errors"
2121
"fmt"
22-
2322
"strings"
24-
"time"
2523

2624
jsoniter "github.com/json-iterator/go"
2725

@@ -42,81 +40,14 @@ import (
4240
// - a pkg or source depending on what is represented by the name/URI
4341
// - An IsOccurence input spec which will generate a predicate for each occurence
4442

45-
// DigestSet is a set of digests keyed by algorithm name (e.g. "sha256").
46-
type DigestSet = map[string]string
47-
48-
// ProvenanceMaterial represents a material used in a provenance attestation.
49-
type ProvenanceMaterial struct {
50-
URI string `json:"uri"`
51-
Digest DigestSet `json:"digest,omitempty"`
52-
}
53-
54-
// ProvenanceBuilder identifies the entity that executed the build steps.
55-
type ProvenanceBuilder struct {
56-
ID string `json:"id"`
57-
}
58-
5943
const (
6044
PredicateSLSAProvenanceV01 = "https://slsa.dev/provenance/v0.1"
6145
PredicateSLSAProvenanceV02 = "https://slsa.dev/provenance/v0.2"
6246

63-
// PredicateSLSAProvenancev1 is the predicate type for SLSAv1.0 provenance.
64-
PredicateSLSAProvenancev1 = "https://slsa.dev/provenance/v1"
47+
// PredicateSLSAProvenanceV1 is the predicate type for SLSAv1.0 provenance.
48+
PredicateSLSAProvenanceV1 = "https://slsa.dev/provenance/v1"
6549
)
6650

67-
// ProvenancePredicateV01 is the SLSA v0.1 provenance predicate.
68-
type ProvenancePredicateV01 struct {
69-
Builder ProvenanceBuilder `json:"builder"`
70-
Recipe ProvenanceRecipe `json:"recipe"`
71-
Metadata *ProvenanceMetadataV01 `json:"metadata,omitempty"`
72-
Materials []ProvenanceMaterial `json:"materials,omitempty"`
73-
}
74-
75-
// ProvenanceRecipe describes how the artifact was produced (SLSA v0.1).
76-
type ProvenanceRecipe struct {
77-
Type string `json:"type"`
78-
DefinedInMaterial *int `json:"definedInMaterial,omitempty"`
79-
EntryPoint string `json:"entryPoint,omitempty"`
80-
Arguments interface{} `json:"arguments,omitempty"`
81-
Environment interface{} `json:"environment,omitempty"`
82-
}
83-
84-
// ProvenanceMetadataV01 holds build metadata for SLSA v0.1 provenance.
85-
type ProvenanceMetadataV01 struct {
86-
BuildInvocationID string `json:"buildInvocationId,omitempty"`
87-
BuildStartedOn *time.Time `json:"buildStartedOn,omitempty"`
88-
BuildFinishedOn *time.Time `json:"buildFinishedOn,omitempty"`
89-
Completeness struct {
90-
Arguments bool `json:"arguments"`
91-
Environment bool `json:"environment"`
92-
Materials bool `json:"materials"`
93-
} `json:"completeness"`
94-
Reproducible bool `json:"reproducible"`
95-
}
96-
97-
// ProvenancePredicateV02 is the SLSA v0.2 provenance predicate.
98-
type ProvenancePredicateV02 struct {
99-
Builder ProvenanceBuilder `json:"builder"`
100-
BuildType string `json:"buildType"`
101-
Invocation interface{} `json:"invocation,omitempty"`
102-
BuildConfig interface{} `json:"buildConfig,omitempty"`
103-
Metadata *ProvenanceMetadataV02 `json:"metadata,omitempty"`
104-
Materials []ProvenanceMaterial `json:"materials,omitempty"`
105-
}
106-
107-
// ProvenanceMetadataV02 holds build metadata for SLSA v0.2 provenance.
108-
type ProvenanceMetadataV02 struct {
109-
BuildInvocationID string `json:"buildInvocationId,omitempty"`
110-
BuildStartedOn *time.Time `json:"buildStartedOn,omitempty"`
111-
BuildFinishedOn *time.Time `json:"buildFinishedOn,omitempty"`
112-
Completeness struct {
113-
Parameters bool `json:"parameters"`
114-
Environment bool `json:"environment"`
115-
Materials bool `json:"materials"`
116-
} `json:"completeness"`
117-
Reproducible bool `json:"reproducible"`
118-
}
119-
12051
var ErrMetadataNil = errors.New("SLSA Metadata is nil")
12152
var ErrBuilderNil = errors.New("SLSA Builder is nil")
12253
var json = jsoniter.ConfigCompatibleWithStandardLibrary
@@ -209,7 +140,7 @@ func (s *slsaParser) getMaterials() error {
209140
if err := s.getMaterials0(s.pred02.Materials); err != nil {
210141
return err
211142
}
212-
case PredicateSLSAProvenancev1:
143+
case PredicateSLSAProvenanceV1:
213144
if s.pred1.BuildDefinition == nil {
214145
return errors.New("SLSA1 buildDefinition is nil")
215146
}
@@ -370,7 +301,7 @@ func (s *slsaParser) getSLSA() error {
370301
if data, err = json.Marshal(s.pred02); err != nil {
371302
return fmt.Errorf("could not marshal SLSA02: %w", err)
372303
}
373-
case PredicateSLSAProvenancev1:
304+
case PredicateSLSAProvenanceV1:
374305
if err := fillSLSA1(inp, s.pred1); err != nil {
375306
return fmt.Errorf("could not fill SLSA1: %w", err)
376307
}
@@ -409,7 +340,7 @@ func (s *slsaParser) getBuilder() error {
409340
s.builder.Uri = s.pred01.Builder.ID
410341
case PredicateSLSAProvenanceV02:
411342
s.builder.Uri = s.pred02.Builder.ID
412-
case PredicateSLSAProvenancev1:
343+
case PredicateSLSAProvenanceV1:
413344
if s.pred1.RunDetails == nil || s.pred1.RunDetails.Builder == nil {
414345
return ErrBuilderNil
415346
}
@@ -440,7 +371,7 @@ func (s *slsaParser) parseSlsaPredicate(p []byte) error {
440371
if err := json.Unmarshal(predBytes, s.pred02); err != nil {
441372
return fmt.Errorf("Could not unmarshal v0.2 SLSA provenance statement : %w", err)
442373
}
443-
case PredicateSLSAProvenancev1:
374+
case PredicateSLSAProvenanceV1:
444375
s.pred1 = &slsa1.Provenance{}
445376
if err := protojson.Unmarshal(predBytes, s.pred1); err != nil {
446377
return fmt.Errorf("Could not unmarshal v1.0 SLSA provenance statement : %w", err)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//
2+
// Copyright 2022 The GUAC Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package slsa
17+
18+
import "time"
19+
20+
// This file contains local copies of types originally defined in the deprecated
21+
// github.com/in-toto/in-toto-golang library. They are kept here to support
22+
// SLSA v0.1 and v0.2 provenance parsing until those formats are dropped.
23+
//
24+
// Original definitions can be found in:
25+
// https://github.com/in-toto/in-toto-golang
26+
//
27+
// TODO: delete this file when SLSA v0.1/v0.2 support is dropped.
28+
29+
// DigestSet is a set of digests keyed by algorithm name (e.g. "sha256").
30+
type DigestSet = map[string]string
31+
32+
// ProvenanceMaterial represents a material used in a provenance attestation.
33+
type ProvenanceMaterial struct {
34+
URI string `json:"uri"`
35+
Digest DigestSet `json:"digest,omitempty"`
36+
}
37+
38+
// ProvenanceBuilder identifies the entity that executed the build steps.
39+
type ProvenanceBuilder struct {
40+
ID string `json:"id"`
41+
}
42+
43+
// ProvenanceRecipe describes how the artifact was produced (SLSA v0.1).
44+
type ProvenanceRecipe struct {
45+
Type string `json:"type"`
46+
DefinedInMaterial *int `json:"definedInMaterial,omitempty"`
47+
EntryPoint string `json:"entryPoint,omitempty"`
48+
Arguments interface{} `json:"arguments,omitempty"`
49+
Environment interface{} `json:"environment,omitempty"`
50+
}
51+
52+
// CompletenessV01 tracks which fields are complete for SLSA v0.1 metadata.
53+
type CompletenessV01 struct {
54+
Arguments bool `json:"arguments"`
55+
Environment bool `json:"environment"`
56+
Materials bool `json:"materials"`
57+
}
58+
59+
// ProvenanceMetadataV01 holds build metadata for SLSA v0.1 provenance.
60+
type ProvenanceMetadataV01 struct {
61+
BuildInvocationID string `json:"buildInvocationId,omitempty"`
62+
BuildStartedOn *time.Time `json:"buildStartedOn,omitempty"`
63+
BuildFinishedOn *time.Time `json:"buildFinishedOn,omitempty"`
64+
Completeness CompletenessV01 `json:"completeness"`
65+
Reproducible bool `json:"reproducible"`
66+
}
67+
68+
// ProvenancePredicateV01 is the SLSA v0.1 provenance predicate.
69+
type ProvenancePredicateV01 struct {
70+
Builder ProvenanceBuilder `json:"builder"`
71+
Recipe ProvenanceRecipe `json:"recipe"`
72+
Metadata *ProvenanceMetadataV01 `json:"metadata,omitempty"`
73+
Materials []ProvenanceMaterial `json:"materials,omitempty"`
74+
}
75+
76+
// CompletenessV02 tracks which fields are complete for SLSA v0.2 metadata.
77+
// Note: field set differs from CompletenessV01 (Parameters instead of Arguments).
78+
type CompletenessV02 struct {
79+
Parameters bool `json:"parameters"`
80+
Environment bool `json:"environment"`
81+
Materials bool `json:"materials"`
82+
}
83+
84+
// ProvenanceMetadataV02 holds build metadata for SLSA v0.2 provenance.
85+
type ProvenanceMetadataV02 struct {
86+
BuildInvocationID string `json:"buildInvocationId,omitempty"`
87+
BuildStartedOn *time.Time `json:"buildStartedOn,omitempty"`
88+
BuildFinishedOn *time.Time `json:"buildFinishedOn,omitempty"`
89+
Completeness CompletenessV02 `json:"completeness"`
90+
Reproducible bool `json:"reproducible"`
91+
}
92+
93+
// ProvenancePredicateV02 is the SLSA v0.2 provenance predicate.
94+
type ProvenancePredicateV02 struct {
95+
Builder ProvenanceBuilder `json:"builder"`
96+
BuildType string `json:"buildType"`
97+
Invocation interface{} `json:"invocation,omitempty"`
98+
BuildConfig interface{} `json:"buildConfig,omitempty"`
99+
Metadata *ProvenanceMetadataV02 `json:"metadata,omitempty"`
100+
Materials []ProvenanceMaterial `json:"materials,omitempty"`
101+
}

pkg/ingestor/verifier/sigstore_verifier/sigstore_verifier_test.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,38 +41,53 @@ import (
4141
const PayloadType = "application/vnd.in-toto+json"
4242

4343
// StatementInTotoV01 is the in-toto v0.1 statement type.
44+
// Mirrors the canonical upstream type URI from github.com/in-toto/in-toto-golang.
4445
const StatementInTotoV01 = "https://in-toto.io/Statement/v0.1"
4546

4647
// predicateSLSAProvenanceV02 is the predicate type for SLSAv0.2 provenance.
48+
// Mirrors parser_slsa.PredicateSLSAProvenanceV02.
4749
const predicateSLSAProvenanceV02 = "https://slsa.dev/provenance/v0.2"
4850

49-
// digestSet is a set of digests keyed by algorithm name.
51+
// digestSet is a set of digests keyed by algorithm name (e.g. "sha256").
52+
// Mirrors the DigestSet type from github.com/in-toto/in-toto-golang/in_toto.
5053
type digestSet = map[string]string
5154

5255
// provenanceBuilder identifies the entity that executed the build steps.
56+
// Mirrors the ProvenanceBuilder type from github.com/in-toto/in-toto-golang/in_toto
57+
// with the same JSON field name to ensure the test exercises the correct wire format.
5358
type provenanceBuilder struct {
5459
ID string `json:"id"`
5560
}
5661

5762
// subject describes the set of software artifacts the statement applies to.
63+
// Mirrors the Subject type from github.com/in-toto/in-toto-golang/in_toto
64+
// with the same JSON field names to ensure the test exercises the correct wire format.
5865
type subject struct {
5966
Name string `json:"name"`
6067
Digest digestSet `json:"digest"`
6168
}
6269

63-
// statementHeader defines the common fields for all statements.
70+
// statementHeader defines the common fields for all in-toto v0.1 statements.
71+
// Mirrors the StatementHeader type from github.com/in-toto/in-toto-golang/in_toto
72+
// with identical JSON tags (_type, predicateType, subject) to exercise the
73+
// exact wire format the verifier processes in production.
6474
type statementHeader struct {
6575
Type string `json:"_type"`
6676
PredicateType string `json:"predicateType"`
6777
Subject []subject `json:"subject"`
6878
}
6979

70-
// provenancePredicate is the SLSA v0.2 provenance predicate (simplified for testing).
80+
// provenancePredicate is the SLSA v0.2 provenance predicate.
81+
// Mirrors the ProvenancePredicate type from github.com/in-toto/in-toto-golang/in_toto
82+
// (simplified to only the fields needed for signing/verification testing).
7183
type provenancePredicate struct {
7284
Builder provenanceBuilder `json:"builder"`
7385
}
7486

75-
// provenanceStatement is the definition for an entire provenance statement (for testing).
87+
// provenanceStatement is the complete in-toto v0.1 provenance statement.
88+
// Mirrors the ProvenanceStatement type from github.com/in-toto/in-toto-golang/in_toto
89+
// with the same embedded statementHeader and JSON field names to ensure
90+
// the test exercises the exact format the verifier consumes in production.
7691
type provenanceStatement struct {
7792
statementHeader
7893
Predicate provenancePredicate `json:"predicate"`

0 commit comments

Comments
 (0)