Documentation
¶
Overview ¶
Package cloudagents governs background coding agents that run on vendor or CI infrastructure rather than a developer machine (ADR-0034): it normalizes tasks from vendor APIs and GitHub webhooks into one inventory mapped to Halos identities, plans and executes kill fan-out (cancel) and over-limit pauses, and turns finished tasks into session ledger records. Rendering is in the workflow subpackage.
Vendor calls go through vendoradmin.Client, so they share its credential rules: token only in the Authorization header and scrubbed from errors, no redirects, https (or loopback http) only. Tests run against httptest fakes.
Index ¶
Constants ¶
const ( GitHubBaseURL = vendoradmin.GitHubBaseURL CursorBaseURL = "https://api.cursor.com" )
API base URLs.
const ( OpCancel = "cancel" // stop the running task (terminal) OpPause = "pause" // stop new tasks, reversibly (a human resumes) )
Operations on a task.
const ( ResultDryRun = "dry-run" ResultDone = "done" ResultFailed = "failed" ResultManual = "manual" // no API: Manual says what a human does ResultNoClient = "no-client" // the vendor API was not configured )
Results of an Action.
const ( ScopeUser = "user" ScopeRing = "ring" ScopeExperiment = "experiment" )
Kill scopes: what a kill fans out to.
const ( AlertDisabled = "disabled" // a task of a vendor policy disables AlertUngoverned = "ungoverned" // a task of a vendor policy does not list AlertUnmanaged = "unmanaged" // a run of a workflow Halos did not render AlertRepo = "repo" // a task in a repository not allowed AlertModel = "model" // a task on a model not allowed AlertUnattributed = "unattributed" // a task no identity maps to a Halos user AlertConcurrency = "concurrency" // more running tasks than maxConcurrent AlertBudget = "budget" // vendor-reported usage over a budget )
Alert kinds.
const ( StatusQueued = "queued" StatusRunning = "running" StatusCompleted = "completed" StatusFailed = "failed" StatusCancelled = "cancelled" StatusUnknown = "unknown" )
Task statuses, normalized across vendors.
const ( SourceGitHubWebhook = "github-webhook" SourceGitHubAPI = "github-api" SourceCursorAPI = "cursor-api" )
Task sources.
const MaxWebhookBody = 1 << 20
MaxWebhookBody bounds a webhook delivery GitHub sends (GitHub caps payloads at 25 MB; a workflow_run delivery is a few KiB).
Variables ¶
var ErrBadSignature = errors.New("webhook signature missing or invalid")
ErrBadSignature means a delivery's X-Hub-Signature-256 is missing or does not match any configured secret.
Functions ¶
func NewClient ¶
func NewClient(vendor, base, token string) (*vendoradmin.Client, error)
NewClient returns a vendor API client ("github" or "cursor") with the credential rules of vendoradmin.Client, or an error for a base URL that is not https (or loopback http). base "" uses the vendor's.
func VerifySignature ¶
VerifySignature checks GitHub's X-Hub-Signature-256 header ("sha256=" + hex HMAC-SHA256 of the raw body) against each secret (two while rotating), in constant time. Per https://docs.github.com/en/webhooks/using-webhooks/validating-webhook-deliveries.
Types ¶
type Action ¶
type Action struct {
Task Task `json:"task"`
Op string `json:"op"`
// Call is the vendor API request, or "" when there is none.
Call string `json:"call,omitempty"`
Manual string `json:"manual,omitempty"`
Result string `json:"result"`
Error string `json:"error,omitempty"`
}
Action is one operation on one task, planned and then (unless a dry run) executed.
type Alert ¶
type Alert struct {
Vendor string `json:"vendor"`
Kind string `json:"kind"`
Key string `json:"key,omitempty"` // user:<id>, group:<g>, org, the repo, the model
Message string `json:"message"`
Value int64 `json:"value,omitempty"`
Limit int64 `json:"limit,omitempty"`
Tasks []string `json:"tasks"`
Pause []string `json:"pause,omitempty"`
}
Alert is one policy violation or over-limit among tasks. Pause lists the tasks to pause when the vendor's onOverLimit is pause (empty otherwise, and for kinds that do not pause).
type Clients ¶
type Clients struct {
GitHub *vendoradmin.Client
Cursor *vendoradmin.Client
// CursorUser is the Halos user the Cursor key belongs to: Cursor lists
// only the key's own agents and names no user.
CursorUser string
}
Clients are the vendor APIs a caller was given; a nil client is not read and its actions are not attempted.
func (Clients) Fetch ¶
func (c Clients) Fetch(ctx context.Context, org *policy.Org, since time.Time) (tasks []Task, warns, errs []string)
Fetch reads the cloud agent tasks created since `since` from every client it has, attributed to Halos users. Each vendor that fails is reported in errs (credential-free) and the others are still read.
type Groups ¶
Groups returns a Halos user's groups (the SCIM directory on halo-server; nil in the CLI, where ring membership then comes from users, percent and default only).
type Task ¶
type Task struct {
// ID is "<vendor>:<repo or agent>:<run>", stable across sources.
ID string `json:"id"`
Vendor string `json:"vendor"`
Source string `json:"source"`
Repo string `json:"repo,omitempty"` // owner/repo
// Ref is the vendor object a cancel targets: the Actions run id, or the
// Cursor agent id. RunRef is Cursor's run id.
Ref string `json:"ref"`
RunRef string `json:"runRef,omitempty"`
// Workflow is the Actions workflow file (GitHub-hosted vendors).
Workflow string `json:"workflow,omitempty"`
// Managed is false for a run of a workflow Halos did not render (a copy
// of the vendor's quick-setup file): it is a violation, not governed.
Managed bool `json:"managed"`
VendorUser string `json:"vendorUser,omitempty"`
// User is the Halos identity (cloudAgents.identities); "" = unattributed.
User string `json:"user,omitempty"`
Model string `json:"model,omitempty"`
Status string `json:"status"`
Tokens int64 `json:"tokens,omitempty"`
URL string `json:"url,omitempty"`
Start time.Time `json:"start"`
Updated time.Time `json:"updated"`
End time.Time `json:"end,omitzero"`
}
Task is one cloud agent task, normalized. Every string in it came from a vendor and passed safeID or a fixed vocabulary, so it is safe to print and to use as an API path segment.
func ParseGitHubEvent ¶
ParseGitHubEvent normalizes a verified delivery. ok is false for events that are not cloud agent runs (ping, other workflows, other event types); they are acknowledged and dropped. Call VerifySignature first.
func PauseTasks ¶
PauseTasks are the distinct tasks alerts ask to pause, in task order.
func Select ¶
func Select(org *policy.Org, tasks []Task, scope, name string, groups Groups) (hit []Task, unattributed int, err error)
Select returns the active tasks a kill of scope/name reaches: tasks of the user, of every user the ring resolves, or of every user the experiment assigns a variant (internal/assign through policy, never reimplemented). unattributed counts active tasks with no Halos user, which no ring or experiment kill can reach.
func (Task) Active ¶
Active reports whether the task may still be running (and so counts toward concurrency and can be cancelled).
func (*Task) Attribute ¶
func (t *Task) Attribute(c *policy.CloudAgents)
Attribute sets t.User from the policy's identity map. A Cursor task keeps the API key owner it was fetched with.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package workflow renders the repository files of the workflow-configured cloud agents (ADR-0034): the Claude Code and Gemini CLI GitHub Actions and Copilot's copilot-setup-steps.yml, SHA-pinned and least-privilege, and checks every rendered file against the security invariants.
|
Package workflow renders the repository files of the workflow-configured cloud agents (ADR-0034): the Claude Code and Gemini CLI GitHub Actions and Copilot's copilot-setup-steps.yml, SHA-pinned and least-privilege, and checks every rendered file against the security invariants. |