<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kunko AI Labs</title>
    <description>The latest articles on DEV Community by Kunko AI Labs (@kunko_ai_labs).</description>
    <link>https://dev.to/kunko_ai_labs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4131347%2F5b273bf1-48ee-4483-84a8-3508e7f6e53f.png</url>
      <title>DEV Community: Kunko AI Labs</title>
      <link>https://dev.to/kunko_ai_labs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kunko_ai_labs"/>
    <language>en</language>
    <item>
      <title>Put a permission gate on your AI agent in 5 minutes (MCP + Claude Code + CI)</title>
      <dc:creator>Kunko AI Labs</dc:creator>
      <pubDate>Fri, 18 Sep 2026 11:22:40 +0000</pubDate>
      <link>https://dev.to/kunko_ai_labs/put-a-permission-gate-on-your-ai-agent-in-5-minutes-mcp-claude-code-ci-12ea</link>
      <guid>https://dev.to/kunko_ai_labs/put-a-permission-gate-on-your-ai-agent-in-5-minutes-mcp-claude-code-ci-12ea</guid>
      <description>&lt;p&gt;Your agent's permissions drift silently. A PR adds an MCP server with write scope, or &lt;code&gt;allow: Bash(*)&lt;/code&gt; lands in &lt;code&gt;.claude/settings.json&lt;/code&gt; 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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: declare the promise
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;agent-assurance.yaml&lt;/code&gt; in your repo — what the agent may do, in plain config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# agent-assurance.yaml (simplified)&lt;/span&gt;
&lt;span class="na"&gt;capabilities&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;        &lt;span class="c1"&gt;# no write, no execute, no external send&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;internal&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;            &lt;span class="c1"&gt;# no customer data, no credentials&lt;/span&gt;
&lt;span class="na"&gt;autonomy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;L2&lt;/span&gt;                &lt;span class="c1"&gt;# a human approves actions&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: scan locally
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx &lt;span class="nb"&gt;install &lt;/span&gt;agent-assurance
agent-assurance scan &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: gate the PR
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .github/workflows/agent-assurance.yml&lt;/span&gt;
&lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull-requests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;write&lt;/span&gt; &lt;span class="pi"&gt;}&lt;/span&gt;
&lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kunko-ai-labs/agent-assurance@v0.5&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;diff&lt;/span&gt;
      &lt;span class="na"&gt;manifest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;agent-assurance.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;h2&gt;
  
  
  Why this shape
&lt;/h2&gt;

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

&lt;p&gt;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: &lt;a href="https://github.com/kunko-ai-labs/agent-assurance" rel="noopener noreferrer"&gt;https://github.com/kunko-ai-labs/agent-assurance&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Try breaking it. That's the point. 🧪&lt;/p&gt;

</description>
      <category>agents</category>
      <category>security</category>
      <category>ai</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
