scobleclaw/scoble-policy/opa/opa-deployment.yaml
hermes 39b21dcda5 feat(opa): Layered judge L0 — OPA deployment + 4 Rego policies (eng#40)
Deploys openpolicyagent/opa:0.68.0 as a single-replica ClusterIP
service in the scobleclaw namespace, with a ConfigMap-mounted
policy bundle under /policies.

Policies (package scobleclaw):
  _lib.rego            shared deny rules (external email, forgejo
                       write outside marcus/engineering, payment
                       kamelets) + helpers (is_external_email,
                       is_payment_kamelet, is_forgejo_write_outside_allowed)
  main-agent.rego      10-kamelet allowlist for main-agent
  demo-concierge.rego  read-only 4-kamelet allowlist
  demo-watchdog.rego   4-kamelet allowlist (ob1 + discord)

L0 contract:
  POST /v1/data/scobleclaw/allow      -> {allow: bool}
  POST /v1/data/scobleclaw/needs_l1   -> {needs_l1: bool}
  POST /v1/data/scobleclaw/deny       -> [reason, ...]

Verified end-to-end against the running OPA pod:
  allow=true  for main-agent + kamelet:source/forgejo-search
  deny=[reason] for external email, forgejo write to stranger/not-mine,
               payment kamelet (stripe-charge), demo-concierge forgejo-create
  needs_l1=true for unknown kamelet (e.g. some-new-kamelet) on main-agent
  needs_l1=false for payment kamelet (L1 cannot override L0 deny)

Out of scope (separate tickets): judge-integration Camel-K binding,
llm-classifier-integration (L1), discord-escalation-integration (L2),
audit-sink OPA log tailing.
2026-06-08 16:36:37 -07:00

76 lines
1.9 KiB
YAML

---
# Single-replica OPA deployment. Fail-closed: if the pod dies, agents fall
# back to deny-by-default (the L1/L2 callers treat an OPA timeout as deny).
#
# Resource footprint is intentionally small: 64Mi mem, 100m CPU. Rego
# evaluation is <1ms per call so we don't need a beefy pod.
apiVersion: apps/v1
kind: Deployment
metadata:
name: opa
namespace: scobleclaw
labels:
app: opa
component: l0-judge
spec:
replicas: 1
strategy:
# Recreate avoids split-brain while the ConfigMap volume is being
# remounted on a content change.
type: Recreate
selector:
matchLabels:
app: opa
template:
metadata:
labels:
app: opa
component: l0-judge
spec:
serviceAccountName: opa
containers:
- name: opa
image: openpolicyagent/opa:0.68.0
imagePullPolicy: IfNotPresent
args:
- "run"
- "--server"
- "--addr=http://0.0.0.0:8181"
- "--log-level=info"
- "--log-format=json"
- "/policies"
ports:
- name: http
containerPort: 8181
protocol: TCP
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 2
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 10
periodSeconds: 15
timeoutSeconds: 2
failureThreshold: 3
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 500m
memory: 256Mi
volumeMounts:
- name: policies
mountPath: /policies
readOnly: true
volumes:
- name: policies
configMap:
name: opa-policies