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);
}