diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 0efd545..731e208 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -26,18 +26,24 @@ "weasyprint" ] }, - "demaconsulting.reqstream": { - "version": "1.7.0", - "commands": [ - "reqstream" - ] - }, "demaconsulting.sarifmark": { "version": "1.3.2", "commands": [ "sarifmark" ] }, + "demaconsulting.sonarmark": { + "version": "1.4.0", + "commands": [ + "sonarmark" + ] + }, + "demaconsulting.reqstream": { + "version": "1.7.0", + "commands": [ + "reqstream" + ] + }, "demaconsulting.buildmark": { "version": "1.0.0", "commands": [ @@ -55,6 +61,12 @@ "commands": [ "reviewmark" ] + }, + "demaconsulting.fileassert": { + "version": "0.3.0", + "commands": [ + "fileassert" + ] } } } \ No newline at end of file diff --git a/.cspell.yaml b/.cspell.yaml index c025b85..14edfcc 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -14,17 +14,12 @@ language: en # Project-specific technical terms and tool names words: - - Anson - - Blockquotes - buildmark - BuildMark - - build_notes - buildtransitive - - camelcase - CodeQL - contentfiles - copilot - - coveragexml - cspell - csproj - csharpsquid @@ -40,16 +35,12 @@ words: - dotnet - dotnettool - editorconfig - - errorlevel - - filepart + - fileassert - finalizer - fsproj - - Gidget - gitattributes - hotspots - - ibiqlik - LINQ - - maintainer - markdownlint - mstest - myterm @@ -82,13 +73,6 @@ words: - spdx - spdxtool - testname - - code_quality - - code_review_plan - - code_review_report - - requirements_doc - - requirements_report - - trace_matrix - - triaging - trx - vbproj - vcxproj @@ -96,6 +80,7 @@ words: - VersionMark - Weasyprint - weasyprinttool + - yamlfix - yamllint # Exclude common build artifacts, dependencies, and vendored third-party code diff --git a/.fileassert.yaml b/.fileassert.yaml new file mode 100644 index 0000000..0790e76 --- /dev/null +++ b/.fileassert.yaml @@ -0,0 +1,276 @@ +--- +# FileAssert document validation tests for SonarMark. +# Tests are tagged by document group to allow per-group execution during the build pipeline. +# Tags: build-notes, code-quality, code-review, design, user-guide, requirements. +# +# NOTE: build-notes through user-guide tests provide OTS evidence for Pandoc and WeasyPrint +# and run before ReqStream. The requirements tests run after ReqStream and validate the +# final outputs, but do not contribute to OTS requirements evidence. + +tests: + + # --- BUILD NOTES --- + + - name: Pandoc_BuildNotesHtml + description: "Build Notes HTML was generated by Pandoc" + tags: [build-notes] + files: + - pattern: "docs/build_notes/build_notes.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Build Notes" + + - name: WeasyPrint_BuildNotesPdf + description: "Build Notes PDF was generated by WeasyPrint" + tags: [build-notes] + files: + - pattern: "docs/SonarMark Build Notes.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "SonarMark" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Build notes" + pages: + min: 1 + text: + - contains: "Build Notes" + + # --- CODE QUALITY --- + + - name: Pandoc_CodeQualityHtml + description: "Code Quality HTML was generated by Pandoc" + tags: [code-quality] + files: + - pattern: "docs/code_quality/quality.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "CodeQL" + + - name: WeasyPrint_CodeQualityPdf + description: "Code Quality PDF was generated by WeasyPrint" + tags: [code-quality] + files: + - pattern: "docs/SonarMark Code Quality.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Code Quality" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Code Quality" + pages: + min: 1 + text: + - contains: "CodeQL" + + # --- CODE REVIEW PLAN --- + + - name: Pandoc_ReviewPlanHtml + description: "Code Review Plan HTML was generated by Pandoc" + tags: [code-review] + files: + - pattern: "docs/code_review_plan/plan.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Review Plan" + + - name: WeasyPrint_ReviewPlanPdf + description: "Code Review Plan PDF was generated by WeasyPrint" + tags: [code-review] + files: + - pattern: "docs/SonarMark Review Plan.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Review Plan" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Review Plan" + pages: + min: 1 + text: + - contains: "Review Plan" + + # --- CODE REVIEW REPORT --- + + - name: Pandoc_ReviewReportHtml + description: "Code Review Report HTML was generated by Pandoc" + tags: [code-review] + files: + - pattern: "docs/code_review_report/report.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Review Report" + + - name: WeasyPrint_ReviewReportPdf + description: "Code Review Report PDF was generated by WeasyPrint" + tags: [code-review] + files: + - pattern: "docs/SonarMark Review Report.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Review Report" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Review Report" + pages: + min: 1 + text: + - contains: "Review Report" + + # --- DESIGN DOCUMENT --- + + - name: Pandoc_DesignHtml + description: "Design HTML was generated by Pandoc" + tags: [design] + files: + - pattern: "docs/design/design.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Design" + + - name: WeasyPrint_DesignPdf + description: "Design PDF was generated by WeasyPrint" + tags: [design] + files: + - pattern: "docs/SonarMark Software Design.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Design" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Design Specification" + pages: + min: 3 + text: + - contains: "Design" + + # --- USER GUIDE --- + + - name: Pandoc_UserGuideHtml + description: "User Guide HTML was generated by Pandoc" + tags: [user-guide] + files: + - pattern: "docs/user_guide/user_guide.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "User Guide" + + - name: WeasyPrint_UserGuidePdf + description: "User Guide PDF was generated by WeasyPrint" + tags: [user-guide] + files: + - pattern: "docs/SonarMark User Guide.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "User Guide" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "SonarQube/SonarCloud Reporting" + pages: + min: 3 + text: + - contains: "User Guide" + + # --- REQUIREMENTS DOCUMENT --- + # Note: these tests run after ReqStream and do not contribute to OTS requirements evidence. + + - name: Pandoc_RequirementsHtml + description: "Requirements HTML was generated by Pandoc" + tags: [requirements] + files: + - pattern: "docs/requirements_doc/requirements.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Requirements" + + - name: WeasyPrint_RequirementsPdf + description: "Requirements PDF was generated by WeasyPrint" + tags: [requirements] + files: + - pattern: "docs/SonarMark Requirements.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Requirements" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Requirements" + pages: + min: 1 + text: + - contains: "Requirements" + + # --- TRACE MATRIX --- + # Note: these tests run after ReqStream and do not contribute to OTS requirements evidence. + + - name: Pandoc_TraceMatrixHtml + description: "Trace Matrix HTML was generated by Pandoc" + tags: [requirements] + files: + - pattern: "docs/requirements_report/trace_matrix.html" + count: 1 + html: + - query: "//head/title" + count: 1 + text: + - contains: "Trace Matrix" + + - name: WeasyPrint_TraceMatrixPdf + description: "Trace Matrix PDF was generated by WeasyPrint" + tags: [requirements] + files: + - pattern: "docs/SonarMark Trace Matrix.pdf" + count: 1 + pdf: + metadata: + - field: "Title" + contains: "Trace Matrix" + - field: "Author" + contains: "DEMA Consulting" + - field: "Subject" + contains: "Traceability" + pages: + min: 1 + text: + - contains: "Trace Matrix" diff --git a/.github/agents/developer.agent.md b/.github/agents/developer.agent.md index 2671008..35f5dda 100644 --- a/.github/agents/developer.agent.md +++ b/.github/agents/developer.agent.md @@ -1,28 +1,31 @@ --- name: developer -description: > - General-purpose software development agent that applies appropriate standards - based on the work being performed. +description: Comprehensive development agent for code, documentation, and requirements across multiple languages user-invocable: true --- # Developer Agent -Perform software development tasks by determining and applying appropriate DEMA Consulting standards from `.github/standards/`. +Perform software development tasks by determining and applying appropriate standards from `.github/standards/`. # Standards-Based Workflow 1. **Analyze the request** to identify scope: languages, file types, requirements, testing, reviews -2. **Read relevant standards** from `.github/standards/` as defined in AGENTS.md based on work performed -3. **Apply loaded standards** throughout development process +2. **Read relevant standards** using the selection matrix in AGENTS.md +3. **Pre-flight verification** before making any changes: + - List files that will be created, modified, or deleted + - For each modified file, identify which companion artifacts need updating + (requirements, design docs, tests, review-sets) + - Include companion artifact updates in the work plan 4. **Execute work** following standards requirements and quality checks -5. **Lint fixes** follow the linting process before performing quality gates -6. **Generate completion report** with results and compliance status +5. **Formatting**: Run `pwsh ./fix.ps1` to silently apply all + available auto-fixers (dotnet format, markdown, YAML) before committing +6. **Build and test** (code changes only): Run `pwsh ./build.ps1` and confirm it + passes — report FAILED if the build or any tests fail +7. **Generate completion report** per the AGENTS.md reporting requirements - save to + `.agent-logs/{agent-name}-{subject}-{unique-id}.md` and return the summary to the caller -# Reporting - -Upon completion create a summary in `.agent-logs/{agent-name}-{subject}-{unique-id}.md` -of the project consisting of: +# Report Template ```markdown # Developer Agent Report @@ -37,7 +40,7 @@ of the project consisting of: ## Tooling Executed -- **Language Tools**: {Compilers, linters, formatters used} +- **Language Tools**: {Compilers, formatters, and build tools used} - **Compliance Tools**: {ReqStream, ReviewMark tools used} - **Validation Results**: {Tool execution results} @@ -46,5 +49,3 @@ of the project consisting of: - **Quality Checks**: {Standards quality checks status} - **Issues Resolved**: {Any problems encountered and resolved} ``` - -Return this summary to the caller. diff --git a/.github/agents/code-review.agent.md b/.github/agents/formal-review.agent.md similarity index 51% rename from .github/agents/code-review.agent.md rename to .github/agents/formal-review.agent.md index bb48e5c..88b0691 100644 --- a/.github/agents/code-review.agent.md +++ b/.github/agents/formal-review.agent.md @@ -1,41 +1,45 @@ --- -name: code-review +name: formal-review description: Agent for performing formal reviews user-invocable: true --- -# Code Review Agent +# Formal Review Agent This agent runs the formal review based on the review-set it's told to perform. +Document findings only - never modify code during a review. -# Formal Review Steps +# Standards -Formal reviews are a quality enforcement mechanism, and as such MUST be performed using the following four steps: +Before reviewing, read these standards to inform review judgments: -1. Download the - - to get the checklist to fill in -2. Use `dotnet reviewmark --elaborate {review-set}` to get the files to review -3. Review the files all together -4. Populate the checklist with the findings to `.agent-logs/reviews/review-report-{review-set}.md` of the project. +- **`requirements-principles.md`** - establishes that requirements flow one-way + and that tests need not link to requirements; informs all requirements and + traceability review judgments +- **`software-items.md`** - defines System/Subsystem/Unit scope; informs all + hierarchy and categorization review judgments +- **`design-documentation.md`** - defines mandatory sections, structural conventions, + and coverage expected at each level; informs all design documentation review judgments -# Don't Do These Things +For review sets that include source code or tests, also consult the relevant +standards from the selection matrix in AGENTS.md. -- **Never modify code during review** (document findings only) -- **Never skip applicable checklist items** (comprehensive review required) -- **Never approve reviews with unresolved critical findings** -- **Never bypass review status requirements** for compliance -- **Never conduct reviews without proper documentation** -- **Never ignore security or compliance findings** -- **Never approve without verifying all quality gates** +# Formal Review Steps -# Reporting +1. Download the review checklist from + . + If the download fails, report the failure rather than proceeding without the template. +2. Use `dotnet reviewmark --elaborate {review-set}` to get the files to review +3. Review all files holistically, checking for cross-file consistency and + compliance with the review checklist +4. Save the populated review checklist to `.agent-logs/reviews/review-report-{review-set}.md`. + This directory holds formal review artifacts, not agent logs. +5. Generate a completion report per the AGENTS.md reporting requirements. -Upon completion create a summary in `.agent-logs/{agent-name}-{subject}-{unique-id}.md` -of the project consisting of: +# Report Template ```markdown -# Code Review Report +# Formal Review Report **Result**: (SUCCEEDED|FAILED) @@ -70,5 +74,3 @@ For each issue found, include: - **Quality Gates**: {Status of review checklist items} - **Approval Status**: {Approved/Rejected with justification} ``` - -Return summary to caller. diff --git a/.github/agents/implementation.agent.md b/.github/agents/implementation.agent.md index 03603a4..7cc0352 100644 --- a/.github/agents/implementation.agent.md +++ b/.github/agents/implementation.agent.md @@ -16,70 +16,105 @@ systematically. the quality of the implementation. The process consists of the following states: -- **RESEARCH** - performs initial analysis +- **PLANNING** - analyzes the request, develops a plan, and self-validates it - **DEVELOPMENT** - develops the implementation changes - **QUALITY** - performs quality validation - **REPORT** - generates final implementation report -The state-transitions include retrying a limited number of times, using a 'retry-count' -counting how many retries have occurred. +The state-transitions include retrying a limited number of times: -## RESEARCH State (start) +- **Quality retry budget**: maximum 3 retries (QUALITY → PLANNING) - when + exhausted, transition directly to REPORT with Result: FAILED -Call the built-in explore sub-agent with: +## PLANNING State (start) -- **context**: the user's request + any previous quality findings + retry context -- **goal**: analyze the implementation state and develop a plan to implement the request +Call the **explore** agent as a sub-agent (built-in agent type) with: -Once the explore sub-agent finishes, transition to the DEVELOPMENT state. +- **context**: the user's request + any previous quality findings + retry context +- **goal**: produce a verified implementation plan through these steps: + + 1. Investigate the codebase and develop a concrete implementation plan that + addresses the request + 2. **Identify companion artifact deliverables**: for every code change in the + plan, list the requirements files, design documents, and review-set entries + that must be created or updated - traceability must flow requirements → + design → code, so these are mandatory deliverables, not optional extras + 3. Review the plan for assumptions, weaknesses, and gaps - identify up to 5 + key assumptions and rate each as: + - **VERIFIED**: confirmed by codebase evidence + - **LIKELY**: consistent with codebase patterns but not directly confirmed + - **UNVERIFIED**: not confirmed by any evidence + 4. For any assumption rated UNVERIFIED or LIKELY, attempt to resolve it + through additional investigation and revise the plan to address identified + weaknesses - repeat the critique-and-strengthen cycle up to 2 additional + times if unresolved issues remain, but stop as soon as the plan is stable + 5. List up to 5 risks to the implementation + 6. Assess feasibility: can this be implemented in a single development pass? + 7. State a **recommendation**: GO or INCOMPLETE - GO if the plan is sound, or + INCOMPLETE if critical unknowns remain that only the user can resolve + +Once the explore sub-agent finishes: + +- IF recommendation is INCOMPLETE: Transition to REPORT with Result: INCOMPLETE, + listing the unknowns and what CAN be implemented once they are resolved +- OTHERWISE (GO): Transition to DEVELOPMENT ## DEVELOPMENT State -Call the developer sub-agent with: +Call the **developer** agent as a sub-agent (custom agent from `.github/agents/`) with: -- **context** the user's request + research plan + specific quality issues to address (if retry) -- **goal** implement the user's request and any identified quality fixes +- **context**: the user's request + planning results + specific quality issues to address (if retry) +- **goal**: implement the user's request as described in the planning results, addressing + any identified quality fixes Once the developer sub-agent finishes: - IF developer SUCCEEDED: Transition to QUALITY state to check the quality of the work -- IF developer FAILED: Transition to REPORT state to report the failure +- OTHERWISE (FAILED): Transition to REPORT state to report the failure ## QUALITY State -Call the quality sub-agent with: +Call the **quality** agent as a sub-agent (custom agent from `.github/agents/`) with: -- **context** the user's request + development summary + files changed + previous issues (if any) -- **goal** check the quality of the work performed for any issues +- **context**: the user's request + development summary + files changed + previous issues (if any) +- **goal**: check the quality of the work performed for any issues Once the quality sub-agent finishes: - IF quality SUCCEEDED: Transition to REPORT state to report completion -- IF quality FAILED and retry-count < 3: Transition to RESEARCH state to plan quality fixes -- IF quality FAILED and retry-count >= 3: Transition to REPORT state to report failure +- IF quality FAILED and quality retry budget not exhausted: Transition to PLANNING + state to plan quality fixes (counts against the quality retry budget) +- OTHERWISE (budget exhausted): Transition to REPORT state to report failure + +## REPORT State (end) -### REPORT State (end) +**Implementation-specific Result rule**: In addition to SUCCEEDED and FAILED, +this agent may report INCOMPLETE when the request cannot be implemented without +information only the user can provide. -Upon completion create a summary in `.agent-logs/{agent-name}-{subject}-{unique-id}.md` -of the project consisting of: +Generate the completion report using the template below, then save it to +`.agent-logs/{agent-name}-{subject}-{unique-id}.md` per the AGENTS.md reporting +requirements, and return the summary to the caller. + +# Report Template ```markdown # Implementation Orchestration Report -**Result**: (SUCCEEDED|FAILED) -**Final State**: (RESEARCH|DEVELOPMENT|QUALITY|REPORT) +**Result**: (SUCCEEDED|FAILED|INCOMPLETE) +**Final State**: (PLANNING|DEVELOPMENT|QUALITY|REPORT) **Retry Count**: ## State Machine Execution -- **Research Results**: {Summary of explore agent findings} +- **Planning Results**: {Implementation plan, assumption ratings, risks, and recommendation} - **Development Results**: {Summary of developer agent results} - **Quality Results**: {Summary of quality agent results} - **State Transitions**: {Log of state changes and decisions} ## Sub-Agent Coordination -- **Explore Agent**: {Research findings and context} +- **Explore Agent (Planning)**: {Plan, assumption verdicts, top risks, GO/INCOMPLETE recommendation} - **Developer Agent**: {Development status and files modified} - **Quality Agent**: {Validation results and compliance status} @@ -89,5 +124,3 @@ of the project consisting of: - **Quality Compliance**: {Final quality validation status} - **Issues Resolved**: {Problems encountered and resolution attempts} ``` - -Return this summary to the caller. diff --git a/.github/agents/lint-fix.agent.md b/.github/agents/lint-fix.agent.md new file mode 100644 index 0000000..83ad8cb --- /dev/null +++ b/.github/agents/lint-fix.agent.md @@ -0,0 +1,77 @@ +--- +name: lint-fix +description: Fixes all lint issues. Run this once before submitting a pull request. +user-invocable: true +--- + +# Lint Fix Agent + +Fix all lint issues in the repository until `pwsh ./lint.ps1` exits cleanly. +This is the **pre-PR lint sweep** - run it once before pull request +submission, not during normal development. + +# Workflow (MANDATORY) + +1. **Auto-fix pass**: Run `pwsh ./fix.ps1` to silently apply all + automatic fixes (dotnet format, markdownlint, yamlfix). + +2. **Fix loop** (maximum 5 iterations): + + a. Run `pwsh ./lint.ps1` and capture the full output. + + b. If exit code is 0 - the repository is lint-clean. Proceed to the report. + + c. Parse the failures and fix each one using the guidance below. + + d. Repeat. + +3. **Budget exhausted**: If still failing after 5 iterations, report the + remaining issues and stop with Result: FAILED. + +# Fix Guidance by Failure Type + +- **cspell spelling errors**: Add legitimate technical terms to `.cspell.yaml` + under the `words` list. Correct genuine misspellings in the source text. + Do not add misspelled words to the dictionary. + +- **markdownlint MD013 (line length)**: Wrap long lines at natural break points, + after commas, before conjunctions, or at sentence boundaries. Do not break + in the middle of a code span or URL. + +- **markdownlint other rules**: Apply the specific fix indicated in the output + (e.g., missing blank lines, heading levels, code fence languages). + +- **yamllint errors**: Fix indentation, trailing spaces, or missing document + markers as indicated. Run `pwsh ./fix.ps1` again if structural YAML + issues appear - yamlfix may handle them. + +- **reqstream / reviewmark / versionmark failures**: Fix the referenced + requirements or review configuration per the standards in + `.github/standards/reqstream-usage.md` and `.github/standards/reviewmark-usage.md`. + +# Rules + +- Fix **only** lint issues - do not refactor, restructure, or make functional changes +- For spelling: prefer adding terms to `.cspell.yaml` over rewriting correct technical text +- Never modify auto-generated files (check file headers for "auto-generated" or "do not edit") +- Respect all protected configuration files listed in AGENTS.md +- Report **all** files modified + +# Report Template + +```markdown +# Lint Fix Report + +**Result**: (SUCCEEDED|FAILED) + +## Summary + +- **Iterations**: {Number of fix-loop iterations performed} +- **Files Modified**: {List of all files changed} +- **Issues Fixed**: {Brief categorized description of what was corrected} + +## Remaining Issues (only when Result is FAILED) + +{List of unfixed lint failures with file:line references and why they could +not be automatically resolved} +``` diff --git a/.github/agents/quality.agent.md b/.github/agents/quality.agent.md index 8376693..da467d4 100644 --- a/.github/agents/quality.agent.md +++ b/.github/agents/quality.agent.md @@ -1,137 +1,130 @@ --- name: quality -description: > - Quality assurance agent that grades developer work against DEMA Consulting - standards and Continuous Compliance practices. +description: Quality assurance agent that validates work against project standards, compliance practices, and quality gates. user-invocable: true --- # Quality Agent -Grade and validate software development work by ensuring compliance with -DEMA Consulting standards and Continuous Compliance practices. +Grade and validate software development work by ensuring compliance with project standards and practices. # Standards-Based Quality Assessment -This assessment is a quality control system of the project and MUST be performed systematically. +1. **Analyze the task request AND completed work** to determine scope: identify + which artifact categories were changed, and which *should have been changed* + given the task - new user-visible features always require requirements, + design, and review-set coverage regardless of whether those files were touched; + test-only additions (corner-case tests, defensive boundary tests, regression + tests) do not require a corresponding requirement +2. **Read relevant standards** using the selection matrix in AGENTS.md +3. **Evaluate all in-scope categories** - N/A only when the task genuinely + cannot affect a category; if the task introduces new user-visible features or + structural changes then Requirements, Design Documentation, and Review + Management are always in scope and FAIL if the artifacts were not updated +4. **Validate tool compliance** using ReqStream, ReviewMark, and build tools +5. **Generate focused quality report** per the AGENTS.md reporting requirements - save to + `.agent-logs/{agent-name}-{subject}-{unique-id}.md` and return the summary to the caller -1. **Analyze completed work** to identify scope and changes made -2. **Read relevant standards** from `.github/standards/` as defined in AGENTS.md based on work performed -3. **Execute comprehensive quality assessment** using the structured evaluation criteria in the reporting template -4. **Validate tool compliance** using ReqStream, ReviewMark, and language tools -5. **Generate quality assessment report** with findings and recommendations +**Quality-specific Result rule**: Result SUCCEEDED requires Overall Grade PASS. +Result FAILED when Overall Grade is FAIL. -# Reporting +# Report Template -Upon completion create a summary in `.agent-logs/{agent-name}-{subject}-{unique-id}.md` -of the project consisting of: +For each checklist item in the template below, record as `(PASS|FAIL|N/A) - {one-line evidence}`. ```markdown # Quality Assessment Report **Result**: (SUCCEEDED|FAILED) -**Overall Grade**: (PASS|FAIL|NEEDS_WORK) +**Overall Grade**: (PASS|FAIL) -## Assessment Summary +## Required Fixes (only when Result is FAILED) -- **Work Reviewed**: {Description of work assessed} -- **Standards Applied**: {Standards files used for assessment} -- **Categories Evaluated**: {Quality check categories assessed} +Priority-ordered list of issues that MUST be resolved for the next retry: + +1. **[severity]** {one-line description} + - File: {path:line} + - Action: {specific fix instruction} + +## Evaluation Scope + +- **Evaluated**: {List sections assessed and why} +- **Skipped**: {One-line per skipped section with reason, e.g., "Design + Documentation: N/A - no design files modified"} ## Requirements Compliance: (PASS|FAIL|N/A) -- Were requirements updated to reflect functional changes? (PASS|FAIL|N/A) - {Evidence} -- Were new requirements created for new features? (PASS|FAIL|N/A) - {Evidence} -- Do requirement IDs follow semantic naming standards? (PASS|FAIL|N/A) - {Evidence} -- Do requirement files follow kebab-case naming convention? (PASS|FAIL|N/A) - {Evidence} -- Are requirement files organized under `docs/reqstream/` with proper folder structure? (PASS|FAIL|N/A) - {Evidence} -- Are OTS requirements properly placed in `docs/reqstream/ots/` subfolder? (PASS|FAIL|N/A) - {Evidence} -- Were source filters applied appropriately for platform-specific requirements? (PASS|FAIL|N/A) - {Evidence} -- Does ReqStream enforcement pass without errors? (PASS|FAIL|N/A) - {Evidence} -- Is requirements traceability maintained to tests? (PASS|FAIL|N/A) - {Evidence} +- Were requirements updated to reflect functional changes? +- Were new requirements created for new features? +- Do requirement IDs follow semantic naming standards? +- Do requirement files follow kebab-case naming convention? +- Are requirement files organized under `docs/reqstream/` with proper folder structure? +- Are OTS requirements properly placed in `docs/reqstream/ots/` subfolder? +- Were source filters applied appropriately for platform-specific requirements? +- Is requirements traceability maintained to tests? ## Design Documentation Compliance: (PASS|FAIL|N/A) -- Were design documents updated for architectural changes? (PASS|FAIL|N/A) - {Evidence} -- Were new design artifacts created for new components? (PASS|FAIL|N/A) - {Evidence} -- Do design folder names use kebab-case convention matching source structure? (PASS|FAIL|N/A) - {Evidence} -- Are design files properly named ({subsystem-name}.md, {unit-name}.md patterns)? (PASS|FAIL|N/A) - {Evidence} -- Is `docs/design/introduction.md` present with required Software Structure section? (PASS|FAIL|N/A) - {Evidence} -- Are design decisions documented with rationale? (PASS|FAIL|N/A) - {Evidence} -- Is system/subsystem/unit categorization maintained? (PASS|FAIL|N/A) - {Evidence} -- Is design-to-implementation traceability preserved? (PASS|FAIL|N/A) - {Evidence} +- Were design documents updated for architectural changes? +- Were new design artifacts created for new components? +- Do design folder names use kebab-case convention matching source structure? +- Are design files properly named ({subsystem-name}.md, {unit-name}.md patterns)? +- Is `docs/design/introduction.md` present with required Software Structure section? +- Are design decisions documented with rationale? +- Is system/subsystem/unit categorization maintained? +- Is design-to-implementation traceability preserved? ## Code Quality Compliance: (PASS|FAIL|N/A) -- Are language-specific standards followed (from applicable standards files)? (PASS|FAIL|N/A) - {Evidence} -- Are quality checks from standards files satisfied? (PASS|FAIL|N/A) - {Evidence} -- Is code properly categorized (system/subsystem/unit/OTS)? (PASS|FAIL|N/A) - {Evidence} -- Is appropriate separation of concerns maintained? (PASS|FAIL|N/A) - {Evidence} -- Was language-specific tooling executed and passing? (PASS|FAIL|N/A) - {Evidence} +- Are language-specific standards followed (from applicable standards files)? +- Are quality checks from standards files satisfied? +- Is code properly categorized (system/subsystem/unit/OTS)? +- Is appropriate separation of concerns maintained? +- Was language-specific build tooling executed and passing? ## Testing Compliance: (PASS|FAIL|N/A) -- Were tests created/updated for all functional changes? (PASS|FAIL|N/A) - {Evidence} -- Is test coverage maintained for all requirements? (PASS|FAIL|N/A) - {Evidence} -- Are testing standards followed (AAA pattern, etc.)? (PASS|FAIL|N/A) - {Evidence} -- Do tests respect software item hierarchy boundaries (System/Subsystem/Unit scope)? (PASS|FAIL|N/A) - {Evidence} -- Are cross-hierarchy test dependencies documented in design docs? (PASS|FAIL|N/A) - {Evidence} -- Does test categorization align with code structure? (PASS|FAIL|N/A) - {Evidence} -- Do all tests pass without failures? (PASS|FAIL|N/A) - {Evidence} +- Were tests created/updated for all functional changes? +- Is test coverage maintained for all requirements? +- Are testing standards followed (AAA pattern, etc.)? +- Do tests respect software item hierarchy boundaries (System/Subsystem/Unit scope)? +- Are cross-hierarchy test dependencies documented in design docs? +- Does test categorization align with code structure? +- Do all tests pass without failures? ## Review Management Compliance: (PASS|FAIL|N/A) -- Were review-sets updated for structural changes (new/deleted systems, subsystems, or units)? (PASS|FAIL|N/A) - {Evidence} -- Do file patterns follow include-then-exclude approach? (PASS|FAIL|N/A) - {Evidence} -- Is review scope appropriate for change magnitude? (PASS|FAIL|N/A) - {Evidence} -- Was ReviewMark tooling executed and passing? (PASS|FAIL|N/A) - {Evidence} -- Were review artifacts generated correctly? (PASS|FAIL|N/A) - {Evidence} +- Were review-sets updated for structural changes (new/deleted systems, subsystems, or units)? +- Do file patterns follow include-then-exclude approach? +- Is review scope appropriate for change magnitude? +- Was ReviewMark tooling executed and passing? +- Were review artifacts generated correctly? ## Documentation Compliance: (PASS|FAIL|N/A) -- Was README.md updated for user-facing changes? (PASS|FAIL|N/A) - {Evidence} -- Were user guides updated for feature changes? (PASS|FAIL|N/A) - {Evidence} -- Does API documentation reflect code changes? (PASS|FAIL|N/A) - {Evidence} -- Was compliance documentation generated? (PASS|FAIL|N/A) - {Evidence} -- Does documentation follow standards formatting? (PASS|FAIL|N/A) - {Evidence} -- Is documentation organized under `docs/` following standard folder structure? (PASS|FAIL|N/A) - {Evidence} -- Do Pandoc collections include proper `introduction.md` with Purpose and Scope sections? (PASS|FAIL|N/A) - {Evidence} -- Are auto-generated markdown files left unmodified? (PASS|FAIL|N/A) - {Evidence} -- Do README.md files use absolute URLs and include concrete examples? (PASS|FAIL|N/A) - {Evidence} -- Is documentation integrated into ReviewMark review-sets for formal review? (PASS|FAIL|N/A) - {Evidence} +- Was README.md updated for user-facing changes? +- Were user guides updated for feature changes? +- Does API documentation reflect code changes? +- Was compliance documentation generated? +- Does documentation follow standards formatting? +- Is documentation organized under `docs/` following standard folder structure? +- Do Pandoc collections include proper `introduction.md` with Purpose and Scope sections? +- Are auto-generated markdown files left unmodified? +- Do README.md files use absolute URLs and include concrete examples? +- Is documentation integrated into ReviewMark review-sets for formal review? ## Software Item Completeness: (PASS|FAIL|N/A) -- Does every identified software unit have its own requirements file? (PASS|FAIL|N/A) - {Evidence} -- Does every identified software unit have its own design document? (PASS|FAIL|N/A) - {Evidence} -- Does every identified subsystem have its own requirements file? (PASS|FAIL|N/A) - {Evidence} -- Does every identified subsystem have its own design document? (PASS|FAIL|N/A) - {Evidence} +- Does every identified software unit have its own requirements file? +- Does every identified software unit have its own design document? +- Does every identified subsystem have its own requirements file? +- Does every identified subsystem have its own design document? ## Process Compliance: (PASS|FAIL|N/A) -- Was Continuous Compliance workflow followed? (PASS|FAIL|N/A) - {Evidence} -- Did all quality gates execute successfully? (PASS|FAIL|N/A) - {Evidence} -- Were appropriate tools used for validation? (PASS|FAIL|N/A) - {Evidence} -- Were standards consistently applied across work? (PASS|FAIL|N/A) - {Evidence} -- Was compliance evidence generated and preserved? (PASS|FAIL|N/A) - {Evidence} - -## Overall Findings - -- **Critical Issues**: {Count and description of critical findings} -- **Recommendations**: {Suggested improvements and next steps} -- **Tools Executed**: {Quality tools used for validation} - -## Compliance Status - -- **Standards Adherence**: {Overall compliance rating with specific standards} -- **Quality Gates**: {Status of automated quality checks with tool outputs} +- Was Continuous Compliance workflow followed? +- Did all quality gates execute successfully? +- Were appropriate tools used for validation? +- Were standards consistently applied across work? +- Was compliance evidence generated and preserved? ``` - -The **Result** field MUST reflect the quality validation outcome for orchestrator decision-making: - -- **Result: SUCCEEDED** - Only when Overall Grade is PASS (all compliance requirements met) -- **Result: FAILED** - When Overall Grade is FAIL or NEEDS_WORK (compliance failures present) - -This ensures orchestrators properly halt workflows when quality gates fail. - -Return this summary to the caller. diff --git a/.github/agents/repo-consistency.agent.md b/.github/agents/repo-consistency.agent.md index b623895..5dbe99f 100644 --- a/.github/agents/repo-consistency.agent.md +++ b/.github/agents/repo-consistency.agent.md @@ -23,6 +23,8 @@ benefit from template evolution while respecting project-specific customizations while respecting project-specific customizations 4. **Apply Appropriate Updates**: Implement applicable template improvements with proper translation for project context 5. **Validate Consistency**: Verify that applied changes maintain functionality and follow project patterns +6. **Generate completion report** per the AGENTS.md reporting requirements - save to + `.agent-logs/{agent-name}-{subject}-{unique-id}.md` and return the summary to the caller ## Key Principles @@ -40,10 +42,7 @@ benefit from template evolution while respecting project-specific customizations - **Never skip validation** of preserved functionality after template alignment - **Never assume all template patterns apply universally** (assess project-specific needs) -# Reporting - -Upon completion create a summary in `.agent-logs/{agent-name}-{subject}-{unique-id}.md` -of the project consisting of: +# Report Template ```markdown # Repo Consistency Report @@ -76,5 +75,3 @@ of the project consisting of: - **Enhancement Adoptions**: {Template improvements successfully integrated} - **Validation Results**: {Testing and validation outcomes} ``` - -Return this summary to the caller. diff --git a/.github/agents/software-architect.agent.md b/.github/agents/software-architect.agent.md new file mode 100644 index 0000000..494568d --- /dev/null +++ b/.github/agents/software-architect.agent.md @@ -0,0 +1,158 @@ +--- +name: software-architect +description: Agent for collaboratively interacting with the user to develop software architecture +user-invocable: true +disable-model-invocation: false +default-mode: sync +--- + +# Role + +Interview the user and produce evolving architecture documentation with prioritized concerns. + +# Standards + +Read `.github/standards/software-items.md` before starting. Use its definitions +(Software Package, System, Subsystem, Unit, OTS) as vocabulary throughout. + +# Approach + +- Ask one question at a time +- Update tree and concerns every 2-3 questions +- Use 18-25 questions as a rough complexity heuristic, not a hard limit or target + +# Core Questions + +- **Scope**: single package or multi-package system? +- **Discovery**: purpose and stakeholders, expected scale, existing system integrations +- **Technology**: language/framework, database, infrastructure/cloud +- **Functionality**: critical features, key data entities and workflows, external services +- **Quality**: + - Performance: response time, throughput + - Security: authentication, authorization, compliance + - Availability: uptime, failover, disaster recovery + - Observability: logging, metrics, alerting +- **Future**: areas likely to change, extensibility plans + +# Interview Process + +Work through the Core Questions in order. The **Scope** answer determines the +tree mode for the rest of the interview: + +- **Single package**: explore System → Subsystems → Units for all remaining topics +- **Multi-package**: focus only on package decomposition (name, responsibility, + inter-package interfaces); do not drill into each package's internals - + each package is architected independently in a separate session + +# Wrapping Up + +Once the Core Questions have been covered and the architecture tree and concerns +feel stable, prompt the user before ending the interview: + +> "I feel I have a solid understanding of the architecture. Is there anything +> else you'd like to add or clarify, or shall I write up the architecture document?" + +Continue the interview as long as the user wants. Only produce the deliverable +when the user confirms they are satisfied. + +# Output Format + +After every update, show the current tree and concerns. + +**Single-package** - System → Subsystems → Units. Collapse to ~20 items with "...": + +```text +SystemName +├── Subsystem +│ ├── Unit +│ └── Unit +└── Subsystem (Unit, Unit/...) +``` + +**Multi-package** - packages only; no internal structure (each package is +architected independently in a separate session). Packages may be hierarchical: + +```text +ProductName +├── PackageA - responsibility summary +│ ├── PackageA.Child1 - responsibility summary +│ └── PackageA.Child2 - responsibility summary +├── PackageB - responsibility summary +└── PackageC - responsibility summary +``` + +**Concerns** - architectural gaps and decision points only, not implementation quality: + +1. 🔴 **HIGH** \: \ +2. 🟡 **MEDIUM** \: \ +3. 🟢 **LOW** \: \ + +# Deliverable + +At the end of the interview, produce a standalone guidance document (suitable +for attaching to a work item or issue ticket). Write it as `architecture.md` in +the current working directory. Do not place it in `docs/`, the session workspace, +or any other location, and do not commit it unless the user explicitly asks. +Use the appropriate template below, filled from the interview conversation. + +## Single-Package Template (`architecture.md`) + +```markdown +# [SystemName] Architecture + +## Purpose + +[What this system does, who it is for, and why it exists.] + +## Scope + +[What is included. What is explicitly excluded.] + +## Technology Stack + +[Language, framework, database, infrastructure/cloud choices.] + +## Software Structure + +[System → Subsystem → Unit tree from the interview.] + +## Architectural Decisions + +[Constraints, trade-offs, and non-obvious choices surfaced during the +interview. Each entry should state the decision and the reason.] + +## Open Concerns + +[Outstanding 🔴🟡🟢 concerns from the interview that require resolution.] +``` + +## Multi-Package Template (`architecture.md`) + +```markdown +# [ProductName] Architecture + +## Purpose + +[What this product does, who it is for, and why it exists.] + +## Scope + +[What is included. What is explicitly excluded.] + +## Package Structure + +[Package hierarchy tree from the interview, with responsibility summaries.] + +## Inter-Package Interfaces + +[How packages communicate or depend on each other.] + +## Architectural Decisions + +[Constraints, trade-offs, and non-obvious choices surfaced during the +interview. Each entry should state the decision and the reason.] + +## Open Concerns + +[Outstanding 🔴🟡🟢 concerns from the interview that require resolution.] +``` diff --git a/.github/standards/coding-principles.md b/.github/standards/coding-principles.md index b00143d..213c031 100644 --- a/.github/standards/coding-principles.md +++ b/.github/standards/coding-principles.md @@ -14,9 +14,15 @@ Continuous Compliance environments. All code MUST follow literate programming principles: -- **Intent Comments**: Every function/method begins with a comment explaining WHY (not what) -- **Logical Separation**: Complex functions use comments to separate logical blocks +- **Intent Documentation**: Function and method documentation (XmlDoc, Doxygen, + JSDoc, etc.) MUST explain WHY the function exists and its design purpose - + not just restate what it does - because reviewers must verify implementation + matches design intent without reading the full codebase +- **Logical Separation**: Complex functions use block comments to separate and + describe logical steps within the implementation - **Public Documentation**: All public interfaces have comprehensive documentation + because consumers and auditors rely on interface contracts for integration + and compliance verification - **Clarity Over Cleverness**: Code should be immediately understandable by team members ## Universal Code Architecture Principles @@ -28,9 +34,8 @@ All code MUST follow literate programming principles: - **Pure Functions**: Minimize side effects and hidden state - **Clear Interfaces**: Well-defined API contracts - **Separation of Concerns**: Business logic separate from infrastructure -- **Repository Structure Adherence**: Before creating any new files, analyze the repository structure to - understand established directory conventions and file placement patterns. Place new files in locations - consistent with existing patterns. +- **Repository Structure Adherence**: Analyze existing directory conventions + before creating files; place new files consistent with established patterns ### Compliance-Ready Code Structure @@ -53,7 +58,8 @@ All code MUST follow literate programming principles: - **Skip Literate Coding**: Don't skip literate programming comments - they are required for maintainability - **Ignore Compiler Warnings**: Don't ignore compiler warnings - they exist for quality enforcement - **Hidden Dependencies**: Don't create untestable code with hidden dependencies -- **Hidden Functionality**: Don't implement functionality without requirement traceability +- **Hidden Functionality**: Don't implement functionality without requirement + traceability because untraced functionality cannot be validated during audits - **Monolithic Functions**: Don't write monolithic functions with multiple responsibilities - **Overcomplicated Solutions**: Don't make solutions more complex than necessary - favor simplicity and clarity - **Premature Optimization**: Don't optimize for performance before establishing correctness @@ -62,9 +68,5 @@ All code MUST follow literate programming principles: # Language-Specific Implementation -For each detected language: - -- **Load Standards**: Read the appropriate `{language}-language.md` file from `.github/standards/` -- **Apply Tooling**: Use language-specific formatting, linting, and build tools -- **Follow Conventions**: Apply language-specific naming, patterns, and best practices -- **Generate Documentation**: Use language-appropriate documentation format (XmlDoc, Doxygen, JSDoc, etc.) +For each detected language, read `{language}-language.md` from `.github/standards/` +and apply its standards, tooling, and conventions. diff --git a/.github/standards/csharp-language.md b/.github/standards/csharp-language.md index 5dbdda6..707b0f9 100644 --- a/.github/standards/csharp-language.md +++ b/.github/standards/csharp-language.md @@ -45,3 +45,4 @@ return OutputFormatter.Format(validatedResults); - [ ] Zero compiler warnings (`TreatWarningsAsErrors=true`) - [ ] XmlDoc documentation complete on all members (public, internal, protected, private) +- [ ] `dotnet format` applied (run `pwsh ./fix.ps1`) diff --git a/.github/standards/csharp-testing.md b/.github/standards/csharp-testing.md index 3d9de81..1591eeb 100644 --- a/.github/standards/csharp-testing.md +++ b/.github/standards/csharp-testing.md @@ -6,7 +6,7 @@ globs: ["**/test/**/*.cs", "**/tests/**/*.cs", "**/*Tests.cs", "**/*Test.cs"] # C# Testing Standards (MSTest) -This document defines DEMA Consulting standards for C# test development using +This document defines standards for C# test development using MSTest within Continuous Compliance environments. ## Required Standards diff --git a/.github/standards/design-documentation.md b/.github/standards/design-documentation.md index f5bbbcd..30becb5 100644 --- a/.github/standards/design-documentation.md +++ b/.github/standards/design-documentation.md @@ -6,10 +6,9 @@ globs: ["docs/design/**/*.md"] # Design Documentation Standards -This document defines DEMA Consulting standards for design documentation -within Continuous Compliance environments, extending the general technical -documentation standards with specific requirements for software design -artifacts. +This document defines standards for design documentation within Continuous +Compliance environments, extending the general technical documentation +standards with specific requirements for software design artifacts. ## Required Standards @@ -39,8 +38,9 @@ docs/design/ ├── introduction.md # Design overview with software structure └── {system-name}/ # System-level design folder (one per system) ├── {system-name}.md # System-level design documentation - ├── {subsystem-name}/ # Subsystem design documents (kebab-case folder names) + ├── {subsystem-name}/ # Subsystem (kebab-case); may nest recursively │ ├── {subsystem-name}.md # Subsystem overview and design + │ ├── {child-subsystem}/ # Child subsystem (same structure as parent) │ └── {unit-name}.md # Unit-level design documents └── {unit-name}.md # Top-level unit design documents (if not in subsystem) ``` @@ -74,6 +74,8 @@ Example format: ```text Project1Name (System) ├── ComponentA (Subsystem) +│ ├── SubComponentP (Subsystem) +│ │ └── ClassW (Unit) │ ├── ClassX (Unit) │ └── ClassY (Unit) ├── ComponentB (Subsystem) @@ -94,14 +96,35 @@ Example format: ```text src/Project1Name/ ├── ComponentA/ -│ ├── ClassX.cs — Core business logic handler -│ └── ClassY.cs — Data validation service +│ ├── SubComponentP/ +│ │ └── ClassW.cs - Specialized processing engine +│ ├── ClassX.cs - Core business logic handler +│ └── ClassY.cs - Data validation service ├── ComponentB/ -│ └── ClassZ.cs — Integration interface -└── UtilityClass.cs — Common utility functions +│ └── ClassZ.cs - Integration interface +└── UtilityClass.cs - Common utility functions src/Project2Name/ -└── HelperClass.cs — Helper functions +└── HelperClass.cs - Helper functions +``` + +### Companion Artifact Structure (RECOMMENDED) + +Include a brief note explaining that each software item has parallel artifacts +across the repository, so agents and reviewers can navigate from any one +artifact to all related files: + +Example format: + +```text +Each software item in the structure above has corresponding artifacts in +parallel directory trees: + +- Requirements: `docs/reqstream/{system}/.../{item}.yaml` (kebab-case) +- Design docs: `docs/design/{system}/.../{item}.md` (kebab-case) +- Source code: `src/{System}/.../{Item}.{ext}` (cased per language - see `software-items.md`) +- Tests: `test/{System}.Tests/.../{Item}Tests.{ext}` (cased per language - see `software-items.md`) +- Review-sets: defined in `.reviewmark.yaml` ``` ## System Design Documentation (MANDATORY) @@ -133,12 +156,9 @@ For every unit identified in the software structure: # Software Items Integration (CRITICAL) -Before creating design documentation, agents MUST: - -1. **Read `.github/standards/software-items.md`** to understand System/Subsystem/Unit classifications -2. **Apply proper categorization** when creating software structure diagrams -3. **Ensure consistency** between software structure and folder layout -4. **Validate mapping** from design categories to source code organization +Read `software-items.md` before creating design documentation - correct +System/Subsystem/Unit categorization is required for software structure +diagrams and folder layout. # Writing Guidelines diff --git a/.github/standards/reqstream-usage.md b/.github/standards/reqstream-usage.md index e4103b1..ae5e565 100644 --- a/.github/standards/reqstream-usage.md +++ b/.github/standards/reqstream-usage.md @@ -4,42 +4,18 @@ description: Follow these standards when managing requirements with ReqStream. globs: ["requirements.yaml", "docs/reqstream/**/*.yaml"] --- -# ReqStream Requirements Management Standards - -This document defines DEMA Consulting standards for requirements management -using ReqStream within Continuous Compliance environments. - -## Required Standards +# Required Standards Read these standards first before applying this standard: +- **`requirements-principles.md`** - Requirements principles and unidirectionality - **`software-items.md`** - Software categorization (System/Subsystem/Unit/OTS) -# Core Principles - -ReqStream implements Continuous Compliance methodology for automated evidence -generation: - -- **Requirements Traceability**: Every requirement MUST link to passing tests -- **Platform Evidence**: Source filters ensure correct testing environment - validation -- **Quality Gate Enforcement**: CI/CD fails on requirements without test - coverage -- **Audit Documentation**: Generated reports provide compliance evidence - -# Software Items Integration (CRITICAL) - -Before creating requirements files, agents MUST: - -1. **Read `.github/standards/software-items.md`** to understand System/Subsystem/Unit/OTS classifications -2. **Apply proper categorization** when organizing requirements files -3. **Mirror source code structure** in requirements folder organization - # Requirements Organization -Organize requirements into separate files under `docs/reqstream/` mirroring -the source code structure because reviewers need clear navigation from -requirements to design to implementation: +Organize requirements under `docs/reqstream/` mirroring the source code structure +because ReqStream discovers files via the includes chain in `requirements.yaml` +and organizes report output by this hierarchy: ```text requirements.yaml # Root file (includes only) @@ -47,67 +23,38 @@ docs/reqstream/ ├── {system-name}/ # System-level requirements folder (one per system) │ ├── {system-name}.yaml # System-level requirements │ ├── platform-requirements.yaml # Platform support requirements -│ ├── {subsystem-name}/ # Subsystem requirements (kebab-case folders) +│ ├── {subsystem-name}/ # Subsystem (kebab-case); may nest recursively │ │ ├── {subsystem-name}.yaml # Requirements for this subsystem +│ │ ├── {child-subsystem}/ # Child subsystem (same structure as parent) │ │ └── {unit-name}.yaml # Requirements for units within this subsystem │ └── {unit-name}.yaml # Requirements for top-level units (outside subsystems) -└── ots/ # OTS software items folder +└── ots/ # OTS items appear as a distinct section in reports └── {ots-name}.yaml # Requirements for OTS components ``` -The folder structure MUST mirror the source code organization to maintain -consistency with design documentation and enable automated tooling. - -# Requirement Hierarchies and Links - -Requirements link downward only - higher-level requirements reference lower-level -ones they decompose into: - -- **System requirements** → may link to subsystem or unit requirements -- **Subsystem requirements** → may link to unit requirements within that subsystem -- **Unit requirements** → should NOT link upward to parent requirements - -This prevents circular dependencies and ensures clear hierarchical relationships -for compliance auditing. - -# Test Linkage Hierarchy - -Requirements MUST link to tests at their own level to maintain proper test scope: - -- **System requirements** → link ONLY to system-level integration tests -- **Subsystem requirements** → link ONLY to subsystem-level tests -- **Unit requirements** → link ONLY to unit-level tests - -Lower-level tests validate implementation details, while higher-level requirements -are validated through integration behavior at their architectural level. - # Requirements File Format ```yaml sections: - title: Functional Requirements requirements: - - id: System-Subsystem-Feature + - id: System-Component-Feature # Used as-is in all reports - make it readable title: The system shall perform the required function. justification: | - Business rationale explaining why this requirement exists. - Include regulatory or standard references where applicable. - children: # Downward links to decomposed requirements (optional) - - ChildSystem-Feature-Behavior - tests: # Links to test methods (required) + Business rationale and any regulatory references. + # ReqStream extracts this field into the justifications report (--justifications) + children: # ReqStream validates this decomposition chain + - ChildSystem-Feature-Behavior # Downward links only (see requirements-principles.md) + tests: # ReqStream matches these by method name in test results - TestMethodName - - windows@PlatformSpecificTest # Source filter for platform evidence + - windows@PlatformSpecificTest # Only test runs on Windows count as evidence ``` -Requirements specify WHAT the system shall do, not HOW, because implementation -details belong in design documentation while requirements focus on externally -observable behavior with clear, testable acceptance criteria. - # OTS Software Requirements -Document third-party component requirements in the `docs/reqstream/ots/` folder -with nested sections because auditors need clear separation between in-house -and external component evidence: +Use nested sections in `docs/reqstream/ots/` because ReqStream renders the `ots/` +subtree as a distinct section in generated reports, separate from in-house +system requirements: ```yaml sections: @@ -123,22 +70,27 @@ sections: # Semantic IDs (MANDATORY) -Use meaningful IDs following `System-Section-ShortDesc` pattern because -auditors need to understand requirements without cross-referencing: +Use the `System-Component-Feature` pattern because ReqStream uses IDs as-is in +all generated reports and the trace matrix - opaque IDs make those outputs +unreadable without a separate lookup: -- **Good**: `TemplateTool-Core-DisplayHelp` -- **Bad**: `REQ-042` (requires lookup to understand) +- **System-level**: `TemplateTool-Core-DisplayHelp` +- **Subsystem-level**: `TemplateTool-Parser-ParseYaml` +- **Unit-level**: `TemplateTool-Validator-CheckFormat` +- **Bad**: `REQ-042` (meaningless in report output) # Source Filter Requirements (CRITICAL) -Platform-specific requirements MUST use source filters for compliance evidence: +Platform-specific requirements MUST use source filters because without them +ReqStream accepts test results from any platform as evidence - a Windows-only +requirement would incorrectly pass on Linux: ```yaml tests: - - "windows@TestMethodName" # Windows platform evidence only - - "ubuntu@TestMethodName" # Linux platform evidence only - - "net8.0@TestMethodName" # .NET 8 runtime evidence only - - "TestMethodName" # Any platform evidence acceptable + - "windows@TestMethodName" # Only Windows test runs count as evidence + - "ubuntu@TestMethodName" # Only Linux test runs count as evidence + - "net8.0@TestMethodName" # Only .NET 8 runs count as evidence + - "TestMethodName" # Any platform acceptable ``` **WARNING**: Removing source filters invalidates platform-specific compliance @@ -146,27 +98,20 @@ evidence. # ReqStream Commands -Essential ReqStream commands for Continuous Compliance: - ```bash -# Lint requirement files for issues (run before use) -dotnet reqstream \ - --requirements requirements.yaml \ - --lint - -# Generate requirements report -dotnet reqstream \ - --requirements requirements.yaml \ +# Validate YAML syntax and requirement IDs before generating any reports +dotnet reqstream --requirements requirements.yaml --lint + +# Generate requirements document for compliance record +dotnet reqstream --requirements requirements.yaml \ --report docs/requirements_doc/requirements.md -# Generate justifications report -dotnet reqstream \ - --requirements requirements.yaml \ +# Generate justifications document for compliance record +dotnet reqstream --requirements requirements.yaml \ --justifications docs/requirements_doc/justifications.md -# Generate trace matrix -dotnet reqstream \ - --requirements requirements.yaml \ +# Generate trace matrix proving each requirement is covered by passing tests +dotnet reqstream --requirements requirements.yaml \ --tests "artifacts/**/*.trx" \ --matrix docs/requirements_report/trace_matrix.md ``` @@ -178,12 +123,9 @@ Before submitting requirements, verify: - [ ] All requirements have semantic IDs (`System-Section-Feature` pattern) - [ ] Every requirement links to at least one passing test - [ ] Platform-specific requirements use source filters (`platform@TestName`) -- [ ] Requirements specify observable behavior (WHAT), not implementation (HOW) - [ ] Comprehensive justification explains business/regulatory need - [ ] Files organized under `docs/reqstream/` following folder structure patterns - [ ] Subsystem folders use kebab-case naming matching source code - [ ] OTS requirements placed in `ots/` subfolder -- [ ] Every software unit has requirements file, design doc, and tests - [ ] Valid YAML syntax passes yamllint validation -- [ ] ReqStream enforcement passes: `dotnet reqstream --enforce` - [ ] Test result formats compatible (TRX, JUnit XML) diff --git a/.github/standards/requirements-principles.md b/.github/standards/requirements-principles.md new file mode 100644 index 0000000..7d2d572 --- /dev/null +++ b/.github/standards/requirements-principles.md @@ -0,0 +1,71 @@ +--- +name: Requirements Principles +description: Follow these standards when creating, reviewing, or evaluating requirements. +--- + +# Unidirectional Flow (MANDATORY) + +Requirements flow strictly top-down - never in reverse: + +```text +User/System Needs → Requirements → Design → Implementation +``` + +- **Requirements** express WHAT is needed - derived from user/system needs only +- **Design** expresses HOW requirements are satisfied - derived from requirements only + +Anti-patterns that MUST NOT occur: + +- Writing a requirement because a class, method, or module exists in the code +- Updating requirements to match an implementation decision already made +- Requirements that describe HOW something is built rather than WHAT it must do + +# What Makes a Requirement + +A requirement expresses **observable, testable behavior** - what the system must +do, not how it does it, so that compliance can be verified without reading +implementation code. + +- **Valid**: "The parser shall report the line number of the first syntax error." +- **Not a requirement (design decision)**: "The parser shall use a `TokenStream` class." + +# Requirements at Every Level (MANDATORY) + +Every identified subsystem and unit MUST have its own requirements file because +reviewers must see what each item is responsible for satisfying and auditors must +be able to trace which items implement which requirements. + +Requirements at each level decompose the parent requirement into the behavioral +responsibility of that software item, and links flow downward only - +unit requirements MUST NOT link upward to parent requirements: + +```text +System requirement + └─ Subsystem requirement (what this subsystem must do) + └─ Unit requirement (what this unit must do) +``` + +Before writing a subsystem or unit requirement ask: *"Am I decomposing a parent +requirement into this item's responsibility, or describing what the code already does?"* +Decomposing a parent requirement is valid. Describing existing code is back-driving. + +# Test Independence + +- **Every requirement MUST link to at least one passing test** because untested + requirements have no compliance evidence +- **Requirements MUST link to tests at their own level** - system requirements to + system-level tests, subsystem requirements to subsystem-level tests, unit + requirements to unit-level tests; linking across levels produces misleading + compliance evidence +- **Tests MAY exist without a requirement** - corner-case, defensive, and regression + tests are valid; never flag them as non-compliant + +# Quality Gates + +- [ ] All requirements describe observable behavior (WHAT), not implementation (HOW) +- [ ] No requirement was derived from or driven by existing design or code +- [ ] Every requirement links to at least one passing test +- [ ] Every identified subsystem has a requirements file +- [ ] Every identified software unit has a requirements file +- [ ] Subsystem and unit requirements decompose parent requirements top-down, not bottom-up from code +- [ ] Tests without a requirement are accepted as valid diff --git a/.github/standards/reviewmark-usage.md b/.github/standards/reviewmark-usage.md index 48380c5..5d6219e 100644 --- a/.github/standards/reviewmark-usage.md +++ b/.github/standards/reviewmark-usage.md @@ -20,8 +20,11 @@ review, organizes them into review-sets, and generates review plans and reports. - **Lint Configuration**: `dotnet reviewmark --lint` - **Elaborate Review-Set**: `dotnet reviewmark --elaborate {review-set}` -- **Generate Plan**: `dotnet reviewmark --plan docs/code_review_plan/plan.md` -- **Generate Report**: `dotnet reviewmark --report docs/code_review_report/report.md` +- **Generate Plan**: `dotnet reviewmark --plan docs/code_review_plan/plan.md --enforce` + +> **Note**: `--enforce` causes the plan to fail with a non-zero exit code if any repository +> files are not covered by a review-set. Uncovered files indicate a gap in review-set +> configuration that should be addressed. ## Repository Structure @@ -29,7 +32,6 @@ Required repository items for ReviewMark operation: - `.reviewmark.yaml` - Configuration for review-sets, file-patterns, and review evidence-source. - `docs/code_review_plan/` - Review planning artifacts -- `docs/code_review_report/` - Review status reports # Review Definition Structure @@ -76,9 +78,9 @@ When constructing review-sets, follow these principles to maintain manageable sc Organize review-sets using these standard patterns to ensure comprehensive coverage while keeping each review manageable in scope: -**Note**: File path patterns shown below use C# naming conventions (PascalCase, `.cs` extensions). -Other languages should adapt these patterns to their conventions (e.g., C++ might use -`snake_case` with `.cpp`/`.hpp` extensions). +**Naming conventions**: See `software-items.md` - kebab-case placeholders +(e.g., `{system-name}`) are always kebab-case; cased placeholders +(e.g., `{SystemName}`) follow your language's convention. ## `Purpose` Review (only one per repository) @@ -107,7 +109,7 @@ Reviews system architecture and operational validation: - System requirements: `docs/reqstream/{system-name}/{system-name}.yaml` - Design introduction: `docs/design/introduction.md` - System design: `docs/design/{system-name}/{system-name}.md` - - System integration tests: `test/{SystemName}.Tests/{SystemName}Tests.cs` + - System integration tests: `test/{SystemName}.Tests/{SystemName}Tests.{ext}` ## `{System}-Design` Review (one per system) @@ -134,7 +136,7 @@ Reviews requirements quality and traceability: - System requirements: `docs/reqstream/{system-name}/**/*.yaml` - OTS requirements: `docs/reqstream/ots/**/*.yaml` (if applicable) -## `{System}-{Subsystem}` Review (one per subsystem) +## `{System}-{Subsystem[-Child...]}` Review (one per subsystem at any depth) Reviews subsystem architecture and interfaces: @@ -143,11 +145,11 @@ Reviews subsystem architecture and interfaces: - **Scope**: Excludes units under the subsystem, relying on subsystem design to describe what units it uses - **File Path Patterns**: - - Requirements: `docs/reqstream/{system-name}/{subsystem-name}/{subsystem-name}.yaml` - - Design: `docs/design/{system-name}/{subsystem-name}/{subsystem-name}.md` - - Tests: `test/{SystemName}.Tests/{SubsystemName}/{SubsystemName}Tests.cs` + - Requirements: `docs/reqstream/{system-name}/.../{subsystem-name}/{subsystem-name}.yaml` + - Design: `docs/design/{system-name}/.../{subsystem-name}/{subsystem-name}.md` + - Tests: `test/{SystemName}.Tests/.../{SubsystemName}/{SubsystemName}Tests.{ext}` -## `{System}-{Subsystem}-{Unit}` Review (one per unit) +## `{System}-{Subsystem[-Child...]}-{Unit}` Review (one per unit) Reviews individual software unit implementation: @@ -155,13 +157,13 @@ Reviews individual software unit implementation: - **Title**: "Review that {System} {Subsystem} {Unit} Implementation is Correct" - **Scope**: Complete unit review including all artifacts - **File Path Patterns**: - - Requirements: `docs/reqstream/{system-name}/{subsystem-name}/{unit-name}.yaml` or - `docs/reqstream/{system-name}/{unit-name}.yaml` - - Design: `docs/design/{system-name}/{subsystem-name}/{unit-name}.md` or - `docs/design/{system-name}/{unit-name}.md` - - Source: `src/{SystemName}/{SubsystemName}/{UnitName}.cs` or `src/{SystemName}/{UnitName}.cs` - - Tests: `test/{SystemName}.Tests/{SubsystemName}/{UnitName}Tests.cs` or - `test/{SystemName}.Tests/{UnitName}Tests.cs` + - Requirements: `docs/reqstream/{system-name}/.../{unit-name}.yaml` + - Design: `docs/design/{system-name}/.../{unit-name}.md` + - Source: `src/{SystemName}/.../{UnitName}.{ext}` + - Tests: `test/{SystemName}.Tests/.../{UnitName}Tests.{ext}` + +**Note**: File path patterns use `{ext}` as a placeholder for language-specific +extensions (`.cs`, `.cpp`/`.hpp`, `.py`, etc.). Adapt to your repository's languages. # Quality Checks @@ -176,4 +178,3 @@ Before submitting ReviewMark configuration, verify: - [ ] Each review-set focuses on a single compliance question (single focus principle) - [ ] File patterns use correct glob syntax and match intended files - [ ] Review-set file counts remain manageable (context management principle) -- [ ] Evidence source properly configured (`none` for dev, `url` for production) diff --git a/.github/standards/software-items.md b/.github/standards/software-items.md index 62abb9f..bb67b1d 100644 --- a/.github/standards/software-items.md +++ b/.github/standards/software-items.md @@ -5,33 +5,54 @@ description: Follow these standards when categorizing software components. # Software Items Definition Standards -This document defines DEMA Consulting standards for categorizing software -items within Continuous Compliance environments because proper categorization -determines requirements management approach, testing strategy, and review -scope. +This document defines standards for categorizing software items within +Continuous Compliance environments because proper categorization determines +requirements management approach, testing strategy, and review scope. # Software Item Categories -Categorize all software into four primary groups: +Categorize all software into five primary groups: +- **Software Package**: Distributable unit delivered to end users or dependent + systems, containing one software system with all its components. All software + systems are delivered as a software package. When consumed by another system, + our software package is treated as an OTS Software Item by that system. - **Software System**: Complete deliverable product including all components - and external interfaces + and external interfaces, contained within a software package - **Software Subsystem**: Major architectural component with well-defined interfaces and responsibilities - **Software Unit**: Individual class, function, or tightly coupled set of functions that can be tested in isolation -- **OTS Software Item**: Third-party component (library, framework, tool) - providing functionality not developed in-house +- **OTS Software Item**: Third-party component (library, framework, tool, or + published software package) providing functionality not developed in-house **Naming**: When names collide in hierarchy, add descriptive suffix to higher-level entity: +- Package: Package (e.g. TestResults → TestResultsPackage) - System: Application/Library/System (e.g. TestResults → TestResultsLibrary) - Subsystem: Subsystem (e.g. Linter → LinterSubsystem) +# Naming Conventions in File Path Patterns + +Two placeholder styles appear in path patterns across these standards: + +- **Kebab-case** (`{system-name}`, `{unit-name}`): always kebab-case - + used in documentation and requirements paths +- **Cased** (`{SystemName}`, `{UnitName}`): follow your language's convention - + `PascalCase` for C#/Java, `snake_case` for C++/Python - + used in source and test file paths + # Categorization Guidelines Choose the appropriate category based on scope and testability: +## Software Package + +- Represents one distributable artifact + (e.g., NuGet package, npm package, Docker image, installer) +- Contains exactly one software system with its subsystems and units +- Tested through package-level acceptance and integration tests + ## Software System - Represents the entire product boundary @@ -40,7 +61,8 @@ Choose the appropriate category based on scope and testability: ## Software Subsystem - Major architectural boundary (authentication, data layer, UI, communications) -- Contains multiple software units working together +- Contains software units and optionally child subsystems +- Subsystems may nest when a component has distinct internal boundaries - Typically maps to project folders or namespaces - Tested through subsystem integration tests @@ -53,6 +75,20 @@ Choose the appropriate category based on scope and testability: ## OTS Software Item -- External dependency not developed in-house +- External dependency not developed in-house - typically a third-party published + software package (NuGet, npm, etc.), hosted service, or tool +- Our own published software package becomes an OTS item to any system that + consumes it - Tested through integration tests proving required functionality works - Examples: System.Text.Json, Entity Framework, third-party APIs + +# Software Item Artifact Model + +Each software item has four artifact types that together form a complete review +unit - because reviewing any one artifact in isolation cannot determine whether +the item is correct, well-designed, and proven to work: + +- **Requirements** - WHAT the item must do (drives all other artifacts; applies to all item types) +- **Design** - HOW the item satisfies its requirements (in-house items only: system, subsystem, unit) +- **Source code** - The implementation of the design (in-house units only) +- **Tests** - PROOF the item does WHAT it is required to do (applies to all item types) diff --git a/.github/standards/technical-documentation.md b/.github/standards/technical-documentation.md index 9da6eab..455b2fd 100644 --- a/.github/standards/technical-documentation.md +++ b/.github/standards/technical-documentation.md @@ -6,8 +6,8 @@ globs: ["docs/**/*.md", "README.md"] # Technical Documentation Standards -This document defines DEMA Consulting standards for technical documentation -within Continuous Compliance environments. +This document defines standards for technical documentation within Continuous +Compliance environments. # Core Principles @@ -41,16 +41,18 @@ docs/ introduction.md # Design overview {system-name}/ # System architecture folder {system-name}.md # System architecture - {subsystem-name}/ # Subsystem design folder + {subsystem-name}/ # Subsystem folder; may nest recursively {subsystem-name}.md # Subsystem-specific designs + {child-subsystem}/ # Child subsystem (same structure) {unit-name}.md # Unit-specific designs {unit-name}.md # Top-level unit design reqstream/ # Requirements source files {system-name}/ # System requirements folder {system-name}.yaml # System requirements platform-requirements.yaml # Platform requirements - {subsystem-name}/ # Subsystem requirements folder + {subsystem-name}/ # Subsystem folder; may nest recursively {subsystem-name}.yaml # Subsystem requirements + {child-subsystem}/ # Child subsystem (same structure) {unit-name}.yaml # Unit-specific requirements {unit-name}.yaml # Top-level unit requirements ots/ # OTS requirement files @@ -67,12 +69,26 @@ docs/ # Pandoc Document Structure (MANDATORY) -All document collections processed by Pandoc MUST include: +All document collections processed by Pandoc MUST include all four files below - +without `title.txt` and `definition.yaml` the pipeline cannot generate the document: -- `definition.yaml` - specifying the files to include -- `title.txt` - document metadata +- `title.txt` - YAML metadata (title, subtitle, author, description, lang, keywords) +- `definition.yaml` - Pandoc build definition (resource paths, input file list, template) - `introduction.md` - document introduction -- `{sections}.md` - additional document sections +- `{sections}.md` - additional content sections + +When creating a new document collection, create `title.txt` and `definition.yaml` +alongside `introduction.md`. Use the existing files under `docs/` as templates - +they share a consistent structure across all collections. + +**`title.txt`** - YAML front matter with document metadata. Use the existing +files under `docs/` as a pattern and keep fields consistent with the rest of +the repository. + +**`definition.yaml`** - Pandoc build configuration. List `title.txt` first in +`input-files` followed by `introduction.md` and content sections in reading +order. Use the existing files under `docs/` as a pattern for resource paths +and template settings. ## Introduction File Format diff --git a/.github/standards/testing-principles.md b/.github/standards/testing-principles.md index d9059e0..73974ff 100644 --- a/.github/standards/testing-principles.md +++ b/.github/standards/testing-principles.md @@ -34,7 +34,9 @@ file organization patterns, and tooling requirements. - [ ] Cross-hierarchy test dependencies documented in design documentation - [ ] All tests follow AAA pattern with descriptive comments - [ ] Test names follow hierarchical naming conventions for requirement linkage -- [ ] Tests linkable to requirements through ReqStream +- [ ] Every requirement has at least one linked passing test +- [ ] Tests without a corresponding requirement are accepted as valid + (corner-case, defensive, and regression tests need not link to a requirement) - [ ] Platform-specific tests use appropriate source filters - [ ] Both success and error scenarios covered - [ ] External dependencies properly mocked for isolation diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index a2daa59..d10c528 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -19,7 +19,8 @@ jobs: contents: read steps: # === INSTALL DEPENDENCIES === - # This section installs all required dependencies for quality checks. + # This section installs all required dependencies and tools for quality checks. + # Downstream projects: Add any additional dependency installations here. - name: Checkout uses: actions/checkout@v6 @@ -33,8 +34,19 @@ jobs: run: > dotnet tool restore + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 24.x + + - name: Setup Python + uses: actions/setup-python@v6 + with: + python-version: '3.14' + # === CAPTURE TOOL VERSIONS === - # This section captures the versions of all tools used in the quality checks. + # This section captures the versions of all tools used in the build process. + # Downstream projects: Add any additional tools to capture here. - name: Capture tool versions shell: bash @@ -47,30 +59,27 @@ jobs: echo "✓ Tool versions captured" # === CAPTURE OTS SELF-VALIDATION RESULTS === - # This section captures self-validation results from OTS tools. + # This section runs the self-validation of each OTS tool and saves TRX results + # so that OTS Software Requirements in requirements.yaml can be satisfied. + # Downstream projects: Add any additional OTS tool self-validation steps here. - name: Run VersionMark self-validation - run: dotnet versionmark --validate --results artifacts/versionmark-self-validation-quality.trx + run: > + dotnet versionmark + --validate + --results artifacts/versionmark-self-validation-quality.trx # === RUN QUALITY CHECKS === - # This section runs all quality checks for the project. - - - name: Setup Node.js - uses: actions/setup-node@v6 - with: - node-version: lts/* - - - name: Setup Python - uses: actions/setup-python@v6 - with: - python-version: '3.14' + # This section runs the linting and quality checks for the project. + # Downstream projects: Add any additional quality check steps here. - name: Run linters - shell: bash - run: bash ./lint.sh + shell: pwsh + run: ./lint.ps1 # === UPLOAD ARTIFACTS === - # This section uploads all quality artifacts. + # This section uploads all generated artifacts for use by downstream jobs. + # Downstream projects: Add any additional artifact uploads here. - name: Upload quality artifacts uses: actions/upload-artifact@v7 @@ -78,13 +87,15 @@ jobs: name: artifacts-quality path: artifacts/ - # Builds and unit-tests the project on supported operating systems with SonarCloud analysis. + # Builds and unit-tests the project on supported operating systems to ensure + # unit-tests operate on all platforms and to run SonarScanner for generating + # the code quality report. build: name: Build ${{ matrix.os }} needs: quality-checks permissions: - contents: read # To read repository contents - pull-requests: write # To write pull requests analysis results and artifacts + contents: read + pull-requests: write strategy: matrix: @@ -95,7 +106,8 @@ jobs: steps: # === INSTALL DEPENDENCIES === - # This section installs all required dependencies for the build. + # This section installs all required dependencies and tools for building the project. + # Downstream projects: Add any additional dependency installations here. - name: Checkout uses: actions/checkout@v6 @@ -116,6 +128,7 @@ jobs: # === CAPTURE TOOL VERSIONS === # This section captures the versions of all tools used in the build process. + # Downstream projects: Add any additional tools to capture here. - name: Capture tool versions shell: bash @@ -131,13 +144,19 @@ jobs: echo "✓ Tool versions captured" # === CAPTURE OTS SELF-VALIDATION RESULTS === - # This section captures self-validation results from OTS tools. + # This section runs the self-validation of each OTS tool and saves TRX results + # so that OTS Software Requirements in requirements.yaml can be satisfied. + # Downstream projects: Add any additional OTS tool self-validation steps here. - name: Run VersionMark self-validation - run: dotnet versionmark --validate --results artifacts/versionmark-self-validation-${{ matrix.os }}.trx + run: > + dotnet versionmark + --validate + --results artifacts/versionmark-self-validation-${{ matrix.os }}.trx # === BUILD AND TEST === # This section builds and tests the project. + # Downstream projects: Add any additional build or test steps here. - name: Restore Dependencies run: > @@ -186,10 +205,12 @@ jobs: dotnet pack --no-build --no-restore + --configuration Release --property:PackageVersion=${{ inputs.version }} # === UPLOAD ARTIFACTS === - # This section uploads all build artifacts. + # This section uploads all generated artifacts for use by downstream jobs. + # Downstream projects: Add any additional artifact uploads here. - name: Upload build artifacts uses: actions/upload-artifact@v7 @@ -205,7 +226,8 @@ jobs: src/DemaConsulting.SonarMark/bin/Release/*.nupkg src/DemaConsulting.SonarMark/bin/Release/*.snupkg - # Performs security analysis using CodeQL. + # Runs CodeQL security and quality analysis, gathering results to include + # in the code quality report. codeql: name: CodeQL Analysis runs-on: ubuntu-latest @@ -217,7 +239,8 @@ jobs: steps: # === INSTALL DEPENDENCIES === - # This section installs all required dependencies for CodeQL analysis. + # This section installs all required dependencies and tools for CodeQL analysis. + # Downstream projects: Add any additional dependency installations here. - name: Checkout uses: actions/checkout@v6 @@ -249,7 +272,8 @@ jobs: dotnet restore # === BUILD AND ANALYZE === - # This section builds the project and runs CodeQL analysis. + # This section builds the project and performs CodeQL analysis. + # Downstream projects: Add any additional analysis steps here. - name: Build run: > @@ -266,7 +290,8 @@ jobs: upload: false # === UPLOAD ARTIFACTS === - # This section uploads all CodeQL artifacts. + # This section uploads all generated artifacts for use by downstream jobs. + # Downstream projects: Add any additional artifact uploads here. - name: Upload CodeQL artifacts uses: actions/upload-artifact@v7 @@ -274,7 +299,9 @@ jobs: name: artifacts-codeql path: artifacts/ - # Tests the packaged tool on multiple OS and .NET versions. + # Performs integration testing on a matrix of operating systems and .NET runtimes, + # involving basic tool execution and running self-validation to ensure compatibility + # across different platforms and runtime versions. integration-test: name: Integration Test ${{ matrix.os }} .NET ${{ matrix.dotnet-version }} runs-on: ${{ matrix.os }} @@ -290,6 +317,7 @@ jobs: steps: # === INSTALL DEPENDENCIES === # This section installs all required dependencies and tools for integration testing. + # Downstream projects: Add any additional dependency installations here. - name: Checkout uses: actions/checkout@v6 @@ -324,6 +352,7 @@ jobs: # === CAPTURE TOOL VERSIONS === # This section captures the versions of all tools used in the integration tests. + # Downstream projects: Add any additional tools to capture here. - name: Capture tool versions shell: bash @@ -341,6 +370,7 @@ jobs: # === RUN INTEGRATION TESTS === # This section runs the integration tests for the tool. + # Downstream projects: Add any additional integration test steps here. - name: Test version display shell: bash @@ -382,17 +412,18 @@ jobs: echo "Report summary:" cat "analysis-report-${{ matrix.os }}-${{ matrix.dotnet-version }}.md" - - name: Run SonarMark self-validation + - name: Run self-validation shell: bash run: | - echo "Running SonarMark self-validation..." + echo "Running self-validation..." sonarmark --validate \ - --results artifacts/sonarmark-self-validation-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }}.trx \ + --results artifacts/validation-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }}.trx \ || { echo "✗ Self-validation failed"; exit 1; } echo "✓ Self-validation succeeded" # === UPLOAD ARTIFACTS === # This section uploads all generated artifacts for use by downstream jobs. + # Downstream projects: Add any additional artifact uploads here. - name: Upload validation artifacts if: always() @@ -401,9 +432,10 @@ jobs: name: artifacts-validation-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }} path: artifacts/ - # Generates all documentation including requirements, trace matrix, and build notes. + # Builds the supporting documentation including user guides, requirements, + # trace matrices, code quality reports, and build notes. build-docs: - name: Build Documentation + name: Build Documents runs-on: windows-latest needs: [build, integration-test, codeql] permissions: @@ -412,6 +444,7 @@ jobs: steps: # === CHECKOUT AND DOWNLOAD ARTIFACTS === # This section retrieves the code and all necessary artifacts from previous jobs. + # Downstream projects: Add any additional artifact downloads here. - name: Checkout uses: actions/checkout@v6 @@ -424,14 +457,9 @@ jobs: merge-multiple: true continue-on-error: true - - name: Download SonarMark package - uses: actions/download-artifact@v8 - with: - name: packages-ubuntu-latest - path: packages - # === INSTALL DEPENDENCIES === # This section installs all required dependencies and tools for document generation. + # Downstream projects: Add any additional dependency installations here. - name: Setup Node.js uses: actions/setup-node@v6 @@ -446,66 +474,116 @@ jobs: - name: Install npm dependencies run: npm install - - name: Install SonarMark from package - shell: bash - run: | - echo "Installing SonarMark version ${{ inputs.version }}" - dotnet tool install --global \ - --add-source packages \ - --version ${{ inputs.version }} \ - DemaConsulting.SonarMark - - name: Restore Tools run: dotnet tool restore # === CAPTURE TOOL VERSIONS === # This section captures the versions of all tools used in the build process. + # Downstream projects: Add any additional tools to capture here. - name: Capture tool versions for build-docs shell: bash run: | + mkdir -p artifacts echo "Capturing tool versions..." dotnet versionmark --capture --job-id "build-docs" \ --output "artifacts/versionmark-build-docs.json" -- \ - dotnet git node npm pandoc weasyprint sarifmark sonarmark reqstream buildmark versionmark reviewmark + dotnet git node npm pandoc weasyprint sarifmark sonarmark reqstream \ + buildmark versionmark reviewmark fileassert echo "✓ Tool versions captured" - # === CAPTURE OTS SELF-VALIDATION RESULTS === - # This section captures self-validation results from OTS tools. - - - name: Run ReqStream self-validation - run: dotnet reqstream --validate --results artifacts/reqstream-self-validation.trx + # === COMPILE BUILD NOTES === + # This section generates the Build Notes document. BuildMark and VersionMark self-validations + # run here to co-locate their evidence with the document that depends on their output. + # Pandoc converts the markdown to HTML, WeasyPrint renders the HTML to PDF, and FileAssert + # validates the outputs contain expected content. + # Downstream projects: Add any additional build notes steps here. - name: Run BuildMark self-validation - run: dotnet buildmark --validate --results artifacts/buildmark-self-validation.trx + run: > + dotnet buildmark + --validate + --results artifacts/buildmark-self-validation.trx - name: Run VersionMark self-validation - run: dotnet versionmark --validate --results artifacts/versionmark-self-validation.trx + run: > + dotnet versionmark + --validate + --results artifacts/versionmark-self-validation.trx - - name: Run SarifMark self-validation - run: dotnet sarifmark --validate --results artifacts/sarifmark-self-validation.trx + - name: Generate Build Notes with BuildMark + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: > + dotnet buildmark + --build-version ${{ inputs.version }} + --report docs/build_notes.md + --report-depth 1 - - name: Run SonarMark self-validation - run: sonarmark --validate --results artifacts/sonarmark-self-validation.trx + - name: Display Build Notes Report + shell: bash + run: | + echo "=== Build Notes Report ===" + cat docs/build_notes.md - - name: Run ReviewMark self-validation - run: dotnet reviewmark --validate --results artifacts/reviewmark-self-validation.trx + - name: Publish Tool Versions + shell: bash + run: | + echo "Publishing tool versions..." + dotnet versionmark --publish --report docs/build_notes/versions.md --report-depth 1 \ + -- "artifacts/**/versionmark-*.json" + echo "✓ Tool versions published" + + - name: Display Tool Versions Report + shell: bash + run: | + echo "=== Tool Versions Report ===" + cat docs/build_notes/versions.md - # === GENERATE MARKDOWN REPORTS === - # This section generates all markdown reports from various tools and sources. + - name: Generate Build Notes HTML with Pandoc + shell: bash + run: > + dotnet pandoc + --defaults docs/build_notes/definition.yaml + --filter node_modules/.bin/mermaid-filter.cmd + --metadata version="${{ inputs.version }}" + --metadata date="$(date +'%Y-%m-%d')" + --output docs/build_notes/build_notes.html - - name: Generate Requirements Report and Trace Matrix + - name: Generate Build Notes PDF with WeasyPrint run: > - dotnet reqstream - --requirements requirements.yaml - --tests "artifacts/**/*.trx" - --report docs/requirements_doc/requirements.md - --justifications docs/requirements_doc/justifications.md - --matrix docs/requirements_report/trace_matrix.md - --enforce + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/build_notes/build_notes.html + "docs/SonarMark Build Notes.pdf" + + - name: Assert Build Notes Documents with FileAssert + run: > + dotnet fileassert + --results artifacts/fileassert-build-notes.trx + build-notes + + # === COMPILE CODE QUALITY REPORT === + # This section generates the Code Quality document. SarifMark and SonarMark self-validations + # run here to co-locate their evidence with the document that depends on their output. + # Pandoc converts the markdown to HTML, WeasyPrint renders the HTML to PDF, and FileAssert + # validates the outputs contain expected content. + # Downstream projects: Add any additional code quality steps here. + + - name: Run SarifMark self-validation + run: > + dotnet sarifmark + --validate + --results artifacts/sarifmark-self-validation.trx + + - name: Run SonarMark self-validation + run: > + dotnet sonarmark + --validate + --results artifacts/sonarmark-self-validation.trx - name: Generate CodeQL Quality Report with SarifMark - shell: bash run: > dotnet sarifmark --sarif artifacts/csharp.sarif @@ -519,12 +597,12 @@ jobs: echo "=== CodeQL Quality Report ===" cat docs/code_quality/codeql-quality.md - - name: Generate Code Quality Report with SonarMark + - name: Generate SonarCloud Quality Report shell: bash env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: > - sonarmark + dotnet sonarmark --server https://sonarcloud.io --project-key demaconsulting_SonarMark --branch ${{ github.ref_name }} @@ -538,6 +616,42 @@ jobs: echo "=== SonarCloud Quality Report ===" cat docs/code_quality/sonar-quality.md + - name: Generate Code Quality HTML with Pandoc + shell: bash + run: > + dotnet pandoc + --defaults docs/code_quality/definition.yaml + --filter node_modules/.bin/mermaid-filter.cmd + --metadata version="${{ inputs.version }}" + --metadata date="$(date +'%Y-%m-%d')" + --output docs/code_quality/quality.html + + - name: Generate Code Quality PDF with WeasyPrint + run: > + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/code_quality/quality.html + "docs/SonarMark Code Quality.pdf" + + - name: Assert Code Quality Documents with FileAssert + run: > + dotnet fileassert + --results artifacts/fileassert-code-quality.trx + code-quality + + # === COMPILE CODE REVIEW === + # This section generates the Code Review Plan and Report documents. ReviewMark + # self-validation runs here to co-locate its evidence with the documents that depend + # on its output. Pandoc converts the markdown to HTML, WeasyPrint renders the HTML to + # PDF, and FileAssert validates the outputs contain expected content. + # Downstream projects: Add any additional code review steps here. + + - name: Run ReviewMark self-validation + run: > + dotnet reviewmark + --validate + --results artifacts/reviewmark-self-validation.trx + - name: Generate Review Plan and Review Report with ReviewMark shell: bash # TODO: Add --enforce once reviews branch is populated with review evidence PDFs and index.json @@ -560,185 +674,188 @@ jobs: echo "=== Review Report ===" cat docs/code_review_report/report.md - - name: Generate Build Notes with BuildMark - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - shell: bash - run: > - dotnet buildmark - --build-version ${{ inputs.version }} - --report docs/build_notes.md - --report-depth 1 - - - name: Display Build Notes Report - shell: bash - run: | - echo "=== Build Notes Report ===" - cat docs/build_notes.md - - - name: Publish Tool Versions - shell: bash - run: | - echo "Publishing tool versions..." - dotnet versionmark --publish --report docs/build_notes/versions.md --report-depth 1 \ - -- "artifacts/**/versionmark-*.json" - echo "✓ Tool versions published" - - - name: Display Tool Versions Report - shell: bash - run: | - echo "=== Tool Versions Report ===" - cat docs/build_notes/versions.md - - # === GENERATE HTML DOCUMENTS WITH PANDOC === - # This section converts markdown documents to HTML using Pandoc. - - - name: Generate Guide HTML with Pandoc + - name: Generate Review Plan HTML with Pandoc shell: bash run: > dotnet pandoc - --defaults docs/user_guide/definition.yaml + --defaults docs/code_review_plan/definition.yaml --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/user_guide/guide.html + --output docs/code_review_plan/plan.html - - name: Generate Requirements HTML with Pandoc - shell: bash + - name: Generate Review Plan PDF with WeasyPrint run: > - dotnet pandoc - --defaults docs/requirements_doc/definition.yaml - --filter node_modules/.bin/mermaid-filter.cmd - --metadata version="${{ inputs.version }}" - --metadata date="$(date +'%Y-%m-%d')" - --output docs/requirements_doc/requirements.html + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/code_review_plan/plan.html + "docs/SonarMark Review Plan.pdf" - - name: Generate Trace Matrix HTML with Pandoc + - name: Generate Review Report HTML with Pandoc shell: bash run: > dotnet pandoc - --defaults docs/requirements_report/definition.yaml + --defaults docs/code_review_report/definition.yaml --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/requirements_report/trace_matrix.html + --output docs/code_review_report/report.html - - name: Generate Build Notes HTML with Pandoc - shell: bash + - name: Generate Review Report PDF with WeasyPrint run: > - dotnet pandoc - --defaults docs/build_notes/definition.yaml - --metadata version="${{ inputs.version }}" - --metadata date="$(date +'%Y-%m-%d')" - --filter node_modules/.bin/mermaid-filter.cmd - --output docs/build_notes/buildnotes.html + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/code_review_report/report.html + "docs/SonarMark Review Report.pdf" - - name: Generate Code Quality HTML with Pandoc - shell: bash + - name: Assert Code Review Documents with FileAssert run: > - dotnet pandoc - --defaults docs/code_quality/definition.yaml - --filter node_modules/.bin/mermaid-filter.cmd - --metadata version="${{ inputs.version }}" - --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_quality/quality.html + dotnet fileassert + --results artifacts/fileassert-code-review.trx + code-review - - name: Generate Review Plan HTML with Pandoc + # === COMPILE DESIGN DOCUMENT === + # This section generates the Design document using Pandoc and WeasyPrint. + # FileAssert validates that the HTML and PDF outputs contain expected content. + # Downstream projects: Add any additional design document steps here. + + - name: Generate Design HTML with Pandoc shell: bash run: > dotnet pandoc - --defaults docs/code_review_plan/definition.yaml + --defaults docs/design/definition.yaml --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_review_plan/plan.html + --output docs/design/design.html - - name: Generate Review Report HTML with Pandoc - shell: bash + - name: Generate Design PDF with WeasyPrint run: > - dotnet pandoc - --defaults docs/code_review_report/definition.yaml - --filter node_modules/.bin/mermaid-filter.cmd - --metadata version="${{ inputs.version }}" - --metadata date="$(date +'%Y-%m-%d')" - --output docs/code_review_report/report.html + dotnet weasyprint + --pdf-variant pdf/a-3u + docs/design/design.html + "docs/SonarMark Software Design.pdf" - - name: Generate Design HTML with Pandoc + - name: Assert Design Documents with FileAssert + run: > + dotnet fileassert + --results artifacts/fileassert-design.trx + design + + # === COMPILE USER GUIDE === + # This section generates the User Guide document using Pandoc and WeasyPrint. + # FileAssert validates that the HTML and PDF outputs contain expected content. + # Downstream projects: Add any additional user guide steps here. + + - name: Generate User Guide HTML with Pandoc shell: bash run: > dotnet pandoc - --defaults docs/design/definition.yaml + --defaults docs/user_guide/definition.yaml --filter node_modules/.bin/mermaid-filter.cmd --metadata version="${{ inputs.version }}" --metadata date="$(date +'%Y-%m-%d')" - --output docs/design/design.html + --output docs/user_guide/user_guide.html - # === GENERATE PDF DOCUMENTS WITH WEASYPRINT === - # This section converts HTML documents to PDF using Weasyprint. - - - name: Generate Guide PDF with Weasyprint + - name: Generate User Guide PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/user_guide/guide.html + docs/user_guide/user_guide.html "docs/SonarMark User Guide.pdf" - - name: Generate Requirements PDF with Weasyprint + - name: Assert User Guide Documents with FileAssert run: > - dotnet weasyprint - --pdf-variant pdf/a-3u - docs/requirements_doc/requirements.html - "docs/SonarMark Requirements.pdf" + dotnet fileassert + --results artifacts/fileassert-user-guide.trx + user-guide + + # === FILEASSERT SELF-VALIDATION === + # By this point Pandoc and WeasyPrint have each produced 6 validated documents + # (Build Notes, Code Quality, Review Plan, Review Report, Design, User Guide), + # providing strong OTS evidence for both tools before ReqStream runs. FileAssert + # self-validation confirms the assertion tool itself is operational. + # Downstream projects: Add any additional FileAssert self-validation steps here. - - name: Generate Trace Matrix PDF with Weasyprint + - name: Run FileAssert self-validation run: > - dotnet weasyprint - --pdf-variant pdf/a-3u - docs/requirements_report/trace_matrix.html - "docs/SonarMark Trace Matrix.pdf" + dotnet fileassert + --validate + --results artifacts/fileassert-self-validation.trx + + # === COMPILE REQUIREMENTS AND TRACE MATRIX === + # This section generates the Requirements and Trace Matrix documents. ReqStream + # self-validation runs here, then ReqStream --enforce consumes all previously generated + # TRX evidence (including FileAssert results for Pandoc, WeasyPrint, and FileAssert OTS + # requirements). Pandoc and WeasyPrint compile the final documents, and FileAssert + # validates their outputs. These final assertions do not contribute to OTS evidence but + # confirm the requirements pipeline produced well-formed documents. + # Downstream projects: Add any additional requirements steps here. - - name: Generate Build Notes PDF with Weasyprint + - name: Run ReqStream self-validation run: > - dotnet weasyprint - --pdf-variant pdf/a-3u - docs/build_notes/buildnotes.html - "docs/SonarMark Build Notes.pdf" + dotnet reqstream + --validate + --results artifacts/reqstream-self-validation.trx - - name: Generate Code Quality PDF with Weasyprint + - name: Generate Requirements Report, Justifications, and Trace Matrix run: > - dotnet weasyprint - --pdf-variant pdf/a-3u - docs/code_quality/quality.html - "docs/SonarMark Code Quality.pdf" + dotnet reqstream + --requirements requirements.yaml + --tests "artifacts/**/*.trx" + --report docs/requirements_doc/requirements.md + --justifications docs/requirements_doc/justifications.md + --matrix docs/requirements_report/trace_matrix.md + --enforce - - name: Generate Review Plan PDF with Weasyprint + - name: Generate Requirements HTML with Pandoc + shell: bash run: > - dotnet weasyprint - --pdf-variant pdf/a-3u - docs/code_review_plan/plan.html - "docs/SonarMark Review Plan.pdf" + dotnet pandoc + --defaults docs/requirements_doc/definition.yaml + --filter node_modules/.bin/mermaid-filter.cmd + --metadata version="${{ inputs.version }}" + --metadata date="$(date +'%Y-%m-%d')" + --output docs/requirements_doc/requirements.html - - name: Generate Review Report PDF with Weasyprint + - name: Generate Requirements PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/code_review_report/report.html - "docs/SonarMark Review Report.pdf" + docs/requirements_doc/requirements.html + "docs/SonarMark Requirements.pdf" - - name: Generate Design PDF with Weasyprint + - name: Generate Trace Matrix HTML with Pandoc + shell: bash + run: > + dotnet pandoc + --defaults docs/requirements_report/definition.yaml + --filter node_modules/.bin/mermaid-filter.cmd + --metadata version="${{ inputs.version }}" + --metadata date="$(date +'%Y-%m-%d')" + --output docs/requirements_report/trace_matrix.html + + - name: Generate Trace Matrix PDF with WeasyPrint run: > dotnet weasyprint --pdf-variant pdf/a-3u - docs/design/design.html - "docs/SonarMark Design.pdf" + docs/requirements_report/trace_matrix.html + "docs/SonarMark Trace Matrix.pdf" + + - name: Assert Requirements Documents with FileAssert + run: > + dotnet fileassert + --results artifacts/fileassert-requirements.trx + requirements # === UPLOAD ARTIFACTS === # This section uploads all generated documentation artifacts. + # Downstream projects: Add any additional artifact uploads here. - name: Upload documentation uses: actions/upload-artifact@v7 with: name: documents - path: | + path: |- docs/*.pdf docs/build_notes.md diff --git a/.github/workflows/build_on_push.yaml b/.github/workflows/build_on_push.yaml index d536b8e..344b21a 100644 --- a/.github/workflows/build_on_push.yaml +++ b/.github/workflows/build_on_push.yaml @@ -2,10 +2,10 @@ name: Build on Push on: - push: # On push to any branch - workflow_dispatch: # Allow manual trigger - schedule: # 5PM UTC every Monday - - cron: '0 17 * * 1' + push: + workflow_dispatch: + schedule: + - cron: '0 17 * * 1' # 5PM UTC every Monday jobs: build: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 842250d..5d3adc2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -74,7 +74,7 @@ jobs: - name: Publish to NuGet.org if: inputs.publish == 'publish' - run: | + run: |- set -e dotnet nuget push artifacts/*.nupkg \ --api-key ${{ secrets.DEMACONSULTINGNUGETKEY }} \ diff --git a/.markdownlint-cli2.yaml b/.markdownlint-cli2.yaml index fa74ad7..c16c443 100644 --- a/.markdownlint-cli2.yaml +++ b/.markdownlint-cli2.yaml @@ -11,6 +11,7 @@ # - Do not relax rules to accommodate existing non-compliant files # - Consistency across repositories is critical for documentation quality +# Disable the banner message (e.g., version info) on stdout noBanner: true # Disable the progress indicator on stdout @@ -32,10 +33,6 @@ config: MD013: line_length: 120 - # Allow duplicate headings in distinct sibling sections (needed for SonarMark guide structure) - MD024: - siblings_only: true - # Allow multiple top-level headers per document MD025: false diff --git a/.reviewmark.yaml b/.reviewmark.yaml index 36a1197..a10a031 100644 --- a/.reviewmark.yaml +++ b/.reviewmark.yaml @@ -6,14 +6,14 @@ # Patterns identifying all files that require review. # Processed in order; prefix a pattern with '!' to exclude. needs-review: - - "requirements.yaml" # Root requirements manifest - - "docs/reqstream/**/*.yaml" # All requirements files - - "docs/design/**/*.md" # All design documents - - "README.md" # Root level README - - "docs/user_guide/**/*.md" # User guide - - "**/*.cs" # All C# source and test files - - "!**/obj/**" # Exclude build output - - "!**/bin/**" # Exclude build output + - "README.md" # Project readme + - "**/*.cs" # All C# source and test files + - "requirements.yaml" # Root requirements file + - "docs/reqstream/**/*.yaml" # Requirements files + - "docs/user_guide/**/*.md" # User guide documents + - "docs/design/**/*.md" # Design documents + - "!**/obj/**" # Exclude build output + - "!**/bin/**" # Exclude build output # Evidence source: review data and index.json are located in the 'reviews' branch # of this repository, accessed through the GitHub public HTTPS raw content access. @@ -23,13 +23,11 @@ evidence-source: type: url location: https://raw.githubusercontent.com/demaconsulting/SonarMark/reviews/index.json -# Review sets grouping files by logical unit of review. -# Each review-set groups requirements, design, source, and tests for a coherent software unit -# so that an AI-assisted review can verify consistency across the full evidence chain. +# Review sets following standardized patterns for hierarchical compliance coverage reviews: - # Purpose review — proves advertised features match design (one per repository) + # Purpose Review (only one per repository) - id: Purpose - title: Review of SonarMark Purpose and Advertised Features + title: Review that Advertised Features Match System Design paths: - "README.md" - "docs/user_guide/**/*.md" @@ -37,58 +35,57 @@ reviews: - "docs/design/introduction.md" - "docs/design/sonar-mark/sonar-mark.md" - # System review — end-to-end integrated system and platform support (NO unit/subsystem source) + # SonarMark-Architecture Review (one per system) - id: SonarMark-Architecture - title: Review of SonarMark Integrated System + title: Review that SonarMark Architecture Satisfies Requirements paths: - "docs/reqstream/sonar-mark/sonar-mark.yaml" - - "docs/reqstream/sonar-mark/platform-requirements.yaml" - "docs/design/introduction.md" - "docs/design/sonar-mark/sonar-mark.md" - "test/**/IntegrationTests.cs" - "test/**/Runner.cs" - "test/**/AssemblyInfo.cs" - # Design review — system requirements against all design documentation + # SonarMark-Design Review (one per system) - id: SonarMark-Design - title: Review of SonarMark Design + title: Review that SonarMark Design is Consistent and Complete paths: - "docs/reqstream/sonar-mark/sonar-mark.yaml" - "docs/reqstream/sonar-mark/platform-requirements.yaml" - "docs/design/**/*.md" - - "README.md" - # Requirements review — all requirements files + # SonarMark-AllRequirements Review (one per system) - id: SonarMark-AllRequirements - title: Review of SonarMark Requirements + title: Review that All SonarMark Requirements are Complete paths: - "requirements.yaml" - "docs/reqstream/**/*.yaml" # Subsystem reviews — subsystem req + design + subsystem test file only (NO unit source files) - id: SonarMark-Cli - title: Review of SonarMark CLI Subsystem + title: Review that SonarMark Cli Satisfies Subsystem Requirements paths: - "docs/reqstream/sonar-mark/cli/cli.yaml" - "docs/design/sonar-mark/cli/cli.md" - "test/**/Cli/CliTests.cs" - id: SonarMark-SonarIntegration - title: Review of SonarMark SonarQube Integration Subsystem + title: Review that SonarMark SonarIntegration Satisfies Subsystem Requirements paths: - "docs/reqstream/sonar-mark/sonar-integration/sonar-integration.yaml" - "docs/design/sonar-mark/sonar-integration/sonar-integration.md" - "test/**/SonarIntegration/SonarIntegrationTests.cs" + - "test/**/SonarIntegration/SonarIntegrationTestHelpers.cs" - id: SonarMark-ReportGeneration - title: Review of SonarMark Report Generation Subsystem + title: Review that SonarMark ReportGeneration Satisfies Subsystem Requirements paths: - "docs/reqstream/sonar-mark/report-generation/report-generation.yaml" - "docs/design/sonar-mark/report-generation/report-generation.md" - "test/**/ReportGeneration/ReportGenerationTests.cs" - id: SonarMark-SelfTest - title: Review of SonarMark SelfTest Subsystem + title: Review that SonarMark SelfTest Satisfies Subsystem Requirements paths: - "docs/reqstream/sonar-mark/self-test/self-test.yaml" - "docs/design/sonar-mark/self-test/self-test.md" @@ -96,7 +93,7 @@ reviews: # Unit reviews — include actual source code + unit tests - id: SonarMark-Cli-Context - title: Review of SonarMark Context Unit + title: Review that SonarMark Cli Context Implementation is Correct paths: - "docs/reqstream/sonar-mark/cli/context.yaml" - "docs/design/sonar-mark/cli/context.md" @@ -104,7 +101,7 @@ reviews: - "test/**/ContextTests.cs" - id: SonarMark-Program - title: Review of SonarMark Program Unit + title: Review that SonarMark Program Implementation is Correct paths: - "docs/reqstream/sonar-mark/program.yaml" - "docs/design/sonar-mark/program.md" @@ -112,7 +109,7 @@ reviews: - "test/**/ProgramTests.cs" - id: SonarMark-SelfTest-Validation - title: Review of SonarMark Validation Unit + title: Review that SonarMark SelfTest Validation Implementation is Correct paths: - "docs/reqstream/sonar-mark/self-test/validation.yaml" - "docs/design/sonar-mark/self-test/validation.md" @@ -120,7 +117,7 @@ reviews: - "test/**/ValidationTests.cs" - id: SonarMark-SonarIntegration-SonarHotSpot - title: Review of SonarMark SonarHotSpot Unit + title: Review that SonarMark SonarIntegration SonarHotSpot Implementation is Correct paths: - "docs/reqstream/sonar-mark/sonar-integration/sonar-hot-spot.yaml" - "docs/design/sonar-mark/sonar-integration/sonar-hot-spot.md" @@ -128,7 +125,7 @@ reviews: - "test/**/SonarHotSpotTests.cs" - id: SonarMark-SonarIntegration-SonarIssue - title: Review of SonarMark SonarIssue Unit + title: Review that SonarMark SonarIntegration SonarIssue Implementation is Correct paths: - "docs/reqstream/sonar-mark/sonar-integration/sonar-issue.yaml" - "docs/design/sonar-mark/sonar-integration/sonar-issue.md" @@ -136,7 +133,7 @@ reviews: - "test/**/SonarIssueTests.cs" - id: SonarMark-ReportGeneration-SonarQualityResult - title: Review of SonarMark SonarQualityResult Unit + title: Review that SonarMark ReportGeneration SonarQualityResult Implementation is Correct paths: - "docs/reqstream/sonar-mark/report-generation/sonar-quality-result.yaml" - "docs/design/sonar-mark/report-generation/sonar-quality-result.md" @@ -144,7 +141,7 @@ reviews: - "test/**/SonarQualityResultTests.cs" - id: SonarMark-SonarIntegration-SonarQubeClient - title: Review of SonarMark SonarQubeClient Unit + title: Review that SonarMark SonarIntegration SonarQubeClient Implementation is Correct paths: - "docs/reqstream/sonar-mark/sonar-integration/sonar-qube-client.yaml" - "docs/design/sonar-mark/sonar-integration/sonar-qube-client.md" diff --git a/.versionmark.yaml b/.versionmark.yaml index 540553e..28387dc 100644 --- a/.versionmark.yaml +++ b/.versionmark.yaml @@ -44,10 +44,9 @@ tools: command: dotnet tool list regex: '(?i)demaconsulting\.sarifmark\s+(?\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)' - # SonarMark - checks global installation since it installs itself globally - # Note: Different from template - uses --global flag like BuildMark + # SonarMark (DemaConsulting.SonarMark from dotnet tool list) sonarmark: - command: dotnet tool list --global + command: dotnet tool list regex: '(?i)demaconsulting\.sonarmark\s+(?\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)' # ReqStream (DemaConsulting.ReqStream from dotnet tool list) @@ -69,3 +68,8 @@ tools: reviewmark: command: dotnet tool list regex: '(?i)demaconsulting\.reviewmark\s+(?\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)' + + # FileAssert (DemaConsulting.FileAssert from dotnet tool list) + fileassert: + command: dotnet tool list + regex: '(?i)demaconsulting\.fileassert\s+(?\d+\.\d+\.\d+(?:-[a-zA-Z0-9.]+)?)' diff --git a/.yamlfix.toml b/.yamlfix.toml new file mode 100644 index 0000000..233d73b --- /dev/null +++ b/.yamlfix.toml @@ -0,0 +1,16 @@ +# YAML Auto-Fix Configuration +# +# PURPOSE: +# - Configure yamlfix to auto-fix common YAML issues before yamllint checks +# - Settings MUST align with .yamllint.yaml to avoid conflicts +# - Use 'pwsh ./fix.ps1' or run 'yamlfix .' before 'pwsh ./lint.ps1' to auto-fix, then verify with yamllint +# +# RELATIONSHIP TO YAMLLINT: +# - line_length MUST match .yamllint.yaml line-length.max (120) +# - preserve_quotes prevents mangling GitHub Actions 'on:' boolean handling +# - After yamlfix auto-fix, yamllint should only fail on genuinely unresolvable issues + +line_length = 120 +preserve_quotes = true +sequence_style = "keep_style" +whitelines = 1 diff --git a/AGENTS.md b/AGENTS.md index a92c86f..eddf785 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,12 +1,5 @@ -# Agent Quick Reference - -Comprehensive guidance for AI agents working on repositories following Continuous Compliance practices. - # Project Structure -The following is the basic folder structure of the project. Agents should use this information when searching for -existing files and to know where to make new files. - ```text ├── docs/ │ ├── build_notes/ @@ -16,112 +9,141 @@ existing files and to know where to make new files. │ ├── design/ │ ├── requirements_doc/ │ ├── requirements_report/ -│ └── reqstream/ +│ ├── reqstream/ +│ └── user_guide/ ├── src/ -│ └── {project}/ +│ └── DemaConsulting.SonarMark/ └── test/ - └── {test-project}/ + └── DemaConsulting.SonarMark.Tests/ ``` +# Codebase Navigation (ALL Agents) + +When working with source code, design, or requirements artifacts, read +`docs/design/introduction.md` first. It provides the software structure, +folder layout, and companion artifact locations. Use it as the primary map +before searching the filesystem. + # Key Configuration Files - **`.config/dotnet-tools.json`** - Local tool manifest for Continuous Compliance tools - **`.editorconfig`** - Code formatting rules - **`.clang-format`** - C/C++ formatting (if applicable) - **`.cspell.yaml`** - Spell-check configuration and technical term dictionary -- **`.markdownlint-cli2.yaml`** - Markdown linting rules -- **`.yamllint.yaml`** - YAML linting configuration +- **`.markdownlint-cli2.yaml`** - Markdown formatting rules +- **`.yamllint.yaml`** - YAML formatting configuration - **`.reviewmark.yaml`** - File review definitions and tracking - **`nuget.config`** - NuGet package sources (if .NET) -- **`package.json`** - Node.js dependencies for linting tools +- **`package.json`** - Node.js dependencies for formatting tools - **`requirements.yaml`** - Root requirements file with includes -- **`pip-requirements.txt`** - Python dependencies for yamllint -- **`lint.sh` / `lint.bat`** - Cross-platform comprehensive linting scripts +- **`pip-requirements.txt`** - Python dependencies for yamllint and yamlfix +- **`fix.ps1`** - Applies all auto-fixers silently (dotnet format, markdown, YAML). Always exits 0. +- **`build.ps1`** - Builds the solution and runs all tests. # Standards Application (ALL Agents Must Follow) -Before performing any work, agents must read and apply the relevant standards from `.github/standards/`: +Before performing any work, agents must read and apply the relevant standards +from `.github/standards/`. Use this matrix to determine which to load: -- **`coding-principles.md`** - For universal coding standards (literate programming, architecture principles) -- **`testing-principles.md`** - For universal testing standards (dependency boundaries, AAA pattern) -- **`csharp-language.md`** - For C# code development (formatting, XML docs, C#-specific guidance) -- **`csharp-testing.md`** - For C# test development (AAA pattern, naming, MSTest anti-patterns) -- **`design-documentation.md`** - For design documentation (software structure diagrams, system.md, hierarchy) -- **`reqstream-usage.md`** - For requirements management (traceability, semantic IDs, source filters) -- **`reviewmark-usage.md`** - For file review management (review-sets, file patterns, enforcement) -- **`software-items.md`** - For software categorization (system/subsystem/unit/OTS classification) -- **`technical-documentation.md`** - For documentation creation and maintenance (structure, Pandoc, best practices) +| Work involves... | Load these standards | +|----------------------|------------------------------------------------------------------------------| +| Any code | `coding-principles.md` | +| C# code | `coding-principles.md`, `csharp-language.md` | +| Any tests | `testing-principles.md` | +| C# tests | `testing-principles.md`, `csharp-testing.md` | +| Requirements | `requirements-principles.md`, `software-items.md`, `reqstream-usage.md` | +| Design docs | `software-items.md`, `design-documentation.md`, `technical-documentation.md` | +| Review configuration | `software-items.md`, `reviewmark-usage.md` | +| Any documentation | `technical-documentation.md` | -Load only the standards relevant to your specific task scope and apply their -quality checks and guidelines throughout your work. +Load only the standards relevant to your specific task scope. # Agent Delegation Guidelines The default agent should handle simple, straightforward tasks directly. Delegate to specialized agents only for specific scenarios: +- **Pre-PR lint cleanup** (fix all lint issues before pull request) → Call the lint-fix agent - **Light development work** (small fixes, simple features) → Call the developer agent -- **Light quality checking** (linting, basic validation) → Call the quality agent +- **Light quality checking** (basic validation) → Call the quality agent - **Formal feature implementation** (complex, multi-step) → Call the implementation agent - **Formal bug resolution** (complex debugging, systematic fixes) → Call the implementation agent -- **Formal reviews** (compliance verification, detailed analysis) → Call the code-review agent +- **Formal reviews** (compliance verification, detailed analysis) → Call the formal-review agent - **Template consistency** (downstream repository alignment) → Call the repo-consistency agent ## Available Specialized Agents +- **lint-fix** - Pre-PR lint sweep agent that loops running `pwsh ./lint.ps1`, + fixing issues until the repository is lint-clean - **developer** - General-purpose software development agent that applies appropriate standards based on the work being performed -- **code-review** - Agent for performing formal reviews using standardized review processes +- **formal-review** - Agent for performing formal reviews using standardized review processes - **implementation** - Orchestrator agent that manages quality implementations through a formal state machine workflow -- **quality** - Quality assurance agent that grades developer work against DEMA - Consulting standards and Continuous Compliance practices +- **quality** - Quality assurance agent that grades developer work against project + standards and Continuous Compliance practices - **repo-consistency** - Ensures downstream repositories remain consistent with the TemplateDotNetTool template patterns and best practices -# Linting (Required Before Quality Gates) +# Agent Reporting (Specialized Agents Must Follow) -1. **Markdown Auto-fix**: `npx markdownlint-cli2 --fix **/*.md` (fixes most markdown issues except line length) -2. **Dotnet Auto-fix**: `dotnet format` (reformats .NET languages) -3. **Run full check**: `lint.bat` (Windows) or `lint.sh` (Unix) -4. **Fix remaining**: Address line length, spelling, YAML syntax manually -5. **Verify clean**: Re-run until 0 errors before quality validation +Specialized agents (lint-fix, developer, quality, implementation, +formal-review, repo-consistency) MUST generate a completion report: -## Linting Tools (ALL Must Pass) +1. Save to `.agent-logs/{agent-name}-{subject}-{unique-id}.md` + where `{subject}` is a kebab-case task summary (max 5 words) and + `{unique-id}` is a short unique suffix (e.g., 8-char hex or timestamp) +2. Start with `**Result**: (SUCCEEDED|FAILED)` as the first metadata field +3. Include the agent-specific report sections defined in each agent's prompt +4. Return the summary to the caller -- **markdownlint-cli2**: Markdown style and formatting enforcement -- **cspell**: Spell-checking across all text files (use `.cspell.yaml` for technical terms) -- **yamllint**: YAML structure and formatting validation -- **Language-specific linters**: Based on repository technology stack +Result semantics for orchestrator decision-making: -# Quality Gate Enforcement (ALL Agents Must Verify) +- **SUCCEEDED**: Work completed and all applicable quality gates met +- **FAILED**: Work could not be completed or quality gates not met +- **INCOMPLETE**: Work cannot proceed without information only the user can + provide (implementation agent only) -Configuration files and scripts are self-documenting with their design intent and -modification policies in header comments. +# Formatting (After Making Changes) -1. **Build Quality**: Zero warnings (`TreatWarningsAsErrors=true`) -2. **Static Analysis**: SonarQube/CodeQL passing with no blockers -3. **Requirements Traceability**: `dotnet reqstream --enforce` passing -4. **Test Coverage**: All requirements linked to passing tests -5. **Documentation Currency**: All docs current and generated -6. **File Review Status**: All reviewable files have current reviews +After making changes, run the auto-fix pass. This applies all available fixers +silently and **always exits 0** — agents do not need to respond to its output. -# Continuous Compliance Overview +```pwsh +pwsh ./fix.ps1 +``` -This repository follows the DEMA Consulting Continuous Compliance - approach, which enforces quality and -compliance gates on every CI/CD run instead of as a last-mile activity. +This automatically handles: `dotnet format`, markdown formatting, and YAML +formatting. Full lint compliance is a **pre-PR responsibility**, not an agent +responsibility — invoke the lint-fix agent once before submitting a pull request. -## Core Principles +## CI Quality Tools -- **Requirements Traceability**: Every requirement MUST link to passing tests -- **Quality Gates**: All quality checks must pass before merge -- **Documentation Currency**: All docs auto-generated and kept current -- **Automated Evidence**: Full audit trail generated with every build +CI runs `lint.ps1` which checks: markdownlint-cli2, cspell, yamllint, dotnet format, +reqstream, versionmark, and reviewmark. -## Requirements & Compliance +# Scope Discipline (ALL Agents Must Follow) + +- **Minimum necessary changes**: Only modify files directly required by the task +- **No speculative refactoring**: Do not refactor code adjacent to the change + unless the task explicitly requests it +- **No drive-by fixes**: If you discover pre-existing issues in files you are + reading but not modifying, document them in the report but do not fix them +- **Declare scope upfront**: Before making changes, determine which files will be + modified. Any file outside this scope requires explicit justification. + +# Protected Configuration Files + +These files contain carefully designed configuration with documented intent +in header comments. Agents MUST NOT modify them unless the task explicitly +requires it and the modification preserves the documented design intent: + +- `.reviewmark.yaml`, `.cspell.yaml`, `.editorconfig` +- `.markdownlint-cli2.yaml`, `.yamllint.yaml` +- `requirements.yaml`, `fix.ps1`, `lint.ps1` + +# Continuous Compliance Overview -- **ReqStream**: Requirements traceability enforcement (`dotnet reqstream --enforce`) -- **ReviewMark**: File review status enforcement -- **BuildMark**: Tool version documentation -- **VersionMark**: Version tracking across CI/CD jobs +This repository follows the [Continuous Compliance](https://github.com/demaconsulting/ContinuousCompliance) +approach. Tools: **ReqStream** (requirements traceability), **ReviewMark** (file review enforcement), +**BuildMark** (tool versions), **VersionMark** (version tracking). diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 348b381..c07c4cb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,12 +79,6 @@ We follow a standard GitHub workflow for contributions: dotnet test --configuration Release ``` -5. Run self-validation tests: - - ```bash - dotnet run --project src/DemaConsulting.SonarMark --configuration Release --framework net10.0 --no-build -- --validate - ``` - ## Coding Standards ### General Guidelines @@ -173,7 +167,8 @@ dotnet test --collect "XPlat Code Coverage" ```bash # Run self-validation tests -dotnet run --project src/DemaConsulting.SonarMark --configuration Release --framework net10.0 --no-build -- --validate +dotnet run --project src/DemaConsulting.SonarMark \ + --configuration Release --framework net10.0 --no-build -- --validate ``` ### Test Execution Strategy @@ -254,16 +249,14 @@ All tests must pass with zero warnings. ### 2. Linting -Use the lint script which installs dependencies and runs all linters: +```pwsh +# After making changes: applies dotnet format, markdown, and YAML fixes silently +pwsh ./fix.ps1 -```bash -./lint.sh # Linux/macOS (or: bash ./lint.sh) -cmd /c lint.bat # Windows (Command Prompt) -./lint.bat # Windows (PowerShell) +# Before submitting a pull request: all linters must pass +pwsh ./lint.ps1 ``` -All linters must pass with no errors or warnings. - ### 3. Code Coverage Maintain or improve code coverage. Use the `--collect "XPlat Code Coverage"` option when running tests. diff --git a/README.md b/README.md index 6d44a16..18fa1ce 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ documentation workflows. ## Features - 📊 **Quality Gate Reports** - Retrieve and report quality gate status with detailed conditions -- 🐛 **Issue Analysis** - Fetch and categorize issues by type and severity +- 🐛 **Issue Analysis** - Fetch and list issues by type and severity - 🔒 **Security Hot-Spots** - Identify and report security vulnerabilities requiring review - 📝 **Markdown Output** - Generate human-readable markdown reports for easy sharing - 🚀 **CI/CD Integration** - Enforce quality gates and fail builds on quality issues diff --git a/build.bat b/build.bat deleted file mode 100644 index a56a4b0..0000000 --- a/build.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off -REM Build and test SonarMark (Windows) - -echo Building SonarMark... -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.ps1 b/build.ps1 new file mode 100644 index 0000000..188d18f --- /dev/null +++ b/build.ps1 @@ -0,0 +1,29 @@ +# build.ps1 +# +# PURPOSE: +# Unified cross-platform build script (replaces build.bat and build.sh). +# Builds the solution in Release configuration and runs all unit tests. +# +# EXTENSION POINTS: +# Search for "[PROJECT-SPECIFIC]" comments to find the designated locations +# for adding project-specific build or test operations. +# +# MODIFICATION POLICY: +# Only modify this file to add project-specific operations at the designated +# [PROJECT-SPECIFIC] extension points. + +$ErrorActionPreference = 'Stop' + +Write-Host "Building project..." +dotnet build --configuration Release +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# [PROJECT-SPECIFIC] Add additional build steps here. + +Write-Host "Running unit tests..." +dotnet test --configuration Release +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# [PROJECT-SPECIFIC] Add additional test or post-build steps here. + +Write-Host "Build and tests completed successfully!" diff --git a/build.sh b/build.sh deleted file mode 100755 index 6bf0f01..0000000 --- a/build.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/env bash -# Build and test SonarMark - -set -e # Exit on error - -echo "🔧 Building SonarMark..." -dotnet build --configuration Release - -echo "✅ Running tests..." -dotnet test --configuration Release --verbosity normal - -echo "✨ Build and test completed successfully!" diff --git a/docs/design/introduction.md b/docs/design/introduction.md index 1ab2321..f627418 100644 --- a/docs/design/introduction.md +++ b/docs/design/introduction.md @@ -11,7 +11,10 @@ class in the codebase. ## Scope -This design document covers the software units that make up SonarMark. +This design document covers the software units that make up SonarMark. It +describes the source code under `src/DemaConsulting.SonarMark/` only. Test +projects, test infrastructure, and build scripts are explicitly out of scope +and are not described here. ## Audience @@ -63,8 +66,6 @@ src/DemaConsulting.SonarMark/ └── Validation.cs — self-validation runner, writes TRX and JUnit result files ``` -The test project mirrors the same layout under `test/DemaConsulting.SonarMark.Tests/`. - The design documentation mirrors the same structure under `docs/design/sonar-mark/`: ```text diff --git a/docs/design/sonar-mark/cli/cli.md b/docs/design/sonar-mark/cli/cli.md index c85128d..096a8a7 100644 --- a/docs/design/sonar-mark/cli/cli.md +++ b/docs/design/sonar-mark/cli/cli.md @@ -10,7 +10,6 @@ to the appropriate functionality. | Unit | Source File | Purpose | | :--- | :---------- | :------ | -| Program | `Program.cs` | Entry point, dispatch, parameter validation, report writing | | Context | `Cli/Context.cs` | Argument parsing, output, log-file, enforce, results-file | ## Interfaces diff --git a/docs/design/sonar-mark/cli/context.md b/docs/design/sonar-mark/cli/context.md index 73398b6..04ab88f 100644 --- a/docs/design/sonar-mark/cli/context.md +++ b/docs/design/sonar-mark/cli/context.md @@ -10,6 +10,26 @@ typed properties used by the rest of the application. `Context` implements `IDisposable` to ensure the log-file stream writer is properly closed when the application exits. +## Public Members + +### WriteLine + +`void WriteLine(string message)` writes a line of text to the standard output stream +unless `Silent` mode is active. When a log file is open, the message is also mirrored +to the log file. Callers never need to check `Silent` themselves. + +### WriteError + +`void WriteError(string message)` writes a line of text to the standard error stream +unless `Silent` mode is active, mirrors it to the log file when open, and sets the +internal `_hasErrors` flag so that `ExitCode` returns `1` after the call. + +### ExitCode + +`int ExitCode` is a read-only property that returns `1` if `WriteError` has been called +at least once during the lifetime of the context, and `0` otherwise. `Program.Main` +returns this value as the process exit code so that CI pipelines can detect failures. + ## Design Decisions ### Factory Method Pattern @@ -50,6 +70,7 @@ Using `IDisposable` rather than a finalizer is appropriate because the resource - `SonarMark-Validation-JUnitFormat` — JUnit XML file extension is accepted by `ResultsFile` - `SonarMark-Enforce-Mode` — `Enforce` flag is parsed and stored - `SonarMark-Enforce-ExitCode` — `ExitCode` returns 1 when `_hasErrors` is true +- `SonarMark-Context-ResultsFile` — `--results` flag is parsed and stored as `ResultsFile` - `SonarMark-Context-ResultAlias` — `--result` is accepted as a legacy alias for `--results` - `SonarMark-Report-Depth` — `Depth` property stores the parsed header depth value - `SonarMark-Context-Depth` — `--depth` is the canonical flag; `--report-depth` is a deprecated alias diff --git a/docs/design/sonar-mark/program.md b/docs/design/sonar-mark/program.md index 2a16c9e..77dac06 100644 --- a/docs/design/sonar-mark/program.md +++ b/docs/design/sonar-mark/program.md @@ -35,6 +35,20 @@ printing, so that the operating system or CI runner can produce an event log ent before attempting any network call. Missing required parameters are reported via `context.WriteError`, which sets the error flag and drives the non-zero exit code. +### HttpClientFactory Injection + +`ProcessSonarAnalysis` obtains its `SonarQubeClient` instance through +`context.HttpClientFactory`, a `Func` delegate held on +`Context`. This delegate is the testability seam: integration tests supply a factory +that returns a mock client pre-loaded with canned responses, while production code +leaves the property `null`. + +When `HttpClientFactory` is `null` (the normal production path), the method falls back +to `new SonarQubeClient(context.Token)`, which creates a real HTTP client authenticated +with the provided token. This design keeps `Program` free of any direct reference to the +test infrastructure and avoids the need to sub-class or wrap `SonarQubeClient` for +testing purposes. + ## Satisfies Requirements - `SonarMark-Cli-Interface` — `Main` is the CLI entry point diff --git a/docs/design/sonar-mark/report-generation/sonar-quality-result.md b/docs/design/sonar-mark/report-generation/sonar-quality-result.md index b70ca98..76837b9 100644 --- a/docs/design/sonar-mark/report-generation/sonar-quality-result.md +++ b/docs/design/sonar-mark/report-generation/sonar-quality-result.md @@ -35,10 +35,23 @@ Issues and hot-spots are rendered in compiler-style format (`component:line: severity: message`) so that they can be read alongside build output and parsed by tools that understand that format. +## SonarQualityCondition + +`SonarQualityCondition` is an immutable positional record declared in the same +file as `SonarQualityResult`. It represents one quality gate condition returned +by the `/api/qualitygates/project_status` endpoint. + +| Parameter | C# Type | Description | +| :---------- | :-------- | :------------ | +| `Metric` | `string` | Metric key as returned by the API (e.g., `new_coverage`, `new_bugs`) | +| `Comparator` | `string` | Comparison operator (e.g., `LT`, `GT`) | +| `ErrorThreshold` | `string?` | Threshold value that triggers an error; `null` when not set | +| `ActualValue` | `string?` | Actual metric value from the analysis; `null` when not available | +| `Status` | `string` | Condition status returned by the API (e.g., `OK`, `WARN`, `ERROR`) | + ## Satisfies Requirements -- `SonarMark-Report-Markdown` — `ToMarkdown` generates the markdown report content -- `SonarMark-Report-Depth` — the `depth` parameter controls heading levels - `SonarMark-Report-QualityGate` — quality gate status and conditions are included in the report - `SonarMark-Report-Issues` — issues are categorized and rendered in the report - `SonarMark-Report-HotSpots` — hot-spots are rendered in the report +- `SonarMark-Report-DepthValidation` — `ToMarkdown` validates depth is in the range 1–6 diff --git a/docs/design/sonar-mark/self-test/self-test.md b/docs/design/sonar-mark/self-test/self-test.md index 552bdb7..60b0f54 100644 --- a/docs/design/sonar-mark/self-test/self-test.md +++ b/docs/design/sonar-mark/self-test/self-test.md @@ -21,3 +21,22 @@ a `Context` and runs four internal tests using a mock HTTP client. 1. `Program.Run` calls `Validation.Run(context)` when `--validate` flag is set 2. `Validation` creates a mock `SonarQubeClient` to exercise the SonarIntegration subsystem 3. Results are written to TRX or JUnit XML files if `--results` is specified + +## Error Handling + +Validation failures are surfaced through the `Context` output mechanism: + +- Individual test failures are reported via `context.WriteError`, which sets the internal + `_hasErrors` flag and causes `context.ExitCode` to return `1`. +- If result-file writing fails (e.g., the output path is not writable or the format is + unsupported), the exception is caught internally and reported via `context.WriteError` + rather than propagating to `Program.Main`. +- If an unexpected exception occurs during an individual test, `RunValidationTest` catches + it, records the failure via `context.WriteError`, and allows the remaining tests to + continue so that CI runners receive accurate pass/fail counts. + +## Satisfies Requirements + +- `SonarMark-Subsystem-SelfTest` — `Validation.Run` exercises the full analysis + pipeline using a mock HTTP client, writes test results, and reports pass/fail + status through the context exit code diff --git a/docs/design/sonar-mark/self-test/validation.md b/docs/design/sonar-mark/self-test/validation.md index eceeef3..9e49298 100644 --- a/docs/design/sonar-mark/self-test/validation.md +++ b/docs/design/sonar-mark/self-test/validation.md @@ -35,6 +35,62 @@ retrieval, markdown report generation) is isolated in its own helper method. This makes failures easy to diagnose and allows individual scenarios to be added or removed independently. +### TemporaryDirectory + +`TemporaryDirectory` is a private nested class that implements `IDisposable`. +It creates a uniquely named temporary directory on construction and deletes it +(including all its contents) on disposal. Each validation test creates its own +`TemporaryDirectory` instance so that log files and report files written during +test execution are cleaned up automatically, preventing cross-test interference +and leaving no file-system artifacts after the run completes. + +### Helper Methods + +Three private helpers manage the test lifecycle: + +- **`CreateTestResult`** — allocates a new `TestResult` object pre-populated with + the test name, class name (`Validation`), and code base (`SonarMark`). Called + before the test body runs to provide a result container into which outcomes are + written. + +- **`HandleTestException`** — invoked from the `catch` block inside + `RunValidationTest` when an unexpected exception escapes the test body. It marks + the result as `Failed`, stores the exception message, and writes the failure to + the context output. The broad `catch (Exception)` is intentional here because + the self-test must not crash the process regardless of what a scenario throws. + +- **`FinalizeTestResult`** — called after every test (pass or fail) to record + elapsed duration and append the result to the shared `TestResults` collection. + Placing this call in the method that wraps the test body guarantees it runs even + when `HandleTestException` has already been invoked. + +## Error Handling + +### Null-Context Precondition + +`Validation.Run` guards against a null `context` argument with +`ArgumentNullException.ThrowIfNull(context)` at the top of the method. Because +`context` is used for all output and all subsequent calls depend on it, an early +fail-fast check is cleaner than a `NullReferenceException` arising deep in the +call chain. + +### Unsupported-Format Error in WriteResultsFile + +`WriteResultsFile` inspects the file extension of `context.ResultsFile` and +branches to the TRX or JUnit serializer. If the extension is neither `.trx` nor +`.xml`, it writes an error message via `context.WriteError` and returns without +writing any file. It does **not** throw, because an unsupported format is a +configuration mistake that the caller has already communicated to the user via +the error message — aborting the whole program would be excessive. + +### I/O Failure Catch Block + +`WriteResultsFile` wraps `File.WriteAllText` in a `try/catch (Exception)` block. +File I/O failures (permissions, disk full, invalid path) are caught, and the +exception message is written to `context.WriteError`. This prevents an I/O +failure from propagating out of the validation run, which could mask the +test-result summary that was already printed to the console. + ## Satisfies Requirements - `SonarMark-Validation-Run` — implements the self-validation mode invoked by `--validate` diff --git a/docs/design/sonar-mark/sonar-integration/sonar-hot-spot.md b/docs/design/sonar-mark/sonar-integration/sonar-hot-spot.md index 4336e25..766f00b 100644 --- a/docs/design/sonar-mark/sonar-integration/sonar-hot-spot.md +++ b/docs/design/sonar-mark/sonar-integration/sonar-hot-spot.md @@ -23,10 +23,19 @@ line, message, security category, and vulnerability probability. Additional fiel returned by the API are ignored to keep the model focused and reduce coupling to the API response schema. +## Fields + +| Field | C# Type | Description | +| :----- | :------- | :----------- | +| `Key` | `string` | Unique identifier for the hot-spot | +| `Component` | `string` | Fully-qualified component path including project key prefix | +| `Line` | `int?` | Source line number; `null` when the hot-spot has no line association | +| `Message` | `string` | Human-readable description of the hot-spot | +| `SecurityCategory` | `string` | Security category key (e.g., `sql-injection`, `xss`) | +| `VulnerabilityProbability` | `string` | Probability level returned by the API (e.g., `HIGH`, `MEDIUM`, `LOW`) | + ## Satisfies Requirements - `SonarMark-HotSpot-Record` — holds the data for one hot-spot fetched from the server - `SonarMark-HotSpot-OptionalLine` — captures the optional line number field - `SonarMark-HotSpot-VulnerabilityProbability` — captures the vulnerability probability field -- `SonarMark-Server-HotSpots` — holds the data for one hot-spot fetched from the server -- `SonarMark-Report-HotSpots` — provides the fields rendered in the hot-spots section of the report diff --git a/docs/design/sonar-mark/sonar-integration/sonar-qube-client.md b/docs/design/sonar-mark/sonar-integration/sonar-qube-client.md index 58fdbe7..823504b 100644 --- a/docs/design/sonar-mark/sonar-integration/sonar-qube-client.md +++ b/docs/design/sonar-mark/sonar-integration/sonar-qube-client.md @@ -26,7 +26,32 @@ format. All network methods are `async` and accept a `CancellationToken`. The primary public method `GetQualityResultByBranchAsync` composes several internal async -calls to retrieve conditions, issues, and hot-spots in a logical sequence. +calls in a fixed sequence: + +1. **Project name retrieval** — calls `/api/components/show?component={projectKey}` + to obtain the human-readable project name. The response JSON must contain a + `component.name` string; if missing, the method falls back to the raw project + key. If the HTTP request fails (non-2xx), an `InvalidOperationException` is + thrown. If the JSON response is malformed, a `JsonException` may be thrown + (see Error Handling below). + +2. **Quality gate status** — calls + `/api/qualitygates/project_status?projectKey={projectKey}` (with optional + `&branch=` parameter) to retrieve the overall gate status and its conditions. + +3. **Metric name resolution** — calls `/api/metrics/search` to build a dictionary + mapping internal metric keys (e.g., `new_coverage`) to human-readable display + names (e.g., `Coverage on New Code`). This dictionary is passed to + `SonarQualityResult` so the report can render friendly metric labels. + +4. **Issues** — paginates through `/api/issues/search` until all pages are + consumed. + +5. **Hot-spots** — paginates through `/api/hotspots/search` until all pages are + consumed. + +Results from all five calls are assembled into a single `SonarQualityResult` +instance and returned to the caller. ### Pagination @@ -40,6 +65,11 @@ HTTP errors (non-2xx responses) are surfaced as `InvalidOperationException` with a message that includes the HTTP status code, so callers can distinguish API errors from network errors and report them appropriately. +`JsonDocument.Parse()` is called on every API response. If the server returns a +syntactically invalid JSON body, `JsonDocument.Parse` throws a `JsonException`. +This exception is not caught by `SonarQubeClient` and propagates to the caller, +indicating a malformed or unexpected server response. + ## Satisfies Requirements - `SonarMark-Server-QualityGate` — fetches quality gate status and conditions from the API diff --git a/docs/design/sonar-mark/sonar-mark.md b/docs/design/sonar-mark/sonar-mark.md index aa6ac18..162072b 100644 --- a/docs/design/sonar-mark/sonar-mark.md +++ b/docs/design/sonar-mark/sonar-mark.md @@ -83,3 +83,20 @@ post-processing. `SonarQualityResult` includes them in the rendered markdown report - `SonarMark-System-Report` — `SonarQualityResult.ToMarkdown` combines all retrieved analysis data and `Program` writes the complete markdown report to disk +- `SonarMark-System-Validation` — `Program` dispatches to the `Validation` subsystem + when `--validate` is supplied; the subsystem runs self-tests and emits a summary +- `SonarMark-System-Enforce` — `Program` reads `Context.Enforce` and calls + `context.WriteError` when the quality gate status is not passing, causing a non-zero + exit code +- `SonarMark-Platform-Windows` — the single-process .NET architecture runs natively on + Windows with no platform-specific code paths +- `SonarMark-Platform-Linux` — the single-process .NET architecture runs natively on + Linux with no platform-specific code paths +- `SonarMark-Platform-MacOS` — the single-process .NET architecture runs natively on + macOS with no platform-specific code paths +- `SonarMark-Platform-Net8` — the project targets `net8.0` in the SDK multi-targeting + list, enabling the tool to run on the .NET 8 runtime +- `SonarMark-Platform-Net9` — the project targets `net9.0` in the SDK multi-targeting + list, enabling the tool to run on the .NET 9 runtime +- `SonarMark-Platform-Net10` — the project targets `net10.0` in the SDK multi-targeting + list, enabling the tool to run on the .NET 10 runtime diff --git a/docs/reqstream/ots/buildmark.yaml b/docs/reqstream/ots/buildmark.yaml new file mode 100644 index 0000000..30f5e16 --- /dev/null +++ b/docs/reqstream/ots/buildmark.yaml @@ -0,0 +1,20 @@ +--- +# BuildMark OTS Software Requirements +# +# Requirements for the BuildMark build documentation tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: BuildMark Requirements + requirements: + - id: SonarMark-OTS-BuildMark + title: BuildMark shall generate build-notes documentation from GitHub Actions metadata. + justification: | + DemaConsulting.BuildMark queries the GitHub API to capture workflow run details and + renders them as a markdown build-notes document included in the release artifacts. + It runs as part of the same CI pipeline that produces the TRX test results, so a + successful pipeline run is evidence that BuildMark executed without error. + tags: [ots] + tests: + - BuildMark_MarkdownReportGeneration diff --git a/docs/reqstream/ots/fileassert.yaml b/docs/reqstream/ots/fileassert.yaml new file mode 100644 index 0000000..8c6b6da --- /dev/null +++ b/docs/reqstream/ots/fileassert.yaml @@ -0,0 +1,22 @@ +--- +# FileAssert OTS Software Requirements +# +# Requirements for the FileAssert document assertion tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: FileAssert Requirements + requirements: + - id: SonarMark-OTS-FileAssert + title: FileAssert shall validate generated documents against acceptance criteria. + justification: | + DemaConsulting.FileAssert validates HTML and PDF documents produced during the + build, asserting that each document exists, has a non-trivial size, is structurally + valid, and contains expected content. It provides OTS evidence for Pandoc and + WeasyPrint and independently confirms file assertion is functioning. Self-validation + proves the tool itself is operational before ReqStream consumes the results. + tags: [ots] + tests: + - FileAssert_VersionDisplay + - FileAssert_HelpDisplay diff --git a/docs/reqstream/ots/mstest.yaml b/docs/reqstream/ots/mstest.yaml new file mode 100644 index 0000000..4e7c972 --- /dev/null +++ b/docs/reqstream/ots/mstest.yaml @@ -0,0 +1,26 @@ +--- +# MSTest OTS Software Requirements +# +# Requirements for the MSTest testing framework functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: MSTest Requirements + requirements: + - id: SonarMark-OTS-MSTest + title: MSTest shall execute unit tests and report results. + justification: | + MSTest (MSTest.TestFramework and MSTest.TestAdapter) is the unit-testing framework used + by the project. It discovers and runs all test methods and writes TRX result files that + feed into coverage reporting and requirements traceability. Passing tests confirm the + framework is functioning correctly. + tags: [ots] + tests: + - Context_Create_WithLogFile_WritesToLogFile + - Context_Create_ResultsFile_SetsResultsProperty + - Context_Create_MissingResultsFilename_ThrowsException + - Context_Create_EnforceFlag_SetsEnforceProperty + - SonarQualityResult_ToMarkdown_Depth1_ProducesCorrectOutput + - SonarQualityResult_ToMarkdown_WithIssues_ProducesCompilerStyleOutput + - SonarQualityResult_ToMarkdown_WithHotSpots_ProducesCompilerStyleOutput diff --git a/docs/reqstream/ots/ots-buildmark.yaml b/docs/reqstream/ots/ots-buildmark.yaml deleted file mode 100644 index 15973e1..0000000 --- a/docs/reqstream/ots/ots-buildmark.yaml +++ /dev/null @@ -1,20 +0,0 @@ ---- -# BuildMark OTS Software Requirements -# -# PURPOSE: -# - Document the functionality required from BuildMark -# - DemaConsulting.BuildMark generates build-notes documentation from GitHub Actions metadata -# -sections: - - title: BuildMark - requirements: - - id: SonarMark-OTS-BuildMark - title: BuildMark shall generate build-notes documentation from GitHub Actions metadata. - justification: | - DemaConsulting.BuildMark queries the GitHub API to capture workflow run details and - renders them as a markdown build-notes document included in the release artifacts. - It runs as part of the same CI pipeline that produces the TRX test results, so a - successful pipeline run is evidence that BuildMark executed without error. - tags: [ots] - tests: - - BuildMark_MarkdownReportGeneration diff --git a/docs/reqstream/ots/ots-mstest.yaml b/docs/reqstream/ots/ots-mstest.yaml deleted file mode 100644 index faa188a..0000000 --- a/docs/reqstream/ots/ots-mstest.yaml +++ /dev/null @@ -1,26 +0,0 @@ ---- -# MSTest OTS Software Requirements -# -# PURPOSE: -# - Document the functionality required from MSTest -# - MSTest (MSTest.TestFramework and MSTest.TestAdapter) is the unit-testing framework -# -sections: - - title: MSTest - requirements: - - id: SonarMark-OTS-MSTest - title: MSTest shall execute unit tests and report results. - justification: | - MSTest (MSTest.TestFramework and MSTest.TestAdapter) is the unit-testing framework used - by the project. It discovers and runs all test methods and writes TRX result files that - feed into coverage reporting and requirements traceability. Passing tests confirm the - framework is functioning correctly. - tags: [ots] - tests: - - Context_Create_WithLogFile_WritesToLogFile - - Context_Create_ResultsFile_SetsResultsProperty - - Context_Create_MissingResultsFilename_ThrowsException - - Context_Create_EnforceFlag_SetsEnforceProperty - - SonarQualityResult_ToMarkdown_Depth1_ProducesCorrectOutput - - SonarQualityResult_ToMarkdown_WithIssues_ProducesCompilerStyleOutput - - SonarQualityResult_ToMarkdown_WithHotSpots_ProducesCompilerStyleOutput diff --git a/docs/reqstream/ots/ots-reqstream.yaml b/docs/reqstream/ots/ots-reqstream.yaml deleted file mode 100644 index fcfbe24..0000000 --- a/docs/reqstream/ots/ots-reqstream.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# ReqStream OTS Software Requirements -# -# PURPOSE: -# - Document the functionality required from ReqStream -# - DemaConsulting.ReqStream enforces requirements traceability across the project -# -sections: - - title: ReqStream - requirements: - - id: SonarMark-OTS-ReqStream - title: ReqStream shall enforce that every requirement is linked to passing test evidence. - justification: | - DemaConsulting.ReqStream processes requirements.yaml and the TRX test-result files to - produce a requirements report, justifications document, and traceability matrix. When - run with --enforce, it exits with a non-zero code if any requirement lacks test evidence, - making unproven requirements a build-breaking condition. A successful pipeline run with - --enforce proves all requirements are covered and that ReqStream is functioning. - tags: [ots] - tests: - - ReqStream_EnforcementMode diff --git a/docs/reqstream/ots/ots-sarifmark.yaml b/docs/reqstream/ots/ots-sarifmark.yaml deleted file mode 100644 index e21824c..0000000 --- a/docs/reqstream/ots/ots-sarifmark.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# SarifMark OTS Software Requirements -# -# PURPOSE: -# - Document the functionality required from SarifMark -# - DemaConsulting.SarifMark converts CodeQL SARIF results into a markdown report -# -sections: - - title: SarifMark - requirements: - - id: SonarMark-OTS-SarifMark - title: SarifMark shall convert CodeQL SARIF results into a markdown report. - justification: | - DemaConsulting.SarifMark reads the SARIF output produced by CodeQL code scanning and - renders it as a human-readable markdown document included in the release artifacts. - It runs in the same CI pipeline that produces the TRX test results, so a successful - pipeline run is evidence that SarifMark executed without error. - tags: [ots] - tests: - - SarifMark_SarifReading - - SarifMark_MarkdownReportGeneration diff --git a/docs/reqstream/ots/ots-versionmark.yaml b/docs/reqstream/ots/ots-versionmark.yaml deleted file mode 100644 index 6688148..0000000 --- a/docs/reqstream/ots/ots-versionmark.yaml +++ /dev/null @@ -1,21 +0,0 @@ ---- -# VersionMark OTS Software Requirements -# -# PURPOSE: -# - Document the functionality required from VersionMark -# - DemaConsulting.VersionMark publishes captured tool-version information -# -sections: - - title: VersionMark - requirements: - - id: SonarMark-OTS-VersionMark - title: VersionMark shall publish captured tool-version information. - justification: | - DemaConsulting.VersionMark reads version metadata for each dotnet tool used in the - pipeline and writes a versions markdown document included in the release artifacts. - It runs in the same CI pipeline that produces the TRX test results, so a successful - pipeline run is evidence that VersionMark executed without error. - tags: [ots] - tests: - - VersionMark_CapturesVersions - - VersionMark_GeneratesMarkdownReport diff --git a/docs/reqstream/ots/pandoc.yaml b/docs/reqstream/ots/pandoc.yaml new file mode 100644 index 0000000..b034810 --- /dev/null +++ b/docs/reqstream/ots/pandoc.yaml @@ -0,0 +1,26 @@ +--- +# Pandoc OTS Software Requirements +# +# Requirements for the Pandoc document conversion tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: Pandoc Requirements + requirements: + - id: SonarMark-OTS-Pandoc + title: Pandoc shall convert Markdown documents to valid HTML. + justification: | + DemaConsulting.PandocTool converts Markdown source documents to HTML as part of the + documentation build pipeline. FileAssert validates that each generated HTML file + exists, has a non-trivial size, contains a valid HTML title element, and includes + expected document content. Passing FileAssert assertions for each document type + proves Pandoc executed correctly and produced meaningful output. + tags: [ots] + tests: + - Pandoc_BuildNotesHtml + - Pandoc_CodeQualityHtml + - Pandoc_ReviewPlanHtml + - Pandoc_ReviewReportHtml + - Pandoc_DesignHtml + - Pandoc_UserGuideHtml diff --git a/docs/reqstream/ots/reqstream.yaml b/docs/reqstream/ots/reqstream.yaml new file mode 100644 index 0000000..763463f --- /dev/null +++ b/docs/reqstream/ots/reqstream.yaml @@ -0,0 +1,21 @@ +--- +# ReqStream OTS Software Requirements +# +# Requirements for the ReqStream requirements traceability tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: ReqStream Requirements + requirements: + - id: SonarMark-OTS-ReqStream + title: ReqStream shall enforce that every requirement is linked to passing test evidence. + justification: | + DemaConsulting.ReqStream processes requirements.yaml and the TRX test-result files to + produce a requirements report, justifications document, and traceability matrix. When + run with --enforce, it exits with a non-zero code if any requirement lacks test evidence, + making unproven requirements a build-breaking condition. A successful pipeline run with + --enforce proves all requirements are covered and that ReqStream is functioning. + tags: [ots] + tests: + - ReqStream_EnforcementMode diff --git a/docs/reqstream/ots/reviewmark.yaml b/docs/reqstream/ots/reviewmark.yaml new file mode 100644 index 0000000..5fa6156 --- /dev/null +++ b/docs/reqstream/ots/reviewmark.yaml @@ -0,0 +1,21 @@ +--- +# ReviewMark OTS Software Requirements +# +# Requirements for the ReviewMark file review tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: ReviewMark Requirements + requirements: + - id: SonarMark-OTS-ReviewMark + title: ReviewMark shall generate a review plan and review report from the review configuration. + justification: | + DemaConsulting.ReviewMark reads the .reviewmark.yaml configuration and the review + evidence store to produce a review plan and review report documenting file review + coverage and currency. It runs in the same CI pipeline that produces the TRX test + results, so a successful pipeline run is evidence that ReviewMark executed without error. + tags: [ots] + tests: + - ReviewMark_ReviewPlanGeneration + - ReviewMark_ReviewReportGeneration diff --git a/docs/reqstream/ots/sarifmark.yaml b/docs/reqstream/ots/sarifmark.yaml new file mode 100644 index 0000000..c1da086 --- /dev/null +++ b/docs/reqstream/ots/sarifmark.yaml @@ -0,0 +1,21 @@ +--- +# SarifMark OTS Software Requirements +# +# Requirements for the SarifMark SARIF report processing tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: SarifMark Requirements + requirements: + - id: SonarMark-OTS-SarifMark + title: SarifMark shall convert CodeQL SARIF results into a markdown report. + justification: | + DemaConsulting.SarifMark reads the SARIF output produced by CodeQL code scanning and + renders it as a human-readable markdown document included in the release artifacts. + It runs in the same CI pipeline that produces the TRX test results, so a successful + pipeline run is evidence that SarifMark executed without error. + tags: [ots] + tests: + - SarifMark_SarifReading + - SarifMark_MarkdownReportGeneration diff --git a/docs/reqstream/ots/versionmark.yaml b/docs/reqstream/ots/versionmark.yaml new file mode 100644 index 0000000..97da43e --- /dev/null +++ b/docs/reqstream/ots/versionmark.yaml @@ -0,0 +1,21 @@ +--- +# VersionMark OTS Software Requirements +# +# Requirements for the VersionMark version tracking tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: VersionMark Requirements + requirements: + - id: SonarMark-OTS-VersionMark + title: VersionMark shall publish captured tool-version information. + justification: | + DemaConsulting.VersionMark reads version metadata for each dotnet tool used in the + pipeline and writes a versions markdown document included in the release artifacts. + It runs in the same CI pipeline that produces the TRX test results, so a successful + pipeline run is evidence that VersionMark executed without error. + tags: [ots] + tests: + - VersionMark_CapturesVersions + - VersionMark_GeneratesMarkdownReport diff --git a/docs/reqstream/ots/weasyprint.yaml b/docs/reqstream/ots/weasyprint.yaml new file mode 100644 index 0000000..5e1007f --- /dev/null +++ b/docs/reqstream/ots/weasyprint.yaml @@ -0,0 +1,26 @@ +--- +# WeasyPrint OTS Software Requirements +# +# Requirements for the WeasyPrint PDF generation tool functionality. + +sections: + - title: OTS Software Requirements + sections: + - title: WeasyPrint Requirements + requirements: + - id: SonarMark-OTS-WeasyPrint + title: WeasyPrint shall convert HTML documents to valid PDF. + justification: | + DemaConsulting.WeasyPrintTool converts HTML documents to PDF as part of the + documentation build pipeline. FileAssert validates that each generated PDF file + exists, has a non-trivial size, contains at least one page, and includes expected + document content in the rendered text. Passing FileAssert assertions for each + document type proves WeasyPrint executed correctly and produced meaningful output. + tags: [ots] + tests: + - WeasyPrint_BuildNotesPdf + - WeasyPrint_CodeQualityPdf + - WeasyPrint_ReviewPlanPdf + - WeasyPrint_ReviewReportPdf + - WeasyPrint_DesignPdf + - WeasyPrint_UserGuidePdf diff --git a/docs/reqstream/sonar-mark/cli/cli.yaml b/docs/reqstream/sonar-mark/cli/cli.yaml index 07e0aa9..1eb8f58 100644 --- a/docs/reqstream/sonar-mark/cli/cli.yaml +++ b/docs/reqstream/sonar-mark/cli/cli.yaml @@ -29,6 +29,8 @@ sections: - SonarMark-Report-Markdown - SonarMark-Report-Depth - SonarMark-Context-Depth + - SonarMark-Context-ResultsFile + - SonarMark-Context-ResultAlias - SonarMark-Enforce-ExitCode tests: - Cli_VersionDispatch_OutputsVersionString diff --git a/docs/reqstream/sonar-mark/report-generation/sonar-quality-result.yaml b/docs/reqstream/sonar-mark/report-generation/sonar-quality-result.yaml index 81400b5..40cb2e4 100644 --- a/docs/reqstream/sonar-mark/report-generation/sonar-quality-result.yaml +++ b/docs/reqstream/sonar-mark/report-generation/sonar-quality-result.yaml @@ -41,3 +41,13 @@ sections: attention and helps teams maintain secure coding practices. tests: - SonarQualityResult_ToMarkdown_WithHotSpots_ProducesCompilerStyleOutput + + - id: SonarMark-Report-DepthValidation + title: The tool shall throw ArgumentOutOfRangeException when report depth is outside the range 1 to 6. + justification: | + Markdown supports heading levels 1 through 6 only. Accepting values outside this range would + produce malformed markdown output. Validating depth at the method boundary provides a clear + contract violation signal to callers instead of silently generating invalid content. + tests: + - SonarQualityResult_ToMarkdown_DepthLessThan1_ThrowsArgumentOutOfRangeException + - SonarQualityResult_ToMarkdown_DepthGreaterThan6_ThrowsArgumentOutOfRangeException diff --git a/docs/reqstream/sonar-mark/sonar-integration/sonar-qube-client.yaml b/docs/reqstream/sonar-mark/sonar-integration/sonar-qube-client.yaml index 28d0469..0877068 100644 --- a/docs/reqstream/sonar-mark/sonar-integration/sonar-qube-client.yaml +++ b/docs/reqstream/sonar-mark/sonar-integration/sonar-qube-client.yaml @@ -35,3 +35,21 @@ sections: and meeting security compliance requirements. tests: - SonarQubeClient_GetQualityResultByBranchAsync_HotSpotsPaginatedAcrossTwoPages_AccumulatesAllHotSpots + + - id: SonarMark-Server-ProjectName + title: The tool shall retrieve the project name from SonarQube/SonarCloud. + justification: | + Using the server-side project name in the report header makes reports immediately identifiable + without requiring callers to supply display names separately. The API call to + /api/components/show provides the canonical name configured in the SonarQube/SonarCloud project. + tests: + - SonarQubeClient_GetQualityResultByBranchAsync_ReturnsQualityGateStatus + + - id: SonarMark-Server-MetricNames + title: The tool shall retrieve human-readable metric names from SonarQube/SonarCloud. + justification: | + Metric keys returned by the quality gate API (e.g., new_coverage) are internal identifiers + not suitable for display. Fetching the metric name dictionary from /api/metrics/search allows + the report to show friendly labels (e.g., Coverage on New Code) without hardcoding a mapping. + tests: + - SonarQubeClient_GetQualityResultByBranchAsync_ReturnsQualityGateStatus diff --git a/docs/reqstream/sonar-mark/sonar-mark.yaml b/docs/reqstream/sonar-mark/sonar-mark.yaml index af654f1..03070fb 100644 --- a/docs/reqstream/sonar-mark/sonar-mark.yaml +++ b/docs/reqstream/sonar-mark/sonar-mark.yaml @@ -62,3 +62,28 @@ sections: - SonarMark-Subsystem-ReportGeneration tests: - SonarMark_MarkdownReportGeneration + + - id: SonarMark-System-Validation + title: The system shall run self-validation tests and report results when --validate is supplied. + justification: | + Self-validation mode lets users verify that SonarMark is functioning correctly without + requiring a live SonarQube/SonarCloud server. Verifying this end-to-end confirms that the + CLI dispatch, self-test runner, and result reporting all integrate correctly and that the + shipped binary is fully testable in isolated environments. + children: + - SonarMark-Subsystem-SelfTest + tests: + - IntegrationTest_ValidateFlag_OutputsHeaderAndSummary + + - id: SonarMark-System-Enforce + title: The system shall return a non-zero exit code when --enforce is supplied and the quality gate fails. + justification: | + Enforcement mode allows SonarMark to act as a build quality gate in CI/CD pipelines, + failing the build automatically when the Sonar quality gate status is not passing. Verifying + this end-to-end confirms that the --enforce flag is correctly parsed, propagated to the + report generation layer, and results in an appropriate process exit code. + children: + - SonarMark-Subsystem-Cli + - SonarMark-Subsystem-ReportGeneration + tests: + - IntegrationTest_EnforceFlag_IsAccepted diff --git a/docs/user_guide/introduction.md b/docs/user_guide/introduction.md index 0b49e35..5f3c2fa 100644 --- a/docs/user_guide/introduction.md +++ b/docs/user_guide/introduction.md @@ -258,7 +258,7 @@ sonarmark --server https://sonarcloud.io \ --enforce ``` -## Self-Validation +## Validation Options ### `--validate` diff --git a/fix.ps1 b/fix.ps1 new file mode 100644 index 0000000..6369087 --- /dev/null +++ b/fix.ps1 @@ -0,0 +1,111 @@ +# fix.ps1 +# +# PURPOSE: +# Applies all available auto-fixers with progress output. Always exits 0. +# Run this after making changes to automatically handle formatting +# so agents and developers do not need to respond to lint output. +# Handles: dotnet format, markdownlint, yamlfix, YAML line endings. +# +# EXTENSION POINTS: +# Search for "[PROJECT-SPECIFIC]" comments to find the designated locations +# for adding project-specific auto-fix operations. +# +# MODIFICATION POLICY: +# Only modify this file to add project-specific operations at the designated +# [PROJECT-SPECIFIC] extension points, or to update tool versions as needed. + +# ============================================================================== +# HELPER FUNCTIONS +# ============================================================================== + +function Get-VenvActivateScript { + if (Test-Path ".venv/Scripts/Activate.ps1") { return ".venv/Scripts/Activate.ps1" } # Windows + if (Test-Path ".venv/bin/Activate.ps1") { return ".venv/bin/Activate.ps1" } # Linux/macOS + return $null +} + +function Initialize-PythonVenv { + param([switch]$Silent) + + if (-not (Test-Path ".venv")) { + if ($Silent) { python -m venv .venv 2>$null } else { python -m venv .venv } + if ($LASTEXITCODE -ne 0) { return $false } + } + + $activateScript = Get-VenvActivateScript + if (-not $activateScript) { return $false } + if ($Silent) { & $activateScript 2>$null } else { & $activateScript } + if (-not (Get-Command deactivate -ErrorAction SilentlyContinue)) { return $false } + + $installSucceeded = $false + try { + if ($Silent) { + pip install -r pip-requirements.txt --quiet --disable-pip-version-check 2>$null + } else { + pip install -r pip-requirements.txt --quiet --disable-pip-version-check + } + $installSucceeded = $LASTEXITCODE -eq 0 + return $installSucceeded + } + finally { + if (-not $installSucceeded -and (Get-Command deactivate -ErrorAction SilentlyContinue)) { + deactivate 2>$null + } + } +} + +function Normalize-YamlLineEndings { + $utf8NoBom = New-Object System.Text.UTF8Encoding($false) + + Get-ChildItem -Recurse -Include "*.yaml", "*.yml" | + Where-Object { $_.FullName -notmatch '[/\\](\.git|node_modules|\.venv|thirdparty|third-party|3rd-party|\.agent-logs)[/\\]' } | + ForEach-Object { + $raw = [System.IO.File]::ReadAllText($_.FullName) + $fixed = $raw.Replace("`r`n", "`n") + if ($raw -ne $fixed) { + [System.IO.File]::WriteAllText($_.FullName, $fixed, $utf8NoBom) + } + } +} + +# ============================================================================== +# AUTO-FIX +# Applies all auto-fixers with progress output. Never fails — applies what it can and +# exits 0 so agents do not react to any output as a problem to solve. +# ============================================================================== + +# --- YAML Auto-Fix --- +Write-Host "Fixing: YAML..." +if (Initialize-PythonVenv -Silent) { + yamlfix . 2>$null + deactivate 2>$null +} +Normalize-YamlLineEndings + +# --- Markdown Auto-Fix --- +Write-Host "Fixing: markdown..." +$env:PUPPETEER_SKIP_DOWNLOAD = "true" +npm install --silent 2>$null +if ($LASTEXITCODE -eq 0) { + npx markdownlint-cli2 --fix "**/*.md" 2>$null +} + +# [PROJECT-SPECIFIC] Add additional auto-fixers here. +# Example (Prettier for TypeScript/JSON): +# npx prettier --write "src/**/*.{ts,json}" 2>$null + +# --- .NET Auto-Format --- +Write-Host "Fixing: dotnet format..." +$slnFiles = @(Get-ChildItem -Filter "*.sln" -ErrorAction SilentlyContinue) + + @(Get-ChildItem -Filter "*.slnx" -ErrorAction SilentlyContinue) +if ($slnFiles.Count -gt 0) { + dotnet format 2>$null +} + +# [PROJECT-SPECIFIC] Add additional language-specific auto-formatters here. +# Example (C/C++ with clang-format): +# Get-ChildItem -Recurse -Include "*.cpp","*.hpp","*.h" | +# ForEach-Object { clang-format -i $_.FullName } 2>$null + +Write-Host "Auto-fix complete." +exit 0 diff --git a/lint.bat b/lint.bat deleted file mode 100644 index f373b99..0000000 --- a/lint.bat +++ /dev/null @@ -1,100 +0,0 @@ -@echo off -setlocal - -REM Comprehensive Linting Script -REM -REM PURPOSE: -REM - Run ALL lint checks when executed (no options or modes) -REM - Output lint failures directly for agent parsing -REM - NO command-line arguments, pretty printing, or colorization -REM - Agents execute this script to identify files needing fixes - -set "LINT_ERROR=0" - -REM === PYTHON SECTION === - -REM Create python venv if necessary -if not exist ".venv\Scripts\activate.bat" python -m venv .venv -if errorlevel 1 goto abort_python - -REM Activate python venv -call .venv\Scripts\activate.bat -if errorlevel 1 goto abort_python - -REM Install python tools -pip install -r pip-requirements.txt --quiet --disable-pip-version-check -if errorlevel 1 goto abort_python - -REM Run yamllint -yamllint . -if errorlevel 1 set "LINT_ERROR=1" - -REM Section error handling -goto npm_section -:abort_python -set "LINT_ERROR=1" -:npm_section - -REM === NPM SECTION === - -REM Install npm dependencies -set "PUPPETEER_SKIP_DOWNLOAD=true" -call npm install --silent -if errorlevel 1 goto abort_npm - -REM Run cspell -call npx cspell --no-progress --no-color --quiet "**/*.{md,yaml,yml,json,cs,cpp,hpp,h,txt}" -if errorlevel 1 set "LINT_ERROR=1" - -REM Run markdownlint-cli2 -call npx markdownlint-cli2 "**/*.md" -if errorlevel 1 set "LINT_ERROR=1" - -REM Section error handling -goto dotnet_linting_section -:abort_npm -set "LINT_ERROR=1" -:dotnet_linting_section - -REM === DOTNET LINTING SECTION === - -REM Restore dotnet tools -dotnet tool restore > nul -if errorlevel 1 goto abort_dotnet_tools - -REM Run reqstream lint -dotnet reqstream --lint --requirements requirements.yaml -if errorlevel 1 set "LINT_ERROR=1" - -REM Run versionmark lint -dotnet versionmark --lint -if errorlevel 1 set "LINT_ERROR=1" - -REM Run reviewmark lint -dotnet reviewmark --lint -if errorlevel 1 set "LINT_ERROR=1" - -REM Section error handling -goto dotnet_format_section -:abort_dotnet_tools -set "LINT_ERROR=1" -:dotnet_format_section - -REM === DOTNET FORMATTING SECTION === - -REM Restore dotnet packages -dotnet restore > nul -if errorlevel 1 goto abort_dotnet_format - -REM Run dotnet format -dotnet format --verify-no-changes --no-restore -if errorlevel 1 set "LINT_ERROR=1" - -REM Section error handling -goto end -:abort_dotnet_format -set "LINT_ERROR=1" -:end - -REM Report result -exit /b %LINT_ERROR% diff --git a/lint.ps1 b/lint.ps1 new file mode 100644 index 0000000..e4d68ac --- /dev/null +++ b/lint.ps1 @@ -0,0 +1,145 @@ +# lint.ps1 +# +# PURPOSE: +# Runs all lint checks and reports failures. Exits 1 on error. +# Used by CI/CD as the merge gate and by the lint-fix agent +# during pre-PR cleanup. +# +# To auto-fix formatting issues, run fix.ps1 instead. +# +# EXTENSION POINTS: +# Search for "[PROJECT-SPECIFIC]" comments to find the designated locations +# for adding project-specific lint checks. +# +# MODIFICATION POLICY: +# Only modify this file to add project-specific operations at the designated +# [PROJECT-SPECIFIC] extension points, or to update tool versions as needed. + +# ============================================================================== +# HELPER FUNCTIONS +# ============================================================================== + +function Get-VenvActivateScript { + if (Test-Path ".venv/Scripts/Activate.ps1") { return ".venv/Scripts/Activate.ps1" } # Windows + if (Test-Path ".venv/bin/Activate.ps1") { return ".venv/bin/Activate.ps1" } # Linux/macOS + return $null +} + +function Initialize-PythonVenv { + if (-not (Test-Path ".venv")) { + python -m venv .venv + if ($LASTEXITCODE -ne 0) { return $false } + } + + $activateScript = Get-VenvActivateScript + if (-not $activateScript) { return $false } + & $activateScript + if (-not (Get-Command deactivate -ErrorAction SilentlyContinue)) { return $false } + + $installSucceeded = $false + try { + pip install -r pip-requirements.txt --quiet --disable-pip-version-check + $installSucceeded = $LASTEXITCODE -eq 0 + return $installSucceeded + } + finally { + if (-not $installSucceeded -and (Get-Command deactivate -ErrorAction SilentlyContinue)) { + deactivate 2>$null + } + } +} + +# ============================================================================== +# LINT CHECKS +# Runs all lint checks. Exits 1 if any check fails. +# ============================================================================== + +$lintError = $false + +# --- PYTHON SECTION --- +# Sets up a virtual environment and runs yamllint. +Write-Host "Linting: YAML..." +$skipPython = -not (Initialize-PythonVenv) +if ($skipPython) { $lintError = $true } + +if (-not $skipPython) { + yamllint . + if ($LASTEXITCODE -ne 0) { $lintError = $true } + deactivate +} + +# [PROJECT-SPECIFIC] Add additional Python-based lint checks here. +# Example: +# if (-not $skipPython) { +# flake8 src/ +# if ($LASTEXITCODE -ne 0) { $lintError = $true } +# } + +# --- NPM SECTION --- +# Installs npm dependencies and runs cspell and markdownlint-cli2. +Write-Host "Linting: spelling and markdown..." +$skipNpm = $false +$env:PUPPETEER_SKIP_DOWNLOAD = "true" +npm install --silent +if ($LASTEXITCODE -ne 0) { $lintError = $true; $skipNpm = $true } + +if (-not $skipNpm) { + npx cspell --no-progress --no-color --quiet "**/*.{md,yaml,yml,json,cs,cpp,hpp,h,txt}" + if ($LASTEXITCODE -ne 0) { $lintError = $true } + + npx markdownlint-cli2 "**/*.md" + if ($LASTEXITCODE -ne 0) { $lintError = $true } +} + +# [PROJECT-SPECIFIC] Add additional npm-based lint checks here. +# Example (ESLint for TypeScript): +# if (-not $skipNpm) { +# npx eslint "src/**/*.ts" +# if ($LASTEXITCODE -ne 0) { $lintError = $true } +# } + +# --- DOTNET LINTING SECTION --- +# Runs compliance tools: reqstream, versionmark, reviewmark. +Write-Host "Linting: compliance tools..." +$skipDotnetTools = $false +dotnet tool restore > $null +if ($LASTEXITCODE -ne 0) { $lintError = $true; $skipDotnetTools = $true } + +if (-not $skipDotnetTools) { + dotnet reqstream --lint --requirements requirements.yaml + if ($LASTEXITCODE -ne 0) { $lintError = $true } + + dotnet versionmark --lint + if ($LASTEXITCODE -ne 0) { $lintError = $true } + + dotnet reviewmark --lint + if ($LASTEXITCODE -ne 0) { $lintError = $true } +} + +# [PROJECT-SPECIFIC] Add additional dotnet tool lint checks here. +# Example: +# if (-not $skipDotnetTools) { +# dotnet custom-tool --lint +# if ($LASTEXITCODE -ne 0) { $lintError = $true } +# } + +# --- DOTNET FORMATTING SECTION --- +# Verifies C# code formatting matches .editorconfig rules. +Write-Host "Linting: dotnet format..." +$skipDotnetFormat = $false +dotnet restore > $null +if ($LASTEXITCODE -ne 0) { $lintError = $true; $skipDotnetFormat = $true } + +if (-not $skipDotnetFormat) { + dotnet format --verify-no-changes --no-restore + if ($LASTEXITCODE -ne 0) { $lintError = $true } +} + +# [PROJECT-SPECIFIC] Add additional format verification checks here. +# Example (clang-format check for C/C++): +# Get-ChildItem -Recurse -Include "*.cpp","*.hpp","*.h" | ForEach-Object { +# $result = clang-format --dry-run --Werror $_.FullName 2>&1 +# if ($LASTEXITCODE -ne 0) { Write-Output $result; $lintError = $true } +# } + +exit ($lintError ? 1 : 0) diff --git a/lint.sh b/lint.sh deleted file mode 100755 index 4588497..0000000 --- a/lint.sh +++ /dev/null @@ -1,82 +0,0 @@ -#!/bin/bash - -# Comprehensive Linting Script -# -# PURPOSE: -# - Run ALL lint checks when executed (no options or modes) -# - Output lint failures directly for agent parsing -# - NO command-line arguments, pretty printing, or colorization -# - Agents execute this script to identify files needing fixes - -lint_error=0 - -# === PYTHON SECTION === - -# Create python venv if necessary -if [ ! -d ".venv" ]; then - python -m venv .venv || { lint_error=1; skip_python=1; } -fi - -# Activate python venv -if [ "$skip_python" != "1" ]; then - source .venv/bin/activate || { lint_error=1; skip_python=1; } -fi - -# Install python tools -if [ "$skip_python" != "1" ]; then - pip install -r pip-requirements.txt --quiet --disable-pip-version-check || { lint_error=1; skip_python=1; } -fi - -# Run yamllint -if [ "$skip_python" != "1" ]; then - yamllint . || lint_error=1 -fi - -# === NPM SECTION === - -# Install npm dependencies -export PUPPETEER_SKIP_DOWNLOAD=true -npm install --silent || { lint_error=1; skip_npm=1; } - -# Run cspell -if [ "$skip_npm" != "1" ]; then - npx cspell --no-progress --no-color --quiet "**/*.{md,yaml,yml,json,cs,cpp,hpp,h,txt}" || lint_error=1 -fi - -# Run markdownlint-cli2 -if [ "$skip_npm" != "1" ]; then - npx markdownlint-cli2 "**/*.md" || lint_error=1 -fi - -# === DOTNET LINTING SECTION === - -# Restore dotnet tools -dotnet tool restore > /dev/null || { lint_error=1; skip_dotnet_tools=1; } - -# Run reqstream lint -if [ "$skip_dotnet_tools" != "1" ]; then - dotnet reqstream --lint --requirements requirements.yaml || lint_error=1 -fi - -# Run versionmark lint -if [ "$skip_dotnet_tools" != "1" ]; then - dotnet versionmark --lint || lint_error=1 -fi - -# Run reviewmark lint -if [ "$skip_dotnet_tools" != "1" ]; then - dotnet reviewmark --lint || lint_error=1 -fi - -# === DOTNET FORMATTING SECTION === - -# Restore dotnet packages -dotnet restore > /dev/null || { lint_error=1; skip_dotnet_format=1; } - -# Run dotnet format -if [ "$skip_dotnet_format" != "1" ]; then - dotnet format --verify-no-changes --no-restore || lint_error=1 -fi - -# Report result -exit $lint_error diff --git a/pip-requirements.txt b/pip-requirements.txt index 7ce0eab..8fb8a08 100644 --- a/pip-requirements.txt +++ b/pip-requirements.txt @@ -1 +1,2 @@ yamllint==1.38.0 +yamlfix==1.19.1 diff --git a/requirements.yaml b/requirements.yaml index b8b63f8..fde2e2f 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -35,8 +35,12 @@ includes: # Platform support requirements - docs/reqstream/sonar-mark/platform-requirements.yaml # OTS software requirements (one per component) - - docs/reqstream/ots/ots-mstest.yaml - - docs/reqstream/ots/ots-reqstream.yaml - - docs/reqstream/ots/ots-buildmark.yaml - - docs/reqstream/ots/ots-versionmark.yaml - - docs/reqstream/ots/ots-sarifmark.yaml + - docs/reqstream/ots/mstest.yaml + - docs/reqstream/ots/reqstream.yaml + - docs/reqstream/ots/buildmark.yaml + - docs/reqstream/ots/versionmark.yaml + - docs/reqstream/ots/sarifmark.yaml + - docs/reqstream/ots/reviewmark.yaml + - docs/reqstream/ots/pandoc.yaml + - docs/reqstream/ots/weasyprint.yaml + - docs/reqstream/ots/fileassert.yaml diff --git a/test/DemaConsulting.SonarMark.Tests/Cli/CliTests.cs b/test/DemaConsulting.SonarMark.Tests/Cli/CliTests.cs index 7db7b42..98d7f1e 100644 --- a/test/DemaConsulting.SonarMark.Tests/Cli/CliTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/Cli/CliTests.cs @@ -101,9 +101,9 @@ public void Cli_SilentMode_SuppressesOutput() using var context = Context.Create(["--silent"]); Program.Run(context); - // Assert - silent mode must suppress banner/version output + // Assert - silent mode must suppress all standard output var outputText = output.ToString(); - Assert.DoesNotContain("SonarMark version", outputText); + Assert.IsTrue(string.IsNullOrWhiteSpace(outputText)); } finally { @@ -112,16 +112,20 @@ public void Cli_SilentMode_SuppressesOutput() } /// - /// Test that --enforce is parsed and made available through the CLI subsystem. + /// Test that --enforce is parsed and the flag is exposed through the CLI subsystem after dispatch. /// [TestMethod] public void Cli_EnforceMode_SetsEnforceFlag() { - // Arrange - create context with --enforce (and required --server so we do not fail before enforce check) - // We expect an error about missing --project-key, but Enforce must be true by the time Context is created + // Arrange - create context with --enforce and --server so dispatch reaches the project-key check using var context = Context.Create(["--enforce", "--server", "https://mock.example.com"]); - // Assert - the Enforce flag must be set to true after CLI argument parsing + // Act - run through Program dispatch; we expect an error about missing --project-key, + // but Enforce must be true on the Context that was dispatched + Program.Run(context); + + // Assert - the Enforce flag must be set to true and dispatch must have been attempted Assert.IsTrue(context.Enforce); + Assert.AreEqual(1, context.ExitCode); } } diff --git a/test/DemaConsulting.SonarMark.Tests/Cli/ContextTests.cs b/test/DemaConsulting.SonarMark.Tests/Cli/ContextTests.cs index bc55315..42d16b3 100644 --- a/test/DemaConsulting.SonarMark.Tests/Cli/ContextTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/Cli/ContextTests.cs @@ -60,8 +60,10 @@ public void TestCleanup() [TestMethod] public void Context_Create_NoArguments_ReturnsDefaultContext() { + // Act using var context = Context.Create([]); + // Assert Assert.IsFalse(context.Version); Assert.IsFalse(context.Help); Assert.IsFalse(context.Silent); @@ -81,6 +83,7 @@ public void Context_Create_NoArguments_ReturnsDefaultContext() [TestMethod] public void Context_Create_VersionFlag_SetsVersionProperty() { + // Act/Assert using var context1 = Context.Create(["-v"]); Assert.IsTrue(context1.Version); Assert.AreEqual(0, context1.ExitCode); @@ -96,6 +99,7 @@ public void Context_Create_VersionFlag_SetsVersionProperty() [TestMethod] public void Context_Create_HelpFlags_SetsHelpProperty() { + // Act/Assert using var context1 = Context.Create(["-?"]); Assert.IsTrue(context1.Help); Assert.AreEqual(0, context1.ExitCode); @@ -115,8 +119,10 @@ public void Context_Create_HelpFlags_SetsHelpProperty() [TestMethod] public void Context_Create_SilentFlag_SetsSilentProperty() { + // Act using var context = Context.Create(["--silent"]); + // Assert Assert.IsTrue(context.Silent); Assert.AreEqual(0, context.ExitCode); } @@ -127,8 +133,10 @@ public void Context_Create_SilentFlag_SetsSilentProperty() [TestMethod] public void Context_Create_ValidateFlag_SetsValidateProperty() { + // Act using var context = Context.Create(["--validate"]); + // Assert Assert.IsTrue(context.Validate); Assert.AreEqual(0, context.ExitCode); } @@ -139,8 +147,10 @@ public void Context_Create_ValidateFlag_SetsValidateProperty() [TestMethod] public void Context_Create_EnforceFlag_SetsEnforceProperty() { + // Act using var context = Context.Create(["--enforce"]); + // Assert Assert.IsTrue(context.Enforce); Assert.AreEqual(0, context.ExitCode); } @@ -151,8 +161,10 @@ public void Context_Create_EnforceFlag_SetsEnforceProperty() [TestMethod] public void Context_Create_ReportFile_SetsReportProperty() { + // Act using var context = Context.Create(["--report", "report.md"]); + // Assert Assert.AreEqual("report.md", context.ReportFile); Assert.AreEqual(0, context.ExitCode); } @@ -163,6 +175,7 @@ public void Context_Create_ReportFile_SetsReportProperty() [TestMethod] public void Context_Create_MissingReportFilename_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--report"])); Assert.Contains("--report requires a filename argument", ex.Message); } @@ -173,8 +186,10 @@ public void Context_Create_MissingReportFilename_ThrowsException() [TestMethod] public void Context_Create_ReportDepthAlias_SetsDepthProperty() { + // Act using var context = Context.Create(["--report-depth", "3"]); + // Assert Assert.AreEqual(3, context.Depth); Assert.AreEqual(0, context.ExitCode); } @@ -185,6 +200,7 @@ public void Context_Create_ReportDepthAlias_SetsDepthProperty() [TestMethod] public void Context_Create_MissingReportDepth_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--report-depth"])); Assert.Contains("--report-depth requires a depth argument", ex.Message); } @@ -195,6 +211,7 @@ public void Context_Create_MissingReportDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidReportDepth_ThrowsException() { + // Act/Assert var ex1 = Assert.ThrowsExactly(() => Context.Create(["--report-depth", "invalid"])); Assert.Contains("--report-depth requires a depth between 1 and 6", ex1.Message); @@ -214,8 +231,10 @@ public void Context_Create_InvalidReportDepth_ThrowsException() [TestMethod] public void Context_Create_Depth_SetsDepthProperty() { + // Act using var context = Context.Create(["--depth", "3"]); + // Assert Assert.AreEqual(3, context.Depth); Assert.AreEqual(0, context.ExitCode); } @@ -226,6 +245,7 @@ public void Context_Create_Depth_SetsDepthProperty() [TestMethod] public void Context_Create_MissingDepth_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--depth"])); Assert.Contains("--depth requires a depth argument", ex.Message); } @@ -236,6 +256,7 @@ public void Context_Create_MissingDepth_ThrowsException() [TestMethod] public void Context_Create_InvalidDepth_ThrowsException() { + // Act/Assert var ex1 = Assert.ThrowsExactly(() => Context.Create(["--depth", "invalid"])); Assert.Contains("--depth requires a depth between 1 and 6", ex1.Message); @@ -255,8 +276,10 @@ public void Context_Create_InvalidDepth_ThrowsException() [TestMethod] public void Context_Create_ReportDepthAlias_StillWorks() { + // Act using var context = Context.Create(["--report-depth", "2"]); + // Assert Assert.AreEqual(2, context.Depth); Assert.AreEqual(0, context.ExitCode); } @@ -267,8 +290,10 @@ public void Context_Create_ReportDepthAlias_StillWorks() [TestMethod] public void Context_Create_Token_SetsTokenProperty() { + // Act using var context = Context.Create(["--token", "test-token-123"]); + // Assert Assert.AreEqual("test-token-123", context.Token); Assert.AreEqual(0, context.ExitCode); } @@ -279,6 +304,7 @@ public void Context_Create_Token_SetsTokenProperty() [TestMethod] public void Context_Create_MissingToken_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--token"])); Assert.Contains("--token requires a token argument", ex.Message); } @@ -289,8 +315,10 @@ public void Context_Create_MissingToken_ThrowsException() [TestMethod] public void Context_Create_Server_SetsServerProperty() { + // Act using var context = Context.Create(["--server", "https://sonarcloud.io"]); + // Assert Assert.AreEqual("https://sonarcloud.io", context.Server); Assert.AreEqual(0, context.ExitCode); } @@ -301,6 +329,7 @@ public void Context_Create_Server_SetsServerProperty() [TestMethod] public void Context_Create_MissingServer_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--server"])); Assert.Contains("--server requires a server URL argument", ex.Message); } @@ -311,8 +340,10 @@ public void Context_Create_MissingServer_ThrowsException() [TestMethod] public void Context_Create_ProjectKey_SetsProjectKeyProperty() { + // Act using var context = Context.Create(["--project-key", "my-project"]); + // Assert Assert.AreEqual("my-project", context.ProjectKey); Assert.AreEqual(0, context.ExitCode); } @@ -323,6 +354,7 @@ public void Context_Create_ProjectKey_SetsProjectKeyProperty() [TestMethod] public void Context_Create_MissingProjectKey_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--project-key"])); Assert.Contains("--project-key requires a project key argument", ex.Message); } @@ -333,8 +365,10 @@ public void Context_Create_MissingProjectKey_ThrowsException() [TestMethod] public void Context_Create_Branch_SetsBranchProperty() { + // Act using var context = Context.Create(["--branch", "main"]); + // Assert Assert.AreEqual("main", context.Branch); Assert.AreEqual(0, context.ExitCode); } @@ -345,6 +379,7 @@ public void Context_Create_Branch_SetsBranchProperty() [TestMethod] public void Context_Create_MissingBranch_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--branch"])); Assert.Contains("--branch requires a branch name argument", ex.Message); } @@ -355,6 +390,7 @@ public void Context_Create_MissingBranch_ThrowsException() [TestMethod] public void Context_Create_MissingLogFilename_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--log"])); Assert.Contains("--log requires a filename argument", ex.Message); } @@ -365,6 +401,7 @@ public void Context_Create_MissingLogFilename_ThrowsException() [TestMethod] public void Context_Create_UnsupportedArgument_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--unsupported"])); Assert.Contains("Unsupported argument '--unsupported'", ex.Message); } @@ -375,15 +412,18 @@ public void Context_Create_UnsupportedArgument_ThrowsException() [TestMethod] public void Context_WriteLine_NormalMode_WritesToConsole() { + // Arrange var originalOut = Console.Out; using var output = new StringWriter(); Console.SetOut(output); try { + // Act using var context = Context.Create([]); context.WriteLine("Test message"); + // Assert Assert.AreEqual("Test message" + Environment.NewLine, output.ToString()); } finally @@ -398,15 +438,18 @@ public void Context_WriteLine_NormalMode_WritesToConsole() [TestMethod] public void Context_WriteLine_SilentMode_DoesNotWriteToConsole() { + // Arrange var originalOut = Console.Out; using var output = new StringWriter(); Console.SetOut(output); try { + // Act using var context = Context.Create(["--silent"]); context.WriteLine("Test message"); + // Assert Assert.AreEqual(string.Empty, output.ToString()); } finally @@ -421,15 +464,18 @@ public void Context_WriteLine_SilentMode_DoesNotWriteToConsole() [TestMethod] public void Context_WriteError_NormalMode_WritesToConsole() { + // Arrange var originalError = Console.Error; using var error = new StringWriter(); Console.SetError(error); try { + // Act using var context = Context.Create([]); context.WriteError("Error message"); + // Assert Assert.AreEqual("Error message" + Environment.NewLine, error.ToString()); Assert.AreEqual(1, context.ExitCode); } @@ -445,15 +491,18 @@ public void Context_WriteError_NormalMode_WritesToConsole() [TestMethod] public void Context_WriteError_SilentMode_DoesNotWriteToConsole() { + // Arrange var originalOut = Console.Out; using var output = new StringWriter(); Console.SetOut(output); try { + // Act using var context = Context.Create(["--silent"]); context.WriteError("Error message"); + // Assert Assert.AreEqual(string.Empty, output.ToString()); Assert.AreEqual(1, context.ExitCode); } @@ -469,14 +518,17 @@ public void Context_WriteError_SilentMode_DoesNotWriteToConsole() [TestMethod] public void Context_Create_WithLogFile_WritesToLogFile() { + // Arrange var logPath = Path.Combine(_testDirectory, "test.log"); + // Act using (var context = Context.Create(["--log", logPath, "--silent"])) { context.WriteLine("Normal message"); context.WriteError("Error message"); } + // Assert Assert.IsTrue(File.Exists(logPath)); var logContent = File.ReadAllText(logPath); Assert.Contains("Normal message", logContent); @@ -489,9 +541,11 @@ public void Context_Create_WithLogFile_WritesToLogFile() [TestMethod] public void Context_Create_InvalidLogFilePath_ThrowsException() { + // Arrange // Use an invalid path that will fail to create var invalidPath = Path.Combine("/invalid/directory/that/does/not/exist", "test.log"); + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--log", invalidPath])); Assert.Contains("Failed to open log file", ex.Message); } @@ -502,8 +556,10 @@ public void Context_Create_InvalidLogFilePath_ThrowsException() [TestMethod] public void Context_Create_ResultsFile_SetsResultsProperty() { + // Act using var context = Context.Create(["--results", "results.trx"]); + // Assert Assert.AreEqual("results.trx", context.ResultsFile); Assert.AreEqual(0, context.ExitCode); } @@ -514,6 +570,7 @@ public void Context_Create_ResultsFile_SetsResultsProperty() [TestMethod] public void Context_Create_MissingResultsFilename_ThrowsException() { + // Act/Assert var ex = Assert.ThrowsExactly(() => Context.Create(["--results"])); Assert.Contains("--results requires a results filename argument", ex.Message); } diff --git a/test/DemaConsulting.SonarMark.Tests/ReportGeneration/ReportGenerationTests.cs b/test/DemaConsulting.SonarMark.Tests/ReportGeneration/ReportGenerationTests.cs index d90dcc0..df54d2f 100644 --- a/test/DemaConsulting.SonarMark.Tests/ReportGeneration/ReportGenerationTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/ReportGeneration/ReportGenerationTests.cs @@ -128,9 +128,10 @@ public void ReportGeneration_HotSpotsReport_IncludesPriorityAndCategory() // Act - render the subsystem output as markdown var markdown = result.ToMarkdown(1); - // Assert - hot-spot vulnerability probability and category must appear in the rendered report + // Assert - hot-spot vulnerability probability, category, and security category must appear in the rendered report Assert.IsNotNull(markdown); Assert.Contains("Review this security hot-spot", markdown); Assert.Contains("HIGH", markdown); + Assert.Contains("xss", markdown); } } diff --git a/test/DemaConsulting.SonarMark.Tests/ReportGeneration/SonarQualityResultTests.cs b/test/DemaConsulting.SonarMark.Tests/ReportGeneration/SonarQualityResultTests.cs index 6e9fafd..a432b05 100644 --- a/test/DemaConsulting.SonarMark.Tests/ReportGeneration/SonarQualityResultTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/ReportGeneration/SonarQualityResultTests.cs @@ -517,6 +517,35 @@ public void SonarQualityResult_ToMarkdown_WithMultipleHotSpots_IncludesBlankLine Assert.Contains($"src/Secure3.cs(30): LOW [xss] Third hot-spot {Environment.NewLine}", markdown); } + /// + /// Test CleanComponent fall-through path where component has no project key prefix + /// + [TestMethod] + public void SonarQualityResult_ToMarkdown_ComponentWithoutProjectKeyPrefix_PassesThroughUnchanged() + { + // Arrange - component does not start with "{ProjectKey}:" + IReadOnlyList issues = + [ + new("key1", "rule:S1234", "MAJOR", "external-component", null, "Some issue", "BUG") + ]; + + var result = new SonarQualityResult( + "https://sonarcloud.io", + "test_project", + "Test Project", + "OK", + [], + new Dictionary(), + issues, + []); + + // Act + var markdown = result.ToMarkdown(1); + + // Assert - component without prefix is passed through unchanged + Assert.Contains("external-component: MAJOR BUG [rule:S1234] Some issue", markdown); + } + /// /// Test SonarQualityCondition can be created with all properties /// diff --git a/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarHotSpotTests.cs b/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarHotSpotTests.cs index f687646..fe95fbc 100644 --- a/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarHotSpotTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarHotSpotTests.cs @@ -93,6 +93,10 @@ public void SonarHotSpot_Constructor_LowProbability_CreatesInstance() // Assert Assert.AreEqual("hs-key-789", hotSpot.Key); + Assert.AreEqual("test_project:src/Helper.cs", hotSpot.Component); + Assert.AreEqual(10, hotSpot.Line); + Assert.AreEqual("Potential security issue", hotSpot.Message); + Assert.AreEqual("xss", hotSpot.SecurityCategory); Assert.AreEqual("LOW", hotSpot.VulnerabilityProbability); } } diff --git a/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarQubeClientTests.cs b/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarQubeClientTests.cs index f2d989d..8430ced 100644 --- a/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarQubeClientTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/SonarIntegration/SonarQubeClientTests.cs @@ -304,5 +304,61 @@ public async Task SonarQubeClient_GetQualityResultByBranchAsync_ReturnsQualityGa private static HttpResponseMessage OkJson(string json) => SonarIntegrationTestHelpers.OkJson(json); + + /// + /// Test that null server URL throws ArgumentNullException + /// + [TestMethod] + public async Task SonarQubeClient_GetQualityResultByBranchAsync_NullServerUrl_ThrowsArgumentNullException() + { + // Arrange + using var client = new SonarQubeClient(new HttpClient(), false); + + // Act & Assert + await Assert.ThrowsExactlyAsync( + async () => await client.GetQualityResultByBranchAsync(null!, "my-project")); + } + + /// + /// Test that whitespace server URL throws ArgumentException + /// + [TestMethod] + public async Task SonarQubeClient_GetQualityResultByBranchAsync_WhitespaceServerUrl_ThrowsArgumentException() + { + // Arrange + using var client = new SonarQubeClient(new HttpClient(), false); + + // Act & Assert + await Assert.ThrowsExactlyAsync( + async () => await client.GetQualityResultByBranchAsync(" ", "my-project")); + } + + /// + /// Test that null project key throws ArgumentNullException + /// + [TestMethod] + public async Task SonarQubeClient_GetQualityResultByBranchAsync_NullProjectKey_ThrowsArgumentNullException() + { + // Arrange + using var client = new SonarQubeClient(new HttpClient(), false); + + // Act & Assert + await Assert.ThrowsExactlyAsync( + async () => await client.GetQualityResultByBranchAsync("https://sonar.example.com", null!)); + } + + /// + /// Test that whitespace project key throws ArgumentException + /// + [TestMethod] + public async Task SonarQubeClient_GetQualityResultByBranchAsync_WhitespaceProjectKey_ThrowsArgumentException() + { + // Arrange + using var client = new SonarQubeClient(new HttpClient(), false); + + // Act & Assert + await Assert.ThrowsExactlyAsync( + async () => await client.GetQualityResultByBranchAsync("https://sonar.example.com", " ")); + } }