Flutter Policy Engine
A lightweight, extensible policy engine for Flutter applications. Define, manage, and evaluate access control rules declaratively using ABAC (Attribute-Based Access Control) or RBAC (Role-Based Access Control) models with a clean, intuitive API.
β¨ Features
- π Dual Access Control Models: Support for both Role-Based (RBAC) and Attribute-Based (ABAC) access control
- π― Declarative Policy Definitions: Define access rules using simple, readable configurations
- π JSON Asset Loading: Load policies from external JSON files bundled with your app
- ποΈ Modular Architecture: Extensible design with clear separation of concerns
- β‘ Lightweight & Fast: Minimal overhead with efficient policy evaluation
- π Real-time Updates: Dynamic policy updates without app restarts
- π¨ Flutter-Native: Built specifically for Flutter with widget integration
- π± Easy Integration: Simple setup with minimal boilerplate code
- π§ͺ Comprehensive Testing: Full test coverage with examples
- π‘οΈ Robust Error Handling: Structured exception handling with detailed context
π Quick Start
Installation
Add the package to your pubspec.yaml
:
dependencies:
flutter_policy_engine: ^1.1.0
Run the installation:
flutter pub get
Basic Usage
import 'package:flutter/material.dart';
import 'package:flutter_policy_engine/flutter_policy_engine.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// Initialize policy manager
final policyManager = PolicyManager();
await policyManager.initialize({
"admin": ["dashboard", "users", "settings", "reports"],
"manager": ["dashboard", "users", "reports"],
"user": ["dashboard"],
"guest": ["login"]
});
runApp(MyApp(policyManager: policyManager));
}
class MyApp extends StatelessWidget {
final PolicyManager policyManager;
const MyApp({super.key, required this.policyManager});
@override
Widget build(BuildContext context) {
return PolicyProvider(
policyManager: policyManager,
child: MaterialApp(
title: 'Policy Engine Demo',
home: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Dashboard')),
body: Column(
children: [
// Only show for admin and manager roles
PolicyWidget(
role: "admin",
content: "users",
child: UserManagementCard(),
fallback: AccessDeniedWidget(),
),
// Show for all authenticated users
PolicyWidget(
role: "user",
content: "dashboard",
child: DashboardCard(),
),
],
),
);
}
}
Loading Policies from JSON Assets
You can also load policies from JSON files bundled with your app:
// Add to pubspec.yaml
flutter:
assets:
- assets/policies/
// Create assets/policies/user_roles.json
{
"admin": {
"allowedContent": ["dashboard", "users", "settings", "reports"]
},
"manager": {
"allowedContent": ["dashboard", "users", "reports"]
},
"user": {
"allowedContent": ["dashboard"]
}
}
// Initialize from JSON asset
final policyManager = PolicyManager();
await policyManager.initializeFromJsonAssets('assets/policies/user_roles.json');
π Core Concepts
Policy Manager
The central orchestrator that manages all access control logic:
final policyManager = PolicyManager();
// Initialize with role definitions
await policyManager.initialize({
"admin": ["dashboard", "users", "settings"],
"user": ["dashboard"],
});
// Check access programmatically
bool hasAccess = policyManager.evaluateAccess("admin", "users"); // true
bool canAccess = policyManager.evaluateAccess("user", "settings"); // false
Policy Widget
Conditionally render content based on user roles:
PolicyWidget(
role: "admin",
content: "settings",
child: SettingsPage(),
fallback: AccessDeniedWidget(),
)
Role Management
Create and manage roles dynamically:
// Add a new role
await policyManager.addRole("moderator", ["dashboard", "comments"]);
// Update existing role
await policyManager.updateRole("user", ["dashboard", "profile"]);
// Remove a role
await policyManager.removeRole("guest");
π§ͺ Testing
Local Testing
Run tests with coverage:
# Using the provided script (recommended)
./scripts/test_with_coverage.sh
# Or manually
fvm flutter test --coverage
lcov --summary coverage/lcov.info
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.html
GitHub Actions Testing
Test GitHub Actions workflows locally before pushing to GitHub:
# Install dependencies (first time only)
./scripts/install_dependencies.sh
# Test a specific workflow
./scripts/test_github_actions.sh -w .github/workflows/check-commits.yml --dry-run
# List available workflows
./scripts/test_github_actions.sh --list-workflows
# Test with verbose output
./scripts/test_github_actions.sh -w .github/workflows/main-branch-pipeline.yml -v
Features:
- π³ Docker-based local testing with
act
- π Workflow validation and syntax checking
- π§ͺ Dry-run mode for safe testing
- π Comprehensive workflow coverage
- π οΈ Automatic dependency management
For detailed usage, see GitHub Actions Testing Guide.
Example App
Explore the interactive example app with multiple demos:
cd example
flutter run
The example includes:
π― Basic Policy Demo
- Core policy evaluation demonstrations
- Real-time access control testing
- Widget-based permission checking
π₯ Role Management Demo
- Dynamic role creation and modification
- Interactive role testing interface
- Real-time policy updates
π JSON Assets Demo
- Loading policies from external JSON files
- Asset-based configuration management
- Comprehensive permission testing
π Documentation
- Quick Start Guide - Get up and running in minutes
- Core Concepts - Deep dive into policy management
- Examples - Practical usage examples
π€ Contributing
We welcome contributions! Please see our Contributing Guide for details.
Development Setup
# Clone the repository
git clone https://github.com/aspicas/flutter_policy_engine.git
cd flutter_policy_engine
# Run the setup script
./setup.sh
# Run tests
./scripts/test_with_coverage.sh
Code Style
- Follow the existing code patterns and style
- Write clear commit messages (Commitlint enabled)
- Add tests for new features
- Ensure all tests pass before submitting PRs
π License
MIT Β© 2025 David Alejandro Garcia Ruiz
π‘ Tip: If you use VSCode, restart your terminal after setup to ensure FVM is properly detected.