# @fireshield/rules-engine

An independent rules engine for security analysis of Firebase and cloud projects. This package provides a Firebase-agnostic rules execution engine that can analyze project configurations against security policies.

## Features

- **Firebase-Independent**: No Firebase dependencies, can be used with any project configuration data
- **Rules Engine**: Powered by json-rules-engine for flexible condition evaluation
- **SARIF Output**: Generate industry-standard SARIF reports for security findings
- **Extensible Scanners**: Plugin architecture for custom security scanners
- **TypeScript**: Full TypeScript support with comprehensive type definitions

## Installation

### From GitHub Packages

```bash
# Configure npm to use GitHub Packages for @fireshield scope
echo "@fireshield:registry=https://npm.pkg.github.com" >> ~/.npmrc

# Install the package
npm install @fireshield/rules-engine
```

### Alternative: Using .npmrc file

Create a `.npmrc` file in your project root:

```
@fireshield:registry=https://npm.pkg.github.com
```

Then install:

```bash
npm install @fireshield/rules-engine
```

### Authentication

For private packages, you'll need a GitHub Personal Access Token with `read:packages` permission:

```bash
echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> ~/.npmrc
```

## Basic Usage

```typescript
import { 
  executeRules, 
  createRuleExecutionContext, 
  generateSARIF 
} from '@fireshield/rules-engine';

// Your project information
const projectInfo = {
  project_id: 'my-project',
  auth: { auth_enabled: false },
  databases: [{ id: 'default', location: 'us-central1' }],
  appcheck: { 
    app_check_enabled: true,
    total_apps: 2,
    total_services: 3,
    enforced_services: 2
  },
  // ... other project data
};

// Your security rules
const rules = [
  {
    id: 'auth-not-enabled',
    name: 'Authentication Not Enabled',
    description: 'Checks if Firebase Authentication is enabled',
    severity: 'high',
    category: 'Authentication',
    conditions: {
      all: [{ fact: 'auth', path: 'auth_enabled', operator: 'equal', value: false }]
    },
    event: {
      type: 'auth-not-enabled',
      params: { message: 'Firebase Authentication is not enabled' }
    }
  }
];

// Execute rules - ProjectInformation is automatically enriched with computed properties
const context = createRuleExecutionContext(projectInfo, rules);
const results = await executeRules(context);

// Generate SARIF report
const analysisResult = {
  scanId: 'scan-123',
  project_id: 'my-project',
  timestamp: new Date().toISOString(),
  total_rules: rules.length,
  triggered_rules: results.filter(r => r.triggered).length,
  results: results
};

const sarifReport = generateSARIF(analysisResult);
```

## Core Types

### ProjectInformation
The core data structure containing Firebase project configuration. ProjectInformation is automatically enriched with computed properties during rule execution.

```typescript
interface ProjectInformation {
  project_id: string;
  databases: DatabaseInfo[];
  functionsv1: FirebaseFunction[];
  functionsv2: FirebaseFunction[];
  storage_buckets: StorageBucket[];
  auth: AuthSettings;
  appcheck: AppCheckSettings;
  function_secrets: SecretScanResult[];
}

// Enriched with computed properties during execution
interface EnrichedProjectInformation extends ProjectInformation {
  computed: {
    enforcement_ratio: number;
    apps_without_attestation_providers: number;
    security_score: number;
    has_secrets: boolean;
    multi_region_deployment: boolean;
  };
}
```

### StaticRule
```typescript
interface StaticRule {
  id: string;
  name: string;
  description: string;
  severity?: 'low' | 'medium' | 'high' | 'critical';
  category?: string;
  conditions: Record<string, unknown>;
  event: {
    type: string;
    params: {
      message: string;
      [key: string]: unknown;
    };
  };
}
```

### RuleResult
```typescript
interface RuleResult {
  rule_id: string;
  rule_name: string;
  severity: string;
  category: string;
  message: string;
  triggered: boolean;
  facts_used: Record<string, unknown>;
  event_params?: Record<string, unknown>;
}
```

## API Reference

### Core Functions

#### `executeRules(context: RuleExecutionContext): Promise<RuleResult[]>`
Executes security rules against project information.

#### `createRuleExecutionContext(projectInfo: ProjectInformation, rules: StaticRule[]): RuleExecutionContext`
Creates an execution context for rule evaluation.

#### `generateSARIF(analysisResult: AnalysisResult): any`
Generates SARIF (Static Analysis Results Interchange Format) output.

### Scanners

The package includes extensible scanners for different security aspects:

- **Secret Scanner**: Detects hardcoded secrets in function environment variables
- **Authentication Scanner**: Analyzes authentication configuration
- **Access Control Scanner**: Reviews database and storage permissions
- **Configuration Scanner**: Validates security settings

## Rule Examples

### Computed Properties

The rules engine automatically enriches ProjectInformation with computed properties that provide calculated values for complex security analysis:

```typescript
// Available computed properties:
{
  computed: {
    enforcement_ratio: number;           // Ratio of enforced AppCheck services
    apps_without_attestation_providers: number; // Count of apps missing attestation
    security_score: number;             // Overall security score (0-100)
    has_secrets: boolean;               // Whether functions contain secrets
    multi_region_deployment: boolean;   // Whether deployment spans multiple regions
  }
}
```

### Rule Path Reference

| ProjectInformation Path      | Description                             | Example Value |
| ---------------------------- | --------------------------------------- | ------------- |
| `auth.auth_enabled`          | Whether authentication is enabled       | `true`        |
| `auth.email_enabled`         | Whether email authentication is enabled | `true`        |
| `auth.password_min_length`   | Minimum password length                 | `8`           |
| `appcheck.app_check_enabled` | Whether App Check is enabled            | `true`        |
| `appcheck.total_apps`        | Total number of apps                    | `3`           |
| `appcheck.total_services`    | Total number of services                | `5`           |
| `appcheck.enforced_services` | Number of enforced services             | `3`           |
| `computed.enforcement_ratio` | Enforcement coverage ratio              | `0.6`         |
| `computed.has_secrets`       | Whether secrets were detected           | `false`       |

## Rule Examples

### Authentication Rules
```typescript
{
  id: 'weak-password-policy',
  name: 'Weak Password Policy',
  description: 'Checks for weak password policies',
  severity: 'medium',
  category: 'Authentication',
  conditions: {
    all: [
      { fact: 'auth', path: 'auth_enabled', operator: 'equal', value: true },
      { fact: 'auth', path: 'password_min_length', operator: 'lessThan', value: 8 }
    ]
  },
  event: {
    type: 'weak-password-policy',
    params: { message: 'Password policy is weak' }
  }
}
```

### App Check Rules
```typescript
{
  id: 'low-enforcement-coverage',
  name: 'Low App Check Enforcement Coverage',
  description: 'Less than 50% of services have App Check enforcement enabled',
  severity: 'warning',
  category: 'AppCheck',
  conditions: {
    all: [
      { fact: 'computed', path: 'enforcement_ratio', operator: 'lessThan', value: 0.5 }
    ]
  },
  event: {
    type: 'low-enforcement-coverage',
    params: { message: 'App Check enforcement coverage is too low' }
  }
}
```

### Function Security Rules
```typescript
{
  id: 'functions-have-secrets',
  name: 'Functions Contain Secrets',
  description: 'Detects hardcoded secrets in function environment variables',
  severity: 'critical',
  category: 'Secrets',
  conditions: {
    all: [{ fact: 'computed', path: 'has_secrets', operator: 'equal', value: true }]
  },
  event: {
    type: 'functions-have-secrets',
    params: { message: 'Functions contain hardcoded secrets' }
  }
}
```

## Development Status

🚧 **This package is under active development as part of the Fireshield rules engine extraction.**

### Implementation Stages

- ✅ **Stage 1**: Package structure, types, and configuration
- ✅ **Stage 2**: Core logic extraction (fact-transformer migration to computed properties)
- ✅ **Stage 3**: Rules engine modernization and ProjectInformation integration
- ⏳ **Stage 4**: Scanner integration
- ⏳ **Stage 5**: Testing and validation
- ⏳ **Stage 6**: Documentation and examples

### Migration Notes

**Fact-Transformer Deprecation (June 2025)**
- ✅ Removed fact-transformer layer for simplified architecture
- ✅ Direct ProjectInformation usage with computed properties
- ✅ Enhanced type safety and performance
- ✅ All 26 rules migrated to new format

For legacy systems still using fact-transformer functions, please update to use `executeRules()` directly with ProjectInformation objects.

## Contributing

This package is part of the Fireshield project. Contributions are welcome!

## License

MIT License - see LICENSE file for details.

## Support

For issues and questions:
- GitHub Issues: [Fireshield Issues](https://github.com/fireshield/issues)
- Documentation: [Fireshield Docs](https://docs.fireshield.dev)

---

*Part of the Fireshield Security Platform*

## Publishing to GitHub Packages

To publish this package to a private GitHub npm repository, follow these steps:

### 1. Create a Personal Access Token (PAT)

- Go to your GitHub account settings.
- Navigate to "Developer settings" > "Personal access tokens" > "Tokens (classic)".
- Click "Generate new token" (or "Generate new token (classic)").
- Give your token a descriptive name (e.g., `npm-publish`).
- Select the scopes `read:packages` and `write:packages`.
- Click "Generate token" and copy the token. You will not be able to see it again.

### 2. Configure npm

Create or edit the `.npmrc` file in your user's home directory (e.g., `~/.npmrc` on Linux/macOS or `C:\Users\YOUR_USERNAME\.npmrc` on Windows). Add the following line, replacing `YOUR_PAT_HERE` with the PAT you just created:

```
//npm.pkg.github.com/:_authToken=YOUR_PAT_HERE
```

This tells npm to authenticate with your PAT when interacting with the GitHub Packages registry.

### 3. Update `package.json`

Ensure your `package.json` file includes the `repository` field and a `publishConfig` field pointing to the GitHub Packages registry. Replace `OWNER` and `REPO` with your GitHub username or organization name and the repository name.

```json
{
  "name": "@OWNER/rules-engine", // It's good practice to scope your package name to your GitHub owner
  // ... other package.json fields
  "repository": {
    "type": "git",
    "url": "https://github.com/OWNER/REPO.git"
  },
  "publishConfig": {
    "registry": "https://npm.pkg.github.com/"
  }
  // ...
}
```
**Note:** For this specific package, the name is `@fireshield/rules-engine`. If you are publishing to a personal fork or a different organization, you would change `fireshield` in the `name` property to your GitHub username or organization name (e.g., `@YOUR_USERNAME/rules-engine`).

### 4. Publish the Package

Once your PAT is configured and `package.json` is updated, you can publish the package using:

```bash
npm publish
```

This command will build your package (if a `prepublishOnly` script is defined) and upload it to the GitHub Packages registry associated with the repository specified in your `package.json`.
