Documentation
¶
Overview ¶
Package policy loads lane policy (ADR-006): .agents/factory/lanes.yaml, validated against the published schema, with defaults applied, a hash per lane for the decision record, CEL guards over structured facts, and placeholders filled only from labels.
Index ¶
- Constants
- Variables
- func DefinesLane(doc []byte, name string) bool
- func Expand(tmpl string, labels []string) (string, error)
- func ExpandShape(tmpl string) string
- func Guard(expr string, facts, item map[string]any) (bool, error)
- func LabelValue(labels []string, prefix string) (string, bool)
- func LaneSources(config, repo []byte, lane string) (map[string]string, error)
- func MergeLanes(config, repo []byte) ([]byte, error)
- func ParseDuration(s string) (time.Duration, error)
- func Resolve(exists func(dir string) bool) (dir string, shadowed []string)
- func ValidateYAML(schemaJSON []byte, schemaURL string, doc []byte) error
- type Budgets
- type Command
- type Defaults
- type Egress
- type Factory
- type File
- type Guards
- type Intake
- type LabelChange
- type Labels
- type Lane
- type PR
- type Pin
- type Reaction
- type Run
- type Stop
- type Ynh
Constants ¶
const DefaultNoCIAfter = 30 * time.Minute
DefaultNoCIAfter is how long a proposed commit may report no check or status at all before the item escalates, when a lane does not say.
const FactoryFile = "factory.yaml"
FactoryFile is a configuration repository's factory file, in its factory folder (ADR-006).
const LanesFile = "lanes.yaml"
LanesFile is the name of the lane policy file in a factory folder.
Variables ¶
var FactoryDirs = []string{".agents/factory", ".ynh/ynf", ".ynm/ynf", ".ynf"}
FactoryDirs is where a repository keeps ynf's files, in lookup order (ADR-009). The first found wins; the others are shadowed and reported, never merged.
var SafeLabel = regexp.MustCompile(`^[A-Za-z0-9._/-]+(:[A-Za-z0-9._/-]+)?$`)
SafeLabel is what a label given with a prompt must match: a plain name or <prefix>:<value>.
var SafeValue = regexp.MustCompile(`^[A-Za-z0-9._/-]+$`)
SafeValue is what a substituted value must match, so ticket data never reaches a shell as anything but a plain path-like token (ADR-006).
Functions ¶
func DefinesLane ¶
DefinesLane reports whether a lanes.yaml document declares a lane called name. A document that does not parse declares none.
func ExpandShape ¶
ExpandShape fills every {label.<prefix>} placeholder with a safe dummy path segment, to check the shape of a template before any item's labels are known.
func Guard ¶
Guard evaluates a CEL guard over structured facts and the item. Free text is never in facts (ADR-006), so a ticket body cannot steer a guard.
func LabelValue ¶
LabelValue returns the value of the first '<prefix>:<value>' label.
func LaneSources ¶
LaneSources says where each of a lane's values came from: every leaf path in the merged lane (dotted, such as run.ynh.focus) maps to "repo" when the repository's lanes set it and "config" when only the configuration repository's do.
func MergeLanes ¶
MergeLanes lays a target repository's lanes over a configuration repository's, key by key: the target repository wins (ADR-006). Maps merge; anything else in the repository replaces the configuration's, lists included, so a repository can narrow a list as well as extend it. Either may be empty. The result is validated as a whole when it is loaded, so a repository may hold only overrides, such as turning a lane off with enabled: false.
func ParseDuration ¶
ParseDuration accepts the schema's durations, including days.
Types ¶
type Budgets ¶
type Budgets struct {
MaxTurns int `yaml:"max_turns" json:"max_turns,omitempty"`
MaxTokens int `yaml:"max_tokens" json:"max_tokens,omitempty"`
MaxWall string `yaml:"max_wall" json:"max_wall,omitempty"`
}
Budgets may only tighten the harness's own.
type Command ¶
type Command struct {
Argv []string `yaml:"argv" json:"argv"`
// Image is the image the command runs in on a container executor. When the lane resolves to
// the command runner it wins over run.image; when it resolves to ynh it is ignored.
Image string `yaml:"image" json:"image,omitempty"`
// ImageUser keeps the image's own user and home, as a ynh-built agent image does, instead of
// running as ynf's user. It is for an image whose command needs its own user; a docker executor
// only.
ImageUser bool `yaml:"image_user" json:"image_user,omitempty"`
ResultFile string `yaml:"result_file" json:"result_file,omitempty"`
}
Command is the command runner's settings.
type Defaults ¶
type Defaults struct {
Executor string `yaml:"executor" json:"executor,omitempty"`
Attempts int `yaml:"attempts" json:"attempts,omitempty"`
Retention string `yaml:"retention" json:"retention,omitempty"`
NoCIAfter string `yaml:"no_ci_after" json:"no_ci_after,omitempty"`
Egress *Egress `yaml:"egress" json:"egress,omitempty"`
Stop *Stop `yaml:"stop" json:"stop,omitempty"`
PR *PR `yaml:"pr" json:"pr,omitempty"`
Labels *Labels `yaml:"labels" json:"labels,omitempty"`
}
Defaults are what every lane inherits unless it sets its own.
type Egress ¶
type Egress struct {
Allow []string `yaml:"allow" json:"allow"`
}
Egress is what a run may reach (ADR-007).
type Factory ¶
type Factory struct {
Version int `yaml:"version" json:"version"`
Repos []string `yaml:"repos" json:"repos"`
Trackers map[string]map[string]any `yaml:"trackers" json:"trackers,omitempty"`
Forges map[string]map[string]any `yaml:"forges" json:"forges,omitempty"`
}
Factory is a configuration repository's factory.yaml: enrolment, and the tracker and forge instances, which are declared only here.
func LoadFactory ¶
LoadFactory validates and reads a factory.yaml.
type File ¶
type File struct {
Version int `yaml:"version" json:"version"`
Defaults Defaults `yaml:"defaults" json:"defaults"`
Lanes map[string]Lane `yaml:"lanes" json:"lanes"`
}
File is a parsed lanes.yaml.
type Guards ¶
type Guards struct {
Eligible string `yaml:"eligible" json:"eligible,omitempty"`
}
Guards are CEL expressions over structured facts.
type Intake ¶
type Intake struct {
GitHubSearch string `yaml:"github.search" json:"github.search,omitempty"`
JiraSearch string `yaml:"jira.search" json:"jira.search,omitempty"`
Every string `yaml:"every" json:"every,omitempty"`
}
Intake is one source of work for a lane.
type LabelChange ¶
type LabelChange struct {
Add []string `yaml:"add" json:"add,omitempty"`
Remove []string `yaml:"remove" json:"remove,omitempty"`
}
LabelChange adds and removes labels.
type Labels ¶
type Labels struct {
OnClaim *LabelChange `yaml:"on_claim" json:"on_claim,omitempty"`
OnPropose *LabelChange `yaml:"on_propose" json:"on_propose,omitempty"`
OnReview *LabelChange `yaml:"on_review" json:"on_review,omitempty"`
OnEscalate *LabelChange `yaml:"on_escalate" json:"on_escalate,omitempty"`
OnDone *LabelChange `yaml:"on_done" json:"on_done,omitempty"`
}
Labels are what ynf writes on the ticket as the item enters a state (ADR-003, ADR-006).
func (*Labels) For ¶
func (l *Labels) For(state string) *LabelChange
For is the change for an item entering state, or nil.
type Lane ¶
type Lane struct {
Name string `yaml:"-" json:"name"`
// ID is the lane's own id for telemetry, when it declares one; otherwise the id is where the
// lane is defined plus its name (ADR-006).
ID string `yaml:"id" json:"id,omitempty"`
Kind string `yaml:"kind" json:"kind"`
Enabled *bool `yaml:"enabled" json:"enabled,omitempty"`
Intake []Intake `yaml:"intake" json:"intake"`
Guards Guards `yaml:"guards" json:"guards"`
Run Run `yaml:"run" json:"run"`
When map[string]Reaction `yaml:"when" json:"when"`
PR PR `yaml:"pr" json:"pr"`
Stop Stop `yaml:"stop" json:"stop"`
Executor string `yaml:"executor" json:"executor,omitempty"`
Attempts int `yaml:"attempts" json:"attempts,omitempty"`
Retention string `yaml:"retention" json:"retention,omitempty"`
// NoCIAfter is how long a proposed head commit may have no check or status at all before the
// item reacts (when: no_ci). Empty means DefaultNoCIAfter; 0s switches it off.
NoCIAfter string `yaml:"no_ci_after" json:"no_ci_after,omitempty"`
Labels *Labels `yaml:"labels" json:"labels,omitempty"`
}
Lane is one lane, with defaults applied after Load.
func (Lane) CheckLabels ¶
CheckLabels reports whether labels fill every {label.<prefix>} placeholder the lane's runs use, with safe values: its command's arguments and its ynh sensor scopes. Work the lane cannot run is refused before it starts, rather than failing in its first run.
func (Lane) Hash ¶
Hash is the SHA-256 of the lane's normalised form, recorded with every decision (ADR-006).
type PR ¶
type PR struct {
AllowedPaths []string `yaml:"allowed_paths" json:"allowed_paths,omitempty"`
ProtectedPaths []string `yaml:"protected_paths" json:"protected_paths,omitempty"`
Draft *bool `yaml:"draft" json:"draft,omitempty"`
}
PR is how changes are proposed.
type Pin ¶
type Pin struct {
Repo string `json:"repo"`
Ref string `json:"ref"`
// URL is the repository as the clone tools are given it, set only when it differs from Repo:
// a bare host and path is cloned over https.
URL string `json:"url,omitempty"`
}
Pin is a harness pinned from a repository: the repository and the tag or commit to take from it. A lane writes it as run.ynh.harness: <repository>@<tag-or-commit>, such as github.com/org/harness@v1.2.0 or file:///srv/harness.git@3f9c2e1. ynh takes the same two things as `ynh install <repository> --ref <tag-or-commit>`.
func ParsePin ¶
ParsePin reads a lane's harness value. ok is false when it is not a pin: a folder in the repository, or the id of an installed harness. A value shaped like a pin that cannot be used as one (no tag or commit, or one a flag could be mistaken for) is an error, so a typo is refused rather than run as an installed id.
func (Pin) CloneURL ¶
CloneURL is the repository as the clone tools are given it. A URL with a scheme and an scp-like address are used as written; a bare host and path, such as github.com/org/repo, is https://github.com/org/repo, because the clone tools read the bare form as a folder.
type Reaction ¶
type Reaction struct {
Action string `json:"action,omitempty"`
Retry int `json:"retry,omitempty"`
Then string `json:"then,omitempty"`
ResumeWith string `json:"resume_with,omitempty"`
Max int `json:"max,omitempty"`
}
Reaction is what to do for an outcome: an action, a retry then an action, or a resume.
type Run ¶
type Run struct {
Runner string `yaml:"runner" json:"runner,omitempty"`
Executor string `yaml:"executor" json:"executor,omitempty"`
Image string `yaml:"image" json:"image,omitempty"`
Egress *Egress `yaml:"egress" json:"egress,omitempty"`
Env []string `yaml:"env" json:"env,omitempty"`
Ynh *Ynh `yaml:"ynh" json:"ynh,omitempty"`
Command *Command `yaml:"command" json:"command,omitempty"`
}
Run is how a lane's runs are made.
type Stop ¶
type Stop struct {
YieldFloor float64 `yaml:"yield_floor" json:"yield_floor,omitempty"`
ReviewTimeCeiling string `yaml:"review_time_ceiling" json:"review_time_ceiling,omitempty"`
EscapedDefects int `yaml:"escaped_defects" json:"escaped_defects,omitempty"`
MaxOpenProposals int `yaml:"max_open_proposals" json:"max_open_proposals,omitempty"`
MinSample int `yaml:"min_sample" json:"min_sample,omitempty"`
}
Stop holds stop conditions (ADR-010).
type Ynh ¶
type Ynh struct {
Harness string `yaml:"harness" json:"harness"`
Vendor string `yaml:"vendor" json:"vendor,omitempty"`
Base string `yaml:"base" json:"base,omitempty"`
Focus string `yaml:"focus" json:"focus,omitempty"`
Profile string `yaml:"profile" json:"profile,omitempty"`
Sandbox string `yaml:"sandbox" json:"sandbox,omitempty"`
// Model is ynh's --model: the model the agent runs on, as the vendor names it. Empty is the
// vendor's default. The schema limits it to a plain name, so it never reaches argv as a flag.
Model string `yaml:"model" json:"model,omitempty"`
// Effort is ynh's --effort (low, medium or high): the reasoning effort the agent is asked to
// run at, which ynh maps to each vendor's own setting and refuses where a vendor has none.
// Empty is the harness's agent.effort, else the vendor's default. It needs ynh 0.10.0 or later.
Effort string `yaml:"effort" json:"effort,omitempty"`
// AutoApprove is ynh's --auto-approve (edits or all): the worker runs without approval prompts.
// ynf passes it only to a contained run (ADR-007).
AutoApprove string `yaml:"auto_approve" json:"auto_approve,omitempty"`
Budgets *Budgets `yaml:"budgets" json:"budgets,omitempty"`
SensorScope map[string]string `yaml:"sensor_scope" json:"sensor_scope,omitempty"`
// TelemetryRelay sets YNH_TELEMETRY_RELAY=1 for the lane's runs, so ynh agent run starts ynr
// relay beside the vendor CLI and the vendor's telemetry reaches the run's spool folder.
TelemetryRelay bool `yaml:"telemetry_relay" json:"telemetry_relay,omitempty"`
}
Ynh is the ynh runner's settings.