verify

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: MIT Imports: 24 Imported by: 0

Documentation

Overview

Package verify governs command execution for a mission: which argv may run, and under which limits. Deny-by-default, and the policy never comes from the request being judged.

Index

Constants

View Source
const (
	VerdictPass    = "pass"
	VerdictFail    = "fail"
	VerdictTimeout = "timeout"
	VerdictBlocked = "blocked"
	VerdictNotRun  = "not_run"
)

Aggregate verdicts. not_run is in the enum on purpose, against the four-value draft of the phase plan: a verify that ran nothing is not an approval, and a cancelled batch reported as failures becomes N phantom remediations downstream. The autonomy policy requires verdict == pass, literally.

View Source
const (
	StatusPassed   = "passed"
	StatusFailed   = "failed"
	StatusTimedOut = "timed_out"
	StatusBlocked  = "blocked"
	StatusNotRun   = "not_run"
)

Per-command outcome. The verdict is a struct, never a formatted string: the previous product decided error by comparing the summary to a literal phrase, so adding the duration to the formatter would have silently inverted the verdict of every successful command.

View Source
const ConfigPath = ".jacu/verify-allowlist.json"

ConfigPath is where a project declares its policy. It is read from the project root and never from a run worktree: the worktree is writable by the model, and a policy the governed object can edit is not a policy.

View Source
const CurrentTaskSchemaVersion = "2"
View Source
const (
	ToolName = "jacu_verify"
)

Variables

This section is empty.

Functions

func RegisterTool

func RegisterTool(server *mcp.Server, root string)

func RegisterToolWithTaskManager

func RegisterToolWithTaskManager(server *mcp.Server, root string, manager *TaskManager)

func RetainTasksAt

func RetainTasksAt(root string, now time.Time) error

RetainTasksAt applies the durable task retention policy for root at now. It is shared with explicit storage lifecycle actions; callers never need to reproduce task classification or deletion decisions.

func Run added in v0.4.0

func RunWithManager added in v0.4.0

func RunWithManager(ctx context.Context, root string, in Input, manager *TaskManager) capabilityruntime.Result

func SearchPath

func SearchPath(pathDirs []string) []string

SearchPath exposes the verifier's reconstructed search path to read-only preflight checks so they predict the environment in which verification runs.

func ValidTaskID

func ValidTaskID(taskID string) bool

Types

type Allowlist

type Allowlist struct {
	// contains filtered or unexported fields
}

Allowlist is the effective policy: the curated global list plus the project allowances, minus the project denials.

func New

func New(config Config) Allowlist

New composes the effective allowlist. Deny wins over allow and over the global list, always — it is the only precedence that cannot loosen policy by accident.

func (Allowlist) Check

func (a Allowlist) Check(argv []string) error

Check applies the rejection order of the phase design. The first rule that matches decides, and every refusal names its own reason: every later gate would also refuse, so a caller reading only "refused" cannot tell which door is locked.

The first rule of the design — a command passed as a single string instead of an argv array — is enforced by the tool schema, which has no string command field to send.

func (Allowlist) KnowsProgram

func (a Allowlist) KnowsProgram(program string) bool

func (Allowlist) Programs

func (a Allowlist) Programs() []string

Programs lists the authorized program names. It exists so a test can prove that checking a command never changes the policy.

type Config

type Config struct {
	Allow    []Entry  `json:"allow,omitempty"`
	Deny     []string `json:"deny,omitempty"`
	PathDirs []string `json:"path_dirs,omitempty"`
}

Config is the per-project policy, read from the project root.

func LoadConfig

func LoadConfig(root string) (Config, error)

LoadConfig reads the project policy. An absent file is normal and means the global list applies alone; a malformed file is an error, because a broken policy must not degrade into no policy.

type Data

type Data struct {
	Verdict         string    `json:"verdict"`
	Commands        []Result  `json:"commands"`
	EvidenceDigest  string    `json:"evidence_digest"`
	TotalDurationMs int64     `json:"total_duration_ms"`
	Task            *TaskInfo `json:"task,omitempty"`
}

Data is the stable result contract that phases 07 and 09 consume.

type Entry

type Entry struct {
	Program           string   `json:"program"`
	RequiredArgPrefix []string `json:"required_arg_prefix,omitempty"`
}

Entry authorizes a program and, optionally, a required prefix of arguments. The prefix authorizes a prefix, not the whole line: {go, [test]} allows `go test ./... -race` and does not allow `go build`.

type Envelope

type Envelope struct {
	Status      string   `json:"status"`
	Summary     string   `json:"summary"`
	Data        Data     `json:"data"`
	Warnings    []string `json:"warnings"`
	NextActions []string `json:"next_actions"`
}

Envelope mirrors the runtime result the capability layer wraps.

func RunCommand

func RunCommand(ctx context.Context, root string, in RunCommandInput) Envelope

RunCommand executes a single diagnostic command inside a run worktree.

func Verify

func Verify(ctx context.Context, root string, in Input) (result Envelope)

Verify runs the mission's verification commands, in order, inside the run worktree.

type Execution

type Execution struct {
	Data    Data
	Refusal string
}

Execution is the verify-owned batch seam shared by jacu_verify and jacu_apply. Refusal is non-empty only when policy or executor setup blocks the batch before ordinary command-result aggregation.

func ExecuteCommands

func ExecuteCommands(ctx context.Context, root string, run runstate.Run, commands [][]string) Execution

ExecuteCommands applies the complete verify policy and bounded executor to an authoritative command batch. The whole batch is checked before the first spawn, so a refused later argv cannot leave effects from an earlier one.

type Input

type Input struct {
	RunID  string   `json:"run_id,omitempty"`
	ArgV   []string `json:"argv,omitempty"`
	Async  bool     `json:"async,omitempty"`
	TaskID string   `json:"task_id,omitempty"`
	Cancel bool     `json:"cancel,omitempty"`
}

Input is the whole surface: no command, no timeout, no allowlist. The argv comes from the compiled mission, and limits are runtime policy, never a parameter of the object being governed.

type RawTaskExecutor

type RawTaskExecutor func(context.Context, json.RawMessage) (json.RawMessage, error)

RawTaskExecutor is used by a registered capability that has its own stable JSON result. Registration is explicit; this is not a generic dispatch or shell execution hook.

type Result

type Result struct {
	ArgV       []string `json:"argv"`
	Status     string   `json:"status"`
	ExitCode   *int     `json:"exit_code,omitempty"`
	DurationMs int64    `json:"duration_ms"`
	StdoutTail string   `json:"stdout_tail"`
	StderrTail string   `json:"stderr_tail"`
	Truncated  bool     `json:"truncated"`
	BytesOut   int64    `json:"bytes_out"`
	Digest     string   `json:"digest"`
	Reason     string   `json:"reason,omitempty"`
}

Result is one command's outcome. not_run is a first-class state: a cancelled run that reports N failures produces N phantom remediations downstream.

type RunCommandInput

type RunCommandInput = Input

RunCommandInput is the one place a command may be named by the caller. It is still not a shell: argv is an array, it faces the same allowlist and the same limits as verification, and there is no timeout or policy parameter. RunCommandInput is retained as an internal source-compatibility alias while callers migrate to Input and the single jacu_verify MCP door.

type Runner

type Runner struct {
	// Worktree is the working directory and the boundary: a program resolved
	// inside it is refused, because a verifier supplied by the thing being
	// verified is not verification.
	Worktree string
	// PathDirs are the project-declared directories, highest precedence in the
	// reconstructed PATH.
	PathDirs []string
	// ToolchainHome is the synthetic HOME. Dropping HOME entirely breaks every
	// toolchain that needs a cache; passing the real one hands the command
	// ~/.aws and ~/.config/gh.
	ToolchainHome string
	// ScratchDir becomes TMPDIR, outside the worktree.
	ScratchDir string
	Timeout    time.Duration
	TailBytes  int
}

Runner executes one allowlisted command under the phase limits.

func (Runner) Run

func (r Runner) Run(ctx context.Context, argv []string) Result

Run executes argv. It never returns an error: every outcome, including a refusal, is a Result — the caller aggregates verdicts, it does not handle exceptions.

type Task

type Task struct {
	SchemaVersion   string          `json:"schema_version"`
	TaskID          string          `json:"task_id"`
	Capability      string          `json:"capability"`
	RunID           string          `json:"run_id"`
	Input           json.RawMessage `json:"input,omitempty"`
	Status          TaskStatus      `json:"status"`
	CreatedAt       time.Time       `json:"created_at"`
	StartedAt       time.Time       `json:"started_at,omitempty"`
	FinishedAt      time.Time       `json:"finished_at,omitempty"`
	Reason          string          `json:"reason,omitempty"`
	Result          *Envelope       `json:"result,omitempty"`
	ResultRaw       json.RawMessage `json:"result_raw,omitempty"`
	ResultDigest    string          `json:"result_digest,omitempty"`
	ExpiresAt       time.Time       `json:"expires_at,omitempty"`
	PayloadPrunedAt time.Time       `json:"payload_pruned_at,omitempty"`
}

Task is the durable record. Input is normalized before persistence: the worker must never re-enter the async/cancel dispatch path when it resumes.

func (*Task) Transition

func (task *Task) Transition(next TaskStatus) error

type TaskConfig

type TaskConfig struct {
	MaxConcurrent int
	TaskTimeout   time.Duration
	ResultTTL     time.Duration
	Executor      TaskExecutor
	Now           func() time.Time
	ID            func() (string, error)
}

type TaskExecutor

type TaskExecutor func(context.Context, Input) Envelope

type TaskInfo

type TaskInfo struct {
	TaskID       string     `json:"task_id"`
	RunID        string     `json:"run_id"`
	Status       TaskStatus `json:"status"`
	Reason       string     `json:"reason,omitempty"`
	ResultDigest string     `json:"result_digest,omitempty"`
}

TaskInfo is the bounded metadata returned by async start and cancellation. The result is intentionally separate so callers can distinguish task state from the verdict produced by verify.

type TaskManager

type TaskManager struct {
	// contains filtered or unexported fields
}

func NewTaskManager

func NewTaskManager(root string) (*TaskManager, error)

func NewTaskManagerWithConfig

func NewTaskManagerWithConfig(root string, config TaskConfig) (*TaskManager, error)

func (*TaskManager) Cancel

func (manager *TaskManager) Cancel(taskID string) (TaskInfo, error)

func (*TaskManager) Get

func (manager *TaskManager) Get(taskID string, includeResult bool) (TaskSnapshot, error)

func (*TaskManager) List

func (manager *TaskManager) List(includeResult bool) ([]TaskSnapshot, error)

func (*TaskManager) RegisterRawExecutor

func (manager *TaskManager) RegisterRawExecutor(capability string, executor RawTaskExecutor) error

RegisterRawExecutor installs one named internal capability executor. The name is still persisted in the task record and is never supplied as an MCP command by the caller.

func (*TaskManager) RetainTasks

func (manager *TaskManager) RetainTasks() error

RetainTasks compacts expired payloads and bounds terminal metadata. It is explicitly invoked at startup/list time; no background collector is used.

func (*TaskManager) Start

func (manager *TaskManager) Start(ctx context.Context, input Input) (TaskInfo, error)

func (*TaskManager) StartRaw

func (manager *TaskManager) StartRaw(ctx context.Context, capability, runID string, input json.RawMessage) (TaskInfo, error)

type TaskSnapshot

type TaskSnapshot struct {
	TaskInfo
	// Result is intentionally unrestricted in the advertised status schema: it
	// is the already-versioned verify envelope, and duplicating all command
	// evidence here would consume the global tools/list budget.
	Result any `json:"result,omitempty"`
}

type TaskStatus

type TaskStatus string
const (
	TaskQueued    TaskStatus = "queued"
	TaskRunning   TaskStatus = "running"
	TaskDone      TaskStatus = "done"
	TaskFailed    TaskStatus = "failed"
	TaskCancelled TaskStatus = "cancelled"
	TaskTimeout   TaskStatus = "timeout"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL