Skip to content

Commit 69dd3fe

Browse files
ruromeroclaude
andauthored
feat(pypi): add pyproject.toml support to IntelliJ plugin (#244)
* feat(pypi): add pyproject.toml support to IntelliJ plugin Add component analysis support for pyproject.toml manifest files, enabling inline vulnerability diagnostics for Python projects using PEP 621 ([project.dependencies]) and Poetry ([tool.poetry.dependencies]) formats. New classes: - PyprojectCAAnnotator: extracts dependencies from TOML PSI structure - PyprojectCAIntentionAction: quick-fix for version updates - PyprojectCAInspection: inspection registration Modified files: - SaAction, SaUtils: recognize pyproject.toml as supported manifest - CAAnnotator, SAIntentionAction: add pyproject.toml to python mapping - ApiService: apply Python-specific settings for pyproject.toml - plugin.xml: register annotator and inspection for TOML language - README.md: document pyproject.toml support Implements TC-3853 Assisted-by: Claude Code * fix(pypi): address Qodo review findings for pyproject.toml support - Fix PEP 621 annotation targeting: use individual TomlLiteral elements instead of parent TomlKeyValue so each dependency gets its own highlight - Fix quick-fix replacement: preserve package name in PEP 508 strings (e.g. "anyio==3.6.2" → "anyio==4.0.0" instead of just "==4.0.0") - Add [project.optional-dependencies] parsing for PEP 621 optional groups - Update README to reflect optional-dependencies are now analyzed Implements TC-3853 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Assisted-by: Claude Code * fix(pypi): preserve PEP 508 extras and markers in quick fix and version extraction The version extraction regex was matching across the ';' environment marker boundary, and the quick fix was dropping extras and markers when rewriting the dependency string. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: fail fast when the toml file is not Cargo.toml Signed-off-by: Ruben Romero Montes <rromerom@redhat.com> * fix: implement license abstract methods Signed-off-by: Ruben Romero Montes <rromerom@redhat.com> * test(pypi): add unit tests for pyproject.toml support Add 35 tests covering PEP 508 utility methods, PEP 621 and Poetry dependency extraction, optional dependencies, intention action version updates, availability checks, and SaAction/SaUtils manifest recognition. Implements TC-4172 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Assisted-by: Claude Code * fix(pypi): resolve Poetry ignore comment misbind for multi-line inline tables When a trustify-da-ignore comment was placed on an inner key of a multi-line Poetry inline table, findAssociatedDependency() returned the inner key name (e.g., "version") instead of the outer dependency name. Added resolvePoetryDependencyEntry() to walk up from inner TomlKeyValue through TomlInlineTable to the actual dependency entry. Resolves: TC-4173 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Signed-off-by: Ruben Romero Montes <rromerom@redhat.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9e75dcc commit 69dd3fe

13 files changed

Lines changed: 1343 additions & 10 deletions

File tree

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ while you build your application.
2121
- Gradle Kotlin and Groovy (gradle)
2222
- Golang (go mod)
2323
- Rust (cargo)
24-
- Python (pip) ecosystems, and base images in Dockerfile.
24+
- Python (pip, pyproject.toml) ecosystems, and base images in Dockerfile.
2525

2626
In future releases, Red Hat plans to support other package managers.
2727

@@ -108,7 +108,7 @@ according to your preferences.
108108
dependencies for Rust projects.
109109
<br >If the path is not provided, your IDE's `PATH` environment will be used to locate the executable.
110110

111-
- **Python** (`requirements.txt`) :
111+
- **Python** (`requirements.txt`, `pyproject.toml`) :
112112
<br >Set the full paths of the Python and the package installer for Python executables, which allows Exhort to locate
113113
and run the `pip3` commands to resolve dependencies for Python projects.
114114
<br >Python 2 executables `python` and `pip` can be used instead, if the `Use python 2.x` option is selected.
@@ -318,6 +318,21 @@ When modifying the grammar or lexer files, you need to regenerate the parser cla
318318
tokio = { version = "1.0", features = ["full"] } # trustify-da-ignore
319319
```
320320

321+
If you want to ignore vulnerabilities for a dependency in a `pyproject.toml` file, you must add `trustify-da-ignore` as a comment
322+
against the dependency in the manifest file.
323+
For PEP 621 format:
324+
```toml
325+
[project]
326+
dependencies = [
327+
"anyio==3.6.2", # trustify-da-ignore
328+
]
329+
```
330+
For Poetry format:
331+
```toml
332+
[tool.poetry.dependencies]
333+
anyio = "^3.6.2" # trustify-da-ignore
334+
```
335+
321336
- **Excluding developmental or test dependencies**
322337
<br >Red Hat Dependency Analytics does not analyze dependencies marked as `dev` or `test`, these dependencies are
323338
ignored.
@@ -365,6 +380,10 @@ When modifying the grammar or lexer files, you need to regenerate the parser cla
365380
You can create an alternative file to `requirements.txt`, for example, a `requirements-dev.txt` or
366381
a `requirements-test.txt` file where you can add the development or test dependencies there.
367382

383+
For `pyproject.toml`, dependencies from `[project.dependencies]` (PEP 621),
384+
`[project.optional-dependencies]`, and `[tool.poetry.dependencies]` are analyzed.
385+
Poetry group dependencies (`[tool.poetry.group.*.dependencies]`) are excluded.
386+
368387

369388
- **Excluding manifest files with patterns**
370389
<br >You can exclude specific manifest files from component analysis using configurable glob patterns. This feature allows you to avoid analyzing third-party dependencies, test files, or other manifests that are not relevant to your security analysis.

src/main/java/org/jboss/tools/intellij/componentanalysis/CAAnnotator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ public static String getPackageManager(String file) {
524524
case "pom.xml" -> "maven";
525525
case "package.json" -> "npm";
526526
case "go.mod" -> "go";
527-
case "requirements.txt" -> "python";
527+
case "requirements.txt", "pyproject.toml" -> "python";
528528
case "build.gradle", "build.gradle.kts" -> "gradle";
529529
case "Cargo.toml" -> "cargo";
530530
default -> null;

src/main/java/org/jboss/tools/intellij/componentanalysis/SAIntentionAction.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file
4949
|| "requirements.txt".equals(file.getName())
5050
|| "build.gradle".equals(file.getName())
5151
|| "build.gradle.kts".equals(file.getName())
52-
|| "Cargo.toml".equals(file.getName());
52+
|| "Cargo.toml".equals(file.getName())
53+
|| "pyproject.toml".equals(file.getName());
5354
}
5455

5556
@Override

src/main/java/org/jboss/tools/intellij/componentanalysis/cargo/CargoCAAnnotator.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ protected String getInspectionShortName() {
7070

7171
@Override
7272
protected Map<Dependency, List<PsiElement>> getDependencies(PsiFile file) {
73+
if (!"Cargo.toml".equals(file.getName())) {
74+
return Map.of();
75+
}
76+
7377
Map<Dependency, List<PsiElement>> resultMap = new HashMap<>();
7478

7579
Set<String> commentIgnoredDeps = getIgnoredDependencies(file);
@@ -381,4 +385,4 @@ private void parseFlatDependencies(TomlTable table, Set<String> ignoredDeps, Map
381385
resultMap.computeIfAbsent(dp, k -> new LinkedList<>()).add(keyValue);
382386
}
383387
}
384-
}
388+
}

0 commit comments

Comments
 (0)