NOISSUE - Add launch TCB info to VM info (#333)

* add launch TCB to VM info

* add mutex for AP

* add policy info to run test

* fix manager Run test

* add SEV-SNP check
This commit is contained in:
Danko Miladinovic
2024-12-11 15:53:42 +01:00
committed by GitHub
parent 0315e7ddfa
commit e48f184075
10 changed files with 187 additions and 92 deletions
+3 -3
View File
@@ -14,8 +14,8 @@ import (
func TestComputationIDFromAddress(t *testing.T) {
ms := &managerService{
vms: map[string]vm.VM{
"comp1": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}, func(event interface{}) error { return nil }, "comp1"),
"comp2": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 5}}, func(event interface{}) error { return nil }, "comp2"),
"comp1": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}}, func(event interface{}) error { return nil }, "comp1"),
"comp2": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 5}}}, func(event interface{}) error { return nil }, "comp2"),
},
}
@@ -47,7 +47,7 @@ func TestReportBrokenConnection(t *testing.T) {
ms := &managerService{
eventsChan: make(chan *ClientStreamMessage, 1),
vms: map[string]vm.VM{
"comp1": qemu.NewVM(qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}, func(event interface{}) error { return nil }, "comp1"),
"comp1": qemu.NewVM(qemu.VMInfo{Config: qemu.Config{VSockConfig: qemu.VSockConfig{GuestCID: 3}}}, func(event interface{}) error { return nil }, "comp1"),
},
}
+14 -8
View File
@@ -34,17 +34,21 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
return nil, fmt.Errorf("computationId %s not found", computationId)
}
config, ok := vm.GetConfig().(qemu.Config)
vmi, ok := vm.GetConfig().(qemu.VMInfo)
if !ok {
return nil, fmt.Errorf("failed to cast config to qemu.Config")
return nil, fmt.Errorf("failed to cast config to qemu.VMInfo")
}
ms.ap.Lock()
_, err := cmd.Output()
ms.ap.Unlock()
if err != nil {
return nil, err
}
ms.ap.Lock()
f, err := os.ReadFile("./attestation_policy.json")
ms.ap.Unlock()
if err != nil {
return nil, err
}
@@ -57,13 +61,13 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
var measurement []byte
switch {
case config.EnableSEV:
measurement, err = guest.CalcLaunchDigest(guest.SEV, config.SMPCount, uint64(cpuid.CpuSigs[ms.qemuCfg.CPU]), config.OVMFCodeConfig.File, config.KernelFile, config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
case vmi.Config.EnableSEV:
measurement, err = guest.CalcLaunchDigest(guest.SEV, vmi.Config.SMPCount, uint64(cpuid.CpuSigs[ms.qemuCfg.CPU]), vmi.Config.OVMFCodeConfig.File, vmi.Config.KernelFile, vmi.Config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
if err != nil {
return nil, err
}
case config.EnableSEVSNP:
measurement, err = guest.CalcLaunchDigest(guest.SEV_SNP, config.SMPCount, uint64(cpuid.CpuSigs[config.CPU]), config.OVMFCodeConfig.File, config.KernelFile, config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
case vmi.Config.EnableSEVSNP:
measurement, err = guest.CalcLaunchDigest(guest.SEV_SNP, vmi.Config.SMPCount, uint64(cpuid.CpuSigs[vmi.Config.CPU]), vmi.Config.OVMFCodeConfig.File, vmi.Config.KernelFile, vmi.Config.RootFsFile, strconv.Quote(qemu.KernelCommandLine), defGuestFeatures, "", vmmtypes.QEMU, false, "", 0)
if err != nil {
return nil, err
}
@@ -72,14 +76,16 @@ func (ms *managerService) FetchAttestationPolicy(_ context.Context, computationI
attestationPolicy.Policy.Measurement = measurement
}
if config.HostData != "" {
hostData, err := base64.StdEncoding.DecodeString(config.HostData)
if vmi.Config.HostData != "" {
hostData, err := base64.StdEncoding.DecodeString(vmi.Config.HostData)
if err != nil {
return nil, err
}
attestationPolicy.Policy.HostData = hostData
}
attestationPolicy.Policy.MinimumLaunchTcb = vmi.LaunchTCB
f, err = protojson.Marshal(&attestationPolicy)
if err != nil {
return nil, err
+32 -20
View File
@@ -15,7 +15,7 @@ import (
"github.com/ultravioletrs/cocos/manager/vm/mocks"
)
func createDummyAttestationPolicyBinary(t *testing.T, behavior string) string {
func CreateDummyAttestationPolicyBinary(t *testing.T, behavior string) string {
var content []byte
switch behavior {
case "success":
@@ -55,13 +55,16 @@ func TestFetchAttestationPolicy(t *testing.T) {
name: "Valid SEV configuration",
computationId: "sev-computation",
binaryBehavior: "success",
vmConfig: qemu.Config{
EnableSEV: true,
SMPCount: 2,
CPU: "EPYC",
OVMFCodeConfig: qemu.OVMFCodeConfig{
File: "/path/to/OVMF_CODE.fd",
vmConfig: qemu.VMInfo{
Config: qemu.Config{
EnableSEV: true,
SMPCount: 2,
CPU: "EPYC",
OVMFCodeConfig: qemu.OVMFCodeConfig{
File: "/path/to/OVMF_CODE.fd",
},
},
LaunchTCB: 0,
},
expectedError: "open /path/to/OVMF_CODE.fd: no such file or directory",
},
@@ -69,13 +72,16 @@ func TestFetchAttestationPolicy(t *testing.T) {
name: "Valid SEV-SNP configuration",
computationId: "sev-snp-computation",
binaryBehavior: "success",
vmConfig: qemu.Config{
EnableSEVSNP: true,
SMPCount: 4,
CPU: "EPYC-v2",
OVMFCodeConfig: qemu.OVMFCodeConfig{
File: "/path/to/OVMF_CODE_SNP.fd",
vmConfig: qemu.VMInfo{
Config: qemu.Config{
EnableSEVSNP: true,
SMPCount: 4,
CPU: "EPYC-v2",
OVMFCodeConfig: qemu.OVMFCodeConfig{
File: "/path/to/OVMF_CODE_SNP.fd",
},
},
LaunchTCB: 0,
},
expectedError: "open /path/to/OVMF_CODE_SNP.fd: no such file or director",
},
@@ -83,7 +89,7 @@ func TestFetchAttestationPolicy(t *testing.T) {
name: "Invalid computation ID",
computationId: "non-existent",
binaryBehavior: "success",
vmConfig: qemu.Config{},
vmConfig: qemu.VMInfo{Config: qemu.Config{}, LaunchTCB: 0},
expectedError: "computationId non-existent not found",
},
{
@@ -91,14 +97,17 @@ func TestFetchAttestationPolicy(t *testing.T) {
computationId: "invalid-config",
binaryBehavior: "success",
vmConfig: struct{}{},
expectedError: "failed to cast config to qemu.Config",
expectedError: "failed to cast config to qemu.VMInfo",
},
{
name: "Binary execution failure",
computationId: "binary-fail",
binaryBehavior: "fail",
vmConfig: qemu.Config{
EnableSEV: true,
vmConfig: qemu.VMInfo{
Config: qemu.Config{
EnableSEV: true,
},
LaunchTCB: 0,
},
expectedError: "exit status 1",
},
@@ -106,8 +115,11 @@ func TestFetchAttestationPolicy(t *testing.T) {
name: "JSON file not created",
computationId: "no-json",
binaryBehavior: "no_json",
vmConfig: qemu.Config{
EnableSEV: true,
vmConfig: qemu.VMInfo{
Config: qemu.Config{
EnableSEV: true,
},
LaunchTCB: 0,
},
expectedError: "no such file or directory",
},
@@ -115,7 +127,7 @@ func TestFetchAttestationPolicy(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tempDir := createDummyAttestationPolicyBinary(t, tc.binaryBehavior)
tempDir := CreateDummyAttestationPolicyBinary(t, tc.binaryBehavior)
defer os.RemoveAll(tempDir)
ms := &managerService{
+1 -1
View File
@@ -13,7 +13,7 @@ const jsonExt = ".json"
type VMState struct {
ID string
Config Config
VMinfo VMInfo
PID int
}
+5 -5
View File
@@ -29,7 +29,7 @@ func TestSaveVM(t *testing.T) {
state := VMState{
ID: "test-vm",
Config: Config{},
VMinfo: VMInfo{Config: Config{}},
PID: 1234,
}
@@ -50,8 +50,8 @@ func TestLoadVMs(t *testing.T) {
// Save two VMs
states := []VMState{
{ID: "vm1", Config: Config{}, PID: 1234},
{ID: "vm2", Config: Config{}, PID: 5678},
{ID: "vm1", VMinfo: VMInfo{Config: Config{}}, PID: 1234},
{ID: "vm2", VMinfo: VMInfo{Config: Config{}}, PID: 5678},
}
for _, state := range states {
@@ -82,7 +82,7 @@ func TestDeleteVM(t *testing.T) {
tempDir := t.TempDir()
fp, _ := NewFilePersistence(tempDir)
state := VMState{ID: "test-vm", Config: Config{}, PID: 1234}
state := VMState{ID: "test-vm", VMinfo: VMInfo{Config: Config{}}, PID: 1234}
// Save VM
if err := fp.SaveVM(state); err != nil {
@@ -126,7 +126,7 @@ func TestConcurrentAccess(t *testing.T) {
for i := 0; i < numGoroutines; i++ {
go func(id int) {
defer wg.Done()
state := VMState{ID: fmt.Sprintf("vm-%d", id), Config: Config{}, PID: id}
state := VMState{ID: fmt.Sprintf("vm-%d", id), VMinfo: VMInfo{Config: Config{}}, PID: id}
if err := fp.SaveVM(state); err != nil {
t.Errorf("Concurrent SaveVM failed: %v", err)
}
+17 -12
View File
@@ -25,8 +25,13 @@ const (
shutdownTimeout = 30 * time.Second
)
type VMInfo struct {
Config Config
LaunchTCB uint64 `env:"LAUNCH_TCB" envDefault:"0"`
}
type qemuVM struct {
config Config
vmi VMInfo
cmd *exec.Cmd
eventsLogsSender vm.EventSender
computationId string
@@ -35,7 +40,7 @@ type qemuVM struct {
func NewVM(config interface{}, eventsLogsSender vm.EventSender, computationId string) vm.VM {
return &qemuVM{
config: config.(Config),
vmi: config.(VMInfo),
eventsLogsSender: eventsLogsSender,
computationId: computationId,
StateMachine: vm.NewStateMachine(),
@@ -54,18 +59,18 @@ func (v *qemuVM) Start() (err error) {
return err
}
v.config.NetDevConfig.ID = fmt.Sprintf("%s-%s", v.config.NetDevConfig.ID, id)
v.config.SevConfig.ID = fmt.Sprintf("%s-%s", v.config.SevConfig.ID, id)
v.vmi.Config.NetDevConfig.ID = fmt.Sprintf("%s-%s", v.vmi.Config.NetDevConfig.ID, id)
v.vmi.Config.SevConfig.ID = fmt.Sprintf("%s-%s", v.vmi.Config.SevConfig.ID, id)
if !v.config.KernelHash {
if !v.vmi.Config.KernelHash {
// Copy firmware vars file.
srcFile := v.config.OVMFVarsConfig.File
srcFile := v.vmi.Config.OVMFVarsConfig.File
dstFile := fmt.Sprintf("%s/%s-%s.fd", tmpDir, firmwareVars, id)
err = internal.CopyFile(srcFile, dstFile)
if err != nil {
return err
}
v.config.OVMFVarsConfig.File = dstFile
v.vmi.Config.OVMFVarsConfig.File = dstFile
}
exe, args, err := v.executableAndArgs()
@@ -140,14 +145,14 @@ func (v *qemuVM) GetProcess() int {
}
func (v *qemuVM) executableAndArgs() (string, []string, error) {
exe, err := exec.LookPath(v.config.QemuBinPath)
exe, err := exec.LookPath(v.vmi.Config.QemuBinPath)
if err != nil {
return "", nil, err
}
args := v.config.ConstructQemuArgs()
args := v.vmi.Config.ConstructQemuArgs()
if v.config.UseSudo {
if v.vmi.Config.UseSudo {
args = append([]string{exe}, args...)
exe = "sudo"
}
@@ -191,9 +196,9 @@ func processExists(pid int) bool {
}
func (v *qemuVM) GetCID() int {
return v.config.GuestCID
return v.vmi.Config.GuestCID
}
func (v *qemuVM) GetConfig() interface{} {
return v.config
return v.vmi.Config
}
+15 -11
View File
@@ -17,7 +17,7 @@ import (
const testComputationID = "test-computation"
func TestNewVM(t *testing.T) {
config := Config{}
config := VMInfo{Config: Config{}}
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID)
@@ -31,12 +31,12 @@ func TestStart(t *testing.T) {
assert.NoError(t, err)
defer os.Remove(tmpFile.Name())
config := Config{
config := VMInfo{Config: Config{
OVMFVarsConfig: OVMFVarsConfig{
File: tmpFile.Name(),
},
QemuBinPath: "echo",
}
}}
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID).(*qemuVM)
@@ -53,13 +53,13 @@ func TestStartSudo(t *testing.T) {
assert.NoError(t, err)
defer os.Remove(tmpFile.Name())
config := Config{
config := VMInfo{Config: Config{
OVMFVarsConfig: OVMFVarsConfig{
File: tmpFile.Name(),
},
QemuBinPath: "echo",
UseSudo: true,
}
}}
vm := NewVM(config, func(event interface{}) error { return nil }, testComputationID).(*qemuVM)
@@ -113,8 +113,8 @@ func TestStop(t *testing.T) {
func TestSetProcess(t *testing.T) {
vm := &qemuVM{
config: Config{
QemuBinPath: "echo", // Use 'echo' as a dummy QEMU binary
vmi: VMInfo{
Config: Config{QemuBinPath: "echo"}, // Use 'echo' as a dummy QEMU binary
},
}
@@ -139,9 +139,11 @@ func TestGetProcess(t *testing.T) {
func TestGetCID(t *testing.T) {
expectedCID := 42
vm := &qemuVM{
config: Config{
VSockConfig: VSockConfig{
GuestCID: expectedCID,
vmi: VMInfo{
Config: Config{
VSockConfig: VSockConfig{
GuestCID: expectedCID,
},
},
},
}
@@ -155,7 +157,9 @@ func TestGetConfig(t *testing.T) {
QemuBinPath: "echo",
}
vm := &qemuVM{
config: expectedConfig,
vmi: VMInfo{
Config: expectedConfig,
},
}
config := vm.GetConfig()
+1 -1
View File
@@ -12,7 +12,7 @@ import (
const VsockConfigPort uint32 = 9999
func (v *qemuVM) SendAgentConfig(ac agent.Computation) error {
conn, err := vsock.Dial(uint32(v.config.GuestCID), VsockConfigPort, nil)
conn, err := vsock.Dial(uint32(v.vmi.Config.GuestCID), VsockConfigPort, nil)
if err != nil {
return err
}
+56 -12
View File
@@ -10,6 +10,7 @@ import (
"log/slog"
"net"
"os"
"os/exec"
"regexp"
"strconv"
"sync"
@@ -17,11 +18,13 @@ import (
"github.com/absmach/magistrala/pkg/errors"
"github.com/cenkalti/backoff/v4"
"github.com/google/go-sev-guest/proto/check"
"github.com/ultravioletrs/cocos/agent"
"github.com/ultravioletrs/cocos/manager/qemu"
"github.com/ultravioletrs/cocos/manager/vm"
"github.com/ultravioletrs/cocos/pkg/manager"
"golang.org/x/crypto/sha3"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/timestamppb"
)
@@ -49,6 +52,15 @@ var (
// ErrFailedToCalculateHash indicates that agent computation returned an error while calculating the hash of the computation.
ErrFailedToCalculateHash = errors.New("error while calculating the hash of the computation")
// ErrFailedToCreateAttestationPolicy indicates that the script to create the attestation policy failed to execute.
ErrFailedToCreateAttestationPolicy = errors.New("error while creating attestation policy")
// ErrFailedToReadPolicy indicates that the file for attestation policy could not be opened.
ErrFailedToReadPolicy = errors.New("error while opening file attestation policy")
// ErrUnmarshalFailed indicates that the file for the attestation policy could not be unmarshaled.
ErrUnmarshalFailed = errors.New("error while unmarshaling the attestation policy")
)
// Service specifies an API that must be fulfilled by the domain service
@@ -68,6 +80,7 @@ type Service interface {
type managerService struct {
mu sync.Mutex
ap sync.Mutex
qemuCfg qemu.Config
attestationPolicyBinaryPath string
logger *slog.Logger
@@ -116,9 +129,38 @@ func New(cfg qemu.Config, attestationPolicyBinPath string, logger *slog.Logger,
func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string, error) {
ms.mu.Lock()
cfg := ms.qemuCfg
cfg := qemu.VMInfo{
Config: ms.qemuCfg,
LaunchTCB: 0,
}
ms.mu.Unlock()
if ms.qemuCfg.EnableSEVSNP || ms.qemuCfg.EnableSEV {
cmd := exec.Command("sudo", fmt.Sprintf("%s/attestation_policy", ms.attestationPolicyBinaryPath), "--policy", "196608")
ms.ap.Lock()
_, err := cmd.Output()
ms.ap.Unlock()
if err != nil {
return "", errors.Wrap(ErrFailedToCreateAttestationPolicy, err)
}
ms.ap.Lock()
f, err := os.ReadFile("./attestation_policy.json")
ms.ap.Unlock()
if err != nil {
return "", errors.Wrap(ErrFailedToReadPolicy, err)
}
var attestationPolicy check.Config
if err = protojson.Unmarshal(f, &attestationPolicy); err != nil {
return "", errors.Wrap(ErrUnmarshalFailed, err)
}
// Define the TCB that was present at launch of the VM.
cfg.LaunchTCB = attestationPolicy.Policy.MinimumLaunchTcb
}
ms.publishEvent(manager.VmProvision.String(), c.Id, manager.Starting.String(), json.RawMessage{})
ac := agent.Computation{
ID: c.Id,
@@ -159,7 +201,7 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
return "", errors.Wrap(ErrFailedToAllocatePort, err)
}
cfg.HostFwdAgent = agentPort
cfg.Config.HostFwdAgent = agentPort
var cid int = qemu.BaseGuestCID
for {
@@ -175,17 +217,19 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
}
cid++
}
cfg.VSockConfig.GuestCID = cid
cfg.Config.VSockConfig.GuestCID = cid
ch, err := computationHash(ac)
if err != nil {
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
return "", errors.Wrap(ErrFailedToCalculateHash, err)
if cfg.Config.EnableSEVSNP {
ch, err := computationHash(ac)
if err != nil {
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.Failed.String(), json.RawMessage{})
return "", errors.Wrap(ErrFailedToCalculateHash, err)
}
// Define host-data value of QEMU for SEV-SNP, with a base64 encoding of the computation hash.
cfg.Config.SevConfig.HostData = base64.StdEncoding.EncodeToString(ch[:])
}
// Define host-data value of QEMU for SEV-SNP, with a base64 encoding of the computation hash.
cfg.SevConfig.HostData = base64.StdEncoding.EncodeToString(ch[:])
cvm := ms.vmFactory(cfg, ms.eventsLogsSender, c.Id)
ms.publishEvent(manager.VmProvision.String(), c.Id, agent.InProgress.String(), json.RawMessage{})
if err = cvm.Start(); err != nil {
@@ -200,7 +244,7 @@ func (ms *managerService) Run(ctx context.Context, c *ComputationRunReq) (string
state := qemu.VMState{
ID: c.Id,
Config: cfg,
VMinfo: cfg,
PID: pid,
}
if err := ms.persistence.SaveVM(state); err != nil {
@@ -358,7 +402,7 @@ func (ms *managerService) restoreVMs() error {
continue
}
cvm := ms.vmFactory(state.Config, ms.eventsLogsSender, state.ID)
cvm := ms.vmFactory(state.VMinfo, ms.eventsLogsSender, state.ID)
if err = cvm.SetProcess(state.PID); err != nil {
ms.logger.Warn("Failed to reattach to process", "computation", state.ID, "pid", state.PID, "error", err)
+43 -19
View File
@@ -45,10 +45,11 @@ func TestRun(t *testing.T) {
persistence := new(persistenceMocks.Persistence)
vmf.On("Execute", mock.Anything, mock.Anything, mock.Anything).Return(vmMock)
tests := []struct {
name string
req *ComputationRunReq
vmStartError error
expectedError error
name string
req *ComputationRunReq
binaryBehavior string
vmStartError error
expectedError error
}{
{
name: "Successful run",
@@ -60,8 +61,9 @@ func TestRun(t *testing.T) {
},
AgentConfig: &AgentConfig{},
},
vmStartError: nil,
expectedError: nil,
binaryBehavior: "success",
vmStartError: nil,
expectedError: nil,
},
{
name: "VM start failure",
@@ -73,8 +75,9 @@ func TestRun(t *testing.T) {
},
AgentConfig: &AgentConfig{},
},
vmStartError: assert.AnError,
expectedError: assert.AnError,
binaryBehavior: "success",
vmStartError: assert.AnError,
expectedError: assert.AnError,
},
{
name: "Invalid algorithm hash",
@@ -86,8 +89,9 @@ func TestRun(t *testing.T) {
},
AgentConfig: &AgentConfig{},
},
vmStartError: nil,
expectedError: errInvalidHashLength,
binaryBehavior: "success",
vmStartError: nil,
expectedError: errInvalidHashLength,
},
{
name: "Invalid dataset hash",
@@ -104,8 +108,23 @@ func TestRun(t *testing.T) {
},
},
},
vmStartError: nil,
expectedError: errInvalidHashLength,
binaryBehavior: "success",
vmStartError: nil,
expectedError: errInvalidHashLength,
},
{
name: "Invalid attestation policy",
req: &ComputationRunReq{
Id: "test-computation",
Name: "Test Computation",
Algorithm: &Algorithm{
Hash: make([]byte, hashLength),
},
AgentConfig: &AgentConfig{},
},
binaryBehavior: "fail",
vmStartError: nil,
expectedError: ErrFailedToCreateAttestationPolicy,
},
}
@@ -124,6 +143,7 @@ func TestRun(t *testing.T) {
persistence.On("SaveVM", mock.Anything).Return(nil)
qemuCfg := qemu.Config{
EnableSEVSNP: true,
VSockConfig: qemu.VSockConfig{
GuestCID: 3,
},
@@ -131,13 +151,17 @@ func TestRun(t *testing.T) {
logger := slog.Default()
eventsChan := make(chan *ClientStreamMessage, 10)
tempDir := CreateDummyAttestationPolicyBinary(t, tt.binaryBehavior)
defer os.RemoveAll(tempDir)
ms := &managerService{
qemuCfg: qemuCfg,
logger: logger,
vms: make(map[string]vm.VM),
eventsChan: eventsChan,
vmFactory: vmf.Execute,
persistence: persistence,
qemuCfg: qemuCfg,
attestationPolicyBinaryPath: tempDir,
logger: logger,
vms: make(map[string]vm.VM),
eventsChan: eventsChan,
vmFactory: vmf.Execute,
persistence: persistence,
}
ctx := context.Background()
@@ -146,7 +170,7 @@ func TestRun(t *testing.T) {
if tt.expectedError != nil {
assert.Error(t, err)
assert.ErrorIs(t, err, tt.expectedError)
assert.Contains(t, err.Error(), tt.expectedError.Error())
assert.Empty(t, port)
} else {
assert.NoError(t, err)