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>
88 lines
2.6 KiB
Python
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
|