Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
c135be5
feat(OMN-2136): RRH nodes — emit effect, validate compute, storage ef…
jonahgabriel Feb 11, 2026
7c730d4
fix(OMN-2136): type dispatcher dict to satisfy mypy no-any-return
jonahgabriel Feb 11, 2026
2aa6efe
fix(review): [major] ReDoS guard + [minor] canonical imports, exports…
jonahgabriel Feb 11, 2026
f8591d1
fix(review): [major] sanitize git URLs/stderr, kill timed-out procs +…
jonahgabriel Feb 11, 2026
d7a366f
fix(review): [major] sanitize storage error + missing rule fail-path …
jonahgabriel Feb 11, 2026
5e92e18
fix(review): [major] kill timed-out subprocesses in toolchain handler
jonahgabriel Feb 11, 2026
2f693c8
fix(review): [major] robust symlink sanitization, sanitize toolchain …
jonahgabriel Feb 11, 2026
faa9594
fix(review): [minor] cache rule dispatcher, truncate patterns, micros…
jonahgabriel Feb 11, 2026
10332a7
fix(review): [minor] guard dot-dot symlink traversal + drop raw stdou…
jonahgabriel Feb 11, 2026
1627ac2
fix(review): [major] consistent correlation_id, sanitize broker & log…
jonahgabriel Feb 11, 2026
ce6762c
fix(review): [major] ReDoS timeout guard + truncate Kafka broker in e…
jonahgabriel Feb 11, 2026
b9458c2
fix(review): [minor] path validation guards, tool allowlist, severity…
jonahgabriel Feb 11, 2026
5e2248e
fix(review): [major] non-blocking ThreadPoolExecutor shutdown on ReDo…
jonahgabriel Feb 11, 2026
3cd3642
fix(review): [minor] add guard tests for path validation, fix tighten…
jonahgabriel Feb 11, 2026
98f4ffd
merge: resolve validation_exemptions.yaml conflict with main
jonahgabriel Feb 12, 2026
785625d
fix(review): address remaining PR #309 review feedback
jonahgabriel Feb 12, 2026
db759bd
fix(review): [major] thread leak shutdown, [minor] base_dir validatio…
jonahgabriel Feb 12, 2026
1e86e08
fix(review): address iteration 2 feedback — error types, test fix, gu…
jonahgabriel Feb 12, 2026
b5c12cb
fix(review): input validation guards, ReDoS timeout leak, GC clock skew
jonahgabriel Feb 12, 2026
f57665d
fix(review): file:// URL edge case, Unix-socket DSN fallback warning
jonahgabriel Feb 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/omnibase_infra/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@
ModelRoutingEntry,
ModelRoutingSubcontract,
)
from omnibase_infra.models.rrh import (
ModelRRHEnvironmentData,
ModelRRHProfile,
ModelRRHRepoState,
ModelRRHResult,
ModelRRHRuleSeverity,
ModelRRHRuntimeTarget,
ModelRRHToolchainVersions,
)
from omnibase_infra.models.runtime import ModelLoadedHandler
from omnibase_infra.models.security import (
ModelEnvironmentPolicy,
Expand Down Expand Up @@ -104,6 +113,14 @@
"ModelBackendResult",
# Resilience models
"ModelCircuitBreakerConfig",
# RRH models
"ModelRRHEnvironmentData",
"ModelRRHProfile",
"ModelRRHRepoState",
"ModelRRHResult",
"ModelRRHRuleSeverity",
"ModelRRHRuntimeTarget",
"ModelRRHToolchainVersions",
# Validation models
"ModelCoverageMetrics",
"ModelDispatchLogContext",
Expand Down
36 changes: 36 additions & 0 deletions src/omnibase_infra/models/rrh/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Release Readiness Handshake (RRH) shared models.

These models are shared across the three RRH nodes:

- ``node_rrh_emit_effect``: Collects environment data
- ``node_rrh_validate_compute``: Validates against rules and profiles
- ``node_rrh_storage_effect``: Writes result artifacts

The RRH result composes existing shared primitives
(``ModelRuleCheckResult``, ``EnumVerdict``) so dashboards can consume
both architecture-validation and RRH results uniformly.
"""

from omnibase_infra.models.rrh.model_rrh_environment_data import (
ModelRRHEnvironmentData,
)
from omnibase_infra.models.rrh.model_rrh_profile import ModelRRHProfile
from omnibase_infra.models.rrh.model_rrh_repo_state import ModelRRHRepoState
from omnibase_infra.models.rrh.model_rrh_result import ModelRRHResult
from omnibase_infra.models.rrh.model_rrh_rule_severity import ModelRRHRuleSeverity
from omnibase_infra.models.rrh.model_rrh_runtime_target import ModelRRHRuntimeTarget
from omnibase_infra.models.rrh.model_rrh_toolchain_versions import (
ModelRRHToolchainVersions,
)

__all__: list[str] = [
"ModelRRHEnvironmentData",
"ModelRRHProfile",
"ModelRRHRepoState",
"ModelRRHResult",
"ModelRRHRuleSeverity",
"ModelRRHRuntimeTarget",
"ModelRRHToolchainVersions",
]
43 changes: 43 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_environment_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Composite environment snapshot for RRH validation.

Composes three sub-models into a single snapshot that flows into the
validation compute node.
"""

from __future__ import annotations

from pydantic import AwareDatetime, BaseModel, ConfigDict, Field

from omnibase_infra.models.rrh.model_rrh_repo_state import ModelRRHRepoState
from omnibase_infra.models.rrh.model_rrh_runtime_target import ModelRRHRuntimeTarget
from omnibase_infra.models.rrh.model_rrh_toolchain_versions import (
ModelRRHToolchainVersions,
)


class ModelRRHEnvironmentData(BaseModel):
"""Complete environment snapshot for RRH validation.

Composed from the three sub-models collected by the emit effect node.
Flows into ``node_rrh_validate_compute`` as its primary input data.

Attributes:
repo_state: Git repository state.
runtime_target: Deployment target context.
toolchain: Build-tool versions.
collected_at: Timezone-aware timestamp of data collection.
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

repo_state: ModelRRHRepoState = Field(..., description="Git repo state.")
runtime_target: ModelRRHRuntimeTarget = Field(..., description="Deployment target.")
toolchain: ModelRRHToolchainVersions = Field(..., description="Tool versions.")
collected_at: AwareDatetime = Field(
..., description="Timezone-aware collection timestamp."
)


__all__: list[str] = ["ModelRRHEnvironmentData"]
53 changes: 53 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""RRH validation profile model.

A profile defines which rules are active and their severity. Profiles
set the *baseline* — contracts can only **tighten** (add rules or raise
severity), never loosen.

Profile Precedence:
PROFILE baseline -> CONTRACT can only TIGHTEN -> Final rule set
"""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field

from omnibase_infra.diagnostics.enum_verdict import EnumVerdict
from omnibase_infra.models.rrh.model_rrh_rule_severity import ModelRRHRuleSeverity


class ModelRRHProfile(BaseModel):
"""RRH validation profile.

Attributes:
name: Profile name (e.g. ``"default"``, ``"ticket-pipeline"``).
description: Human-readable profile description.
rules: Per-rule severity configuration.
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

name: str = Field(..., description="Profile name.")
description: str = Field(default="", description="Profile description.")
rules: tuple[ModelRRHRuleSeverity, ...] = Field(
default_factory=tuple, description="Per-rule configurations."
)

def is_rule_enabled(self, rule_id: str) -> bool:
"""Check if a rule is enabled in this profile."""
for rule in self.rules:
if rule.rule_id == rule_id:
return rule.enabled
return False

def get_severity(self, rule_id: str) -> EnumVerdict:
"""Get the severity for a rule. Defaults to FAIL if not found."""
for rule in self.rules:
if rule.rule_id == rule_id:
return rule.severity
return EnumVerdict.FAIL


__all__: list[str] = ["ModelRRHProfile"]
30 changes: 30 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_repo_state.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Git repository state snapshot for RRH validation."""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field


class ModelRRHRepoState(BaseModel):
"""Git repository state snapshot.

Attributes:
branch: Current checked-out branch name.
head_sha: Full SHA of HEAD commit.
is_dirty: Whether the working tree has uncommitted changes.
repo_root: Absolute path to repository root.
remote_url: Origin remote URL (empty string if no remote).
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

branch: str = Field(..., description="Current branch name.")
head_sha: str = Field(..., description="Full SHA of HEAD commit.")
is_dirty: bool = Field(..., description="Working tree has uncommitted changes.")
repo_root: str = Field(..., description="Absolute path to repo root.")
remote_url: str = Field(default="", description="Origin remote URL.")


__all__: list[str] = ["ModelRRHRepoState"]
135 changes: 135 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""RRH result model composing shared primitives.

``ModelRRHResult`` composes ``ModelRuleCheckResult`` (per-rule outcomes)
and ``EnumVerdict`` (aggregate verdict) so that dashboards can consume
both architecture-validation and RRH results through the same types.

Verdict Semantics:
PASS — all applicable checks passed
WARN — non-critical issues (e.g. missing optional toolchain)
FAIL — critical violation blocking release
"""

from __future__ import annotations

from typing import TYPE_CHECKING
from uuid import UUID, uuid4

from pydantic import AwareDatetime, BaseModel, ConfigDict, Field

from omnibase_infra.diagnostics.enum_verdict import EnumVerdict
from omnibase_infra.nodes.architecture_validator.models.model_rule_check_result import (
ModelRuleCheckResult,
)

if TYPE_CHECKING:
from omnibase_infra.models.rrh.model_rrh_rule_severity import ModelRRHRuleSeverity


class ModelRRHResult(BaseModel):
"""Aggregate RRH validation result.

Composes the same ``ModelRuleCheckResult`` and ``EnumVerdict`` types
used by the architecture validation pipeline so that dashboards and
downstream consumers can process both uniformly.

Attributes:
checks: Individual rule check results (RRH-1001 through RRH-1701).
verdict: Aggregate verdict derived from worst check outcome.
profile_name: Name of the profile used for this validation.
ticket_id: Ticket identifier this RRH was run for (empty if N/A).
repo_name: Repository name this RRH was run against.
correlation_id: Distributed tracing correlation ID.
evaluated_at: Timezone-aware timestamp when validation completed.
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

checks: tuple[ModelRuleCheckResult, ...] = Field(
..., description="Per-rule check results."
)
verdict: EnumVerdict = Field(..., description="Aggregate verdict.")
profile_name: str = Field(..., description="Profile used for validation.")
ticket_id: str = Field(default="", description="Ticket identifier.")
repo_name: str = Field(default="", description="Repository name.")
correlation_id: UUID = Field(
default_factory=uuid4, description="Correlation ID for tracing."
)
evaluated_at: AwareDatetime = Field(
..., description="Timezone-aware evaluation timestamp."
)

def __bool__(self) -> bool:
"""Allow boolean context: True when verdict is PASS.

Warning:
**Non-standard __bool__ behavior**: Returns ``True`` only when
``verdict`` is ``EnumVerdict.PASS``. Differs from typical
Pydantic behavior where any populated model is truthy.
"""
return self.verdict == EnumVerdict.PASS

@property
def failed_checks(self) -> tuple[ModelRuleCheckResult, ...]:
"""Return only checks that represent violations."""
return tuple(c for c in self.checks if c.is_violation())

@property
def applicable_checks(self) -> tuple[ModelRuleCheckResult, ...]:
"""Return only checks that were actually evaluated (not skipped)."""
return tuple(c for c in self.checks if c.is_applicable())

def warning_checks(
self,
effective_rules: dict[str, ModelRRHRuleSeverity],
) -> tuple[ModelRuleCheckResult, ...]:
"""Return violations whose configured severity is WARN.

Note:
``ModelRuleCheckResult`` does not carry per-check severity;
severity is a profile-level concept stored in
``ModelRRHRuleSeverity``. Callers must supply the effective
rules mapping produced by ``HandlerRRHValidate._apply_tightening``.

Args:
effective_rules: Rule-ID to severity mapping from the profile.

Returns:
Tuple of failed checks where the rule severity is ``WARN``.
"""
return tuple(
c
for c in self.checks
if c.is_violation()
and c.rule_id in effective_rules
and effective_rules[c.rule_id].severity == EnumVerdict.WARN
)

def error_checks(
self,
effective_rules: dict[str, ModelRRHRuleSeverity],
) -> tuple[ModelRuleCheckResult, ...]:
"""Return violations whose configured severity is FAIL.

Note:
See ``warning_checks`` for rationale on the *effective_rules*
parameter.

Args:
effective_rules: Rule-ID to severity mapping from the profile.

Returns:
Tuple of failed checks where the rule severity is ``FAIL``.
"""
return tuple(
c
for c in self.checks
if c.is_violation()
and c.rule_id in effective_rules
and effective_rules[c.rule_id].severity == EnumVerdict.FAIL
)


__all__: list[str] = ["ModelRRHResult"]
31 changes: 31 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_rule_severity.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Per-rule severity configuration for RRH profiles."""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field

from omnibase_infra.diagnostics.enum_verdict import EnumVerdict


class ModelRRHRuleSeverity(BaseModel):
"""Per-rule severity configuration.

Attributes:
rule_id: Rule identifier (e.g. ``"RRH-1001"``).
enabled: Whether the rule is active in this profile.
severity: Verdict level when the rule fails (WARN or FAIL).
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

rule_id: str = Field(..., description="Rule identifier.")
enabled: bool = Field(default=True, description="Whether the rule is active.")
severity: EnumVerdict = Field(
default=EnumVerdict.FAIL,
description="Verdict when rule fails (WARN or FAIL).",
)


__all__: list[str] = ["ModelRRHRuleSeverity"]
30 changes: 30 additions & 0 deletions src/omnibase_infra/models/rrh/model_rrh_runtime_target.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# SPDX-License-Identifier: MIT
# Copyright (c) 2025 OmniNode Team
"""Deployment target context for RRH validation."""

from __future__ import annotations

from pydantic import BaseModel, ConfigDict, Field


class ModelRRHRuntimeTarget(BaseModel):
"""Deployment target context.

Attributes:
environment: Target environment label (e.g. ``"dev"``, ``"staging"``).
kafka_broker: Kafka bootstrap server address (empty if N/A).
kubernetes_context: Active kubectl context (empty if N/A).
"""

model_config = ConfigDict(frozen=True, extra="forbid", from_attributes=True)

environment: str = Field(default="dev", description="Target environment label.")
kafka_broker: str = Field(
default="",
max_length=1024,
description="Kafka bootstrap server (max 1024 chars).",
)
kubernetes_context: str = Field(default="", description="Active kubectl context.")


__all__: list[str] = ["ModelRRHRuntimeTarget"]
Loading