fastapi-gsap/gsap_broker/templates/policy.py
Tyler J King 77964e4042 feat(templates): add template system — manifest, policy, loader, registries
bastion.toml manifest parser with variable validation and dependency
declarations. Declarative compliance policy schema with per-platform
check implementations. Template loader with variable substitution
(Bastion-owned files only — never touches Ansible/Terraform).
PolicyRegistry and AccordRegistry with builtin fallbacks.

BOUNDARY: loader never touches automation framework files.

Signed-off-by: Tyler King <tking@guildhouse.dev>
2026-04-14 11:09:41 -04:00

88 lines
2.6 KiB
Python

# Copyright 2026 Guildhouse Dev
# SPDX-License-Identifier: Apache-2.0
"""Declarative compliance policy schema.
A policy defines conditions that managed devices must satisfy.
Each condition maps to a PostureConditionKind evaluated by
Bastion's compliance engine. Conditions can have platform-specific
check implementations (Intune field, script, Keylime attestation).
Policies are framework-agnostic. They describe WHAT must be true,
not HOW to achieve it. Playbooks/scripts achieve compliance;
policies evaluate it.
"""
from __future__ import annotations
import tomllib
from pathlib import Path
from typing import Any, Optional
from pydantic import BaseModel
class PlatformCheck(BaseModel):
"""Platform-specific check implementation."""
intune_field: Optional[str] = None
intune_policy: Optional[str] = None
expect: Optional[Any] = None
script: Optional[str] = None
keylime_check: Optional[str] = None
class PolicyCondition(BaseModel):
"""A single compliance condition."""
id: str
kind: str
description: str = ""
framework_ref: Optional[str] = None
severity: str = "medium"
optional: bool = False
linux: Optional[PlatformCheck] = None
windows: Optional[PlatformCheck] = None
macos: Optional[PlatformCheck] = None
class BreachResponseConfig(BaseModel):
"""What happens when conditions at each severity level fail."""
critical: str = "suspend_access"
high: str = "alert_msp"
medium: str = "log_only"
low: str = "log_only"
class EvaluationSchedule(BaseModel):
"""How often to evaluate compliance."""
interval_seconds: int = 300
full_evaluation_hours: int = 24
class CompliancePolicy(BaseModel):
"""A complete compliance policy definition."""
name: str
description: str = ""
version: str = "1.0.0"
framework: Optional[str] = None
framework_controls: list[str] = []
conditions: list[PolicyCondition] = []
breach_response: BreachResponseConfig = BreachResponseConfig()
schedule: EvaluationSchedule = EvaluationSchedule()
@classmethod
def from_toml(cls, path: str | Path) -> CompliancePolicy:
"""Parse a policy TOML file."""
with open(path, "rb") as f:
data = tomllib.load(f)
return cls.model_validate(data)
def conditions_for_platform(self, platform: str) -> list[PolicyCondition]:
"""Return conditions applicable to a specific platform."""
result = []
for c in self.conditions:
check = getattr(c, platform, None)
if check is not None:
result.append(c)
return result