70 lines
2.7 KiB
Rego
70 lines
2.7 KiB
Rego
package scobleclaw.main_agent
|
|
|
|
# main-agent.rego — policy for the primary orchestrator agent.
|
|
#
|
|
# Per scobleclaw#42 refactor: this file now lives at
|
|
# `package scobleclaw.main_agent` (was `package scobleclaw` in the
|
|
# package-root layout). API path is now `data.scobleclaw.main_agent.allow`
|
|
# (was `data.scobleclaw.allow`). The shared `lib` package contributes
|
|
# the base deny rules, which are re-emitted into the per-agent `deny`
|
|
# set below so callers see a single `deny` path per agent.
|
|
#
|
|
# Scope: this is the agent that drives engineering work (Forgejo
|
|
# reads/writes, OB1 captures, kamelet dispatch). It has the tightest
|
|
# allowlist.
|
|
|
|
import data.scobleclaw.lib
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Per-agent allowlist
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Kamelets main-agent is allowed to invoke. Anything else is `needs_l1`
|
|
# (caller decides whether to escalate).
|
|
main_agent_allowed_kamelets = {
|
|
"kamelet:source/forgejo-search",
|
|
"kamelet:source/forgejo-read",
|
|
"kamelet:source/forgejo-create-issue",
|
|
"kamelet:source/forgejo-create-pr",
|
|
"kamelet:source/forgejo-comment",
|
|
"kamelet:source/ob1-capture",
|
|
"kamelet:source/ob1-search",
|
|
"kamelet:source/kamelet-dispatch",
|
|
"kamelet:source/kubectl-exec",
|
|
"kamelet:source/age-decrypt",
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Deny set — re-emit base_deny from lib, plus per-agent rules.
|
|
# ---------------------------------------------------------------------------
|
|
# Each rule below re-publishes a base_deny[reason] entry into the
|
|
# per-agent `deny` set. This keeps the API surface to a single
|
|
# `data.scobleclaw.main_agent.deny` path while still giving lib
|
|
# ownership of the shared rules.
|
|
|
|
deny[reason] {
|
|
lib.base_deny[reason]
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Per-agent allow rule
|
|
# ---------------------------------------------------------------------------
|
|
|
|
allow {
|
|
input.agent_id == "main-agent"
|
|
main_agent_allowed_kamelets[input.kamelet_ref]
|
|
# If the kamelet is on the allowlist, the shared deny rules still apply.
|
|
# Rego semantics: the rule body is true only when ALL expressions hold;
|
|
# `count(deny) == 0` makes the deny-set check explicit in the rule head.
|
|
count(deny) == 0
|
|
}
|
|
|
|
# If the agent is main-agent but the kamelet is NOT on its allowlist, we
|
|
# mark it `needs_l1` so the caller can decide to escalate to an LLM judge
|
|
# or Discord. We do NOT deny outright — a new kamelet might legitimately
|
|
# need to be added to the allowlist via a policy PR.
|
|
needs_l1 {
|
|
input.agent_id == "main-agent"
|
|
not main_agent_allowed_kamelets[input.kamelet_ref]
|
|
not lib.payment_kamelets[input.kamelet_ref]
|
|
}
|