Skip to content

Commit 2d8adec

Browse files
authored
doc: add missing doc for Rust support (#306)
doc: add missing doc for Rust support --------- Signed-off-by: Chao Wang <chaowan@redhat.com>
1 parent 8bc453f commit 2d8adec

File tree

3 files changed

+88
-21
lines changed

3 files changed

+88
-21
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,7 @@ public class TrustifyExample {
172172
<li><a href="https://go.dev//">Golang</a> - <a href="https://go.dev/blog/using-go-modules//">Go Modules</a></li>
173173
<li><a href="https://go.dev//">Python</a> - <a href="https://pypi.org/project/pip//">pip Installer</a></li>
174174
<li><a href="https://gradle.org//">Gradle</a> - <a href="https://gradle.org/install//">Gradle Installation</a></li>
175+
<li><a href="https://www.rust-lang.org/">Rust</a> - <a href="https://doc.rust-lang.org/cargo/">Cargo</a></li>
175176

176177
</ul>
177178

@@ -315,6 +316,19 @@ test {
315316
```
316317
</li>
317318

319+
<li>
320+
<em>Rust Cargo</em> users can add a comment with #trustify-da-ignore next to the package to be ignored in <em>Cargo.toml</em>:
321+
322+
```toml
323+
[dependencies]
324+
serde = "1.0.136" # trustify-da-ignore
325+
tokio = { version = "1.0", features = ["full"] }
326+
327+
[workspace.dependencies]
328+
regex = "1.5.4" # trustify-da-ignore
329+
```
330+
</li>
331+
318332
</ul>
319333

320334
#### Ignore Strategies - experimental
@@ -337,6 +351,7 @@ System.setProperty("TRUSTIFY_DA_PNPM_PATH", "/path/to/custom/pnpm");
337351
System.setProperty("TRUSTIFY_DA_YARN_PATH", "/path/to/custom/yarn");
338352
System.setProperty("TRUSTIFY_DA_GO_PATH", "/path/to/custom/go");
339353
System.setProperty("TRUSTIFY_DA_GRADLE_PATH", "/path/to/custom/gradle");
354+
System.setProperty("TRUSTIFY_DA_CARGO_PATH", "/path/to/custom/cargo");
340355
//python - python3, pip3 take precedence if python version > 3 installed
341356
System.setProperty("TRUSTIFY_DA_PYTHON3_PATH", "/path/to/python3");
342357
System.setProperty("TRUSTIFY_DA_PIP3_PATH", "/path/to/pip3");
@@ -452,6 +467,11 @@ following keys for setting custom paths for the said executables.
452467
<td><em>pip</em></td>
453468
<td>TRUSTIFY_DA_PIP_PATH</td>
454469
</tr>
470+
<tr>
471+
<td><a href="https://doc.rust-lang.org/cargo/">Cargo Package Manager</a></td>
472+
<td><em>cargo</em></td>
473+
<td>TRUSTIFY_DA_CARGO_PATH</td>
474+
</tr>
455475

456476
</table>
457477

@@ -653,6 +673,9 @@ java -jar trustify-da-java-client-cli.jar component /path/to/requirements.txt
653673
# Component analysis with summary
654674
java -jar trustify-da-java-client-cli.jar component /path/to/go.mod --summary
655675

676+
# Rust Cargo analysis
677+
java -jar trustify-da-java-client-cli.jar stack /path/to/Cargo.toml --summary
678+
656679
# Container image analysis with JSON output (default)
657680
java -jar trustify-da-java-client-cli.jar image nginx:latest
658681

src/main/java/io/github/guacsec/trustifyda/providers/CargoProvider.java

Lines changed: 64 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,12 @@
4545
import java.util.HashSet;
4646
import java.util.Map;
4747
import java.util.Set;
48+
import java.util.concurrent.ExecutionException;
49+
import java.util.concurrent.ExecutorService;
50+
import java.util.concurrent.Executors;
51+
import java.util.concurrent.Future;
4852
import java.util.concurrent.TimeUnit;
53+
import java.util.concurrent.TimeoutException;
4954
import java.util.logging.Logger;
5055
import org.tomlj.Toml;
5156
import org.tomlj.TomlParseResult;
@@ -341,23 +346,64 @@ private CargoMetadata executeCargoMetadata() throws IOException, InterruptedExce
341346
.directory(workingDir.toFile())
342347
.start();
343348

349+
// Use bounded executor to read streams concurrently to avoid two potential deadlocks:
350+
// 1. buffer deadlock (process blocks on write when output buffers fill up while Java waits for
351+
// process completion)
352+
// 2. stalled process deadlock (readAllBytes() hangs forever when cargo process stalls
353+
// completely with no timeout protection)
354+
// Bounded executor allows proper cancellation and cleanup vs CompletableFuture common pool
355+
ExecutorService streamExecutor = Executors.newFixedThreadPool(2);
344356
String output;
345-
try (InputStream is = process.getInputStream()) {
346-
output = new String(is.readAllBytes(), StandardCharsets.UTF_8);
347-
}
357+
String errorOutput;
358+
359+
try {
360+
Future<String> outputFuture =
361+
streamExecutor.submit(
362+
() -> {
363+
try (InputStream is = process.getInputStream()) {
364+
return new String(is.readAllBytes(), StandardCharsets.UTF_8);
365+
} catch (IOException e) {
366+
log.warning("Failed to read stdout from cargo metadata: " + e.getMessage());
367+
return "";
368+
}
369+
});
370+
371+
Future<String> errorFuture =
372+
streamExecutor.submit(
373+
() -> {
374+
try (InputStream is = process.getErrorStream()) {
375+
return new String(is.readAllBytes(), StandardCharsets.UTF_8);
376+
} catch (IOException e) {
377+
log.warning("Failed to read stderr from cargo metadata: " + e.getMessage());
378+
return "";
379+
}
380+
});
381+
382+
boolean finished = process.waitFor(TIMEOUT, TimeUnit.SECONDS);
383+
384+
if (!finished) {
385+
process.destroyForcibly();
386+
outputFuture.cancel(true);
387+
errorFuture.cancel(true);
388+
throw new InterruptedException("cargo metadata timed out after " + TIMEOUT + " seconds");
389+
}
348390

349-
boolean finished = process.waitFor(TIMEOUT, TimeUnit.SECONDS);
391+
try {
392+
// Short timeout since process already finished
393+
output = outputFuture.get(1, TimeUnit.SECONDS);
394+
errorOutput = errorFuture.get(1, TimeUnit.SECONDS);
395+
} catch (ExecutionException | TimeoutException e) {
396+
log.warning("Failed to read process output: " + e.getMessage());
397+
return null;
398+
}
399+
} finally {
400+
streamExecutor.shutdownNow();
401+
}
350402

403+
// Safe to call exitValue() - we confirmed the process finished
351404
int exitCode = process.exitValue();
352405

353406
if (exitCode != 0) {
354-
String errorOutput = "";
355-
try (InputStream errorStream = process.getErrorStream()) {
356-
errorOutput = new String(errorStream.readAllBytes(), StandardCharsets.UTF_8);
357-
} catch (IOException e) {
358-
log.warning("Failed to read error stream: " + e.getMessage());
359-
}
360-
361407
String errorMessage = "cargo metadata failed with exit code: " + exitCode;
362408
if (!errorOutput.isEmpty()) {
363409
errorMessage += ". Error: " + errorOutput.trim();
@@ -373,11 +419,6 @@ private CargoMetadata executeCargoMetadata() throws IOException, InterruptedExce
373419
return null;
374420
}
375421

376-
if (!finished) {
377-
process.destroyForcibly();
378-
throw new InterruptedException("cargo metadata timed out after " + TIMEOUT + " seconds");
379-
}
380-
381422
try {
382423
CargoMetadata metadata = MAPPER.readValue(output, CargoMetadata.class);
383424
if (debugLoggingIsNeeded()) {
@@ -552,12 +593,14 @@ private DependencyInfo getPackageInfo(String packageId, Map<String, CargoPackage
552593
public CargoProvider(Path manifest) {
553594
super(Type.CARGO, manifest);
554595
this.cargoExecutable = Operations.getExecutable("cargo", "--version");
555-
if (cargoExecutable != null) {
556-
log.info("Found cargo executable: " + cargoExecutable);
557-
} else {
558-
log.warning("Cargo executable not found - dependency analysis will not work");
596+
if (debugLoggingIsNeeded()) {
597+
if (cargoExecutable != null) {
598+
log.info("Found cargo executable: " + cargoExecutable);
599+
} else {
600+
log.warning("Cargo executable not found - dependency analysis will not work");
601+
}
602+
log.info("Initialized RustProvider for manifest: " + manifest);
559603
}
560-
log.info("Initialized RustProvider for manifest: " + manifest);
561604
}
562605

563606
@Override

src/main/resources/cli_help.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ EXAMPLES:
4242
java -jar trustify-da-java-client-cli.jar stack /path/to/package.json --summary
4343
java -jar trustify-da-java-client-cli.jar stack /path/to/build.gradle --html
4444
java -jar trustify-da-java-client-cli.jar component /path/to/requirements.txt
45+
java -jar trustify-da-java-client-cli.jar stack /path/to/Cargo.toml
4546

4647
# Container image analysis
4748
java -jar trustify-da-java-client-cli.jar image nginx:latest

0 commit comments

Comments
 (0)