diff --git a/.cspell.json b/.cspell.json
index a24ddb7..d511b6a 100644
--- a/.cspell.json
+++ b/.cspell.json
@@ -5,6 +5,7 @@
"Anson",
"Blockquotes",
"camelcase",
+ "Checkmarx",
"copilot",
"cspell",
"csproj",
@@ -34,17 +35,21 @@
"opencover",
"pagetitle",
"pandoc",
+ "Pylint",
+ "Qube",
"reqstream",
"ReqStream",
"Sarif",
"SarifMark",
"SBOM",
+ "Semgrep",
"semver",
"snupkg",
"spdx",
"testname",
"tracematrix",
"triaging",
+ "Trivy",
"trx",
"vbproj",
"vcxproj",
diff --git a/.github/agents/documentation-writer.md b/.github/agents/documentation-writer.md
index 96f9ef9..153fe1f 100644
--- a/.github/agents/documentation-writer.md
+++ b/.github/agents/documentation-writer.md
@@ -1,124 +1,47 @@
---
name: Documentation Writer
-description: >-
- Expert agent for creating, updating, and maintaining project documentation including README, guides, and API
- documentation
+description: Expert agent for SarifMark documentation, requirements.yaml maintenance, and markdown/spell/YAML linting
---
-# Documentation Writer Agent
+# Documentation Writer - SarifMark
-You are a specialized documentation writer agent for the SarifMark project. Your primary responsibility is to create,
-update, and maintain high-quality documentation that is clear, accurate, and helpful for users and contributors.
+Create and maintain clear, accurate documentation for the SarifMark .NET CLI tool.
-## Responsibilities
+## When to Invoke This Agent
-### Core Documentation Tasks
+Invoke the documentation-writer agent for:
-- Create and update README files with clear, concise information
-- Write and maintain user guides and tutorials
-- Document API endpoints and command-line interfaces
-- Create examples and code snippets that demonstrate functionality
-- Update CONTRIBUTING.md with relevant development information
-- Maintain SECURITY.md with security policies and reporting procedures
-- Keep AGENTS.md up to date with agent configurations
-- Maintain requirements documentation in `requirements.yaml`
-- Update requirements when features are added or changed
+- Documentation updates and reviews (README.md, guides, CONTRIBUTING.md, etc.)
+- Requirements updates in `requirements.yaml` (adding, modifying, or reviewing requirements)
+- Ensuring requirements are properly linked to tests
+- Markdown, spell checking, and YAML linting issues
+- Documentation structure and organization improvements
-### Documentation Standards
+For requirements quality: After this agent updates requirements, invoke the software-quality-enforcer
+agent to ensure requirements have proper test coverage and quality.
-- **Clarity**: Write in clear, simple language that is easy to understand
-- **Accuracy**: Ensure all technical details are correct and up to date
-- **Completeness**: Cover all features and functionality comprehensively
-- **Examples**: Provide practical examples that users can follow
-- **Consistency**: Maintain consistent style and formatting throughout
+## SarifMark-Specific Rules
-## Project-Specific Guidelines
+### Markdown
-### Markdown Style
+- **README.md ONLY**: Absolute URLs (shipped in NuGet) - `https://github.com/demaconsulting/SarifMark/blob/main/FILE.md`
+- **All other .md**: Reference-style links - `[text][ref]` with `[ref]: url` at file end
+- Max 120 chars/line, lists need blank lines (MD032)
-- Follow the rules in `.markdownlint.json`
-- Maximum line length: 120 characters
-- Use ATX-style headers (e.g., `# Header`)
-- Use reference-style links for maintainability (e.g., `[text][ref]` with `[ref]: url` at end of document)
-- **Exception**: README.md must use absolute URLs to GitHub (e.g.,
- `https://github.com/demaconsulting/SarifMark/blob/main/FILE.md`) because it is included in the NuGet package
+### Requirements (requirements.yaml)
-### Spell Checking
+- All requirements MUST link to tests (prefer `SarifMark_*` self-validation over unit tests)
+- When adding features: add requirement + test linkage
+- Test CLI commands before documenting
+- After updating requirements, recommend invoking software-quality-enforcer to verify test quality
-- Use `.cspell.json` for spell checking configuration
-- Add project-specific terms to the custom dictionary
-- Ensure all markdown files pass cspell validation
+### Linting Before Commit
-### Documentation Content
+- markdownlint (see CI workflow)
+- cspell (add terms to `.cspell.json`)
+- yamllint
-- **README.md**: Keep concise and focused on getting started quickly
-- **Code Examples**: Use proper formatting for examples
-- **CLI Usage**: Document all command-line options and arguments
-- **API Documentation**: Use clear descriptions and examples
-- **Requirements**: Keep `requirements.yaml` synchronized with features and tests
+## Don't
-### Requirements Management
-
-- **Requirements File**: `requirements.yaml` contains all project requirements
-- **Test Linkage**: All requirements must be linked to test methods that validate them
-- **Self-Validation**: Prefer linking to self-validation tests (e.g., `SarifMark_*`) over unit tests
-- **Test Naming**: Use the convention `ClassName_Method_Scenario_ExpectedBehavior` for clarity
-- **Enforcement**: Requirements are enforced via the `dotnet reqstream --enforce` command in CI/CD
-- **Updates**: When adding features, add corresponding requirements; when adding tests, link them to requirements
-
-### Technical Accuracy
-
-- Verify all code examples work correctly
-- Test CLI commands before documenting them
-- Keep documentation synchronized with code changes
-- Reference actual file names, paths, and configurations
-
-## Quality Checks
-
-Before finalizing documentation changes:
-
-1. **Markdown Linting**: Ensure markdown files follow project conventions
-2. **Spell Checking**: Verify spelling is correct
-3. **Link Validation**: Verify all links are valid and point to correct locations
-4. **Example Testing**: Test all code examples and CLI commands
-5. **Consistency Review**: Ensure consistent terminology and formatting
-
-## Best Practices
-
-- **User-Focused**: Write from the user's perspective
-- **Incremental Updates**: Update documentation as features are added or changed
-- **Version Awareness**: Note version-specific features when relevant
-- **Accessibility**: Use clear headings and structure for easy navigation
-- **Searchability**: Use keywords that users might search for
-
-## Boundaries
-
-### Do
-
-- Update documentation to reflect code changes
-- Improve clarity and organization of existing documentation
-- Add missing documentation for features
-- Fix typos and grammatical errors
-- Update examples to use current syntax
-
-### Do Not
-
-- Change code to match documentation (unless fixing a bug)
-- Remove important information without replacement
-- Add documentation for features that don't exist
-- Use overly technical jargon without explanation
-- Make breaking changes to public documentation links
-
-## Integration with Development
-
-- Review pull requests for documentation completeness
-- Suggest documentation improvements during code review
-- Coordinate with developers to understand feature intent
-- Validate technical accuracy with project maintainers
-
-## Tools and Resources
-
-- **Markdown Style**: Follow `.markdownlint.json` configuration
-- **Spell Checking**: Follow `.cspell.json` dictionary
-- **Style Guide**: Follow project conventions in AGENTS.md
-- **Code of Conduct**: Reference CODE_OF_CONDUCT.md for community guidelines
+- Change code to match docs
+- Add docs for non-existent features
diff --git a/.github/agents/project-maintainer.md b/.github/agents/project-maintainer.md
index fb641f5..dabfcb4 100644
--- a/.github/agents/project-maintainer.md
+++ b/.github/agents/project-maintainer.md
@@ -1,215 +1,50 @@
---
name: Project Maintainer
-description: >-
- Expert agent for overall project management, dependency updates, CI/CD maintenance, and release coordination
+description: Expert agent for SarifMark project management, dependencies, CI/CD, releases, and requirements traceability
---
-# Project Maintainer Agent
+# Project Maintainer - SarifMark
-You are a specialized project maintainer agent for the SarifMark project. Your primary responsibility is to maintain
-the overall health of the project, manage dependencies, maintain CI/CD pipelines, coordinate releases, and ensure the
-project infrastructure is well-maintained.
+Maintain SarifMark .NET CLI tool infrastructure, dependencies, releases, and requirements traceability.
-## Responsibilities
+## SarifMark-Specific
-### Project Management
+### Build
-- Monitor and manage project dependencies
-- Coordinate releases and versioning
-- Maintain CI/CD pipelines and workflows
-- Manage project configuration files
-- Review and merge pull requests
-- Triage and prioritize issues
-- Ensure project documentation is up to date
-- Maintain requirements in `requirements.yaml` and ensure they're linked to tests
+- Targets: .NET 8.0, 9.0, 10.0
+- Zero warnings required (TreatWarningsAsErrors=true)
-### Dependency Management
+### Workflows (.github/workflows)
-- Keep NuGet packages up to date
-- Monitor for security vulnerabilities in dependencies
-- Update .NET SDK versions when necessary
-- Maintain dotnet tools manifest (`.config/dotnet-tools.json`)
-- Review and approve dependency updates from Dependabot
+- **build.yaml**: Reusable (checkout, setup .NET, restore, build Release, test, pack, upload)
+- **build_on_push.yaml**: Main CI/CD (quality checks, Windows+Linux builds)
-### CI/CD Maintenance
+### Requirements Traceability (Critical)
-- Maintain GitHub Actions workflows
-- Ensure build pipelines are efficient and reliable
-- Monitor build and test failures
-- Update workflow configurations as needed
-- Optimize build times and resource usage
+- `requirements.yaml` defines all project requirements
+- ALL requirements MUST link to tests
+- Enforced: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce`
+- Published as PDFs: "SarifMark Requirements.pdf", "SarifMark Trace Matrix.pdf"
-## Project-Specific Guidelines
+### Quality Gates (Must Pass)
-### Build System
+1. Build (zero warnings)
+2. All tests pass
+3. Markdown/spell/YAML linting
+4. Requirements enforcement
+5. CodeQL security
-- **Framework Targets**: .NET 8.0, 9.0, and 10.0
-- **Build Tool**: dotnet CLI
-- **Test Framework**: MSTest
-- **Package Manager**: NuGet
-
-### CI/CD Workflows
-
-Located in `.github/workflows/`:
-
-- **build.yaml**: Reusable build workflow
- - Checkout, setup .NET, restore tools, restore dependencies
- - Build (Release), test (normal verbosity), package, upload artifacts
-- **build_on_push.yaml**: Main CI/CD pipeline
- - Quality checks (markdown lint, spell check, YAML lint)
- - Build on Windows (windows-latest) and Linux (ubuntu-latest)
- - Triggers: Push, manual dispatch, weekly schedule (Monday 5PM UTC)
-
-### Configuration Files
-
-- **`.editorconfig`**: Code style rules and naming conventions
-- **`.cspell.json`**: Spell checking configuration
-- **`.markdownlint.json`**: Markdown linting rules
-- **`.yamllint.yaml`**: YAML linting rules
-- **`.config/dotnet-tools.json`**: Dotnet tools manifest
-- **`DemaConsulting.SarifMark.sln`**: Solution file
-- **`requirements.yaml`**: Project requirements with test linkage
-
-### Requirements Management
-
-- **Requirements File**: `requirements.yaml` defines all project requirements
-- **ReqStream Tool**: Use `dotnet reqstream` to generate requirements reports and trace matrices
-- **Enforcement**: The `--enforce` flag ensures all requirements are linked to passing tests
-- **Documentation**: Requirements are published as "SarifMark Requirements.pdf" and "SarifMark Trace Matrix.pdf"
-- **Maintenance**: Keep requirements synchronized with features and tests
-- **Test Linkage**: All requirements must be linked to test methods that validate them
-- **Preference**: Link to self-validation tests first, integration tests second, unit tests as last resort
-
-### Quality Standards
-
-- All builds must succeed without warnings
-- All tests must pass
-- Code must pass static analysis
-- Documentation must be up to date
-- Markdown linting must pass
-- Spell checking must pass
-- YAML linting must pass
-- Requirements enforcement must pass
-
-## Release Process
-
-### Version Management
-
-- Follow semantic versioning (SemVer)
-- Update version numbers in project files
-- Create and tag releases appropriately
-- Generate release notes
-
-## Quality Checks
-
-Before merging changes:
-
-1. **Build Validation**: Ensure builds succeed on all target frameworks
-2. **Test Execution**: All tests pass with no failures
-3. **Linting**: All linting checks pass (markdown, YAML, spell check)
-4. **Static Analysis**: No new warnings or errors
-5. **Code Review**: Changes reviewed by maintainers
-6. **Security Scanning**: No new security vulnerabilities
-7. **Requirements Enforcement**: All requirements linked to passing tests
-
-## Best Practices
-
-### Pull Request Management
-
-- Review PRs promptly
-- Provide constructive feedback
-- Ensure PRs meet quality standards
-- Verify CI checks pass before merging
-- Keep PRs focused and reasonably sized
-
-### Issue Management
-
-- Triage new issues quickly
-- Label issues appropriately
-- Prioritize based on impact and effort
-- Close stale or resolved issues
-- Keep issue discussions focused
-
-### Dependency Updates
-
-- Test thoroughly before merging
-- Review release notes for breaking changes
-- Update documentation if APIs change
-- Consider impact on users
-
-### Communication
-
-- Keep stakeholders informed
-- Document decisions and rationale
-- Be responsive to community feedback
-- Maintain professional and friendly tone
-
-## Boundaries
-
-### Do
-
-- Approve and merge well-reviewed PRs
-- Update project dependencies regularly
-- Maintain CI/CD pipelines
-- Coordinate releases
-- Triage and manage issues
-- Ensure quality standards are met
-- Update project configuration files
-
-### Do Not
-
-- Merge PRs without proper review
-- Make breaking changes without discussion
-- Ignore failing tests or builds
-- Rush releases without proper validation
-- Remove or disable quality checks
-- Make unilateral architectural decisions
-
-## Security and Compliance
-
-- Monitor security advisories for dependencies
-- Respond promptly to security reports
-- Follow security disclosure procedures in SECURITY.md
-- Ensure license compliance
-- Maintain MIT license headers in source files
-
-## Tools and Commands
-
-### Build and Test
+### Commands
```bash
-# Restore tools
-dotnet tool restore
-
-# Restore dependencies
-dotnet restore
-
-# Build
+dotnet tool restore && dotnet restore
dotnet build --no-restore --configuration Release
-
-# Test
-dotnet test --no-build --configuration Release --verbosity normal
-
-# Package
+dotnet test --no-build --configuration Release
dotnet pack --no-build --configuration Release
```
-### Linting Commands
-
-Use the project's CI pipeline configuration as the source of truth for linting commands. Linting tools and their
-specific versions are managed through the CI/CD workflows.
-
-## Integration with Development
-
-- Work closely with developers on architectural decisions
-- Coordinate with documentation writer for release documentation
-- Collaborate with quality enforcer on quality standards
-- Engage with community on feature priorities
-
-## Continuous Improvement
+## Don't
-- Regularly review and optimize build processes
-- Update tooling and dependencies
-- Improve documentation and processes
-- Learn from issues and incidents
-- Solicit feedback from contributors
+- Merge without CI passing
+- Ignore failing tests/builds
+- Disable quality checks
diff --git a/.github/agents/software-quality-enforcer.md b/.github/agents/software-quality-enforcer.md
index cc2b761..943b4ca 100644
--- a/.github/agents/software-quality-enforcer.md
+++ b/.github/agents/software-quality-enforcer.md
@@ -1,136 +1,34 @@
---
name: Software Quality Enforcer
-description: Code quality specialist focused on enforcing testing standards and code coverage, running static analysis and linting, performing code reviews and quality gates, and ensuring zero-warning builds.
+description: Code quality specialist for SarifMark - enforce testing, coverage >80%, static analysis, and zero warnings
---
-# Software Quality Enforcer
+# Software Quality Enforcer - SarifMark
-Code quality specialist focused on maintaining high standards for the SarifMark
-library. Enforces testing, linting, static analysis, and code review standards.
-Ensures all changes meet quality gates before merging.
+Enforce quality standards for SarifMark .NET CLI tool.
-## Primary Responsibilities
+## Quality Gates (ALL Must Pass)
-1. **Enforce Quality Standards**
- - Ensure all code changes have appropriate unit tests
- - Verify code coverage meets thresholds (>80%)
- - Run static analyzers and ensure zero warnings
- - Check that code follows .editorconfig style rules
+- Zero build warnings (TreatWarningsAsErrors=true)
+- All tests passing (68/68 on .NET 8/9/10)
+- Code coverage >80% (currently 87.76%)
+- Static analysis (Microsoft.CodeAnalysis.NetAnalyzers, SonarAnalyzer.CSharp)
+- Code formatting (.editorconfig compliance)
+- Markdown/spell/YAML linting
+- Requirements traceability (all linked to tests)
-2. **Testing Standards**
- - Verify new features have comprehensive unit tests
- - Ensure tests follow AAA (Arrange, Act, Assert) pattern
- - Check tests are isolated and don't depend on execution order
- - Validate test names are descriptive (ClassName_MethodUnderTest_Scenario_ExpectedBehavior)
- - Confirm both success and failure scenarios are tested
- - Verify all requirements in `requirements.yaml` are linked to tests
- - Ensure requirements traceability is maintained for all changes
+## SarifMark-Specific
-3. **Code Review**
- - Review code for adherence to C# conventions
- - Check nullable reference type usage
- - Verify XML documentation exists for public APIs
- - Ensure no external runtime dependencies are added
- - Look for security vulnerabilities
+- **Test Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` (for requirements traceability)
+- **Test Linkage**: All requirements MUST link to tests (prefer `SarifMark_*` self-validation)
+- **XML Docs**: On ALL members (public/internal/private) with spaces after `///`
+- **No external runtime deps**: Only DemaConsulting.TestResults allowed
-4. **Build and CI/CD**
- - Verify builds complete with zero warnings
- - Ensure all tests pass on all target frameworks (.NET 8, 9, 10)
- - Check SonarCloud quality gates pass
- - Validate SBOM generation succeeds
-
-## Working Approach
-
-- **Run Checks First**: Always build and test before making changes
-- **Use Existing Tools**: Leverage dotnet format, analyzers, and tests
-- **Fix, Don't Suppress**: Address warnings rather than suppressing them
-- **Be Thorough**: Check both obvious and edge cases
-- **Provide Context**: Explain why changes improve quality
-- **Automate**: Prefer automated checks over manual reviews
-
-## Commands You Use
+## Commands
```bash
-# Build with zero warnings
-dotnet build --configuration Release
-
-# Run all tests
-dotnet test --configuration Release
-
-# Check code formatting
+dotnet build --configuration Release # Zero warnings required
+dotnet test --configuration Release --collect "XPlat Code Coverage"
dotnet format --verify-no-changes
-
-# Run with coverage
-dotnet test --collect "XPlat Code Coverage"
-
-# Restore tools and dependencies
-dotnet tool restore
-dotnet restore
-
-# Validate requirements traceability
dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce
```
-
-## Quality Gates
-
-All changes must pass:
-
-- ✅ Zero build warnings (warnings are errors)
-- ✅ All unit tests passing
-- ✅ Code coverage > 80%
-- ✅ Static analysis (Microsoft.CodeAnalysis.NetAnalyzers, SonarAnalyzer.CSharp)
-- ✅ SonarCloud quality gate
-- ✅ Code formatting per .editorconfig
-- ✅ Spell checking passes (cspell)
-- ✅ Markdown linting passes (markdownlint)
-- ✅ Requirements traceability (all requirements have tests, all tests pass)
-
-## Review Checklist
-
-For every code change, verify:
-
-- [ ] New code has unit tests
-- [ ] Tests follow AAA pattern
-- [ ] Tests are linked to requirements in `requirements.yaml`
-- [ ] Public APIs have XML documentation
-- [ ] No runtime dependencies added
-- [ ] Nullable reference types used correctly
-- [ ] No security vulnerabilities introduced
-- [ ] Code follows naming conventions
-- [ ] Methods are focused and concise
-- [ ] No code duplication (DRY principle)
-- [ ] Build succeeds with zero warnings
-- [ ] All tests pass
-- [ ] Requirements traceability is maintained
-
-## Common Issues to Catch
-
-- Missing unit tests for new functionality
-- Insufficient test coverage
-- Warnings being ignored
-- Inconsistent code formatting
-- Missing XML documentation
-- Adding external runtime dependencies
-- Security vulnerabilities (XXE, injection, etc.)
-- Nullable reference type misuse
-- Overly complex methods
-- Code duplication
-
-## What NOT To Do
-
-- Don't suppress warnings without justification
-- Don't reduce test coverage
-- Don't disable or remove existing tests
-- Don't add external runtime dependencies
-- Don't bypass quality gates
-- Don't merge changes that break builds or tests
-
-## Collaboration
-
-- Work with Documentation Writer to ensure documentation matches code quality
-- Work with Project Maintainer to improve CI/CD pipelines
-- Escalate architectural concerns that affect quality
-- Provide constructive feedback to contributors
-
-Remember: Quality is not negotiable. Your role ensures that SarifMark maintains
-its reputation for reliability, performance, and maintainability.
diff --git a/.gitignore b/.gitignore
index ad0856d..ea48538 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@ coverage/
# Test results
*.trx
+test-results/
+*.log
# Temporary files
*.tmp
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 0000000..bdfb70b
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,166 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "--configuration",
+ "Release",
+ "${workspaceFolder}/DemaConsulting.SarifMark.slnx"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "build",
+ "isDefault": true
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "test",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "test",
+ "--configuration",
+ "Release",
+ "${workspaceFolder}/DemaConsulting.SarifMark.slnx"
+ ],
+ "problemMatcher": "$msCompile",
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "presentation": {
+ "reveal": "always",
+ "panel": "shared"
+ }
+ },
+ {
+ "label": "build and test",
+ "dependsOn": [
+ "build",
+ "test"
+ ],
+ "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",
+ "."
+ ],
+ "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": "test with coverage",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "test",
+ "--configuration",
+ "Release",
+ "--collect",
+ "XPlat Code Coverage",
+ "${workspaceFolder}/DemaConsulting.SarifMark.slnx"
+ ],
+ "problemMatcher": "$msCompile",
+ "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 abf26e9..be06311 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,204 +1,62 @@
-# GitHub Copilot Agents
-
-This document provides comprehensive guidance for GitHub Copilot agents working on the SarifMark project.
-
-## Overview
-
-GitHub Copilot agents are AI-powered assistants that help with various development tasks. This document will be
-updated as agents are configured for this repository.
-
-## Project Overview
-
-SarifMark is a .NET command-line tool for creating SARIF reports from various static analysis tools.
-It provides functionality to generate markdown reports that summarize code quality metrics, issues, and violations.
-
-### Technology Stack
-
-- **Language**: C# 12
-- **Framework**: .NET 8.0, 9.0, and 10.0
-- **Testing Framework**: MSTest
-- **Build System**: dotnet CLI
-- **Package Manager**: NuGet
-
-## Project Structure
-
-```text
-SarifMark/
-├── .github/ # GitHub Actions workflows
-│ ├── agents/ # Agent configurations
-│ ├── ISSUE_TEMPLATE/ # Issue templates
-│ └── workflows/
-│ ├── build.yaml # Reusable build workflow
-│ └── build_on_push.yaml # Main CI/CD pipeline
-├── src/ # Source code
-│ └── DemaConsulting.SarifMark/ # Main application project
-├── test/ # Test projects
-│ └── DemaConsulting.SarifMark.Tests/ # Test project
-├── .cspell.json # Spell checking configuration
-├── .editorconfig # Code style configuration
-├── .markdownlint.json # Markdown linting rules
-├── .yamllint.yaml # YAML linting rules
-├── AGENTS.md # This file
-├── CODE_OF_CONDUCT.md # Code of Conduct
-├── LICENSE # MIT License
-├── README.md # Project documentation
-├── requirements.yaml # Project requirements
-└── SECURITY.md # Security policy
-```
-
-### Critical Files
-
-- **`.editorconfig`**: Defines code style rules, naming conventions, and formatting standards
-- **`.cspell.json`**: Contains spell-checking configuration and custom dictionary
-- **`.markdownlint.json`**: Markdown linting rules
-- **`.yamllint.yaml`**: YAML linting rules
-- **`DemaConsulting.SarifMark.sln`**: Solution file containing all projects
-- **`requirements.yaml`**: Project requirements with test linkage
-
-## Requirements Management
-
-SarifMark uses DemaConsulting.ReqStream for requirements management:
-
-- **Requirements File**: `requirements.yaml` contains all project requirements
-- **Test Linkage**: All requirements must be linked to test methods that validate them
-- **Self-Validation**: Prefer linking to self-validation tests (e.g., `SarifMark_*`) over unit tests
-- **Enforcement**: Requirements are enforced via `dotnet reqstream --enforce` in CI/CD
-- **Documentation**: Requirements are published as "SarifMark Requirements.pdf" and "SarifMark Trace Matrix.pdf"
-- **Updates**: When adding features, add corresponding requirements; when adding tests, link them to requirements
-
-## Testing Guidelines
-
-- **Test Framework**: MSTest v4 (Microsoft.VisualStudio.TestTools.UnitTesting)
-- **Test File Naming**: `[Component]Tests.cs` (e.g., `ProgramTests.cs`)
-- **Test Method Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` format
- - Example: `Program_Main_NoArguments_ReturnsSuccess` clearly indicates testing the `Program.Main` method
- - This pattern makes test intent clear for requirements traceability
-- **MSTest v4 APIs**: Use modern assertions:
- - `Assert.HasCount(collection, expectedCount)` instead of `Assert.AreEqual(count, collection.Count)`
- - `Assert.IsEmpty(collection)` instead of `Assert.AreEqual(0, collection.Count)`
- - `Assert.DoesNotContain(item, collection)` for negative checks
-- **Console Testing**: Save and restore `Console.Out` in tests that modify console output:
-
- ```csharp
- var originalOut = Console.Out;
- try { /* test code */ }
- finally { Console.SetOut(originalOut); }
- ```
-
-- **All tests must pass** before merging changes
-- **No warnings allowed** in test builds
+# Agent Quick Reference
-## Code Style and Conventions
+Project-specific guidance for agents working on SarifMark - a .NET CLI tool for creating markdown reports from SARIF files.
-### Naming Conventions
+## Tech Stack
-- **Interfaces**: Must begin with `I` (e.g., `IReportGenerator`)
-- **Classes, Structs, Enums**: PascalCase
-- **Methods, Properties**: PascalCase
-- **Parameters, Local Variables**: camelCase
+- C# 12, .NET 8.0/9.0/10.0, MSTest, dotnet CLI, NuGet
-### Code Organization
+## Key Files
-- **Namespace Declarations**: Use file-scoped namespaces (C# 10+)
-- **Using Directives**: Sort system directives first
-- **Braces**: Required for all control statements
-- **Indentation**: 4 spaces for C#, 2 spaces for YAML/JSON/XML
-- **Encoding**: UTF-8 with BOM, LF line endings with final newline
+- **`requirements.yaml`** - All requirements with test linkage (enforced via `dotnet reqstream --enforce`)
+- **`.editorconfig`** - Code style (file-scoped namespaces, 4-space indent, UTF-8+BOM, LF endings)
+- **`.cspell.json`, `.markdownlint.json`, `.yamllint.yaml`** - Linting configs
-### Documentation and Comments
+## Requirements (SarifMark-Specific)
-- **Copyright Headers**: All source files must include the MIT license header
-- **XML Documentation**: Use triple-slash comments (`///`) for all public, internal, and private members
- - **IMPORTANT**: Summary blocks must be indented with spaces after `///`
+- Link ALL requirements to tests (prefer `SarifMark_*` self-validation over unit tests)
+- Enforced in CI: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce`
+- When adding features: add requirement + link to test
- ```csharp
- ///
- /// This is the correct indentation format for summary blocks.
- ///
- ```
+## Testing (SarifMark-Specific)
-- **Error Handling Patterns**:
- - Argument parsing: Throw `ArgumentException` with descriptive messages
- - Runtime errors during execution: Use `InvalidOperationException`
- - Write methods (WriteLine/WriteError) are for output AFTER successful parsing
-- **Code Reusability**: Create properties or methods to avoid code duplication
+- **Test Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` (for requirements traceability)
+- **MSTest v4**: Use `Assert.HasCount()`, `Assert.IsEmpty()`, `Assert.DoesNotContain()` (not old APIs)
+- **Console Tests**: Always save/restore `Console.Out` in try/finally
-## Quality Standards
+## Code Style (SarifMark-Specific)
-- **Static Analysis**: Built-in .NET analyzers enforce code style, naming rules, and nullable reference types
-- **Documentation**:
- - README.md uses absolute URLs (included in NuGet package)
- - Other markdown files use link references: `[text][ref]` with `[ref]: url` at end
-- **Linting**:
- - **Markdown**: Must pass markdownlint (max line length: 120 chars)
- - Lists must be surrounded by blank lines (MD032)
- - Run locally: Check CI workflow for markdownlint-cli2-action usage
- - **Spell Check**: Must pass cspell (custom dictionary in `.cspell.json`)
- - Add project-specific terms to the custom dictionary if needed
- - **YAML**: Must pass yamllint (2-space indentation, max line length: 120 chars)
- - **All linting must pass locally before committing** - CI will reject changes with linting errors
+- **XML Docs**: On ALL members (public/internal/private) with spaces after `///` in summaries
+- **Errors**: `ArgumentException` for parsing, `InvalidOperationException` for runtime, Write* only after success
+- **No code duplication**: Extract to properties/methods
-## CI/CD Pipelines
+## Linting (SarifMark-Specific)
-The project uses GitHub Actions workflows in `.github/workflows/`:
+- **README.md**: Absolute URLs only (shipped in NuGet package)
+- **Other .md**: Reference-style links `[text][ref]` with `[ref]: url` at end
+- **All linters must pass locally**: markdownlint, cspell, yamllint (see CI workflows for commands)
-- **build_on_push.yaml**: Runs quality checks, builds on Windows and Linux
-- **build.yaml**: Reusable workflow for restore, build, test, and package
-
-Build commands:
+## Build & Quality (Quick Reference)
```bash
-dotnet restore # Restore dependencies
-dotnet build --no-restore --configuration Release
-dotnet test --no-build --configuration Release --verbosity normal
-dotnet pack --no-build --configuration Release
+# Standard build/test
+dotnet build --configuration Release && dotnet test --configuration Release
+
+# Pre-finalization checklist (in order):
+# 1. Build/test (zero warnings required)
+# 2. code_review tool
+# 3. codeql_checker tool
+# 4. All linters (markdownlint, cspell, yamllint)
+# 5. Requirements: dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce
```
-## Pre-Finalization Quality Checks
-
-Before completing any task, you **MUST** perform these checks in order and ensure they all pass:
-
-1. **Build and Test**: Run `dotnet build --configuration Release && dotnet test --configuration Release` - all tests
- must pass with zero warnings
-2. **Code Review**: Use `code_review` tool and address all valid concerns
-3. **Security Scanning**: Use `codeql_checker` tool after code review - must report zero vulnerabilities
-4. **Linting**: Run all linters locally and fix any issues before pushing changes:
- - **Markdown**: Run markdownlint on all changed `.md` files - must pass with zero errors
- - **Spell Check**: Run cspell on all changed files - must pass with zero errors
- - **YAML**: Run yamllint on all changed `.yaml` or `.yml` files - must pass with zero errors
- - These linters run in CI and will fail the build if not passing
-5. **Requirements Enforcement**: Verify all requirements have test linkage by running
- `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce` - must pass
-
-## Project-Specific Guidelines
-
-### Key Decisions from Recent Reviews
-
-These patterns emerged from code review feedback and should be followed:
-
-1. **XmlDoc Formatting**: Always indent summary content with spaces after `///`
-2. **Error Handling**: Throw exceptions during parsing; use Write methods only after successful parsing
-3. **Code Reuse**: Extract repeated code into properties or methods
-4. **Console Testing**: Always save/restore `Console.Out` in try/finally blocks
-5. **Modern Test APIs**: Prefer MSTest v4 assertions (HasCount, IsEmpty, DoesNotContain)
-
-### What NOT to Do
-
-- Don't delete or modify working code unless fixing a security vulnerability
-- Don't remove or modify existing tests unless directly related to your changes
-- Don't commit build artifacts (`bin/`, `obj/`, `node_modules/`)
-- Don't use force push (`git reset`, `git rebase`)
-- Don't create temporary files in the repository (use `/tmp` instead)
-- Don't make changes to `.github/agents/` files (for other agents only)
-
-## Available Agents
+## Custom Agents
-The following custom agents are configured for this repository. Each agent file contains detailed guidelines,
-responsibilities, and project-specific conventions.
+Delegate tasks to specialized agents for better results:
-- **Documentation Writer** (`.github/agents/documentation-writer.md`) - Expert agent for creating, updating, and
- maintaining project documentation
-- **Project Maintainer** (`.github/agents/project-maintainer.md`) - Expert agent for overall project management,
- dependency updates, CI/CD maintenance, and release coordination
-- **Software Quality Enforcer** (`.github/agents/software-quality-enforcer.md`) - Expert agent for enforcing code
- quality standards, testing requirements, and quality gates
+- **documentation-writer** - Invoke for: documentation updates/reviews, requirements.yaml changes,
+ markdown/spell/YAML linting
+- **project-maintainer** - Invoke for: dependency updates, CI/CD maintenance, releases, requirements
+ traceability enforcement
+- **software-quality-enforcer** - Invoke for: code quality reviews, test coverage verification (>80%),
+ static analysis, zero-warning builds, requirements test quality
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
new file mode 100644
index 0000000..dc67e86
--- /dev/null
+++ b/DEVELOPMENT.md
@@ -0,0 +1,99 @@
+# Development Quick Start
+
+Quick reference for developers and AI agents working on SarifMark.
+
+## Prerequisites
+
+- [.NET SDK 8.0, 9.0, or 10.0][dotnet-sdk]
+- [Node.js][nodejs] (for linting tools)
+
+## Quick Commands
+
+```bash
+# First time setup
+npm install # Install linting tools
+dotnet tool restore # Install .NET tools
+dotnet restore # Restore dependencies
+
+# Build and test
+dotnet build --configuration Release # Build (zero warnings required)
+dotnet test --configuration Release # Run all tests
+
+# Code quality
+dotnet format # Format code
+dotnet format --verify-no-changes # Verify formatting
+npx markdownlint-cli2 "**/*.md" # Lint markdown
+npx cspell "**/*.{cs,md,json,yaml,yml}" # Spell check
+npx yamllint . # Lint YAML
+
+# Requirements traceability
+dotnet test --configuration Release --logger "trx;LogFileName=test-results.trx"
+dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce
+
+# Coverage
+dotnet test --configuration Release --collect "XPlat Code Coverage"
+
+# Package
+dotnet pack --configuration Release
+```
+
+## Project Structure
+
+```text
+SarifMark/
+├── src/DemaConsulting.SarifMark/ # Main CLI tool
+├── test/DemaConsulting.SarifMark.Tests/ # Tests
+├── requirements.yaml # Requirements (linked to tests)
+├── .editorconfig # Code style rules
+└── .github/workflows/ # CI/CD pipelines
+```
+
+## Code Standards
+
+- **Test Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior`
+- **XML Docs**: Required on ALL members (public/internal/private)
+- **Requirements**: All features must have requirements linked to tests
+- **Zero Warnings**: Build must complete with zero warnings
+- **Coverage**: Maintain >80% code coverage
+
+## Pre-Commit Checklist
+
+1. ✅ `dotnet build --configuration Release` (zero warnings)
+2. ✅ `dotnet test --configuration Release` (all pass)
+3. ✅ `dotnet format --verify-no-changes` (formatting)
+4. ✅ `npx markdownlint-cli2 "**/*.md"` (markdown)
+5. ✅ `npx cspell "**/*.{cs,md,json,yaml,yml}"` (spelling)
+6. ✅ Requirements enforcement passes
+
+## Common Tasks
+
+### Adding a Feature
+
+1. Add requirement to `requirements.yaml`
+2. Write tests (link to requirement)
+3. Implement feature
+4. Update documentation
+5. Run pre-commit checklist
+
+### Fixing a Bug
+
+1. Write failing test
+2. Fix bug
+3. Verify test passes
+4. Run pre-commit checklist
+
+### Updating Dependencies
+
+1. Update package references
+2. Run full build and test suite
+3. Update `requirements.yaml` if needed
+4. Check for security vulnerabilities
+
+## Resources
+
+- [AGENTS.md](AGENTS.md) - Agent-specific guidance
+- [CONTRIBUTING.md](CONTRIBUTING.md) - Detailed contribution guide
+- [README.md](README.md) - Project overview
+
+[dotnet-sdk]: https://dotnet.microsoft.com/download
+[nodejs]: https://nodejs.org/
diff --git a/README.md b/README.md
index 70c0f59..71f23c2 100644
--- a/README.md
+++ b/README.md
@@ -63,6 +63,30 @@ Run the tool:
dotnet sarifmark --version
```
+### Update
+
+To update to the latest version:
+
+```bash
+# Global installation
+dotnet tool update --global DemaConsulting.SarifMark
+
+# Local installation
+dotnet tool update DemaConsulting.SarifMark
+```
+
+### Compatibility
+
+| Component | Version | Status |
+| :-------- | :------ | :----- |
+| .NET SDK | 8.0 | ✅ Supported |
+| .NET SDK | 9.0 | ✅ Supported |
+| .NET SDK | 10.0 | ✅ Supported |
+| SARIF Format | 2.1.0 | ✅ Supported |
+| OS | Windows | ✅ Supported |
+| OS | Linux | ✅ Supported |
+| OS | macOS | ✅ Supported |
+
## Usage
### Basic Usage
diff --git a/build.bat b/build.bat
new file mode 100644
index 0000000..6ea0688
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,12 @@
+@echo off
+REM Build and test SarifMark (Windows)
+
+echo Building SarifMark...
+dotnet build --configuration Release
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo Running tests...
+dotnet test --configuration Release --verbosity normal
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo Build and test completed successfully!
diff --git a/build.sh b/build.sh
new file mode 100755
index 0000000..03d8518
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# Build and test SarifMark
+
+set -e # Exit on error
+
+echo "🔧 Building SarifMark..."
+dotnet build --configuration Release
+
+echo "✅ Running tests..."
+dotnet test --configuration Release --verbosity normal
+
+echo "✨ Build and test completed successfully!"
diff --git a/docs/guide/guide.md b/docs/guide/guide.md
index 0f9cd6a..0420e04 100644
--- a/docs/guide/guide.md
+++ b/docs/guide/guide.md
@@ -228,6 +228,89 @@ SarifMark uses the following exit codes:
- `1`: Error (invalid arguments, file not found, processing error)
- Non-zero (with `--enforce`): Issues found in SARIF file
+## Frequently Asked Questions
+
+### What is SARIF?
+
+SARIF (Static Analysis Results Interchange Format) is a standard format for the output of static analysis tools. It's
+designed to be easily integrated into development workflows and provides a consistent structure for representing
+analysis results from different tools.
+
+For more information, visit the [SARIF website](https://sarifweb.azurewebsites.net/).
+
+### Which static analysis tools produce SARIF output?
+
+Many popular static analysis tools support SARIF output, including:
+
+- **CodeQL** - Security and quality analysis
+- **SonarQube** - Code quality and security analysis
+- **ESLint** - JavaScript linting (with SARIF formatter)
+- **Pylint** - Python linting (with SARIF converter)
+- **Semgrep** - Pattern-based code analysis
+- **Checkmarx** - Security scanning
+- **Trivy** - Container vulnerability scanning
+
+Check your tool's documentation for SARIF export options.
+
+### Can I process multiple SARIF files at once?
+
+Currently, SarifMark processes one SARIF file at a time. To process multiple files, run the tool multiple times with
+different input and output files. You can combine the reports manually or use a script to merge them.
+
+### How do I use SarifMark in a CI/CD pipeline?
+
+See the [Integration Examples](#integration-examples) section above for CI/CD integration examples. The key steps are:
+
+1. Run your static analysis tool to generate a SARIF file
+2. Install SarifMark in your pipeline
+3. Run SarifMark to generate a report
+4. Optionally use `--enforce` to fail the build if issues are found
+
+### What happens when I use the --enforce flag?
+
+When you use the `--enforce` flag, SarifMark will:
+
+- Process the SARIF file normally
+- Generate any requested reports
+- Return a non-zero exit code if the SARIF file contains any issues
+
+This is useful in CI/CD pipelines to fail builds when quality issues are detected.
+
+### Can I customize the report format?
+
+Yes, you can customize:
+
+- **Heading**: Use `--heading "Custom Title"` to set a custom report heading
+- **Header Depth**: Use `--report-depth 2` to adjust the markdown header level (useful when including the report in
+ a larger document)
+
+The report content format is standardized but these options allow you to integrate reports into different documentation
+structures.
+
+### What .NET versions are supported?
+
+SarifMark supports .NET 8.0, 9.0, and 10.0. You need at least one of these SDK versions installed to use the tool.
+The tool is built as a multi-targeted package, so it will automatically use the appropriate version based on your
+installed .NET runtime.
+
+### How do I update SarifMark?
+
+To update to the latest version:
+
+```bash
+# Global installation
+dotnet tool update --global DemaConsulting.SarifMark
+
+# Local installation
+dotnet tool update DemaConsulting.SarifMark
+```
+
+### Where can I find more help?
+
+- **GitHub Issues**:
+- **GitHub Discussions**:
+- **Documentation**:
+
## Troubleshooting
### SARIF File Not Found
diff --git a/lint.bat b/lint.bat
new file mode 100644
index 0000000..eb048bf
--- /dev/null
+++ b/lint.bat
@@ -0,0 +1,20 @@
+@echo off
+REM Run all linters for SarifMark (Windows)
+
+echo Checking markdown...
+call npx markdownlint-cli2 "**/*.md" "#node_modules"
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo Checking spelling...
+call npx cspell "**/*.{cs,md,json,yaml,yml}" --no-progress
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo Checking YAML...
+call npx yamllint .
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo Checking code formatting...
+dotnet format --verify-no-changes
+if %errorlevel% neq 0 exit /b %errorlevel%
+
+echo All linting passed!
diff --git a/lint.sh b/lint.sh
new file mode 100755
index 0000000..e096d23
--- /dev/null
+++ b/lint.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+# Run all linters for SarifMark
+
+set -e # Exit on error
+
+echo "📝 Checking markdown..."
+npx markdownlint-cli2 "**/*.md" "#node_modules"
+
+echo "🔤 Checking spelling..."
+npx cspell "**/*.{cs,md,json,yaml,yml}" --no-progress
+
+echo "📋 Checking YAML..."
+npx yamllint .
+
+echo "🎨 Checking code formatting..."
+dotnet format --verify-no-changes
+
+echo "✨ All linting passed!"
diff --git a/test/DemaConsulting.SarifMark.Tests/PathHelpersTests.cs b/test/DemaConsulting.SarifMark.Tests/PathHelpersTests.cs
index de29a70..628c305 100644
--- a/test/DemaConsulting.SarifMark.Tests/PathHelpersTests.cs
+++ b/test/DemaConsulting.SarifMark.Tests/PathHelpersTests.cs
@@ -54,7 +54,7 @@ public void PathHelpers_SafePathCombine_PathWithParentDirectory_ThrowsArgumentEx
var relativePath = "../etc/passwd";
// Act & Assert
- var exception = Assert.Throws(() =>
+ var exception = Assert.Throws(() =>
PathHelpers.SafePathCombine(basePath, relativePath));
Assert.Contains("Invalid path component", exception.Message);
Assert.AreEqual("relativePath", exception.ParamName);
@@ -71,7 +71,7 @@ public void PathHelpers_SafePathCombine_PathWithDoubleDots_ThrowsArgumentExcepti
var relativePath = "documents/../../../etc/passwd";
// Act & Assert
- var exception = Assert.Throws(() =>
+ var exception = Assert.Throws(() =>
PathHelpers.SafePathCombine(basePath, relativePath));
Assert.Contains("Invalid path component", exception.Message);
}
@@ -85,7 +85,7 @@ public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException()
// Test Unix absolute path
var unixBasePath = "/home/user";
var unixRelativePath = "/etc/passwd";
- var unixException = Assert.Throws(() =>
+ var unixException = Assert.Throws(() =>
PathHelpers.SafePathCombine(unixBasePath, unixRelativePath));
Assert.Contains("Invalid path component", unixException.Message);
@@ -94,7 +94,7 @@ public void PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException()
{
var windowsBasePath = "C:\\Users\\User";
var windowsRelativePath = "C:\\Windows\\System32";
- var windowsException = Assert.Throws(() =>
+ var windowsException = Assert.Throws(() =>
PathHelpers.SafePathCombine(windowsBasePath, windowsRelativePath));
Assert.Contains("Invalid path component", windowsException.Message);
}
diff --git a/test/DemaConsulting.SarifMark.Tests/SarifResultsTests.cs b/test/DemaConsulting.SarifMark.Tests/SarifResultsTests.cs
index c4af6eb..f5e8c3b 100644
--- a/test/DemaConsulting.SarifMark.Tests/SarifResultsTests.cs
+++ b/test/DemaConsulting.SarifMark.Tests/SarifResultsTests.cs
@@ -312,15 +312,15 @@ public void SarifResults_Read_WithResults_ReturnsValidResults()
Assert.AreEqual("1.0.0", results.ToolVersion);
Assert.AreEqual(3, results.ResultCount);
Assert.HasCount(3, results.Results);
-
+
Assert.AreEqual("TEST001", results.Results[0].RuleId);
Assert.AreEqual("error", results.Results[0].Level);
Assert.AreEqual("Error 1", results.Results[0].Message);
-
+
Assert.AreEqual("TEST002", results.Results[1].RuleId);
Assert.AreEqual("warning", results.Results[1].Level);
Assert.AreEqual("Warning 1", results.Results[1].Message);
-
+
Assert.AreEqual("TEST003", results.Results[2].RuleId);
Assert.AreEqual("note", results.Results[2].Level);
Assert.AreEqual("Note 1", results.Results[2].Message);
@@ -967,10 +967,10 @@ public void SarifResults_Read_WithSuppressedResults_ExcludesSuppressedResults()
Assert.AreEqual("1.0.0", results.ToolVersion);
Assert.AreEqual(2, results.ResultCount);
Assert.HasCount(2, results.Results);
-
+
Assert.AreEqual("TEST001", results.Results[0].RuleId);
Assert.AreEqual("Unsuppressed warning", results.Results[0].Message);
-
+
Assert.AreEqual("TEST003", results.Results[1].RuleId);
Assert.AreEqual("Another unsuppressed error", results.Results[1].Message);
}