198 lines
5.4 KiB
Go
198 lines
5.4 KiB
Go
// Package developmentexecutor contains the local, read-only verification
|
|
// adapter for governed development candidates. It is deliberately not a
|
|
// source mutator, promotion authority, secret resolver, or deployment tool.
|
|
package developmentexecutor
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type CheckKind string
|
|
|
|
const (
|
|
CheckGoTest CheckKind = "GO_TEST"
|
|
CheckGoVet CheckKind = "GO_VET"
|
|
CheckGitDiffCheck CheckKind = "GIT_DIFF_CHECK"
|
|
)
|
|
|
|
type Check struct {
|
|
Kind CheckKind
|
|
Packages []string
|
|
}
|
|
|
|
type Plan struct {
|
|
Worktree string
|
|
WorktreeID string
|
|
BaseRepoRevision string
|
|
ProtectedMainAccess string
|
|
ProductionAccess string
|
|
SecretAccess string
|
|
Checks []Check
|
|
}
|
|
|
|
type CheckResult struct {
|
|
Kind CheckKind `json:"kind"`
|
|
Passed bool `json:"passed"`
|
|
ExitCode int `json:"exit_code"`
|
|
DurationMillis int64 `json:"duration_millis"`
|
|
}
|
|
|
|
type Result struct {
|
|
WorktreeID string `json:"worktree_id"`
|
|
BaseRepoRevision string `json:"base_repo_revision"`
|
|
Passed bool `json:"passed"`
|
|
Checks []CheckResult `json:"checks"`
|
|
EvidenceRef string `json:"evidence_ref"`
|
|
}
|
|
|
|
var (
|
|
ErrInvalidPlan = errors.New("invalid governed verification plan")
|
|
ErrUnsupportedCheck = errors.New("unsupported governed verification check")
|
|
ErrProtectedWorktree = errors.New("protected worktree is not executable")
|
|
)
|
|
|
|
type CommandRunner interface {
|
|
Run(context.Context, string, string, []string) int
|
|
}
|
|
|
|
type OSCommandRunner struct{}
|
|
|
|
func (OSCommandRunner) Run(ctx context.Context, dir, name string, args []string) int {
|
|
command := exec.CommandContext(ctx, name, args...)
|
|
command.Dir = dir
|
|
command.Stdin = nil
|
|
command.Stdout = io.Discard
|
|
command.Stderr = io.Discard
|
|
command.Env = safeEnvironment()
|
|
if err := command.Run(); err != nil {
|
|
if exitErr, ok := err.(*exec.ExitError); ok {
|
|
return exitErr.ExitCode()
|
|
}
|
|
return -1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func ValidatePlan(plan Plan) error {
|
|
if strings.TrimSpace(plan.Worktree) == "" || strings.TrimSpace(plan.WorktreeID) == "" || strings.TrimSpace(plan.BaseRepoRevision) == "" || len(plan.Checks) == 0 {
|
|
return ErrInvalidPlan
|
|
}
|
|
if !filepath.IsAbs(plan.Worktree) {
|
|
return ErrInvalidPlan
|
|
}
|
|
if plan.ProtectedMainAccess != "DENIED" || plan.ProductionAccess != "DENIED" || plan.SecretAccess != "DENIED" {
|
|
return ErrProtectedWorktree
|
|
}
|
|
switch strings.ToLower(filepath.Base(filepath.Clean(plan.WorktreeID))) {
|
|
case "main", "protected-main", "production":
|
|
return ErrProtectedWorktree
|
|
}
|
|
for _, check := range plan.Checks {
|
|
if err := validateCheck(check); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateCheck(check Check) error {
|
|
switch check.Kind {
|
|
case CheckGoTest, CheckGoVet:
|
|
if len(check.Packages) == 0 {
|
|
return ErrInvalidPlan
|
|
}
|
|
for _, packagePath := range check.Packages {
|
|
if strings.TrimSpace(packagePath) == "" || strings.ContainsAny(packagePath, ";&|`$()<>\r\n") || unsafePackagePath(packagePath) {
|
|
return ErrInvalidPlan
|
|
}
|
|
}
|
|
case CheckGitDiffCheck:
|
|
if len(check.Packages) != 0 {
|
|
return ErrInvalidPlan
|
|
}
|
|
default:
|
|
return ErrUnsupportedCheck
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func unsafePackagePath(value string) bool {
|
|
value = strings.ReplaceAll(value, "\\", "/")
|
|
for _, part := range strings.Split(value, "/") {
|
|
if part == ".." {
|
|
return true
|
|
}
|
|
}
|
|
return strings.HasPrefix(value, "../") || strings.HasPrefix(value, "/") || (len(value) > 1 && value[1] == ':')
|
|
}
|
|
|
|
func Execute(ctx context.Context, plan Plan, runner CommandRunner) (Result, error) {
|
|
if err := ValidatePlan(plan); err != nil {
|
|
return Result{}, err
|
|
}
|
|
if runner == nil {
|
|
runner = OSCommandRunner{}
|
|
}
|
|
if _, err := os.Stat(plan.Worktree); err != nil {
|
|
return Result{}, fmt.Errorf("worktree unavailable: %w", err)
|
|
}
|
|
result := Result{WorktreeID: plan.WorktreeID, BaseRepoRevision: plan.BaseRepoRevision, Passed: true, Checks: make([]CheckResult, 0, len(plan.Checks))}
|
|
for _, check := range plan.Checks {
|
|
started := time.Now()
|
|
name, args := commandFor(check)
|
|
exitCode := runner.Run(ctx, plan.Worktree, name, args)
|
|
passed := exitCode == 0
|
|
result.Checks = append(result.Checks, CheckResult{Kind: check.Kind, Passed: passed, ExitCode: exitCode, DurationMillis: time.Since(started).Milliseconds()})
|
|
if !passed {
|
|
result.Passed = false
|
|
}
|
|
if ctx.Err() != nil {
|
|
result.Passed = false
|
|
break
|
|
}
|
|
}
|
|
result.EvidenceRef = evidenceRef(result)
|
|
return result, nil
|
|
}
|
|
|
|
func commandFor(check Check) (string, []string) {
|
|
switch check.Kind {
|
|
case CheckGoTest:
|
|
return "go", append([]string{"test"}, check.Packages...)
|
|
case CheckGoVet:
|
|
return "go", append([]string{"vet"}, check.Packages...)
|
|
default:
|
|
return "git", []string{"diff", "--check"}
|
|
}
|
|
}
|
|
|
|
func evidenceRef(result Result) string {
|
|
hash := sha256.New()
|
|
_, _ = fmt.Fprintf(hash, "%s|%s|%t|", result.WorktreeID, result.BaseRepoRevision, result.Passed)
|
|
for _, check := range result.Checks {
|
|
_, _ = fmt.Fprintf(hash, "%s|%t|%d|", check.Kind, check.Passed, check.ExitCode)
|
|
}
|
|
return "verification:" + hex.EncodeToString(hash.Sum(nil))
|
|
}
|
|
|
|
func safeEnvironment() []string {
|
|
allowed := []string{"PATH", "SystemRoot", "TEMP", "TMP", "GOROOT", "GOPATH", "GOMODCACHE"}
|
|
result := make([]string, 0, len(allowed))
|
|
for _, name := range allowed {
|
|
if value, ok := os.LookupEnv(name); ok && value != "" {
|
|
result = append(result, name+"="+value)
|
|
}
|
|
}
|
|
return result
|
|
}
|