diff --git a/cmd/rekor-cli/app/get.go b/cmd/rekor-cli/app/get.go index 440b10a18..b75f8a5b5 100644 --- a/cmd/rekor-cli/app/get.go +++ b/cmd/rekor-cli/app/get.go @@ -159,7 +159,7 @@ func parseEntry(uuid string, e models.LogEntryAnon) (interface{}, error) { if err != nil { return nil, err } - eimpl, err := types.NewEntry(pe) + eimpl, err := types.UnmarshalEntry(pe) if err != nil { return nil, err } diff --git a/pkg/api/entries.go b/pkg/api/entries.go index 3225ed652..dac3be04f 100644 --- a/pkg/api/entries.go +++ b/pkg/api/entries.go @@ -101,7 +101,7 @@ func logEntryFromLeaf(ctx context.Context, signer signature.Signer, tc TrillianC if err != nil { return nil, err } - eimpl, err := types.NewEntry(pe) + eimpl, err := types.UnmarshalEntry(pe) if err != nil { return nil, err } @@ -161,7 +161,7 @@ func GetLogEntryByIndexHandler(params entries.GetLogEntryByIndexParams) middlewa func createLogEntry(params entries.CreateLogEntryParams) (models.LogEntry, middleware.Responder) { ctx := params.HTTPRequest.Context() - entry, err := types.NewEntry(params.ProposedEntry) + entry, err := types.CreateVersionedEntry(params.ProposedEntry) if err != nil { return nil, handleRekorAPIError(params, http.StatusBadRequest, err, fmt.Sprintf(validationError, err)) } @@ -341,7 +341,7 @@ func SearchLogQueryHandler(params entries.SearchLogQueryParams) middleware.Respo for _, e := range params.Entry.Entries() { e := e // https://golang.org/doc/faq#closures_and_goroutines g.Go(func() error { - entry, err := types.NewEntry(e) + entry, err := types.UnmarshalEntry(e) if err != nil { return err } diff --git a/pkg/types/README.md b/pkg/types/README.md index f77f2408c..81246c449 100644 --- a/pkg/types/README.md +++ b/pkg/types/README.md @@ -8,6 +8,10 @@ Rekor supports pluggable types (aka different schemas) for entries stored in the - Alpine Packages [schema](alpine/alpine_schema.json) - Versions: 0.0.1 +- COSE Envelopes [schema](cose/cose_schema.json) + - Versions: 0.0.1 +- HashedRekord [schema](hashedrekord/hashedrekord_schema.json) + - Versions: 0.0.1 - Helm Provenance Files [schema](helm/helm_schema.json) - Versions: 0.0.1 - In-Toto Attestations [schema](intoto/intoto_schema.json) @@ -20,7 +24,7 @@ Rekor supports pluggable types (aka different schemas) for entries stored in the - Versions: 0.0.1 - RPM Packages [schema](rpm/rpm_schema.json) - Versions: 0.0.1 -- COSE Envelopes [schema](cose/cose_schema.json) +- TUF Metadata [schema](tuf/tuf_schema.json) - Versions: 0.0.1 Refer to [Rekor docs](https://docs.sigstore.dev/rekor/pluggable-types) for adding support for new types. diff --git a/pkg/types/alpine/v0.0.1/entry_test.go b/pkg/types/alpine/v0.0.1/entry_test.go index d53e0f326..153e748ea 100644 --- a/pkg/types/alpine/v0.0.1/entry_test.go +++ b/pkg/types/alpine/v0.0.1/entry_test.go @@ -157,7 +157,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/entries.go b/pkg/types/entries.go index 529ede070..cda7f2782 100644 --- a/pkg/types/entries.go +++ b/pkg/types/entries.go @@ -59,8 +59,28 @@ func NewProposedEntry(ctx context.Context, kind, version string, props ArtifactP return nil, fmt.Errorf("could not create entry for kind '%v'", kind) } -// NewEntry returns the specific instance for the type and version specified in the doc -func NewEntry(pe models.ProposedEntry) (EntryImpl, error) { +// CreateVersionedEntry returns the specific instance for the type and version specified in the doc +// This method should be used on the insertion flow, which validates that the specific version proposed +// is permitted to be entered into the log. +func CreateVersionedEntry(pe models.ProposedEntry) (EntryImpl, error) { + ei, err := UnmarshalEntry(pe) + if err != nil { + return nil, err + } + kind := pe.Kind() + if tf, found := TypeMap.Load(kind); found { + if !tf.(func() TypeImpl)().IsSupportedVersion(ei.APIVersion()) { + return nil, fmt.Errorf("entry kind '%v' does not support inserting entries of version '%v'", kind, ei.APIVersion()) + } + } + + return ei, nil +} + +// UnmarshalEntry returns the specific instance for the type and version specified in the doc +// This method does not check for whether the version of the entry could be currently inserted into the log, +// and is useful when dealing with entries that have been persisted to the log. +func UnmarshalEntry(pe models.ProposedEntry) (EntryImpl, error) { if pe == nil { return nil, errors.New("proposed entry cannot be nil") } @@ -73,7 +93,7 @@ func NewEntry(pe models.ProposedEntry) (EntryImpl, error) { } return t.UnmarshalEntry(pe) } - return nil, fmt.Errorf("could not create entry for kind '%v'", kind) + return nil, fmt.Errorf("could not unmarshal entry for kind '%v'", kind) } // DecodeEntry maps the (abstract) input structure into the specific entry implementation class; diff --git a/pkg/types/hashedrekord/v0.0.1/entry_test.go b/pkg/types/hashedrekord/v0.0.1/entry_test.go index 99b1177d7..72a55d61c 100644 --- a/pkg/types/hashedrekord/v0.0.1/entry_test.go +++ b/pkg/types/hashedrekord/v0.0.1/entry_test.go @@ -285,7 +285,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/helm/v0.0.1/entry_test.go b/pkg/types/helm/v0.0.1/entry_test.go index 655e7b544..69eb38f8f 100644 --- a/pkg/types/helm/v0.0.1/entry_test.go +++ b/pkg/types/helm/v0.0.1/entry_test.go @@ -188,7 +188,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/intoto/v0.0.1/entry_test.go b/pkg/types/intoto/v0.0.1/entry_test.go index 5d4151e62..f01b85450 100644 --- a/pkg/types/intoto/v0.0.1/entry_test.go +++ b/pkg/types/intoto/v0.0.1/entry_test.go @@ -270,7 +270,7 @@ func TestV001Entry_Unmarshal(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tt.name, err) } - canonicalEntry, err := types.NewEntry(pe) + canonicalEntry, err := types.UnmarshalEntry(pe) if err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tt.name, err) } diff --git a/pkg/types/jar/v0.0.1/entry_test.go b/pkg/types/jar/v0.0.1/entry_test.go index e56c62e28..42ff5337d 100644 --- a/pkg/types/jar/v0.0.1/entry_test.go +++ b/pkg/types/jar/v0.0.1/entry_test.go @@ -108,7 +108,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/rekord/v0.0.1/entry_test.go b/pkg/types/rekord/v0.0.1/entry_test.go index d0d7cee42..0e79731f7 100644 --- a/pkg/types/rekord/v0.0.1/entry_test.go +++ b/pkg/types/rekord/v0.0.1/entry_test.go @@ -233,7 +233,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/rfc3161/v0.0.1/entry_test.go b/pkg/types/rfc3161/v0.0.1/entry_test.go index 72f90d8b7..9f39f5bca 100644 --- a/pkg/types/rfc3161/v0.0.1/entry_test.go +++ b/pkg/types/rfc3161/v0.0.1/entry_test.go @@ -182,7 +182,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/rpm/v0.0.1/entry_test.go b/pkg/types/rpm/v0.0.1/entry_test.go index 6819ee459..3e5087379 100644 --- a/pkg/types/rpm/v0.0.1/entry_test.go +++ b/pkg/types/rpm/v0.0.1/entry_test.go @@ -173,7 +173,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/tuf/v0.0.1/entry_test.go b/pkg/types/tuf/v0.0.1/entry_test.go index 4dbc16c39..f8d090f6a 100644 --- a/pkg/types/tuf/v0.0.1/entry_test.go +++ b/pkg/types/tuf/v0.0.1/entry_test.go @@ -208,7 +208,7 @@ func TestCrossFieldValidation(t *testing.T) { if err != nil { t.Errorf("unexpected err from Unmarshalling canonicalized entry for '%v': %v", tc.caseDesc, err) } - if _, err := types.NewEntry(pe); err != nil { + if _, err := types.UnmarshalEntry(pe); err != nil { t.Errorf("unexpected err from type-specific unmarshalling for '%v': %v", tc.caseDesc, err) } } diff --git a/pkg/types/types_test.go b/pkg/types/types_test.go index 9be029fcf..ea7c5302e 100644 --- a/pkg/types/types_test.go +++ b/pkg/types/types_test.go @@ -65,7 +65,7 @@ func (e UnmarshalErrorValidEntry) ContextValidate(context context.Context, forma return nil } -func TestNewEntry(t *testing.T) { +func TestUnmarshalEntry(t *testing.T) { type TestCase struct { entry models.ProposedEntry expectSuccess bool @@ -83,7 +83,7 @@ func TestNewEntry(t *testing.T) { } for _, tc := range testCases { - if _, err := NewEntry(tc.entry); (err == nil) != tc.expectSuccess { + if _, err := UnmarshalEntry(tc.entry); (err == nil) != tc.expectSuccess { t.Errorf("unexpected error creating entry of type '%v': %v", tc.entry.Kind(), err) } }