Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0d755c2
chore: remove issue auto assign github action as now in issue templates
blindzero Jan 10, 2026
ed2c0fb
ci: add PSScriptAnalyzer linting with repo settings
blindzero Jan 10, 2026
96220be
ci: run-tests as minimalistic backward wrapper
blindzero Jan 10, 2026
a4f4bdf
ci: change to new Invoke-IdlePesterTests.ps1
blindzero Jan 10, 2026
6632857
ci: remove old run-tests.ps1 sript legacy
blindzero Jan 10, 2026
9e468ad
ci: add repo PSScriptAnalyzer settings
blindzero Jan 10, 2026
8f09b1a
ci: add Invoke-IdleScriptAnalyzer runner with pinned toolchain and op…
blindzero Jan 10, 2026
c8fe007
ci: add lint job and switch tests to Invoke-IdlePesterTests; remove r…
blindzero Jan 10, 2026
300f7b6
docs: updated releases.md to new Invoke-IdlePesterTests.ps1
blindzero Jan 10, 2026
b86f578
docs: updating to new Pester Tests adding Script Analyzers infos
blindzero Jan 10, 2026
83b9c07
docs: updating to new Pester Tests adding Script Analyzers infos
blindzero Jan 10, 2026
12957b4
Merge branch 'issues/68-ci-add-PSScriptAnalyzer-linting-with-repo-set…
blindzero Jan 10, 2026
c019f89
Merge branch 'issues/68-ci-add-PSScriptAnalyzer-linting-with-repo-set…
blindzero Jan 10, 2026
f5be858
Merge branch 'issues/68-ci-add-PSScriptAnalyzer-linting-with-repo-set…
blindzero Jan 10, 2026
3c2c6f3
ci: fixing multiple path invoaction with foreach
blindzero Jan 10, 2026
43b50da
ci: fixing multiple path invoaction with foreach
blindzero Jan 10, 2026
49911bc
ci: fixing .count() issue with entitlement tests
blindzero Jan 10, 2026
1d5c222
Merge branch 'issues/68-ci-add-PSScriptAnalyzer-linting-with-repo-set…
blindzero Jan 10, 2026
557d64e
ci: fixed missing paranthesis issue in check SARIF upload step
blindzero Jan 10, 2026
4a5ba02
ci: remove check to upload SARIF to always upload (for create + auto-…
blindzero Jan 10, 2026
ae62818
Initial plan
Copilot Jan 10, 2026
d79e67c
fix: pin Pester to specific version 5.7.1 for supply-chain security
Copilot Jan 10, 2026
7818a34
refactor: rename Ensure-* functions to Initialize-* to use approved v…
Copilot Jan 10, 2026
41c14b1
Merge pull request #71 from blindzero/copilot/sub-pr-70
blindzero Jan 10, 2026
0d6eca9
ci: let SARIF upload run always, even if ScriptAnalyzer fails.
blindzero Jan 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 41 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ jobs:
name: Pester (${{ matrix.os }})
runs-on: ${{ matrix.os }}

# add job-scoped permissions needed for artifact upload
permissions:
contents: read
actions: write
Expand All @@ -32,15 +31,49 @@ jobs:

- name: Run Pester
shell: pwsh
run: pwsh -NoProfile -File ./tools/run-tests.ps1 -CI
run: pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1 -CI

- name: Upload test results
- name: Upload Pester artifacts
if: always()
continue-on-error: true
uses: actions/upload-artifact@v6
with:
name: test-results-${{ matrix.os }}
path: artifacts/test-results.xml
name: pester-artifacts-${{ matrix.os }}
if-no-files-found: warn
path: |
artifacts/test-results.xml
artifacts/coverage.xml

lint:
name: PSScriptAnalyzer
runs-on: ubuntu-latest

permissions:
contents: read
actions: read
security-events: write

steps:
- uses: actions/checkout@v6

- name: Run PSScriptAnalyzer
shell: pwsh
run: pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1 -CI

- name: Upload PSScriptAnalyzer artifacts
if: always()
uses: actions/upload-artifact@v6
with:
name: psscriptanalyzer-artifacts
if-no-files-found: warn
path: |
artifacts/pssa-results.json
artifacts/pssa-results.sarif

- name: Upload SARIF to GitHub Code Scanning
if: always() && github.event_name == 'push' && github.ref == 'refs/heads/main'
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: artifacts/pssa-results.sarif

docs-cmdlet-reference:
name: Verify cmdlet reference is up to date
Expand All @@ -63,12 +96,11 @@ jobs:
# Ignore if not supported in this environment
}
}

# platyPS is pinned for deterministic Markdown output.
# See CONTRIBUTING.md for upgrade procedure.

Install-Module -Name platyPS -RequiredVersion 0.14.2 -Scope CurrentUser -Force -AllowClobber -ErrorAction Stop

- name: Debug platyPS version
shell: pwsh
run: |
Expand Down
32 changes: 0 additions & 32 deletions .github/workflows/issue-auto-assign.yml

This file was deleted.

51 changes: 43 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,14 +123,54 @@ Pull Requests must:

A contribution is complete when:

- all tests pass (`Invoke-Pester -Path ./tests`)
- no architecture rules are violated (see `docs/01-architecture.md`)
- all tests pass (`pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1`)
- static analysis passes (`pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1`)
- no architecture rules are violated (see `docs/advanced/architecture.md`)
- public APIs are documented (comment-based help for exported functions)
- documentation is updated where required:
- README.md (only high-level overview + pointers)
- docs/ (usage/concepts/examples)
- provider/step module READMEs if behavior/auth changes

## Local quality checks

IdLE provides canonical scripts under `tools/` so you can reproduce the same checks locally that CI runs.

### Run tests (Pester)

Run the test suite:

- `pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1`

To generate CI-like artifacts (test results + coverage) under `artifacts/`:

- `pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1 -CI`

Outputs:

- `artifacts/test-results.xml` (NUnitXml)
- `artifacts/coverage.xml` (coverage report)

### Run static analysis (PSScriptAnalyzer)

Run PSScriptAnalyzer using the repository settings:

- `pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1`

To generate CI-like artifacts under `artifacts/` (including SARIF for GitHub Code Scanning):

- `pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1 -CI`

Outputs:

- `artifacts/pssa-results.json` (summary)
- `artifacts/pssa-results.sarif` (SARIF)

The rule set is defined in `PSScriptAnalyzerSettings.psd1` at the repository root.
The runner pins tool versions for deterministic CI results; update pins intentionally and document the change in the PR.

> Note: `artifacts/` is a build output folder and should not be committed.

---

## Generated cmdlet reference (platyPS)
Expand Down Expand Up @@ -253,11 +293,6 @@ To fix a failing PR:

Repository maintainers should configure branch protection so that required status checks include this workflow.






## Documentation

Keep docs short and linkable:
Expand All @@ -269,7 +304,7 @@ Keep docs short and linkable:
Key links:

- Docs map: `docs/00-index.md`
- Architecture: `docs/01-architecture.md`
- Architecture: `docs/advanced/architecture.md`
- Examples: `docs/02-examples.md`
- Coding & in-code documentation rules: `STYLEGUIDE.md`

Expand Down
58 changes: 58 additions & 0 deletions PSScriptAnalyzerSettings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# PSScriptAnalyzer settings for IdentityLifecycleEngine (IdLE)
#
# This file is intentionally data-only (no script blocks, no expressions).
# It is used by CI and can also be referenced from VS Code workspace settings.
#
# Notes:
# - We explicitly list IncludeRules to keep the first rollout focused and low-noise.
# - Formatting rules are enabled to align with STYLEGUIDE.md (4 spaces, consistent whitespace).

@{
Severity = @('Error', 'Warning')

IncludeRules = @(
# Naming / API hygiene
'PSUseApprovedVerbs',
'PSAvoidGlobalVars',
'PSAvoidUsingCmdletAliases',
'PSAvoidUsingPositionalParameters',
'PSUseCorrectCasing',

# Common correctness issues
'PSAvoidUsingEmptyCatchBlock',
'PSReviewUnusedParameter',
'PSUseDeclaredVarsMoreThanAssignments',
'PSAvoidTrailingWhitespace',

# Security / risky constructs
'PSAvoidUsingInvokeExpression',
'PSAvoidUsingPlainTextForPassword',
'PSAvoidUsingConvertToSecureStringWithPlainText',

# Style / formatting (enabled explicitly)
'PSUseConsistentIndentation',
'PSUseConsistentWhitespace'
)

Rules = @{
PSUseConsistentIndentation = @{
Enable = $true
IndentationSize = 4
PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
Kind = 'space'
}

PSUseConsistentWhitespace = @{
Enable = $true
CheckInnerBrace = $true
CheckOpenBrace = $true
CheckOpenParen = $true
CheckOperator = $true
CheckPipe = $true
CheckPipeForRedundantWhitespace = $false
CheckSeparator = $true
CheckParameter = $false
IgnoreAssignmentOperatorInsideHashTable = $false
}
}
}
14 changes: 14 additions & 0 deletions STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ Providers:
- No live system calls in unit tests
- Providers require contract tests

## Quality Gates

IdLE uses static analysis and automated tests to keep the codebase consistent and maintainable.

- **PSScriptAnalyzer** is the required linter for PowerShell code.
- Repository policy is defined in `PSScriptAnalyzerSettings.psd1` (repo root).
- Run locally via `pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1`.
- CI publishes analyzer outputs under `artifacts/`.
- On default-branch runs, CI also uploads SARIF to GitHub Code Scanning.

- **Pester** is the required test framework.
- Run locally via `pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1`.
- CI publishes test results and coverage under `artifacts/`.

---

## Documentation Responsibilities
Expand Down
16 changes: 12 additions & 4 deletions docs/advanced/releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,19 @@ Pre-release tags do **not** publish to PowerShell Gallery.
pwsh -NoProfile -File ./tools/Set-IdleModuleVersion.ps1 -TargetVersion 1.2.0
```

3. Run tests:
3. Run quality checks locally:

```powershell
pwsh -NoProfile -File ./tools/run-tests.ps1
```
- Pester tests:

```powershell
pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1
```

- Static analysis (PSScriptAnalyzer):

```powershell
pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1
```

4. Commit and push the changes.
5. Open a Pull Request to `main` and wait for CI to pass.
Expand Down
65 changes: 48 additions & 17 deletions docs/advanced/testing.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,67 @@
# Testing

IdLE is designed to be testable in isolation.
IdLE is designed to be testable in isolation. Tests should be deterministic, fast, and runnable on any machine (local or CI) without requiring live systems.

## Running tests locally

Use the canonical test runner:

```powershell
pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1
```

Enable coverage (optional):

```powershell
pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1 -EnableCoverage
```

If you want a specific coverage format:

```powershell
pwsh -NoProfile -File ./tools/Invoke-IdlePesterTests.ps1 -EnableCoverage -CoverageOutputFormat Cobertura
```

## Unit tests

Unit tests should:

- use Pester
- use mock providers
- use **Pester**
- use **mock providers**
- avoid live system calls
- prefer explicit, committed fixtures over writing ad-hoc temporary files

## Provider contract tests

Provider contract tests verify that an implementation matches the expected contract.
They can run against:

- a mock harness
- a local test double
- a dedicated test tenant (only when explicitly intended)
They should:

- test the *contract behavior* (inputs/outputs, error handling, capability surface)
- run against **mock/file providers** by default
- run against real providers only as an explicit, opt-in scenario (separate pipeline / environment)

## CI artifacts

The CI pipeline produces test artifacts under the `artifacts/` folder and uploads them.

Expected outputs:

- `artifacts/test-results.xml` (NUnitXml test results)
- `artifacts/coverage.xml` (code coverage report; format depends on configuration)

## Static analysis

## Workflow validation in CI
IdLE uses **PSScriptAnalyzer** as a CI quality gate to enforce baseline style and correctness rules.

Validate workflows and step metadata in CI using a dedicated validation command.
Local run:

Principles:
```powershell
pwsh -NoProfile -File ./tools/Invoke-IdleScriptAnalyzer.ps1
```

- fail fast for unknown keys
- fail early for invalid references
- keep configuration data-only (no script blocks)
The analyzer uses the repository settings file:

## Tips
- `PSScriptAnalyzerSettings.psd1` (repo root)

- Prefer deterministic input fixtures
- Keep tests readable and focused
- Treat public cmdlets as stable contracts
In CI, PSScriptAnalyzer emits machine-readable artifacts under `artifacts/` (JSON and optional SARIF) and can publish SARIF findings to GitHub Code Scanning on default-branch runs.
4 changes: 2 additions & 2 deletions tests/ProviderContracts/EntitlementProvider.Contract.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,8 @@ function Invoke-IdleEntitlementProviderContractTests {
[void]$script:Provider.RevokeEntitlement($id, $entitlement)
$afterRevoke = @($script:Provider.ListEntitlements($id))

($afterGrant | Where-Object { $_.Kind -eq $entitlement.Kind -and $_.Id -eq $entitlement.Id }).Count | Should -Be 1
($afterRevoke | Where-Object { $_.Kind -eq $entitlement.Kind -and $_.Id -eq $entitlement.Id }).Count | Should -Be 0
@($afterGrant | Where-Object { $_.Kind -eq $entitlement.Kind -and $_.Id -eq $entitlement.Id }).Count | Should -Be 1
@($afterRevoke | Where-Object { $_.Kind -eq $entitlement.Kind -and $_.Id -eq $entitlement.Id }).Count | Should -Be 0

# Sanity: $null is treated as empty.
($before -is [object[]]) | Should -BeTrue
Expand Down
Loading