Export the reviewed allowlisted snapshot from private source commit 8aab3db43f35e6a49aa497f45d73701b13fc9f32 and tree 992132ea4703437dc13ffdbb04a077816c02caf9. This includes routed singleton continuity, deployment evidence, strict schema-2 configuration, restricted transport, and the independently compilable public-tree guard. AI-Assisted: OpenAI Codex Signed-off-by: Cole Speelman <crspeelman@gmail.com>
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package eventlog
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
const Version = 1
|
|
|
|
var safeValue = regexp.MustCompile(`^[A-Za-z0-9._:/@+-]{1,256}$`)
|
|
var hexDigest = regexp.MustCompile(`^[0-9a-f]{64}$`)
|
|
var gitCommit = regexp.MustCompile(`^[0-9a-f]{40}$`)
|
|
var operationID = regexp.MustCompile(`^[0-9a-f]{32}$`)
|
|
|
|
type Event struct {
|
|
Version int `json:"version"`
|
|
OperationID string `json:"operation_id"`
|
|
Service string `json:"service"`
|
|
ArtifactDigest string `json:"artifact_digest"`
|
|
Commit string `json:"commit"`
|
|
ReleaseVersion string `json:"release_version"`
|
|
Phase string `json:"phase"`
|
|
Slot string `json:"slot,omitempty"`
|
|
DurationMillis int64 `json:"duration_ms"`
|
|
Outcome string `json:"outcome"`
|
|
ObservedAt string `json:"observed_at"`
|
|
}
|
|
|
|
func OperationID() (string, error) {
|
|
b := make([]byte, 16)
|
|
if _, err := rand.Read(b); err != nil {
|
|
return "", errors.New("cryptographic randomness unavailable")
|
|
}
|
|
return hex.EncodeToString(b), nil
|
|
}
|
|
|
|
func Append(path string, event Event) error {
|
|
if err := event.validate(); err != nil {
|
|
return err
|
|
}
|
|
if !filepath.IsAbs(path) || filepath.Clean(path) != path {
|
|
return errors.New("event log path must be absolute and clean")
|
|
}
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
|
|
return fmt.Errorf("create event directory: %w", err)
|
|
}
|
|
if info, err := os.Lstat(path); err == nil {
|
|
if !info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 || info.Mode().Perm()&0o022 != 0 {
|
|
return errors.New("event log must be a non-writable regular non-symlink file")
|
|
}
|
|
} else if !errors.Is(err, os.ErrNotExist) {
|
|
return fmt.Errorf("inspect event log: %w", err)
|
|
}
|
|
b, err := json.Marshal(event)
|
|
if err != nil {
|
|
return fmt.Errorf("encode deployment event: %w", err)
|
|
}
|
|
if len(b) > 4096 {
|
|
return errors.New("deployment event exceeds bound")
|
|
}
|
|
b = append(b, '\n')
|
|
fd, err := syscall.Open(path, syscall.O_WRONLY|syscall.O_APPEND|syscall.O_CREAT|syscall.O_CLOEXEC|syscall.O_NOFOLLOW, 0o640)
|
|
if err != nil {
|
|
return fmt.Errorf("open event log: %w", err)
|
|
}
|
|
file := os.NewFile(uintptr(fd), path)
|
|
if file == nil {
|
|
_ = syscall.Close(fd)
|
|
return errors.New("open event log file")
|
|
}
|
|
defer file.Close()
|
|
n, err := file.Write(b)
|
|
if err != nil || n != len(b) {
|
|
return errors.New("write complete deployment event")
|
|
}
|
|
if err := file.Sync(); err != nil {
|
|
return fmt.Errorf("sync deployment event: %w", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (e Event) validate() error {
|
|
if e.Version != Version || !operationID.MatchString(e.OperationID) {
|
|
return errors.New("deployment event identity is invalid")
|
|
}
|
|
if !hexDigest.MatchString(e.ArtifactDigest) || !gitCommit.MatchString(e.Commit) {
|
|
return errors.New("deployment event provenance is invalid")
|
|
}
|
|
for label, value := range map[string]string{"service": e.Service, "artifact_digest": e.ArtifactDigest, "commit": e.Commit, "release_version": e.ReleaseVersion, "phase": e.Phase, "outcome": e.Outcome} {
|
|
if !safeValue.MatchString(value) || strings.ContainsRune(value, '\x00') {
|
|
return fmt.Errorf("deployment event %s is invalid", label)
|
|
}
|
|
}
|
|
if e.Slot != "" && !safeValue.MatchString(e.Slot) {
|
|
return errors.New("deployment event slot is invalid")
|
|
}
|
|
if e.DurationMillis < 0 {
|
|
return errors.New("deployment event duration is invalid")
|
|
}
|
|
if _, err := time.Parse(time.RFC3339Nano, e.ObservedAt); err != nil {
|
|
return errors.New("deployment event timestamp is invalid")
|
|
}
|
|
return nil
|
|
}
|