Skip to content

Run Ymir agent containers with catatonit as PID 1 - #867

Open
opohorel wants to merge 1 commit into
packit:mainfrom
opohorel:catatonit
Open

opohorel wants to merge 1 commit into
packit:mainfrom
opohorel:catatonit

Conversation

@opohorel

@opohorel opohorel commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Install catatonit in both agent images and preserve the image entrypoint in OpenShift deployments. Add static CI checks for image and deployment startup configuration, with local runtime checks for orphan reaping, signal forwarding, exit codes, non-root execution, and agent module imports. Reject commented or overridden init entrypoints and empty deployment discovery. Document the persistent-worker decision.

Assisted-by: Codex (GPT-6)

@qodo-for-packit

Copy link
Copy Markdown

PR Summary by Qodo

Run Ymir agent containers with catatonit as PID 1

✨ Enhancement 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Install catatonit in both agent images to forward signals and reap orphaned processes.
• Preserve image entrypoints across OpenShift agent deployments while retaining persistent workers.
• Add CI configuration checks, local runtime probes, and startup documentation.
Diagram

graph TD
  D["OpenShift args"] --> I["Agent image"] --> C["Catatonit PID 1"] --> W["Python worker"] --> P["Child processes"]
  T["CI static check"] -. validates .-> D
  T -. validates .-> I
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Inject an init through the container runtime
  • ➕ Could avoid adding catatonit to both images.
  • ➖ Would depend on each deployment environment providing and consistently enabling an init process.
  • ➖ Would not make the image's startup behavior self-contained.

Recommendation: Keep catatonit in the images and pass the agent invocation through deployment args. This gives local containers and OpenShift the same explicit startup behavior without changing the persistent-worker model.

Files changed (18) +284 / -28

Enhancement (2) +14 / -0
Containerfile.c10sAdd catatonit entrypoint to the c10s agent image +7/-0

Add catatonit entrypoint to the c10s agent image

• Installs catatonit, verifies its executable path, and makes it the image entrypoint while retaining the non-root user and existing default command.

Containerfile.c10s

Containerfile.c9sAdd catatonit entrypoint to the c9s agent image +7/-0

Add catatonit entrypoint to the c9s agent image

• Installs catatonit, verifies its executable path, and makes it the image entrypoint while retaining the non-root user and existing default command.

Containerfile.c9s

Documentation (2) +20 / -0
README-agents.mdDocument agent init behavior and validation +13/-0

Document agent init behavior and validation

• Explains signal forwarding, orphan reaping, the decision to retain persistent workers, and how to run static and local runtime checks.

README-agents.md

README.mdDocument OpenShift agent startup +7/-0

Document OpenShift agent startup

• Explains why deployments supply Python through args rather than command so the catatonit image entrypoint remains active.

openshift/README.md

Other (14) +250 / -28
beeai-make-build.ymlRun agent init configuration checks in build CI +3/-0

Run agent init configuration checks in build CI

• Runs the new static checker after container builds to catch missing catatonit entrypoints and deployment command overrides.

.github/workflows/beeai-make-build.yml

.secrets.baselineRealign secret baseline locations +8/-8

Realign secret baseline locations

• Adjusts recorded line numbers for affected deployment manifests and refreshes the baseline generation timestamp.

.secrets.baseline

deployment-backport-agent-c10s.ymlPreserve the entrypoint for c10s backport workers +1/-2

Preserve the entrypoint for c10s backport workers

• Moves /usr/bin/python3 from command into args ahead of the backport module invocation.

openshift/deployment-backport-agent-c10s.yml

deployment-backport-agent-c9s.ymlPreserve the entrypoint for c9s backport workers +1/-2

Preserve the entrypoint for c9s backport workers

• Moves python from command into args ahead of the backport module invocation.

openshift/deployment-backport-agent-c9s.yml

deployment-mr-consolidation-agent-c10s.ymlPreserve the entrypoint for c10s MR consolidation workers +1/-2

Preserve the entrypoint for c10s MR consolidation workers

• Moves /usr/bin/python3 from command into args ahead of the MR consolidation module invocation.

openshift/deployment-mr-consolidation-agent-c10s.yml

deployment-mr-consolidation-agent-c9s.ymlPreserve the entrypoint for c9s MR consolidation workers +1/-2

Preserve the entrypoint for c9s MR consolidation workers

• Moves python from command into args ahead of the MR consolidation module invocation.

openshift/deployment-mr-consolidation-agent-c9s.yml

deployment-rebase-agent-c10s.ymlPreserve the entrypoint for c10s rebase workers +1/-2

Preserve the entrypoint for c10s rebase workers

• Moves /usr/bin/python3 from command into args ahead of the rebase module invocation.

openshift/deployment-rebase-agent-c10s.yml

deployment-rebase-agent-c9s.ymlPreserve the entrypoint for c9s rebase workers +1/-2

Preserve the entrypoint for c9s rebase workers

• Moves python from command into args ahead of the rebase module invocation.

openshift/deployment-rebase-agent-c9s.yml

deployment-rebuild-agent-c10s.ymlPreserve the entrypoint for c10s rebuild workers +1/-2

Preserve the entrypoint for c10s rebuild workers

• Moves /usr/bin/python3 from command into args ahead of the rebuild module invocation.

openshift/deployment-rebuild-agent-c10s.yml

deployment-rebuild-agent-c9s.ymlPreserve the entrypoint for c9s rebuild workers +1/-2

Preserve the entrypoint for c9s rebuild workers

• Moves python from command into args ahead of the rebuild module invocation.

openshift/deployment-rebuild-agent-c9s.yml

deployment-reproducer-agent.ymlPreserve the entrypoint for reproducer workers +1/-2

Preserve the entrypoint for reproducer workers

• Moves /usr/bin/python3 from command into args ahead of the reproducer module invocation.

openshift/deployment-reproducer-agent.yml

deployment-triage-agent.ymlPreserve the entrypoint for triage workers +1/-2

Preserve the entrypoint for triage workers

• Moves /usr/bin/python3 from command into args ahead of the triage module invocation.

openshift/deployment-triage-agent.yml

check_agent_init.pyStatically validate agent image and deployment startup +60/-0

Statically validate agent image and deployment startup

• Checks that both Containerfiles install catatonit and end with its exec-form entrypoint. Rejects OpenShift agent deployments that override the entrypoint and fails if no qualifying deployments are found.

scripts/check_agent_init.py

test_agent_init.pyProbe built agent images for init behavior +169/-0

Probe built agent images for init behavior

• Provides local Podman or Docker checks for PID 1, orphan reaping, signal forwarding, exit-code preservation, non-root execution, and agent module imports. Tests both default and alternate user execution.

scripts/test_agent_init.py

@opohorel

opohorel commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator Author

I didn't run e2e tests yet. waiting for copr to be available

@qodo-for-packit

qodo-for-packit Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Every code change reinstalls catatonit at build time ✓ Resolved
Description
The new RUN dnf -y install catatonit layer sits after COPY ymir/agents/, ymir/tools/ and
ymir/common/ and after chgrp -R, so it depends on the agent source layers. Any change to agent
Python code invalidates this layer, and every rebuild then downloads dnf metadata again and
reinstalls the package. That makes the CI podman-compose build and local builds slower, and they
now need repository access even when only Python code changed.
Code

Containerfile.c10s[R116-119]

+RUN dnf -y install catatonit \
+    && dnf clean all \
+    && ln -s /usr/libexec/catatonit/catatonit /usr/bin/catatonit \
+    && test -x /usr/bin/catatonit
Relevance

●●● Strong

Moving package installation before source COPY is a deterministic cache optimization consistent with
container package-install practices.

PR-#48

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
In both Containerfiles the catatonit install comes right after the COPY of ymir/agents, ymir/tools
and ymir/common and the recursive chgrp/chmod of /home/beeai. Build layer caching invalidates every
layer after a changed COPY, so this dnf step runs again on every source change. The earlier package
installs, which sit before the COPYs, stay cached.

Containerfile.c10s[107-119]
Containerfile.c9s[113-125]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The catatonit `dnf install` layer comes after the COPY of agent source, so any Python change busts the cache and reinstalls the package.

## Fix Focus Areas
- Containerfile.c10s[115-119]
- Containerfile.c9s[121-125]

## Recommended Fix
Add `catatonit` to the main early `dnf -y install` package list in each Containerfile, or move the separate RUN step so it comes before the `COPY ymir/...` lines. Keep the `ln -s /usr/libexec/catatonit/catatonit /usr/bin/catatonit && test -x /usr/bin/catatonit` step, and keep the static check regex happy (it looks for `dnf ... install ... catatonit` in a RUN command).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

2. CI blocks any exec probe in agent deployments ✓ Resolved
Description
check_agent_init.py fails a deployment if any indented line matches ^\s+command: anywhere in the
file, not just the container's own command field. An exec liveness or readiness probe, a
lifecycle hook, or an initContainer with command: added to an agent Deployment would fail CI even
though it does not override the image ENTRYPOINT.
Code

scripts/check_agent_init.py[R49-50]

+    if re.search(r"^\s+command:", content, re.MULTILINE):
+        errors.append(f"{dep}: uses 'command:' which overrides the image ENTRYPOINT")
Relevance

●●● Strong

Raw YAML scanning can reject valid nested commands; repository history favors hardening scripts
against false positives.

PR-#488
PR-#600

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The check runs a raw regex over the whole YAML text. Other deployments in this repo already use
command: in nested places, as phoenix-db does, which shows the key shows up in Kubernetes
manifests for reasons other than container entrypoints.

scripts/check_agent_init.py[43-50]
openshift/deployment-phoenix-db.yml[43-53]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The static check flags any `command:` key in an agent deployment, including probe or lifecycle `exec.command`, so valid manifests would fail.

## Fix Focus Areas
- scripts/check_agent_init.py[43-50]

## Recommended Fix
Load the deployment with a YAML parser (e.g. PyYAML) and check only `spec.template.spec.containers[*].command` for containers whose image starts with `beeai-agent`. If you want to avoid the dependency, at least limit the regex to `command:` at the container-field indentation.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context sources
✅ Compliance rules (platform): 8 rules
Review mode: Auto: 🧠 Deep: Multiple container, deployment, CI, and runtime-test paths create dense independent defect risk.

Grey Divider

Tip of the day
💡 Did you know, you can show, collapse, or hide each part of a finding: code, evidence, and all

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread Containerfile.c10s Outdated
Comment thread scripts/check_agent_init.py Outdated
Install catatonit in both agent images and preserve the image entrypoint in OpenShift deployments. Add static CI checks for image and deployment startup configuration, with local runtime checks for orphan reaping, signal forwarding, exit codes, non-root execution, and agent module imports. Reject commented or overridden init entrypoints and empty deployment discovery. Document the persistent-worker decision.

Assisted-by: Codex (GPT-6)

@cgwalters cgwalters left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely a good idea, though the most robust long term fix is to avoid long-lived containers (or VMs) and have most agents align with CI and be relatively short-lived (e.g. 6h cap like GHA does)

for cf in CONTAINERFILES:
with open(cf) as f:
content = f.read()
# Dockerfile comments are ignored, including between continued lines.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a pretty fragile and hacky parser...

I think a more robust check for this is looking at the built images (which can be done as part of a CI pipeline that builds them) and not re-inspecting the source code.

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.

2 participants