diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index f386e2e..c6136ce 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -9,95 +9,70 @@ source: current task evidence ## Current focus -Phase 2 of the quality gate before 5.0.0 (Decision 21), on the branch -`ai/release-5.0.0-rc6`, released as 5.0.0-rc6: tests until every code -path is tested or explained, live tests for the remaining cmdlets, and -test-first fixes of the known defects. The maintainer approved it on -2026-10-08. Then Phase 3 and 5.0.0; after 5.0.0 the repository is archived -in favor of WindowsAccessControl (Decision 18). +Phase 2 of the quality gate before 5.0.0 (Decision 21) is complete on the +local branch `ai/release-5.0.0-rc6`, candidate `7b0781f`. The maintainer +pushes the branch, merges the pull request after CI, and tags 5.0.0-rc6. +Then Phase 3 (live tests on more operating systems) and 5.0.0; after +5.0.0 the repository is archived in favor of WindowsAccessControl +(Decision 18). ## Evidence -- 2026-10-08, Phase 1, measured on 5.0.0-rc5 (`fcb370e`): - - The published package passes the live tests in both editions: 8 role - runs, no failure. - - As a basic user, the 11 tests that CI skips pass in both editions. The - one failure, `Enable-Privileges should write one object per - privilege`, assumes more than one privilege. Every test runs in at - least one of four configurations (elevated or basic user, two - editions), but CI runs only elevated. - - The suite runs 55.9% of the C# lines and 37.4% of the branches - (`techContext.md`, Validation). No line of `Test-Path2` and - `Get-DiskSpace` runs; `Set-NTFSOwner` (46%) runs only as a setup step - of another test; `Clear-NTFSAccess` and the access inheritance cmdlets - run about 43%, `FileSystemSecurity2` 42%. No cmdlet calls the registry - classes, `SimpleFileSystemAuditRule`, `PrivilegeEnabler`, or - `FileSystemEffectivePermissionEntry` (244 lines). - - 19 of the 36 cmdlets never ran over SMB, among them `Get-NTFSOwner`, - `Set-NTFSOwner`, the audit inheritance cmdlets, and `Clear-NTFSAudit`; - no account of another domain or forest ran; both ends of the lab run - Windows Server 2025. -- Known defects from the reviews of #113 and #114 (`progress.md`, open - work 3): `Move-Item2 -PassThru` returns the source item; the conflict - checks of `Copy-Item2` and `Move-Item2` use `File.Exists` also for - folders, maybe the cause of #21; an error while restoring the owner can - hide the original one (R4); `Set-NTFSSecurityDescriptor -PassThru` reads - the item again inside the retry (R5); the access check doesn't read - `AUTHZ_ACCESS_REPLY.Error`, and its buffers aren't initialized. #110 - lists seven test follow-ups. -- #34: no reply from the tester by 06:44 UTC on 2026-10-08. -- Phase 2, step 1, first part (2026-10-08, commits `82969ba` to - `ff74100`): 34 new tests for `Set-NTFSOwner`, `Test-Path2`, and - `Get-DiskSpace`, and two defects found and fixed test-first. Every - cmdlet that enables privileges left the Backup, Restore, Take Ownership, - and Security privileges enabled in the session when a later command or a - terminating error stopped the pipeline; `Test-Path2` stopped with - "Illegal characters in path" in Windows PowerShell for a path such as - `C:\a|b`. -- Phase 2, step 1, link cmdlets (2026-10-08, `4d5c8c4`, `09eb337`): 18 new - tests for `New-NTFSHardLink`, `Get-NTFSHardLink`, and - `New-NTFSSymbolicLink` pass elevated and as a basic user in both - editions; no code defect. The page of `New-NTFSSymbolicLink` was wrong - twice: `-PassThru` returns a folder object for a link to a folder since - 5.0.0, and Windows Developer Mode doesn't help, because AlphaFS 2.2.1 - passes only the File or Directory flag to `CreateSymbolicLinkW`. Lab - check on `F1AFile1` as `NtfsLiveServerAdmin` (no administrator): - with Developer Mode on, `mklink` created a link and the cmdlet of - 5.0.0-rc5 failed with error 1314; the setting was restored. -- Security review of `fcb370e..00c3646` (`security-reviewer`, 2026-10-08): - the `Dispose` approach is sound; two Major findings, both one root cause - that 4.2.6 already had: the privilege cleanup decided on the states read - in `BeginProcessing` and stopped at the first failure. Reproduced: a - privilege that another command in the pipeline disabled left the others - enabled (silently after an early stop), and - `Get-NTFSOwner ... | ForEach-Object { Disable-Privileges; $_ }` stopped - with "Priviledge already disabled". Two Minor findings: the early-stop - tests could pass vacuously, and `Test-Path2` gave no reason for `$false`. - The maintainer chose to fix all four; fixed test-first in `578042f` and - `b241441`. The suite (555 tests) passes elevated in both editions - (534/0/21 and 504/0/51), and the changed test files pass as a basic user. +- 2026-10-08, Phase 2 on `ai/release-5.0.0-rc6`, 31 commits on `fcb370e` + (5.0.0-rc5); the candidate is `7b0781f`: + - The suite has 684 tests. Elevated: 662 passed and 22 skipped in + Windows PowerShell 5.1, 632 and 52 in PowerShell 7. As a basic user + through `Invoke-TestsAsBasicUser.ps1`: 590 and 94, 560 and 124. No + failure, and no test is skipped in all four configurations; CI runs + all four since this branch. + - C# coverage of all four configurations (AltCover without `--save`, + `techContext.md`): 68.1% of the lines and 44.3% of the branches on + `1b9edbb`; rc5 58.1% and 38.0%. The earlier figures counted one of + the four runs. Of the 972 points that no test ran at `e2b6b24` + (without the classes that no cmdlet calls), 400 are code that nothing + calls, 107 defensive guards, 74 need a failure of Windows, 4 need the + lab, and 387 are reachable; 51 of those ran in runs that the first + measurement missed, and the top items of the rest are in + `progress.md`, open work 7. + - Fixed test-first: `Get-NTFSSimpleAccess` (`ReadData`, the parent of a + relative path); `Copy-Item2` and `Move-Item2` (a folder at the + destination, the missing destination folder of #21, also with + `-WhatIf`); the hard-link cmdlets on shares and at folders; + `Set-NTFSSecurityDescriptor -PassThru` (R5); the error ID of + `Get-NTFSOrphanedAccess`; relative paths that start with a dot, which + every cmdlet shortened by two characters (`Remove-Item2 .x` removed + another item); comparing entries and descriptors + (`InvalidCastException`, also `Compare-Object` in PowerShell 7) and + their conversions; `InheritedFrom` with `-ExcludeExplicit` and for a + descriptor with audit entries (`ArgumentOutOfRangeException`). + `Copy-Item2` no longer creates the missing folders of a destination + for a folder (assumption, flagged for the maintainer). + - Live tests: cases 4b to 9 and accounts of `b.forest1.net`, + `forest2.net`, and `forest3.net`. The lab acceptance passed for + `acfe3af`, `1b9edbb`, and `7b0781f` (326 tests each, none failed; + `Tests/Lab/Acceptance-2026-10-08-5.0.0-rc6.md`). Baseline: the + published 5.0.0-rc5 fails only the two hard-link tests of case 8. The + fixture was removed and the removal checked after each run; three + checkpoints `ntfs-rc6-*-before-acceptance` stay on six machines. + - `Get-NTFSEffectiveAccess -ServerName` needs administrators or + Access Control Assistance Operators on the named computer (lab probe, + documented). + - Two `security-reviewer` passes approved the branch with no Blocker or + Major finding: `fcb370e..e2b6b24` (findings 1, 4, 5, 10 fixed in + `acfe3af`) and `e2b6b24..1b9edbb` (findings 1, 2, 6, 7 fixed in + `7b0781f`). Not fixed: a failed privilege disable isn't tried again, + and a non-qualified ACE could shift `InheritedFrom` (neither + reproducible); `New-NTFSHardLink` stays terminating for a folder (a + behavior change for the maintainer). +- #34: no reply from the tester since 2026-10-06. ## Next step -Phase 2, one step at a time, each with evidence before the next: - -1. Tests for the cmdlets without tests of their own: done for - `Set-NTFSOwner`, `Test-Path2`, `Get-DiskSpace`, and the link cmdlets; - open for `Get-NTFSOrphanedAudit` and `Get-NTFSSimpleAccess`. -2. The other parameter sets and error paths, such as the - `-SecurityDescriptor` sets of the inheritance cmdlets and of - `Clear-NTFSAccess`. -3. The paths of `Security2` that no test runs, and #110. -4. Test-first fixes of the known defects; behavior changes go to the - maintainer (Decision 16). -5. A CI job as a basic user, live tests for the other cmdlets over SMB and - for accounts of other forests, and a lab run. -6. Measure the coverage again, explain what remains, review, and prepare - 5.0.0-rc6. The final review covers the whole branch, including the fix - round of `578042f` and `b241441`. - -Open question for the maintainer, not planned: `New-NTFSSymbolicLink` -could request unprivileged creation with -`SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`, so that Developer Mode -works. That is a behavior change (Decision 16) and needs a fallback for -Windows versions before 10 1703, which don't know the flag. +1. The maintainer pushes the branch, opens the pull request, merges it + after CI, and tags `5.0.0-rc6`; then the live tests run against the + published package (`-Version 5.0.0-rc6`). The first CI run is the first + run of `Invoke-TestsAsBasicUser.ps1` on a GitHub runner. +2. The maintainer decides the behavior changes in `progress.md`, open + work 4 (Decision 16), and the scope of Phase 3: the operating systems, + the code that nothing calls, and file servers that aren't Windows + (#34). diff --git a/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md b/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md index d32a8d7..5664903 100644 --- a/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md +++ b/.memory-bank/decisions/0021-quality-gate-before-5.0.0.md @@ -28,7 +28,9 @@ source: maintainer decision of 2026-10-08 of the matrix. - Rationale: rc5 passed every test that ran, but the tests ran 55.9% of the code lines and 37.4% of the branches; five cmdlets had no tests of - their own, and 19 cmdlets never ran over SMB. + their own, and 19 cmdlets never ran over SMB. (That measurement counted + only one of the four test runs; with all four, rc5 runs 58.1% of the + lines and 38.0% of the branches, see `techContext.md`.) - Open: behavior changes found on the way stay the maintainer's decision (Decision 16); so do the 244 lines of classes that no cmdlet calls, the operating systems of Phase 3, and how to cover file servers that aren't diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index c9435e0..435d20f 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -11,13 +11,13 @@ source: repository evidence 5.0.0-rc5 is on the PowerShell Gallery and in the GitHub releases, published by CI on 2026-10-08 from the tag `5.0.0-rc5` on `master` -(`fcb370e`, the merge of #114; Decision 12). It adds to 5.0.0-rc4 the live -tests in a lab (Decision 20) and the fix of -`Get-NTFSEffectiveAccess -ServerName` that they found. Before 5.0.0, the -maintainer wants the highest quality with everything tested: the quality -gate of Decision 21, now in Phase 2, which ends with 5.0.0-rc6. The stable -Gallery version is still 4.2.6. NTFSSecurity will be archived soon; its -users move to WindowsAccessControl (Decision 18). +(`fcb370e`, the merge of #114; Decision 12). Phase 2 of the quality gate +(Decision 21) is complete on the local branch `ai/release-5.0.0-rc6`: the +candidate 5.0.0-rc6 (`acfe3af`) passed the suite in four configurations, +one `security-reviewer` pass, and the lab acceptance. It waits for the +maintainer to push, merge, and tag it; Phase 3 follows. The stable Gallery +version is still 4.2.6. NTFSSecurity will be archived soon; its users move +to WindowsAccessControl (Decision 18). ## Recent milestones @@ -83,6 +83,23 @@ users move to WindowsAccessControl (Decision 18). PowerShell; and, from one `security-reviewer` pass, the privilege cleanup decided on stale states, a defect since 4.2.6. The page of `New-NTFSSymbolicLink` was corrected after a lab check of Developer Mode. +- 2026-10-08: Phase 2 finished on `ai/release-5.0.0-rc6` (local). Tests for + `Get-NTFSOrphanedAudit`, `Get-NTFSSimpleAccess`, the + `-SecurityDescriptor` parameter sets, the error contracts of all path + cmdlets, and #110. Fixed test-first: `Get-NTFSSimpleAccess` (`ReadData`, + relative paths), `Copy-Item2` and `Move-Item2` (folder conflicts, the + missing destination folder of #21), the hard-link cmdlets on shares, + `Set-NTFSSecurityDescriptor -PassThru` (R5), and the error ID of + `Get-NTFSOrphanedAccess`; from the coverage report, relative paths that + start with a dot (every cmdlet acted on the item without the first two + characters), comparing output objects (`InvalidCastException`), and + `InheritedFrom`. CI runs the suite as a basic user too; the live tests + cover all cmdlet groups and accounts of three more domains. Suite: 677 + tests, none failed, none skipped in every configuration; C# coverage + 68.1% of the lines and 44.3% of the branches (rc5: 58.1% and 38.0%, + measured again; the first measurements counted one of four runs). Two + `security-reviewer` passes; the lab acceptance of `7b0781f` passed + (`Tests/Lab/Acceptance-2026-10-08-5.0.0-rc6.md`). ## Stable capabilities @@ -97,15 +114,20 @@ users move to WindowsAccessControl (Decision 18). ## Open work -1. Quality gate before 5.0.0 (Decision 21): Phase 2 on the branch - `ai/release-5.0.0-rc6` (`activeContext.md`), released as 5.0.0-rc6; - Phase 3 runs the live tests on more operating systems. Then release +1. Quality gate before 5.0.0 (Decision 21): Phase 2 is done on the branch + `ai/release-5.0.0-rc6` (`activeContext.md`); the maintainer pushes it, + merges the pull request, and tags 5.0.0-rc6, and the live tests run + against the published package. Phase 3 runs the live tests on more + operating systems. Then release 5.0.0 through CI (Decision 12): remove the label, date `[Unreleased]` as `[5.0.0]`, add the last prerelease to `$publishedVersions`, and tag `5.0.0` (steps in `Docs/Contributing/05-Releasing.md`). #34 stays open with Bug and Help Wanted until a tester with a file server that refuses the owner confirms the fix, or until 5.0.0 ships. -2. Issues: #110 (tests) is the open follow-up of the review findings; #68 +2. Issues: the rc6 branch addresses the seven items of #110 (tests); the + pull request names it without a closing keyword, so the maintainer + closes it after the merge. #21 (a misleading error of `Move-Item2`) got + a fix in rc6 that names the missing destination folder. #68 tracks `-WhatIf` and `-Confirm` for every cmdlet that changes security. The labels follow Decision 17; #16, #21, #45, and #89 wait for their reporters (Needs Info). Not planned for 5.0.0: the enhancements #22, @@ -119,11 +141,51 @@ users move to WindowsAccessControl (Decision 18). `AUTHZ_ACCESS_REPLY.Error`, a fallback warning without the server name, and hardening of the lab controller (guards in the setup blocks, interpolated `-EncodedCommand` paths, CredSSP by IP address, the - password string in memory, disabling the role accounts after a run). -4. `pwsh` 7.6.1 crashed three times during test runs on the ARM64 + password string in memory, disabling the role accounts after a run); of + rc6, a privilege that fails to be disabled isn't tried again by + `Dispose` (finding 2, not reproducible). +4. Behavior changes found in Phase 2, for the maintainer (Decision 16): + `Get-NTFSOrphanedAudit` returns nothing without the Security privilege, + while `Get-NTFSAudit` writes `ReadSecurityError`; + `Get-NTFSSimpleAccess` skips a folder whose parent it didn't process; + `New-NTFSSymbolicLink` could create links without the privilege in + Developer Mode (flag `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`, with + a fallback before Windows 10 1703); `-WhatIf` names a conflict in a + verbose message instead of a warning (R7); the fallback warning of + `Get-NTFSEffectiveAccess` doesn't name the server; `Move-Item2` can't + move a folder to another volume; `New-NTFSHardLink` stops with a + terminating error for a folder, unlike `Get-NTFSHardLink` (rc6 review, + finding 11). Taken as an assumption in rc6, for review: `Copy-Item2` + no longer creates the missing folders of a destination for a folder. + Found by the coverage report of rc6: `-Target` of the link cmdlets is + optional and means the current location when it's omitted; equality of + entries and descriptors is the identity of the wrapped .NET object, so + two reads of the same entry differ for `Compare-Object` and + `Select-Object -Unique` (value equality would be a behavior change); 400 + points of code that nothing calls besides the 244 lines of unused + classes (Phase 3). +5. `pwsh` 7.6.1 crashed three times during test runs on the ARM64 workstation (x64 emulation), without module frames; none of the CI runs on native x64 on 2026-10-05 crashed. -5. Optional for the maintainer: delete the AppVeyor project and revoke its +6. Optional for the maintainer: delete the AppVeyor project and revoke its GitHub authorization, restrict wiki editing to collaborators, ask `Sup3rlativ3` to delete the Read the Docs project, and delete the branch - `test/transfer`. + `test/transfer`. In the lab, delete the checkpoints + `ntfs-rc6-*-before-acceptance` of the six machines when they are no + longer needed. +7. Reachable code that no test runs (coverage report of rc6, ranked by + impact; about 300 points): `Remove-Item2` on folders (`-Recurse`, + `-Force`, `DeleteError`); the owner restore after taking ownership + (`RestoreOwnerError`); the inheritance cmdlets on folders and + `Set-NTFSInheritance -AccessInheritanceEnabled $true`; the mapping of + all 13 `-AppliesTo` values and the flag parameters of + `Remove-NTFSAccess`, `Add-NTFSAudit`, and `Remove-NTFSAudit`; the + switches and errors of `Get-ChildItem2`; the table views and + `InheritedFrom` in them; `Move-Item2 -Force`; account input errors; + `-PassThru` after success of the audit and inheritance cmdlets; + `Set-NTFSSecurityDescriptor` failures; the audit cmdlets without the + Security privilege on a local item; `Get-NTFSEffectiveAccess` for an + unresolvable SID; failed ownership retries of `Clear-NTFSAccess` and + `Set-NTFSInheritance`. A display limit, not a defect: a conditional ACE + shows as an unconditional entry, because the .NET rules have no + condition. diff --git a/.memory-bank/systemPatterns.md b/.memory-bank/systemPatterns.md index 44118f5..5b9208e 100644 --- a/.memory-bank/systemPatterns.md +++ b/.memory-bank/systemPatterns.md @@ -99,9 +99,20 @@ Each Decision record is a file in `decisions/`; read only the relevant ones. - A test that changes files, links, or security descriptors uses `Tests\TestHelpers.psm1`: its own sandbox, `Assert-TestSandboxPath` before each change, `Remove-TestSandbox`. Cases that need a privilege - skip with `Test-PrivilegeHeld` and run in CI (elevated). `Block-Test*` - make a read or a write fail without elevation; `Set-TestOwner` with + skip with `Test-PrivilegeHeld`, cases that need its absence skip when + elevated; CI runs the suite elevated and as a basic user in both + editions, so each case runs somewhere. `Block-Test*` make a read or a + write fail without elevation; `Set-TestOwner` with `EnablePrivileges = $false` reproduces an owner the user can't assign. +- Fixtures write a DACL with `SetAccessControl`, never with `Set-Acl`: + `Set-Acl` compares `AreAuditRulesProtected` of the new descriptor with + `AreAccessRulesProtected` of the item (`FileSystemSecurity.cs` of + PowerShell), so for an item with a protected DACL it writes the audit + section too. Without the Security privilege that fails with + `PrivilegeNotHeldException`; with it, `Set-Acl` writes every section and + drops the audit entries. Windows PowerShell has + `FileInfo`/`DirectoryInfo.SetAccessControl`; PowerShell 7 has + `[System.IO.FileSystemAclExtensions]::SetAccessControl`. - `Get-Help -Online` tests run only in Windows PowerShell, which honors the hook `BypassOnlineHelpRetrieval`. `Manifest.Tests.ps1` and `Release.Tests.ps1` check the manifest, the version (Decision 10), the diff --git a/.memory-bank/techContext.md b/.memory-bank/techContext.md index 84e6aaf..9b949e1 100644 --- a/.memory-bank/techContext.md +++ b/.memory-bank/techContext.md @@ -88,7 +88,8 @@ source: repository evidence ## Constraints -- `ModuleVersion` is `5.0.0` with the prerelease label `rc5`. +- `ModuleVersion` is `5.0.0` with the prerelease label `rc6` on the branch + `ai/release-5.0.0-rc6` (`rc5` on `master`). The latest stable tag and Gallery release is `4.2.6`. The manifest requires PowerShell 5.1 and .NET Framework 4.5.2, uses `RootModule`, and lists exactly 36 cmdlets; `Test-ModuleManifest` passes in Windows @@ -143,7 +144,9 @@ source: repository evidence then: 01 `Update-MarkdownHelp` and fail on `git diff -- Docs/Cmdlets`; 02 `Get-MarkdownLink -BrokenOnly`; 03 regenerate the help file and fail on `git status --porcelain -- NTFSSecurity/en-US`; 04 `Invoke-Tests.ps1` in - Windows PowerShell 5.1 and in PowerShell 7. Job `wiki` on `ubuntu-latest` + Windows PowerShell 5.1 and in PowerShell 7, then + `Invoke-TestsAsBasicUser.ps1` in both editions (since 5.0.0-rc6). Job + `wiki` on `ubuntu-latest` (read-only) clones the wiki (`gh auth setup-git` with the built-in token), runs `Export-WikiContent.ps1`, and lists the changed pages in the job summary; job `publish-wiki` (`contents: write`) repeats that and publishes, @@ -163,7 +166,8 @@ source: repository evidence ci.yml`, `gh pr checks `, and `gh run view --log-failed` (read-only). - Workflow lint: actionlint (download the release zip into `$env:TEMP` and - check its SHA-256 against the checksum file); PowerShell steps check + check its SHA-256 against the checksum file; 1.7.12 on 2026-10-08); + PowerShell steps check `$LASTEXITCODE` after every native command, because GitHub checks only the last one. - Run platyPS in Windows PowerShell 5.1 to avoid PowerShell 7.4+ @@ -175,25 +179,37 @@ source: repository evidence PowerShell 5.1: the launcher starts `pwsh`, and its payload runs `powershell.exe -NoProfile -EncodedCommand` with Pester imported by full path. A run without `bin\Release\en-US` must fail. -- Tests that run only without a privilege skip in CI and in an elevated - session. Run them as a basic user with `runas /trustlevel:0x20000`, and - give Windows PowerShell its own `PSModulePath`; that token holds one - privilege, so the `Enable-Privileges -PassThru` count test fails there. - `runas` returns at once, so the script it starts writes its own log. +- Tests that run only without a privilege skip in an elevated session. + `.github\scripts\Invoke-TestsAsBasicUser.ps1` runs the suite from an + elevated session with a token of the SAFER level Normal User, like + `runas /trustlevel:0x20000`, and CI runs it in both editions. For a + single file, `runas /trustlevel:0x20000` works too; give Windows + PowerShell its own `PSModulePath`, and note that `runas` returns at once, + so the script it starts writes its own log. Both tokens hold only the + privilege to bypass traverse checking. Pester reports a skipped `-ForEach` test under its template name, such as `<_> should ...`, and a test that ran under the expanded name: compare runs by template. - C# coverage (Decision 21): AltCover 9.0.145 (`tools\net472\AltCover.exe` of the nuget.org package) instruments a copy of the local Release build, - which has the PDB files that the published package lacks: `--save`, + which has the PDB files that the published package lacks: `--reportFormat=OpenCover`, AlphaFS and `System.Management.Automation` - excluded with `--assemblyFilter`. Put the instrumented module in - `NTFSSecurity\bin\Release` of a `git worktree`, run - `.github\scripts\Invoke-Tests.ps1` elevated and as a basic user in both - editions, then `AltCover.exe runner --collect --recorderDirectory=`. Baseline of the rc5 tree on 2026-10-08: 55.9% of - the lines (1,943 of 3,476), 37.4% of the branches (700 of 1,873); 60.1% - of the lines without 244 lines in classes that no cmdlet calls. + excluded with `--assemblyFilter`, and no `--save`: then every process + writes its hits into the report when it exits. With `--save`, each + process writes a recorder file, and `runner --collect` keeps only the + first one (verified 2026-10-08), so the numbers measured that way held + only the main process of the elevated Windows PowerShell run. Put the + instrumented module in `NTFSSecurity\bin\Release` of a `git worktree`, + run `.github\scripts\Invoke-Tests.ps1` elevated and + `Invoke-TestsAsBasicUser.ps1` in both editions, then + `AltCover.exe runner --collect --recorderDirectory=`, which recalculates the summary of the report from the hits. + All four configurations, 2026-10-08: the rc5 tree 58.1% of the lines + (2,020 of 3,476) and 38.0% of the branches (711 of 1,873), 62.5% without + 244 lines in classes that no cmdlet calls; the rc6 candidate (`1b9edbb`) + 68.1% of the lines (2,412 of 3,540) and 44.3% of the branches (850 of + 1,918), 73.2% without those classes, the `NTFSSecurity` assembly 78.1%. + The earlier figures, 55.9% for rc5 and 65.6% for rc6, used `--save`. - Live tests (Decision 20): in an elevated Windows PowerShell 5.1 session on the lab host, `Tests\Lab\Invoke-NTFSSecurityLabTest.ps1` with `-Version` for Gallery packages or `-ModulePath` for a build; it writes @@ -204,6 +220,20 @@ source: repository evidence (Remote Management Users on the client, CredSSP by IP address like the controller): reset its password on the PDC emulator to a random value in memory; the next run of the controller sets a new one anyway. +- Lab acceptance of a candidate (modeled on the WindowsAccessControl + handoff 07): build once, package it with `New-ModulePackage.ps1`, and + record the SHA-256 of the packages and module files; check WinRM, LDAP + (RootDSE), Kerberos (`klist get`), the secure channel, and the clock of + the six VMs; take a Production checkpoint named + `ntfs-