treewide: add missing error handling

Change-Id: I55ccf3ff490b58f6af93e665c668428acddc8d65
Reviewed-on: https://review.monogon.dev/c/monogon/+/3019
Vouch-Run-CI: Tim Windelschmidt <tim@monogon.tech>
Tested-by: Jenkins CI
Reviewed-by: Serge Bazanski <serge@monogon.tech>
diff --git a/metropolis/installer/main.go b/metropolis/installer/main.go
index 6313548..a35a734 100644
--- a/metropolis/installer/main.go
+++ b/metropolis/installer/main.go
@@ -89,6 +89,9 @@
 	// Use the partition's name to find and return the name of its parent
 	// device. It will be excluded from the list of suitable target devices.
 	srcDev, err := sysfs.ParentBlockDevice(espDev)
+	if err != nil{
+		return nil, fmt.Errorf("failed to fetch parent device: %w", err)
+	}
 	// Build the exclusion list containing forbidden handle prefixes.
 	exclude := []string{"dm-", "zram", "ram", "loop", srcDev}
 
diff --git a/metropolis/installer/test/main.go b/metropolis/installer/test/main.go
index 3c2460a..b2fb8dc 100644
--- a/metropolis/installer/test/main.go
+++ b/metropolis/installer/test/main.go
@@ -273,6 +273,9 @@
 	}
 	// Verify that GPT exists.
 	ti, err := storage.GetPartitionTable()
+	if err != nil {
+		t.Fatalf("Couldn't read the installer image partition table: %s", err)
+	}
 	if ti.Type() != "gpt" {
 		t.Error("Couldn't verify that the resulting node image contains a GPT.")
 	}
diff --git a/metropolis/node/build/fwprune/main.go b/metropolis/node/build/fwprune/main.go
index dfabcde..4f26fa0 100644
--- a/metropolis/node/build/fwprune/main.go
+++ b/metropolis/node/build/fwprune/main.go
@@ -209,6 +209,9 @@
 	// Format output in a both human- and machine-readable form
 	marshalOpts := prototext.MarshalOptions{Multiline: true, Indent: "  "}
 	fsspecRaw, err := marshalOpts.Marshal(&fsspec.FSSpec{File: files, SymbolicLink: symlinks})
+	if err != nil {
+		log.Fatalf("failed to marshal fsspec: %v", err)
+	}
 	if err := os.WriteFile(*outFSSpecPath, fsspecRaw, 0644); err != nil {
 		log.Fatalf("failed writing output: %v", err)
 	}
diff --git a/metropolis/node/core/curator/state_node.go b/metropolis/node/core/curator/state_node.go
index d580e87..bd11f6a 100644
--- a/metropolis/node/core/curator/state_node.go
+++ b/metropolis/node/core/curator/state_node.go
@@ -446,7 +446,11 @@
 		return status.Errorf(codes.InvalidArgument, "invalid node id")
 	}
 	jkey, err := n.etcdJoinKeyPath()
-
+	if err != nil {
+		// This should never happen.
+		rpc.Trace(ctx).Printf("invalid join key representation: %v", err)
+		return status.Errorf(codes.InvalidArgument, "invalid join key representation")
+	}
 	// Delete both.
 	_, err = l.txnAsLeader(ctx,
 		clientv3.OpDelete(nkey),
diff --git a/metropolis/node/core/mgmt/svc_logs.go b/metropolis/node/core/mgmt/svc_logs.go
index b24e485..6566cee 100644
--- a/metropolis/node/core/mgmt/svc_logs.go
+++ b/metropolis/node/core/mgmt/svc_logs.go
@@ -169,7 +169,6 @@
 		if err != nil {
 			return err
 		}
-		chunk = make([]*cpb.LogEntry, 0, maxChunkSize)
 	}
 
 	// Start serving streaming data, if streaming has been requested.
diff --git a/metropolis/node/core/network/static.go b/metropolis/node/core/network/static.go
index a178e2c..6c72be5 100644
--- a/metropolis/node/core/network/static.go
+++ b/metropolis/node/core/network/static.go
@@ -168,6 +168,8 @@
 			for _, a := range i.Address {
 				ipNet, err := addressOrPrefix(a)
 				if err != nil {
+					l.Warningf("failed to parse %q as IPNet", a)
+					continue
 				}
 				if ipNet.IP.To4() != nil {
 					selectedAddr = ipNet.IP.To4()
diff --git a/metropolis/node/core/update/update.go b/metropolis/node/core/update/update.go
index ad4ad43..8490c78 100644
--- a/metropolis/node/core/update/update.go
+++ b/metropolis/node/core/update/update.go
@@ -275,6 +275,9 @@
 
 func (*Service) tryDownloadBundle(ctx context.Context, bundleURL string, bundleRaw *bytes.Buffer) error {
 	bundleReq, err := http.NewRequestWithContext(ctx, "GET", bundleURL, nil)
+	if err != nil {
+		return fmt.Errorf("failed to create request: %w", err)
+	}
 	bundleRes, err := http.DefaultClient.Do(bundleReq)
 	if err != nil {
 		return fmt.Errorf("HTTP request failed: %w", err)
diff --git a/metropolis/node/kubernetes/authproxy/authproxy.go b/metropolis/node/kubernetes/authproxy/authproxy.go
index e8e6fd8..c4a844e 100644
--- a/metropolis/node/kubernetes/authproxy/authproxy.go
+++ b/metropolis/node/kubernetes/authproxy/authproxy.go
@@ -56,6 +56,9 @@
 
 	k8sCAs := x509.NewCertPool()
 	cert, _, err := s.KPKI.Certificate(ctx, pki.IdCA)
+	if err != nil {
+		return fmt.Errorf("could not load certificate %q from PKI: %w", pki.IdCA, err)
+	}
 	parsedCert, err := x509.ParseCertificate(cert)
 	if err != nil {
 		return fmt.Errorf("failed to parse K8s CA certificate: %w", err)
diff --git a/metropolis/node/kubernetes/pki/kubernetes.go b/metropolis/node/kubernetes/pki/kubernetes.go
index a30aeda..66731ae 100644
--- a/metropolis/node/kubernetes/pki/kubernetes.go
+++ b/metropolis/node/kubernetes/pki/kubernetes.go
@@ -337,7 +337,7 @@
 	// Save to etcd.
 	_, err = k.KV.Put(ctx, path, string(key))
 	if err != nil {
-		err = fmt.Errorf("failed to write newly generated key: %w", err)
+		return nil, fmt.Errorf("failed to write newly generated key: %w", err)
 	}
 	return key, nil
 }
diff --git a/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go b/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
index bef049a..007bde6 100644
--- a/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
+++ b/metropolis/node/kubernetes/plugins/kvmdevice/kvmdevice.go
@@ -158,6 +158,9 @@
 	}
 
 	kvmDevNode, err := deviceNumberFromString(string(kvmDevRaw))
+	if err != nil {
+		return fmt.Errorf("failed to parse KVM device node: %w", err)
+	}
 
 	err = unix.Mknod("/dev/kvm", 0660, int(kvmDevNode))
 	if err != nil && errors.Is(err, unix.EEXIST) {
diff --git a/metropolis/node/kubernetes/service_controller.go b/metropolis/node/kubernetes/service_controller.go
index ccb5b29..c1cec27 100644
--- a/metropolis/node/kubernetes/service_controller.go
+++ b/metropolis/node/kubernetes/service_controller.go
@@ -85,6 +85,9 @@
 	}
 
 	clientConfig, err := rawClientConfig.ClientConfig()
+	if err != nil {
+		return fmt.Errorf("could not fetch generate client config: %w", err)
+	}
 	clientSet, err := kubernetes.NewForConfig(clientConfig)
 	if err != nil {
 		return fmt.Errorf("could not generate kubernetes client: %w", err)
diff --git a/metropolis/node/kubernetes/service_worker.go b/metropolis/node/kubernetes/service_worker.go
index 2572dfa..7ad985f 100644
--- a/metropolis/node/kubernetes/service_worker.go
+++ b/metropolis/node/kubernetes/service_worker.go
@@ -238,6 +238,9 @@
 		return nil, nil, fmt.Errorf("could not generate kubernetes client config: %w", err)
 	}
 	clientConfig, err := rawClientConfig.ClientConfig()
+	if err != nil {
+		return nil, nil, fmt.Errorf("could not fetch generate client config: %w", err)
+	}
 	clientSet, err := kubernetes.NewForConfig(clientConfig)
 	if err != nil {
 		return nil, nil, fmt.Errorf("could not generate kubernetes client: %w", err)
diff --git a/metropolis/pkg/logtree/unraw/unraw_test.go b/metropolis/pkg/logtree/unraw/unraw_test.go
index 5526feb..71c88fd 100644
--- a/metropolis/pkg/logtree/unraw/unraw_test.go
+++ b/metropolis/pkg/logtree/unraw/unraw_test.go
@@ -112,6 +112,7 @@
 		close(started)
 		return r(ctx)
 	})
+	defer stop()
 
 	<-started
 
diff --git a/metropolis/pkg/tpm/tpm.go b/metropolis/pkg/tpm/tpm.go
index 7973399..2dbe6f6 100644
--- a/metropolis/pkg/tpm/tpm.go
+++ b/metropolis/pkg/tpm/tpm.go
@@ -160,6 +160,9 @@
 	}
 	tpmName := tpms[0]
 	ueventData, err := sysfs.ReadUevents(filepath.Join("/sys/class/tpm", tpmName, "uevent"))
+	if err != nil {
+		return fmt.Errorf("failed to read uevents: %w", err)
+	}
 	majorDev, err := strconv.Atoi(ueventData["MAJOR"])
 	if err != nil {
 		return fmt.Errorf("failed to convert uevent: %w", err)