Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions src/omnimarket/nodes/node_pipeline_audit_orchestrator/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc.
# SPDX-License-Identifier: MIT
"""Named constants for node_pipeline_audit_orchestrator [OMN-13693].

Topic-namespace prefixes are declared here so handler code never contains
bare string literals that could silently diverge from the platform convention.
"""

from __future__ import annotations

#: Prefix shared by all dead-letter queue topics in the ONEX platform.
#: Topics matching this prefix are excluded from "produced but no consumer"
#: findings because DLQ consumers are optional by design.
DLQ_TOPIC_PREFIX: str = "onex.dlq."
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@

import yaml

from omnimarket.nodes.node_pipeline_audit_orchestrator.constants import (
DLQ_TOPIC_PREFIX,
)
from omnimarket.nodes.node_pipeline_audit_orchestrator.models.model_pipeline_audit_request import (
EnumAuditType,
ModelPipelineAuditRequest,
Expand Down Expand Up @@ -347,7 +350,7 @@ def _topic_findings(
}
findings: list[ModelGapFinding] = []
for topic, repo in sorted(produced.items()):
if topic not in consumed and not topic.startswith("onex.dlq."):
if topic not in consumed and not topic.startswith(DLQ_TOPIC_PREFIX):
findings.append(
_finding(
EnumFindingSeverity.HIGH,
Expand Down
77 changes: 77 additions & 0 deletions tests/test_golden_chain_pipeline_audit_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,83 @@ def test_pipeline_audit_orchestrator_skip_ticket_creation_is_read_only(
assert result.tickets_created == ()


# ---------------------------------------------------------------------------
# OMN-13693: DLQ topic prefix must be a named constant, not a string literal
# ---------------------------------------------------------------------------


@pytest.mark.unit
def test_dlq_topic_prefix_constant_is_importable() -> None:
"""DLQ_TOPIC_PREFIX must exist in the node constants module (OMN-13693)."""
from omnimarket.nodes.node_pipeline_audit_orchestrator.constants import (
DLQ_TOPIC_PREFIX,
)

assert DLQ_TOPIC_PREFIX == "onex.dlq."


@pytest.mark.unit
def test_dlq_topics_excluded_from_no_consumer_finding(tmp_path: Path) -> None:
"""Topics matching DLQ_TOPIC_PREFIX must not trigger a 'no consumer' finding."""
_write_repo(
tmp_path,
"dlq_producer",
contract_yaml="""
name: node_dlq_producer
event_bus:
publish_topics:
- onex.dlq.sample.failed.v1
subscribe_topics: []
""",
source="pass\n",
)

result = HandlerPipelineAuditOrchestrator().handle(
ModelPipelineAuditRequest(
repos=("dlq_producer",),
audit_type=EnumAuditType.TOPICS,
dry_run=True,
omni_home_path=str(tmp_path),
)
)

# DLQ topics must be suppressed — zero findings expected
topic_findings = [
f
for f in result.gap_register
if f.proof_category == EnumProofCategory.WIRE_TOPICS
and "no audited consumer" in (f.description or "")
and "onex.dlq." in (f.evidence or "")
]
assert topic_findings == [], (
"DLQ topics must not appear in 'produced but no consumer' findings"
)


@pytest.mark.unit
def test_handler_source_has_no_literal_dlq_string() -> None:
"""Guard against regression: handler source must not contain the bare string literal."""
handler_path = (
Path(__file__).resolve().parents[1]
/ "src"
/ "omnimarket"
/ "nodes"
/ "node_pipeline_audit_orchestrator"
/ "handlers"
/ "handler_pipeline_audit_orchestrator.py"
)
source = handler_path.read_text(encoding="utf-8")
# The constant name is allowed; the raw literal in a startswith call is not.
assert '"onex.dlq."' not in source, (
"handler_pipeline_audit_orchestrator.py must not contain the raw "
"DLQ topic prefix as a double-quoted string literal — use DLQ_TOPIC_PREFIX from constants"
)
assert "'onex.dlq.'" not in source, (
"handler_pipeline_audit_orchestrator.py must not contain the raw "
"DLQ topic prefix as a single-quoted string literal — use DLQ_TOPIC_PREFIX from constants"
)


def _write_repo(
root: Path,
name: str,
Expand Down
Loading