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
23 changes: 23 additions & 0 deletions docker/Dockerfile.runtime
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,29 @@ COPY --from=builder --chown=omniinfra:omniinfra /app/build-provenance.json /app/
COPY --chown=omniinfra:omniinfra docker/entrypoint-runtime.sh /app/entrypoint-runtime.sh
RUN chmod +x /app/entrypoint-runtime.sh

# OMN-16026: Keycloak realm reconciler, invoked as a batch Job -- NOT by the
# runtime kernel. omninode_infra's k8s/onex-dev/jobs/seed-keycloak-clients-job.yaml
# runs `python scripts/seed-keycloak-clients.py` with workingDir /app against
# this same digest-pinned image, which is why the file has to live here rather
# than only in the build context.
#
# Until this COPY existed the Job could not run at all: the `runtime` stage
# carried no `scripts/` directory, so every execution died on
# "python: can't open file '/app/scripts/seed-keycloak-clients.py'" (observed
# live on onex-dev 2026-08-13). The earlier attempt to close this,
# omnibase_infra#2661, was closed without merging, and the stale ordering note
# in that Job manifest kept pointing at it.
#
# Copied as a plain file rather than exposed via `python -m`, for the same
# reason as onex-container-healthcheck above: the module imports nothing but
# the standard library (argparse/json/os/subprocess/sys/urllib/pathlib), so
# running it directly avoids the multi-second omnibase_infra package import.
# tests/unit/scripts/test_seed_keycloak_clients_stdlib_only.py pins the
# stdlib-only property so this stays true.
COPY --chown=omniinfra:omniinfra \
scripts/seed-keycloak-clients.py \
/app/scripts/seed-keycloak-clients.py

# OMN-15217: semantic container healthcheck, installed at a stable path.
# Same file as omnibase_infra/runtime/health/container_healthcheck.py — copied
# rather than invoked via `python -m` on purpose: importing the omnibase_infra
Expand Down
88 changes: 88 additions & 0 deletions tests/unit/scripts/test_seed_keycloak_clients_stdlib_only.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# SPDX-FileCopyrightText: 2025 OmniNode.ai Inc.
# SPDX-License-Identifier: MIT
"""Deployment-seam pins for the Keycloak realm reconciler (OMN-16026).

``scripts/seed-keycloak-clients.py`` is invoked as a batch Job -- omninode_infra's
``k8s/onex-dev/jobs/seed-keycloak-clients-job.yaml`` runs
``python scripts/seed-keycloak-clients.py`` with ``workingDir: /app`` against the
digest-pinned ``omninode-runtime`` image.

Two properties have to hold for that to work, and both were violated in
production simultaneously on 2026-08-13:

1. The file must be present in the runtime image at ``/app/scripts/``. It was
not -- the ``runtime`` stage of ``docker/Dockerfile.runtime`` had no ``COPY``
of ``scripts/`` at all, so every Job run died with
``python: can't open file '/app/scripts/seed-keycloak-clients.py'``. The
earlier fix attempt (omnibase_infra#2661) was closed without merging.
2. The module must stay import-cheap. It is run as a plain file, not via
``python -m``, precisely so it does not pay the ``omnibase_infra`` package
import cost -- the same reasoning as ``onex-container-healthcheck``.

Both are pinned here rather than left as comments, because a comment did not
stop (1) from regressing for months.

Related Tickets:
- OMN-16026: seed-keycloak-clients Job cannot run -- script absent from image
"""

from __future__ import annotations

import ast
import sys
from pathlib import Path

import pytest

REPO_ROOT = Path(__file__).resolve().parents[3]
SEED_SCRIPT = REPO_ROOT / "scripts" / "seed-keycloak-clients.py"
DOCKERFILE = REPO_ROOT / "docker" / "Dockerfile.runtime"

#: The path the omninode_infra Job's ``command``/``workingDir`` pair resolves to.
INVOKED_PATH = "/app/scripts/seed-keycloak-clients.py"


@pytest.mark.unit
class TestSeedKeycloakClientsDeploymentSeam:
"""Pins that keep the reconciler runnable where it is actually invoked."""

def test_script_exists(self) -> None:
assert SEED_SCRIPT.is_file(), f"missing reconciler at {SEED_SCRIPT}"

def test_module_imports_only_the_standard_library(self) -> None:
"""Kept stdlib-only so the Job can run it as a plain file.

The Dockerfile copies this to a bare path instead of relying on
``python -m omnibase_infra...`` for the documented import-cost reason.
A single first-party import would silently invalidate that choice.
"""
tree = ast.parse(SEED_SCRIPT.read_text(encoding="utf-8"))

imported: set[str] = set()
for node in ast.walk(tree):
if isinstance(node, ast.Import):
imported.update(alias.name.split(".")[0] for alias in node.names)
elif isinstance(node, ast.ImportFrom) and node.module and node.level == 0:
imported.add(node.module.split(".")[0])

non_stdlib = {
name
for name in imported
if name not in sys.stdlib_module_names and name != "__future__"
}
assert non_stdlib == set(), (
"seed-keycloak-clients.py must stay stdlib-only (it is run as a "
f"plain file by the onex-dev Job); found {sorted(non_stdlib)}"
)

def test_dockerfile_installs_the_script_at_the_invoked_path(self) -> None:
"""The regression guard for OMN-16026.

Without this COPY the Job fails at exec time, not build time, so
nothing in CI notices -- which is exactly how it stayed broken.
"""
dockerfile = DOCKERFILE.read_text(encoding="utf-8")
assert INVOKED_PATH in dockerfile, (
f"{DOCKERFILE.name} must COPY the reconciler to {INVOKED_PATH}; the "
"onex-dev seed Job execs that literal path against this image."
)
Loading