Skip to content

feat(edge-cve): add Black CVE investigation plugin with govulncheck#232

Open
eggfoobar wants to merge 4 commits into
openshift-eng:mainfrom
eggfoobar:add-cve-scanner
Open

feat(edge-cve): add Black CVE investigation plugin with govulncheck#232
eggfoobar wants to merge 4 commits into
openshift-eng:mainfrom
eggfoobar:add-cve-scanner

Conversation

@eggfoobar

@eggfoobar eggfoobar commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Initial edge-cve plugin that fetches open Black CVE Jira tickets, maps them to configured edge components/versions, runs govulncheck via OpenShift Jobs, podman, or ad-hoc single-repo checks, and produces markdown/HTML reports plus remediation prompts. Scans use ticket release refs only (not tip-of-tree main), private tickets are redacted in HTML, and OCP versions are taken from Jira fields/summary so upstream library semver in descriptions is not mistaken for OpenShift releases.

Summary by CodeRabbit

  • New Features
    • Added the Edge CVE investigation marketplace plugin (edge-cve) with the edge-cve:investigate workflow.
    • Implemented deterministic Jira CVE fetching/parsing, scan-target building, govulncheck execution (OpenShift Jobs or local Podman), and result analysis with actionable verdicts.
    • Added deterministic Markdown + self-contained HTML reporting, including private-ticket redaction and an ad-hoc single-repo check mode.
    • Added Kubernetes resources for scan execution (namespace, RBAC, job template).
  • Documentation
    • Added end-to-end workflow docs for edge-cve.
  • Chores
    • Added default component→repo configuration, plus an ignore rule and required dependency.
  • Tests
    • Added unit tests for parsing, scan-result analysis, Jira pagination, report generation/redaction, target building, and result collection.

@openshift-ci

openshift-ci Bot commented Jul 16, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: eggfoobar

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

The PR adds and registers the edge-cve plugin, including Jira ingestion, CVE parsing and grouping, Go repository target construction, OpenShift and Podman scans, result collection, deterministic analysis, report generation, redaction, tests, and workflow documentation.

Changes

Edge CVE plugin workflow

Layer / File(s) Summary
Plugin registration and workflow contract
.claude-plugin/*, .gitignore, plugins/edge-cve/{README.md,config/*,k8s/*,requirements.txt}, plugins/edge-cve/skills/investigate/*
Registers the plugin, defines repository mappings and dependencies, provisions scan resources, and documents commands, prerequisites, outputs, and execution rules.
Jira ingestion and scan-target preparation
plugins/edge-cve/scripts/lib/*, plugins/edge-cve/scripts/{fetch_cves.py,parse_cves.py,group_cves.py,build_scan_targets.py,validate_grouped_cves.py}
Fetches and normalizes Jira issues, extracts CVEs and versions, resolves repositories and refs, groups tickets, validates reviewed grouping data, and builds deduplicated Go scan targets.
OpenShift and Podman scan execution
plugins/edge-cve/scripts/{scan_target.sh,process_govulncheck_result.go,run_govulncheck_jobs.sh,run_govulncheck_podman.sh,run_single_repo_scan.sh}, plugins/edge-cve/k8s/*
Runs govulncheck against repository refs, handles timeouts and incomplete scans, and publishes curated results locally or through ConfigMaps.
Collection, analysis, and reporting
plugins/edge-cve/scripts/{collect_govulncheck_results.py,analyze_scan_result.py,redact_parsed_for_analysis.py,generate_report.py,generate_html_report.py,cve-investigator.sh}
Collects results, computes verdicts and remediation prompts, redacts private tickets, orchestrates workflow commands, and generates Markdown, HTML, and summary artifacts.
Validation tests
plugins/edge-cve/scripts/test_*.py, plugins/edge-cve/scripts/process_govulncheck_result_test.go
Covers extraction, Jira pagination, target identifiers, verdict computation, private-ticket redaction, grouping validation, collection state, HTML rendering, and OSV/CVE finding matching.

Estimated code review effort: 5 (Critical) | ~120 minutes

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@coderabbitai coderabbitai Bot added the ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review label Jul 16, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 15

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
plugins/edge-cve/k8s/namespace.yaml (1)

1-7: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Missing NetworkPolicy for edge-cve-scans namespace.

No NetworkPolicy is defined anywhere in the manifests. Scan Jobs clone and build third-party Go repos; without network isolation, pods in this namespace have unrestricted egress/ingress to the rest of the cluster.

As per path instructions for Kubernetes/OpenShift manifests: "NetworkPolicy defined for the namespace."

Example default-deny NetworkPolicy
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: edge-cve-scans
spec:
  podSelector: {}
  policyTypes:
    - Ingress
    - Egress
  egress:
    - {} # tighten to required egress (e.g. git remotes, k8s API) as needed
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/k8s/namespace.yaml` around lines 1 - 7, Add a Kubernetes
NetworkPolicy for the edge-cve-scans Namespace, using the namespace name and an
empty podSelector to cover all pods. Configure default-deny ingress and egress
policy types, while preserving only the explicitly required egress destinations
for scan Jobs if those requirements are defined in the manifests.

Source: Path instructions

plugins/edge-cve/scripts/test_cve_extract.py (1)

1-112: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Missing test coverage for is_private_ticket.

This function gates redaction of CVE IDs/summaries for restricted tickets in HTML reports — a privacy-sensitive path — but has no positive/negative test here (only security_level match and label match paths are exercised elsewhere in the codebase, if at all). Per CONTRIBUTING.md: "ensure...validation/parsing logic has positive/negative test coverage" for this plugin's Jira parsing pipeline.

def test_is_private_ticket_security_level(self):
    self.assertTrue(is_private_ticket({"security_level": "Private", "labels": []}))

def test_is_private_ticket_label(self):
    self.assertTrue(is_private_ticket({"security_level": "", "labels": ["Private-CVE"]}))

def test_is_private_ticket_public(self):
    self.assertFalse(is_private_ticket({"security_level": "Restricted", "labels": ["cve"]}))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/test_cve_extract.py` around lines 1 - 112, Add
is_private_ticket to the imported CVE extraction helpers and extend
CveExtractTests with positive coverage for a Private security_level and
Private-CVE label, plus negative coverage for a non-private ticket. Keep the
assertions focused on the boolean result for each case.
🟡 Minor comments (9)
plugins/edge-cve/README.md-49-51 (1)

49-51: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use Markdown link syntax for the saved-filter URL.

The bare URL is not customer-friendly and may violate the repository’s Markdown lint configuration. Render it as a descriptive Markdown link.

Per CONTRIBUTING.md, Markdown must pass markdownlint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/README.md` around lines 49 - 51, Update the saved-filter
reference in the README to use descriptive Markdown link syntax instead of a
bare URL, preserving the existing destination and ensuring it complies with
repository markdownlint rules.

Source: Coding guidelines

plugins/edge-cve/README.md-15-15 (1)

15-15: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the token example valid shell.

export JIRA_API_TOKEN=<token> is parsed as shell redirection syntax rather than a value assignment. Use a quoted placeholder such as export JIRA_API_TOKEN='replace-with-token'.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/README.md` at line 15, Update the JIRA_API_TOKEN example in
the README to use a quoted placeholder value, ensuring the export command is
valid shell syntax and does not interpret the placeholder as redirection.
plugins/edge-cve/README.md-107-111 (1)

107-111: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Install from the requirements file, and pin it there first. pip install requests bypasses plugins/edge-cve/requirements.txt; update the README to python3 -m pip install -r plugins/edge-cve/requirements.txt, and change requests>=2.28.0 to an exact pin. Per CONTRIBUTING.md: “production dependencies must be pinned exactly.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/README.md` around lines 107 - 111, Update the Python
dependencies section in the README to install via the requirements file using
python3 -m pip install -r plugins/edge-cve/requirements.txt, and change the
requests dependency in plugins/edge-cve/requirements.txt from the minimum
version constraint to an exact version pin.

Source: Path instructions

plugins/edge-cve/config/component-repos.json-44-47 (1)

44-47: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Trim trailing punctuation from repo slugs. In plugins/edge-cve/config/component-repos.json:44-47, these patterns can capture closing ), ], ,, or . from prose, and extract_repo_urls() forwards that into slug unchanged. That produces invalid targets like openshift/microshift). Make the match boundary-aware or strip trailing punctuation before building the slug.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/config/component-repos.json` around lines 44 - 47, The
repo_url_patterns entries currently allow trailing prose punctuation into the
captured repo name. Update the repository URL extraction flow, including
extract_repo_urls(), so captured slugs exclude closing ), ], commas, and periods
before the slug is constructed, while preserving valid repository characters and
existing URL matching behavior.
plugins/edge-cve/k8s/rbac.yaml-12-15 (1)

12-15: 🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Narrow the ConfigMap RBAC

Per CONTRIBUTING.md: “RBAC: least privilege.” This job only creates and patch-merges ConfigMaps, so get, list, and update can be removed from plugins/edge-cve/k8s/rbac.yaml:15.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/k8s/rbac.yaml` around lines 12 - 15, Update the ConfigMap
rule under resources ["configmaps"] to remove the unnecessary "get", "list", and
"update" verbs, retaining only "create" and "patch" for the job’s required
operations.

Source: Path instructions

plugins/edge-cve/scripts/build_scan_targets.py-21-27 (1)

21-27: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Truncated slug-based target_id risks collisions across distinct repo/ref pairs.

slugify() lowercases, replaces non-alnum with -, and truncates to 50 chars; target_id concatenates two truncated slugs. Two different (repo_slug, git_ref) pairs that normalize/truncate to the same string (e.g., long slugs sharing a 50-char prefix, or refs differing only in characters that both become -) would collide in targets_map (line 47), silently merging unrelated CVE/ticket metadata into one scan target. Downstream, run_govulncheck_jobs.sh treats this id as the unique key for job addressing, so a collision could also cause one scan job to be skipped or overwritten by another.

Append a short content hash to guarantee uniqueness regardless of truncation.

🔧 Suggested fix
+import hashlib
+
 def slugify(value: str) -> str:
     return re.sub(r"[^a-z0-9]+", "-", value.lower()).strip("-")[:50]
 
 
 def target_id(repo_slug: str, git_ref: str) -> str:
-    return f"{slugify(repo_slug)}--{slugify(git_ref)}"
+    digest = hashlib.sha256(f"{repo_slug}@{git_ref}".encode()).hexdigest()[:8]
+    return f"{slugify(repo_slug)}--{slugify(git_ref)}--{digest}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/build_scan_targets.py` around lines 21 - 27, Update
target_id to append a short deterministic content hash derived from the original
repo_slug and git_ref, while retaining the existing slugified components for
readability. Ensure the hash input distinguishes the two values unambiguously
and is included in every returned ID so truncation or normalization cannot cause
collisions in targets_map or downstream job addressing.
plugins/edge-cve/scripts/cve-investigator.sh-9-11 (1)

9-11: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Usage text/header comment omit --repo-slug and --no-prune.

cmd_check_repo parses --repo-slug (line 87) and --no-prune (line 97), but neither the top-of-file comment nor usage() documents them, which will confuse users of --help.

Also applies to: 145-147

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/cve-investigator.sh` around lines 9 - 11, Update the
cve-investigator.sh usage header and usage() output for cmd_check_repo to
document both supported options, --repo-slug and --no-prune, alongside the
existing repository arguments. Keep the descriptions consistent with their
parsed behavior and ensure both help locations expose them.
plugins/edge-cve/scripts/cve-investigator.sh-1-1 (1)

1-1: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Shebang must be #!/usr/bin/bash per coding guidelines.

This file uses #!/usr/bin/env bash.

🛠️ Proposed fix
-#!/usr/bin/env bash
+#!/usr/bin/bash

As per coding guidelines, **/*.sh: "Shebang must be #!/usr/bin/bash".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/cve-investigator.sh` at line 1, Update the shebang
at the start of the cve-investigator.sh script from the env-based form to the
required direct Bash path, using exactly #!/usr/bin/bash.

Source: Coding guidelines

plugins/edge-cve/scripts/run_single_repo_scan.sh-82-84 (1)

82-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Handle SSH remote URLs in REPO_SLUG fallback. git@github.com:org/repo.git becomes repo, so omitting --repo-slug drops the org segment for SSH remotes. Normalize user@host:owner/repo first, or use a proper parser here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_single_repo_scan.sh` around lines 82 - 84,
Update the REPO_SLUG fallback normalization to support SSH remotes such as
git@github.com:owner/repo.git, preserving the owner/repository path while
removing the SSH host prefix and optional .git suffix. Keep the existing HTTPS
URL handling intact and apply the change within the REPO_SLUG assignment block.
🧹 Nitpick comments (12)
plugins/edge-cve/k8s/govulncheck-job.yaml.template (1)

24-24: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Consider pinning the base image by digest.

registry.redhat.io/ubi9/go-toolset:1.23 is pinned by tag only; the tag can be re-pointed to a different underlying image over time.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/k8s/govulncheck-job.yaml.template` at line 24, Update the
image reference in the govulncheck job template from the mutable
registry.redhat.io/ubi9/go-toolset:1.23 tag to the corresponding immutable
digest-pinned reference, preserving the intended Go toolset version.

Source: Path instructions

plugins/edge-cve/requirements.txt (1)

1-1: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pin an exact requests version.

requests>=2.28.0 allows any newer release to be installed, which conflicts with the supply-chain guideline to pin exact versions for reproducible, vetted builds.

As per path instructions, **/{requirements*.txt,...}: "Pin exact versions; verify hashes where supported."

Proposed fix
-requests>=2.28.0
+requests==2.32.3
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/requirements.txt` at line 1, Update the requests dependency
declaration in requirements.txt from a minimum-version constraint to an exact,
vetted version pin, following the repository’s supply-chain guidance; preserve
the existing dependency name and verify or add its hash if supported by the
project’s requirements format.

Source: Path instructions

plugins/edge-cve/scripts/generate_report.py (1)

29-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Scan-by-ticket indexing is implemented three times across two files. generate_report.py defines an unused scan_by_ticket (duplicating its own inline loop at lines 76-78), and generate_html_report.py reimplements the same logic yet again as build_scan_index, even though it already imports helpers from generate_report.py.

  • plugins/edge-cve/scripts/generate_report.py#L29-L35: delete the dead scan_by_ticket, or promote it to the single shared implementation and have main() call it instead of the inline loop at lines 76-78.
  • plugins/edge-cve/scripts/generate_html_report.py#L87-L92: import and reuse that shared implementation instead of build_scan_index.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/generate_report.py` around lines 29 - 35, The
scan-by-ticket indexing logic is duplicated across both report generators. In
plugins/edge-cve/scripts/generate_report.py lines 29-35, retain scan_by_ticket
as the shared implementation and update main() to call it instead of its inline
loop; in plugins/edge-cve/scripts/generate_html_report.py lines 87-92, import
and reuse scan_by_ticket and remove or replace build_scan_index.
plugins/edge-cve/scripts/run_single_repo_scan.sh (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial

Shebang doesn't match required #!/usr/bin/bash.

See consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_single_repo_scan.sh` at line 1, Update the
shebang at the start of run_single_repo_scan.sh from #!/usr/bin/env bash to the
required #!/usr/bin/bash.

Sources: Coding guidelines, Path instructions

plugins/edge-cve/scripts/run_govulncheck_jobs.sh (2)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial

Shebang doesn't match required #!/usr/bin/bash.

Same issue as scan_target.sh; see consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_govulncheck_jobs.sh` at line 1, Update the
shebang at the top of run_govulncheck_jobs.sh to use the required /usr/bin/bash
interpreter path, matching scan_target.sh.

Sources: Coding guidelines, Path instructions


94-115: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Python heredoc for parsing scan-targets.json is duplicated in run_govulncheck_podman.sh.

Lines 96-113 are byte-for-byte identical to run_govulncheck_podman.sh lines 137-154. Worth extracting to a small shared helper script (e.g. list_scan_targets.py) invoked by both, so future schema changes to scan-targets.json only need updating in one place. See consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_govulncheck_jobs.sh` around lines 94 - 115,
Extract the duplicated scan-target parsing heredoc from run_govulncheck_jobs.sh
and run_govulncheck_podman.sh into a shared list_scan_targets.py helper.
Preserve the existing target filtering, stderr summary, and pipe-delimited
output consumed by both scripts, then invoke the helper with the same arguments
and remove both inline Python blocks.
plugins/edge-cve/scripts/run_govulncheck_podman.sh (2)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial

Shebang doesn't match required #!/usr/bin/bash.

See consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh` at line 1, Update the
shebang at the top of run_govulncheck_podman.sh from #!/usr/bin/env bash to the
required #!/usr/bin/bash.

Sources: Coding guidelines, Path instructions


130-156: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated with run_govulncheck_jobs.sh's target-parsing heredoc.

See consolidated comment (shared with run_govulncheck_jobs.sh lines 94-115).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh` around lines 130 - 156,
Remove the duplicated target-parsing heredoc from the script’s
PYTHON_ARGS/TARGET_LINES flow and reuse the shared parsing implementation
established for run_govulncheck_jobs.sh. Preserve repository filtering and the
existing target fields/output format while consolidating the logic in one
reusable location.
plugins/edge-cve/scripts/collect_govulncheck_results.py (2)

42-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Ruff RUF005: prefer iterable unpacking over list concatenation.

As per coding guidelines, `**/*.py`: Python code must pass ruff validation. Line 46-54's oc_base(namespace) + [...] triggers RUF005.

♻️ Proposed fix
         proc = run(
-            oc_base(namespace)
-            + [
-                "get",
-                "jobs",
-                "-l",
-                "app.kubernetes.io/name=edge-cve-govulncheck",
-                "-o",
-                "json",
-            ],
+            [*oc_base(namespace), "get", "jobs", "-l",
+             "app.kubernetes.io/name=edge-cve-govulncheck", "-o", "json"],
             check=False,
         )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/collect_govulncheck_results.py` around lines 42 -
84, Update the command construction in wait_for_jobs to use iterable unpacking
when combining oc_base(namespace) with the additional get jobs arguments,
removing the list concatenation that triggers Ruff RUF005. Preserve the existing
command order and behavior.

Sources: Coding guidelines, Linters/SAST tools


87-116: 🗄️ Data Integrity & Integration | 🔵 Trivial

No scoping to the current run's expected targets — historically-published ConfigMaps accumulate and get re-collected on every future run.

collect_result_configmaps selects on RESULT_LABEL (plus an optional repo filter), but there's nothing here (or in run_govulncheck_jobs.sh) that deletes/expires ConfigMaps for targets that no longer appear in a newer scan-targets.json (e.g., a resolved ticket dropped from the list). Those stale ConfigMaps keep matching the selector indefinitely and get folded into every subsequent report as if they were fresh, until someone manually cleans the namespace. Also flags the same RUF005 pattern at line 97 as the block above.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/collect_govulncheck_results.py` around lines 87 -
116, Update collect_result_configmaps and the run_govulncheck_jobs.sh flow to
scope result ConfigMaps to the current scan-targets.json targets, removing or
expiring ConfigMaps for targets no longer present so stale results are not
re-collected. Preserve repo filtering while adding the run-target boundary, and
replace the RUF005-prone list concatenation around the oc command with the
project’s preferred iterable-unpacking approach.
plugins/edge-cve/scripts/scan_target.sh (1)

1-1: 📐 Maintainability & Code Quality | 🔵 Trivial

Shebang doesn't match required #!/usr/bin/bash.

As per coding guidelines, `**/*.sh`: Shebang must be `#!/usr/bin/bash`, and CONTRIBUTING.md reiterates "keep Shell scripts using #!/usr/bin/bash". This file (and the other three shell scripts in this cohort) use #!/usr/bin/env bash. See consolidated comment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/scan_target.sh` at line 1, Update the shebang at the
top of scan_target.sh from “#!/usr/bin/env bash” to the required
“#!/usr/bin/bash”, preserving the rest of the script unchanged.

Sources: Coding guidelines, Path instructions

plugins/edge-cve/scripts/process_govulncheck_result.go (1)

201-233: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Set an explicit TLS MinVersion on the in-cluster API client.

tls.Config{RootCAs: pool} relies on Go's implicit default (currently TLS 1.2 for clients). Since this client sends a bearer token to the Kubernetes API, explicitly pinning a floor removes ambiguity about the negotiated floor and guards against any future change in Go's default.

🔒 Proposed fix
 	client := &http.Client{
 		Transport: &http.Transport{
-			TLSClientConfig: &tls.Config{RootCAs: pool},
+			TLSClientConfig: &tls.Config{RootCAs: pool, MinVersion: tls.VersionTLS12},
 		},
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go` around lines 201 -
233, Update the TLS configuration created in inClusterClient to explicitly set
MinVersion to TLS 1.2 alongside RootCAs, ensuring the Kubernetes API client
never negotiates an older protocol.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/edge-cve/k8s/govulncheck-job.yaml.template`:
- Around line 18-67: Add pod/container securityContext hardening to the
govulncheck container: run as non-root, disable privilege escalation, use a
read-only root filesystem, and drop all capabilities. Because HOME, GOPATH,
GOCACHE, and GOMODCACHE in the container command flow write under /tmp, add a
writable emptyDir volume mounted at /tmp while preserving the existing workspace
and scripts mounts.

In `@plugins/edge-cve/README.md`:
- Around line 203-210: Make Podman cleanup explicitly confirmed and opt-in: in
plugins/edge-cve/README.md lines 203-210, remove the default system prune
behavior or require explicit confirmation before running it; in
plugins/edge-cve/skills/investigate/SKILL.md lines 161-168, warn users before
local scans and pass --no-prune unless cleanup has been explicitly approved.

In `@plugins/edge-cve/scripts/analyze_scan_result.py`:
- Around line 31-41: Update determine_verdict so every abnormal scan_exit_code
not in (0, 3) returns "inconclusive", regardless of finding_count, while
preserving the existing scan_incomplete and affected handling. Add positive and
negative tests covering scan_exit_code=1 with zero findings and normal clean
results.

In `@plugins/edge-cve/scripts/collect_govulncheck_results.py`:
- Around line 35-39: Update sanitize_label to lowercase the sanitized label,
matching the Go-side sanitizeLabel behavior used for the edge-cve/repo label.
Apply lowercasing consistently before enforcing the 63-character limit.

In `@plugins/edge-cve/scripts/cve-investigator.sh`:
- Around line 105-107: Update the workdir creation branch in check-repo to use a
GNU-compatible mktemp template with trailing Xs, and register cleanup of the
newly created temporary workdir via a trap. Only add the trap when the branch
creates the directory; preserve caller-provided workdir behavior and the
existing results_dir setup.

In `@plugins/edge-cve/scripts/lib/jira_client.py`:
- Around line 76-101: Update search_jql()’s pagination loop to enforce a hard
maximum iteration count and raise an error when nextPageToken repeats or
otherwise fails to advance. Handle missing pagination metadata without silently
truncating results, while preserving normal termination when Jira explicitly
indicates the final page.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go`:
- Around line 243-260: Update sanitizeLabel to match the Python sanitize_label
behavior by removing the uppercase-to-lowercase conversion and preserving
uppercase characters as allowed label content. Truncate the sanitized string to
63 characters before trimming “-”, “_”, and “.” so the final result always ends
with an alphanumeric character and remains consistent with --repo filtering.
- Around line 311-361: Update findingOSV and the matching flow to handle
govulncheck entries where finding.osv is a string ID rather than an embedded
object. Resolve that ID against the available top-level OSV data, preserve the
original finding entry in matched, and retain support for existing
embedded-object and alias matching behavior.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh`:
- Around line 241-268: Apply repo_filters when collecting result files in the
aggregation heredoc: inspect each loaded result’s target repo_slug and include
only results matching the requested filters, while retaining all results when no
filters are provided. Update the loop around results_dir.glob and preserve the
existing invalid-JSON warning, payload metadata, counts, and output behavior.

In `@plugins/edge-cve/scripts/scan_target.sh`:
- Around line 42-49: Update the checkout flow in scan_target.sh to fail
immediately when neither the requested GIT_REF nor origin/GIT_REF can be checked
out. Remove the unconditional success fallback after the checkout attempts,
while preserving the existing clone and fetch behavior.

In `@plugins/edge-cve/skills/investigate/SKILL.md`:
- Around line 159-176: Validate the --local and --dry-run combination before the
Step 2 branching logic in the investigation workflow. If both flags are
supplied, stop immediately with a clear incompatibility error; otherwise
preserve the existing local and dry-run behaviors unchanged.
- Around line 47-50: Update the workdir contract used by the investigate
workflow and its documentation: make the default workdir unique per run instead
of reusing a daily path, and validate overridden workdirs by rejecting unsafe or
non-empty directories before execution. In
plugins/edge-cve/skills/investigate/SKILL.md at lines 47-50, document the
generated per-run workdir and override validation; in plugins/edge-cve/README.md
at line 21, update the copy/paste example to use the same contract.
- Around line 178-185: Update the OpenShift investigation workflow around the
cve-investigator.sh scan and collect commands to define explicit stop conditions
for command failures, zero discovered targets, missing result files, malformed
JSON, and partial results. Keep these policies inline beside the affected
invocations, and prevent analysis or finalization from treating stale or
incomplete data as complete; retain the existing timeout guidance while
documenting how each condition is handled.
- Around line 200-219: Update the govulncheck analysis prompt and input flow
around the generalPurpose subagent so private tickets are excluded or redacted
before processing. Ensure cves-parsed.json is never passed directly when it
contains is_private tickets, while preserving the existing analysis of
non-private ticket context and required output file.
- Around line 129-153: Add a validation step between the foreground Agent
instruction and the build_scan_targets.py invocation in the investigation
workflow. Require cves-grouped-reviewed.json to exist and validate against the
cves-grouped.json schema; stop without rebuilding targets if it is missing or
invalid, preventing stale data from being used.

---

Outside diff comments:
In `@plugins/edge-cve/k8s/namespace.yaml`:
- Around line 1-7: Add a Kubernetes NetworkPolicy for the edge-cve-scans
Namespace, using the namespace name and an empty podSelector to cover all pods.
Configure default-deny ingress and egress policy types, while preserving only
the explicitly required egress destinations for scan Jobs if those requirements
are defined in the manifests.

In `@plugins/edge-cve/scripts/test_cve_extract.py`:
- Around line 1-112: Add is_private_ticket to the imported CVE extraction
helpers and extend CveExtractTests with positive coverage for a Private
security_level and Private-CVE label, plus negative coverage for a non-private
ticket. Keep the assertions focused on the boolean result for each case.

---

Minor comments:
In `@plugins/edge-cve/config/component-repos.json`:
- Around line 44-47: The repo_url_patterns entries currently allow trailing
prose punctuation into the captured repo name. Update the repository URL
extraction flow, including extract_repo_urls(), so captured slugs exclude
closing ), ], commas, and periods before the slug is constructed, while
preserving valid repository characters and existing URL matching behavior.

In `@plugins/edge-cve/k8s/rbac.yaml`:
- Around line 12-15: Update the ConfigMap rule under resources ["configmaps"] to
remove the unnecessary "get", "list", and "update" verbs, retaining only
"create" and "patch" for the job’s required operations.

In `@plugins/edge-cve/README.md`:
- Around line 49-51: Update the saved-filter reference in the README to use
descriptive Markdown link syntax instead of a bare URL, preserving the existing
destination and ensuring it complies with repository markdownlint rules.
- Line 15: Update the JIRA_API_TOKEN example in the README to use a quoted
placeholder value, ensuring the export command is valid shell syntax and does
not interpret the placeholder as redirection.
- Around line 107-111: Update the Python dependencies section in the README to
install via the requirements file using python3 -m pip install -r
plugins/edge-cve/requirements.txt, and change the requests dependency in
plugins/edge-cve/requirements.txt from the minimum version constraint to an
exact version pin.

In `@plugins/edge-cve/scripts/build_scan_targets.py`:
- Around line 21-27: Update target_id to append a short deterministic content
hash derived from the original repo_slug and git_ref, while retaining the
existing slugified components for readability. Ensure the hash input
distinguishes the two values unambiguously and is included in every returned ID
so truncation or normalization cannot cause collisions in targets_map or
downstream job addressing.

In `@plugins/edge-cve/scripts/cve-investigator.sh`:
- Around line 9-11: Update the cve-investigator.sh usage header and usage()
output for cmd_check_repo to document both supported options, --repo-slug and
--no-prune, alongside the existing repository arguments. Keep the descriptions
consistent with their parsed behavior and ensure both help locations expose
them.
- Line 1: Update the shebang at the start of the cve-investigator.sh script from
the env-based form to the required direct Bash path, using exactly
#!/usr/bin/bash.

In `@plugins/edge-cve/scripts/run_single_repo_scan.sh`:
- Around line 82-84: Update the REPO_SLUG fallback normalization to support SSH
remotes such as git@github.com:owner/repo.git, preserving the owner/repository
path while removing the SSH host prefix and optional .git suffix. Keep the
existing HTTPS URL handling intact and apply the change within the REPO_SLUG
assignment block.

---

Nitpick comments:
In `@plugins/edge-cve/k8s/govulncheck-job.yaml.template`:
- Line 24: Update the image reference in the govulncheck job template from the
mutable registry.redhat.io/ubi9/go-toolset:1.23 tag to the corresponding
immutable digest-pinned reference, preserving the intended Go toolset version.

In `@plugins/edge-cve/requirements.txt`:
- Line 1: Update the requests dependency declaration in requirements.txt from a
minimum-version constraint to an exact, vetted version pin, following the
repository’s supply-chain guidance; preserve the existing dependency name and
verify or add its hash if supported by the project’s requirements format.

In `@plugins/edge-cve/scripts/collect_govulncheck_results.py`:
- Around line 42-84: Update the command construction in wait_for_jobs to use
iterable unpacking when combining oc_base(namespace) with the additional get
jobs arguments, removing the list concatenation that triggers Ruff RUF005.
Preserve the existing command order and behavior.
- Around line 87-116: Update collect_result_configmaps and the
run_govulncheck_jobs.sh flow to scope result ConfigMaps to the current
scan-targets.json targets, removing or expiring ConfigMaps for targets no longer
present so stale results are not re-collected. Preserve repo filtering while
adding the run-target boundary, and replace the RUF005-prone list concatenation
around the oc command with the project’s preferred iterable-unpacking approach.

In `@plugins/edge-cve/scripts/generate_report.py`:
- Around line 29-35: The scan-by-ticket indexing logic is duplicated across both
report generators. In plugins/edge-cve/scripts/generate_report.py lines 29-35,
retain scan_by_ticket as the shared implementation and update main() to call it
instead of its inline loop; in plugins/edge-cve/scripts/generate_html_report.py
lines 87-92, import and reuse scan_by_ticket and remove or replace
build_scan_index.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go`:
- Around line 201-233: Update the TLS configuration created in inClusterClient
to explicitly set MinVersion to TLS 1.2 alongside RootCAs, ensuring the
Kubernetes API client never negotiates an older protocol.

In `@plugins/edge-cve/scripts/run_govulncheck_jobs.sh`:
- Line 1: Update the shebang at the top of run_govulncheck_jobs.sh to use the
required /usr/bin/bash interpreter path, matching scan_target.sh.
- Around line 94-115: Extract the duplicated scan-target parsing heredoc from
run_govulncheck_jobs.sh and run_govulncheck_podman.sh into a shared
list_scan_targets.py helper. Preserve the existing target filtering, stderr
summary, and pipe-delimited output consumed by both scripts, then invoke the
helper with the same arguments and remove both inline Python blocks.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh`:
- Line 1: Update the shebang at the top of run_govulncheck_podman.sh from
#!/usr/bin/env bash to the required #!/usr/bin/bash.
- Around line 130-156: Remove the duplicated target-parsing heredoc from the
script’s PYTHON_ARGS/TARGET_LINES flow and reuse the shared parsing
implementation established for run_govulncheck_jobs.sh. Preserve repository
filtering and the existing target fields/output format while consolidating the
logic in one reusable location.

In `@plugins/edge-cve/scripts/run_single_repo_scan.sh`:
- Line 1: Update the shebang at the start of run_single_repo_scan.sh from
#!/usr/bin/env bash to the required #!/usr/bin/bash.

In `@plugins/edge-cve/scripts/scan_target.sh`:
- Line 1: Update the shebang at the top of scan_target.sh from “#!/usr/bin/env
bash” to the required “#!/usr/bin/bash”, preserving the rest of the script
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 4ba48fec-94ec-4892-a78c-bdc990c00aed

📥 Commits

Reviewing files that changed from the base of the PR and between 9d4247a and be89556.

📒 Files selected for processing (28)
  • .claude-plugin/marketplace.json
  • .gitignore
  • plugins/edge-cve/.claude-plugin/plugin.json
  • plugins/edge-cve/README.md
  • plugins/edge-cve/config/component-repos.json
  • plugins/edge-cve/k8s/govulncheck-job.yaml.template
  • plugins/edge-cve/k8s/namespace.yaml
  • plugins/edge-cve/k8s/rbac.yaml
  • plugins/edge-cve/requirements.txt
  • plugins/edge-cve/scripts/analyze_scan_result.py
  • plugins/edge-cve/scripts/build_scan_targets.py
  • plugins/edge-cve/scripts/collect_govulncheck_results.py
  • plugins/edge-cve/scripts/cve-investigator.sh
  • plugins/edge-cve/scripts/fetch_cves.py
  • plugins/edge-cve/scripts/generate_html_report.py
  • plugins/edge-cve/scripts/generate_report.py
  • plugins/edge-cve/scripts/group_cves.py
  • plugins/edge-cve/scripts/lib/__init__.py
  • plugins/edge-cve/scripts/lib/cve_extract.py
  • plugins/edge-cve/scripts/lib/jira_client.py
  • plugins/edge-cve/scripts/parse_cves.py
  • plugins/edge-cve/scripts/process_govulncheck_result.go
  • plugins/edge-cve/scripts/run_govulncheck_jobs.sh
  • plugins/edge-cve/scripts/run_govulncheck_podman.sh
  • plugins/edge-cve/scripts/run_single_repo_scan.sh
  • plugins/edge-cve/scripts/scan_target.sh
  • plugins/edge-cve/scripts/test_cve_extract.py
  • plugins/edge-cve/skills/investigate/SKILL.md

Comment thread plugins/edge-cve/k8s/govulncheck-job.yaml.template
Comment thread plugins/edge-cve/README.md Outdated
Comment thread plugins/edge-cve/scripts/analyze_scan_result.py
Comment thread plugins/edge-cve/scripts/collect_govulncheck_results.py Outdated
Comment thread plugins/edge-cve/scripts/cve-investigator.sh Outdated
Comment thread plugins/edge-cve/skills/investigate/SKILL.md Outdated
Comment thread plugins/edge-cve/skills/investigate/SKILL.md
Comment thread plugins/edge-cve/skills/investigate/SKILL.md
Comment thread plugins/edge-cve/skills/investigate/SKILL.md Outdated
Comment thread plugins/edge-cve/skills/investigate/SKILL.md
eggfoobar and others added 2 commits July 17, 2026 11:19
Initial edge-cve plugin that fetches open Black CVE Jira tickets, maps
them to configured edge components/versions, runs govulncheck via
OpenShift Jobs, podman, or ad-hoc single-repo checks, and produces
markdown/HTML reports plus remediation prompts. Scans use ticket release
refs only (not tip-of-tree main), private tickets are redacted in HTML,
and OCP versions are taken from Jira fields/summary so upstream library
semver in descriptions is not mistaken for OpenShift releases.

Co-Authored-By: Cursor Grok 4.5 <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: ehila <ehila@redhat.com>
… workflow

Harden job/podman paths, Jira pagination, OSV resolution, workdir/validation
gates, and private-ticket redaction before LLM analysis.

Co-authored-by: Cursor Grok 4.5 <cursoragent@cursor.com>
Signed-off-by: ehila <ehila@redhat.com>
@coderabbitai coderabbitai Bot removed the ready-for-human-review Indicates a PR has been reviewed by automated tools and is ready for human review label Jul 17, 2026

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 17

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🟡 Minor comments (5)
plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py-44-49 (1)

44-49: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Add a timeout to the subprocess.run call.

If the script under test deadlocks or hangs, the test will block indefinitely. Adding timeout=10 ensures the test fails fast.

🛡️ Proposed fix
             result = subprocess.run(
                 [sys.executable, str(SCRIPT), "--workdir", str(workdir)],
                 capture_output=True,
                 text=True,
+                timeout=10,
                 check=False,
             )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py` around lines 44
- 49, Update the subprocess.run call in the test to include a 10-second timeout,
ensuring hung or deadlocked script execution fails promptly while preserving the
existing arguments and result handling.
plugins/edge-cve/scripts/test_jira_client.py-12-17 (1)

12-17: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Avoid shadowing an installed requests module.
sys.modules only reflects imports already performed; in a fresh test process this replaces a real requests install for the rest of the interpreter. Import requests and fall back to the stub only on ModuleNotFoundError.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/test_jira_client.py` around lines 12 - 17, Update
the test setup before importing jira_client to first import the real requests
module and only create/register the stub module when that import raises
ModuleNotFoundError; do not use the current sys.modules presence check, so an
installed requests package is preserved.
plugins/edge-cve/scripts/process_govulncheck_result.go-285-290 (1)

285-290: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Sort CVE IDs before serializing them.

Go map iteration is nondeterministic, so identical scans can emit different cve_ids ordering. Sort out before returning to preserve the PR's deterministic-output contract.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go` around lines 285 -
290, Update mapKeys to sort the collected out slice before returning it,
ensuring CVE IDs derived from the map have deterministic ordering while
preserving the existing collection behavior.
plugins/edge-cve/scripts/run_govulncheck_podman.sh-32-32 (1)

32-32: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Synchronize Podman memory defaults and remediation guidance. The executable default is 16g, while documentation and the OOM message still reference 6g.

  • plugins/edge-cve/scripts/run_govulncheck_podman.sh#L32-L32: establish the intended default as the source of truth.
  • plugins/edge-cve/README.md#L197-L201: document that same default.
  • plugins/edge-cve/scripts/run_govulncheck_podman.sh#L280-L282: recommend retrying above the current default, not at 6g.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh` at line 32, Use
CONTAINER_MEMORY in plugins/edge-cve/scripts/run_govulncheck_podman.sh as the
source of truth with the 16g default; update plugins/edge-cve/README.md lines
197-201 to document 16g, and update the OOM guidance in
plugins/edge-cve/scripts/run_govulncheck_podman.sh lines 280-282 to recommend
retrying with memory greater than 16g.
plugins/edge-cve/scripts/fetch_cves.py-68-69 (1)

68-69: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Create parent directories for every custom output path.

Optional output arguments currently fail with FileNotFoundError when their parent directory does not already exist.

  • plugins/edge-cve/scripts/fetch_cves.py#L68-L69: call output_path.parent.mkdir(parents=True, exist_ok=True) before writing.
  • plugins/edge-cve/scripts/group_cves.py#L148-L149: call llm_path.parent.mkdir(parents=True, exist_ok=True) before writing.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/fetch_cves.py` around lines 68 - 69, Ensure custom
output paths have existing parent directories before writing: in
plugins/edge-cve/scripts/fetch_cves.py lines 68-69, create output_path.parent
with parents=True and exist_ok=True before the open call; apply the same change
to llm_path.parent in plugins/edge-cve/scripts/group_cves.py lines 148-149.
🧹 Nitpick comments (1)
plugins/edge-cve/scripts/scan_target.sh (1)

55-56: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Pin govulncheck to a fixed version. @latest makes the scan job non-reproducible and can break when upstream changes; use a centrally declared, tested version instead.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/scan_target.sh` around lines 55 - 56, Replace the
`@latest` specifier in the govulncheck installation command with the centrally
declared, tested fixed version, reusing the repository’s existing version symbol
or configuration rather than introducing a new inline version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/edge-cve/scripts/analyze_scan_result.py`:
- Around line 45-53: Update finding_label to handle inner.osv values that are
string IDs as well as mapping-like embedded OSV objects, deriving vuln_id
without calling .get on a string and preserving the existing fallback behavior
for missing data. Add positive and negative tests covering string-valued IDs and
embedded OSV objects, including the expected label output.

In `@plugins/edge-cve/scripts/build_scan_targets.py`:
- Around line 21-26: Make target IDs collision-resistant in target_id within
plugins/edge-cve/scripts/build_scan_targets.py: append a stable digest derived
from the full repo_slug and git_ref after normalization, while preserving the
existing readable slug components. Apply the corresponding change in
plugins/edge-cve/scripts/run_single_repo_scan.sh lines 109-115 by appending a
stable digest of the full repository URL and ref before selecting the result
directory.

In `@plugins/edge-cve/scripts/collect_govulncheck_results.py`:
- Around line 50-59: Update the command construction in the govulncheck result
collection flow, including the additional occurrence, to use iterable unpacking
rather than list concatenation with oc_base(namespace). Preserve the existing
command argument order and behavior while resolving Ruff RUF005 validation
errors.
- Around line 65-80: Update the completion logic in the job-status aggregation
loop to inspect each job’s terminal conditions, rather than treating active == 0
as complete. Only return complete when every job has a Complete or Failed
condition; otherwise preserve the polling path for newly created or retrying
jobs.

In `@plugins/edge-cve/scripts/generate_html_report.py`:
- Around line 203-205: Update the report statistics around the total/affected
calculations and the component/global summary logic to deduplicate rows by their
ticket key before counting. Ensure tickets appearing under multiple versions
contribute once to total and verdict counts, while preserving the existing badge
and summary behavior.
- Around line 423-425: Update the component-loading flow around
load_known_components so an absent or empty mapping is treated as a fatal
configuration error: print an error to stderr and terminate before rendering
Jira components. Remove the fallback behavior that continues with all
components, preserving the report’s edge-only scope.
- Around line 115-132: Update the version grouping loop in the report-generation
flow so private tickets use the neutral version value “Withheld” instead of
their actual versions. Keep non-private tickets grouped by their existing
versions, while preserving the current redaction fields in the row construction
around is_private and versions.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go`:
- Around line 183-198: The doRequest function must bound the Kubernetes API call
and propagate response-body read errors. Configure the provided HTTP client with
an appropriate timeout before client.Do, and capture the error from io.ReadAll,
returning it with an empty httpResult instead of accepting truncated data; apply
the same handling to the additional request path around the referenced lines.
- Around line 293-312: Update readNDJSON to return ([]map[string]any, error),
propagating os.Open failures, JSON decode failures, and scanner.Err() instead of
silently skipping or returning partial entries. Update every caller of
readNDJSON to handle and propagate the error so failed scans cannot produce
clean or not_affected results; preserve skipping blank lines only.
- Around line 35-40: Update main’s SCAN_EXIT parsing to handle the strconv.Atoi
error instead of discarding it. Reject missing or malformed values with a
non-zero process exit and an appropriate error message, while preserving the
parsed scan exit code for valid input. Ensure no error return is ignored.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh`:
- Line 1: Update the shebang at the first line of
plugins/edge-cve/scripts/run_govulncheck_podman.sh (line 1) and
plugins/edge-cve/scripts/run_single_repo_scan.sh (line 1) to use the required
/usr/bin/bash interpreter.
- Around line 104-109: Require a timeout utility in both timeout-selection
blocks: plugins/edge-cve/scripts/run_govulncheck_podman.sh lines 104-109 and
plugins/edge-cve/scripts/run_single_repo_scan.sh lines 95-100 must fail with a
clear prerequisite error when neither timeout nor gtimeout is available, rather
than continuing without a wall-clock limit; preserve the existing preference for
timeout, then gtimeout.
- Around line 111-122: Update cleanup_current_container in
plugins/edge-cve/scripts/run_govulncheck_podman.sh (lines 111-122) and the
corresponding signal handling in
plugins/edge-cve/scripts/run_single_repo_scan.sh (lines 130-136) to use separate
INT and TERM handlers that invoke cleanup_current_container and then exit,
preventing execution from resuming after signal cleanup.

In `@plugins/edge-cve/scripts/scan_target.sh`:
- Line 1: Update the shebang at the beginning of scan_target.sh from
#!/usr/bin/env bash to the required exact form, #!/usr/bin/bash.

In `@plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py`:
- Around line 16-58: Add negative test methods to RedactParsedForAnalysisTest
covering a non-list tickets value that exits with code 1, a missing tickets key
that is handled gracefully, non-dict ticket entries being excluded, and an empty
tickets list producing private_redacted_count of 0. Reuse the existing
subprocess/workdir setup and assert the resulting output or exit behavior for
each case.

In `@plugins/edge-cve/scripts/test_validate_grouped_cves.py`:
- Around line 16-17: Replace the hard-coded /tmp path in the grouped CVE fixture
metadata with the relative placeholder cves-parsed.json, preserving the field’s
role as fixture metadata and leaving the surrounding grouped_at data unchanged.
- Around line 41-45: Add a narrowly scoped Ruff suppression comment for S603 to
the subprocess.run call in the test command helper, documenting that the command
uses the interpreter, fixed SCRIPT path, and test-controlled arguments. Keep the
existing subprocess behavior unchanged.

---

Minor comments:
In `@plugins/edge-cve/scripts/fetch_cves.py`:
- Around line 68-69: Ensure custom output paths have existing parent directories
before writing: in plugins/edge-cve/scripts/fetch_cves.py lines 68-69, create
output_path.parent with parents=True and exist_ok=True before the open call;
apply the same change to llm_path.parent in
plugins/edge-cve/scripts/group_cves.py lines 148-149.

In `@plugins/edge-cve/scripts/process_govulncheck_result.go`:
- Around line 285-290: Update mapKeys to sort the collected out slice before
returning it, ensuring CVE IDs derived from the map have deterministic ordering
while preserving the existing collection behavior.

In `@plugins/edge-cve/scripts/run_govulncheck_podman.sh`:
- Line 32: Use CONTAINER_MEMORY in
plugins/edge-cve/scripts/run_govulncheck_podman.sh as the source of truth with
the 16g default; update plugins/edge-cve/README.md lines 197-201 to document
16g, and update the OOM guidance in
plugins/edge-cve/scripts/run_govulncheck_podman.sh lines 280-282 to recommend
retrying with memory greater than 16g.

In `@plugins/edge-cve/scripts/test_jira_client.py`:
- Around line 12-17: Update the test setup before importing jira_client to first
import the real requests module and only create/register the stub module when
that import raises ModuleNotFoundError; do not use the current sys.modules
presence check, so an installed requests package is preserved.

In `@plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py`:
- Around line 44-49: Update the subprocess.run call in the test to include a
10-second timeout, ensuring hung or deadlocked script execution fails promptly
while preserving the existing arguments and result handling.

---

Nitpick comments:
In `@plugins/edge-cve/scripts/scan_target.sh`:
- Around line 55-56: Replace the `@latest` specifier in the govulncheck
installation command with the centrally declared, tested fixed version, reusing
the repository’s existing version symbol or configuration rather than
introducing a new inline version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 87686335-e842-4c63-93a8-9cee0df74058

📥 Commits

Reviewing files that changed from the base of the PR and between be89556 and d84bbf8.

📒 Files selected for processing (35)
  • .claude-plugin/marketplace.json
  • .gitignore
  • plugins/edge-cve/.claude-plugin/plugin.json
  • plugins/edge-cve/README.md
  • plugins/edge-cve/config/component-repos.json
  • plugins/edge-cve/k8s/govulncheck-job.yaml.template
  • plugins/edge-cve/k8s/namespace.yaml
  • plugins/edge-cve/k8s/rbac.yaml
  • plugins/edge-cve/requirements.txt
  • plugins/edge-cve/scripts/analyze_scan_result.py
  • plugins/edge-cve/scripts/build_scan_targets.py
  • plugins/edge-cve/scripts/collect_govulncheck_results.py
  • plugins/edge-cve/scripts/cve-investigator.sh
  • plugins/edge-cve/scripts/fetch_cves.py
  • plugins/edge-cve/scripts/generate_html_report.py
  • plugins/edge-cve/scripts/generate_report.py
  • plugins/edge-cve/scripts/group_cves.py
  • plugins/edge-cve/scripts/lib/__init__.py
  • plugins/edge-cve/scripts/lib/cve_extract.py
  • plugins/edge-cve/scripts/lib/jira_client.py
  • plugins/edge-cve/scripts/parse_cves.py
  • plugins/edge-cve/scripts/process_govulncheck_result.go
  • plugins/edge-cve/scripts/process_govulncheck_result_test.go
  • plugins/edge-cve/scripts/redact_parsed_for_analysis.py
  • plugins/edge-cve/scripts/run_govulncheck_jobs.sh
  • plugins/edge-cve/scripts/run_govulncheck_podman.sh
  • plugins/edge-cve/scripts/run_single_repo_scan.sh
  • plugins/edge-cve/scripts/scan_target.sh
  • plugins/edge-cve/scripts/test_analyze_scan_result.py
  • plugins/edge-cve/scripts/test_cve_extract.py
  • plugins/edge-cve/scripts/test_jira_client.py
  • plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py
  • plugins/edge-cve/scripts/test_validate_grouped_cves.py
  • plugins/edge-cve/scripts/validate_grouped_cves.py
  • plugins/edge-cve/skills/investigate/SKILL.md
🚧 Files skipped from review as they are similar to previous changes (14)
  • plugins/edge-cve/k8s/namespace.yaml
  • plugins/edge-cve/config/component-repos.json
  • plugins/edge-cve/scripts/lib/init.py
  • plugins/edge-cve/.claude-plugin/plugin.json
  • plugins/edge-cve/requirements.txt
  • plugins/edge-cve/k8s/rbac.yaml
  • .claude-plugin/marketplace.json
  • plugins/edge-cve/k8s/govulncheck-job.yaml.template
  • .gitignore
  • plugins/edge-cve/scripts/lib/jira_client.py
  • plugins/edge-cve/scripts/test_cve_extract.py
  • plugins/edge-cve/scripts/cve-investigator.sh
  • plugins/edge-cve/skills/investigate/SKILL.md
  • plugins/edge-cve/scripts/run_govulncheck_jobs.sh

Comment thread plugins/edge-cve/scripts/analyze_scan_result.py
Comment thread plugins/edge-cve/scripts/build_scan_targets.py Outdated
Comment thread plugins/edge-cve/scripts/collect_govulncheck_results.py
Comment thread plugins/edge-cve/scripts/collect_govulncheck_results.py Outdated
Comment thread plugins/edge-cve/scripts/generate_html_report.py Outdated
Comment thread plugins/edge-cve/scripts/run_govulncheck_podman.sh Outdated
Comment thread plugins/edge-cve/scripts/scan_target.sh Outdated
Comment thread plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py
Comment thread plugins/edge-cve/scripts/test_validate_grouped_cves.py Outdated
Comment thread plugins/edge-cve/scripts/test_validate_grouped_cves.py Outdated
Make target IDs collision-resistant, fix OSV string labels, require timeout
tools and signal-safe cleanup, fail closed on bad NDJSON/SCAN_EXIT/config,
dedupe HTML stats, and withhold private ticket versions; add covering tests.

Co-authored-by: Cursor Grok 4.5 <cursoragent@cursor.com>
Signed-off-by: ehila <ehila@redhat.com>

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@plugins/edge-cve/scripts/test_generate_html_report.py`:
- Around line 92-103: Suppress Ruff S603 narrowly on the fixed subprocess test
invocation in plugins/edge-cve/scripts/test_generate_html_report.py lines
92-103, adding a # noqa: S603 with a rationale that the command is fixed. Apply
the same targeted suppression to the fixed redaction-script invocation in
plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py lines 21-26; make no
other changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 5587de2d-278b-4f09-99f3-441239168646

📥 Commits

Reviewing files that changed from the base of the PR and between d84bbf8 and af2f38a.

📒 Files selected for processing (15)
  • plugins/edge-cve/scripts/analyze_scan_result.py
  • plugins/edge-cve/scripts/build_scan_targets.py
  • plugins/edge-cve/scripts/collect_govulncheck_results.py
  • plugins/edge-cve/scripts/generate_html_report.py
  • plugins/edge-cve/scripts/process_govulncheck_result.go
  • plugins/edge-cve/scripts/process_govulncheck_result_test.go
  • plugins/edge-cve/scripts/run_govulncheck_podman.sh
  • plugins/edge-cve/scripts/run_single_repo_scan.sh
  • plugins/edge-cve/scripts/scan_target.sh
  • plugins/edge-cve/scripts/test_analyze_scan_result.py
  • plugins/edge-cve/scripts/test_build_scan_targets.py
  • plugins/edge-cve/scripts/test_collect_govulncheck_results.py
  • plugins/edge-cve/scripts/test_generate_html_report.py
  • plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py
  • plugins/edge-cve/scripts/test_validate_grouped_cves.py
🚧 Files skipped from review as they are similar to previous changes (6)
  • plugins/edge-cve/scripts/scan_target.sh
  • plugins/edge-cve/scripts/analyze_scan_result.py
  • plugins/edge-cve/scripts/build_scan_targets.py
  • plugins/edge-cve/scripts/run_govulncheck_podman.sh
  • plugins/edge-cve/scripts/generate_html_report.py
  • plugins/edge-cve/scripts/run_single_repo_scan.sh

Comment thread plugins/edge-cve/scripts/test_generate_html_report.py Outdated
Mark trap-invoked cleanup in scan_target.sh, and noqa fixed subprocess
invocations in HTML/redaction unit tests.

Co-authored-by: Cursor Grok 4.5 <cursoragent@cursor.com>
Signed-off-by: ehila <ehila@redhat.com>

@coderabbitai coderabbitai Bot 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/edge-cve/scripts/test_generate_html_report.py (1)

93-104: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Bound test subprocesses with a timeout.

Both test paths can hang CI indefinitely if the invoked script blocks.

  • plugins/edge-cve/scripts/test_generate_html_report.py#L93-L104: add timeout=10 to subprocess.run.
  • plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py#L22-L27: add the same timeout in _run_with_parsed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@plugins/edge-cve/scripts/test_generate_html_report.py` around lines 93 - 104,
Bound both test subprocess invocations with a 10-second timeout: add timeout=10
to subprocess.run in plugins/edge-cve/scripts/test_generate_html_report.py lines
93-104 and to the subprocess invocation inside _run_with_parsed in
plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py lines 22-27.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@plugins/edge-cve/scripts/test_generate_html_report.py`:
- Around line 93-104: Bound both test subprocess invocations with a 10-second
timeout: add timeout=10 to subprocess.run in
plugins/edge-cve/scripts/test_generate_html_report.py lines 93-104 and to the
subprocess invocation inside _run_with_parsed in
plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py lines 22-27.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Central YAML (inherited)

Review profile: CHILL

Plan: Enterprise

Run ID: 02a62e49-c44b-4ca0-ba1e-5ba0ac84a11d

📥 Commits

Reviewing files that changed from the base of the PR and between af2f38a and c56ac4a.

📒 Files selected for processing (3)
  • plugins/edge-cve/scripts/scan_target.sh
  • plugins/edge-cve/scripts/test_generate_html_report.py
  • plugins/edge-cve/scripts/test_redact_parsed_for_analysis.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/edge-cve/scripts/scan_target.sh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant