Commit 9772fc9

Eric Bower  ·  2026-05-08 15:14:26 -0400 EDT
parent ab5ea95
feat: attestation
1 files changed,  +53, -4
M main.go
+53, -4
  1@@ -17,6 +17,7 @@ import (
  2 	"os/exec"
  3 	"os/signal"
  4 	"path/filepath"
  5+	"runtime"
  6 	"strconv"
  7 	"strings"
  8 	"syscall"
  9@@ -313,6 +314,9 @@ type Workspace interface {
 10 	Setup() error
 11 	Cleanup() error
 12 	GetDir() string
 13+	// Checksum returns a content hash of the workspace (e.g. sha256 of the tarball).
 14+	// Returns empty string if not available.
 15+	Checksum() string
 16 }
 17 
 18 type WorkspaceRsync struct {
 19@@ -355,11 +359,16 @@ func (w *WorkspaceRsync) GetDir() string {
 20 	return w.Dest
 21 }
 22 
 23+func (w *WorkspaceRsync) Checksum() string {
 24+	return ""
 25+}
 26+
 27 type WorkspaceTar struct {
 28-	Cfg    *Cfg
 29-	Logger *slog.Logger
 30-	Source string // e.g. "pgs.sh:/private-ci/workspaces/repo_abc123.tar"
 31-	Dest   string
 32+	Cfg      *Cfg
 33+	Logger   *slog.Logger
 34+	Source   string // e.g. "pgs.sh:/private-ci/workspaces/repo_abc123.tar"
 35+	Dest     string
 36+	checksum string
 37 }
 38 
 39 func (w *WorkspaceTar) Setup() error {
 40@@ -383,6 +392,14 @@ func (w *WorkspaceTar) Setup() error {
 41 		return fmt.Errorf("rsync download: %w", err)
 42 	}
 43 
 44+	// Compute sha256 checksum of the tarball
 45+	tarData, err := os.ReadFile(tarPath)
 46+	if err != nil {
 47+		return fmt.Errorf("read tar for checksum: %w", err)
 48+	}
 49+	w.checksum = fmt.Sprintf("sha256:%x", sha256.Sum256(tarData))
 50+	log.Debug("workspace checksum", "checksum", w.checksum)
 51+
 52 	// Open the tar file for extraction
 53 	f, err := os.Open(tarPath)
 54 	if err != nil {
 55@@ -436,6 +453,10 @@ func (w *WorkspaceTar) Setup() error {
 56 	return nil
 57 }
 58 
 59+func (w *WorkspaceTar) Checksum() string {
 60+	return w.checksum
 61+}
 62+
 63 func (w *WorkspaceTar) Cleanup() error {
 64 	return nil
 65 }
 66@@ -586,6 +607,26 @@ func eventHandler(cfg *Cfg, eventData *Event) error {
 67 		}
 68 	}
 69 
 70+	// Write attestation.json with runner/workspace provenance
 71+	hostname, _ := os.Hostname()
 72+	attestation := map[string]interface{}{
 73+		"runner": map[string]string{
 74+			"hostname": hostname,
 75+			"os":       runtimeOS(),
 76+			"arch":     runtimeArch(),
 77+		},
 78+		"provenance": map[string]string{
 79+			"repo":   eventData.Name,
 80+			"branch": eventData.Branch,
 81+			"commit": eventData.Commit,
 82+		},
 83+		"workspace_checksum": eng.Wk.Checksum(),
 84+	}
 85+	attestationBytes, _ := json.Marshal(attestation)
 86+	if err := os.WriteFile(filepath.Join(eventDir, "attestation.json"), attestationBytes, 0644); err != nil {
 87+		log.Error("write attestation", "err", err)
 88+	}
 89+
 90 	manifest, err := eng.FindManifest()
 91 	if err != nil {
 92 		fmt.Fprintf(os.Stdout, "❌ %s\n\n", err) //nolint:errcheck
 93@@ -1293,6 +1334,14 @@ func generateJobID(name, workspace string) string {
 94 	return jobIDFor(name, workspace, time.Now().UnixNano())
 95 }
 96 
 97+func runtimeOS() string {
 98+	return runtime.GOOS
 99+}
100+
101+func runtimeArch() string {
102+	return runtime.GOARCH
103+}
104+
105 func jobIDFor(name, workspace string, ts int64) string {
106 	h := sha256.Sum256([]byte(name + workspace + fmt.Sprintf("%d", ts)))
107 	return fmt.Sprintf("%x", h[:4])