Skip to content

Commit

Permalink
Fix intoto unmarshal (#366)
Browse files Browse the repository at this point in the history
* Fix intoto statement marshal/unmarshal (see in-toto/attestation#363)

Signed-off-by: Andrew Gillis <[email protected]>

* Apply modified tests from be320de

Co-authored-by: Andrew Gillis <[email protected]>
Signed-off-by: Cody Soyland <[email protected]>

* Simplify custom Marshal, remove Unmarshal

Signed-off-by: Cody Soyland <[email protected]>

* Add custom UnmarshalJSON to VerificationResult

Signed-off-by: Cody Soyland <[email protected]>

---------

Signed-off-by: Andrew Gillis <[email protected]>
Signed-off-by: Cody Soyland <[email protected]>
Co-authored-by: Andrew Gillis <[email protected]>
  • Loading branch information
codysoyland and gillisandrew authored Dec 20, 2024
1 parent cd3c718 commit da38613
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 0 deletions.
36 changes: 36 additions & 0 deletions pkg/verify/signed_entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package verify
import (
"crypto/x509"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
"io"
Expand All @@ -26,6 +27,7 @@ import (
"github.com/sigstore/sigstore-go/pkg/fulcio/certificate"
"github.com/sigstore/sigstore-go/pkg/root"
"github.com/sigstore/sigstore/pkg/cryptoutils"
"google.golang.org/protobuf/encoding/protojson"
)

const (
Expand Down Expand Up @@ -221,6 +223,40 @@ func NewVerificationResult() *VerificationResult {
}
}

// MarshalJSON deals with protojson needed for the Statement.
// Can be removed when https://github.com/in-toto/attestation/pull/403 is merged.
func (b *VerificationResult) MarshalJSON() ([]byte, error) {
statement, err := protojson.Marshal(b.Statement)
if err != nil {
return nil, err
}
// creating a type alias to avoid infinite recursion, as MarshalJSON is
// not copied into the alias.
type Alias VerificationResult
return json.Marshal(struct {
Alias
Statement json.RawMessage `json:"statement,omitempty"`
}{
Alias: Alias(*b),
Statement: statement,
})
}

func (b *VerificationResult) UnmarshalJSON(data []byte) error {
b.Statement = &in_toto.Statement{}
type Alias VerificationResult
aux := &struct {
Alias
Statement json.RawMessage `json:"statement,omitempty"`
}{
Alias: Alias(*b),
}
if err := json.Unmarshal(data, aux); err != nil {
return err
}
return protojson.Unmarshal(aux.Statement, b.Statement)
}

type PolicyOption func(*PolicyConfig) error
type ArtifactPolicyOption func(*PolicyConfig) error

Expand Down
52 changes: 52 additions & 0 deletions pkg/verify/signed_entity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ import (
"encoding/hex"
"encoding/json"

in_toto "github.com/in-toto/attestation/go/v1"
"github.com/sigstore/sigstore-go/pkg/testing/data"
"github.com/sigstore/sigstore-go/pkg/verify"
"github.com/stretchr/testify/assert"
"google.golang.org/protobuf/types/known/structpb"
)

func TestSignedEntityVerifierInitialization(t *testing.T) {
Expand Down Expand Up @@ -422,3 +424,53 @@ func TestSigstoreBundle2Sig(t *testing.T) {
assert.True(t, errors.Is(err, verify.ErrDSSEInvalidSignatureCount))
assert.Nil(t, res)
}

func TestStatementSerializesToValidInTotoStatement(t *testing.T) {
statement := in_toto.Statement{}
statement.Type = "https://in-toto.io/Statement/v0.1"
statement.PredicateType = "https://example.org/predicate"
statement.Subject = []*in_toto.ResourceDescriptor{
{
Name: "artifact-name",
Digest: map[string]string{
"sha256": "artifact-digest",
},
},
}
statement.Predicate = &structpb.Struct{
Fields: map[string]*structpb.Value{},
}

result := verify.NewVerificationResult()
result.Statement = &statement

// marshal the statement to JSON
resultJSON, err := json.Marshal(result)
assert.NoError(t, err)
want := `
{
"mediaType": "application/vnd.dev.sigstore.verificationresult+json;version=0.1",
"verifiedTimestamps": null,
"statement": {
"_type": "https://in-toto.io/Statement/v0.1",
"predicateType": "https://example.org/predicate",
"subject": [
{
"name": "artifact-name",
"digest": {
"sha256": "artifact-digest"
}
}
],
"predicate": {}
}
}`
assert.JSONEq(t, want, string(resultJSON))

// unmarshal the JSON back to a VerificationResult
result2 := verify.NewVerificationResult()
err = json.Unmarshal(resultJSON, result2)
assert.NoError(t, err)
assert.Equal(t, result.MediaType, result2.MediaType)
assert.Equal(t, result.Statement, result2.Statement)
}

0 comments on commit da38613

Please sign in to comment.