Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
483248e
code changes for cargo package package identifier
crvreddy Sep 3, 2025
b1b50f9
Updated for identify right dependency
crvreddy Sep 10, 2025
b5ee6b7
Updated as per metadata.json file
crvreddy Sep 15, 2025
8fca48f
Updated code changes
crvreddy Sep 15, 2025
4b0ed7b
updated changes for cargo property
crvreddy Sep 16, 2025
c39f7af
Add Cargo package type support In Artifactory Uploader
Sep 16, 2025
9f2f052
added unit test
malavikakrishnan123 Sep 19, 2025
a299d4b
updated code for identify direct dependencies
crvreddy Sep 19, 2025
fee76d9
Added unit tests and integration tests for Cargo
Sep 19, 2025
7be7bc0
Updated CA_UsageDocument.md
Nikkireddy1 Sep 19, 2025
abbf173
Update CA_UsageDocument.md
Nikkireddy1 Sep 19, 2025
03a1628
Updated appSettings.json with Cargo
Nikkireddy1 Sep 19, 2025
42d59d4
Updated a few more tests for cargo
Sep 21, 2025
85b8fed
Merge branch 'test/PackageIdentifierCargoTests' of https://github.com…
Sep 21, 2025
b5740bf
sonar issues fix
crvreddy Sep 22, 2025
f658abc
Merge remote-tracking branch 'origin/feature/PackageIdentifierForCarg…
Sep 22, 2025
5264b9e
sonar issues fix
crvreddy Sep 22, 2025
1d92600
Merge remote-tracking branch 'origin/feature/PackageIdentifierForCarg…
Sep 22, 2025
2f3d7f7
Pushed UTs for BomHelper and DisplayInfo
Sep 22, 2025
09d8f31
Improved code coverage
Sep 23, 2025
37a7e15
Fixed the failing tests
Sep 23, 2025
eb6f3ef
updated for identify dev dependency
crvreddy Sep 23, 2025
844cd0f
changed nameing conversion
crvreddy Sep 23, 2025
f8e68a3
Added coverage and updated usage doc
Sep 23, 2025
3f0d9e6
Merge remote-tracking branch 'origin/feature/PackageIdentifierForCarg…
Sep 23, 2025
798076d
Merge branch 'development' into feature/PackageIdentifierForCargo
crvreddy Sep 23, 2025
7fc871d
Merge pull request #345 from siemens/test/PackageIdentifierCargoTests
crvreddy Sep 23, 2025
f915dfd
Added unit test
malavikakrishnan123 Sep 23, 2025
e158ecb
Merge branch 'feature/PackageIdentifierForCargo' into feature/Artifac…
Sep 24, 2025
4c0c9a2
unit test cases updated
crvreddy Sep 24, 2025
52ee303
integration test and unit test
malavikakrishnan123 Sep 26, 2025
611df53
removed the duplication code
malavikakrishnan123 Sep 29, 2025
2cec9f6
fixed unit test
malavikakrishnan123 Sep 30, 2025
338651d
fixed integration test
malavikakrishnan123 Sep 30, 2025
fedda6b
Merge branch 'feature/PackageIdentifierForCargo' into feature/Artifac…
sumanthkb44 Oct 5, 2025
a3d17c1
updated change cli
crvreddy Oct 6, 2025
23265d2
removed empty statement
malavikakrishnan123 Oct 6, 2025
9962c65
Merge branch 'feature/ArtifactoryUploader_ForCargo' of https://github…
malavikakrishnan123 Oct 6, 2025
6d6565a
fixed the maintainability issue
malavikakrishnan123 Oct 6, 2025
d0be70d
Merge branch 'feature/PackageIdentifierForCargo' into feature/Artifac…
crvreddy Oct 7, 2025
4a5d79e
Merge pull request #355 from siemens/feature/ArtifactoryUploader_ForC…
crvreddy Oct 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11,437 changes: 11,437 additions & 0 deletions TestFiles/IntegrationTestFiles/SpdxTestFiles/Cargo/Cargo.spdx.sbom.json

Large diffs are not rendered by default.

Large diffs are not rendered by default.

21 changes: 16 additions & 5 deletions doc/UsageDoc/CA_UsageDocument.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@


# Introduction
Welcome to the Continuous Clearing Tool, your automated solution for streamlining the SW360 clearing process. Designed with Project Managers and Developers in mind, this tool efficiently manages third-party components across various platforms, including NPM, NuGet, Maven, Python, Conan, Alpine, and Debian.
Welcome to the Continuous Clearing Tool, your automated solution for streamlining the SW360 clearing process. Designed with Project Managers and Developers in mind, this tool efficiently manages third-party components across various platforms, including NPM, NuGet, Maven, Python, Conan, Cargo, Alpine, and Debian.

## Key Features
- **Automated Scanning and Identification**: The tool automatically scans and identifies third-party components in your projects.
Expand All @@ -77,17 +77,17 @@ Simply integrate the Continuous Clearing Tool into your project workflow to expe

# Continuous Clearing Tool workflow diagram
* Package Identifier
* [NPM/NUGET/MAVEN/PYTHON/CONAN](../usagedocimg/packageIdentifiernpmnuget.PNG)
* [NPM/NUGET/MAVEN/PYTHON/CONAN/CARGO](../usagedocimg/packageIdentifiernpmnuget.PNG)
* [Debian/Alpine](../usagedocimg/packageIdentifierdebianalpine.PNG)
* [BasicSBOM](../usagedocimg/PackageidentifierBasicSBOMflowdiagram.png)

* SW360 Package Creator
* [NPM/NUGET/MAVEN/PYTHON/CONAN](../usagedocimg/packageCreatirnpmnuget.PNG)
* [NPM/NUGET/MAVEN/PYTHON/CONAN/CARGO](../usagedocimg/packageCreatirnpmnuget.PNG)
* [Debian](../usagedocimg/packagecreatordebian.PNG)
* [Alpine](../usagedocimg/ComponentcreaterforAlpine.PNG)

* Artifactory Uploader
* [NPM/NUGET/MAVEN/PYTHON/CONAN](../usagedocimg/artifactoryuploader.PNG)
* [NPM/NUGET/MAVEN/PYTHON/CONAN?CARGO](../usagedocimg/artifactoryuploader.PNG)

# Prerequisite
To ensure a smooth operation of the Continuous Clearing Tool, please follow these prerequisites:
Expand Down Expand Up @@ -196,6 +196,17 @@ Users have the flexibility to generate a basic SBOM even if connections to SW360
* **Project Type :** **Conan**

* Input file repository should contain **conan.lock** file.

* **Project Type :** **Cargo**

* Run the command given below (i.e., To generate a metadata file for your project, run the following command in your project directory (where your Cargo.toml is located)) .

* For creating metadata.json file you can use the format version 1.

**Example**: cargo metadata --format-version 1 > cargo.metadata.json
After successful execution, *.metadata.json file will be created in specified directory .

Resulted cargo.metadata.json file will be having the list of installed packages and the same file will be used as an input to Continuous clearing tool - Package identifier via the input directory parameter. The remaining process is same as other project types.

* **Project Type :** **Debian & Alpine**

Expand Down Expand Up @@ -254,7 +265,7 @@ Description for the settings in appSettings.json file
| S.No | Argument Name | Description | Mandatory | Example |
| ---- | ----------------------------------------- | ------------------------------------------------------------- | --------------- | ------------------------------------------------------------------------ |
| 1 | TimeOut | Timeout in seconds | No | 400 |
| 2 | ProjectType | Type of the project | Yes | `Nuget`, `NPM`, `Poetry`, `Conan`, `Alpine`, `Debian`, `Maven` |
| 2 | ProjectType | Type of the project | Yes | `Nuget`, `NPM`, `Poetry`, `Conan`, `Alpine`, `Debian`, `Maven`, `Cargo` |
| 3 | MultipleProjectType | Whether multiple project types are supported | No | `False` |
| 4 | Telemetry.Enable | Enable telemetry | No | `False` |
| 5 | Telemetry.ApplicationInsightsConnectionString | Application Insights instrumentation key | No | `123-456-789-123-123` |
Expand Down
238 changes: 238 additions & 0 deletions src/AritfactoryUploader.UTest/PackageUploadHelperTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public void GetComponentListFromComparisonBOM_GivenComparisonBOM_ReturnsComponen
[TestCase("DEBIAN", ".deb")]
[TestCase("POETRY", ".whl")]
[TestCase("CONAN", "package.tgz")]
[TestCase("CARGO", ".crate")]
public void GetPkgeNameExtensionBasedOnComponentType_GivenType_ReturnsPkgNameExtension(string type, string extension)
{
// Arrange
Expand Down Expand Up @@ -212,6 +213,7 @@ public void GetJfrogApiCommInstance_GivenComponentWithUnknownType_ReturnsJfrogAp
[TestCase("POETRY")]
[TestCase("CONAN")]
[TestCase("DEBIAN")]
[TestCase("CARGO")]
public async Task JfrogNotFoundPackagesAsync_CoversAllScenarios(string compType)
{
// Arrange
Expand All @@ -224,6 +226,7 @@ public async Task JfrogNotFoundPackagesAsync_CoversAllScenarios(string compType)
displayPackagesInfo.JfrogNotFoundPackagesPython = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogNotFoundPackagesConan = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogNotFoundPackagesDebian = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogNotFoundPackagesCargo = new List<ComponentsToArtifactory>();

// Act
await PackageUploadHelper.JfrogNotFoundPackagesAsync(item, displayPackagesInfo);
Expand Down Expand Up @@ -259,6 +262,11 @@ public async Task JfrogNotFoundPackagesAsync_CoversAllScenarios(string compType)
Assert.AreEqual(1, displayPackagesInfo.JfrogNotFoundPackagesDebian.Count);
Assert.That(displayPackagesInfo.JfrogNotFoundPackagesDebian[0], Is.Not.Null);
}
else if (item.ComponentType == "CARGO")
{
Assert.AreEqual(1, displayPackagesInfo.JfrogNotFoundPackagesCargo.Count);
Assert.That(displayPackagesInfo.JfrogNotFoundPackagesCargo[0], Is.Not.Null);
}
}

[Test]
Expand All @@ -268,6 +276,7 @@ public async Task JfrogNotFoundPackagesAsync_CoversAllScenarios(string compType)
[TestCase("POETRY")]
[TestCase("CONAN")]
[TestCase("DEBIAN")]
[TestCase("CARGO")]
public async Task JfrogFoundPackagesAsync_CoversAllScenarios(string compType)
{
// Arrange
Expand All @@ -280,6 +289,7 @@ public async Task JfrogFoundPackagesAsync_CoversAllScenarios(string compType)
displayPackagesInfo.JfrogFoundPackagesPython = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogFoundPackagesConan = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogFoundPackagesDebian = new List<ComponentsToArtifactory>();
displayPackagesInfo.JfrogFoundPackagesCargo = new List<ComponentsToArtifactory>();
var operationType = "operationType";
var responseMessage = new HttpResponseMessage();
var dryRunSuffix = "dryRunSuffix";
Expand Down Expand Up @@ -318,6 +328,234 @@ public async Task JfrogFoundPackagesAsync_CoversAllScenarios(string compType)
Assert.AreEqual(1, displayPackagesInfo.JfrogFoundPackagesDebian.Count);
Assert.That(displayPackagesInfo.JfrogFoundPackagesDebian[0], Is.Not.Null);
}
else if (item.ComponentType == "CARGO")
{
Assert.AreEqual(1, displayPackagesInfo.JfrogFoundPackagesCargo.Count);
Assert.That(displayPackagesInfo.JfrogFoundPackagesCargo[0], Is.Not.Null);
}
}

[Test]
public async Task JfrogNotFoundPackagesAsync_CargoComponent_AddsToCargoNotFoundList()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "serde",
Version = "1.0.150",
Purl = "pkg:cargo/[email protected]",
SrcRepoName = "cargo-src-repo",
DestRepoName = "cargo-dest-repo",
PackageType = PackageType.ClearedThirdParty
};
var displayPackagesInfo = new DisplayPackagesInfo();
displayPackagesInfo.JfrogNotFoundPackagesCargo = new List<ComponentsToArtifactory>();

// Act
await PackageUploadHelper.JfrogNotFoundPackagesAsync(cargoItem, displayPackagesInfo);

// Assert
Assert.AreEqual(1, displayPackagesInfo.JfrogNotFoundPackagesCargo.Count);
var addedComponent = displayPackagesInfo.JfrogNotFoundPackagesCargo[0];
Assert.AreEqual("serde", addedComponent.Name);
Assert.AreEqual("1.0.150", addedComponent.Version);
Assert.AreEqual("pkg:cargo/[email protected]", addedComponent.Purl);
Assert.AreEqual("cargo-src-repo", addedComponent.SrcRepoName);
Assert.AreEqual(PackageType.ClearedThirdParty, addedComponent.PackageType);
}

[Test]
public async Task JfrogFoundPackagesAsync_CargoComponent_AddsToCargoFoundList()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "tokio",
Version = "1.23.0",
Purl = "pkg:cargo/[email protected]",
SrcRepoName = "cargo-src-repo",
DestRepoName = "cargo-dest-repo",
Token = "test-token",
CopyPackageApiUrl = "https://test.api.url",
PackageName = "tokio-1.23.0.crate",
PackageType = PackageType.ClearedThirdParty
};
var displayPackagesInfo = new DisplayPackagesInfo();
displayPackagesInfo.JfrogFoundPackagesCargo = new List<ComponentsToArtifactory>();
var operationType = "copy";
var responseMessage = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var dryRunSuffix = "";

// Act
await PackageUploadHelper.JfrogFoundPackagesAsync(cargoItem, displayPackagesInfo, operationType, responseMessage, dryRunSuffix);

// Assert
Assert.AreEqual(1, displayPackagesInfo.JfrogFoundPackagesCargo.Count);
var addedComponent = displayPackagesInfo.JfrogFoundPackagesCargo[0];
Assert.AreEqual("tokio", addedComponent.Name);
Assert.AreEqual("1.23.0", addedComponent.Version);
Assert.AreEqual("pkg:cargo/[email protected]", addedComponent.Purl);
Assert.AreEqual("cargo-src-repo", addedComponent.SrcRepoName);
Assert.AreEqual("cargo-dest-repo", addedComponent.DestRepoName);
Assert.AreEqual("copy", addedComponent.OperationType);
Assert.AreEqual(responseMessage, addedComponent.ResponseMessage);
Assert.AreEqual("test-token", addedComponent.Token);
Assert.AreEqual("tokio-1.23.0.crate", addedComponent.PackageName);
Assert.AreEqual(PackageType.ClearedThirdParty, addedComponent.PackageType);
}

[Test]
public void GetPackageNameExtensionBasedOnComponentType_CargoComponent_ReturnsCorrectExtension()
{
// Arrange
var cargoPackage = new ComponentsToArtifactory
{
ComponentType = "CARGO"
};

// Act
var extension = PackageUploadHelper.GetPackageNameExtensionBasedOnComponentType(cargoPackage);

// Assert
Assert.AreEqual(".crate", extension);
}

[Test]
public void GetPackageNameExtensionBasedOnComponentType_CargoComponentCaseInsensitive_ReturnsCorrectExtension()
{
// Arrange
var cargoPackage = new ComponentsToArtifactory
{
ComponentType = "cargo" // lowercase
};

// Act
var extension = PackageUploadHelper.GetPackageNameExtensionBasedOnComponentType(cargoPackage);

// Assert
Assert.AreEqual(".crate", extension);
}

[Test]
public void JfrogNotFoundPackagesAsync_CargoComponentWithNullDisplayInfo_ThrowsNullReferenceException()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "regex",
Version = "1.7.0"
};

// Act & Assert
Assert.ThrowsAsync<System.NullReferenceException>(async () =>
await PackageUploadHelper.JfrogNotFoundPackagesAsync(cargoItem, null));
}

[Test]
public void JfrogFoundPackagesAsync_CargoComponentWithNullDisplayInfo_ThrowsNullReferenceException()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "clap",
Version = "4.0.0"
};
var operationType = "move";
var responseMessage = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var dryRunSuffix = "";

// Act & Assert
Assert.ThrowsAsync<System.NullReferenceException>(async () =>
await PackageUploadHelper.JfrogFoundPackagesAsync(cargoItem, null, operationType, responseMessage, dryRunSuffix));
}

[Test]
public async Task JfrogFoundPackagesAsync_CargoComponentWithNullResponseMessage_StillAddsToList()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "rand",
Version = "0.8.5"
};
var displayPackagesInfo = new DisplayPackagesInfo();
displayPackagesInfo.JfrogFoundPackagesCargo = new List<ComponentsToArtifactory>();
var operationType = "copy";
HttpResponseMessage responseMessage = null;
var dryRunSuffix = "dry-run";

// Act
await PackageUploadHelper.JfrogFoundPackagesAsync(cargoItem, displayPackagesInfo, operationType, responseMessage, dryRunSuffix);

// Assert
Assert.AreEqual(1, displayPackagesInfo.JfrogFoundPackagesCargo.Count);
var addedComponent = displayPackagesInfo.JfrogFoundPackagesCargo[0];
Assert.AreEqual("rand", addedComponent.Name);
Assert.AreEqual("0.8.5", addedComponent.Version);
Assert.AreEqual("copy", addedComponent.OperationType);
Assert.IsNull(addedComponent.ResponseMessage);
Assert.AreEqual("dry-run", addedComponent.DryRunSuffix);
}

[Test]
public async Task JfrogNotFoundPackagesAsync_CargoComponentWithEmptyName_AddsComponentWithEmptyName()
{
// Arrange
var cargoItem = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "",
Version = "1.0.0",
Purl = "pkg:cargo/@1.0.0"
};
var displayPackagesInfo = new DisplayPackagesInfo();
displayPackagesInfo.JfrogNotFoundPackagesCargo = new List<ComponentsToArtifactory>();

// Act
await PackageUploadHelper.JfrogNotFoundPackagesAsync(cargoItem, displayPackagesInfo);

// Assert
Assert.AreEqual(1, displayPackagesInfo.JfrogNotFoundPackagesCargo.Count);
var addedComponent = displayPackagesInfo.JfrogNotFoundPackagesCargo[0];
Assert.AreEqual("", addedComponent.Name);
Assert.AreEqual("1.0.0", addedComponent.Version);
}

[Test]
public async Task JfrogFoundPackagesAsync_CargoComponentMultipleCalls_AddsMultipleComponents()
{
// Arrange
var cargoItem1 = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "serde",
Version = "1.0.150"
};
var cargoItem2 = new ComponentsToArtifactory
{
ComponentType = "CARGO",
Name = "tokio",
Version = "1.23.0"
};
var displayPackagesInfo = new DisplayPackagesInfo();
displayPackagesInfo.JfrogFoundPackagesCargo = new List<ComponentsToArtifactory>();
var operationType = "move";
var responseMessage = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
var dryRunSuffix = "";

// Act
await PackageUploadHelper.JfrogFoundPackagesAsync(cargoItem1, displayPackagesInfo, operationType, responseMessage, dryRunSuffix);
await PackageUploadHelper.JfrogFoundPackagesAsync(cargoItem2, displayPackagesInfo, operationType, responseMessage, dryRunSuffix);

// Assert
Assert.AreEqual(2, displayPackagesInfo.JfrogFoundPackagesCargo.Count);
Assert.AreEqual("serde", displayPackagesInfo.JfrogFoundPackagesCargo[0].Name);
Assert.AreEqual("tokio", displayPackagesInfo.JfrogFoundPackagesCargo[1].Name);
}


Expand Down
Loading