Skip to content
Open
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
27 changes: 27 additions & 0 deletions README-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,33 @@ Three agents process tasks through Redis queues:
- **Backport Agent**: Applies specific fixes/patches to packages. It looks for patches that are linked, attached and present in the description or comments in the issue. It tries to apply the patch and resolve any conflicts that may arise during the backport process.
- **Issue Verification Agent**: Manages the post-fix lifecycle of a JIRA issue — from merged MR through errata creation, testing analysis, and status transitions to RELEASE_PENDING. Migrated from the supervisor's `IssueHandler`.

### Y-stream inheritance fast path

For Important and Critical Y-stream CVEs, triage carries the shipped leading
Z-stream clone build to the backport agent. The leading stream is the entry in
`current_z_streams`; `upcoming_z_streams` is not an inheritance source. The agent
uses only the leading source for the target Y-stream's RHEL major; it does not
fall back through older Z-streams. Before invoking the normal LLM backport, the
agent may reproduce the exact single-issue Z-stream packaging commit on
`cXs` when the Brew build and target spec have the same Epoch:Version. The commit
source, Jira footer, and changed files are validated deterministically. An
inheritance-only LLM maps the source spec change onto the Y-stream spec, but
inherited patch files must remain byte-for-byte identical to their shipped
Z-stream Git blobs. The LLM cannot use shell, network, file-creation, or
patch-generation tools, and its spec changes are audited before release and
changelog bookkeeping is added.

The inherited change must pass clean `%prep`, SRPM creation, and Copr validation.
If an immutable patch is changed or does not apply cleanly, inheritance is
disabled durably and the existing normal backport starts with the original patch
URLs. Any other pre-push source failure also resets the checkout and starts the
normal backport; only an environmental cleanup failure permits one fresh-clone
retry of the same leading source. An already-present fix is a routing error, not
a successful no-op. After a push, recovery never creates a second fallback
backport. The queue task stores a publication checkpoint and a retry verifies the
fork branch still points at the validated commit before it resumes at MR
creation. Routing-invariant failures are terminal and are not requeued.


## Dry run mode

Expand Down
1 change: 1 addition & 0 deletions THREAT_MODEL.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ Security-relevant assumptions this system makes about its environment:
| T2 | Indirect prompt injection via untrusted Jira issue or GitLab MR comment content causes an agent to misuse privileged tools (unauthorized push, credential exfiltration, SSRF via `patch_url`, resource exhaustion — see T12) | remote_auth | Jira issue content; GitLab MR comments; `GetPatchFromUrlTool` | Dist-git write access, GitLab PAT, Kerberos keytabs, source/patch integrity | critical | possible | partially_mitigated | credential redaction (`redact_credentials()`/`_REDACT_PATTERNS` in `gateway_utils.py`, shared by both privileged and unprivileged gateways); credentials never mounted into agent pods (isolated to `mcp-gateway`); per-agent hardcoded privileged-tool whitelists (model never sees the full privileged set); network egress allow-list bounds SSRF blast radius; human review expected before merge (not code-enforced — see open questions) | `ymir/tools/gateway_utils.py` (`redact_credentials`), commit `8b181341` (path traversal fix) |
| T3 | `CreateZstreamBranchTool` parses spec-file content pulled from arbitrary historical dist-git commits using the macro/shell-expanding `specfile` library, inside the privileged `mcp-gateway` pod that alone holds the Kerberos keytab and GitLab PAT — a spec macro (e.g. `%(shell command)`) surviving in dist-git history achieves code execution with access to those credentials | remote_auth | `Specfile(content=...)` in `ymir/tools/privileged/distgit.py` (`CreateZstreamBranchTool._find_latest_same_nvr_ref`) | Kerberos keytabs, GitLab PAT, Dist-git write access | critical | rare | unmitigated | none — spec parsing runs with the same container privileges as every other tool in `mcp-gateway` (`runAsNonRoot` + default `RuntimeDefault` seccomp only); no sandboxing of macro/shell expansion; this is the one pod holding all credentials, so code execution here is a full compromise | `ymir/tools/privileged/distgit.py:156-157`; tracked upstream as [PACKIT-4796](https://redhat.atlassian.net/browse/PACKIT-4796) |
| T4 | Credential material leaks into LLM agent context or centralized logs via tool error/stderr output | insider | privileged GitLab/dist-git tool error handling; Splunk-forwarded stdout/stderr | GitLab PAT, Kerberos keytabs | critical | rare | mitigated | `redact_credentials()`/`_REDACT_PATTERNS` (`ymir/tools/gateway_utils.py`), used by both the privileged and unprivileged gateways, strips credential-shaped strings before they reach agent context or logs; `sanitize_url()` (`ymir/tools/privileged/utils.py`) redacts credentials embedded in URLs | `ymir/tools/gateway_utils.py`, `ymir/tools/privileged/utils.py` |
| T13 | Compromised or malformed Brew source metadata redirects Y-stream inheritance to an unrelated repository or commit, or embeds instructions that influence the inheritance adaptation LLM | remote_auth | Brew build `source`; source commit/spec diff; `resolve_brew_source`; privileged `FetchCommitTool` | Source/patch integrity, GitLab PAT | high | rare | mitigated | require an existing build for the expected package; derive Epoch:Version from Brew fields; accept only HTTPS `gitlab.com/redhat/rhel/rpms/<package>` and a full hexadecimal SHA; fetch into a namespaced ref; require one exact single-Jira `Resolves:` commit; reject unsupported, binary, renamed, deleted, source, and unrelated packaging files; give the adaptation LLM only spec text tools; verify inherited patch Git blob IDs; audit changed files plus protected Epoch, Version, Release, Source, and changelog metadata; require prep, SRPM, and Copr validation before push | `ymir/agents/ystream_inherit.py`, `ymir/agents/prompts/backport/instructions_inherit.j2`, `ymir/tools/privileged/gitlab.py` (`FetchCommitTool`) |
| T5 | Operator (or anyone with `oc exec`/`oc rsh` RBAC into the `valkey` pod) directly injects or tampers with queue entries, controlling which package/branch/issue privileged agents act on | local_admin | `oc exec`/`oc rsh` into `valkey` pod | Redis/Valkey task queues | high | possible | partially_mitigated | OpenShift namespace RBAC restricts who can `oc exec`; no application-level audit trail for direct queue mutation | none (routine operational practice; not yet documented in a committed doc) |
| T6 | SSRF-shaped fetch of an attacker-supplied `patch_url` reaches internal network endpoints reachable from the agent pod | remote_auth | `GetPatchFromUrlTool` `patch_url` parameter | Internal network reachability, GCP Vertex AI endpoints, other RH internal services within the egress allow-list | high | possible | partially_mitigated | OpenShift `TenantEgress` default-deny egress allow-list (network-level only; no in-app URL validation) | none |
| T10 | RPM spec files are parsed with the macro/shell-expanding `specfile` library and executed via `rpmbuild -bp`/`-bs` (not naive text parsing) while an agent rebases/backports a package; a spec crafted with `%(shell command)` macro syntax (e.g. via a malicious patch or a compromised upstream tarball) achieves arbitrary code execution during parsing/prep, independent of and in addition to the LLM's own tool-call surface (T2) | remote_auth | `Specfile()` calls in `ymir/tools/unprivileged/specfile.py` (`GetPackageInfoTool`, `AddChangelogEntryTool`, `UpdateReleaseTool`); `rpmbuild -bp`/`-bs` in `ymir/tools/unprivileged/wicked_git.py` (`RunPackagePrepTool`, `BuildSrpmTool`) | Pod filesystem/process (backport/rebase agent pods), source/patch integrity | high | possible | unmitigated | none — `rpmbuild` and the full RPM build toolchain run with standard container privileges only (`runAsNonRoot` + default `RuntimeDefault` seccomp, no restricted profile, no sandboxed macro evaluation) | `ymir/tools/unprivileged/specfile.py`, `ymir/tools/unprivileged/wicked_git.py`; tracked upstream as [PACKIT-4796](https://redhat.atlassian.net/browse/PACKIT-4796) |
Expand Down
2 changes: 2 additions & 0 deletions ai_providers_data_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ sequenceDiagram

**Use Cases:**
- Spec file analysis and modification
- Guided Y-stream adaptation of shipped Z-stream spec changes; inherited patch
content is immutable and verified outside the model
- Patch backporting and application
- Build failure diagnosis and fixing
- Test result analysis
Expand Down
6 changes: 6 additions & 0 deletions docs/mr_consolidation_architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,12 @@ pair at any time.
filing an MR. Creates a `pending` entry. If one already exists, it's a no-op (the
existing pending job will pick up the new MR when it runs).

This includes MRs produced by the Y-stream inheritance fast path. They retain
the normal `ymir_backport` label and contain one target Jira fix, so discovery,
ordering, stale-HEAD filtering, and per-commit consolidation need no special
case. Inheritance provenance (source Jira key, Brew NVR, and commit SHA) remains
in the original MR description.

**`pick_next_job()`** — Finds any `pending` field whose package-branch pair has no
`active` field, atomically deletes the `pending` entry and creates an `active` entry
with the same value. Implemented as a **Lua script** running inside Redis, so the
Expand Down
18 changes: 18 additions & 0 deletions gitlab_distgit_data_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,26 @@ graph TD
|------|---------|---------|
| **fork_repository** | Create or get existing fork | GitLab API |
| **clone_repository** | Clone repo to local path | Git CLI |
| **fetch_commit** | Fetch a validated full SHA into `refs/ymir/zstream/<sha>` | Git CLI |
| **push_to_remote_repository** | Push branch to remote | Git CLI |

`fetch_commit` is used by Y-stream inheritance for a Brew-recorded RHEL
dist-git commit. The caller first restricts the source to HTTPS on
`gitlab.com/redhat/rhel/rpms/<package>` and validates a full hexadecimal SHA;
the privileged tool reuses GitLab authentication and credential-safe logging.
The agent polls the namespaced ref to tolerate shared-NFS visibility delay.
Patch files from the selected commit are restored directly from their Git blobs
and their blob IDs are recorded. A restricted adaptation agent may modify the
target spec, but the patch blob IDs are checked again before validation and
staging. A changed patch abandons inheritance and starts normal backporting.

Inherited publication has distinct local-commit, push, and MR phases. A failure
before push may return to the normal backport workflow. If push reports an
uncertain result, the agent compares the fork update branch's exact remote HEAD
with the validated local commit. Once push is attempted, the queue task retains
a publication checkpoint; retries verify that branch and resume only at MR
creation, never at inheritance selection or the fallback backport.

### Merge Request Management

| Tool | Purpose | Returns |
Expand Down
10 changes: 10 additions & 0 deletions jira_data_flow.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,16 @@ sequenceDiagram
end
```

For an exactly Important or Critical Y-stream CVE, `CVEEligibilityResult` also
contains shipped clones from each RHEL major's configured current Z-stream that
have a non-empty Fixed in Build value. `upcoming_z_streams` and older Z-stream
clones are ignored for inheritance. Each source retains its Jira key, NVR, and
fixVersions. This metadata travels in `Task.metadata` to the backport queue,
which uses only the single source matching the target Y-stream major. Old tasks
without the field remain valid and use the normal backport path. A shipped clone
without an NVR still
satisfies the existing dependency decision but cannot be inherited.

### 3. Supervisor → Jira (READ/WRITE)

```mermaid
Expand Down
13 changes: 13 additions & 0 deletions jira_label_workflow_routing.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ flowchart TD

Two env-var flags affect pipeline behaviour: `DRY_RUN` and `JIRA_ALLOW_STATUS_CHANGES`. Verbosity is no longer controlled by an env var — the system is silent by default. The only way to opt into comments is per-issue, by adding `ymir_todo` (which flows through the task as `user_triggered=True`).

Important/Critical Y-stream CVEs may take the deterministic inheritance fast
path before the normal backport agent. A restricted LLM adapts only the target
spec; inherited patches remain exact shipped Git blobs and deterministic checks
audit the resulting files and protected spec metadata. This does not introduce
new Jira or GitLab labels: a validated inherited MR is still `ymir_backport`, reaches
`ymir_backported`, and enters the same consolidation queue. Pre-push failures
fall back without changing routing state. Detection of an already-inherited fix
is treated as a terminal error so a routing defect cannot manufacture an empty
success or consume queue retries. After a validated inherited commit reaches the
fork, retry metadata resumes MR publication without rerunning either backport
path. An immutable patch application failure records a task-level disable marker
so clone or queue retries continue only through normal backporting.

Ground rules:

- **Default is silent.** No result or error comments are posted on the Jira issue, and intermediate `_failed` labels are not written. Only `not-affected`, `postponed`, `open-ended-analysis`, and `clarification-needed` triage resolutions still post a comment unbidden (those have no MR to look at, so the comment is the only visible explanation).
Expand Down
Loading
Loading