Skip to main content
DevOps10 min read

Policy-as-Code for AI Agents: When Valid Tool Calls Are Still Unsafe

AWS Dogwood highlights a growing DevOps problem: AI agent tool calls can be syntactically valid and properly authorized, yet still be operationally dangerous. As teams bring agents into CI/CD, incident response, and cloud operations, policy-as-code needs to govern not just what an agent can call, but whether a sequence of actions is safe in context.

An AI agent can make a perfectly valid API call and still create a production incident. The syntax may be correct, the credentials may be valid, and the permission may be allowed — but the action can still be wrong for the current workflow, environment, or business context.

That is the gap policy-as-code for AI agents is starting to address.

The New Risk: Valid, Authorized, and Still Wrong

Policy-as-Code for AI Agents: When Valid Tool Calls Are Still Unsafe
Policy-as-Code for AI Agents: When Valid Tool Calls Are Still Unsafe

As AI agents move from demos into real engineering workflows, they are gaining access to tools developers already use every day: CI/CD systems, cloud consoles, ticketing platforms, observability dashboards, incident management tools, and internal developer portals.

In traditional DevOps, we usually reason about access in terms of identity and permissions. Can this service account deploy to production? Can this user restart a Kubernetes workload? Can this automation open a pull request, merge code, or modify infrastructure?

Those checks are necessary, but they are no longer sufficient.

An agent might be authorized to call a deployment tool. The deployment API request might be well-formed. The target service name and environment might be valid. But the deployment could still be unsafe if it happens during an active incident, skips a required canary step, violates a change freeze, targets the wrong region, or rolls forward a version that failed integration tests.

This is the distinction The New Stack captured in its coverage of AWS Dogwood: an AI agent’s next tool call may be valid, but wrong. AWS has launched Dogwood as an open-source policy language and reference interpreter designed to govern sequences of AI agent tool calls, not just isolated API requests.

That shift matters for every team adding agents to production-adjacent workflows.

Why Tool-Level Permissions Are Not Enough

Most engineering organizations already have some combination of IAM, RBAC, service accounts, API tokens, approval workflows, and environment-level permissions. These controls answer important questions:

  • Who is making the request?
  • What system are they allowed to access?
  • What operation can they perform?
  • Which resource can they modify?

Agentic workflows introduce another question: should this action happen now, given what happened before and what should happen next?

That question is fundamentally about sequence and context.

For example, an AI agent operating in a CI/CD pipeline might perform this sequence:

  1. Read a pull request
  2. Summarize the change
  3. Trigger tests
  4. Detect a flaky failure
  5. Re-run the pipeline
  6. Approve the deployment
  7. Promote to production

Each individual tool call may be valid. But the sequence may be unacceptable if the agent treats a flaky test as a pass, approves its own change, bypasses required human review, or deploys during a restricted window.

The same problem appears in incident response. An agent may be allowed to restart services, scale workloads, or roll back releases. But should it restart three dependent services at once? Should it roll back a database migration after writes have occurred? Should it page another team before changing a shared infrastructure component?

Traditional API authorization does not usually model those workflow-level constraints. Policy-as-code can.

What Dogwood Adds to the Conversation

AWS Dogwood is significant because it focuses on governing sequences of AI agent tool calls. Instead of treating agent actions as independent API invocations, Dogwood is designed around the idea that safety often depends on the path an agent takes through a workflow.

That is a natural extension of policy-as-code practices many DevOps teams already use. Tools such as Open Policy Agent, HashiCorp Sentinel, Kubernetes admission controllers, and CI/CD release gates have trained teams to encode operational rules as testable, reviewable policy instead of relying only on tribal knowledge or manual approvals.

Dogwood brings that mindset closer to agent execution.

The key idea is not simply to ask whether an agent can call a tool. It is to ask whether the call is allowed in the current state of the workflow. Has the agent gathered enough evidence? Has it satisfied preconditions? Is it attempting an action out of order? Is the target environment protected? Has a required approval or verification step occurred?

That is especially important because AI agents are probabilistic planners. They may choose plausible next steps that look reasonable locally but violate broader operational rules. A human SRE may know that a production rollback requires checking database compatibility first. An agent may not, unless the workflow policy explicitly requires it.

Examples: Where Valid Calls Become Unsafe

CI/CD and Release Automation

Consider an agent that helps manage releases. It can inspect pull requests, update changelogs, trigger builds, and deploy services. All of those capabilities are useful.

But unsafe behavior can emerge quickly:

  • Deploying a service when its dependency has not been upgraded
  • Promoting a build that passed unit tests but skipped security scans
  • Merging a dependency update without checking runtime compatibility
  • Deploying outside an approved release window
  • Releasing to all regions instead of starting with a canary

Policy-as-code can define the release path: tests must pass, vulnerabilities above a threshold must be resolved or approved, canary metrics must be healthy, and production promotion must happen only after an explicit gate.

Incident Response

Agents are attractive for incident response because they can summarize alerts, correlate logs, recommend mitigations, and automate repetitive actions. But this is also where mistakes are costly.

A restart command may be valid. Scaling a deployment may be valid. Disabling a feature flag may be valid. The danger is choosing the wrong action at the wrong time.

Policies can require agents to operate within bounded playbooks: gather diagnostics before remediation, avoid destructive actions without approval, limit the blast radius of automated changes, and trigger rollback if health metrics worsen.

Cloud Operations and Infrastructure Changes

In cloud operations, agents may help resize resources, clean up unused infrastructure, rotate credentials, or update network rules. Again, the problem is rarely syntax. The problem is context.

A valid infrastructure change might expose an internal service, delete a resource still used by a legacy workload, or modify a shared role used by multiple systems. Policy-as-code can enforce dependency checks, tagging requirements, ownership metadata, and staged rollout rules before allowing the agent to proceed.

Connecting Agent Governance to Modernization

For companies modernizing legacy systems, AI agents are often positioned as accelerators. They can analyze old codebases, generate migration plans, open pull requests, update dependencies, and automate repetitive maintenance tasks.

That is valuable, but modernization work is full of hidden coupling. Legacy services may depend on undocumented APIs, outdated runtime behavior, fragile deployment scripts, or manually maintained configuration. An agent can produce a technically valid change that breaks an operational assumption nobody encoded.

This is where platforms such as Vibgrate fit into the broader engineering picture. Software maintenance and modernization are not just about making changes faster; they are about making safe, observable, reversible changes at scale. If agents are going to participate in upgrades, refactoring, dependency remediation, or platform migration, they need guardrails that reflect how the system actually operates.

Policy-as-code provides a durable way to encode those guardrails. Instead of relying on every developer or agent prompt to remember release rules, teams can make the rules executable, version-controlled, and auditable.

Lessons from Adjacent DevOps Trends

The Dogwood discussion also lines up with broader trends in production AI and cloud-native operations.

InfoQ’s coverage of runtime-agnostic AI workflows points to a related need: durable workflow design that can evolve quickly without binding every decision to a single runtime. That principle applies to governance too. Agent policies should be portable enough to survive changes in orchestration frameworks, model providers, and internal platforms.

Similarly, discussions around running AI agents on Kubernetes often distinguish between agents as intelligent planners and pods as operational units. That separation matters. Kubernetes can schedule workloads, enforce resource limits, and isolate execution, but it does not automatically know whether an agent’s planned sequence is safe for a business-critical release.

Security incidents such as cloud control-plane exposures also remind teams that credentials and permissions are only part of the story. Stronger runtime governance, auditability, and blast-radius control are essential when automation can act quickly across many systems.

Practical Implications for Engineering Teams

1. Treat Agent Actions Like Production Changes

If an agent can deploy, modify infrastructure, change configuration, or affect incident response, its actions should be governed like any other production change. That means reviewable policies, logs, approvals, and rollback plans.

Do not treat agent tool calls as harmless because they are generated through a conversational interface. A tool call is an operational action.

2. Define Workflow-Level Policies, Not Just Permissions

Start by mapping the workflows where agents operate. For each workflow, define required preconditions, allowed sequences, approval points, and stop conditions.

For example:

  • A production deployment must follow successful tests, security checks, and canary validation.
  • An incident remediation action must be tied to an active incident record.
  • A dependency upgrade must include compatibility checks and rollback instructions.
  • A database-affecting change must require human approval.

These policies should be explicit and testable.

3. Apply Least Privilege to Tools and Sequences

Least privilege should apply at two levels. First, agents should have access only to the tools and resources they need. Second, they should be allowed to use those tools only in approved sequences.

An agent that can read logs does not necessarily need permission to restart services. An agent that can deploy to staging does not automatically need production promotion rights. An agent that can propose a rollback may still need a human to execute it.

4. Make Agent Decisions Auditable

Every meaningful tool call should produce an audit trail: what the agent observed, what it attempted, which policy allowed or denied the action, and what happened afterward.

This is essential for incident reviews, compliance, and continuous improvement. If an agent makes a poor recommendation or attempts an unsafe action, teams need to understand whether the issue was missing context, an insufficient policy, a flawed workflow, or excessive permissions.

5. Design for Automated Rollback

Agent governance should not stop at prevention. Production systems need recovery paths. If an approved agent action causes error rates to spike or latency to degrade, automated rollback should be available where possible.

That means pairing agent policies with observability signals, deployment health checks, and progressive delivery practices.

A Good Starting Checklist

Engineering leaders evaluating agents in DevOps workflows can start with a simple checklist:

  • Which tools can the agent call?
  • Which environments can it affect?
  • What sequences are explicitly allowed?
  • What actions require human approval?
  • What telemetry determines success or failure?
  • What is the rollback path?
  • Where are policies versioned and reviewed?
  • How are denied actions logged and analyzed?

If those questions are difficult to answer, the agent is probably operating with too much implicit trust.

Conclusion: Safer Agents Need Operational Memory

AI agents will become more common in CI/CD, incident response, cloud operations, and internal developer platforms. The productivity upside is real, especially for teams maintaining and modernizing complex software estates.

But production safety depends on more than valid syntax and authorized credentials. Agents need operational memory: an understanding of sequence, context, policy, and consequence. AWS Dogwood is an important signal that the industry is moving toward policy-as-code designed specifically for agent workflows.

The teams that succeed with agents will not be the ones that automate everything first. They will be the ones that encode their engineering judgment into durable controls, making automation faster, safer, and easier to trust.

Vibgrate CLI

See a real scan run

A replay of the actual CLI running against our test repositories — live progress, real findings, a genuine DriftScore. Nothing executes in your browser.

Replay
demo@vibgrate — bash
npx @vibgrate/cli scan
 
╭──────────────────────────────────────────╮
Vibgrate Drift Report
╰──────────────────────────────────────────╯
 
── node-turborepo (node) .
Runtime: >=18.0.0 (6 majors behind)
Frameworks:
Turbo: 1.13.4 → 2.10.13 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 1 1-behind 3 2+ behind 1 unknown
 
── @repo/admin (node) apps/admin
Frameworks:
TanStack Query: 5.103.1 → 5.103.1 (current)
React: 18.3.1 → 19.3.0 (1 behind)
React DOM: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vite: 5.4.21 → 8.3.0 (3 behind)
Dependencies:
3 current 9 1-behind 3 2+ behind 4 unknown
 
── @repo/api (node) apps/api
Frameworks:
Express: 4.22.3 → 5.2.1 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 5.0.1 (4 behind)
Dependencies:
7 current 5 1-behind 3 2+ behind 4 unknown
 
── @repo/web (node) apps/web
Frameworks:
Next.js: 14.2.35 → 16.3.5 (2 behind)
React: 18.3.1 → 19.3.0 (1 behind)
React DOM: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 6 1-behind 3 2+ behind 5 unknown
 
── @repo/config (node) packages/config
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
2 current 2 1-behind 5 2+ behind 0 unknown
 
── @repo/database (node) packages/database
Frameworks:
Prisma: 5.22.0 → 7.10.0 (2 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
1 current 0 1-behind 3 2+ behind 1 unknown
 
── @repo/types (node) packages/types
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Dependencies:
0 current 0 1-behind 1 2+ behind 1 unknown
 
── @repo/ui (node) packages/ui
Frameworks:
React: 18.3.1 → 19.3.0 (1 behind)
TypeScript: 5.9.3 → 7.0.2 (2 behind)
React: 18.3.1 → 19.3.0 (1 behind)
Dependencies:
1 current 4 1-behind 1 2+ behind 1 unknown
 
── @repo/utils (node) packages/utils
Frameworks:
TypeScript: 5.9.3 → 7.0.2 (2 behind)
Vitest: 1.6.1 → 5.0.1 (4 behind)
Dependencies:
0 current 1 1-behind 2 2+ behind 1 unknown
 
Tech Stack
Frontend: React, React DOM
Meta-frameworks: Next.js
Bundlers: tsx, Turbo, Vite
CSS / UI: Autoprefixer, PostCSS, Tailwind CSS
Backend: Express
ORM / Database: Prisma, Prisma Client
Testing: Vitest
Lint & Format: ESLint, ESLint Prettier, ESLint React, Prettier, typescript-eslint
 
Services & Integrations
Auth: JWT 9.0.3
Databases: Prisma 5.22.0
 
TypeScript
v5.3.3 · strict ✔ · MIXED · target: ES2022
 
Build & Deploy
Package Managers: pnpm
Monorepo: npm-workspaces, pnpm-workspaces, turbo
 
Product Purpose Signals
Frameworks: react, nextjs
Evidence: 177
Top Signals:
- [heading] Dashboard (apps/admin/src/pages/Dashboard.tsx)
- [title] Revenue Overview (apps/admin/src/pages/Dashboard.tsx)
- [copy] workspace:* (packages/ui/package.json)
- [copy] ./dist (packages/ui/tsconfig.json)
- [copy] ./src/index.ts (packages/ui/package.json)
- [copy] @repo/config/tsconfig-base.json (packages/ui/tsconfig.json)
- [copy] @repo/ui (packages/ui/package.json)
- [copy] #3b82f6 (apps/admin/src/pages/Dashboard.tsx)
Unknowns:
- No pricing or billing evidence found.
- No integrations/connectors evidence found.
- No route structure evidence found.
 
Security Posture
Lockfile ✖ · .env ✔ · node_modules ✔
 
Platform
Native modules: turbo
 
Code Quality
Files: 36 · Functions: 183 · Avg complexity: 2.62 · Avg length: 21.13 lines
Max nesting: 2 · Circular deps: 0 · Dead code: 0%
God files: apps/admin/src/pages/Products (448 lines)
 
Database Schema
postgresql · 8 models · 1 enum
Models: Address, CartItem, Category, Order, OrderItem (+3 more)
 
Findings (16 errors, 11 warnings)
Node.js runtime ">=18.0.0" reached end-of-life on 2025-04-30 (latest: 24.0.0).
vibgrate/runtime-eol in .
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in .
60% of dependencies are 2+ major versions behind in node-turborepo.
vibgrate/dependency-rot in .
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.1).
vibgrate/dependency-major-lag in .
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/admin
Vite is 3 major versions behind (current: 5.4.21, latest: 8.3.0).
vibgrate/framework-major-lag in apps/admin
vite is 3 major versions behind (spec: ^5.0.12, latest: 8.3.0).
vibgrate/dependency-major-lag in apps/admin
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/api
Vitest is 4 major versions behind (current: 1.6.1, latest: 5.0.1).
vibgrate/framework-major-lag in apps/api
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.1).
vibgrate/dependency-major-lag in apps/api
vitest is 4 major versions behind (spec: ^1.2.1, latest: 5.0.1).
vibgrate/dependency-major-lag in apps/api
Next.js is 2 major versions behind (current: 14.2.35, latest: 16.3.5).
vibgrate/framework-major-lag in apps/web
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in apps/web
@types/node is 6 major versions behind (spec: ^20.11.0, latest: 26.6.1).
vibgrate/dependency-major-lag in apps/web
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/config
56% of dependencies are 2+ major versions behind in @repo/config.
vibgrate/dependency-rot in packages/config
eslint-plugin-react-hooks is 3 major versions behind (spec: ^4.6.0, latest: 7.1.1).
vibgrate/dependency-major-lag in packages/config
Prisma is 2 major versions behind (current: 5.22.0, latest: 7.10.0).
vibgrate/framework-major-lag in packages/database
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/database
75% of dependencies are 2+ major versions behind in @repo/database.
vibgrate/dependency-rot in packages/database
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/types
100% of dependencies are 2+ major versions behind in @repo/types.
vibgrate/dependency-rot in packages/types
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/ui
TypeScript is 2 major versions behind (current: 5.9.3, latest: 7.0.2).
vibgrate/framework-major-lag in packages/utils
Vitest is 4 major versions behind (current: 1.6.1, latest: 5.0.1).
vibgrate/framework-major-lag in packages/utils
67% of dependencies are 2+ major versions behind in @repo/utils.
vibgrate/dependency-rot in packages/utils
vitest is 4 major versions behind (spec: ^1.2.1, latest: 5.0.1).
vibgrate/dependency-major-lag in packages/utils
 
╭──────────────────────────────────────────╮
Top Priority Actions
╰──────────────────────────────────────────╯
 
1. Upgrade EOL runtime in node-turborepo
End-of-life runtimes no longer receive security patches and block ecosystem upgrades.
./.
>=18.0.0 → 24.0.0 (6 majors behind)
Impact: −10 drift points (runtime & EOL)
 
2. Fix security posture: no lockfile found
Without a lockfile, installs are non-deterministic. Run the install command to generate one and commit it.
./
Missing: package-lock.json, pnpm-lock.yaml, or yarn.lock
 
3. Upgrade Vitest 1.6.1 → 5.0.1 in @repo/api (+2 more)
4 major versions behind. Major framework drift increases breaking change risk and blocks access to security fixes and performance improvements.
./apps/api
Vitest: 1.6.1 → 5.0.1 (4 majors behind)
./packages/utils
Vitest: 1.6.1 → 5.0.1 (4 majors behind)
./apps/admin
Vite: 5.4.21 → 8.3.0 (3 majors behind)
Impact: −5–15 drift points
 
4. Reduce dependency rot in @repo/types (100% severely outdated)
1 of 1 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/types
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
5. Reduce dependency rot in @repo/database (75% severely outdated)
3 of 4 dependencies are 2+ majors behind. Run `npm outdated` and prioritise packages with known CVEs or breaking API changes.
./packages/database
@prisma/client: 5.22.0 → 7.10.0 (2 majors behind)
prisma: 5.22.0 → 7.10.0 (2 majors behind)
typescript: 5.9.3 → 7.0.2 (2 majors behind)
Impact: −5–10 drift points
 
╭──────────────────────────────────────────╮
Architecture Layers
╰──────────────────────────────────────────╯
 
Archetype: nextjs (80% confidence)
Files classified: 24 (11 unclassified)
Folders classified: 8
apps/admin/src presentation 100% 4 files
apps/admin/src/pages presentation 100% 2 files
apps/api/src/middleware middleware 100% 2 files
apps/api/src/routes routing 100% 2 files
apps/web/src/app presentation 100% 4 files
apps/web/src/app/products presentation 100% 2 files
apps/web/src/app/products/[id] presentation 100% 1 file
packages/ui/src presentation 100% 6 files
Unclassified source (sample): 11
 
presentation 15 files drift ████████████████████ 100 risk high
routing 4 files drift ████████████████████ 100 risk high
middleware 2 files drift ███████▍░░░░░░░░░░░░ 37 risk moderate
config 2 files drift ░░░░░░░░░░░░░░░░░░░░ 0 risk none
shared 1 file drift ████████████████████ 100 risk high
 
╭──────────────────────────────────────────╮
DriftScore Summary
╰──────────────────────────────────────────╯
 
DriftScore: 70/100
Risk Level: HIGH
Projects: 9
Classified: 8 nano · 1 micro · 0 small · 0 standard
Billable: 0.42 · 9 detected → 0.42 billable projects (micro-project pricing)
0.1 micro · 0.32 nano
These fractions add up across repositories, then round down to whole billable projects.
 
Score Breakdown
Runtime: ████████████████████ 100
Frameworks: ███████████▊░░░░░░░░ 59
Dependencies: ██████▌░░░░░░░░░░░░░ 33
EOL Risk: ████████████████████ 100
 
Scanned at 2026-09-17T13:19:05.436Z · 6.0s · 286 files scanned · 56 workspace files · 27 dirs
Press Run to start.