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