diff --git a/src/DemaConsulting.SpdxTool/SelfValidation/Validate.cs b/src/DemaConsulting.SpdxTool/SelfValidation/Validate.cs index f6d10ee..7ddd118 100644 --- a/src/DemaConsulting.SpdxTool/SelfValidation/Validate.cs +++ b/src/DemaConsulting.SpdxTool/SelfValidation/Validate.cs @@ -62,6 +62,7 @@ public static void Run(Context context) ValidateCopyPackage.Run(context, results); ValidateFindPackage.Run(context, results); ValidateGetVersion.Run(context, results); + ValidateNtia.Run(context, results); ValidateQuery.Run(context, results); ValidateRenameId.Run(context, results); ValidateUpdatePackage.Run(context, results); diff --git a/src/DemaConsulting.SpdxTool/SelfValidation/ValidateNtia.cs b/src/DemaConsulting.SpdxTool/SelfValidation/ValidateNtia.cs new file mode 100644 index 0000000..85db22f --- /dev/null +++ b/src/DemaConsulting.SpdxTool/SelfValidation/ValidateNtia.cs @@ -0,0 +1,204 @@ +// Copyright (c) 2024 DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using DemaConsulting.TestResults; + +namespace DemaConsulting.SpdxTool.SelfValidation; + +/// +/// Self-validation of NTIA validation +/// +internal static class ValidateNtia +{ + /// + /// Run validation test + /// + /// Program context + /// Test results + public static void Run(Context context, TestResults.TestResults results) + { + var passed = DoValidate(); + + // Report validation result + context.WriteLine($"- SpdxTool_Ntia: {(passed ? "Passed" : "Failed")}"); + results.Results.Add( + new TestResult + { + Name = "SpdxTool_Ntia", + ClassName = "DemaConsulting.SpdxTool.SelfValidation.ValidateNtia", + ComputerName = Environment.MachineName, + StartTime = DateTime.Now, + Outcome = passed ? TestOutcome.Passed : TestOutcome.Failed + }); + } + + /// + /// Do the validation + /// + /// True on success + private static bool DoValidate() + { + try + { + // Create the temporary validation folder + Directory.CreateDirectory("validate.tmp"); + + // Run individual validation tests + return DoValidateMissingSupplier() && DoValidateCompliant(); + } + finally + { + // Delete the temporary validation folder + Directory.Delete("validate.tmp", true); + } + } + + /// + /// Validate that NTIA validation detects missing supplier + /// + /// True on success + private static bool DoValidateMissingSupplier() + { + // Write test SPDX file that is valid but not NTIA compliant + // Missing: supplier field for the package + File.WriteAllText("validate.tmp/test-ntia.spdx.json", + """ + { + "files": [], + "packages": [ + { + "SPDXID": "SPDXRef-Package", + "name": "Test Package", + "versionInfo": "1.0.0", + "downloadLocation": "https://github.com/demaconsulting/SpdxTool", + "filesAnalyzed": false, + "licenseConcluded": "MIT" + } + ], + "relationships": [ + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relatedSpdxElement": "SPDXRef-Package", + "relationshipType": "DESCRIBES" + } + ], + "spdxVersion": "SPDX-2.2", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "name": "Test Document", + "documentNamespace": "https://sbom.spdx.org", + "creationInfo": { + "created": "2021-10-01T00:00:00Z", + "creators": [ "Person: Malcolm Nixon" ] + } + } + """); + + // Run validation without NTIA flag - should succeed + var exitCode1 = Validate.RunSpdxTool( + "validate.tmp", + [ + "--silent", + "validate", + "test-ntia.spdx.json" + ]); + + // Fail if SpdxTool reported an error + if (exitCode1 != 0) + return false; + + // Run validation with NTIA flag - should fail due to missing supplier + // The log file will be written to validate.tmp/output.log since the working directory is changed + var exitCode2 = Validate.RunSpdxTool( + "validate.tmp", + [ + "--log", "output.log", + "validate", + "test-ntia.spdx.json", + "ntia" + ]); + + // Should fail validation + if (exitCode2 == 0) + return false; + + // Read the log file and verify it contains the expected error + var log = File.ReadAllText("validate.tmp/output.log"); + if (!log.Contains("NTIA: Package 'Test Package' Missing Supplier")) + return false; + + return true; + } + + /// + /// Validate that NTIA validation passes for compliant document + /// + /// True on success + private static bool DoValidateCompliant() + { + // Write test SPDX file that is NTIA compliant + File.WriteAllText("validate.tmp/test-ntia-valid.spdx.json", + """ + { + "files": [], + "packages": [ + { + "SPDXID": "SPDXRef-Package", + "name": "Test Package", + "versionInfo": "1.0.0", + "supplier": "Organization: Test", + "downloadLocation": "https://github.com/demaconsulting/SpdxTool", + "filesAnalyzed": false, + "licenseConcluded": "MIT" + } + ], + "relationships": [ + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relatedSpdxElement": "SPDXRef-Package", + "relationshipType": "DESCRIBES" + } + ], + "spdxVersion": "SPDX-2.2", + "dataLicense": "CC0-1.0", + "SPDXID": "SPDXRef-DOCUMENT", + "name": "Test Document", + "documentNamespace": "https://sbom.spdx.org", + "creationInfo": { + "created": "2021-10-01T00:00:00Z", + "creators": [ "Person: Malcolm Nixon" ] + } + } + """); + + // Run validation with NTIA flag on valid document - should succeed + var exitCode = Validate.RunSpdxTool( + "validate.tmp", + [ + "--silent", + "validate", + "test-ntia-valid.spdx.json", + "ntia" + ]); + + // Should pass validation + return exitCode == 0; + } +} diff --git a/test/DemaConsulting.SpdxTool.Tests/SelfValidationTests.cs b/test/DemaConsulting.SpdxTool.Tests/SelfValidationTests.cs index 37d04b1..8f96a9e 100644 --- a/test/DemaConsulting.SpdxTool.Tests/SelfValidationTests.cs +++ b/test/DemaConsulting.SpdxTool.Tests/SelfValidationTests.cs @@ -98,12 +98,13 @@ public void SelfValidation_TrxResults() Assert.Contains("SpdxTool_CopyPackage", results); Assert.Contains("SpdxTool_FindPackage", results); Assert.Contains("SpdxTool_GetVersion", results); + Assert.Contains("SpdxTool_Ntia", results); Assert.Contains("SpdxTool_Query", results); Assert.Contains("SpdxTool_RenameId", results); Assert.Contains("SpdxTool_UpdatePackage", results); Assert.Contains(""" - + """, results); }