DEV Community

Kunko AI Labs
Kunko AI Labs

Posted on

Put a permission gate on your AI agent in 5 minutes (MCP + Claude Code + CI)

Your agent's permissions drift silently. A PR adds an MCP server with write scope, or allow: Bash(*) lands in .claude/settings.json while the runbook says "a human approves". Tests don't catch it. Linters don't catch it. Here's a 5-minute gate that does.

Step 1: declare the promise

Create agent-assurance.yaml in your repo — what the agent may do, in plain config:

# agent-assurance.yaml (simplified)
capabilities: [read]        # no write, no execute, no external send
data: [internal]            # no customer data, no credentials
autonomy: L2                # a human approves actions
Enter fullscreen mode Exit fullscreen mode

Step 2: scan locally

pipx install agent-assurance
agent-assurance scan .
Enter fullscreen mode Exit fullscreen mode

You get the observed blast radius plus a "declared vs observed" verdict. Now break it on purpose — add an MCP server with write scope — and watch it point at the file and line.

Step 3: gate the PR

# .github/workflows/agent-assurance.yml
permissions: { contents: read, pull-requests: write }
steps:
  - uses: actions/checkout@v4
  - uses: kunko-ai-labs/agent-assurance@v0.5
    with:
      mode: diff
      manifest: agent-assurance.yaml
Enter fullscreen mode Exit fullscreen mode

Every PR now gets one comment, updated on every push, plus a red check when the promise breaks. On push/release, switch to mode: scan for SARIF findings in the Security tab and in-toto attestations.

Why this shape

Two checks: AA-001 blast radius (if it misbehaves, how much breaks?) and AA-002 declared vs observed. Unknown servers come out UNKNOWN — scored conservatively, never a silent pass. An inferred guess (e.g. a tool named billing.issue_refund → financial) only ever triggers review, never fails a build.

It's deterministic — no LLM in the verdict — makes no network calls, and never reads a secret's value. Every release ships Sigstore-signed SLSA provenance, and the whole thing is Apache-2.0: https://github.com/kunko-ai-labs/agent-assurance

Try breaking it. That's the point. 🧪

Top comments (2)

Collapse
 
mateo_ruiz_6992b1fce47843 profile image
Mateo Ruiz

The declared vs observed distinction is the part I’d pay the most attention to. A permission file tells you what someone intended to authorize; inspecting the actual MCP/tool configuration tells you what the agent can really reach. Those are two different security properties.

I also like treating UNKNOWN as a first-class state rather than silently converting uncertainty into a pass. That pattern matters well beyond MCP especially for agent systems where new tools and capabilities can appear through configuration changes.

At IT Path Solutions, this same separation is useful when hardening production agent workflows: keep the policy deterministic and outside the model, then make CI continuously verify that the executable capability surface still matches the declared contract.

The nice part is that this turns permission drift into something engineering teams can catch before deployment, rather than discovering it through an incident.

Collapse
 
kunko_ai_labs profile image
Kunko AI Labs

Thanks Mateo — "two different security properties" puts it better than anything in the post. Stealing that!

Curious: what's been the hardest capability surface to observe on your side? For me it's inferred tools — a tool named billing.issue_refund that probably touches money but declares nothing. That's exactly why UNKNOWN exists as a state rather than a guess.