NOISSUE - Add path to expected PCR values (#398)
CI / ci (push) Has been cancelled
Rust CI Pipeline / rust-check (push) Has been cancelled

* add path to expected PCR values

* change rust scrtip for attestation policy to print policy to stdout

* fix cli test

* remove stdout from cmd config struct

* fix manager test

* fix manager readme
This commit is contained in:
Danko Miladinovic
2025-03-17 12:25:42 +01:00
committed by GitHub
parent 33744a12a8
commit 293c65a3aa
22 changed files with 205 additions and 160 deletions
@@ -1,48 +1,46 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package igvmmeasure
package cmdconfig
import (
"bytes"
"fmt"
"io"
"os/exec"
"strings"
)
var IgvmMeasureOptions = []string{"measure", "-b"}
type MeasurementProvider interface {
Run(igvmBinaryPath string) error
Run(binaryPath string) ([]byte, error)
Stop() error
}
type IgvmMeasurement struct {
type CmdConfig struct {
binPath string
options []string
stderr io.Writer
stdout io.Writer
cmd *exec.Cmd
execCommand func(name string, arg ...string) *exec.Cmd
}
func NewIgvmMeasurement(binPath string, stderr, stdout io.Writer) (*IgvmMeasurement, error) {
func NewCmdConfig(binPath string, options []string, stderr io.Writer) (*CmdConfig, error) {
if binPath == "" {
return nil, fmt.Errorf("pathToBinary cannot be empty")
}
return &IgvmMeasurement{
return &CmdConfig{
binPath: binPath,
options: options,
stderr: stderr,
stdout: stdout,
execCommand: exec.Command,
}, nil
}
func (m *IgvmMeasurement) Run(pathToFile string) error {
func (m *CmdConfig) Run(pathToFile string) ([]byte, error) {
binary := m.binPath
args := []string{}
args = append(args, m.options...)
args = append(args, pathToFile)
args = append(args, "measure")
args = append(args, "-b")
args = append(args, m.options...)
outBuf := &bytes.Buffer{}
cmd := m.execCommand(binary, args...)
@@ -50,26 +48,13 @@ func (m *IgvmMeasurement) Run(pathToFile string) error {
cmd.Stdout = outBuf
if err := cmd.Run(); err != nil {
return err
}
outputString := outBuf.String()
lines := strings.Split(strings.TrimSpace(outputString), "\n")
if len(lines) == 1 {
outputString = strings.ToLower(outputString)
_, err := m.stdout.Write([]byte(outputString))
if err != nil {
return err
}
} else {
return fmt.Errorf("error: %s", outputString)
return nil, err
}
return nil
return outBuf.Bytes(), nil
}
func (m *IgvmMeasurement) Stop() error {
func (m *CmdConfig) Stop() error {
if m.cmd == nil || m.cmd.Process == nil {
return fmt.Errorf("no running process to stop")
}
@@ -82,6 +67,6 @@ func (m *IgvmMeasurement) Stop() error {
}
// SetExecCommand allows tests to inject a mock execCommand function.
func (m *IgvmMeasurement) SetExecCommand(cmdFunc func(name string, arg ...string) *exec.Cmd) {
func (m *CmdConfig) SetExecCommand(cmdFunc func(name string, arg ...string) *exec.Cmd) {
m.execCommand = cmdFunc
}
@@ -1,6 +1,6 @@
// Copyright (c) Ultraviolet
// SPDX-License-Identifier: Apache-2.0
package igvmmeasure
package cmdconfig
import (
"bytes"
@@ -14,15 +14,15 @@ import (
func TestIgvmMeasurement(t *testing.T) {
tests := []struct {
name string
setup func() *IgvmMeasurement
setup func() *CmdConfig
runArgs string
expectErr bool
expectedErr string
}{
{
name: "NewIgvmMeasurement - Empty pathToBinary",
setup: func() *IgvmMeasurement {
igvm, err := NewIgvmMeasurement("", nil, nil)
setup: func() *CmdConfig {
igvm, err := NewCmdConfig("", []string{""}, nil)
assert.Error(t, err)
assert.Nil(t, igvm)
return nil
@@ -32,8 +32,8 @@ func TestIgvmMeasurement(t *testing.T) {
},
{
name: "Run - Successful Execution",
setup: func() *IgvmMeasurement {
igvm, _ := NewIgvmMeasurement("/valid/path", nil, nil)
setup: func() *CmdConfig {
igvm, _ := NewCmdConfig("/valid/path", []string{""}, nil)
igvm.SetExecCommand(func(name string, arg ...string) *exec.Cmd {
return exec.Command("sh", "-c", "echo 'measurement successful'")
})
@@ -43,8 +43,8 @@ func TestIgvmMeasurement(t *testing.T) {
},
{
name: "Run - Failure Execution",
setup: func() *IgvmMeasurement {
igvm, _ := NewIgvmMeasurement("/invalid/path", nil, nil)
setup: func() *CmdConfig {
igvm, _ := NewCmdConfig("/invalid/path", []string{""}, nil)
igvm.SetExecCommand(func(name string, arg ...string) *exec.Cmd {
return exec.Command("sh", "-c", "echo 'some error occurred\nextra line' && exit 1")
})
@@ -61,10 +61,9 @@ func TestIgvmMeasurement(t *testing.T) {
if igvm != nil {
buf := new(bytes.Buffer)
igvm.stdout = buf
igvm.stderr = buf
err := igvm.Run(tc.runArgs)
_, err := igvm.Run(tc.runArgs)
if tc.expectErr {
assert.Error(t, err)
assert.Equal(t, strings.TrimSpace(tc.expectedErr), strings.TrimSpace(err.Error()))
+5 -4
View File
@@ -21,10 +21,11 @@ const (
)
var (
AttestationPolicy = Config{SnpCheck: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &PcrConfig{}}
AttestationPolicy = Config{Config: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &PcrConfig{}}
ErrAttestationPolicyOpen = errors.New("failed to open Attestation Policy file")
ErrAttestationPolicyDecode = errors.New("failed to decode Attestation Policy file")
ErrAttestationPolicyMissing = errors.New("failed due to missing Attestation Policy file")
ErrAttestationPolicyEncode = errors.New("failed to encode the Attestation Policy")
)
type PcrValues struct {
@@ -37,8 +38,8 @@ type PcrConfig struct {
}
type Config struct {
SnpCheck *check.Config
PcrConfig *PcrConfig
*check.Config
*PcrConfig
}
func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config) error {
@@ -57,7 +58,7 @@ func ReadAttestationPolicy(policyPath string, attestationConfiguration *Config)
func ReadAttestationPolicyFromByte(policyData []byte, attestationConfiguration *Config) error {
unmarshalOptions := protojson.UnmarshalOptions{AllowPartial: true, DiscardUnknown: true}
if err := unmarshalOptions.Unmarshal(policyData, attestationConfiguration.SnpCheck); err != nil {
if err := unmarshalOptions.Unmarshal(policyData, attestationConfiguration.Config); err != nil {
return errors.Wrap(ErrAttestationPolicyDecode, err)
}
+1 -1
View File
@@ -142,7 +142,7 @@ func GetLeveledQuoteProvider() (client.LeveledQuoteProvider, error) {
}
func VerifyAttestationReportTLS(attestationPB *sevsnp.Attestation, reportData []byte) error {
config, err := copyConfig(config.AttestationPolicy.SnpCheck)
config, err := copyConfig(config.AttestationPolicy.Config)
if err != nil {
return errors.Wrap(fmt.Errorf("failed to create a copy of attestation policy"), err)
}
+11 -11
View File
@@ -145,8 +145,8 @@ func TestVerifyAttestationReportUnknownProduct(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config.AttestationPolicy.SnpCheck.RootOfTrust.ProductLine = ""
config.AttestationPolicy.SnpCheck.Policy.Product = nil
config.AttestationPolicy.Config.RootOfTrust.ProductLine = ""
config.AttestationPolicy.Config.Policy.Product = nil
err := VerifyAttestationReportTLS(tt.attestationReport, tt.reportData)
assert.True(t, errors.Contains(err, tt.err), fmt.Sprintf("expected error %v, got %v", tt.err, err))
})
@@ -192,23 +192,23 @@ func prepVerifyAttReport(t *testing.T) (*sevsnp.Attestation, []byte) {
rr, err := abi.ReportCertsToProto(file)
require.NoError(t, err)
config.AttestationPolicy = config.Config{SnpCheck: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &config.PcrConfig{}}
config.AttestationPolicy = config.Config{Config: &check.Config{Policy: &check.Policy{}, RootOfTrust: &check.RootOfTrust{}}, PcrConfig: &config.PcrConfig{}}
attestationPolicyFile, err := os.ReadFile("../../../scripts/attestation_policy/attestation_policy.json")
require.NoError(t, err)
unmarshalOptions := protojson.UnmarshalOptions{DiscardUnknown: true}
err = unmarshalOptions.Unmarshal(attestationPolicyFile, config.AttestationPolicy.SnpCheck)
err = unmarshalOptions.Unmarshal(attestationPolicyFile, config.AttestationPolicy.Config)
require.NoError(t, err)
config.AttestationPolicy.SnpCheck.Policy.Product = &sevsnp.SevProduct{Name: sevsnp.SevProduct_SEV_PRODUCT_MILAN}
config.AttestationPolicy.SnpCheck.Policy.FamilyId = rr.Report.FamilyId
config.AttestationPolicy.SnpCheck.Policy.ImageId = rr.Report.ImageId
config.AttestationPolicy.SnpCheck.Policy.Measurement = rr.Report.Measurement
config.AttestationPolicy.SnpCheck.Policy.HostData = rr.Report.HostData
config.AttestationPolicy.SnpCheck.Policy.ReportIdMa = rr.Report.ReportIdMa
config.AttestationPolicy.SnpCheck.RootOfTrust.ProductLine = sevProductNameMilan
config.AttestationPolicy.Config.Policy.Product = &sevsnp.SevProduct{Name: sevsnp.SevProduct_SEV_PRODUCT_MILAN}
config.AttestationPolicy.Config.Policy.FamilyId = rr.Report.FamilyId
config.AttestationPolicy.Config.Policy.ImageId = rr.Report.ImageId
config.AttestationPolicy.Config.Policy.Measurement = rr.Report.Measurement
config.AttestationPolicy.Config.Policy.HostData = rr.Report.HostData
config.AttestationPolicy.Config.Policy.ReportIdMa = rr.Report.ReportIdMa
config.AttestationPolicy.Config.RootOfTrust.ProductLine = sevProductNameMilan
return rr, rr.Report.ReportData
}
+3 -3
View File
@@ -251,13 +251,13 @@ func TestReadAttestationPolicy(t *testing.T) {
defer os.Remove(tt.manifestPath)
}
config := att.Config{SnpCheck: &check.Config{}, PcrConfig: &att.PcrConfig{}}
config := att.Config{Config: &check.Config{}, PcrConfig: &att.PcrConfig{}}
err := att.ReadAttestationPolicy(tt.manifestPath, &config)
assert.True(t, errors.Contains(err, tt.err), fmt.Sprintf("expected error %v, got %v", tt.err, err))
if tt.err == nil {
assert.NotNil(t, config.SnpCheck.Policy)
assert.NotNil(t, config.SnpCheck.RootOfTrust)
assert.NotNil(t, config.Config.Policy)
assert.NotNil(t, config.Config.RootOfTrust)
}
})
}