Skip to content

Commit

Permalink
Merge pull request #106 from deeglaze/coverage
Browse files Browse the repository at this point in the history
Fix tools/lib/report issues
  • Loading branch information
deeglaze authored Feb 6, 2024
2 parents 3ee8fc6 + ac86ea4 commit b0523ea
Show file tree
Hide file tree
Showing 4 changed files with 230 additions and 7 deletions.
2 changes: 1 addition & 1 deletion tools/check/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ func main() {
die(errors.New("cannot specify both -check_crl=true and -network=false"))
}

attestation, err := report.GetAttestation(*infile, *inform)
attestation, err := report.ReadAttestation(*infile, *inform)
if err != nil {
die(err)
}
Expand Down
22 changes: 17 additions & 5 deletions tools/lib/report/report.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package report provides functions for reading and writing attestation reports of various formats.
package report

import (
"errors"
"fmt"
"io"
"os"
Expand Down Expand Up @@ -66,15 +79,14 @@ func ParseAttestation(b []byte, inform string) (*spb.Attestation, error) {
return nil, fmt.Errorf("could not parse as textproto: %v", multierr.Append(aerr, rerr))
}
}
return result, nil
default:
return nil, fmt.Errorf("unknown inform: %q", inform)
}
// This should be impossible.
return nil, errors.New("internal error")
}

// GetAttestation reads an attestation report from a file.
func GetAttestation(infile, inform string) (*spb.Attestation, error) {
// ReadAttestation reads an attestation report from a file.
func ReadAttestation(infile, inform string) (*spb.Attestation, error) {
var in io.Reader
var f *os.File
if infile == "-" {
Expand Down
197 changes: 197 additions & 0 deletions tools/lib/report/report_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package report

import (
"bytes"
"fmt"
"os"
"path"
"sync"
"testing"
"time"

"github.com/google/go-sev-guest/abi"
"github.com/google/go-sev-guest/client"
spb "github.com/google/go-sev-guest/proto/sevsnp"
test "github.com/google/go-sev-guest/testing"
"google.golang.org/protobuf/encoding/prototext"
"google.golang.org/protobuf/proto"
)

var qp client.QuoteProvider
var mu sync.Once

type reports struct {
attestation *spb.Attestation
bincerts []byte
binreport []byte
protocerts []byte
protoreport []byte
textcerts []byte
textreport []byte
}

var input *reports

func initDevice() {
now := time.Date(2022, time.May, 3, 9, 0, 0, 0, time.UTC)
tests := test.TestCases()
ones32 := make([]byte, 32)
for i := range ones32 {
ones32[i] = 1
}
opts := &test.DeviceOptions{Now: now}
tcqp, err := test.TcQuoteProvider(tests, opts)
if err != nil {
panic(fmt.Sprintf("failed to create test device: %v", err))
}
qp = tcqp

var zeros [abi.ReportDataSize]byte
bincerts, err := qp.GetRawQuote(zeros)
if err != nil {
panic(fmt.Errorf("mock failed to quote: %v", err))
}
if len(bincerts) < abi.ReportSize+abi.CertTableEntrySize {
panic("mock failed to return cert table")
}
binreport := bincerts[:abi.ReportSize]
attestation, err := ParseAttestation(bincerts, "bin")
if err != nil {
panic(fmt.Errorf("marshal failure: %v", err))
}
protocerts, err := proto.Marshal(attestation)
if err != nil {
panic(fmt.Errorf("marshal failure: %v", err))
}
protoreport, err := proto.Marshal(attestation.Report)
if err != nil {
panic(fmt.Errorf("marshal failure: %v", err))
}
textcerts, err := prototext.MarshalOptions{Multiline: true, Indent: " "}.Marshal(attestation)
if err != nil {
panic(fmt.Errorf("marshal failure: %v", err))
}
textreport, err := prototext.MarshalOptions{Multiline: true, Indent: " "}.Marshal(attestation.Report)
if err != nil {
panic(fmt.Errorf("marshal failure: %v", err))
}
input = &reports{
attestation: attestation,
bincerts: bincerts,
binreport: binreport,
protocerts: protocerts,
protoreport: protoreport,
textcerts: textcerts,
textreport: textreport,
}
}

func TestParseAttestation(t *testing.T) {
mu.Do(initDevice)
type testcase struct {
input []byte
inform string
}
good := []testcase{
{input.bincerts, "bin"},
{input.binreport, "bin"},
{input.protocerts, "proto"},
{input.protoreport, "proto"},
{input.textcerts, "textproto"},
{input.textreport, "textproto"},
}
bad := []testcase{
{input.bincerts, "proto"},
{input.textcerts, "bin"},
{input.protoreport, "textproto"},
}
for _, tc := range good {
if _, err := ParseAttestation(tc.input, tc.inform); err != nil {
t.Fatalf("ParseAttestation(_, %q) = _, %v. Expect nil", tc.inform, err)
}
}
for _, tc := range bad {
if _, err := ParseAttestation(tc.input, tc.inform); err == nil {
t.Fatalf("ParseAttestation(_, %q) = _, nil. Expected an error", tc.inform)
}
}
}

func TestReadAttestation(t *testing.T) {
mu.Do(initDevice)
type testcase struct {
input []byte
inform string
}
good := []testcase{
{input.bincerts, "bin"},
{input.binreport, "bin"},
{input.protocerts, "proto"},
{input.protoreport, "proto"},
{input.textcerts, "textproto"},
{input.textreport, "textproto"},
}
bad := []testcase{
{input.bincerts, "proto"},
{input.textcerts, "bin"},
{input.protoreport, "textproto"},
}
for _, tc := range good {
p := path.Join(t.TempDir(), "input")
if err := os.WriteFile(p, tc.input, 0644); err != nil {
t.Fatalf("Could not write test file %q: %v", p, err)
}
if _, err := ReadAttestation(p, tc.inform); err != nil {
t.Fatalf("ParseAttestation(_, %q) = _, %v. Expect nil", tc.inform, err)
}
}
for _, tc := range bad {
p := path.Join(t.TempDir(), "input")
if err := os.WriteFile(p, tc.input, 0644); err != nil {
t.Fatalf("Could not write test file %q: %v", p, err)
}
if _, err := ReadAttestation(p, tc.inform); err == nil {
t.Fatalf("ReadAttestation(_, %q) = _, nil. Expected an error", tc.inform)
}
}
}

func TestTransform(t *testing.T) {
mu.Do(initDevice)
binout, err := Transform(input.attestation, "bin")
if err != nil {
t.Fatalf("Transform(_, \"bin\") = _, %v. Expect nil.", err)
}
if !bytes.Equal(binout, input.bincerts) {
t.Fatalf("Transform(_, \"bin\") = %v, nil. Expect %v.", binout, input.bincerts)
}
protoout, err := Transform(input.attestation, "proto")
if err != nil {
t.Fatalf("Transform(_, \"proto\") = _, %v. Expect nil.", err)
}
if !bytes.Equal(protoout, input.protocerts) {
t.Fatalf("Transform(_, \"proto\") = %v, nil. Expect %v.", protoout, input.protocerts)
}
textout, err := Transform(input.attestation, "textproto")
if err != nil {
t.Fatalf("Transform(_, \"textproto\") = _, %v. Expect nil.", err)
}
if !bytes.Equal(textout, input.textcerts) {
t.Fatalf("Transform(_, \"textproto\") = %v, nil. Expect %v.", string(textout), string(input.textcerts))
}

}
16 changes: 15 additions & 1 deletion tools/show/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// show reads an attestation report and outputs it in a preferred format.
package main

Expand All @@ -22,7 +36,7 @@ func main() {
logger.Init("", false, false, os.Stderr)
flag.Parse()

attestation, err := report.GetAttestation(*infile, *inform)
attestation, err := report.ReadAttestation(*infile, *inform)
if err != nil {
logger.Fatal(err)
}
Expand Down

0 comments on commit b0523ea

Please sign in to comment.