Skip to content

Commit 3132c89

Browse files
authored
feat: include path dependencies in SBOM with repository_url=local qua… (#384)
…lifier ## Description Path dependencies (source == null in cargo metadata) are now included in the generated SBOM with a repository_url=local qualifier on their PURL, e.g. pkg:cargo/[email protected]?repository_url=local. This lets the backend distinguish local crates from registry packages and skip vulnerability checks for them, while still preserving the full dependency tree in the SBOM. **Related issue (if any):** fixes #issue_number_goes_here ## Checklist - [x] I have followed this repository's contributing guidelines. - [x] I will adhere to the project's code of conduct. ## Additional information > Anything else?
1 parent 0fef32a commit 3132c89

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.HashSet;
4747
import java.util.Map;
4848
import java.util.Set;
49+
import java.util.TreeMap;
4950
import java.util.concurrent.ExecutionException;
5051
import java.util.concurrent.ExecutorService;
5152
import java.util.concurrent.Executors;
@@ -285,8 +286,7 @@ void processWorkspaceDependencies(
285286
CargoPackage depPackage = findPackageByName(packageMap, depName);
286287
try {
287288
PackageURL depUrl =
288-
new PackageURL(
289-
Type.CARGO.getType(), null, depPackage.name(), depPackage.version(), null, null);
289+
createCargoPurl(depPackage.name(), depPackage.version(), depPackage.isPathDependency());
290290
sbom.addDependency(root, depUrl, null);
291291
} catch (Exception e) {
292292
log.warning("Failed to create PackageURL for workspace dependency: " + depName);
@@ -332,8 +332,7 @@ private void processWorkspaceMember(
332332

333333
try {
334334
PackageURL memberUrl =
335-
new PackageURL(
336-
Type.CARGO.getType(), null, memberPkg.name(), memberPkg.version(), null, null);
335+
createCargoPurl(memberPkg.name(), memberPkg.version(), memberPkg.isPathDependency());
337336
sbom.addDependency(workspaceRoot, memberUrl, null);
338337

339338
if (debugLoggingIsNeeded()) {
@@ -528,8 +527,7 @@ private void processDirectDependencies(
528527

529528
try {
530529
PackageURL packageUrl =
531-
new PackageURL(
532-
Type.CARGO.getType(), null, childInfo.name(), childInfo.version(), null, null);
530+
createCargoPurl(childInfo.name(), childInfo.version(), childInfo.isPathDependency());
533531
sbom.addDependency(sourceUrl, packageUrl, null);
534532
if (debugLoggingIsNeeded()) {
535533
log.info(
@@ -594,8 +592,7 @@ private void processDependencyNode(
594592

595593
try {
596594
PackageURL childUrl =
597-
new PackageURL(
598-
Type.CARGO.getType(), null, childInfo.name(), childInfo.version(), null, null);
595+
createCargoPurl(childInfo.name(), childInfo.version(), childInfo.isPathDependency());
599596

600597
String relationshipKey = parent.getCoordinates() + "->" + childUrl.getCoordinates();
601598

@@ -641,7 +638,7 @@ private Map<String, CargoPackage> buildPackageMap(CargoMetadata metadata) {
641638

642639
private DependencyInfo getPackageInfo(String packageId, Map<String, CargoPackage> packageMap) {
643640
CargoPackage pkg = packageMap.get(packageId);
644-
return new DependencyInfo(pkg.name(), pkg.version());
641+
return new DependencyInfo(pkg.name(), pkg.version(), pkg.source());
645642
}
646643

647644
public CargoProvider(Path manifest) {
@@ -821,4 +818,16 @@ private boolean lineContainsDependency(String trimmed, String depName) {
821818
}
822819
return false;
823820
}
821+
822+
/**
823+
* Creates a {@link PackageURL} for a Cargo package. Path dependencies ({@code source == null})
824+
* get a {@code repository_url=local} qualifier so the backend can distinguish them from registry
825+
* packages and skip vulnerability checks.
826+
*/
827+
private static PackageURL createCargoPurl(String name, String version, boolean isPathDep)
828+
throws Exception {
829+
TreeMap<String, String> qualifiers =
830+
isPathDep ? new TreeMap<>(Map.of("repository_url", "local")) : null;
831+
return new PackageURL(Type.CARGO.getType(), null, name, version, qualifiers, null);
832+
}
824833
}

src/main/java/io/github/guacsec/trustifyda/providers/rust/model/CargoPackage.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,12 @@ public record CargoPackage(
2424
@JsonProperty("name") String name,
2525
@JsonProperty("version") String version,
2626
@JsonProperty("id") String id,
27+
@JsonProperty("source") String source,
2728
@JsonProperty("manifest_path") String manifestPath,
28-
@JsonProperty("dependencies") List<CargoDependency> dependencies) {}
29+
@JsonProperty("dependencies") List<CargoDependency> dependencies) {
30+
31+
/** Path dependencies have {@code source == null} in cargo metadata. */
32+
public boolean isPathDependency() {
33+
return source == null;
34+
}
35+
}

src/main/java/io/github/guacsec/trustifyda/providers/rust/model/DependencyInfo.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,10 @@
1616
*/
1717
package io.github.guacsec.trustifyda.providers.rust.model;
1818

19-
public record DependencyInfo(String name, String version) {}
19+
public record DependencyInfo(String name, String version, String source) {
20+
21+
/** Path dependencies have {@code source == null} in cargo metadata. */
22+
public boolean isPathDependency() {
23+
return source == null;
24+
}
25+
}

0 commit comments

Comments
 (0)