| name | cve-remediation |
| description | Processes CVE vulnerability tickets from Jira filter 113291 (jetbrains-ide-dev-server CVEs), checks if the vulnerable package exists in the container image or Gradle dependency tree, and applies dependency bumps or version constraints. Can be invoked manually with a Jira ticket key or automatically via cron polling. |
| argument-hint | JIRA-KEY (optional, polls filter 113291 if omitted) |
CVE Remediation
Automatically triage and remediate CVE vulnerability tickets from Jira filter 113291 targeting the devspaces/jetbrains-ide-rhel9 component.
Required input
- If
$ARGUMENTS contains a Jira ticket key (e.g. CRW-11271), process only that ticket.
- If
$ARGUMENTS is empty, poll Jira filter 113291 and process all matching tickets.
Step 1 — Fetch and filter tickets
Query Jira:
- Use JQL:
filter=113291
- Cloud ID:
redhat.atlassian.net
Filter tickets:
- Only process tickets whose status is
New or in the To Do status category
- Skip all other statuses (
In Progress, Review, Closed, Done, etc.)
Step 2 — Extract CVE and package info from summary
The ticket summary follows this pattern:
CVE-YYYY-NNNNN devspaces/jetbrains-ide-rhel9: <package-name>: <description> [rhos_devspaces-X.XX]
Extract:
- CVE ID: e.g.
CVE-2026-48043
- Package name: the token after
jetbrains-ide-rhel9: and before the next : (trimmed)
Step 2b — Group tickets by package
After extracting CVE and package info from all tickets, group tickets by package name. Multiple CVEs often target the same package (e.g. three netty CVEs). Processing them together avoids redundant branches and ensures a single version bump covers all vulnerabilities.
For each package group:
- Collect all CVE IDs and Jira ticket keys
- Proceed through Steps 3–7 once per group, not once per ticket
Step 3 — Fetch advisory details and build a version map
For each ticket in the group, fetch remote/web links using getJiraIssueRemoteIssueLinks.
Look for (in priority order):
- GitHub Security Advisory link (github.com/advisories/ or github.com/.../security/advisories/) — preferred, contains patched version ranges
- CVE.org link (cve.org/CVERecord or nvd.nist.gov) — fallback for details
Fetch the advisory page using WebFetch to extract:
- All affected version ranges: e.g.
>=4.1.0 <4.1.135
- Patched version for each range: e.g.
4.1.135.Final
- Severity: if available
If no advisory link is found, use WebSearch to look up the CVE ID and find the advisory.
3b. Build the consolidated version map
Collect all affected ranges and their patched versions across every CVE in the group. When multiple CVEs specify different patched versions for the same major line, pick the highest patched version for that line.
Step 4 — Identify the dependency source
This project has two dependency ecosystems:
4a. Gradle/Java dependencies (che-integration-plugin)
The Gradle build file is at che-integration-plugin/build.gradle.kts. Java/Kotlin dependencies (like Netty, OkHttp, Kubernetes client) come from here, often as transitive dependencies.
Run:
cd che-integration-plugin && ./gradlew dependencies --configuration runtimeClasspath 2>&1 | grep -i "<package-name>"
This shows the full dependency tree including transitive versions and which parent pulls them in.
4b. npm dependencies (status-app)
The Node.js app is at status-app/. npm dependencies come from status-app/package.json.
Run:
cd status-app && npm ls <package-name> 2>/dev/null
4c. Container image system packages (RPMs)
Some vulnerabilities target system-level packages installed via RPM in the container image (defined in build/dockerfiles/Dockerfile). These cannot be fixed by dependency bumps — they require a base image update or explicit dnf update in the Dockerfile.
Run:
grep -i "<package-name>" build/dockerfiles/Dockerfile
If the package is not found in Gradle or npm but appears in the Dockerfile or is a known system library (e.g. glibc, openssl, curl), note it as a container-level dependency.
4d. Cross-reference with the version map
For each installed version found:
- Check if it falls within any affected range from the version map
- If yes, note:
- The source (Gradle, npm, or RPM)
- Whether it is a direct or transitive dependency
- The parent that pulls it in (for transitive deps)
- The patched version for that major line from the version map
- If no installed version falls in any affected range → the package is not vulnerable
Step 5 — Apply the fix (or comment)
If NOT VULNERABLE (no installed version in any affected range):
- Add a Jira comment on the ticket:
Automated CVE scan: package "<package-name>" is present in the codebase but the installed version(s) are outside the vulnerable range. No fix needed.
If the package is not present at all:
Automated CVE scan: package "<package-name>" was not found in the jetbrains-ide-dev-server codebase (neither as direct nor transitive dependency). Manual review may be needed if it is a system-level (RPM) package in the container image.
- Do NOT change the ticket status.
- Move to the next ticket.
If VULNERABLE — Gradle dependency fix:
- Create a new branch from
main named after the package group (e.g. fix-netty-cves). When the group contains a single CVE, use the CVE ID instead (e.g. CVE-2026-48043).
5a. Try bumping the direct dependency first (preferred)
Check whether updating the direct dependency that transitively pulls in the vulnerable package would resolve the CVE:
- Identify the dependency chain: e.g.
client-java → netty-nio-client → netty-codec-http2
- Check Maven Central for newer versions of the direct dependency:
curl -s "https://repo1.maven.org/maven2/<group-path>/<artifact>/maven-metadata.xml" | grep "<version>"
- For each candidate version (starting from the latest), temporarily update
build.gradle.kts and run:
cd che-integration-plugin && ./gradlew dependencies --configuration runtimeClasspath 2>&1 | grep -i "<vulnerable-package>"
- If a newer version of the direct dependency pulls in a patched version of the vulnerable package → bump the direct dependency
- Verify with
./gradlew dependencies and ./gradlew test
5b. Fall back to version constraints if no direct dependency bump resolves it
If no available version of the parent dependency pulls in the patched version:
- Add a
constraints block inside the dependencies block in build.gradle.kts:
constraints {
implementation("<group>:<artifact>:<patched-version>")
}
- When constraining a package like Netty that has many submodules, constrain all related artifacts to the same version for consistency.
- Verify with:
cd che-integration-plugin && ./gradlew dependencies --configuration runtimeClasspath 2>&1 | grep -i "<package>"
Look for -> <patched-version> indicating the constraint is applied.
- Run tests:
./gradlew test
5c. Commit
Commit with a message listing all CVE IDs:
fix: update <package-name> to <version> (<CVE-ID-1>, <CVE-ID-2>, ...)
If the fix was achieved by bumping a parent:
fix: update <parent-package> to <version> (resolves <CVE-ID-1>, <CVE-ID-2>, ... in transitive <package-name>)
Sign off all commits with --signoff.
If VULNERABLE — npm dependency fix:
- Create a branch as above.
Direct dependency
If the vulnerable package is a direct dependency in status-app/package.json, bump its version directly.
Transitive dependency
If the vulnerable package is transitive (pulled in by another dependency), use the overrides field in status-app/package.json to pin the patched version:
"overrides": {
"minimatch@5": {
".": "5.1.9",
"brace-expansion": "2.1.2"
},
"path-to-regexp": "8.4.0"
}
- Use scoped overrides (e.g.
"parent@range": { "child": "version" }) when the override should only apply under a specific parent package.
- Use top-level overrides when the package should be pinned globally.
- Remove stale override entries for dependency ranges that are no longer in the tree (e.g. if
minimatch@3 is no longer pulled by any dependency, drop its override block).
Verification sequence
After updating package.json:
- Run
cd status-app && npm install to regenerate the lock file.
- Run
npm ls <package-name> — confirm all instances resolve to the patched version. Look for overridden markers in the output.
- Run
npm audit — confirm 0 vulnerabilities.
- Smoke-test: start the app briefly with
timeout 5 node status-app/index.mjs and confirm it prints Status app is listening on port 3400 without errors (requires a mock product-info.json and std.out file at the repo root).
All four checks must pass before committing.
- Commit as above with
--signoff.
If VULNERABLE — Container/RPM package:
- Add a Jira comment:
Automated CVE scan: package "<package-name>" appears to be a system-level (RPM) dependency in the container image, not a direct project dependency. The fix requires a base image update or an explicit package update in the Dockerfile. Manual intervention needed.
- Do NOT change the ticket status.
Step 6 — Run security review
After applying a fix, run /security-review to validate the change does not introduce regressions.
Step 7 — Transition Jira tickets to In Progress
Once the fix is fully complete (committed, tests pass, security review passed):
- For each Jira ticket in the group, get the available transitions using
getTransitionsForJiraIssue
- Find the transition that moves the ticket to In Progress
- Apply the transition using
transitionJiraIssue
- Confirm to the user which tickets were transitioned
Important notes
- Always work on a fresh branch per package group, branched from
main
- Sign off all commits with
--signoff (adds Signed-off-by: line per DCO)
- Do NOT comment on Jira for applied fixes — only comment when the package is not found or not vulnerable
- If the patched version cannot be determined from advisories, log a warning and skip the fix (do not guess versions)
- When adding Gradle
constraints, respect the existing structure — the build.gradle.kts may already have constraints for other packages
- Prefer direct dependency bumps over constraints — constraints are maintenance overhead; a dependency bump is cleaner
- Always run
./gradlew test after applying Gradle fixes to catch compilation or runtime issues