Skip to content

[None][infra] Using agent to triage risks detected from PLC pipeline - #16510

Open
yuanjingx87 wants to merge 10 commits into
NVIDIA:mainfrom
yuanjingx87:user/yuanjingx/call_plc_triage_agent_to_process_scan_result
Open

[None][infra] Using agent to triage risks detected from PLC pipeline#16510
yuanjingx87 wants to merge 10 commits into
NVIDIA:mainfrom
yuanjingx87:user/yuanjingx/call_plc_triage_agent_to_process_scan_result

Conversation

@yuanjingx87

@yuanjingx87 yuanjingx87 commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Summary by CodeRabbit

  • New Features

    • Added automated triage of vulnerability and license findings.
    • Ticket references are now attached to matching risk records.
    • Added persistence for triage records and improved handling of previously triaged findings.
    • Updated the security dashboard link.
  • Bug Fixes

    • Reports now consistently process current findings without relying on previous scan results.
    • Improved default values and handling for vulnerability and license details.

Description

After PLC pipeline detected some new risks, send to PLC triage agent (https://gitlab-master.nvidia.com/ftp/infra/plc-risk-triage-agent) to create nvbug / jira task for it. And add ticket link to the report for later status tracking

Test Coverage

PR Checklist

Please review the following before submitting your PR:

  • PR description clearly explains what and why. If using CodeRabbit's summary, please make sure it makes sense.

  • PR Follows TRT-LLM CODING GUIDELINES to the best of your knowledge.

  • Test cases are provided for new code paths (see test instructions)

  • If PR introduces API changes, an appropriate PR label is added - either api-compatible or api-breaking. For api-breaking, include BREAKING in the PR title.

  • Any new dependencies have been scanned for license and vulnerabilities

  • CODEOWNERS updated if ownership changes

  • Documentation updated as needed

  • Update tava architecture diagram if there is a significant design change in PR.

  • The reviewers assigned automatically/manually are appropriate for the PR.

  • Please check this after reviewing the above items as appropriate for this PR.

GitHub Bot Help

To see a list of available CI bot commands, please comment /bot help.

@yuanjingx87
yuanjingx87 requested a review from a team as a code owner July 16, 2026 17:18
@yuanjingx87
yuanjingx87 requested review from mlefeb01 and mzweilz July 16, 2026 17:18
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

The pipeline no longer loads previous scan results. Report submission now identifies untriaged risks, sends them to a triage agent, stores ticket records in Elasticsearch, and attaches ticket URLs to vulnerability and license documents.

Triage-driven scan reporting

Layer / File(s) Summary
Triage agent formatting and ticket parsing
jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py
Risk documents are converted into capped, deduplicated agent items; agent responses are parsed into license and vulnerability ticket references.
Elasticsearch triage record handling
jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py
Triaged dependencies can be retrieved, new ticket records persisted, and the dashboard identifier updated.
Triage-aware report submission
jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py
Source and container vulnerability and license reports use standardized documents, triage records, and ticket URL backfilling.
Pipeline submission call flow
jenkins/scripts/pulse_in_pipeline_scanning/main.py
Source reports submit directly, container reports submit per architecture, and previous-scan parameters are removed.
Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Pipeline
  participant SubmitReport
  participant Elasticsearch
  participant TriageAgent
  Pipeline->>SubmitReport: submit current scan reports
  SubmitReport->>Elasticsearch: retrieve triaged dependencies
  SubmitReport->>TriageAgent: send untriaged risk items
  TriageAgent-->>SubmitReport: return ticket references
  SubmitReport->>Elasticsearch: save triage records
  SubmitReport->>Elasticsearch: bulk-post reports with ticket URLs
  Elasticsearch-->>Pipeline: return submission results
Loading

Suggested reviewers: mlefeb01

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main infra change: using an agent to triage PLC pipeline risks.
Description check ✅ Passed The description explains the purpose and solution and follows the required template, with only test coverage left blank.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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: 11

🧹 Nitpick comments (2)
jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py (1)

49-50: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document the changed public interfaces consistently.

Add Google-style Args and Returns sections; also correct extract_ticket_refs because it returns a dictionary, not a list.

  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py#L49-L50: document both input document lists and returned agent items.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py#L70-L71: document input items and response behavior.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py#L90-L107: document response shape and dictionary return value.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py#L80-L81: document filters and returned mapping.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py#L112-L122: document persistence arguments and failure behavior.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py#L142-L152: add a docstring for the dashboard URL builder.

As per coding guidelines, “Prefer docstrings for external interfaces, use Google-style docstrings, [and] document public function arguments.”

🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py` around lines 49 -
50, Update the public function docstrings with Google-style Args and Returns
sections: in jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py lines
49-50 document both document-list inputs and returned agent items; lines 70-71
document input items and response behavior; lines 90-107 document the response
shape and dictionary return type, correcting extract_ticket_refs from list to
dictionary. In jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py lines
80-81 document filters and returned mapping, lines 112-122 document persistence
arguments and failure behavior, and lines 142-152 add a docstring for the
dashboard URL builder.

Source: Coding guidelines

jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py (1)

32-71: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Redundant debug artifacts in _run_triage.

Lines 36-41 call format_risks_for_agent([], risk_docs) purely to print it, always misclassifying risk_docs as license docs regardless of scan_type (wrong for vulnerability calls), then the real call on lines 43-48 redoes the formatting correctly. Line 49's print(agent_resp) is also a leftover debug statement. This duplicates formatting work and prints misleading data.

🧹 Proposed cleanup
     if not risk_docs:
         return {}
-    print(
-        format_risks_for_agent(
-            [],
-            risk_docs,
-        )
-    )
     is_vuln = "vulnerability" in scan_type
     agent_resp = call_triage_agent(
         format_risks_for_agent(
             risk_docs if is_vuln else [],
             risk_docs if not is_vuln else [],
         )
     )
-    print(agent_resp)
     if not agent_resp:
         return {}
🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py` around lines 32
- 71, Remove the standalone format_risks_for_agent call and print before
call_triage_agent in _run_triage, since it duplicates work and misclassifies
vulnerability risks; retain the correctly constructed formatting passed to
call_triage_agent. Also remove the print(agent_resp) debug output while
preserving the existing response handling and ticket persistence logic.
🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py`:
- Line 117: Standardize the no-ticket fallback for s_ticket_url across
submit_source_code_vulns, submit_source_code_licenses, submit_container_vulns,
and submit_container_licenses. Choose one sentinel convention and apply it
consistently to all four document-building paths, including their triaged_deps
lookups, without changing ticketed values.
- Around line 111-118: Update the s_package_fix_version construction in the
report-building logic to coerce a null Upgrade-Guidance value to an empty
mapping before chaining Long-Term and Short-Term lookups. Preserve the existing
safe fallback order and “N/A” default.
- Around line 251-256: Update the container submission flow around
submit_container_* and save_triage_records so amd64 and arm64 passes reuse the
same triaged dependency data instead of calling get_triaged_deps independently.
Load triaged records once before both passes, pass that data into each
submit_container_* invocation, and ensure both architectures’ newly saved
records are considered before ticket creation.
- Around line 43-53: Guard the extract_ticket_refs(agent_resp) call in the
triage flow with exception handling for invalid or malformed responses,
including AttributeError, TypeError, and JSONDecodeError, and fall back to an
empty ticket-reference mapping on failure. Preserve the existing empty-response
return and continue processing so later es_post indexing still runs.

In `@jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py`:
- Around line 137-139: Update the error branch after es_post in the
triage-record persistence flow to retry indexing or fail the operation instead
of returning normally. Ensure bulk indexing errors are propagated after retries
so callers do not treat persistence as successful; preserve the existing stderr
logging context for scan_type.
- Around line 83-98: Update the triaged-dependency lookup around
ES_CLIENT.search to paginate through all matching records instead of limiting
results to the first 10,000. Use Elasticsearch search_after or scroll with a
stable sort, repeatedly request subsequent pages, and aggregate each hit’s
s_package_name and s_ticket_url until no results remain while preserving the
existing filters.
- Around line 123-131: Use package name and version consistently for triage
cache identity: in jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py lines
123-131, persist the version alongside s_package_name in saved triage records;
in lines 103-108, update lookup/filter key construction to include that version.
In jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py lines 53-58,
deduplicate items using the tuple (dependency_name, current_version,
action_type) rather than dependency name alone.

In `@jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py`:
- Line 1: Add the standard NVIDIA copyright header at the beginning of the new
triage.py module, before the existing module docstring. Preserve the current
docstring and implementation unchanged.
- Around line 26-27: Update the detail_parts construction near the triage agent
payload so it retains both severity and scan_type instead of overwriting the
severity entry. Ensure the resulting payload includes the existing severity
value and scan_type value.
- Around line 60-66: Update the license filtering condition in the triage loop
so known non-permissive license IDs, including GPL/LGPL values, reach
_license_doc_to_agent_item and are submitted for triage; do not restrict
processing to only “Unknown License” or empty IDs, while preserving the existing
seen-key deduplication and item append behavior.
- Around line 76-82: Narrow the exception handling in triage.py around the
request flow in the visible try block to catch only requests.RequestException
and the JSON decode exception raised by resp.json(), while preserving the
existing error logging and empty-dictionary fallback. In
jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py lines 82-101, replace the
broad exception handler with only the Elasticsearch client’s transport/API
exception base; do not let programming errors be converted into empty results.

---

Nitpick comments:
In `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py`:
- Around line 32-71: Remove the standalone format_risks_for_agent call and print
before call_triage_agent in _run_triage, since it duplicates work and
misclassifies vulnerability risks; retain the correctly constructed formatting
passed to call_triage_agent. Also remove the print(agent_resp) debug output
while preserving the existing response handling and ticket persistence logic.

In `@jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py`:
- Around line 49-50: Update the public function docstrings with Google-style
Args and Returns sections: in
jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py lines 49-50 document
both document-list inputs and returned agent items; lines 70-71 document input
items and response behavior; lines 90-107 document the response shape and
dictionary return type, correcting extract_ticket_refs from list to dictionary.
In jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py lines 80-81 document
filters and returned mapping, lines 112-122 document persistence arguments and
failure behavior, and lines 142-152 add a docstring for the dashboard URL
builder.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5846405b-6458-467d-925c-fae638421307

📥 Commits

Reviewing files that changed from the base of the PR and between 107e972 and cc30562.

📒 Files selected for processing (4)
  • jenkins/scripts/pulse_in_pipeline_scanning/main.py
  • jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py

Comment on lines +43 to +53
agent_resp = call_triage_agent(
format_risks_for_agent(
risk_docs if is_vuln else [],
risk_docs if not is_vuln else [],
)
)
print(agent_resp)
if not agent_resp:
return {}
ticket_refs = extract_ticket_refs(agent_resp)
new_tickets = {}

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.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- submit_report.py ---\n'
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py

printf '\n--- triage utils ---\n'
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py

Repository: NVIDIA/TensorRT-LLM

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '--- call sites and surrounding flow ---\n'
rg -n "call_triage_agent|extract_ticket_refs|es_post\(" jenkins/scripts/pulse_in_pipeline_scanning -n -A6 -B6

printf '\n--- file list in subtree ---\n'
git ls-files jenkins/scripts/pulse_in_pipeline_scanning

Repository: NVIDIA/TensorRT-LLM

Length of output: 248


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

paths = [
    Path("jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py"),
    Path("jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py"),
]
for path in paths:
    print(f"\n### {path} ({sum(1 for _ in path.open())} lines)")
    with path.open() as f:
        for i, line in enumerate(f, 1):
            if i <= 260:
                print(f"{i:4d}: {line.rstrip()}")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 17164


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '## submit_report.py'
nl -ba jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py | sed -n '1,220p'

echo
echo '## triage.py'
nl -ba jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py | sed -n '1,220p'

echo
echo '## call sites'
rg -n "call_triage_agent|extract_ticket_refs|es_post\\(" jenkins/scripts/pulse_in_pipeline_scanning -A6 -B6

Repository: NVIDIA/TensorRT-LLM

Length of output: 217


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for rel in [
    "jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py",
    "jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py",
]:
    p = Path(rel)
    print(f"\n### {rel}")
    text = p.read_text()
    for i, line in enumerate(text.splitlines(), 1):
        if 1 <= i <= 260:
            print(f"{i:4d}: {line}")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 17140


Guard triage response parsing before ES indexing.

extract_ticket_refs(agent_resp) can raise AttributeError, TypeError, or JSONDecodeError on a non-dict response, missing value, or malformed JSON. Since _run_triage runs before es_post(...), that exception aborts the whole batch and skips indexing every collected document for the run. Wrap this parse step and fall back to {} on failure.

Proposed fix
-    ticket_refs = extract_ticket_refs(agent_resp)
+    try:
+        ticket_refs = extract_ticket_refs(agent_resp)
+    except (TypeError, ValueError, AttributeError) as exc:
+        print(f"Failed to parse triage agent response: {exc}", file=sys.stderr)
+        return {}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
agent_resp = call_triage_agent(
format_risks_for_agent(
risk_docs if is_vuln else [],
risk_docs if not is_vuln else [],
)
)
print(agent_resp)
if not agent_resp:
return {}
ticket_refs = extract_ticket_refs(agent_resp)
new_tickets = {}
agent_resp = call_triage_agent(
format_risks_for_agent(
risk_docs if is_vuln else [],
risk_docs if not is_vuln else [],
)
)
print(agent_resp)
if not agent_resp:
return {}
try:
ticket_refs = extract_ticket_refs(agent_resp)
except (TypeError, ValueError, AttributeError) as exc:
print(f"Failed to parse triage agent response: {exc}", file=sys.stderr)
return {}
new_tickets = {}
🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py` around lines 43
- 53, Guard the extract_ticket_refs(agent_resp) call in the triage flow with
exception handling for invalid or malformed responses, including AttributeError,
TypeError, and JSONDecodeError, and fall back to an empty ticket-reference
mapping on failure. Preserve the existing empty-response return and continue
processing so later es_post indexing still runs.

Comment on lines +111 to 118
"s_package_fix_version": (
safe(v.get("Upgrade-Guidance", {}).get("Long-Term"))
or safe(v.get("Upgrade-Guidance", {}).get("Short-Term"))
or "N/A"
),
"s_license_ids": "N/A",
"s_ticket_url": triaged_deps.get(package_name, "N/A"),
}

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

echo '--- submit_report.py excerpt ---'
sed -n '80,140p' jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py

echo
echo '--- search for Upgrade-Guidance usages ---'
rg -n '"Upgrade-Guidance"|Upgrade-Guidance' jenkins/scripts/pulse_in_pipeline_scanning -S

echo
echo '--- python semantics probe ---'
python3 - <<'PY'
v1 = {"Upgrade-Guidance": None}
try:
    print((v1.get("Upgrade-Guidance", {}).get("Long-Term")))
except Exception as e:
    print(type(e).__name__, e)

v2 = {}
try:
    print((v2.get("Upgrade-Guidance", {}).get("Long-Term")))
except Exception as e:
    print(type(e).__name__, e)
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 3233


🏁 Script executed:

set -euo pipefail

echo '--- file stats ---'
wc -l jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py

echo
echo '--- relevant region with line numbers ---'
nl -ba jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py | sed -n '95,130p'

Repository: NVIDIA/TensorRT-LLM

Length of output: 323


🏁 Script executed:

set -euo pipefail
python3 - <<'PY'
v = {"Upgrade-Guidance": None}
try:
    x = v.get("Upgrade-Guidance", {}).get("Long-Term")
    print("ok", x)
except Exception as e:
    print(type(e).__name__, str(e))
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 213


Guard Upgrade-Guidance before chaining .get() v.get("Upgrade-Guidance", {}) still raises when the scanner emits "Upgrade-Guidance": null; coerce it first with (v.get("Upgrade-Guidance") or {}).

🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py` around lines 111
- 118, Update the s_package_fix_version construction in the report-building
logic to coerce a null Upgrade-Guidance value to an empty mapping before
chaining Long-Term and Short-Term lookups. Preserve the existing safe fallback
order and “N/A” default.

or "N/A"
),
"s_license_ids": "N/A",
"s_ticket_url": triaged_deps.get(package_name, "N/A"),

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Inconsistent "no ticket" sentinel across scan types ("N/A" vs "").

submit_source_code_vulns/submit_source_code_licenses default s_ticket_url to "N/A" (lines 117, 214) while submit_container_vulns/submit_container_licenses default to "" (lines 287, 371). Mixed sentinels for the same semantic "no ticket yet" state complicate downstream Kibana filtering/queries on s_ticket_url.

Pick one convention consistently across all four documents.

Also applies to: 214-214, 287-287, 371-371

🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py` at line 117,
Standardize the no-ticket fallback for s_ticket_url across
submit_source_code_vulns, submit_source_code_licenses, submit_container_vulns,
and submit_container_licenses. Choose one sentinel convention and apply it
consistently to all four document-building paths, including their triaged_deps
lookups, without changing ticketed values.

Comment on lines +251 to +256
) -> list:
"""Triage untriaged container vulnerabilities, save all docs to ES, return untriaged risks."""
SCAN_TYPE = "container_vulnerability"
triaged_deps = get_triaged_deps(SCAN_TYPE, build_metadata["ref"])
ts = int(start_datetime.timestamp() * 1000)

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.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant files and symbols first.
git ls-files 'jenkins/scripts/pulse_in_pipeline_scanning/*' | sed -n '1,120p'

echo '--- outline submit_report.py ---'
ast-grep outline jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py --view expanded || true

echo '--- search triage helpers ---'
rg -n "def (get_triaged_deps|save_triage_records|submit_container_vulns|submit_container_licenses|_run_triage|main)" jenkins/scripts/pulse_in_pipeline_scanning -S || true

echo '--- outline main.py ---'
ast-grep outline jenkins/scripts/pulse_in_pipeline_scanning/main.py --view expanded || true

Repository: NVIDIA/TensorRT-LLM

Length of output: 2286


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant sections with line numbers once files are identified.
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py | cat -n
echo '---'
sed -n '220,420p' jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py | cat -n
echo '--- main.py ---'
sed -n '1,240p' jenkins/scripts/pulse_in_pipeline_scanning/main.py | cat -n

Repository: NVIDIA/TensorRT-LLM

Length of output: 24378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- submit_report.py 220-360 ---'
sed -n '220,360p' jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py | cat -n

echo '--- main.py 1-220 ---'
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/main.py | cat -n

echo '--- helper definitions ---'
rg -n "def (get_triaged_deps|save_triage_records|_run_triage|submit_container_vulns|submit_container_licenses)" jenkins/scripts/pulse_in_pipeline_scanning -S

Repository: NVIDIA/TensorRT-LLM

Length of output: 13424


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py | cat -n

Repository: NVIDIA/TensorRT-LLM

Length of output: 6312


Avoid re-reading ES between the amd64 and arm64 container passes. In main.py:98-127 and submit_report.py:245-256, 310-321, each submit_container_* call does a fresh get_triaged_deps(...), while save_triage_records(...) only bulk-indexes to ES with no refresh. The second pass can miss the first pass’s new triage records and open a duplicate ticket for the same package.

🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/submit_report.py` around lines 251
- 256, Update the container submission flow around submit_container_* and
save_triage_records so amd64 and arm64 passes reuse the same triaged dependency
data instead of calling get_triaged_deps independently. Load triaged records
once before both passes, pass that data into each submit_container_* invocation,
and ensure both architectures’ newly saved records are considered before ticket
creation.

Comment thread jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py
Comment thread jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py
Comment thread jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py
Comment thread jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py
Comment on lines +60 to +66
lics = doc.get("s_license_ids", "")
if lics == "Unknown License" or lics == "":
item = _license_doc_to_agent_item(doc)
key = (item["dependency_name"], item["current_version"], item["action_type"])
if key not in seen:
seen.add(key)
items.append(item)

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Submit known non-permissive licenses to triage.

The downstream license submitters construct risk documents with non-empty license IDs such as GPL/LGPL. This condition drops those risks, so no license ticket is created unless the license is unknown or absent.

Proposed fix
 for doc in license_docs:
-    lics = doc.get("s_license_ids", "")
-    if lics == "Unknown License" or lics == "":
-        item = _license_doc_to_agent_item(doc)
-        key = (item["dependency_name"], item["current_version"], item["action_type"])
-        if key not in seen:
-            seen.add(key)
-            items.append(item)
+    item = _license_doc_to_agent_item(doc)
+    key = (item["dependency_name"], item["current_version"], item["action_type"])
+    if key not in seen:
+        seen.add(key)
+        items.append(item)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lics = doc.get("s_license_ids", "")
if lics == "Unknown License" or lics == "":
item = _license_doc_to_agent_item(doc)
key = (item["dependency_name"], item["current_version"], item["action_type"])
if key not in seen:
seen.add(key)
items.append(item)
item = _license_doc_to_agent_item(doc)
key = (item["dependency_name"], item["current_version"], item["action_type"])
if key not in seen:
seen.add(key)
items.append(item)
🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py` around lines 60 -
66, Update the license filtering condition in the triage loop so known
non-permissive license IDs, including GPL/LGPL values, reach
_license_doc_to_agent_item and are submitted for triage; do not restrict
processing to only “Unknown License” or empty IDs, while preserving the existing
seen-key deduplication and item append behavior.

Comment on lines +76 to +82
try:
resp = requests.post(TRIAGE_AGENT_URL, json=body, timeout=TRIAGE_AGENT_TIMEOUT)
resp.raise_for_status()
return resp.json()
except Exception as exc:
print(f"Triage agent call failed: {exc}", file=sys.stderr)
return {}

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== triage.py ==\n'
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py

printf '\n== es.py ==\n'
sed -n '1,220p' jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py

printf '\n== search for exception imports/usages ==\n'
rg -n "RequestException|JSONDecodeError|ElasticsearchException|TransportError|ApiError|ConnectionError|Exception as exc|except Exception" jenkins/scripts/pulse_in_pipeline_scanning/utils -S

Repository: NVIDIA/TensorRT-LLM

Length of output: 10159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

for path in [
    Path("jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py"),
    Path("jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py"),
]:
    print(f"\n== {path} ==")
    for i, line in enumerate(path.read_text().splitlines(), 1):
        if 1 <= i <= 220:
            print(f"{i:4}: {line}")
PY

Repository: NVIDIA/TensorRT-LLM

Length of output: 11770


🌐 Web query:

requests Response.json JSONDecodeError requests.exceptions.RequestException raise_for_status HTTPError and elasticsearch-py ApiError TransportError exception hierarchy

💡 Result:

The exception hierarchies for the Python requests library and the elasticsearch-py client serve distinct purposes, managing HTTP request errors and API-specific errors, respectively. Requests Exception Hierarchy In the requests library, RequestException is the base class for all exceptions [1][2]. Key components include: - RequestException: The root class for all exceptions raised by the library [1]. - HTTPError: A subclass of RequestException, raised when calling Response.raise_for_status if the response contains an unsuccessful HTTP status code (4xx or 5xx) [1][3]. - JSONDecodeError: A subclass of RequestException (and InvalidJSONError), raised when the Response.json method fails to parse the response body as valid JSON [4][1]. When handling these, it is best practice to catch specific exceptions first, followed by the more general RequestException [2]. Elasticsearch-py Exception Hierarchy The elasticsearch-py client uses a hierarchy centered on transport and API-level failures [5][6]: - TransportError: A generic exception for the underlying elastic-transport package, triggered by errors occurring before an HTTP response is received (e.g., connection issues, timeouts) [5][7]. - ApiError: A subclass used when the server returns an HTTP response that is not in the 2xx range [5][7]. The client maps specific HTTP status codes (like 400, 401, 409) to specialized subclasses of ApiError (e.g., BadRequestError, ConflictError) [8]. Unlike requests, where HTTPError is specifically triggered by an explicit call to raise_for_status, elasticsearch-py's ApiError is typically raised automatically by the client when it receives a non-successful response from the Elasticsearch cluster [5].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== dependency/version hints ==\n'
rg -n "elasticsearch|elastic-transport|requests==" -S requirements* pyproject.toml poetry.lock Pipfile* setup.cfg setup.py jenkins/scripts -g '!**/.git/**' || true

printf '\n== elasticsearch exception imports in repo ==\n'
rg -n "from elasticsearch import|import elasticsearch|TransportError|ApiError|ConnectionError|ElasticsearchException" -S . || true

Repository: NVIDIA/TensorRT-LLM

Length of output: 2076


Narrow these exception handlers

  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py: catch requests.RequestException plus the JSON decode error from resp.json(), not Exception.
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py: catch the Elasticsearch client’s transport/API exception base only.

return {} here can hide programming bugs as empty results.

🧰 Tools
🪛 ast-grep (0.44.1)

[warning] 76-76: Request-controlled URL passed to requests; validate against an allowlist to prevent SSRF.
Context: requests.post(TRIAGE_AGENT_URL, json=body, timeout=TRIAGE_AGENT_TIMEOUT)
Note: [CWE-918] Server-Side Request Forgery (SSRF).

(ssrf-requests)

🪛 Ruff (0.15.21)

[warning] 80-80: Do not catch blind exception: Exception

(BLE001)

📍 Affects 2 files
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py#L76-L82 (this comment)
  • jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py#L82-L101
🤖 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 `@jenkins/scripts/pulse_in_pipeline_scanning/utils/triage.py` around lines 76 -
82, Narrow the exception handling in triage.py around the request flow in the
visible try block to catch only requests.RequestException and the JSON decode
exception raised by resp.json(), while preserving the existing error logging and
empty-dictionary fallback. In
jenkins/scripts/pulse_in_pipeline_scanning/utils/es.py lines 82-101, replace the
broad exception handler with only the Elasticsearch client’s transport/API
exception base; do not let programming errors be converted into empty results.

Sources: Coding guidelines, Linters/SAST tools

Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
1. exclude cubin files when running sonarqube scanning
2. fail the stage if sbom not generated when running source code
   scanning

Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
@yuanjingx87
yuanjingx87 force-pushed the user/yuanjingx/call_plc_triage_agent_to_process_scan_result branch from 6a7121c to edfbc60 Compare August 1, 2026 17:27
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
@yuanjingx87
yuanjingx87 force-pushed the user/yuanjingx/call_plc_triage_agent_to_process_scan_result branch from 856fa1b to 8d7e987 Compare August 2, 2026 01:26
Signed-off-by: Yuanjing Xue <197832395+yuanjingx87@users.noreply.github.com>
@yuanjingx87
yuanjingx87 force-pushed the user/yuanjingx/call_plc_triage_agent_to_process_scan_result branch from 8d7e987 to 91e2f45 Compare August 2, 2026 02:04
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