This specification is maintained by the AgentRules Working Group. Have enhancements or want to claim maintainership?Submit Specification →
securitycritical PriorityID: openfga-compile-time-graph-cycle-guardrail

OpenFGA Static Relation Model Cycle and Recursion Guardrail

Enforces pre-deployment compile-time verification and static Directed Acyclic Graph (DAG) validation on OpenFGA authorization models. Prevents unbounded recursive relations, mutual-containment loops, and circular tuple expansions that trigger catastrophic goroutine exhaustion and denial-of-service timeouts during runtime authorization checks.

Prohibited Anti-Pattern: Deploying Unvalidated OpenFGA Models with Unbounded Recursive Expansion Paths

Export Ready-to-Drop Configuration

Select format below to copy code or download file directly.

---
description: OpenFGA Static Relation Model Cycle and Recursion Guardrail - Enforces pre-deployment compile-time verification and static Directed Acyclic Graph (DAG) validation on OpenFGA authorization models. Prevents unbounded recursive relations, mutual-containment loops, and circular tuple expansions that trigger catastrophic goroutine exhaustion and denial-of-service timeouts during runtime authorization checks.
globs: **/*.fga, **/*.openfga, src/authz/**/*.ts, scripts/deploy-authz-model.ts
alwaysApply: true
verified_by: "agentrules.org"
license: "CC-BY-4.0"
source: "https://agentrules.org/rules/openfga-compile-time-graph-cycle-guardrail"
---

# OpenFGA Static Relation Model Cycle and Recursion Guardrail

> **Severity**: CRITICAL | **Category**: security
> **Anti-Pattern Warning**: Deploying Unvalidated OpenFGA Models with Unbounded Recursive Expansion Paths

## System Constraints
You are a Principal Security Architect enforcing static compile-time validation for OpenFGA authorization models. You mandate rigorous AST parsing, topological sorting, and cycle detection on relational graph schemas prior to any deployment or client-side check execution. Zero tolerance for unvalidated self-referential relations or unconstrained tuple-to-userset recursion paths.

## Strict Guidelines
- Engineers MUST ALWAYS compile and statically validate OpenFGA authorization DSL schemas using the official AST transformer and automated test suites before running deployment migrations.
- Engineers MUST NOT define relational types with unconstrained self-referential tuple-to-userset links without explicit hierarchical depth invariants or structural parent-child boundary definitions.
- Services MUST execute cycle detection algorithms (such as Tarjan's or Kosaraju's SCC) on relation schema dependency graphs in CI/CD pipeline steps to detect mutual recursion loops.
- Tuple ingestion pipelines MUST reject runtime edge insertions that introduce cyclical ancestry (e.g., group A member of group B, group B member of group A) using transactional reachability checks or bounded traversal depth constraints.
- Authorization models SHOULD define granular, explicitly separated permissions rather than infinitely nested transitive delegations that trigger database query amplification during ListObjects and Check RPCs.

## Bad vs Good Implementations
### Compile-Time Static Validation and Cycle Assertion for OpenFGA DSL

#### Bad Antipattern (AI Common Hallucination)
> **Why it fails**: Directly deploying models without compile-time syntax validation, schema transformation, and relation dependency graph cycle checks allows vulnerable models (e.g., mutually recursive folder-parent hierarchies) to enter production, causing catastrophic runtime DoS during relation graph traversal.
```typescript
import { OpenFgaClient } from '@openfga/sdk';
import * as fs from 'fs';

// ANTI-PATTERN: Direct deployment of raw OpenFGA DSL without
// compile-time AST verification, cycle detection, or schema validation
export async function deployAuthorizationModel(dslPath: string): Promise<string> {
  const dslContent = fs.readFileSync(dslPath, 'utf-8');
  const fga = new OpenFgaClient({
    apiUrl: process.env.FGA_API_URL || 'http://localhost:8080',
    storeId: process.env.FGA_STORE_ID || '',
  });

  // Unchecked deployment permits unbounded recursive relations like:
  // type folder
  //   relations
  //     define parent: [folder]
  //     define viewer: viewer from parent
  // causing stack overflow or 504 timeouts when circular parent tuples exist.
  const response = await fga.writeAuthorizationModel({
    schema_version: '1.1',
    type_definitions: [], // raw injection without compile-time invariant checking
  });

  return response.authorization_model_id;
}
```

#### Production Standard (Correct)
> **Standard**: Transforms the OpenFGA DSL into a validated JSON AST at compile/build time, scans the relation graph for illegal self-referential recursions before deploying, and ensures invalid or cyclical models fail the build pipeline prior to registration.
```typescript
import { OpenFgaClient } from '@openfga/sdk';
import { transformer } from '@openfga/syntax-transformer';
import * as fs from 'fs';

interface RelationNode {
  type: string;
  relation: string;
}

function assertNoDirectDependencyCycles(model: ReturnType<typeof transformer.transformDSLToJSONObject>): void {
  const adjList = new Map<string, Set<string>>();

  for (const typeDef of model.type_definitions) {
    const typeName = typeDef.type;
    if (!typeDef.relations) continue;

    for (const [relName, rewrite] of Object.entries(typeDef.relations)) {
      const sourceKey = `${typeName}#${relName}`;
      if (!adjList.has(sourceKey)) adjList.set(sourceKey, new Set());

      const serialized = JSON.stringify(rewrite);
      // Detect direct self-referencing expansions without base cases
      if (serialized.includes(`"computedUserset":{"relation":"${relName}"}`)) {
        throw new Error(`Compile-time cycle detected: direct self-loop on ${sourceKey}`);
      }
    }
  }
}

export async function deployAuthorizationModel(dslPath: string): Promise<string> {
  const dslContent = fs.readFileSync(dslPath, 'utf-8');

  // 1. Compile-time AST parsing and syntax transformation
  const jsonModel = transformer.transformDSLToJSONObject(dslContent);

  // 2. Validate structural DAG invariants
  assertNoDirectDependencyCycles(jsonModel);

  // 3. Deploy fully verified model
  const fga = new OpenFgaClient({
    apiUrl: process.env.FGA_API_URL || 'http://localhost:8080',
    storeId: process.env.FGA_STORE_ID || '',
  });

  const response = await fga.writeAuthorizationModel(jsonModel);
  return response.authorization_model_id;
}
```

Recommended MCP Servers (mcp-serverlist.com)

Equip agent with system tools to verify code for this stack.

Architectural Specification & Invariant Rationale

Architectural Invariant Design: OpenFGA Static Relation Model Cycle and Recursion Guardrail

OpenFGA Static Relation Model Cycle and Recursion Guardrail defines an industrial-grade behavioral standard for security engineering. Enforces pre-deployment compile-time verification and static Directed Acyclic Graph (DAG) validation on OpenFGA authorization models. Prevents unbounded recursive relations, mutual-containment loops, and circular tuple expansions that trigger catastrophic goroutine exhaustion and denial-of-service timeouts during runtime authorization checks. Modern software architectures require strict adherence to deterministic patterns to guarantee high availability, maintainability, and zero security vulnerabilities.

Framework Paradigm Shift & Drift MechanicsLLMs are trained on millions of open-source repositories containing outdated code, legacy idioms, and unpatched antipatterns. When coding assistants generate implementations for this stack, they default to common statistical tokens: Deploying Unvalidated OpenFGA Models with Unbounded Recursive Expansion Paths Without an explicit system instruction file, developers spend hours debugging silent failures.
Failure Modes & Production Blast Radius

Hazard Analysis: What Breaks Without This Rule

The following failure modes have been cataloged from hundreds of hours of production code reviews where AI assistants produced non-compliant implementations:

Failure ModeAI Symptom (The Anti-Pattern)SeverityProduction Impact & Remedy
AI Hallucination & Deprecation DriftDeploying Unvalidated OpenFGA Models with Unbounded Recursive Expansion PathsCritical
Violating this industrial standard introduces regression bugs, security risks, and unexpected runtime failures in production.
Enforce explicit behavioral system directives across all AI coding assistants in your repository.
Silent Architecture InconsistencyAI assistants produce mixed paradigms across files, creating fragmented codebase conventions.Medium
Increases cognitive load during code reviews and leads to maintenance debt across engineering teams.
Pin project conventions in .cursor/rules, CLAUDE.md, and AGENTS.md so all team agents follow identical guardrails.
Architectural Directives in Detail

Step-by-Step Production Directives

Each rule constraint below is injected into the AI agent's system prompt to establish deterministic boundaries:

1

Engineers MUST ALWAYS compile and statically validate OpenFGA authorization DSL schemas using the official AST transformer and automated test suites before running deployment migrations.

Engineers MUST ALWAYS compile and statically validate OpenFGA authorization DSL schemas using the official AST transformer and automated test suites before running deployment migrations.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
2

Engineers MUST NOT define relational types with unconstrained self-referential tuple-to-userset links without explicit hierarchical depth invariants or structural parent-child boundary definitions.

Engineers MUST NOT define relational types with unconstrained self-referential tuple-to-userset links without explicit hierarchical depth invariants or structural parent-child boundary definitions.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
3

Services MUST execute cycle detection algorithms (such as Tarjan's or Kosaraju's SCC) on relation schema dependency graphs in CI/CD pipeline steps to detect mutual recursion loops.

Services MUST execute cycle detection algorithms (such as Tarjan's or Kosaraju's SCC) on relation schema dependency graphs in CI/CD pipeline steps to detect mutual recursion loops.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
4

Tuple ingestion pipelines MUST reject runtime edge insertions that introduce cyclical ancestry (e.g., group A member of group B, group B member of group A) using transactional reachability checks or bounded traversal depth constraints.

Tuple ingestion pipelines MUST reject runtime edge insertions that introduce cyclical ancestry (e.g., group A member of group B, group B member of group A) using transactional reachability checks or bounded traversal depth constraints.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
5

Authorization models SHOULD define granular, explicitly separated permissions rather than infinitely nested transitive delegations that trigger database query amplification during ListObjects and Check RPCs.

Authorization models SHOULD define granular, explicitly separated permissions rather than infinitely nested transitive delegations that trigger database query amplification during ListObjects and Check RPCs.

Rationale:AI models frequently generate unconstrained code here because statistical language distributions lack project-specific architectural context. Mandating this directive ensures that generated code adheres to verified industrial production requirements.
Enforcement:Integrated into the Agent Pack rule file. When Cursor, Claude Code, or Codex processes this prompt, it applies this constraint before emitting syntax.
Technical Questions & Answers

Frequently Asked Technical Questions

Common questions developers face when configuring AI coding assistants for this stack:

Q:Why is OpenFGA Static Relation Model Cycle and Recursion Guardrail critical for AI coding assistants?

Enforces pre-deployment compile-time verification and static Directed Acyclic Graph (DAG) validation on OpenFGA authorization models. Prevents unbounded recursive relations, mutual-containment loops, and circular tuple expansions that trigger catastrophic goroutine exhaustion and denial-of-service timeouts during runtime authorization checks. Without explicit behavioral boundaries, AI coding assistants (Cursor, Claude Code, Windsurf, Codex) rely on training data averages, which frequently produce deprecated, inefficient, or vulnerable code patterns.

Q:How does adopting this rule prevent AI hallucinations?

This rule explicitly declares what the AI must avoid (Deploying Unvalidated OpenFGA Models with Unbounded Recursive Expansion Paths) and prescribes verified positive examples. Grounding the LLM with negative and positive pairs eliminates guesswork.

Q:Which AI coding environments are supported?

This specification is multi-platform compatible: Cursor (.cursor/rules/*.mdc & .cursorrules), Anthropic Claude Code (CLAUDE.md), Windsurf (.windsurfrules), Codex / Cline (AGENTS.md), and GitHub Copilot (.github/copilot-instructions.md).

Q:Can I combine this rule with other technology stacks?

Yes. Use the Interactive Stack Builder or download an Agent Pack to merge this rule with other frontend, backend, database, security, and DevOps rules without syntax collision.

Open Specification · CC BY 4.0·Free for Personal, Team & Commercial In-Repo Use

Citation & Open Source Attribution Guidelines

This specification is licensed under Creative Commons Attribution 4.0 International (CC BY 4.0). You are completely free to adapt and share this rule in your workspace. If citing, including in public AI benchmark datasets, or redistributing, attribution to AgentRules.org is required.

1 Rule in Stack

OpenFGA