PolicyFlow

Language Grammar and Syntax

Keywords, comments, literals, and operators in PolicyFlow

This section provides a detailed reference for the fundamental building blocks of the PolicyFlow language, including keywords, comments, literals, and operators.

Keywords

PolicyFlow uses a set of reserved keywords to define its structure and logic.

Declaration Keywords

KeywordDescriptionExample
policyDeclares a new policypolicy DocumentAccess { ... }
schemaDeclares a new schema in a .pfs fileschema AuthSchema { ... }
testDeclares a test suite in a .pftest filetest DocumentAccessTests for DocumentAccess { ... }
typeDeclares a new complex object typetype CorporateUser { ... }
enumDeclares a new enumerationenum Status { ACTIVE, PENDING }

Designated Type Keywords

KeywordDescriptionExample
UserDesignates a type as a UserUser type CorporateUser { ... }
ResourceDesignates a type as a ResourceResource type Document { ... }
ContextDesignates a type as a ContextContext type RequestContext { ... }
RelationshipDesignates a type as a RelationshipRelationship type TeamMembership { ... }

Module System Keywords

KeywordDescriptionExample
importImports types from other filesimport * as Auth from "@/schemas/auth.pfs";
fromSpecifies the import sourceSee above
asCreates an alias for importsSee above

Policy Structure Keywords

KeywordDescriptionExample
rulesDefines the rules blockrules { ... }
ruleDeclares an individual rulerule OwnerAccess { ... }
whenStarts a conditionwhen user.id == resource.ownerId
thenSpecifies the decisionthen ALLOW
prioritySets rule prioritypriority: 1000
reasonProvides explanationreason: "Owner has full access"

Comments

Comments are used to document code and are ignored by the compiler. PolicyFlow supports three styles:

Single-Line Comments

Start with // and continue to the end of the line.

// This rule checks for ownership.
when user.id == resource.ownerId then ALLOW

Multi-Line Comments

Start with /* and end with */. They can span multiple lines.

/*
  This policy is part of the compliance module
  and should not be edited without approval from the security team.
*/
policy ComplianceSOX { ... }

Documentation Comments

A special type of multi-line comment starting with /**. These are parsed by IDEs and tooling for contextual information.

/**
 * Defines the standard user model for our application.
 * Includes core attributes like email and clearance level.
 */
User type CorporateUser { ... }

Literals

Literals are notations for representing fixed values in source code.

String Literals

Enclosed in double quotes with support for escape sequences.

const message = "Hello, World!";
const multiline = "First line\nSecond line";
const withTab = "Column1\tColumn2";

Number Literals

Whole numbers (integers) with optional underscores for readability. The Number type represents 64-bit signed integers.

const count = 123;
const negative = -50;
const million = 1_000_000;  // Underscores for readability

Decimal Literals

Numbers with fractional parts. The Decimal type provides high-precision floating-point arithmetic.

const price = 99.9;
const precise = -0.123;
const percentage = 0.15;

Boolean Literals

const isActive = true;
const isDeleted = false;

Null Literal

const manager = null;  // No manager assigned

Assignment Syntax

PolicyFlow uses different assignment operators depending on the context:

In Type Definitions

Use : (colon) for property definitions and default values:

schema Example {
    type User {
        name: String                    // Property type
        age: Number                     // Property type
        isActive: Boolean = true        // Property with default
    }
}

policy MyPolicy {
    description: "Policy description"   // Metadata field
    version: "1.0.0"                   // Metadata field
}

In Rule Logic

Use = (equals) for variable assignments:

rule Example {
    when {
        const userName = user.name;     // Variable assignment
        let count = 0;                  // Mutable variable
        count = count + 1;              // Reassignment
        return count > 0;
    }
    then ALLOW
}

Actions and Wildcards

An Action is a string that represents the operation a user is attempting to perform. Actions are typically namespaced using colons.

Action Patterns

policy DocumentAccess {
    actions: ["documents:**"]  // This policy handles all document actions

    rules {
        rule ReadAccess {
            when action == "documents:read"
            then ALLOW
        }

        rule WriteAccess {
            when action.Matches("documents:write:*")
            then ALLOW
        }
    }
}

Action Wildcard Matching

The action variable has a special .Matches() method that supports wildcard patterns. This is specific to the action variable and uses PolicyFlow's wildcard syntax, not regular expressions.

PatternDescriptionExample MatchesDoes NOT Match
*Matches one segmentdocuments:read, users:viewdocuments:read:all, read
**Matches zero or more segmentsdocuments, documents:read, documents:system:restartread
documents:*Matches one segment after documentsdocuments:read, documents:writedocuments:read:all
documents:**Matches any action in the namespacedocuments, documents:read, documents:write:draftusers:read
**:readMatches any action ending with :readdocuments:read, files:public:readread, documents:read:all
rule WildcardExamples {
    when {
        // Check if action matches specific patterns
        const isReadAction = action.Matches("**:read");
        const isDocumentAction = action.Matches("documents:**");
        const isSpecificWrite = action.Matches("documents:write:*");

        return isReadAction OR (isDocumentAction AND user.hasDocumentAccess);
    }
    then ALLOW
}

Note: The .Matches() method on regular String types uses regular expressions, while action.Matches() uses PolicyFlow's wildcard syntax.

Variables and Constants

Environment Variables

Access global configuration through the env map. Environment variables in the .env file support automatic type detection.

Type Detection in .env Files

The parser for .env files automatically detects the following types:

  • Boolean: true or false (without quotes).
  • Number: Any integer value (e.g., 1000, -50).
  • Decimal: Any floating-point value (e.g., 0.08, 15.5).
  • String: Any value enclosed in double quotes (e.g., "system-admin").
# .env file with different types:

# Strings
ADMIN_ROLE = "system-admin"
COMPANY_DOMAIN = "example.com"

# Numbers
API_RATE_LIMIT = 1000
MAX_RETRIES = 3
MIN_CLEARANCE_LEVEL = 4

# Decimals
TAX_RATE = 0.08
DISCOUNT_PERCENTAGE = 15.5
MAX_CPU_THRESHOLD = 85.0

# Booleans
FEATURE_ENABLED = true
DEBUG_MODE = false

Using Environment Variables in Policies

rule AdminAccess {
    // ADMIN_ROLE is a string
    when env["ADMIN_ROLE"] in user.roles
    then ALLOW
    priority: 1000
}

rule RateLimit {
    when {
        // API_RATE_LIMIT is a Number
        const limit = env["API_RATE_LIMIT"];
        return user.requestCount > limit;
    }
    then DENY
    reason: "Rate limit exceeded"
}

rule TaxCalculation {
    when {
        // TAX_RATE is a Decimal
        const taxRate = env["TAX_RATE"];
        const totalWithTax = resource.price * (1 + taxRate);
        return totalWithTax <= user.budget;
    }
    then ALLOW
}

rule ClearanceLevelCheck {
    when {
        // MIN_CLEARANCE_LEVEL is a Number
        return user.clearanceLevel >= env["MIN_CLEARANCE_LEVEL"];
    }
    then ALLOW
}

// For booleans, use direct comparison
rule MaintenanceMode {
    when env["DEBUG_MODE"] == true
    then DENY
    priority: 0
    reason: "System under maintenance"
}

Scoped Variables

Use const for immutable values and let for mutable ones:

rule ComplexCheck {
    when {
        const adminRole = env["ADMIN_ROLE"];  // Immutable
        let effectiveClearance = user.clearanceLevel;  // Mutable

        if (user.hasTemporaryBoost) {
            effectiveClearance = effectiveClearance + 1;  // Can reassign
        }

        return adminRole in user.roles AND effectiveClearance >= 5;
    }
    then ALLOW
}

Control Flow

Conditional Logic in Rules

Rules support complex conditional logic within when blocks:

rule ComplexAccess {
    when {
        // Early return for admins
        if ("admin" in user.roles) {
            return true;
        }

        // Check ownership
        if (user.id == resource.ownerId) {
            return true;
        }

        // Check permissions based on classification
        const canRead = resource.classification == "Public" ||
                       (resource.classification == "Internal" && user.isEmployee);

        return canRead && action == "read";
    }
    then ALLOW
}

Ternary Operator

For concise conditional expressions:

const accessLevel = user.isAdmin ? "full" : "limited";
const timeout = user.isPremium ? 3600 : 1800;

Default Values

Default values are evaluated at object instantiation time, not at schema compilation time:

schema DefaultExample {
    type User {
        createdAt: DateTime = DateTime.Now()  // Set when object is created
        isActive: Boolean = true
        tags: String[] = []
    }
}

Next Steps