scobleclaw#42: refactor OPA Rego to per-agent packages (main_agent, demo_concierge, demo_watchdog, lib). Verifies eng#40 7/7 test cases.
This commit is contained in:
parent
39b21dcda5
commit
bfe6e4cdd1
5 changed files with 164 additions and 57 deletions
|
|
@ -1,7 +1,10 @@
|
||||||
---
|
---
|
||||||
# ConfigMap containing the Rego policy bundle. Mounted at /policies in the
|
# ConfigMap containing the Rego policy bundle. Mounted at /policies in the
|
||||||
# OPA pod. Policies share the `scobleclaw` package; per-agent files add
|
# OPA pod. Per scobleclaw#42 refactor (cycle 142): policies are now split
|
||||||
# their own allow + agent-specific deny rules on top of _lib's base denies.
|
# into per-agent packages — `scobleclaw.lib` (helpers + base deny rules)
|
||||||
|
# and one package per agent (`scobleclaw.main_agent`,
|
||||||
|
# `scobleclaw.demo_concierge`, `scobleclaw.demo_watchdog`). API paths are
|
||||||
|
# `data.scobleclaw.<agent>.{allow,deny,needs_l1}`.
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: ConfigMap
|
kind: ConfigMap
|
||||||
metadata:
|
metadata:
|
||||||
|
|
@ -11,11 +14,23 @@ metadata:
|
||||||
app: opa
|
app: opa
|
||||||
component: l0-judge
|
component: l0-judge
|
||||||
data:
|
data:
|
||||||
_lib.rego: |
|
lib.rego: |
|
||||||
package scobleclaw
|
package scobleclaw.lib
|
||||||
|
|
||||||
|
# lib.rego — shared helpers + base deny rules for all agents.
|
||||||
|
#
|
||||||
|
# Per scobleclaw#42 refactor: this file lives at `package scobleclaw.lib`
|
||||||
|
# (was `package scobleclaw` in the package-root layout). Per-agent policy
|
||||||
|
# files (main_agent, demo_concierge, demo_watchdog) `import data.scobleclaw.lib`
|
||||||
|
# to pull in the constants, helpers, and base deny rules. Each per-agent
|
||||||
|
# package re-aggregates `base_deny` into its own `deny` set so the API
|
||||||
|
# surface is `data.scobleclaw.<agent>.deny` (one path per agent).
|
||||||
|
|
||||||
|
# Internal email domain. Anything else is treated as external.
|
||||||
internal_email_domain = "scoble.me"
|
internal_email_domain = "scoble.me"
|
||||||
|
|
||||||
|
# Kamelets that move money or have irreversible side-effects. They are
|
||||||
|
# ALWAYS denied at L0. L1/L2 cannot override an L0 deny.
|
||||||
payment_kamelets = {
|
payment_kamelets = {
|
||||||
"kamelet:source/stripe-charge",
|
"kamelet:source/stripe-charge",
|
||||||
"kamelet:source/paypal-transfer",
|
"kamelet:source/paypal-transfer",
|
||||||
|
|
@ -41,14 +56,17 @@ data:
|
||||||
params.repo != "engineering"
|
params.repo != "engineering"
|
||||||
}
|
}
|
||||||
|
|
||||||
deny[reason] {
|
# Base deny rules. Each per-agent package re-emits these into its own
|
||||||
|
# `deny` set via `deny[reason] { lib.base_deny[reason] }`, giving each
|
||||||
|
# agent a single `data.scobleclaw.<agent>.deny` path.
|
||||||
|
base_deny[reason] {
|
||||||
input.kamelet_ref != ""
|
input.kamelet_ref != ""
|
||||||
input.params.to != ""
|
input.params.to != ""
|
||||||
is_external_email(input.params.domain)
|
is_external_email(input.params.domain)
|
||||||
reason := sprintf("external email not permitted (domain=%v, to=%v)", [input.params.domain, input.params.to])
|
reason := sprintf("external email not permitted (domain=%v, to=%v)", [input.params.domain, input.params.to])
|
||||||
}
|
}
|
||||||
|
|
||||||
deny[reason] {
|
base_deny[reason] {
|
||||||
is_forgejo_write_outside_allowed(input.params)
|
is_forgejo_write_outside_allowed(input.params)
|
||||||
reason := sprintf(
|
reason := sprintf(
|
||||||
"forgejo writes restricted to marcus/engineering (got owner=%v repo=%v)",
|
"forgejo writes restricted to marcus/engineering (got owner=%v repo=%v)",
|
||||||
|
|
@ -56,12 +74,16 @@ data:
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
deny[reason] {
|
base_deny[reason] {
|
||||||
is_payment_kamelet(input.kamelet_ref)
|
is_payment_kamelet(input.kamelet_ref)
|
||||||
reason := sprintf("payment kamelet blocked at L0: %v", [input.kamelet_ref])
|
reason := sprintf("payment kamelet blocked at L0: %v", [input.kamelet_ref])
|
||||||
}
|
}
|
||||||
main-agent.rego: |
|
main-agent.rego: |
|
||||||
package scobleclaw
|
package scobleclaw.main_agent
|
||||||
|
|
||||||
|
# main-agent.rego — policy for the primary orchestrator agent.
|
||||||
|
# Per scobleclaw#42: API path is `data.scobleclaw.main_agent.allow`.
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
main_agent_allowed_kamelets = {
|
main_agent_allowed_kamelets = {
|
||||||
"kamelet:source/forgejo-search",
|
"kamelet:source/forgejo-search",
|
||||||
|
|
@ -76,6 +98,11 @@ data:
|
||||||
"kamelet:source/age-decrypt",
|
"kamelet:source/age-decrypt",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Re-emit lib base_deny into the per-agent deny set.
|
||||||
|
deny[reason] {
|
||||||
|
lib.base_deny[reason]
|
||||||
|
}
|
||||||
|
|
||||||
allow {
|
allow {
|
||||||
input.agent_id == "main-agent"
|
input.agent_id == "main-agent"
|
||||||
main_agent_allowed_kamelets[input.kamelet_ref]
|
main_agent_allowed_kamelets[input.kamelet_ref]
|
||||||
|
|
@ -85,10 +112,14 @@ data:
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "main-agent"
|
input.agent_id == "main-agent"
|
||||||
not main_agent_allowed_kamelets[input.kamelet_ref]
|
not main_agent_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
}
|
||||||
demo-concierge.rego: |
|
demo-concierge.rego: |
|
||||||
package scobleclaw
|
package scobleclaw.demo_concierge
|
||||||
|
|
||||||
|
# demo-concierge.rego — policy for the demo concierge agent.
|
||||||
|
# Per scobleclaw#42: API path is `data.scobleclaw.demo_concierge.allow`.
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
demo_concierge_allowed_kamelets = {
|
demo_concierge_allowed_kamelets = {
|
||||||
"kamelet:source/forgejo-search",
|
"kamelet:source/forgejo-search",
|
||||||
|
|
@ -97,6 +128,18 @@ data:
|
||||||
"kamelet:source/kamelet-dispatch",
|
"kamelet:source/kamelet-dispatch",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Re-emit lib base_deny into the per-agent deny set.
|
||||||
|
deny[reason] {
|
||||||
|
lib.base_deny[reason]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Per-agent deny: demo-concierge is read-only.
|
||||||
|
deny[reason] {
|
||||||
|
input.agent_id == "demo-concierge"
|
||||||
|
startswith(input.kamelet_ref, "kamelet:source/forgejo-create")
|
||||||
|
reason := sprintf("demo-concierge is read-only; %v not permitted", [input.kamelet_ref])
|
||||||
|
}
|
||||||
|
|
||||||
allow {
|
allow {
|
||||||
input.agent_id == "demo-concierge"
|
input.agent_id == "demo-concierge"
|
||||||
demo_concierge_allowed_kamelets[input.kamelet_ref]
|
demo_concierge_allowed_kamelets[input.kamelet_ref]
|
||||||
|
|
@ -106,16 +149,14 @@ data:
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "demo-concierge"
|
input.agent_id == "demo-concierge"
|
||||||
not demo_concierge_allowed_kamelets[input.kamelet_ref]
|
not demo_concierge_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
|
||||||
|
|
||||||
deny[reason] {
|
|
||||||
input.agent_id == "demo-concierge"
|
|
||||||
startswith(input.kamelet_ref, "kamelet:source/forgejo-create")
|
|
||||||
reason := sprintf("demo-concierge is read-only; %v not permitted", [input.kamelet_ref])
|
|
||||||
}
|
}
|
||||||
demo-watchdog.rego: |
|
demo-watchdog.rego: |
|
||||||
package scobleclaw
|
package scobleclaw.demo_watchdog
|
||||||
|
|
||||||
|
# demo-watchdog.rego — policy for the demo watchdog agent.
|
||||||
|
# Per scobleclaw#42: API path is `data.scobleclaw.demo_watchdog.allow`.
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
demo_watchdog_allowed_kamelets = {
|
demo_watchdog_allowed_kamelets = {
|
||||||
"kamelet:source/ob1-search",
|
"kamelet:source/ob1-search",
|
||||||
|
|
@ -124,6 +165,11 @@ data:
|
||||||
"kamelet:source/kamelet-dispatch",
|
"kamelet:source/kamelet-dispatch",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Re-emit lib base_deny into the per-agent deny set.
|
||||||
|
deny[reason] {
|
||||||
|
lib.base_deny[reason]
|
||||||
|
}
|
||||||
|
|
||||||
allow {
|
allow {
|
||||||
input.agent_id == "demo-watchdog"
|
input.agent_id == "demo-watchdog"
|
||||||
demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
||||||
|
|
@ -133,5 +179,5 @@ data:
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "demo-watchdog"
|
input.agent_id == "demo-watchdog"
|
||||||
not demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
not demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
package scobleclaw
|
package scobleclaw.demo_concierge
|
||||||
|
|
||||||
# demo-concierge.rego — policy for the demo concierge agent.
|
# demo-concierge.rego — policy for the demo concierge agent.
|
||||||
#
|
#
|
||||||
# Scope: read-only Forgejo + OB1 read access. No writes anywhere. This is a
|
# Per scobleclaw#42 refactor: this file now lives at
|
||||||
# demo / smoke-test agent; its allowlist is intentionally small.
|
# `package scobleclaw.demo_concierge` (was `package scobleclaw` in the
|
||||||
|
# package-root layout). API path is now
|
||||||
|
# `data.scobleclaw.demo_concierge.allow`.
|
||||||
|
#
|
||||||
|
# Scope: read-only Forgejo + OB1 read access. No writes anywhere. This
|
||||||
|
# is a demo / smoke-test agent; its allowlist is intentionally small.
|
||||||
|
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
demo_concierge_allowed_kamelets = {
|
demo_concierge_allowed_kamelets = {
|
||||||
"kamelet:source/forgejo-search",
|
"kamelet:source/forgejo-search",
|
||||||
|
|
@ -12,6 +19,24 @@ demo_concierge_allowed_kamelets = {
|
||||||
"kamelet:source/kamelet-dispatch",
|
"kamelet:source/kamelet-dispatch",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Deny set — re-emit base_deny from lib, plus per-agent rules.
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
deny[reason] {
|
||||||
|
lib.base_deny[reason]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Per-agent deny rule: demo-concierge is read-only. Any kamelet whose
|
||||||
|
# name suggests a Forgejo write (starts with `forgejo-create`) is
|
||||||
|
# denied at L0. Note: this is in addition to the lib base_deny rules
|
||||||
|
# (external email, forgejo writes outside engineering, payment kamelets).
|
||||||
|
deny[reason] {
|
||||||
|
input.agent_id == "demo-concierge"
|
||||||
|
startswith(input.kamelet_ref, "kamelet:source/forgejo-create")
|
||||||
|
reason := sprintf("demo-concierge is read-only; %v not permitted", [input.kamelet_ref])
|
||||||
|
}
|
||||||
|
|
||||||
# Allow only if kamelet is on the allowlist AND no shared deny rule fires.
|
# Allow only if kamelet is on the allowlist AND no shared deny rule fires.
|
||||||
allow {
|
allow {
|
||||||
input.agent_id == "demo-concierge"
|
input.agent_id == "demo-concierge"
|
||||||
|
|
@ -24,13 +49,5 @@ allow {
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "demo-concierge"
|
input.agent_id == "demo-concierge"
|
||||||
not demo_concierge_allowed_kamelets[input.kamelet_ref]
|
not demo_concierge_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
|
||||||
|
|
||||||
# Per-agent deny rule: demo-concierge is read-only. Any kamelet whose
|
|
||||||
# params suggest a write (presence of `body` + `create_*` action) is denied.
|
|
||||||
deny[reason] {
|
|
||||||
input.agent_id == "demo-concierge"
|
|
||||||
startswith(input.kamelet_ref, "kamelet:source/forgejo-create")
|
|
||||||
reason := sprintf("demo-concierge is read-only; %v not permitted", [input.kamelet_ref])
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,16 @@
|
||||||
package scobleclaw
|
package scobleclaw.demo_watchdog
|
||||||
|
|
||||||
# demo-watchdog.rego — policy for the demo watchdog agent.
|
# demo-watchdog.rego — policy for the demo watchdog agent.
|
||||||
#
|
#
|
||||||
# Scope: monitoring-only. Can read OB1 thoughts and ping Discord, but cannot
|
# Per scobleclaw#42 refactor: this file now lives at
|
||||||
# touch Forgejo, kubectl, or any kamelet with side-effects.
|
# `package scobleclaw.demo_watchdog` (was `package scobleclaw` in the
|
||||||
|
# package-root layout). API path is now
|
||||||
|
# `data.scobleclaw.demo_watchdog.allow`.
|
||||||
|
#
|
||||||
|
# Scope: monitoring-only. Can read OB1 thoughts and ping Discord, but
|
||||||
|
# cannot touch Forgejo, kubectl, or any kamelet with side-effects.
|
||||||
|
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
demo_watchdog_allowed_kamelets = {
|
demo_watchdog_allowed_kamelets = {
|
||||||
"kamelet:source/ob1-search",
|
"kamelet:source/ob1-search",
|
||||||
|
|
@ -12,6 +19,16 @@ demo_watchdog_allowed_kamelets = {
|
||||||
"kamelet:source/kamelet-dispatch",
|
"kamelet:source/kamelet-dispatch",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Deny set — re-emit base_deny from lib (watchdog has no per-agent
|
||||||
|
# deny rules of its own; the lib's external-email / forgejo / payment
|
||||||
|
# blocks are sufficient).
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
deny[reason] {
|
||||||
|
lib.base_deny[reason]
|
||||||
|
}
|
||||||
|
|
||||||
allow {
|
allow {
|
||||||
input.agent_id == "demo-watchdog"
|
input.agent_id == "demo-watchdog"
|
||||||
demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
||||||
|
|
@ -21,9 +38,9 @@ allow {
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "demo-watchdog"
|
input.agent_id == "demo-watchdog"
|
||||||
not demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
not demo_watchdog_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Watchdog is the only agent allowed to post to Discord from L0. The
|
# Watchdog is the only agent allowed to post to Discord from L0. The
|
||||||
# shared `is_external_email` rule still applies, so Discord DMs to external
|
# shared `is_external_email` rule still applies, so Discord DMs to
|
||||||
# addresses are blocked.
|
# external addresses are blocked.
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
package scobleclaw
|
package scobleclaw.lib
|
||||||
|
|
||||||
# _lib.rego — shared helpers + base deny rules for all agents.
|
# lib.rego — shared helpers + base deny rules for all agents.
|
||||||
# Every per-agent policy (main_agent, demo_concierge, demo_watchdog)
|
#
|
||||||
# imports this file by including these rules in its own `allow` / `deny`
|
# Per scobleclaw#42 refactor: this file lives at `package scobleclaw.lib`
|
||||||
# definitions. Rego merges rules across files in the same package, so
|
# (was `package scobleclaw` in the package-root layout). Per-agent policy
|
||||||
# helpers below are visible everywhere in `scobleclaw.*`.
|
# files (main_agent, demo_concierge, demo_watchdog) `import data.scobleclaw.lib`
|
||||||
|
# to pull in the constants, helpers, and base deny rules. Each per-agent
|
||||||
|
# package re-aggregates `base_deny` into its own `deny` set so the API
|
||||||
|
# surface is `data.scobleclaw.<agent>.deny` (one path per agent).
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Input shape (L0 contract)
|
# Input shape (L0 contract)
|
||||||
|
|
@ -64,13 +67,21 @@ is_forgejo_write_outside_allowed(params) {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Base deny rules — every agent inherits these. An agent file only needs
|
# Base deny rules — every agent inherits these by importing this package
|
||||||
# to add its own `deny` rules on top.
|
# and re-emitting the `base_deny` set into its own `deny` set.
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
#
|
||||||
|
# Why `base_deny` instead of just `deny`? With per-agent packages, a
|
||||||
|
# `deny` set in this lib package would be exposed at
|
||||||
|
# `data.scobleclaw.lib.deny` (one shared path) and would force every
|
||||||
|
# caller to merge it with the per-agent set. By naming it `base_deny`
|
||||||
|
# here and letting each agent package own the final `deny` set, the
|
||||||
|
# API stays clean: one `deny` path per agent, and the lib package
|
||||||
|
# contributes only shared rules.
|
||||||
|
|
||||||
# Rule 1: no external email. Any kamelet whose params include a `to` field
|
# Rule 1: no external email. Any kamelet whose params include a `to` field
|
||||||
# with an external email domain is denied.
|
# with an external email domain is denied.
|
||||||
deny[reason] {
|
base_deny[reason] {
|
||||||
input.kamelet_ref != ""
|
input.kamelet_ref != ""
|
||||||
input.params.to != ""
|
input.params.to != ""
|
||||||
is_external_email(input.params.domain)
|
is_external_email(input.params.domain)
|
||||||
|
|
@ -78,7 +89,7 @@ deny[reason] {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Rule 2: no Forgejo writes outside marcus/engineering.
|
# Rule 2: no Forgejo writes outside marcus/engineering.
|
||||||
deny[reason] {
|
base_deny[reason] {
|
||||||
is_forgejo_write_outside_allowed(input.params)
|
is_forgejo_write_outside_allowed(input.params)
|
||||||
reason := sprintf(
|
reason := sprintf(
|
||||||
"forgejo writes restricted to marcus/engineering (got owner=%v repo=%v)",
|
"forgejo writes restricted to marcus/engineering (got owner=%v repo=%v)",
|
||||||
|
|
@ -87,7 +98,7 @@ deny[reason] {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Rule 3: no payment kamelets. Period.
|
# Rule 3: no payment kamelets. Period.
|
||||||
deny[reason] {
|
base_deny[reason] {
|
||||||
is_payment_kamelet(input.kamelet_ref)
|
is_payment_kamelet(input.kamelet_ref)
|
||||||
reason := sprintf("payment kamelet blocked at L0: %v", [input.kamelet_ref])
|
reason := sprintf("payment kamelet blocked at L0: %v", [input.kamelet_ref])
|
||||||
}
|
}
|
||||||
|
|
@ -1,13 +1,19 @@
|
||||||
package scobleclaw
|
package scobleclaw.main_agent
|
||||||
|
|
||||||
# main-agent.rego — policy for the primary orchestrator agent.
|
# main-agent.rego — policy for the primary orchestrator agent.
|
||||||
#
|
#
|
||||||
# Scope: this is the agent that drives engineering work (Forgejo reads/writes,
|
# Per scobleclaw#42 refactor: this file now lives at
|
||||||
# OB1 captures, kamelet dispatch). It has the tightest allowlist.
|
# `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.
|
||||||
#
|
#
|
||||||
# This file uses the same package as _lib.rego, so all the shared `deny`
|
# Scope: this is the agent that drives engineering work (Forgejo
|
||||||
# rules apply automatically. We add a per-agent `allow` rule that defines
|
# reads/writes, OB1 captures, kamelet dispatch). It has the tightest
|
||||||
# the kamelet allowlist and a couple of agent-specific deny rules.
|
# allowlist.
|
||||||
|
|
||||||
|
import data.scobleclaw.lib
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Per-agent allowlist
|
# Per-agent allowlist
|
||||||
|
|
@ -28,6 +34,18 @@ main_agent_allowed_kamelets = {
|
||||||
"kamelet:source/age-decrypt",
|
"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
|
# Per-agent allow rule
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
@ -48,7 +66,5 @@ allow {
|
||||||
needs_l1 {
|
needs_l1 {
|
||||||
input.agent_id == "main-agent"
|
input.agent_id == "main-agent"
|
||||||
not main_agent_allowed_kamelets[input.kamelet_ref]
|
not main_agent_allowed_kamelets[input.kamelet_ref]
|
||||||
not payment_kamelets[input.kamelet_ref]
|
not lib.payment_kamelets[input.kamelet_ref]
|
||||||
}
|
}
|
||||||
|
|
||||||
# Anything not main-agent falls through to the per-agent policy files.
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue