272 lines
12 KiB
Python
272 lines
12 KiB
Python
# [DEF:ComplianceOrchestrator:Module]
|
|
# @COMPLEXITY: 5
|
|
# @SEMANTICS: clean-release, orchestrator, compliance-gate, stages
|
|
# @PURPOSE: Execute mandatory clean compliance stages and produce final COMPLIANT/BLOCKED/FAILED outcome.
|
|
# @LAYER: Domain
|
|
# @RELATION: [DEPENDS_ON] ->[ComplianceStages]
|
|
# @RELATION: [DEPENDS_ON] ->[RepositoryRelations]
|
|
# @RELATION: [DEPENDS_ON] ->[CleanReleaseModels]
|
|
# @INVARIANT: COMPLIANT is impossible when any mandatory stage fails.
|
|
# @TEST_CONTRACT: ComplianceCheckRun -> ComplianceCheckRun
|
|
# @TEST_FIXTURE: compliant_candidate -> file:backend/tests/fixtures/clean_release/fixtures_clean_release.json
|
|
# @TEST_EDGE: stage_failure_blocks_release -> Mandatory stage returns FAIL and final status becomes BLOCKED
|
|
# @TEST_EDGE: missing_stage_result -> Finalization with incomplete/empty mandatory stage set must not produce COMPLIANT
|
|
# @TEST_EDGE: report_generation_error -> Downstream reporting failure does not alter orchestrator status derivation contract
|
|
# @TEST_INVARIANT: compliant_requires_all_mandatory_pass -> VERIFIED_BY: [stage_failure_blocks_release]
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime, timezone
|
|
from typing import List, Optional
|
|
from uuid import uuid4
|
|
|
|
from .enums import (
|
|
RunStatus,
|
|
ComplianceDecision,
|
|
ComplianceStageName,
|
|
ViolationCategory,
|
|
ViolationSeverity,
|
|
)
|
|
from ...models.clean_release import (
|
|
ComplianceRun,
|
|
ComplianceStageRun,
|
|
ComplianceViolation,
|
|
CheckFinalStatus,
|
|
)
|
|
from .policy_engine import CleanPolicyEngine
|
|
from .repository import CleanReleaseRepository
|
|
from .stages import derive_final_status
|
|
from ...core.logger import belief_scope, logger
|
|
|
|
|
|
# [DEF:CleanComplianceOrchestrator:Class]
|
|
# @PURPOSE: Coordinate clean-release compliance verification stages.
|
|
class CleanComplianceOrchestrator:
|
|
# [DEF:__init__:Function]
|
|
# @PURPOSE: Bind repository dependency used for orchestrator persistence and lookups.
|
|
# @PRE: repository is a valid CleanReleaseRepository instance with required methods.
|
|
# @POST: self.repository is assigned and used by all orchestration steps.
|
|
# @SIDE_EFFECT: Stores repository reference on orchestrator instance.
|
|
# @DATA_CONTRACT: Input -> CleanReleaseRepository, Output -> None
|
|
def __init__(self, repository: CleanReleaseRepository):
|
|
with belief_scope("CleanComplianceOrchestrator.__init__"):
|
|
self.repository = repository
|
|
|
|
# [/DEF:__init__:Function]
|
|
|
|
# [DEF:start_check_run:Function]
|
|
# @PURPOSE: Initiate a new compliance run session.
|
|
# @PRE: candidate_id and policy_id are provided; legacy callers may omit persisted manifest/policy records.
|
|
# @POST: Returns initialized ComplianceRun in RUNNING state persisted in repository.
|
|
# @SIDE_EFFECT: Reads manifest/policy when present and writes new ComplianceRun via repository.save_check_run.
|
|
# @DATA_CONTRACT: Input -> (candidate_id:str, policy_id:str, requested_by:str, manifest_id:str|None), Output -> ComplianceRun
|
|
def start_check_run(
|
|
self,
|
|
candidate_id: str,
|
|
policy_id: str,
|
|
requested_by: str | None = None,
|
|
manifest_id: str | None = None,
|
|
**legacy_kwargs,
|
|
) -> ComplianceRun:
|
|
with belief_scope("start_check_run"):
|
|
actor = requested_by or legacy_kwargs.get("triggered_by") or "system"
|
|
execution_mode = (
|
|
str(legacy_kwargs.get("execution_mode") or "").strip().lower()
|
|
)
|
|
manifest_id_value = manifest_id
|
|
|
|
if manifest_id_value and str(manifest_id_value).strip().lower() in {
|
|
"tui",
|
|
"api",
|
|
"scheduler",
|
|
}:
|
|
logger.reason(
|
|
"Detected legacy positional execution_mode passed through manifest_id slot",
|
|
extra={
|
|
"candidate_id": candidate_id,
|
|
"execution_mode": manifest_id_value,
|
|
},
|
|
)
|
|
execution_mode = str(manifest_id_value).strip().lower()
|
|
manifest_id_value = None
|
|
|
|
manifest = (
|
|
self.repository.get_manifest(manifest_id_value)
|
|
if manifest_id_value
|
|
else None
|
|
)
|
|
policy = self.repository.get_policy(policy_id)
|
|
|
|
if manifest_id_value and manifest is None:
|
|
logger.explore(
|
|
"Manifest lookup missed during run start; rejecting explicit manifest contract",
|
|
extra={
|
|
"candidate_id": candidate_id,
|
|
"manifest_id": manifest_id_value,
|
|
},
|
|
)
|
|
raise ValueError("Manifest or Policy not found")
|
|
|
|
if policy is None:
|
|
logger.explore(
|
|
"Policy lookup missed during run start; using compatibility placeholder snapshot",
|
|
extra={
|
|
"candidate_id": candidate_id,
|
|
"policy_id": policy_id,
|
|
"execution_mode": execution_mode or "unspecified",
|
|
},
|
|
)
|
|
|
|
manifest_id_value = manifest_id_value or f"manifest-{candidate_id}"
|
|
manifest_digest = getattr(manifest, "manifest_digest", "pending")
|
|
registry_snapshot_id = (
|
|
getattr(policy, "registry_snapshot_id", None)
|
|
or getattr(policy, "internal_source_registry_ref", None)
|
|
or "pending"
|
|
)
|
|
|
|
check_run = ComplianceRun(
|
|
id=f"check-{uuid4()}",
|
|
candidate_id=candidate_id,
|
|
manifest_id=manifest_id_value,
|
|
manifest_digest=manifest_digest,
|
|
policy_snapshot_id=policy_id,
|
|
registry_snapshot_id=registry_snapshot_id,
|
|
requested_by=actor,
|
|
requested_at=datetime.now(timezone.utc),
|
|
started_at=datetime.now(timezone.utc),
|
|
status=RunStatus.RUNNING,
|
|
)
|
|
logger.reflect(
|
|
"Initialized compliance run with compatibility-safe dependency placeholders",
|
|
extra={
|
|
"run_id": check_run.id,
|
|
"candidate_id": candidate_id,
|
|
"policy_id": policy_id,
|
|
},
|
|
)
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
# [/DEF:start_check_run:Function]
|
|
|
|
# [DEF:execute_stages:Function]
|
|
# @PURPOSE: Execute or accept compliance stage outcomes and set intermediate/final check-run status fields.
|
|
# @PRE: check_run exists and references candidate/policy/registry/manifest identifiers resolvable by repository.
|
|
# @POST: Returns persisted ComplianceRun with status FAILED on missing dependencies, otherwise SUCCEEDED with final_status set.
|
|
# @SIDE_EFFECT: Reads candidate/policy/registry/manifest and persists updated check_run.
|
|
# @DATA_CONTRACT: Input -> (check_run:ComplianceRun, forced_results:Optional[List[ComplianceStageRun]]), Output -> ComplianceRun
|
|
def execute_stages(
|
|
self,
|
|
check_run: ComplianceRun,
|
|
forced_results: Optional[List[ComplianceStageRun]] = None,
|
|
) -> ComplianceRun:
|
|
with belief_scope("execute_stages"):
|
|
if forced_results is not None:
|
|
for index, result in enumerate(forced_results, start=1):
|
|
if isinstance(result, ComplianceStageRun):
|
|
stage_run = result
|
|
else:
|
|
status_value = getattr(result, "status", None)
|
|
if status_value == "PASS":
|
|
decision = ComplianceDecision.PASSED.value
|
|
elif status_value == "FAIL":
|
|
decision = ComplianceDecision.BLOCKED.value
|
|
else:
|
|
decision = ComplianceDecision.ERROR.value
|
|
stage_run = ComplianceStageRun(
|
|
id=f"{check_run.id}-stage-{index}",
|
|
run_id=check_run.id,
|
|
stage_name=result.stage.value,
|
|
status=result.status.value,
|
|
decision=decision,
|
|
details_json={"details": result.details},
|
|
)
|
|
self.repository.stage_runs[stage_run.id] = stage_run
|
|
|
|
check_run.final_status = derive_final_status(forced_results).value
|
|
check_run.status = RunStatus.SUCCEEDED
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
candidate = self.repository.get_candidate(check_run.candidate_id)
|
|
policy = self.repository.get_policy(check_run.policy_snapshot_id)
|
|
registry = self.repository.get_registry(check_run.registry_snapshot_id)
|
|
manifest = self.repository.get_manifest(check_run.manifest_id)
|
|
|
|
if not candidate or not policy or not registry or not manifest:
|
|
check_run.status = RunStatus.FAILED
|
|
check_run.finished_at = datetime.now(timezone.utc)
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
summary = manifest.content_json.get("summary", {})
|
|
purity_ok = summary.get("prohibited_detected_count", 0) == 0
|
|
check_run.final_status = (
|
|
ComplianceDecision.PASSED.value
|
|
if purity_ok
|
|
else ComplianceDecision.BLOCKED.value
|
|
)
|
|
check_run.status = RunStatus.SUCCEEDED
|
|
check_run.finished_at = datetime.now(timezone.utc)
|
|
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
# [/DEF:execute_stages:Function]
|
|
|
|
# [DEF:finalize_run:Function]
|
|
# @PURPOSE: Finalize run status based on cumulative stage results.
|
|
# @PRE: check_run was started and may already contain a derived final_status from stage execution.
|
|
# @POST: Returns persisted ComplianceRun in SUCCEEDED status with final_status guaranteed non-empty.
|
|
# @SIDE_EFFECT: Mutates check_run terminal fields and persists via repository.save_check_run.
|
|
# @DATA_CONTRACT: Input -> ComplianceRun, Output -> ComplianceRun
|
|
def finalize_run(self, check_run: ComplianceRun) -> ComplianceRun:
|
|
with belief_scope("finalize_run"):
|
|
if check_run.status == RunStatus.FAILED:
|
|
check_run.finished_at = datetime.now(timezone.utc)
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
if not check_run.final_status:
|
|
stage_results = [
|
|
stage_run
|
|
for stage_run in self.repository.stage_runs.values()
|
|
if stage_run.run_id == check_run.id
|
|
]
|
|
derived = derive_final_status(stage_results)
|
|
check_run.final_status = derived.value
|
|
|
|
check_run.status = RunStatus.SUCCEEDED
|
|
check_run.finished_at = datetime.now(timezone.utc)
|
|
return self.repository.save_check_run(check_run)
|
|
|
|
# [/DEF:finalize_run:Function]
|
|
|
|
|
|
# [/DEF:CleanComplianceOrchestrator:Class]
|
|
|
|
|
|
# [DEF:run_check_legacy:Function]
|
|
# @PURPOSE: Legacy wrapper for compatibility with previous orchestrator call style.
|
|
# @PRE: repository and identifiers are valid and resolvable by orchestrator dependencies.
|
|
# @POST: Returns finalized ComplianceRun produced by orchestrator start->execute->finalize sequence.
|
|
# @SIDE_EFFECT: Reads/writes compliance entities through repository during orchestrator calls.
|
|
# @DATA_CONTRACT: Input -> (repository:CleanReleaseRepository, candidate_id:str, policy_id:str, requested_by:str, manifest_id:str), Output -> ComplianceRun
|
|
def run_check_legacy(
|
|
repository: CleanReleaseRepository,
|
|
candidate_id: str,
|
|
policy_id: str,
|
|
requested_by: str,
|
|
manifest_id: str,
|
|
) -> ComplianceRun:
|
|
with belief_scope("run_check_legacy"):
|
|
orchestrator = CleanComplianceOrchestrator(repository)
|
|
run = orchestrator.start_check_run(
|
|
candidate_id=candidate_id,
|
|
policy_id=policy_id,
|
|
requested_by=requested_by,
|
|
manifest_id=manifest_id,
|
|
)
|
|
run = orchestrator.execute_stages(run)
|
|
return orchestrator.finalize_run(run)
|
|
|
|
|
|
# [/DEF:run_check_legacy:Function]
|
|
# [/DEF:ComplianceOrchestrator:Module]
|