diff --git a/.github/workflows/build-docs.yaml b/.github/workflows/build-docs.yaml index 797fc8b37..c90f2a2bd 100644 --- a/.github/workflows/build-docs.yaml +++ b/.github/workflows/build-docs.yaml @@ -15,24 +15,24 @@ jobs: build: permissions: contents: read - pull-requests: read runs-on: ubuntu-latest steps: - - name: Generate maester-bot app token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.MAESTER_BOT_APP_ID }} - private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - token: ${{ steps.app-token.outputs.token }} persist-credentials: false - name: Update docs run: ./build/Update-CommandReference.ps1 shell: pwsh + - name: Generate maester-bot app token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.MAESTER_BOT_APP_ID }} + private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + - name: Create PR to update repo uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: diff --git a/.github/workflows/build-maester-report-template.yaml b/.github/workflows/build-maester-report-template.yaml index d157082e0..727f860f1 100644 --- a/.github/workflows/build-maester-report-template.yaml +++ b/.github/workflows/build-maester-report-template.yaml @@ -20,6 +20,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Setup Node.js uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 diff --git a/.github/workflows/build-website.yaml b/.github/workflows/build-website.yaml index d4c122ea5..aa45c5047 100644 --- a/.github/workflows/build-website.yaml +++ b/.github/workflows/build-website.yaml @@ -48,6 +48,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Check command reference inputs if: github.event_name == 'pull_request' @@ -72,6 +74,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Generate command reference shell: pwsh @@ -125,6 +129,7 @@ jobs: with: # Full history so contributor attribution can be derived from git. fetch-depth: 0 + persist-credentials: false - name: Download generated command reference if: needs.detect-command-reference-changes.outputs.generate == 'true' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 5b825aa64..9e056684c 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -62,10 +62,12 @@ jobs: # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages steps: - - name: Checkout repository + - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - # Add any setup steps before running the `github/codeql-action/init` action. + with: + persist-credentials: false + + # Add any setup steps before running the `github/codeql-action/init` action. # This includes steps like installing compilers or runtimes (`actions/setup-node` # or others). This is typically only required for manual builds. # - name: Setup runtime (example) diff --git a/.github/workflows/dependency-review.yaml b/.github/workflows/dependency-review.yaml index 07b274894..84d2e43f6 100644 --- a/.github/workflows/dependency-review.yaml +++ b/.github/workflows/dependency-review.yaml @@ -22,6 +22,8 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false - name: Dependency review uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 diff --git a/.github/workflows/opengrep.yml b/.github/workflows/opengrep.yml index 10e5f1df6..120d72e14 100644 --- a/.github/workflows/opengrep.yml +++ b/.github/workflows/opengrep.yml @@ -41,10 +41,12 @@ jobs: actions: read steps: - - name: Checkout repository + - name: Checkout repository uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - # Install OpenGrep by downloading the release binary directly from + with: + persist-credentials: false + + # Install OpenGrep by downloading the release binary directly from # GitHub Releases (pinned by tag) and verifying its SHA256 before # executing it. Avoids piping a moving `install.sh` into bash and # closes the integrity gap left by trusting a mutable release tag. diff --git a/.github/workflows/publish-module-manualversionupdate.yaml b/.github/workflows/publish-module-manualversionupdate.yaml index 27769fac4..23b76217e 100644 --- a/.github/workflows/publish-module-manualversionupdate.yaml +++ b/.github/workflows/publish-module-manualversionupdate.yaml @@ -60,7 +60,9 @@ jobs: - name: Stamp maester-config.json version fields shell: pwsh - run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion '${{ steps.moduleversion.outputs.tag }}' + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion $env:MODULE_VERSION # ./module/ is a build artifact produced by Build-MaesterModule.ps1. # It is ignored by git and must never be committed to source control. @@ -95,7 +97,9 @@ jobs: run: npm ci - name: Update website release version - run: node ./build/Update-WebsiteReleaseVersion.mjs ${{ steps.moduleversion.outputs.tag }} + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: node ./build/Update-WebsiteReleaseVersion.mjs "$MODULE_VERSION" - name: Create website release version pull request uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 diff --git a/.github/workflows/publish-module-preview.yaml b/.github/workflows/publish-module-preview.yaml index ed054ddf8..816149914 100644 --- a/.github/workflows/publish-module-preview.yaml +++ b/.github/workflows/publish-module-preview.yaml @@ -49,7 +49,9 @@ jobs: - name: Stamp maester-config.json version fields shell: pwsh - run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion '${{ steps.moduleversion.outputs.tag }}' + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion $env:MODULE_VERSION # ./module/ is a build artifact produced by Build-MaesterModule.ps1. # It is ignored by git and must never be committed to source control. @@ -80,7 +82,9 @@ jobs: commit: ${{ github.sha }} - name: Update website preview version - run: node ./build/Update-WebsitePreviewVersion.mjs ${{ steps.moduleversion.outputs.tag }} + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: node ./build/Update-WebsitePreviewVersion.mjs "$MODULE_VERSION" - name: Commit website preview version uses: stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d #v5 diff --git a/.github/workflows/publish-module.yaml b/.github/workflows/publish-module.yaml index 435d6d3c9..79f289acf 100644 --- a/.github/workflows/publish-module.yaml +++ b/.github/workflows/publish-module.yaml @@ -60,7 +60,9 @@ jobs: - name: Stamp maester-config.json version fields shell: pwsh - run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion '${{ steps.moduleversion.outputs.tag }}' + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath tests/maester-config.json -ModuleVersion $env:MODULE_VERSION # ./module/ is a build artifact produced by Build-MaesterModule.ps1. # It is ignored by git and must never be committed to source control. @@ -95,7 +97,9 @@ jobs: run: npm ci - name: Update website release version - run: node ./build/Update-WebsiteReleaseVersion.mjs ${{ steps.moduleversion.outputs.tag }} + env: + MODULE_VERSION: ${{ steps.moduleversion.outputs.tag }} + run: node ./build/Update-WebsiteReleaseVersion.mjs "$MODULE_VERSION" - name: Create website release version pull request uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 diff --git a/.github/workflows/publish-tests.yaml b/.github/workflows/publish-tests.yaml index 31cb54284..6dcb11388 100644 --- a/.github/workflows/publish-tests.yaml +++ b/.github/workflows/publish-tests.yaml @@ -23,14 +23,16 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 + persist-credentials: false - name: Resolve latest release tag id: release_tag shell: pwsh env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RELEASE_TAG: ${{ github.event.release.tag_name }} run: | - $tag = '${{ github.event.release.tag_name }}' + $tag = $env:RELEASE_TAG if ([string]::IsNullOrWhiteSpace($tag)) { $tag = (gh release view --repo $env:GITHUB_REPOSITORY --json tagName -q .tagName) } @@ -41,10 +43,12 @@ jobs: - name: Stamp maester-config.json version fields shell: pwsh - run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath ./tests/maester-config.json -ModuleVersion '${{ steps.release_tag.outputs.tag }}' + env: + RELEASE_TAG: ${{ steps.release_tag.outputs.tag }} + run: ./build/Update-MaesterConfigVersion.ps1 -ConfigPath ./tests/maester-config.json -ModuleVersion $env:RELEASE_TAG - name: Publish to maester-tests id: push_directory - uses: cpina/github-action-push-to-another-repository@3fc9348237c8c6954ff88e58719af8a88af543f7 + uses: cpina/github-action-push-to-another-repository@55306faa4ed53b815ae49e564af8cfb359d32ae2 # v1.7.3 env: SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }} with: diff --git a/.github/workflows/publish-versioned-docs.yml b/.github/workflows/publish-versioned-docs.yml index 7e247495a..7361846c3 100644 --- a/.github/workflows/publish-versioned-docs.yml +++ b/.github/workflows/publish-versioned-docs.yml @@ -51,7 +51,9 @@ jobs: run: npm ci - name: Update website release version - run: node ./build/Update-WebsiteReleaseVersion.mjs ${{ inputs.version }} + env: + WEBSITE_VERSION: ${{ inputs.version }} + run: node ./build/Update-WebsiteReleaseVersion.mjs "$WEBSITE_VERSION" - name: ✍️ Create Version Files Pull Request uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 diff --git a/.github/workflows/update-module-docs.yaml b/.github/workflows/update-module-docs.yaml index d6e4f0a7a..ea090a8db 100644 --- a/.github/workflows/update-module-docs.yaml +++ b/.github/workflows/update-module-docs.yaml @@ -20,25 +20,26 @@ jobs: runs-on: windows-latest permissions: contents: read - pull-requests: read - - steps: - - name: Generate maester-bot app token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.MAESTER_BOT_APP_ID }} - private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} - + + steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ steps.app-token.outputs.token }} - - name: Update maester.dev powershell docs - run: ./build/Update-CommandReference.ps1 - shell: pwsh - - - name: Create Pull Request - uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 + with: + persist-credentials: false + - name: Update maester.dev powershell docs + run: ./build/Update-CommandReference.ps1 + shell: pwsh + + - name: Generate maester-bot app token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.MAESTER_BOT_APP_ID }} + private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - name: Create Pull Request + uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ steps.app-token.outputs.token }} title: Update maester.dev powershell docs diff --git a/.github/workflows/update-public-suffix-list.yaml b/.github/workflows/update-public-suffix-list.yaml index 4bdbd8772..5b124cd60 100644 --- a/.github/workflows/update-public-suffix-list.yaml +++ b/.github/workflows/update-public-suffix-list.yaml @@ -15,26 +15,26 @@ jobs: update-public-suffix-list: runs-on: ubuntu-latest permissions: - contents: write - pull-requests: write + contents: read steps: - - name: Generate maester-bot app token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.MAESTER_BOT_APP_ID }} - private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - token: ${{ steps.app-token.outputs.token }} persist-credentials: false - name: Update public suffix list shell: pwsh run: ./build/Update-PublicSuffixList.ps1 + - name: Generate maester-bot app token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.MAESTER_BOT_APP_ID }} + private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + - name: Create Pull Request uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: diff --git a/.github/workflows/update-role-definitions.yaml b/.github/workflows/update-role-definitions.yaml index 1791a3e02..a53b533cd 100644 --- a/.github/workflows/update-role-definitions.yaml +++ b/.github/workflows/update-role-definitions.yaml @@ -12,34 +12,32 @@ concurrency: cancel-in-progress: false jobs: - update-role-definitions: - runs-on: windows-latest - permissions: - contents: read - pull-requests: read - - steps: - - name: Generate maester-bot app token - id: app-token - uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 - with: - app-id: ${{ secrets.MAESTER_BOT_APP_ID }} - private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} - permission-contents: write - permission-pull-requests: write - + update-role-definitions: + runs-on: windows-latest + permissions: + contents: read + + steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - token: ${{ steps.app-token.outputs.token }} - persist-credentials: false - - - name: Update Entra ID role definitions - id: update - run: ./build/Update-MtRoleDefinitions.ps1 - shell: pwsh - - - name: Create Pull Request - if: success() + with: + persist-credentials: false + + - name: Update Entra ID role definitions + id: update + run: ./build/Update-MtRoleDefinitions.ps1 + shell: pwsh + + - name: Generate maester-bot app token + id: app-token + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + app-id: ${{ secrets.MAESTER_BOT_APP_ID }} + private-key: ${{ secrets.MAESTER_BOT_PRIVATE_KEY }} + permission-contents: write + permission-pull-requests: write + + - name: Create Pull Request + if: success() uses: peter-evans/create-pull-request@5f6978faf089d4d20b00c7766989d076bb2fc7f1 # v8.1.1 with: token: ${{ steps.app-token.outputs.token }} diff --git a/.github/workflows/update-tag-documentation.yml b/.github/workflows/update-tag-documentation.yml deleted file mode 100644 index 8d5e9766a..000000000 --- a/.github/workflows/update-tag-documentation.yml +++ /dev/null @@ -1,44 +0,0 @@ -name: 🏷️ Update Tag Documentation - -on: - push: - paths: - - 'tests/**' - - 'build/Update-TagsDocumentation.ps1' - - '.github/workflows/update-tags.yml' - -permissions: {} - -concurrency: - group: update-tag-documentation - cancel-in-progress: false - -jobs: - update-tags: - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - name: Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - - name: Set up PowerShell modules - run: | - pwsh -NoLogo -NoProfile -Command "Install-Module Pester -MinimumVersion 5.7.1 -MaximumVersion 5.7.1 -Scope CurrentUser -Force -SkipPublisherCheck" - - - name: Generate tags document - run: pwsh -NoLogo -NoProfile -File build/Update-TagsDocumentation.ps1 - - - name: Commit and push changes - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - if git diff --quiet -- website/docs/tags.md; then - echo "No changes to commit." - exit 0 - fi - git add website/docs/tags.md - git commit -m "chore: update tags documentation" - git push - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/build/Update-TagsDocumentation.ps1 b/build/Update-TagsDocumentation.ps1 deleted file mode 100644 index 685ebf37b..000000000 --- a/build/Update-TagsDocumentation.ps1 +++ /dev/null @@ -1,243 +0,0 @@ -# Update-TagsDocumentation.ps1 - -<# -.SYNOPSIS - Updates the tags documentation file with an inventory of tags used in Maester tests. - -.DESCRIPTION - This script scans Maester's tests directory for tags used in Pester tests and generates a - markdown documentation file. The document lists all tags along with their usage counts, grouped by categories. - -.PARAMETER RepoRoot - The path to the root of the repository. Defaults to the parent directory of the script location (i.e., the repository root). - -.PARAMETER TestsPath - The path to the Maester tests directory. Defaults to 'tests' within the repository root. - -.PARAMETER TagsDocPath - The path to the tags documentation file to update. Defaults to 'website/docs/tests/tags/readme.md' within the repository root. - -.EXAMPLE - .\Update-TagsDocumentation.ps1 - - Updates the tags documentation file using default paths for the repository root, tests directory, and tags documentation file. - -.EXAMPLE - .\Update-TagsDocumentation.ps1 -RepoRoot 'C:\Maester' -TestsPath 'C:\Maester\tests' -TagsDocPath 'C:\Maester\website\docs\tests\tags\readme.md' - - Updates the tags documentation file using specified paths for the repository root, tests directory, and tags documentation file. -#> -[CmdletBinding()] -param( - # The path to the root of the repository. - [Parameter()] - [ValidateScript( { Test-Path $_ } )] - [string]$RepoRoot = (Split-Path -Path $PSScriptRoot), - - # The path to the Maester tests directory. Defaults to tests within the repository root. - [Parameter()] - [ValidateScript( { Test-Path $_ } )] - [string]$TestsPath = (Join-Path -Path (Split-Path -Path $PSScriptRoot) -ChildPath 'tests'), - - # The path to the tags documentation file to update. Defaults to website/docs/tests/tags/readme.md within the repository root. - [Parameter()] - [ValidateScript( { Test-Path (Split-Path $_ -Parent) } )] - [string]$TagsDocPath = (Join-Path -Path (Split-Path -Path $PSScriptRoot) -ChildPath 'website/docs/tests/tags/readme.md') -) - -#region Get Tag Inventory -# Dot-source the Get-MtTestInventory script (in lieu of importing the entire module). -try { - $InventoryScript = Join-Path $RepoRoot 'powershell/public/Get-MtTestInventory.ps1' - . $InventoryScript -} catch { - throw "Failed to load Get-MtTestInventory.ps1 from $InventoryScript. $_" -} - -# Get test and tag inventory -$Inventory = Get-MtTestInventory -Path $TestsPath - -# Build list of tags counts for use as table rows. -$TagCounts = [System.Collections.Generic.List[pscustomobject]]::new() -foreach ($Item in $Inventory.GetEnumerator()) { - $TagCounts.Add([pscustomobject]@{ - Tag = $Item.Name - Count = $Item.Value.Count - }) -} - -function Add-OrUpdateTag { - <# - .SYNOPSIS - Adds a new tag and its count to the list, or updates the count if the tag already exists in the list. - #> - param( - # The tag to add or update in the list. - [string]$Tag, - - # The count to add to the tag's existing count (or set if new). - [int]$Count - ) - - # Check if the tag already exists in the TagCounts list. - $Existing = $TagCounts | Where-Object { $_.Tag -eq $Tag } - if ($Existing) { - # Increment the count if it already exists in the list. - foreach ($item in $Existing) { - $item.Count += $Count - } - } else { - # Add a new entry if the tag does not exist in the list. - $TagCounts.Add([pscustomobject]@{ - Tag = $Tag - Count = $Count - }) - } -} # end function Add-OrUpdateTag - -#region Manually Add Tags -# Manually add and count tags from tests that fail discovery so counts remain accurate. -# For example, 'MT.1059' will always fail discovery unless connected to an environment that has implemented MDI. -Add-OrUpdateTag -Tag 'MT.1059' -Count 1 -Add-OrUpdateTag -Tag 'MDI' -Count 1 -#endregion Manually Add Tags - -# Define groups for categorizing tags in the documentation. -$TagGroups = [ordered]@{ - 'CIS' = { param($t) $t.Tag -match '^CIS(\.|\s|$)|L1|L2' } - 'CISA' = { param($t) $t.Tag -match '^CISA(\.|$)' -or $t.Tag -match '^MS\.' } - 'EIDSCA' = { param($t) $t.Tag -match '^EIDSCA(\.|$)' } - 'ORCA' = { param($t) $t.Tag -match '^ORCA(\.|$)' } - 'Maester' = { param($t) $t.Tag -match '^(MT\.|Maester)' } - 'Ungrouped' = { param($t) $t.Tag -notmatch '^(CIS|L1|L2|CISA|MS\.|EIDSCA|ORCA|MT\.|Maester)' } -} -#endregion Get Tag Inventory - - -function ConvertTo-MarkdownTable { - <# - .SYNOPSIS - Converts a list of tags and their counts into a markdown-formatted table. - #> - param( - [string] $TagCategoryTitle, - [System.Collections.Generic.List[PSCustomObject]] $Items - ) - - # Return null if there are no items to process. - if (-not $Items -or $Items.Count -eq 0) { return $null } - - # Split items into multiple use (count > 1) and single use (count = 1) for the summary. - $MultipleUse = $Items | Where-Object { $_.Count -gt 1 } | Sort-Object -Property Tag - $SingleUse = $Items | Where-Object { $_.Count -eq 1 } | Sort-Object -Property Tag - - # Initialize a StringBuilder to construct the markdown table. - $SB = [System.Text.StringBuilder]::new() - [void]$SB.AppendLine("### $TagCategoryTitle") - [void]$SB.AppendLine() - - # Only create table if there are tags used more than once. - if ($MultipleUse) { - [void]$SB.AppendLine('| Tag | Count |') - [void]$SB.AppendLine('| :--- | ---: |') - foreach ($i in $MultipleUse) { - [void]$SB.AppendLine("| $($i.Tag) | $($i.Count) |") - } - [void]$SB.AppendLine() - } - - # Add single-use tags as comma-separated list - if ($SingleUse) { - $singleTagList = ($SingleUse | ForEach-Object { $_.Tag }) -join ', ' - [void]$SB.AppendLine("**Individual tags**: $singleTagList") - #[void]$SB.AppendLine() - } - - # Return the constructed markdown string. - return $SB.ToString() -} # end function ConvertTo-MarkdownTable - -# Build markdown sections for each tag group. -$SectionBlocks = @() -foreach ($Key in $TagGroups.Keys) { - $matched = $TagCounts | Where-Object { & $TagGroups[$Key] $_ } - if ($matched) { $SectionBlocks += ConvertTo-MarkdownTable -TagCategoryTitle $Key -Items ([System.Collections.Generic.List[PSCustomObject]]$matched) } -} - -# Join the section blocks into a single markdown string. -$SectionsText = ($SectionBlocks | Where-Object { $_ }) -join "`n" - -#region Create Static Markdown Content -# Create the markdown front matter. -$FrontMatter = @" ---- -id: overview -title: Tags Overview -sidebar_label: 🏷️ Tags -description: Overview of the tags used to identify and group related tests. ---- - -"@ - -# Create the introductory text for the tags documentation. -$Intro = @" -## Tags Overview - -Tags are used by Maester to identify and group related tests. They can also be used to select specific tests to run or exclude during test execution. This makes them very useful, but they can also get in the way if too many tags are created. Our goal is to minimize the "signal to noise" ratio when it comes to tags by focusing on a few key areas: - -- **Test Suites**: We use standardized tag categories for test suites that align with well-known benchmarks and baselines. This helps users quickly identify tests that align with these widely recognized standards or with Maester's own suite of tests: - - **CIS Benchmarks**: Tags prefixed with `CIS` (e.g., `CIS.M365.1.1`, `CIS.Azure.3.2`) - - **CISA & Microsoft Baseline**: Tags prefixed with `CISA` or `MS` (e.g., `CISA.M365.Baseline`, `MS.Azure.Baseline`) - - **EIDSCA**: Tags prefixed with `EIDSCA` (e.g., `EIDSCA.EntraID.2.1`) - - **ORCA**: Tags prefixed with `ORCA` (e.g., `ORCA.Exchange.1.1`) - - **Maester**: Tags prefixed with `Maester` or `MT` (e.g., `MT.1001`, `MT.1024`) - -- **Product Areas**: Tags related to specific products and services that are being tested: - - Azure - - Defender XDR - - Entra ID - - Exchange - - Microsoft 365 - - SharePoint - - Teams - -- **Practices or Capabilities**: Tags that denote specific security practices or capabilities within the security domain, such as: - - Authentication (May include related topics such as MFA, SSPR, etc.) - - Conditional Access (CA) - - Data Loss Prevention (DLP) - - Extended Security Posture Management (XSPM) - - Hybrid Identity - - Privileged Access Management (PAM) - - Privileged Identity Management (PIM) - -### Recommendations for Tag Usage - -Less is more! When creating or assigning tags to tests, consider the following best practices: - -1. Assign one ``Test Suite`` tag per test to ensure clarity on which benchmark or baseline the test aligns with. This tag will usually go in the `Describe` block of a Pester test file. -2. Assign a ``Product Area`` tag to indicate which products or services the test is most relevant to. Limit these to 1-3 tags per test to avoid over-tagging. -3. Use ``Practice`` or ``Capability`` tags sparingly and only when they add significant value in categorizing the test. Avoid creating overly specific tags that may only apply to a single test. - -## Tags Used - -The tables below list every tag discovered via `Get-MtTestInventory`. - -"@ -#endregion Create Static Markdown Content - -# Combine all parts into the final markdown content and write to the documentation file. -$Body = ($FrontMatter + $Intro + "`n" + $SectionsText) -join "`n" - -# Create the directory for the tags documentation file if it doesn't exist. -if (-not (Test-Path -Path (Split-Path -Parent $TagsDocPath))) { - New-Item -ItemType Directory -Path (Split-Path -Parent $TagsDocPath) -Force | Out-Null -} - -# Write the final markdown content to the tags documentation file. -try { - Set-Content -LiteralPath $TagsDocPath -Value $Body -Encoding UTF8 - Write-Host "Updated $TagsDocPath" -} -catch { - Write-Error "Failed to write tags documentation to $TagsDocPath. $_" -} diff --git a/docs/proposals/repo-restructure.md b/docs/proposals/repo-restructure.md index fdb63fc3e..9c400cb83 100644 --- a/docs/proposals/repo-restructure.md +++ b/docs/proposals/repo-restructure.md @@ -362,7 +362,7 @@ unit-test tree in Phase 4. - `.gitignore:525` → `maester-tests/Custom/*.ps1`. - `website/scripts/generate-test-docs.mjs` — tests root + config path; regenerate. - `build/orca/Update-OrcaTests.ps1`, `build/eidsca/Update-EidscaTests.ps1` write - paths; `build/Update-TagsDocumentation.ps1` default `$TestsPath`. + paths. - Sweep for stragglers: `Install-MaesterTests.ps1:9` help link, `powershell/README.md`, root `README.md`, `.github/` docs, and `website/docs` contributing pages. 3. Known, accepted quirk: an **older released module** run inside a **new checkout**