feat(governance): add local bounded verification executor #230

Merged
m merged 1 commits from codex/dev-000248-self-development-runtime-status into main 2026-08-23 18:23:18 +00:00
4 changed files with 292 additions and 2 deletions
+197
View File
@@ -0,0 +1,197 @@
// 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
}
@@ -0,0 +1,70 @@
package developmentexecutor
import (
"context"
"errors"
"path/filepath"
"testing"
)
type fakeRunner struct {
calls []string
exits []int
}
func (r *fakeRunner) Run(_ context.Context, _ string, name string, args []string) int {
call := name
for _, arg := range args {
call += " " + arg
}
r.calls = append(r.calls, call)
if len(r.exits) == 0 {
return 0
}
exit := r.exits[0]
r.exits = r.exits[1:]
return exit
}
func validPlan(t *testing.T) Plan {
t.Helper()
worktree, err := filepath.Abs(".")
if err != nil {
t.Fatal(err)
}
return Plan{Worktree: worktree, WorktreeID: "sandbox-1", BaseRepoRevision: "revision-1", ProtectedMainAccess: "DENIED", ProductionAccess: "DENIED", SecretAccess: "DENIED", Checks: []Check{{Kind: CheckGoTest, Packages: []string{"./modules/work/..."}}, {Kind: CheckGoVet, Packages: []string{"./modules/work/..."}}, {Kind: CheckGitDiffCheck}}}
}
func TestExecuteRunsOnlyTypedChecksAndReturnsEvidence(t *testing.T) {
runner := &fakeRunner{}
result, err := Execute(context.Background(), validPlan(t), runner)
if err != nil || !result.Passed || len(result.Checks) != 3 || result.EvidenceRef == "" {
t.Fatalf("result=%+v err=%v", result, err)
}
if len(runner.calls) != 3 || runner.calls[0] != "go test ./modules/work/..." || runner.calls[2] != "git diff --check" {
t.Fatalf("calls=%v", runner.calls)
}
}
func TestExecuteFailureCannotBecomeVerificationSuccess(t *testing.T) {
runner := &fakeRunner{exits: []int{1, 0}}
plan := validPlan(t)
plan.Checks = []Check{{Kind: CheckGoTest, Packages: []string{"./..."}}, {Kind: CheckGitDiffCheck}}
result, err := Execute(context.Background(), plan, runner)
if err != nil || result.Passed || result.Checks[0].Passed || result.EvidenceRef == "" {
t.Fatalf("failed result was overclaimed: %+v err=%v", result, err)
}
}
func TestValidatePlanRejectsProtectedAndShellLikeInputs(t *testing.T) {
protected := validPlan(t)
protected.WorktreeID = "production"
if !errors.Is(ValidatePlan(protected), ErrProtectedWorktree) {
t.Fatal("protected worktree accepted")
}
injection := validPlan(t)
injection.Checks = []Check{{Kind: CheckGoTest, Packages: []string{"./...; echo leaked"}}}
if !errors.Is(ValidatePlan(injection), ErrInvalidPlan) {
t.Fatal("shell-like package accepted")
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
{
"task_file": "dev/tasks/DEV-000251-reflection-cognition-routing.json",
"task_id": "DEV-000251",
"task_file": "dev/tasks/DEV-000252-local-governed-verification-executor.json",
"task_id": "DEV-000252",
"task_revision": 1
}
@@ -0,0 +1,23 @@
{
"task_id": "DEV-000252",
"task_revision": 1,
"architecture_revision": "ADR-0018",
"base_repo_revision": "c925089fd2304213758d2721a0592ca73d765047",
"risk_tier": "E",
"intent": "Add a local governed verification executor that runs only typed, bounded checks inside an isolated worktree and returns evidence without source, secret, production or promotion authority.",
"requirement_ids": ["governed self-development", "isolated verification", "independent test evidence"],
"allowed_change_scope": {"modules": ["governed-development"], "paths": ["adapters/developmentexecutor/**", "dev/ACTIVE_TASK.json", "dev/tasks/DEV-000252-local-governed-verification-executor.json"]},
"forbidden_change_scope": {"paths": ["architecture/**", "security/**", "database/**", "deploy/**", "contracts/**", "LLM-local/**", "modules/work/**", "cmd/core-runtime/**", "cmd/agent-worker/**"]},
"allowed_architecture_delta": {"new_cross_module_dependencies": 0, "new_canonical_owners": 0, "new_privileges": 0, "new_third_party_dependencies": 0, "new_database_owner_roles": 0},
"contracts": {"consume": ["existing DevelopmentScaffold semantics", "typed local check plan"], "may_change": []},
"semantic_owner": "governed development verification adapter",
"canonical_state": ["none; executor returns evidence to a future gate owner"],
"state_transitions": ["typed plan -> validated sandbox checks -> immutable result summary"],
"side_effects_and_privileges": ["read-only source/test execution in supplied isolated worktree; no secrets, production, protected main or promotion access"],
"persistence_and_migrations": ["none"],
"failure_retry_restart": ["each check has an explicit result; failed or cancelled checks never become verification success; rerun creates a new result"],
"assumptions": ["worktree isolation and gate persistence are supplied by the surrounding governed control plane"],
"acceptance_scenarios": ["allowed go test/vet and git diff check plans validate", "shell injection and unsupported commands reject", "protected or production worktree rejects", "failed check returns non-success evidence", "result contains no command output or secret material"],
"required_tests": ["go test ./adapters/developmentexecutor", "go vet ./adapters/developmentexecutor", "go run ./cmd/devctl preflight -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-diff -active dev/ACTIVE_TASK.json", "go run ./cmd/devctl check-architecture", "git diff --check", "independent", "CI"],
"terminal_gap_states": ["BLOCKED_BY_MISSING_CAPABILITY", "BLOCKED_BY_SPEC_GAP"]
}