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
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,7 @@ def resolve_uses_ref(
) -> ParsedWorkflow | None:
"""Resolve a job's `uses:` reference to a locally-parseable ParsedWorkflow,
or None if the reference points outside this repo (cross-repo reusable —
e.g. omnibase_core's occ-preflight.yml, onex_change_control's
pr-title-check-reusable.yml)."""
e.g. omniclaude's reject-deploy-gate-skip.yml)."""
local_match = _LOCAL_USES_RE.match(uses_ref)
if local_match:
return workflows.get(Path(local_match.group("path")).name)
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4966,11 +4966,11 @@ jobs:
|| fromJSON(vars.OMNI_PUBLIC_PR_RUNS_ON_JSON || '["ubuntu-latest"]')
}}
steps:
- uses: OmniNode-ai/omnibase_core/.github/actions/validate-boundaries@de3398d1fcf7a6f48451f680b74b1a6c6c383b8a # omnibase_core dev (OMN-20074 H/F)
- uses: OmniNode-ai/omnibase_core/.github/actions/validate-boundaries@c1f8e8fe0c513c0ac70ad666433a3ce1cec136c1 # omnibase_core dev (OMN-20074): #1972, no change-control boundary
with:
checks: "boundary-parity"
warn-only: "false"
repos: "omniclaude,omnidash,omniintelligence,omnibase_infra,omnibase_core,omnimemory,omnimarket,onex_change_control"
repos: "omniclaude,omnidash,omniintelligence,omnibase_infra,omnibase_core,omnimemory,omnimarket"

ci-summary:
name: CI Summary
Expand Down
6 changes: 1 addition & 5 deletions .github/workflows/dependency-cascade.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,10 @@
# to pick up the new version.
#
# Downstream mapping:
# omnibase_core -> omnibase_infra, omniintelligence, omnimemory, omniclaude, onex_change_control, omninode_infra
# omnibase_core -> omnibase_infra, omniintelligence, omnimemory, omniclaude, omninode_infra
# omnibase_spi -> omnibase_infra, omniintelligence, omnimemory, omniclaude
# omnibase_infra -> omniintelligence, omnimemory, omniclaude
#
# Note (OMN-9425): onex_change_control depends on omnibase-core only (not spi/infra);
# see onex_change_control/pyproject.toml. If ccc later adds spi or infra deps,
# extend the corresponding cases below.
#
# This workflow is reusable so that omnibase_core and omnibase_spi can also call
# it from their own release workflows.
name: Dependency Cascade
Expand Down
31 changes: 10 additions & 21 deletions .github/workflows/main-target-guard.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# SPDX-FileCopyrightText: 2026 OmniNode.ai Inc.
# SPDX-License-Identifier: MIT
#
# OMN-12243: Block PRs targeting main unless they are promotion PRs
# from dev or promotion/* with a promotion receipt.
# OMN-12477: Removed the hotfix/* bypass — main accepts only promotions.
# OMN-12243: Block PRs targeting main.
# OMN-12477: Removed the hotfix/* bypass.
# OMN-20074: Removed the promotion-receipt exception. main is release-synced:
# release.yml ("Sync main to release tag") fast-forwards it to the published
# tag and opens no pull request against it, so the change-control receipt the
# exception read admitted nothing the release path uses. Every PR onto main is
# refused. Pinned by tests/ci/test_main_target_guard_prepush_omn20780.py.

name: Main target guard

Expand Down Expand Up @@ -33,7 +37,6 @@ jobs:
env:
BASE_REF: ${{ github.event.pull_request.base.ref }}
HEAD_REF: ${{ github.event.pull_request.head.ref }}
PR_BODY: ${{ github.event.pull_request.body }}
run: |
set -euo pipefail

Expand All @@ -42,21 +45,7 @@ jobs:
exit 0
fi

echo "PR targets main. Checking head ref: '${HEAD_REF}'"

if [[ "${HEAD_REF}" == "dev" || "${HEAD_REF}" == promotion/* ]]; then
if echo "${PR_BODY}" | grep -qE 'promotion-receipt:[[:space:]]*OCC-[0-9]+'; then
echo "::notice::Promotion PR from '${HEAD_REF}' with valid promotion-receipt. Allowed."
exit 0
fi

echo "::error::Promotion PR from '${HEAD_REF}' is missing a promotion receipt."
echo "::error::Add a line matching: promotion-receipt: OCC-<number>"
echo "::error::Retarget this PR to dev; main accepts only promotion PRs."
exit 1
fi

echo "::error::PRs targeting main must come from dev or promotion/*."
echo "::error::Head ref '${HEAD_REF}' is not permitted to target main directly."
echo "::error::Retarget this PR to dev; main accepts only promotion PRs."
echo "::error::PR from '${HEAD_REF}' targets main, which is release-synced and never a pull-request target."
echo "::error::The release workflow moves main by fast-forwarding it to the published tag; it opens no PR against main."
echo "::error::Retarget this PR to dev."
exit 1
5 changes: 2 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -862,7 +862,7 @@ repos:
# Exclusions:
# - typed_dict_demo.py: sample_id and ticket_id are external corpus identifiers, not internal UUIDs (OMN-1396)
# - doctor_check_base.py: check_id is a semantic identifier ("kafka", "postgres"), not a version string
# - contracts/OMN-*.yaml: ticket-contract schema is owned by onex_change_control and currently requires string schema_version
# - contracts/OMN-*.yaml: the ticket-contract schema (omnibase_core ModelTicketContract) requires a string schema_version
- id: validate-string-versions
name: ONEX String Version Anti-Pattern Detection
entry: uv run python scripts/validation/validate-string-versions.py
Expand Down Expand Up @@ -1654,8 +1654,7 @@ repos:
# DOCUMENTATION files, executed as a COMPUTE node over the in-memory event
# bus (same two-transport seam as check-private-ip-compute; Kafka backend
# in CI). Generated + corpus-accepted (OMN-13569). Exemptions (OMN-13572):
# onex_change_control/ paths exempt from the OMN-<digits> rule only
# (local-env rules still apply); contracts/ excluded from the OMN rule; a
# contracts/ excluded from the OMN rule (local-env rules still apply); a
# SKILL.md `ticket: OMN-NNNN` frontmatter field is exempt. BLOCKING (no
# warn-only). Suppress a line with `doc-content-ok`; suppress a doc whose
# subject IS these traces with `doc-content-file-ok`. The runner's EFFECT
Expand Down
7 changes: 3 additions & 4 deletions .pre-commit-hooks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,9 @@
paths, ssh user@host, personal e-mail) and Linear OMN-<digits> ticket references in DOCUMENTATION
files (*.md / *.mdx / .rst / .txt / .adoc). The docs-facing union of CLAUDE.md Rule 6 and the knowledge-base
sanitizer. Generated + corpus-accepted COMPUTE validator (OMN-13569) executed over the in-memory event
bus (Kafka backend in CI). Exemptions (OMN-13572): onex_change_control/ paths are exempt from the
OMN-<digits> rule only (local-env rules still apply); contracts/ excluded from the OMN rule; a SKILL.md
`ticket: OMN-NNNN` frontmatter field is exempt. Suppress a line with `doc-content-ok`; suppress a
doc whose subject IS these traces with `doc-content-file-ok`.
bus (Kafka backend in CI). Exemptions (OMN-13572): contracts/ excluded from the OMN-<digits> rule
(local-env rules still apply); a SKILL.md `ticket: OMN-NNNN` frontmatter field is exempt. Suppress
a line with `doc-content-ok`; suppress a doc whose subject IS these traces with `doc-content-file-ok`.
language: python
entry: python -m omnibase_core.validation.doc_content_scan.runtime_doc_content_scan
types_or: [markdown, rst, text]
Expand Down
8 changes: 3 additions & 5 deletions architecture-handshakes/validator-requirements.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -621,12 +621,10 @@ required_validators:
private-IP / hardcoded-topic validators.

EXEMPTIONS (operator-set, OMN-13572):
* onex_change_control/ paths are exempt from the OMN-<digits> rule only —
the governance ledger legitimately cites ticket ids; the
local-environment rules (LAN IP / host / personal path / ssh / e-mail)
still apply there.
* contracts/ paths are excluded from the OMN-<digits> rule (contract
fixtures cite ticket ids).
fixtures cite ticket ids); the local-environment rules (LAN IP / host /
personal path / ssh / e-mail) still apply there. OMN-20074 removed the
change-control repository's tree from the exemption.
* a SKILL.md YAML-frontmatter field `ticket: OMN-NNNN` is exempt (a
machine-readable skill→ticket binding, not a leaked prose reference).
Suppress a line with `doc-content-ok`; suppress a doc whose subject IS these
Expand Down
68 changes: 68 additions & 0 deletions contracts/OMN-20074.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,26 @@ requirements:
and the reviewed #1972 action with seven repositories; missing peers, mismatched lists, unknown
actions and duplicate peers fail -- falsifier: uv run pytest tests/unit/validation/test_ci_workflow_shape.py
-q --no-cov -o addopts= -p no:randomly -k boundary_repo_contract'
- id: req-omn20074-core-residual-callers
statement: omnibase_core's boundary-validation job must not clone onex_change_control, and the main
target guard must not admit a pull request on a change-control promotion receipt; main is moved
only by the release workflow's fast-forward.
acceptance:
- id: AC52
statement: 'AC52: the boundary-validation job pins validate-boundaries at the omnibase_core#1972
merge and its repos input names no onex_change_control repository -- falsifier: uv run pytest
tests/ci/test_validate_boundaries_caller_omn20962.py -q --no-cov -p no:randomly fails at the
merge base'
- id: AC53
statement: 'AC53: main-target-guard refuses every pull request onto main, a dev or promotion/*
head carrying a promotion-receipt line included, and reads no change-control receipt, while
a pull request onto dev is admitted -- falsifier: uv run pytest tests/ci/test_main_target_guard_prepush_omn20780.py
-q --no-cov -p no:randomly fails at the merge base'
- id: AC54
statement: 'AC54: the doc-content scan exempts OMN ticket references under contracts/ only, so
a ticket reference under an onex_change_control/ path is flagged and the local-environment rules
still apply under contracts/ -- falsifier: uv run pytest tests/unit/validation/doc_content_scan/test_handler_doc_content_scan_compute.py
-q --no-cov -p no:randomly fails at the merge base'
evidence_requirements:
- kind: tests
description: The workflow test asserts that verify has no job-level condition and that enforcing caller
Expand Down Expand Up @@ -569,6 +589,18 @@ evidence_requirements:
step must match the exact repository list audited for its action revision. No runtime service changes.
command: uv run pytest tests/unit/validation/test_ci_workflow_shape.py -q --no-cov -o addopts= -p
no:randomly -k test_cross_repo_boundary_validation_clones_all_boundary_repos
- kind: tests
description: The boundary-validation caller test finds the omnibase_core#1972 action pin and a repos
input with no change-control repository; the main-target-guard test runs the shipped step and finds
a promotion PR onto main refused whatever its body, with a PR onto dev admitted as the negative
control.
command: uv run pytest tests/ci/test_validate_boundaries_caller_omn20962.py tests/ci/test_main_target_guard_prepush_omn20780.py
-q --no-cov -p no:randomly
- kind: tests
description: The doc-content scan tests find a ticket reference under an onex_change_control/ path
flagged and the contracts/ exemption kept, with the local-environment rules applied under contracts/.
command: uv run pytest tests/unit/validation/doc_content_scan/test_handler_doc_content_scan_compute.py
-q --no-cov -p no:randomly
emergency_bypass:
enabled: false
justification: ''
Expand Down Expand Up @@ -1012,3 +1044,39 @@ dod_evidence:
check_value: uv run pytest tests/unit/validation/test_ci_workflow_shape.py -q --no-cov -o addopts=
-p no:randomly -k test_cross_repo_boundary_validation_clones_all_boundary_repos
cwd: ${OMNI_HOME}/omnibase_core
- id: dod-omn-20074-ac52
description: The caller test reads the parsed ci.yml and finds the validate-boundaries step pinned
at the omnibase_core#1972 merge with a repos input that names no change-control repository.
source: manual
execution_scope: hosted_and_local
checks:
- check_type: test_passes
check_value: uv run pytest tests/ci/test_validate_boundaries_caller_omn20962.py -q --no-cov -p
no:randomly
cwd: ${OMNI_HOME}/omnibase_core
binds_ac:
- AC52
- id: dod-omn-20074-ac53
description: The guard test runs the shipped main-target-guard step and finds every PR onto main refused,
a promotion-receipt body included, and a PR onto dev admitted.
source: manual
execution_scope: hosted_and_local
checks:
- check_type: test_passes
check_value: uv run pytest tests/ci/test_main_target_guard_prepush_omn20780.py -q --no-cov -p
no:randomly
cwd: ${OMNI_HOME}/omnibase_core
binds_ac:
- AC53
- id: dod-omn-20074-ac54
description: The doc-content scan test finds a ticket reference under an onex_change_control/ path
flagged, ticket references under contracts/ exempt, and a LAN IP under contracts/ flagged.
source: manual
execution_scope: hosted_and_local
checks:
- check_type: test_passes
check_value: uv run pytest tests/unit/validation/doc_content_scan/test_handler_doc_content_scan_compute.py
-q --no-cov -p no:randomly
cwd: ${OMNI_HOME}/omnibase_core
binds_ac:
- AC54
1 change: 0 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ ignore = [
"scripts/check_dep_provenance.py" = ["T201"] # CLI output for dep-provenance gate (OMN-13873/OMN-13877)
"scripts/ci/check_import_ratchet.py" = ["T201"] # CLI output for import-layering growth-ratchet gate (OMN-14340)
"scripts/ci/check_occ_companion_merged.py" = ["T201"] # CLI verdict/annotation output for the OCC companion-merged gate (OMN-15222)
"scripts/ci/occ_preflight_wait.py" = ["T201"] # CLI verdict/annotation output for the occ-preflight bounded wait (OMN-17864)
"scripts/ci/canonical_handler_shape.py" = ["T201", "BLE001"] # CLI output + fail-closed catches for canonical handler-shape ratchet gate (OMN-14355)
"scripts/ci/rsd_provenance_stamp.py" = ["T201"] # CLI output for RSD provenance-stamp gate (OMN-15011)
"scripts/hooks/prepush_override_grant.py" = ["T201"] # CLI output for the single-use pre-push override grant (OMN-16480, ported by OMN-17159)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
user@host`` lines, personal e-mail) or Linear ticket references (``OMN-<digits>``),
except where exempt (``localhost`` / loopback / RFC5737 doc IPs / ``example.com`` /
portable env-var forms; ``doc-content-ok`` / ``doc-content-file-ok`` suppression;
``OMN-<digits>`` under ``onex_change_control/`` or ``contracts/``).
``OMN-<digits>`` under ``contracts/``).

Architecture (§1A — validator = COMPUTE node over a swappable bus), mirroring the
private-IP validator:
Expand Down
19 changes: 10 additions & 9 deletions src/omnibase_core/validation/doc_content_scan/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
emits at most one finding per (line, class) in a stable source order so the
verdict is order-independent regardless of dispatch backend (§1A).
* Added the PATH-based ``OMN-<digits>`` exemptions the corpus (text-only) could not
express: a file under ``onex_change_control/`` or ``contracts/`` keeps its ticket
references (governance ledgers + contract fixtures legitimately cite OMN ids),
express: a file under ``contracts/`` keeps its ticket
references (contract fixtures legitimately cite OMN ids),
but the local-environment rules (LAN IP / host shorthand / personal path / ssh /
e-mail) still apply everywhere. This is a pure decision over the ``path`` LABEL
string — the handler never opens the path.
Expand Down Expand Up @@ -135,11 +135,12 @@
# before any line-marker check (the file marker also contains "doc-content-ok").
_FILE_SUPPRESSION_MARKER: Final[str] = "doc-content-file-ok"

# Path prefixes under which an ``OMN-<digits>`` ticket reference is EXEMPT: the
# governance ledger repo and contract-fixture trees legitimately cite ticket ids.
# The local-environment rules still apply under these paths. Matched as a path
# segment so a substring elsewhere does not accidentally exempt.
_TICKET_EXEMPT_SEGMENTS: Final[tuple[str, ...]] = ("onex_change_control", "contracts")
# Path prefixes under which an ``OMN-<digits>`` ticket reference is EXEMPT:
# contract-fixture trees legitimately cite ticket ids. The local-environment
# rules still apply under these paths. Matched as a path segment so a substring
# elsewhere does not accidentally exempt. OMN-20074 removed the change-control
# repository's tree: that repository is retired and no tracked path sits under it.
_TICKET_EXEMPT_SEGMENTS: Final[tuple[str, ...]] = ("contracts",)


def _lan_ip_match(o1: int, o2: int, o3: int, o4: int) -> bool:
Expand Down Expand Up @@ -183,8 +184,8 @@ def scan_source(content: str, path: str = "<input>") -> ModelDocContentScanResul

Pure and deterministic. A line containing ``doc-content-ok`` is skipped; a file
containing ``doc-content-file-ok`` is suppressed entirely. ``OMN-<digits>``
references are skipped when ``path`` is under ``onex_change_control/`` or
``contracts/`` (the local-environment rules still apply there). Findings are
references are skipped when ``path`` is under ``contracts/`` (the
local-environment rules still apply there). Findings are
emitted in a stable order (line, then class order, then column) so the verdict
is order-independent regardless of dispatch backend (§1A).
"""
Expand Down
4 changes: 2 additions & 2 deletions src/omnibase_core/validation/doc_content_scan/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class ModelDocContentScanInput(BaseModel):
``content`` is the raw file text; ``path`` is the file's path. ``path`` is used
for two pure decisions only — selecting the docs-only glob is the EFFECT
boundary's job, but the path also drives the ``OMN-<digits>`` exemptions
(files under ``onex_change_control/`` or ``contracts/`` keep ticket refs) — and
(files under ``contracts/`` keep ticket refs) — and
to label findings. It is a plain label string, not a filesystem handle; the
handler never opens it.
"""
Expand All @@ -58,7 +58,7 @@ class ModelDocContentScanInput(BaseModel):
default="<input>",
description=(
"Label for the source (e.g. file path) used in findings AND for the "
"OMN-<digits> path exemptions (onex_change_control/ and contracts/)"
"OMN-<digits> path exemption (contracts/)"
),
)

Expand Down
26 changes: 24 additions & 2 deletions tests/ci/test_main_target_guard_prepush_omn20780.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,15 @@ def _guard_program() -> str:
return str(named[0]["run"])


def _run_guard(base: str, head: str) -> subprocess.CompletedProcess[str]:
def _run_guard(
base: str, head: str, body: str = ""
) -> subprocess.CompletedProcess[str]:
"""Run the guard the way Actions does: ``bash -e`` over the step script."""
env = {
"PATH": os.defpath,
"BASE_REF": base,
"HEAD_REF": head,
"PR_BODY": "",
"PR_BODY": body,
}
return subprocess.run(
["bash", "-e", "-c", _guard_program()],
Expand All @@ -78,6 +80,26 @@ def test_a_feature_pr_onto_main_is_refused() -> None:
assert "dev" in result.stdout, "the refusal must name dev as the base to use"


@pytest.mark.parametrize("head", ["dev", "promotion/v0.1.0"])
def test_a_promotion_pr_onto_main_is_refused_whatever_its_body(head: str) -> None:
"""OMN-20074: no change-control promotion receipt admits a PR onto main.

release.yml moves main by fast-forwarding it to the release tag and opens no
pull request against it, so the receipt exception admitted nothing the
release path uses and named a retired repository's numbering.
"""
result = _run_guard("main", head, "promotion-receipt: OCC-123\n")
assert result.returncode != 0, f"{head} onto main was admitted:\n{result.stdout}"
assert "::error::" in result.stdout
assert "OCC-" not in result.stdout, "the refusal must not ask for a receipt"


def test_the_guard_reads_no_change_control_receipt() -> None:
program = _guard_program()
assert "promotion-receipt" not in program
assert "OCC-" not in program


def test_a_feature_pr_onto_dev_is_admitted() -> None:
"""The negative control: a guard that refused everything would fail here."""
result = _run_guard("dev", "feature/OMN-1-thing")
Expand Down
Loading
Loading