Documentation
¶
Overview ¶
Posture-gated autonomy, arithmetic half. The api half — the gate that refuses a request shape and derives a hold — is internal/api/runs_autonomy.go; everything here is PURE, so launch and the Review dry run fold the same inputs to the same answer by construction.
The comparator for "which ceiling grant bounds this proposed grant". Lives here because composer holds the RUNTIME clamp and internal/api (the WRITE-TIME comparator) imports composer, not the reverse — one definition, two callers.
SECURITY invariant: both callers must ask it the same way — some single ceiling grant must dominate the proposal on every axis. A per-kind map must never supply the bound instead: the LAST same-kind ceiling grant would win, so a ceiling listing two ssh_key grants (normal for two forges) could clamp a proposal naming the STRICT forge's pairing to the PERMISSIVE forge's posture, answering differently by slice order.
Index ¶
- Constants
- func AutonomyPostureOf(spec types.RunPolicySpec, enforced types.ConfinementClass) types.AutonomyPosture
- func CapDiskMiB(disk, ceil int) int
- func CeilingGrantsCovering(g types.GrantSpec, ceiling []types.GrantSpec) []types.GrantSpec
- func Clamp(proposed, ceiling types.RunPolicySpec, maxEphemeralDiskMiB int) (types.RunPolicySpec, []string)
- func ClampRunConfinement(runClass string, floor types.ConfinementClass) (string, string)
- func EffectiveConfinementFloor(policyMin, floor, cap types.ConfinementClass) types.ConfinementClass
- func FoldAutonomy(rubric types.AutonomyRubric, posture types.AutonomyPosture) (types.AutonomyLevel, []string)
- func GitHubScopeWithin(proposed, ceiling json.RawMessage) error
- func GrantPairing(g types.GrantSpec) (host, secretRef, knownHostsRef string, covered, ok bool)
- func PairingInCeiling(g types.GrantSpec, ceiling []types.GrantSpec) bool
- func RequiredConfinementFloor(spec types.RunPolicySpec) types.ConfinementClass
- type RiskItem
- type RiskLevel
- type RunInput
Constants ¶
const WarnResourcesCapped = "resources capped to operator maximum"
ClampRunConfinement raises a proposed run's confinement class to the policy floor (never lowers) so the composer can't emit a run that handleCreateRun would 422 for advertising a weaker class than its own inline_policy floor (invariant 5); empty/unknown ranks 0 and is also raised. WarnResourcesCapped is shared with dispatch's own ephemeral-disk clamp (runs_dispatch_ceiling.go) so the same fact about the same number isn't hand-typed twice and drift apart.
Variables ¶
This section is empty.
Functions ¶
func AutonomyPostureOf ¶ added in v0.8.0
func AutonomyPostureOf(spec types.RunPolicySpec, enforced types.ConfinementClass) types.AutonomyPosture
AutonomyPostureOf grades a run's three-axis posture from its RESOLVED spec and the confinement class the run will actually enforce. It keys on the same inputs as Grade and RequiredConfinementFloor, so posture and risk grade never disagree about what "powerful" or "beyond baseline" means on the same Review screen. Purely a function of the spec, never of anything a model claimed.
func CapDiskMiB ¶ added in v0.7.2
CapDiskMiB bounds a non-zero ephemeral-disk size by one operator ceiling; 0 on either side means "no bound". Shared by Clamp (preview) and api.ephemeralDiskFor (dispatch) so both ceilings agree — previously each applied a different ceiling (profile vs org), so a 100000 MiB policy under a 4096 MiB org max previewed 100000 but ran on 4096; pinned by TestPreflightAndDispatchAgreeOnEphemeralDisk. A zero disk stays zero: a ceiling bounds a request, it never invents one.
func CeilingGrantsCovering ¶ added in v0.7.0
CeilingGrantsCovering returns the ceiling grants whose identity covers g (same kind, and for a stored-secret kind the same host/secret/known_hosts pairing) — exported so api's write-time comparator selects from the same set the runtime clamp bounds against, one definition not two. Identity only, never bounds: an undecodable proposal scope is covered by nothing (fail closed).
func Clamp ¶
func Clamp(proposed, ceiling types.RunPolicySpec, maxEphemeralDiskMiB int) (types.RunPolicySpec, []string)
Clamp tightens a proposed RunPolicySpec to the operator's policy ceiling so the composer can never propose something more permissive than the operator allows, returning the clamped spec and a warning for every tightening performed. Defense-in-depth alongside the deterministic risk grade: the grade informs the human, this enforces the operator's hard limits regardless of what an untrusted-input-driven analyzer or a member's own inline_policy proposed.
The returned spec owns its memory (see cloneProposal): it shares no backing array or pointee with either argument, so a later mutation of either side can never move an already-enforced ceiling.
maxEphemeralDiskMiB is the acting principal's GovernanceLimits.MaxEphemeralDiskMiB (0 = unlimited). It's applied via CapDiskMiB, shared with dispatch's own ephemeral-disk clamp so preview and the actual run agree, and only clamps a non-zero request since 0 means unbounded scratch.
func ClampRunConfinement ¶
func ClampRunConfinement(runClass string, floor types.ConfinementClass) (string, string)
func EffectiveConfinementFloor ¶
func EffectiveConfinementFloor(policyMin, floor, cap types.ConfinementClass) types.ConfinementClass
EffectiveConfinementFloor caps the per-run floor (the Getting Started default tier, sent raise-only) at the strongest class this host's runner can enforce, then returns max(policyMin, cappedFloor). The cap degrades only the per-run floor, never policyMin — an unenforceable policy minimum still fails closed at launch (invariant 5); degrading it here would make compose the one path that bypasses an operator security control. cap=="" means "do not cap". Feeding the result into Clamp's ceiling reuses its existing "confinement raised" warning.
func FoldAutonomy ¶ added in v0.8.0
func FoldAutonomy(rubric types.AutonomyRubric, posture types.AutonomyPosture) (types.AutonomyLevel, []string)
FoldAutonomy folds a rubric against a posture: the level is the MINIMUM over the three fields the posture selects, and boundBy names EVERY field tied at that minimum (its rubric wire name), not just the first — so an admin who raises one capping row can see the level not move because another field tied it. An unset field caps nothing and is skipped, so an all-unset rubric returns ("", nil), matching the "empty means unrestricted" rule every GovernanceLimits field follows. Order is applicableAutonomyCaps's fixed field order, so the audit row and the Review response agree byte for byte.
func GitHubScopeWithin ¶ added in v0.7.0
func GitHubScopeWithin(proposed, ceiling json.RawMessage) error
GitHubScopeWithin reports whether a proposed github_token scope stays inside a ceiling's, by the same rules clampGitHubScope enforces (ceiling repo list is an allowlist, empty = deny-all; an absent permission is ungrantable; a present one bounds the level by permRank) — one shared copy so accept-here can't drift from widen-there.
Differs in one way: an undecodable scope is an error here, not empty, since a comparator reading "no constraint" would fail open (the clamp instead intersects toward empty, fail-closed).
func GrantPairing ¶ added in v0.7.0
GrantPairing returns the pairing a grant names and whether its kind names a stored secret at all. covered=false is honest for github_token/cloud_sts, which name no stored secret. ok=false means the scope didn't decode into a usable pairing — deliberately not an error return, since fail-closed here means an unreadable scope never MATCHES anything. env_secret puts the env var NAME in the host slot.
func PairingInCeiling ¶ added in v0.7.0
PairingInCeiling reports whether some ceiling grant of the SAME kind names the same stored-secret pairing — the identity axis of the one comparator (internal/api's storedSecretPairingInCeiling forwards to it). Takes the whole proposed grant, not a destructured pairing, so the pairing rule lives in exactly ONE decoder. Fail-closed: a grant whose kind names no stored secret, or whose scope doesn't decode, is in no pairing.
func RequiredConfinementFloor ¶
func RequiredConfinementFloor(spec types.RunPolicySpec) types.ConfinementClass
RequiredConfinementFloor returns the deterministic minimum confinement class a run's blast radius requires, independent of model/operator choice: SECURITY: a run holding a write-capable grant or an api_key to a non-baseline host is a high-value target and must run in CC3 so an escape is contained. "" means no floor. Enforced both at composer proposal and (defense-in-depth) at run.create.
Types ¶
type RiskItem ¶
type RiskItem struct {
Field string `json:"field"`
Value string `json:"value"`
Level RiskLevel `json:"risk_level"`
Rationale string `json:"rationale"`
InvariantRef string `json:"invariant_ref,omitempty"`
}
RiskItem is one graded config choice. Field/Value identify what was graded, Level is Wardyn's deterministic grade, Rationale explains it to the human, and InvariantRef (optional) cites the security invariant the choice bears on.
func Grade ¶
func Grade(run RunInput, spec types.RunPolicySpec) []RiskItem
Grade computes the deterministic risk assessment of a proposed run setup purely from its fields. SECURITY: it never consults any LLM self-assessment — a prompt-injected attachment cannot lower the grade, since the grade is a function of the spec, not of anything the model claims about it. Emits one item per notable choice (including LOW ones), sorted riskiest-first.
type RiskLevel ¶
type RiskLevel string
RiskLevel is Wardyn's deterministic grade for a single config choice.
func OverallLevel ¶
OverallLevel returns the highest level among items (low if none).
type RunInput ¶
type RunInput struct {
Agent string `json:"agent"`
Repo string `json:"repo"`
Task string `json:"task"`
ConfinementClass string `json:"confinement_class,omitempty"`
Interactive bool `json:"interactive,omitempty"`
DevcontainerRepo string `json:"devcontainer_repo,omitempty"`
}
RunInput is the scalar create-run fields graded by Grade — the same fields the wizard's buildSpec puts on `run`. Mapped onto the create-run request by the API layer (this package must not import internal/api).