Skip to content

feat(OMN-15521): sanctioned .201 gateway-forwarder deploy path - #2611

Merged
jonahgabriel merged 2 commits into
devfrom
jonah/omn-15521-build-lane
Aug 1, 2026
Merged

jonahgabriel merged 2 commits into
devfrom
jonah/omn-15521-build-lane

Conversation

@jonahgabriel

@jonahgabriel jonahgabriel commented Aug 1, 2026 •

Copy link
Copy Markdown
Collaborator

OMN-15521 — The .201 gateway-forwarder lane has no sanctioned deploy path

Closes the repo-side + live-deploy gap described in OMN-15521: omninode-gateway
(the .201 operator-edge forwarder bridging cloud MSK → local Redpanda for
cloud→local inference, per operator ruling 2026-08-01T17:20Z — "what we are
trying to do is connect our cloud architecture to our 201 box so that we can
use local inference") was hand-deployed on 2026-07-29 by copying files into a
root-owned /opt/omninode/gateway, was outside deploy-runtime.sh's
-p omnibase-infra scope, carried no org.opencontainers.image.revision
label, and had no recorded rollback target.

What this adds

  • scripts/deploy-gateway.sh — builds the gateway-forwarder image from this
    repo checkout with the same OCI provenance build-args every
    omnibase-infra runtime container gets, pins the running container to the
    resulting image digest (never :latest — the existing systemd unit's
    ExecStartPre already hard-asserts a real sha256:<64 hex>), syncs the
    host compose files from this checkout (replacing the 2026-07-29 hand-copy
    as the source of truth), and records a rollback target via a
    registry.json mirroring the omnibase-infra lane's own convention.
  • docs/runbooks/gateway-lane-deploy.md — procedure + rollback runbook
    alongside docs/runbooks/cold-lane-full-bringup.md.
  • tests/scripts/test_deploy_gateway.py — 16 subprocess-driven tests against
    the real script (fake docker/sudo, matching the existing
    test_deploy_runtime_promotion_class.py convention), RED-before/GREEN-after
    per acceptance criterion.

Seam definition

Fields/paths this change reads or writes across a boundary:

Seam Direction Shape
docker/docker-compose.gateway.yml build-args script → docker compose build VCS_REF, RUNTIME_VERSION, BUILD_DATE, COMPOSE_PROJECT=omninode-gateway, RUNTIME_SOURCE_HASH, BUILD_SOURCE/EXPECTED_BUILD_SOURCE (release), PROMOTION_CLASS (clean-main), NON_MAIN_LINEAGE (false) — same names deploy-runtime.sh's build_images() passes
Built image OCI labels docker image inspect --format='{{.Id}}' → script sha256:<64 hex> digest, read from org.opencontainers.image.revision/com.omninode.build_source on readback
/etc/omninode/gateway/gateway.env script writes GATEWAY_IMAGE= line rewritten to the new digest; every other key (GATEWAY_AWS_*, GATEWAY_TPM_*, GATEWAY_CONTAINER_*) preserved untouched, sourced by the script for compose interpolation
/opt/omninode/gateway/{docker-compose.gateway.yml,gateway/beta-gateway-canary.yaml} script writes (sudo install -m 0444 -o root -g root) byte-identical copy of the repo files at deploy time
~/.omnibase/gateway/registry.json script writes active_version, git_sha, active_digest, previous_digest, deployed_at, compose_project, gateway_env_file, host_compose_file, rollback_command
onex-gateway-forwarder systemd unit script → sudo systemctl reload unchanged unit file; reload picks up the new gateway.env digest via its existing ExecReload
docker exec omninode-gateway-forwarder script reads (verify) ls .../nodes/node_bus_forwarder_effect/services/service_gateway_delivery.py, ls .../idempotency/store_sqlite.py

Acceptance-criterion → test map

AC Proof
AC1 (repo-resident deploy path, no hand-copy) test_script_exists_and_is_executable, test_runbook_exists_alongside_cold_lane_bringup, test_print_compose_cmd_targets_repo_resident_compose_project (asserts -p omninode-gateway -f docker/docker-compose.gateway.yml, refutes any /opt/omninode/gateway literal), test_dry_run_default_performs_no_mutation, test_execute_without_env_file_fails_closed
AC2 (non-empty image.revision/build_source) test_build_command_stamps_oci_provenance_build_args, test_current_compose_file_declares_no_provenance_build_args (RED-before control: the compose file's own build.args block never carried these — matches the ticket's rev=(empty) finding), test_execute_deploy_produces_non_empty_image_labels
AC3 (the two OMN-12912 files present) test_verify_deployment_red_before_files_absent (RED) / test_verify_deployment_green_after_files_present (GREEN) — mechanism-level proof against a fake docker exec; live proof also captured this session (see below)
AC4 (host compose file matches merged dev) test_sync_host_files_red_before_stale_copy_diverges (RED) / test_sync_host_files_green_after_diff_is_empty (GREEN, asserts byte-identical compose + canary yaml)
AC5 (OMN-12912 restart/redelivery receipt) Out of scope per the ticket text — lands on OMN-12912, not here
AC6 (rollback target via registry.json) test_execute_deploy_writes_registry_with_rollback_target, test_second_deploy_records_previous_digest_as_first_deploys_active (rollback chains correctly across deploys), test_skip_reload_leaves_container_on_previous_digest

Live execution against .201 this session (ACs 2/3/4/6, real box)

Ran scripts/deploy-gateway.sh --execute against the canonical omnibase_infra
clone on .201 (beebd1d636b9, ancestor of merged dev, includes #2556):

image=sha256:972321bea3ee... rev=beebd1d636b9 src=release project=omninode-gateway   # AC2
ls .../node_bus_forwarder_effect/services/ -> service_gateway_delivery.py present    # AC3
ls .../idempotency/ -> store_sqlite.py present                                       # AC3
diff /opt/omninode/gateway/docker-compose.gateway.yml docker/docker-compose.gateway.yml  -> empty  # AC4
~/.omnibase/gateway/registry.json: active_digest/previous_digest/rollback_command recorded  # AC6
docker inspect omninode-gateway-forwarder --format Health.Status -> healthy

Out-of-band finding, filed separately, not folded into this PR's scope:
restarting the container surfaced a genuinely pre-existing, unrelated defect —
the local .201 broker had never provisioned
onex.evt.omnibase-infra.gateway-heartbeat.v1 (a topic
node_bus_forwarder_effect/contract.yaml has declared since before #2556;
confirmed via git show 2375c25a4 touching neither the topic list nor
mirror_topic_set). Masked for 3 days because the hand-built container was
never restarted. Applied a one-off rpk topic create stopgap to reach a
genuinely healthy container and prove the ACs live; filed OMN-15629 for
the durable fix (provisioning should be repo-resident and contract-driven,
not a manual rpk command).

Notes

  • A second commit (f91527bc23) fixes a readarray/local -n (bash 4+)
    portability bug in this script itself — macOS ships /bin/bash 3.2 (no
    readarray, no namerefs), and the governed pre-push selector invokes this
    script under plain bash. Rewrote both call sites as inlined
    while-read-into-array loops (bash-3.2-portable, matching
    deploy-runtime.sh's own convention of avoiding bash-4-only constructs).
  • Gates + push ran on stickybeatz-studio (.200) via patch-transfer with
    sha256 verification of every changed file (gates_host=.200). Pre-push
    governed selector: scripts/tests/ tests/scripts/ tests/unit/scripts/,
    1535 passed / 5 skipped (skips are pre-existing, GNU-realpath/opt-in-fence
    platform gates unrelated to this change).
  • Never merges — Codex merge sweep owns landing this.

Evidence-Source: 7b43c030ae0281c9a6d9dc5f863817546b739486
Evidence-Ticket: OMN-15521

- scripts/deploy-gateway.sh: builds the omninode-gateway forwarder image
  from this repo checkout with the same OCI provenance build-args every
  omnibase-infra runtime container gets (VCS_REF, RUNTIME_VERSION,
  BUILD_DATE, COMPOSE_PROJECT, RUNTIME_SOURCE_HASH, PROMOTION_CLASS,
  NON_MAIN_LINEAGE), pins the running container to the resulting image
  digest, syncs the host compose files from this checkout (replacing the
  2026-07-29 hand-copy), and records a rollback target via a registry.json
  mirroring the omnibase-infra lanes own convention.
- docs/runbooks/gateway-lane-deploy.md: procedure + rollback runbook
  alongside docs/runbooks/cold-lane-full-bringup.md.
- tests/scripts/test_deploy_gateway.py: subprocess-driven RED-before/
  GREEN-after coverage against the real script (fake docker/sudo), one
  case per OMN-15521 acceptance criterion (AC1/2/3/4/6; AC5 is explicitly
  out of scope, it lands on OMN-12912).
macOS ships /bin/bash 3.2.57 (Apple has not updated past 3.2 since bash
moved to GPLv3) with no readarray/mapfile (bash 4+) and no local -n
namerefs (bash 4.3+). The pre-push governed-selector hook invokes this
script under plain bash, which resolves /bin/bash 3.2 in that non-
interactive shell -- readarray failed there even though it silently
worked under a newer bash picked up by an interactive PATH. Replaced
with an inlined while-read-into-array loop at each of the two call
sites, matching the rest of scripts/ (deploy-runtime.sh and siblings
use no bash-4-only constructs). Re-verified: /bin/bash -n syntax check,
a live /bin/bash --print-compose-cmd run, and the full governed-selector
scope (scripts/tests/ tests/scripts/ tests/unit/scripts/, 1535 passed /
5 skipped) all green on this host.
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 2 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2ca02727-826a-4f69-ba7d-8732fb930c78

📥 Commits

Reviewing files that changed from the base of the PR and between 3064309 and f91527b.

📒 Files selected for processing (3)
  • docs/runbooks/gateway-lane-deploy.md
  • scripts/deploy-gateway.sh
  • tests/scripts/test_deploy_gateway.py

Comment @coderabbitai help to get the list of available commands.

jonahgabriel pushed a commit to OmniNode-ai/onex_change_control that referenced this pull request Aug 1, 2026
#5862)

* evidence: OCC companion pass 1 for OmniNode-ai/omnibase_infra#2611

* evidence: OCC companion self-bind for #5862

---------

Co-authored-by: node-occ-companion-effect <occ-companion-effect@omninode.ai>
@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

⚠️ Hostile Reviewer — DEGRADED (informational)

Blocking findings (critical): 0
Total findings: 0
Models succeeded: none

Note: All reviewer models failed or were unavailable. Degraded results are informational during the pilot phase (OMN-8468/OMN-8524) and do not block merge. Error: all review endpoints [192.168.86.201:8000 192.168.86.201:8001 ] unreachable — preflight short-circuit (no models available)


Gate semantics (pilot phase)

Verdict Meaning Blocks merge?
passed No critical findings No
blocked CRITICAL findings found Yes
degraded All models unavailable (infra) No (pilot)

Powered by omniintelligence.review_pairing.cli_review — node-based adversarial review via HandlerLlmCliSubprocess (OMN-8468/OMN-8524)

@jonahgabriel
jonahgabriel merged commit 6644803 into dev Aug 1, 2026
144 of 153 checks passed
@jonahgabriel
jonahgabriel deleted the jonah/omn-15521-build-lane branch August 1, 2026 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant