feat(config): track per-test license requirements in maester-config.json#1746
feat(config): track per-test license requirements in maester-config.json#1746SamErde wants to merge 5 commits into
Conversation
…ck the license requirements for each test Id.
…settings from version control
Up to standards ✅🟢 Issues
|
There was a problem hiding this comment.
Pull request overview
This PR adds structured per-test license metadata to the Maester test configuration so license requirements can be centrally indexed (and later used for filtering/skipping/reporting) rather than inferred from scattered code/doc signals.
Changes:
- Adds a
"Licenses": [...]array to eachTestSettingsentry intests/maester-config.json. - Introduces
build/Update-MaesterConfigLicenses.ps1to derive/populate license tokens from tests and underlying functions. - Introduces
build/Test-MaesterConfigLicenses.ps1to audit/verify config license tokens against independently re-derived signals (including markdown cross-checks).
Reviewed changes
Copilot reviewed 2 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| tests/maester-config.json | Adds a Licenses array to every test config entry. |
| build/Update-MaesterConfigLicenses.ps1 | New script to derive and write license tokens into the config. |
| build/Test-MaesterConfigLicenses.ps1 | New verifier script to detect drift/mismatches between config and signals in code/docs. |
| .gitignore | Ignores a local Claude Code settings file. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Make Update-MaesterConfigLicenses.ps1 idempotent: strip any existing Licenses field from each TestSettings object before re-inserting. Re-running the script no longer produces duplicate "Licenses" keys. - Add markdown-signal extraction to the updater (website doc + companion function .md). MT.1071's "Microsoft Entra ID P1 or P2 is required" language now derives EntraIDP1 deterministically instead of needing a manual override that would be reverted on re-run. - Update the .SYNOPSIS / .DESCRIPTION blocks on both scripts so the documented signal list, defaults, verdicts, and -OnlyMismatches behavior match the actual code paths. - Validate License:<Token> tag tokens against the canonical vocabulary in the verifier so it stays consistent with the updater (both reject unknown tokens instead of silently disagreeing). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying maester with
|
| Latest commit: |
0459a63
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://42c24b96.maester.pages.dev |
| Branch Preview URL: | https://feat-tracklicensemetadata.maester.pages.dev |
|
For licenses there are a few key requirements we need to take into account.
I would re-use the same functionality since it has been tested and is in use by ZeroTrust assessment and helps keep the logic the same Test-ZtLicense -CompatibleLicense @("LicenseA", "LicenseB&LicenseC") -CurrentLicense @("LicenseD", "LicenseB", "LicenseC") |
|
Thanks, I'll check out the ZTA implementation! |
|
The actual implementation in Maester is going to be a bit different to ZTAssess. Since here Pester is the engine running the tests. I think the approach would be to run pester and make it skip the tests, then we go back and add all the skipped tests into testresults and include the .md content (as well as the info on why they were skipped). This way the results will let the user have the same experience they do today. |
|
just adding this information from my pr #1727 in agreement with @merill Pretty sure this does not cover everything that requires a license in Maester but i think it is a nice start Test Skip ConditionsLicense: Intune
License: P2 / GovernanceTest Files
Functions
Entra ID Plan: Free
|

📑 Description
Adds a
Licensesarray to everyTestSettingsentry intests/maester-config.json, giving us a single index that answers: which licenses make this test's feature available?Today, license requirements are scattered across Pester
Describetags ("Entra ID P1"), inlineGet-MtLicenseInformationskip checks, theNotLicensed*skip-reason vocabulary inGet-MtSkippedReason.ps1, and prose in test docs. This change consolidates those signals into a structured field on each test, plus two scripts (one to populate the field, one to audit it) so future drift is detectable.Relates to #1071 (filter tests by license type) and #627 (add license metadata).
Vocabulary
Token names mirror the existing Maester abstractions in
Get-MtLicenseInformation.ps1andGet-MtSkippedReason.ps1:EntraIDP1,EntraIDP2,EntraIDGovernance,EntraWorkloadIDP1,EntraWorkloadIDP2,Eop,MdoP1,MdoP2,ExoDlp,AdvAudit,DefenderXDR,Intune,CustomerLockbox, plusAzureDevOpsforAZDO.*tests.Semantics:
[]→ no premium license required (baseline; matches today's implicit default).["EntraIDP2"]→ exactly this tier required.["Eop", "MdoP1"]→ any one of the listed licenses satisfies the requirement (matches the OR-semantics already used forMdo/MdoV2inGet-MtLicenseInformation).["TBD"]→ reserved for orphan entries (config rows with no backing.Tests.ps1).Note for reviewers: I considered using Microsoft's official SKU/license display names (e.g.
Microsoft Entra ID P1) but kept the existing internal shorthand for consistency with the rest of the codebase. Happy to rename in a follow-up if maintainers prefer.Approach
build/Update-MaesterConfigLicenses.ps1walks everytests/**/*.Tests.ps1, locates eachItblock by test ID, and extracts license signals in this priority order:Add-MtTestResultDetail -SkippedBecause NotLicensed<Token>inside theItblock.Get-MtLicenseInformation -Product Xcomparisons (e.g.-ne 'P2'→EntraIDP2).-Skip:( … license check … )parameter on theItblock.Test-*PowerShell function.Describe/Context/Ittags ("Entra ID P1","DefenderXDR","Intune","MDI","Governance","MdoP1","MdoP2","customerlockbox"). Forward-compatible: a futureLicense:<Token>tag form is parsed too. The bare"Defender"tag is intentionally not treated as a signal because it's ambiguous (MDE / MDO / MDI / MDC / MDCA) — those tests are caught by signals 1–4.AZDO.*→["AzureDevOps"]; everything else with no signal →[].build/Test-MaesterConfigLicenses.ps1independently re-derives signals from the test file, the underlying function, the website doc (website/docs/tests/<id>.md), and the function's companion help doc (powershell/public/**/<function>.md), then compares against the config. Verdicts:OK,OK_MD(config justified by markdown evidence only),BASELINE,ORPHAN,MISMATCH. Use-OnlyMismatchesto filter.Result
MT.1071— companionTest-MtCaAzureDevOps.mdstates "Microsoft Entra ID P1 or P2 is required".Licenses: []; no premium signals found anywhere..Tests.ps1:CIS.M365.8.2.4,ORCA.1000–ORCA.1004. Marked["TBD"]until a backing test is added or the row is removed.Markdown-only signals reviewed and intentionally not actioned (false positives — phrases in remediation prose that aren't actual license gates):
CIS.M365.2.1.{3,6,12,13}andORCA.{109, 118.x, 231-233.x}— "EOP" appears in remediation prose, but EOP is bundled with any tenant that has Exchange Online (not a premium gate).CISA.MS.EXO.16.2— "Defender XDR" is a portal-name reference (admin nav path), not a license claim. Function gates onMdoP1.CISA.MS.EXO.17.2— deprecated CISA test that returns null; historical "Purview Audit (Premium)" context only.MT.1098— markdown mentions Defender for Endpoint integration, but the MTD connector configuration is an Intune feature.✅ Checks
/powershell/tests/pester.ps1locally.ℹ️ Additional Information
Files changed
tests/maester-config.jsonTestSettingsrow gains one"Licenses": [...]line; the priorTitleline gains a trailing comma. No other edits, no reordering. LF line endings preserved.build/Update-MaesterConfigLicenses.ps1-DryRun.build/Test-MaesterConfigLicenses.ps1-OnlyMismatches.Out of scope (suggested follow-ups)
Licensesfrom the config and skip tests accordingly. Today, skipping is still driven by inlineGet-MtLicenseInformationchecks; this PR only populates the index.Licensesin the generated test docs fromwebsite/scripts/generate-test-docs.mjs.Update-MaesterConfigLicenses.ps1 -DryRunand fails on diff (similar tobuild/eidsca/Update-EidscaTests.ps1).ORPHANconfig rows.Reproducing locally