106 lines
4.1 KiB
Go
106 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"data-terminal-cloud/internal/firmwareconformance"
|
|
)
|
|
|
|
func recordSimulatedFirmwareEvidence(command simulatedDeviceCommand, manifest simulatedFirmwareManifest, phase string, state simulatedFirmwareBootState, resultCode string) error {
|
|
path := strings.TrimSpace(os.Getenv("SIM_FIRMWARE_EVIDENCE_FILE"))
|
|
if path == "" {
|
|
return nil
|
|
}
|
|
now := time.Now().UTC()
|
|
var evidence firmwareconformance.DeviceEvidence
|
|
content, err := os.ReadFile(path)
|
|
if errors.Is(err, os.ErrNotExist) {
|
|
partitionDigest := strings.ToLower(env("SIM_PARTITION_TABLE_SHA256", firmwareconformance.SHA256([]byte(env("SIM_DEVICE_MODEL", "simulated-terminal")+":"+env("SIM_DEVICE_HARDWARE_REVISION", "sim-rev-a")+":A/B"))))
|
|
secureBoot, parseErr := simulatedEvidenceBoolean("SIM_SECURE_BOOT_ENABLED", false)
|
|
if parseErr != nil {
|
|
return parseErr
|
|
}
|
|
evidence = firmwareconformance.DeviceEvidence{
|
|
SchemaVersion: firmwareconformance.DeviceEvidenceSchema, EvidenceSource: "SIMULATOR",
|
|
CandidateVersion: env("SIM_CANDIDATE_VERSION", "local-development"), BuildDigest: strings.ToLower(strings.TrimSpace(os.Getenv("SIM_BUILD_DIGEST"))),
|
|
DeviceID: env("SIM_DEVICE_ID", "10000000-0000-0000-0000-000000000511"), DeviceModel: env("SIM_DEVICE_MODEL", "simulated-terminal"), HardwareRevision: env("SIM_DEVICE_HARDWARE_REVISION", "sim-rev-a"),
|
|
ReleaseID: manifest.ReleaseID, CommandID: command.ID, Scenario: strings.ToUpper(strings.TrimSpace(os.Getenv("SIM_FIRMWARE_EVIDENCE_SCENARIO"))),
|
|
BootloaderVersion: env("SIM_BOOTLOADER_VERSION", "sim-bootloader-1"), PartitionTableSHA256: partitionDigest, SecureBootEnabled: secureBoot,
|
|
ArtifactSHA256: manifest.Digest, SigningKeyID: manifest.SigningKeyID,
|
|
InitialSlot: state.PreviousSlot, TargetSlot: state.TargetSlot, FinalSlot: state.PreviousSlot,
|
|
InitialVersion: state.PreviousVersion, TargetVersion: state.TargetVersion, FinalVersion: state.PreviousVersion,
|
|
BootAttemptID: state.BootAttemptID, CollectedAt: now, Events: []firmwareconformance.DeviceEvent{},
|
|
}
|
|
if evidence.BuildDigest == "" || evidence.Scenario == "" {
|
|
return errors.New("SIM_BUILD_DIGEST and SIM_FIRMWARE_EVIDENCE_SCENARIO are required when evidence capture is enabled")
|
|
}
|
|
} else if err != nil {
|
|
return fmt.Errorf("read simulated firmware evidence: %w", err)
|
|
} else {
|
|
evidence, err = firmwareconformance.ParseDeviceEvidence(content)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if evidence.CommandID != command.ID || evidence.ReleaseID != manifest.ReleaseID {
|
|
return errors.New("simulated firmware evidence belongs to a different command or release")
|
|
}
|
|
}
|
|
if manifest.SigningKeyID != "" && evidence.SigningKeyID == "" {
|
|
evidence.SigningKeyID = manifest.SigningKeyID
|
|
}
|
|
if state.BootAttemptID != "" {
|
|
evidence.BootAttemptID = state.BootAttemptID
|
|
}
|
|
event := firmwareconformance.DeviceEvent{
|
|
Phase: phase, OccurredAt: now, ActiveSlot: state.ActiveSlot, TargetSlot: state.TargetSlot, ResultCode: resultCode, BootAttemptID: state.BootAttemptID,
|
|
}
|
|
evidence.Events = append(evidence.Events, event)
|
|
evidence.CollectedAt = now
|
|
switch phase {
|
|
case "confirmed":
|
|
evidence.FinalSlot = state.ActiveSlot
|
|
evidence.FinalVersion = manifest.Version
|
|
case "rolled_back":
|
|
evidence.FinalSlot = state.ActiveSlot
|
|
evidence.FinalVersion = state.TargetVersion
|
|
}
|
|
encoded, err := json.MarshalIndent(evidence, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o600)
|
|
if err != nil {
|
|
return fmt.Errorf("open simulated firmware evidence: %w", err)
|
|
}
|
|
if _, err = file.Write(encoded); err == nil {
|
|
err = file.Sync()
|
|
}
|
|
closeErr := file.Close()
|
|
if err != nil {
|
|
return fmt.Errorf("write simulated firmware evidence: %w", err)
|
|
}
|
|
if closeErr != nil {
|
|
return fmt.Errorf("close simulated firmware evidence: %w", closeErr)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func simulatedEvidenceBoolean(key string, fallback bool) (bool, error) {
|
|
value := strings.ToLower(strings.TrimSpace(os.Getenv(key)))
|
|
if value == "" {
|
|
return fallback, nil
|
|
}
|
|
if value == "true" {
|
|
return true, nil
|
|
}
|
|
if value == "false" {
|
|
return false, nil
|
|
}
|
|
return false, fmt.Errorf("%s must be true or false", key)
|
|
}
|