diff --git a/.editorconfig b/.editorconfig
index f3253fb..2e3a15c 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -47,13 +47,6 @@ csharp_style_expression_bodied_accessors = true:silent
csharp_style_expression_bodied_lambdas = true:silent
csharp_style_expression_bodied_local_functions = false:silent
-# Dotnet code style settings:
-[*.{cs,vb}]
-
-# Sort using and Import directives with System.* appearing first
-dotnet_sort_system_directives_first = true
-dotnet_separate_import_directive_groups = false
-
# Naming Conventions
dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning
dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
diff --git a/.github/agents/code-quality-agent.md b/.github/agents/code-quality-agent.md
index 826dbd7..487a9b9 100644
--- a/.github/agents/code-quality-agent.md
+++ b/.github/agents/code-quality-agent.md
@@ -38,7 +38,9 @@ Ensure the project is:
3. **Static Analysis**:
- Microsoft.CodeAnalysis.NetAnalyzers
- SonarAnalyzer.CSharp
-4. **Tests**: All validation tests passing
+4. **Requirements Traceability**:
+ - `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce`
+5. **Tests**: All validation tests passing
### SpdxTool-Specific
@@ -59,8 +61,13 @@ dotnet build --configuration Release
dotnet run --project src/DemaConsulting.SpdxTool \
--configuration Release --framework net10.0 --no-build -- --validate
-# Run unit tests
-dotnet test --configuration Release
+# Requirements enforcement
+dotnet reqstream --requirements requirements.yaml \
+ --tests "test-results/**/*.trx" --enforce
+
+# Run all linters
+./lint.sh # Linux/macOS
+lint.bat # Windows
```
## Defer To
diff --git a/.github/agents/requirements-agent.md b/.github/agents/requirements-agent.md
index f2d02dc..12f6a4c 100644
--- a/.github/agents/requirements-agent.md
+++ b/.github/agents/requirements-agent.md
@@ -11,7 +11,7 @@ Develop and maintain high-quality requirements with proper test coverage linkage
Invoke the requirements-agent for:
-- Identifying missing or unclear requirements
+- Creating new requirements in `requirements.yaml`
- Reviewing and improving existing requirements
- Ensuring requirements have appropriate test coverage
- Determining which type of test (unit, integration, or self-validation) is appropriate
@@ -27,6 +27,15 @@ Invoke the requirements-agent for:
- Use clear, testable language with measurable acceptance criteria
- Each requirement should be traceable to test evidence
+### Requirements Format
+
+Follow the `requirements.yaml` structure:
+
+- Clear ID and description
+- Justification explaining why the requirement is needed
+- Linked to appropriate test(s)
+- Enforced via: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce`
+
### Test Coverage Strategy
- **All requirements MUST be linked to tests** - this is enforced in CI
diff --git a/.github/agents/software-developer.md b/.github/agents/software-developer.md
index 0386581..7c173ad 100644
--- a/.github/agents/software-developer.md
+++ b/.github/agents/software-developer.md
@@ -65,6 +65,7 @@ var results = ProcessFile(options.InputFile);
- These tests ship with the product and run via `--validate` flag
- Must support TRX/JUnit output format
- Located in `src/DemaConsulting.SpdxTool/SelfValidation/`
+- Link to requirements in `requirements.yaml`
## Defer To
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 7be8539..3fdb273 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -58,6 +58,12 @@ jobs:
# This section runs all quality checks for the project.
# Downstream projects: Add any additional quality checks here.
+ - name: Run markdown linter
+ uses: DavidAnson/markdownlint-cli2-action@v22
+ with:
+ config: .markdownlint-cli2.jsonc
+ globs: '**/*.md'
+
- name: Run spell checker
uses: streetsidesoftware/cspell-action@v8
with:
@@ -69,12 +75,6 @@ jobs:
**/*.yaml
**/*.yml
- - name: Run markdown linter
- uses: DavidAnson/markdownlint-cli2-action@v22
- with:
- config: .markdownlint-cli2.jsonc
- globs: '**/*.md'
-
- name: Run YAML linter
uses: ibiqlik/action-yamllint@v3
with:
@@ -98,7 +98,7 @@ jobs:
strategy:
matrix:
- os: [ubuntu-latest, windows-latest]
+ os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
@@ -134,7 +134,8 @@ jobs:
run: |
mkdir -p artifacts
echo "Capturing tool versions..."
- OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/')
+ # Create short job ID: build-windows, build-ubuntu, build-macos
+ OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/-latest//')
JOB_ID="build-${OS_SHORT}"
dotnet versionmark --capture --job-id "${JOB_ID}" \
--output "artifacts/versionmark-${JOB_ID}.json" -- \
@@ -310,7 +311,7 @@ jobs:
strategy:
matrix:
- os: [windows-latest, ubuntu-latest]
+ os: [windows-latest, ubuntu-latest, macos-latest]
dotnet-version: ['8.x', '9.x', '10.x']
steps:
@@ -358,8 +359,8 @@ jobs:
run: |
mkdir -p artifacts
echo "Capturing tool versions..."
- # Create short job ID: int-win-8, int-win-9, int-ubuntu-8, etc.
- OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/')
+ # Create short job ID: int-windows-8, int-ubuntu-9, int-macos-10, etc.
+ OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/-latest//')
DOTNET_SHORT=$(echo "${{ matrix.dotnet-version }}" | sed 's/\.x$//')
JOB_ID="int-${OS_SHORT}-${DOTNET_SHORT}"
dotnet versionmark --capture --job-id "${JOB_ID}" \
@@ -418,7 +419,7 @@ jobs:
strategy:
matrix:
- os: [windows-latest, ubuntu-latest]
+ os: [windows-latest, ubuntu-latest, macos-latest]
steps:
# === INSTALL DEPENDENCIES ===
diff --git a/.github/workflows/build_on_push.yaml b/.github/workflows/build_on_push.yaml
index 1f30ade..e705ea5 100644
--- a/.github/workflows/build_on_push.yaml
+++ b/.github/workflows/build_on_push.yaml
@@ -1,7 +1,7 @@
---
# Main build workflow that runs on all pushes
# This workflow calls the reusable build workflow
-name: Build
+name: Build on Push
on:
push: # On push to any branch
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..e584cc8
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,156 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "--configuration",
+ "Release",
+ "${workspaceFolder}/DemaConsulting.SpdxTool.slnx"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "validate",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "run",
+ "--project",
+ "${workspaceFolder}/src/DemaConsulting.SpdxTool",
+ "--configuration",
+ "Release",
+ "--framework",
+ "net10.0",
+ "--no-build",
+ "--",
+ "--validate"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "build and validate",
+ "dependsOn": [
+ "build",
+ "validate"
+ ],
+ "dependsOrder": "sequence",
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "format",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "format"
+ ],
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "lint markdown",
+ "command": "npx",
+ "type": "shell",
+ "args": [
+ "markdownlint-cli2",
+ "\"**/*.md\"",
+ "\"#node_modules\""
+ ],
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "spell check",
+ "command": "npx",
+ "type": "shell",
+ "args": [
+ "cspell",
+ "\"**/*.{cs,md,json,yaml,yml}\"",
+ "--no-progress"
+ ],
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "lint yaml",
+ "command": "npx",
+ "type": "shell",
+ "args": [
+ "yamllint",
+ "-c",
+ ".yamllint.yaml",
+ "."
+ ],
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "lint all",
+ "dependsOn": [
+ "format",
+ "lint markdown",
+ "spell check",
+ "lint yaml"
+ ],
+ "dependsOrder": "parallel",
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "verify requirements",
+ "command": "dotnet",
+ "type": "shell",
+ "args": [
+ "reqstream",
+ "--requirements",
+ "requirements.yaml",
+ "--tests",
+ "\"test-results/**/*.trx\"",
+ "--enforce"
+ ],
+ "problemMatcher": [],
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ }
+ ]
+}
diff --git a/AGENTS.md b/AGENTS.md
index f4c5896..5f8b167 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -12,6 +12,18 @@ manipulating SPDX SBOM files.
- **Code Quality Agent** - Enforces linting, static analysis, and security standards
- **Repo Consistency Agent** - Ensures SpdxTool remains consistent with TemplateDotNetTool patterns
+## Agent Selection Guide
+
+- Fix a bug → **Software Developer**
+- Add a new feature → **Requirements Agent** → **Software Developer** → **Test Developer**
+- Write a test → **Test Developer**
+- Fix linting or static analysis issues → **Code Quality Agent**
+- Update documentation → **Technical Writer**
+- Add or update requirements → **Requirements Agent**
+- Ensure test coverage linkage in `requirements.yaml` → **Requirements Agent**
+- Run security scanning or address CodeQL alerts → **Code Quality Agent**
+- Propagate template changes → **Repo Consistency Agent**
+
## Tech Stack
- C# (latest), .NET 8.0/9.0/10.0, dotnet CLI, NuGet
@@ -22,6 +34,31 @@ manipulating SPDX SBOM files.
- **`.editorconfig`** - Code style (file-scoped namespaces, 4-space indent, UTF-8+BOM, LF endings)
- **`.cspell.json`, `.markdownlint-cli2.jsonc`, `.yamllint.yaml`** - Linting configs
+## Requirements
+
+- All requirements MUST be linked to tests (prefer `SpdxTool_*` self-validation tests)
+- Not all tests need to be linked to requirements (tests may exist for corner cases, ...)
+- Enforced in CI: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce`
+- When adding features: add requirement + link to test
+
+## Test Source Filters
+
+Test links in `requirements.yaml` can include a source filter prefix to restrict which test results count as
+evidence. This is critical for platform and framework requirements - **do not remove these filters**.
+
+- `windows@TestName` - proves the test passed on a Windows platform
+- `ubuntu@TestName` - proves the test passed on a Linux (Ubuntu) platform
+- `macos@TestName` - proves the test passed on a macOS platform
+- `net8.0@TestName` - proves the test passed under the .NET 8 target framework
+- `net9.0@TestName` - proves the test passed under the .NET 9 target framework
+- `net10.0@TestName` - proves the test passed under the .NET 10 target framework
+- `dotnet8.x@TestName` - proves the self-validation test ran on a machine with .NET 8.x runtime
+- `dotnet9.x@TestName` - proves the self-validation test ran on a machine with .NET 9.x runtime
+- `dotnet10.x@TestName` - proves the self-validation test ran on a machine with .NET 10.x runtime
+
+Without the source filter, a test result from any platform/framework satisfies the requirement. Adding the filter
+ensures the CI evidence comes specifically from the required environment.
+
## Testing
- **Test Naming**: `SpdxTool_FeatureBeingValidated` for self-validation tests
@@ -71,9 +108,9 @@ dotnet run --project src/DemaConsulting.SpdxTool \
## CI/CD
- **Quality Checks**: Markdown lint, spell check, YAML lint
-- **Build**: Multi-platform (Windows/Linux)
+- **Build**: Multi-platform (Windows/Linux/macOS)
- **CodeQL**: Security scanning
-- **Integration Tests**: .NET 8/9/10 on Windows/Linux
+- **Integration Tests**: .NET 8/9/10 on Windows/Linux/macOS
## Common Tasks
diff --git a/README.md b/README.md
index 3cc71e4..799d25d 100644
--- a/README.md
+++ b/README.md
@@ -166,6 +166,14 @@ This project maintains high code quality standards:
- ✓ Self-validation system for tool correctness
- ✓ Warnings treated as errors
- ✓ EditorConfig for consistent code style
+- ✓ **Continuous Compliance**: Compliance evidence generated automatically on every CI run,
+ following the [Continuous Compliance][link-continuous-compliance] methodology
+
+## License
+
+Copyright (c) DEMA Consulting. Licensed under the MIT License. See [LICENSE][link-license] for details.
+
+By contributing to this project, you agree that your contributions will be licensed under the MIT License.
## Additional Information
@@ -187,3 +195,5 @@ Additional information can be found at:
[spdx-site]: https://spdx.dev/
[github-ci-docs]: https://github.com/demaconsulting/SpdxTool/blob/main/docs/spdx-tool-github-ci.md
[sbom-tool-docs]: https://github.com/demaconsulting/SpdxTool/blob/main/docs/spdx-tool-and-sbom-tool.md
+[link-continuous-compliance]: https://demaconsulting.github.io/SpdxTool/articles/continuous-compliance.html
+[link-license]: https://github.com/demaconsulting/SpdxTool/blob/main/LICENSE
diff --git a/requirements.yaml b/requirements.yaml
index bf9decf..5885e41 100644
--- a/requirements.yaml
+++ b/requirements.yaml
@@ -19,6 +19,7 @@
# Source filter prefixes:
# windows@TestName - proves the test passed on a Windows platform
# ubuntu@TestName - proves the test passed on a Linux (Ubuntu) platform
+# macos@TestName - proves the test passed on a macOS platform
# net8.0@TestName - proves the test passed under the .NET 8 target framework
# net9.0@TestName - proves the test passed under the .NET 9 target framework
# net10.0@TestName - proves the test passed under the .NET 10 target framework
@@ -360,6 +361,24 @@ sections:
- ubuntu@SingleTfmProject_GenerateSbomFalse_SkipsEntirely
- ubuntu@SingleTfmProject_MissingWorkflow_ReportsError
+ - id: SpdxTool-Plt-MacOS
+ title: The tool shall run successfully on macOS platforms.
+ tags:
+ - platform
+ - msbuild
+ justification: |
+ macOS is a widely used operating system for development, especially
+ among software engineers and developers. The tool (both the dotnet-tool
+ and the MSBuild targets package) must function correctly on macOS to
+ support a broad user base.
+ tests:
+ - macos@SpdxTool_Validate
+ - macos@SingleTfmProject_DecorateSbomTrue_DecoratesSbom
+ - macos@MultiTfmProject_DecorateSbomTrue_DecoratesSbom
+ - macos@SingleTfmProject_DecorateSbomFalse_SkipsDecoration
+ - macos@SingleTfmProject_GenerateSbomFalse_SkipsEntirely
+ - macos@SingleTfmProject_MissingWorkflow_ReportsError
+
- id: SpdxTool-Plt-Net8
title: The tool shall run successfully on .NET 8.x.
tags:
diff --git a/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj b/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
index 6dc0fe8..74ba3a5 100644
--- a/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
+++ b/test/DemaConsulting.SpdxTool.Tests/DemaConsulting.SpdxTool.Tests.csproj
@@ -19,7 +19,14 @@
latest
+
+
+
+
+
+
+
all
@@ -50,10 +57,4 @@
-
-
-
-
-
-
\ No newline at end of file