From f11ff412947b35d682878ac4a8121c949868fcb2 Mon Sep 17 00:00:00 2001 From: Raimund Andree Date: Fri, 9 Oct 2026 10:09:33 +0000 Subject: [PATCH] chore(memory-bank): record quality-gate evidence and release status Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: AI Assistant --- .memory-bank/activeContext.md | 103 +++++---- .memory-bank/progress.md | 288 +++++++++---------------- .memory-bank/systemPatterns.md | 148 +++++-------- .memory-bank/techContext.md | 375 ++++++++++++--------------------- 4 files changed, 341 insertions(+), 573 deletions(-) diff --git a/.memory-bank/activeContext.md b/.memory-bank/activeContext.md index 2ad5297..52c5dab 100644 --- a/.memory-bank/activeContext.md +++ b/.memory-bank/activeContext.md @@ -1,6 +1,6 @@ --- status: current -last-verified: 2026-10-08 +last-verified: 2026-10-09 owner: active-agent source: current task evidence --- @@ -9,62 +9,57 @@ source: current task evidence ## Current focus -5.0.0-rc6 is on the PowerShell Gallery (tag `5.0.0-rc6` on `b51d970`, the -merge of #115); its GitHub release waits for a rerun of the failed Release -job. #116 (`ai/release-5.0.0-rc7`, base `master`) holds the behavior -changes that Phase 2 found, decided as assumptions for the maintainer's -review (Decision 22), and waits for that review. Then 5.0.0-rc7, Phase 3, -and 5.0.0; after 5.0.0 the repository is archived in favor of -WindowsAccessControl (Decision 18). +Quality-gate follow-up is implemented and validated locally on +`ai/quality-gate-coverage`, based on `d25647d` of #116. Code/test baseline +`3442194`, lab regression/acceptance `7594e0c`; final records follow. +No remote mutation. Architecture/cmdlet-design choices remain deferred; +Decision 22 is still proposed. Stable 5.0.0 is not ready (Decision 21). ## Evidence -- 2026-10-08, 5.0.0-rc6: the Release job of the tag (run `37839669028`) - published the package at 20:40 UTC and failed after it, because - `Publish-PSResource` gave up waiting after 100 seconds and its retry got - 409 (`progress.md`, open work 8). The live tests of rc7 ran with - `-Version 5.0.0-rc6`, which checks the hash of the Gallery, in both - editions, 20:43 to 21:00 UTC: all passed except the warning text that - rc7 changed, which matches the live tests of rc6. The fixture was - removed at 21:03 UTC and its removal checked. -- 2026-10-08, #116, 11 commits on `be04cb7` (`3899228` to `1063b29`) and - commits of records: - - Decision 22: items 1, 2, 5, 6, 7, and 8 changed, 7 and 8 breaking (the - link cmdlets require `-Path` and `-Target` and write non-terminating - errors); items 3, 4, 9, and 10 kept, 9 with an FAQ entry. New defects, - fixed with a regression test that failed first: `Move-Item2` deleted - an empty folder that it moved to another volume (AlphaFS emulated the - move); the link cmdlets failed with `GetDefaultValueFailed` for every - piped object; `Get-NTFSSimpleAccess` failed for a folder that came - after its parent folder a second time. - - One `security-reviewer` pass over `be04cb7..4ee01e5`: no Blocker or - Major. Minor 1 to 5 and Nits 7 to 9 fixed test-first in `7936d9f` to - `1063b29`; Nit 7, the warning of `Get-NTFSEffectiveAccess` for names - of this computer, was reproduced first. Nit 6 declined (Decision 22). - - Suite of `1063b29`: 712 tests. Elevated: 688 passed and 24 skipped in - Windows PowerShell 5.1, 658 and 54 in PowerShell 7. As a basic user: - 612 and 100, 582 and 130. No failure, none skipped in all four. - - Lab acceptance of `dc6e9f5` after the checkpoint - `ntfs-rc7-dc6e9f5-before-acceptance`, 16:24 to 16:40 UTC: 326 tests in - both editions, none failed, 2 skipped as in rc6 - (`Tests/Lab/Acceptance-2026-10-08-5.0.0-rc7.md`). The code of - `4ee01e5` and a first run of `dc6e9f5` without the checkpoint had the - same counts. The fixture was removed at 16:21 and 16:44 UTC, and its - removal checked each time. -- #115 passed CI in all four configurations on `be04cb7`, with the first - runs of `Invoke-TestsAsBasicUser.ps1` on GitHub runners; #116 passed CI - on `ebe91fe` against the rc6 branch. -- #34: no reply from the tester since 2026-10-06. +- rc6 Release run `37839669028`, attempt 2, succeeded; GitHub prerelease + with zip appeared 2026-10-09 07:01:34 UTC. First attempt proves HTTP 409 + after Gallery publication, not the previously assumed retry chronology. +- #116 is open, base master, head `d25647d`, CI build/wiki passed. rc7 + publication is pending. The follow-up does not change that PR's head. +- Local changes: deletion/ownership guards (`a97e46f`); all scopes and + inheritance (`e7ee203`); absolute basic-user results (`51dec86`); + exact-package publication recovery (`95b827e`); first-hidden-item fix + (`d610372`); Force/descriptor guards (`3442194`); SMB regression above. +- Hidden omission was reproduced in all four configurations before the + fix. No parameter/design change. Publication tests are wholly mocked; + exact ordinal SHA-512 identity is required, no real upload occurred. +- Final uninstrumented suite: 914 each, zero failed. Passed/skipped: + elevated Desktop 890/24, Core 860/54; basic Desktop 749/165, Core 719/195. + Frozen aggregate: 2,641/3,559 sequence (74.21%), 974/1,933 branches + (50.39%); NTFSSecurity assembly 84.28%. All skipped templates have + executed counterparts; mutations restored exactly before green builds. +- Live packaged candidate, 09:20 to 09:51 UTC: 330 passed, zero failed, + two expected Server-module skips. Published rc6: 326 passed, four + expected failures (Hidden and rc7 warning text in each edition), two + skips. Tested folder and all 11 ZIP files are byte-identical. +- Temporary host result verifier failed on Desktop JSON wrapping/full + test names; corrected verification passed on unchanged raw results in + both editions. Cleanup wrapper's broad Error.Count was not acceptance + proof. Independent probes verified all fixture objects/members/profiles + gone from six machines. Raw failing markers and corrected evidence kept. +- One read-only independent code review approved, high confidence, no + significant findings or confirmed exploit. Custom reviewer could not + start (model unavailable); built-in code-review performed the one pass. +- Six checkpoints exist but report Standard, even after a successful + temporary ProductionOnly probe; policy restored, no restore performed. + Do not claim verified Production rollback evidence. +- Wider matrix not deployed: 13 Server 2025 VMs; Windows 11/2019/2022 + media present, OS detection cache empty. #34 has no reply since Oct 6. +- Full evidence: session artifact `quality-gate-3442194-20261009`; + repository report `Tests/Lab/Acceptance-2026-10-09-quality-gate.md`. ## Next step -1. The maintainer reruns the failed Release job of 5.0.0-rc6, which skips - the published package and creates the GitHub release, and closes #110. -2. He pushes the records to #116 and reviews the choices of Decision 22, - each its own commit, above all the two breaking changes of the link - cmdlets. After the CI of the push, he merges #116 with a merge commit - (Decision 15) and tags `5.0.0-rc7`; the live tests then run against the - published package (`-Version 5.0.0-rc7`). -3. He decides the fix of the publish step (`progress.md`, open work 8) and - the scope of Phase 3: the operating systems, the code that nothing - calls, and file servers that aren't Windows (#34). +1. Maintainer pushes/reviews this follow-up; retain separate commits and + stacked-PR merge order (15). #116's Decision 22 review remains required. +2. Integrate and pass CI, then publish/test the next candidate package. +3. Close the remaining-path inventory (918 points, 562 for finer review), + decide/provision the OS matrix, obtain or explicitly accept #34 feedback. +4. Only then release 5.0.0 through documented CI steps; never claim the + current coverage percentage alone meets the quality gate. diff --git a/.memory-bank/progress.md b/.memory-bank/progress.md index 72b5f84..15a0f01 100644 --- a/.memory-bank/progress.md +++ b/.memory-bank/progress.md @@ -1,203 +1,121 @@ --- status: current -last-verified: 2026-10-08 +last-verified: 2026-10-09 owner: active-agent -source: repository evidence +source: repository and validation evidence --- # Progress ## Current status -5.0.0-rc6 is on the PowerShell Gallery, published by CI on 2026-10-08 at -20:40 UTC from the tag `5.0.0-rc6` on `master` (`b51d970`, the merge of -pull request #115; Decision 12). The Release job failed after the upload, -so the GitHub release waits for a rerun of the failed job. The published -package passed the live tests. Phase 2 of the quality gate (Decision 21) -is complete. The pull request #116 (`ai/release-5.0.0-rc7`) holds the -behavior changes that Phase 2 found, decided as assumptions for the -maintainer's review (Decision 22), and waits for that review. Phase 3 -follows. The stable Gallery version is still 4.2.6. NTFSSecurity will be -archived soon; its users move to WindowsAccessControl (Decision 18). +5.0.0-rc6 is published on the Gallery and GitHub; its failed Release job +recovered in attempt 2 on 2026-10-09. #116 (rc7, `d25647d`, base `master`) +is open and green, not merged or published. Further quality-gate work is +local on `ai/quality-gate-coverage`; Phase 2 is not complete while the +remaining-path inventory is open. Stable Gallery version: 4.2.6. +After 5.0.0, archive in favor of WindowsAccessControl (Decision 18). ## Recent milestones -- 2026-10-02 to 2026-10-04: #91 to #97 aligned the docs with the code, - shipped the help file, kept the docs on GitHub, set version 5.0.0, moved - CI and a wiki generated from `Docs` to GitHub Actions, and completed the - version history (Decisions 6 to 11). -- 2026-10-04: #98 (`e0f5366`) added releases on a version tag through CI - (Decision 12). The tag `5.0.0-rc1` published to the Gallery and created - the GitHub prerelease; the installed module passed the full suite. -- 2026-10-05, overnight run: the 24 code defects of work package 5 and the - issues #3, #4, #5, #17, #74, #82, #86, and #88 fixed with regression - tests, plus what one security review per PR found; the 37 open issues - triaged; `Docs/FAQ.md`, Dependabot for the actions, and the label `rc2`. - #5 and #82 are breaking changes, like the change of Decision 13. -- 2026-10-05: the first CI runs of the eight PRs found a defect that the - workstation had skipped, fixed in `629f4e7` (audit inheritance of an item - without a SACL). The PRs #99 to #106 were merged in order with merge - commits, CI on `master` passed, and the tag `5.0.0-rc2` published the - prerelease; GitHub's Actions outage that day cancelled the first two - attempts of the release run before they started. Repository hardening is - optional (Decision 14); the merge rule and the maintainer's rule for - fixes are Decisions 15 and 16. -- 2026-10-06: the issues got their labels (Decision 17). The maintainer - decided to publish 5.0.0-rc3 before 5.0.0 and to archive the project in - favor of WindowsAccessControl (Decision 18); the README, the docs home, - and the changelog announce it. -- 2026-10-06: 5.0.0-rc3 (#112): the access and audit cmdlets write only - the section that they change, which fixes #34 and the inherited entries - that elevated sessions copied as explicit ones (Decision 19). #67 has its - cause outside the module (a share root over UNC can't re-inherit), is - explained in `Docs/FAQ.md`, and was closed as not planned. One - `security-reviewer` pass approved the branch. The PR description said - "fixes #34", so the merge closed #34; it was reopened for a tester. -- 2026-10-06: 5.0.0-rc4 (#113), test-first: drive and volume roots read - and change their root folder, not the device (#41); the audit cmdlets - reject a descriptor without the audit entries (#109); `-WhatIf` previews - `Copy-Item2` and `Move-Item2` despite an existing destination (#108); - small items (#111). One `security-reviewer` pass approved it; its Minor - findings R1, R2, R6, and R8 were fixed before the merge. #41, #108, - #109, and #111 closed as completed, #90 and #107 as not planned. -- 2026-10-07: live tests in the lab of WindowsAccessControl (Decision 20) - against 5.0.0-rc2 and 5.0.0-rc4 in both editions: rc2 fails #34 over SMB - with error 1307 for `Add-NTFSAccess`, `Clear-NTFSAccess`, and - `Set-NTFSSecurityDescriptor`; rc4 passes the four cases, except - `Get-NTFSEffectiveAccess -ServerName` with a computer that can't be - reached, which returned no access since before rc1. The maintainer chose - to fix it test-first in 5.0.0-rc5; the branch build passes all live tests - and the suite. One `security-reviewer` pass approved it with minor - findings (`activeContext.md`). -- 2026-10-08: #114 merged (`fcb370e`); the tag `5.0.0-rc5` published it to - the Gallery and the GitHub releases, whose `NTFSSecurity.zip` holds the - same 11 files. Phase 1 of the quality gate (Decision 21) measured rc5: - the published package passes the live tests in both editions; the 11 - tests that need a session without the Security privilege pass as a basic - user, so every test runs in at least one configuration, but CI runs only - elevated; the suite runs 55.9% of the C# lines and 37.4% of the branches. - The maintainer approved Phase 2. -- 2026-10-08: Phase 2, step 1 on `ai/release-5.0.0-rc6` (local): tests for - `Set-NTFSOwner`, `Test-Path2`, `Get-DiskSpace`, and the link cmdlets - (suite: 555 tests). Fixed test-first: the privileges stayed enabled after - an early stop; `Test-Path2` stopped for invalid characters in Windows - 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`). -- 2026-10-08: #115 (rc6, head `be04cb7`) passed CI in all four - configurations. On `ai/release-5.0.0-rc7` (local), the behavior changes - of Phase 2 were decided as assumptions for review (Decision 22) and - implemented test-first, two of them breaking (the link cmdlets); new - defects found on the way: `Move-Item2` deleted an empty folder that it - moved to another volume, the link cmdlets failed for every piped object, - and `Get-NTFSEffectiveAccess` warned for names of this computer. One - `security-reviewer` pass (no Blocker or Major; its findings fixed but - one, declined). Suite and lab acceptance in `activeContext.md`. -- 2026-10-08: #115 merged (`b51d970`) and tagged `5.0.0-rc6`. The Release - job published the package at 20:40 UTC, then failed: `Publish-PSResource` - gave up waiting after 100 seconds while the Gallery accepted the upload, - and its retry got 409, so the job didn't create the GitHub release. The - published package passed the live tests of rc7 in both editions except - the one test whose expected warning text rc7 changed - (`Tests/Lab/Acceptance-2026-10-08-5.0.0-rc6.md`, After the release). - #116 (5.0.0-rc7) was opened on the rc6 branch and moved to `master`. +- 2026-10-02 to 2026-10-06: documentation/help aligned with source, CI and + wiki moved to GitHub Actions, versioning/release automation established, + and prereleases rc1 to rc4 published. Earlier detail is in git, + `CHANGELOG.md`, `Docs/Version-History.md`, and Decisions 1 to 19. +- 2026-10-07: lab comparison of rc2/rc4 reproduced #34 over SMB and proved + changed-section writes preserve the owner. Remote effective-access + fallback returned no result; fixed test-first for rc5 (Decision 20). +- 2026-10-08: #114 merged (`fcb370e`), rc5 published and live-tested. + Decision 21 established the quality gate. Corrected four-run coverage: + rc5 58.1% sequence points/38.0% branches, not the initial one-run result. +- 2026-10-08: rc6 Phase 2 added basic-user CI, parameter-set/error tests, + expanded domain/SMB cases, and fixes for privilege cleanup, path + resolution, ownership retries, item conflicts, output equality, and + inherited flags. Suite: 677; coverage 68.14% sequence/44.32% branches. + Lab acceptance of `7b0781f` passed; two independent review passes. +- 2026-10-08: rc7 implemented proposed Decision 22, including breaking + link binding/error changes, SimpleAccess traversal, cross-volume folder + preservation, and named effective-access warnings. Suite: 712, no + failures or test skipped everywhere. One review: no Blocker/Major. + Lab candidate `dc6e9f5`: 326 passed, 2 skipped, cleanup verified. +- 2026-10-08: #115 merged (`b51d970`) and tagged rc6. Release run + `37839669028` failed with HTTP 409 after Gallery publication. The log + does not establish the previously assumed initial timeout/retry cause. + Published rc6 live tests differed only in rc7's warning expectation. +- 2026-10-09: release attempt 2 succeeded; rc6 GitHub prerelease and zip + appeared at 07:01:34 UTC. #116 passed CI on `d25647d`. +- 2026-10-09: autonomous follow-up on `ai/quality-gate-coverage`, through + `3442194`, adds 202 cases above rc7: deletion/owner failures, all 13 + scopes, inheritance transitions, enumeration, forced replacement, + descriptor failures, and offline CI recovery. Reproduced/fixed rooted + result-path handling and first-hidden-item omission. Publication recovery + verifies exact SHA-512 identity, not merely version existence. +- 2026-10-09: final uninstrumented suite: 914 per configuration, zero + failures; coverage: 2,641/3,559 sequence points (74.21%) and 974/1,933 + branches (50.39%), aggregate of four runs without AltCover `--save`. + All skipped templates have executed counterparts. Mutation guards were + proved and production source restored; Release build/checks pass. +- 2026-10-09: live comparison, 09:20 to 09:51 UTC: candidate 330 passed, + zero failed, two expected skips; published rc6 four expected Hidden/ + warning-text failures only. Independent cleanup probes verified fixture + absence; raw host-verifier failures retained with corrected verification. + Lab guards/acceptance committed in `7594e0c`. One independent code review + approved with no significant finding (custom model unavailable; built-in + fallback). All 11 tested files match the ZIP. OS/path gates stay open. ## Stable capabilities -- 36 cmdlets: access (7), audit (5), inheritance (6), owner and security - descriptor (4), privileges (3), long-path items (6), links, hash, and - disk space (5). -- Works in Windows PowerShell 5.1 and PowerShell 7. In PowerShell 7, - `Get-FileHash2` lacks `RIPEMD160` and `MACTripleDES`, which .NET lacks. -- Pester tests in `Tests\` run in `$env:TEMP` sandboxes through - `Tests\TestHelpers.psm1`; tests that need privileges skip without them - and run in CI, whose runners are elevated. +- 36 cmdlets: access, audit, inheritance, owners/descriptors, privileges, + long-path items, links, hash, and disk space. +- Windows PowerShell 5.1 and PowerShell 7; RIPEMD160 and MACTripleDES are + available only in Desktop. Both editions run elevated/basic-user in CI. +- Pester fixtures use `Tests/TestHelpers.psm1` TEMP sandboxes. Live tests + are excluded from CI and run only on approved lab client/server targets. ## Open work -1. Quality gate before 5.0.0 (Decision 21): the maintainer reruns the - failed Release job of 5.0.0-rc6, which creates the GitHub release; - reviews the choices of Decision 22 in #116; merges #116 and tags - 5.0.0-rc7, whose published package then runs the live tests. 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: 5.0.0-rc6 addresses the seven items of #110 (tests); #115 - named it without a closing keyword, so the maintainer closes it now. - #21 (a misleading error of `Move-Item2`) got - a fix in rc6 that names the missing destination folder; the folder - moves to another volume that rc7 fixes are a different defect. #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, - #49, #68, #77, #87. -3. Review findings, not filed: of rc3, an extra DACL read and four SDDL - snapshots on read paths, and a duplicate SACL check; of rc4, R3 to R5, - R7, and five older defects, listed in the description of #113, among - them the accounts filter that `RemoveFileSystemAccessRuleAll` and - `RemoveFileSystemAuditRuleAll` ignore, which no cmdlet passes; of rc5, - the bare `catch` in `Win32.GetEffectiveAccess`, the unchecked - `AUTHZ_ACCESS_REPLY.Error`, 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); of rc6, a privilege that fails to be disabled isn't tried - again by `Dispose` (finding 2, not reproducible); of rc7, one error ID - for a missing path in the audit cmdlets (declined, Decision 22). -4. Behavior changes found in Phase 2 (Decision 16): decided in Decision 22 - as assumptions for the maintainer's review, on `ai/release-5.0.0-rc7`; - two of them are breaking changes of the link cmdlets. Left for Phase 3: - 400 points of code that nothing calls besides the 244 lines of unused - classes. -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. -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`. In the lab, delete the checkpoints - `ntfs-rc6-*-before-acceptance` and `ntfs-rc7-*-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. -8. The publish step of the Release job fails when `Publish-PSResource` - gives up waiting after 100 seconds while the Gallery accepts the - package, because its retry gets 409 (5.0.0-rc6). Proposed for the - maintainer (Decision 16, not reproducible on demand; he was asked on - 2026-10-08 and didn't answer, so it stays open): treat the error as - success when `Find-PSResource` then lists the version, in a script with - Pester tests. Until then, rerun the failed job. +1. Decision 21 gate: review Decision 22, integrate reviewed quality-gate + follow-up, publish the next candidate, and test the published package. + Do not release 5.0.0 until the remaining-path and OS-matrix gates close. + Release steps: `Docs/Contributing/05-Releasing.md`; remove prerelease + label, date `[5.0.0]`, update `$publishedVersions`, tag through CI. +2. Issues: #110's seven items were addressed by rc6, but #115 deliberately + used no closing keyword. #34 stays open for non-Windows owner feedback + or maintainer acceptance. #16, #21, #45, #89 await reporters. #68 tracks + ShouldProcess for security cmdlets; enhancements #22/#49/#68/#77/#87 + are not planned for 5.0.0. Labels follow Decision 17. +3. Deferred reviews (not silently accepted): rc3 extra DACL read/SDDL + snapshots/duplicate SACL check; rc4 findings listed in #113, including + library-only RemoveAll account filters; rc5 unchecked Authz errors and + lab-controller hardening; rc6 failed privilege-disable retry (not + reproduced); rc7 audit missing-path error IDs declined in Decision 22. +4. Architecture/cmdlet design: Decision 22 remains proposed; two link + changes are breaking. Keep unused classes/helper overloads until a + maintainer decision; do not remove them to improve coverage percentages. +5. ARM64 workstation: PowerShell 7.6.1 crashed under x64 emulation without + module frames; native-x64 CI did not reproduce it. +6. Optional maintainer cleanup: obsolete AppVeyor/Read the Docs access, + wiki editing restrictions, `test/transfer`, and old lab checkpoints + when no longer needed. No remote changes or snapshot restores here. +7. Fresh coverage inventory at `3442194`: 918 unvisited sequence points. + Of these, 244 are in classes unused by cmdlets and 112 in parameter + getters; 562 remain for finer review/testing, including unused overloads, + defensive/native failures, and environment-specific branches. High-value + local gaps closed: folders/Force/DeleteError, RestoreOwnerError, all + scopes, file/folder inheritance, enumeration/depth/link skipping, + descriptor write failures, and forced file replacement. Remaining + candidates: audit ownership-retry failures, SD inheritance edge cases, + effective-access unresolved identity, recursive denial/error surfaces, + output-object comparisons/formatting. A conditional ACE display remains + a .NET representation limit, not evidence of unconditional permissions. +8. Publication recovery is implemented locally in `95b827e`, with 14 offline + tests and exact artifact SHA-512 verification. Original upload errors + remain errors for missing/different/unverifiable outcomes. Not deployed + until the maintainer merges/pushes; no publication was performed here. +9. Phase 3: choose OS scope (proposed Windows 11 client/2019/2022 servers), + detect ISO editions, provision without repurposing shared VMs, then run + published-package acceptance. #34 has no new reply since 2026-10-06. +10. Lab rollback evidence: new checkpoints exist but report Standard even + after a successful temporary ProductionOnly probe. Classification is + unresolved; original VM policy restored, no checkpoint restored. Do + not represent these as verified Production snapshots. diff --git a/.memory-bank/systemPatterns.md b/.memory-bank/systemPatterns.md index 4f71acb..6feb456 100644 --- a/.memory-bank/systemPatterns.md +++ b/.memory-bank/systemPatterns.md @@ -1,57 +1,27 @@ --- status: current -last-verified: 2026-10-08 +last-verified: 2026-10-09 owner: active-agent -source: repository evidence +source: repository and regression evidence --- # System patterns ## Architecture -```text -NTFSSecurity.psd1 ─┬─ ScriptsToProcess: NTFSSecurity.Init.ps1 - │ Add-Type: Security2.dll, PrivilegeControl.dll, - │ ProcessPrivileges.dll, inline NTFS.DriveInfoExt; - │ Update-FormatData -PrependPath format.ps1xml - ├─ TypesToProcess: NTFSSecurity.types.ps1xml - │ (Owner, IsInheritanceBlocked, LengthOnDisk on - │ FileInfo/DirectoryInfo; AccountType on ACEs) - ├─ RootModule: NTFSSecurity.psm1 (aliases) - ├─ NestedModules: NTFSSecurity.dll (36 cmdlets) - └─ en-US\NTFSSecurity.dll-Help.xml (Get-Help; generated - from Docs/Cmdlets, Decision 8) -NTFSSecurity.dll ── cmdlets ──> Security2.dll (FileSystemAccessRule2, - FileSystemAuditRule2, IdentityReference2, - FileSystemInheritanceInfo, EffectiveAccess) - ── long paths ──> AlphaFS - ── privileges ──> PrivilegeControl / ProcessPrivileges -``` - -- `BaseCmdlet` resolves only relative paths, against the current file - system location of the session (not `$PWD`, #86). Path parameters carry - `[FileSystemPathTransformation]`, which binds file objects as full paths. -- On access denied, most cmdlets retry through `InvokeAsOwner`, which takes - ownership and restores the previous owner on every exit path. -- `BaseCmdletWithPrivControl` enables Backup, Restore, TakeOwnership, and - Security in `BeginProcessing` when `PrivateData.EnablePrivileges` is - `$true`, and disables the ones it enabled in `EndProcessing` and, since - 5.0.0-rc6, in `Dispose`: PowerShell skips `EndProcessing` when a later - command, such as `Select-Object -First`, or a terminating error stops the - pipeline, but calls `Dispose`. `Enable-Privileges` keeps them - (`KeepEnabledPrivileges`). The cleanup reads the current state of each - privilege, because another command in the pipeline can have changed it, - and tries every privilege even when one fails: `EndProcessing` warns, - `Dispose` stays silent, because PowerShell ignores exceptions thrown - there and no stream is open anymore. -- `PrivateData` switches: `EnablePrivileges`, `GetInheritedFrom`, - `GetFileSystemModeProperty`, `IdentifyHardLinks`, `ShowAccountSid`. -- Cmdlets accept `-Path` (alias `FullName`) or `-SecurityDescriptor`; the - SD sets change the object in memory until `Set-NTFSSecurityDescriptor`. +| Component | Responsibility | +| --- | --- | +| `NTFSSecurity.psd1` | Root script, nested binary, initialization, types, help | +| `NTFSSecurity.Init.ps1` | Loads Security2/privilege assemblies and prepends formatting | +| `NTFSSecurity.dll` | 36 PowerShell cmdlets; BaseCmdlet path/privilege behavior | +| `Security2.dll` | DACL/SACL objects, owners, inheritance, effective access, Win32 | +| AlphaFS | Long-path files/directories/links | +| PrivilegeControl / ProcessPrivileges | Token privilege operations | +| `en-US/NTFSSecurity.dll-Help.xml` | Committed help generated from cmdlet Markdown | ## Decisions -Each Decision record is a file in `decisions/`; read only the relevant ones. +Read only task-relevant records; the index controls routing. | # | Decision | | --- | --- | @@ -80,65 +50,45 @@ Each Decision record is a file in `decisions/`; read only the relevant ones. ## Patterns -### Writing cmdlets +### Cmdlets and security sections -- A parameter that takes pipeline input needs a getter that doesn't - throw: PowerShell reads it before it binds each input object, and an - exception turns every object into `GetDefaultValueFailed` (the link - cmdlets before 5.0.0-rc7). -- An error for one item is non-terminating, so that the cmdlet goes on - with the next path or pipeline object; since 5.0.0-rc7, the link cmdlets - too. Its message names the item, and its target object is the item that - the cmdlet was asked to process. Resolving a path can throw in Windows - PowerShell for an invalid character, so that belongs inside the - per-item error handling. -- Folders move without `MoveOptions.CopyAllowed`: for another volume, - AlphaFS then copies and deletes, which lost empty folders. Windows - refuses such a move with `NotSameDeviceException` (17). Tests reach - another volume through `\\localhost\C$`, elevated only. +- BaseCmdlet resolves relative paths against the current filesystem + location; file-object input binds FullName through path transformation. +- Write only changed/read sections (Decision 19); a descriptor parameter + changes memory until `Set-NTFSSecurityDescriptor` persists it. +- Access denial can retry through InvokeAsOwner; restore the previous owner + on every exit, except a successful descriptor write that intentionally + sets the owner. Restoration failures must report RestoreOwnerError. +- Privilege cleanup runs in EndProcessing and Dispose, reads current states, + attempts all cleanup, and preserves explicit enables. Dispose has no stream. +- Pipeline getters never throw; per-item errors name input and allow continuation. +- Folder moves never use CopyAllowed; preserve cross-volume source folders. +- Apply implied Hidden/Force before deciding to emit, including the first item. -### Verifying documentation +### Tests and documentation -- Run platyPS in Windows PowerShell 5.1 against a Release build; a copy of - `Docs/Cmdlets` must round-trip through `Update-MarkdownHelp` unchanged. - Keep cmdlet pages ASCII-only. platyPS takes `Position` and `Required` from - the shipped help file: after such a change, edit the page YAML, run - `New-ExternalHelp`, rebuild, and check the round trip. -- MarkdownLinkCheck checks relative `Docs` links, `Tests\Wiki.Tests.ps1` - the wiki links and anchors. The wiki is generated from `Docs` (never edit - it); `Docs/README.md` becomes Home, its cmdlet groups the sidebar. -- In cmdlet pages, end a sentence with a link (platyPS drops the space - after it). Verify examples in a `$env:TEMP` sandbox, never on real data. +- Tests import Release in isolated processes, both editions and privilege + modes. File/ACL/link fixtures use shared sandbox guards and cleanup. + Privilege-dependent skips must have eligible counterparts in the matrix. +- Assert persisted state, errors/targets, continuation, and no failed + PassThru output. Prove new characterization guards with bounded mutations; + restore source exactly and rebuild before green validation or packaging. +- Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes. +- Scope/descendant expectations are independent of the production converter. +- Desktop platyPS: generate help, rebuild, round-trip unchanged, check links. +- Live tests use only approved lab targets, SMB then independent server state; + Get/SetFileSecurity preserves stored DACLs; rights oracles use S4U tokens. -### Testing the module +### CI results and publication -- Pester 5 tests in `Tests/*.Tests.ps1` import the Release build; CI runs - them in Windows PowerShell 5.1 and PowerShell 7 (Decision 11). -- 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`, 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 - release notes, and the packages. -- The live tests in `Tests\Lab` (Decision 20) run as domain accounts in a - lab: on the client over SMB, then on the file server, which checks what - the client runs left. They read and write descriptors as Windows stores - them with `GetFileSecurity` and `SetFileSecurity`, because - `GetNamedSecurityInfo` converts a DACL without the auto-inherit flag and - returns its owner. The expected effective rights come from the S4U tokens - of the file server and the client, like the Effective Access tab. +- Use Path.Combine then GetFullPath for a rooted-or-repository-relative + result path; Join-Path appends even a rooted child and corrupts it. +- Discovery handles only expected PackageNotFound as absence; repository, + authentication, and network errors remain failures. +- Rerun/uncertain-upload success requires Gallery SHA-512 equality with the + exact build artifact. Base64 is case-sensitive: use ordinal comparison. + Missing/different/unverifiable metadata preserves the upload error. +- Secrets stay by environment reference, never in process arguments/logs. + Test all external publication commands with mocks; no test may upload. +- AltCover aggregates all four sequential runs without --save. Report + sequence points, not unique source lines; keep unmatched paths visible. diff --git a/.memory-bank/techContext.md b/.memory-bank/techContext.md index 9b949e1..83acc4c 100644 --- a/.memory-bank/techContext.md +++ b/.memory-bank/techContext.md @@ -1,251 +1,156 @@ --- status: current -last-verified: 2026-10-08 +last-verified: 2026-10-09 owner: active-agent -source: repository evidence +source: repository and executable evidence --- # Tech context ## Stack -- C# class libraries, old-style `.csproj`, .NET Framework 4.5.2, - solution `NTFSSecurity.sln` (Visual Studio 2017 format). -- Projects: `NTFSSecurity` (cmdlets), `Security2` (ACL object model, Win32 - interop), `PrivilegeControl` and `ProcessPrivileges` (token privileges), - `Log`, `TestClient`, `NTFSSecurityTest` (MSTest, minimal coverage). -- NuGet (`packages.config`): AlphaFS 2.2.x for long paths; - `System.Management.Automation.dll` 10.0.10586.0. For a drive or volume - root, AlphaFS `DirectoryInfo` reaches the device object, while - `Directory.Get/SetAccessControl('C:\')` reaches the root folder (#41). -- Module: `NTFSSecurity.psd1` loads `NTFSSecurity.psm1` (aliases `dir2`, - `gi2`, `rm2`, `del2`), `NTFSSecurity.Init.ps1` (Add-Type of the helper - assemblies, prepends `NTFSSecurity.format.ps1xml`), and `NTFSSecurity.dll`. -- Documentation: Markdown in `Docs` and `README.md`, rendered by GitHub and - published to the wiki by CI; no documentation site (Decisions 9 and 11). - Cmdlet pages are platyPS 0.14 markdown (schema 2.0.0) in `Docs/Cmdlets`. -- Help: `NTFSSecurity\en-US\NTFSSecurity.dll-Help.xml`, generated from - `Docs/Cmdlets` and committed (Decision 8). -- Tests: Pester 5 in `Tests`, one file per area, against the Release - build; `Wiki.Tests.ps1` (wiki conversion) runs without a build. -- CI: GitHub Actions, `.github/workflows/ci.yml` with the scripts in - `.github/scripts` (Decision 11). +- Legacy C# projects, .NET Framework 4.5.2, `NTFSSecurity.sln`. + Cmdlets depend on Security2, PrivilegeControl/ProcessPrivileges, and + AlphaFS 2.2.x. System.Management.Automation reference: 10.0.10586.0. +- Module supports Windows PowerShell 5.1 and PowerShell 7; 36 cmdlets. + Manifest initializes helper assemblies, aliases, type data, formatting, + and committed help generated from `Docs/Cmdlets` (platyPS 0.14/schema 2). +- CI: `.github/workflows/ci.yml`, scripts in `.github/scripts`; GitHub + renders Docs and publishes a generated wiki. No separate docs site. -## Environment +## Current environment -- Windows only (NTFS, Win32 security APIs). -- The Debug build writes straight into - `C:\Program Files\WindowsPowerShell\Modules\NTFSSecurity\`. -- No Visual Studio MSBuild or .NET Framework targeting pack on the - workstation. A local build works with the .NET Framework MSBuild - (`%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe`) plus - `/p:CscToolPath` to the Roslyn `csc.exe` of the `Microsoft.Net.Compilers` - package; the legacy C# 5 compiler fails with CS0136. `dotnet msbuild` - fails on the binary resources in `Resources.resx` (MSB3822, MSB3823). -- platyPS 0.14.2, Pester 5.7.1, PSScriptAnalyzer, and powershell-yaml are - installed only for PowerShell 7. Windows PowerShell 5.1, started from - PowerShell 7, imports platyPS and Pester by full path - (`~\OneDrive\Documents\PowerShell\Modules\platyPS\0.14.2`, - `C:\Program Files\PowerShell\Modules\Pester\5.7.1`). Leave - `$env:PSModulePath` alone: PowerShell 7 hands the child the Windows - PowerShell default path, and clearing it leaves Windows PowerShell without - its core modules (Pester fails: `Add-Member` not found). -- MarkdownLinkCheck is not installed, and `Save-Module` crashed (FailFast) - in PowerShell 7.6 on 2026-10-04. Download the 0.2.0 package from - `https://www.powershellgallery.com/api/v2/package/MarkdownLinkCheck/0.2.0` - into `$env:TEMP`, extract it, and import it by path. -- The first workstation is ARM64; PowerShell 7 runs as x64 under emulation. -- The NuGet cache (`~\.nuget\packages`) holds every build dependency: copy - `alphafs\2.2.1`, `system.management.automation.dll\10.0.10586`, and - `microsoft.netframework.referenceassemblies.net452\1.0.3` into - `packages\.`, and point `CscToolPath` at - `microsoft.net.compilers\4.2.0\tools`. -- The second workstation (x64, used since 2026-10-05) runs the agent - session elevated, so the tests that need privileges run there as in CI. - It has no NuGet cache with these packages: download each from - `https://api.nuget.org/v3-flatcontainer///..nupkg`, - extract the first three into `packages\.` and the compilers - into `$env:TEMP`; Pester 5.7.1 comes from the Gallery package API the - same way, its folder first on `$env:PSModulePath` of the test process. - The GitHub CLI is in `C:\Program Files\GitHub CLI`, outside the PATH of - sessions started before its installation. -- The third workstation (`ExHost`, a Windows Server 2025 VM, x64, used since - 2026-10-07) runs the agent session elevated and hosts the AutomatedLab lab - `WindowsAccessControlLab` (Decision 20) with Hyper-V and AutomatedLab - 5.61.704. It has no NuGet cache or platyPS: check each - nuget.org package against the SHA-512 `packageHash` of its catalog entry - (`https://api.nuget.org/v3/registration5-semver1//.json`, - then `catalogEntry`), and each Gallery package against `PackageHash` of - `api/v2/Packages(Id='',Version='')`. Pester 5.7.1 is in - `V:\Git\WindowsAccessControl\output\RequiredModules`. The GitHub CLI - 2.102.0 is in `C:\Program Files\GitHub CLI`, outside the PATH, and signed - in as `raandree` since 2026-10-08; `Block-RemoteMutation` denies its - mutating commands, so the agent uses it read-only. The lab domains - `a.forest1.net` and `b.forest1.net` had a maximum password age of 42 - days, so the password of `install` expired on 2026-09-15 and AutomatedLab - got access denied; it never expires since 2026-10-07, as in - `forest1.net`. +- Host `ExHost`: Windows Server 2025 VM, native x64, elevated agent; + repository `V:\Git\NTFSSecurity`. AutomatedLab 5.61.704, Hyper-V, + approved lab `WindowsAccessControlLab` (Decision 20). +- Build Release only: Debug writes to Program Files. Native .NET Framework + MSBuild plus Roslyn `Microsoft.Net.Compilers` 4.2.0 and .NET 4.5.2 + reference assemblies work; legacy compiler fails CS0136, dotnet MSBuild + fails binary resources MSB3822/MSB3823. Build packages are already cached + in `packages`; compiler/tools are under TEMP `ntfs-build`. +- Pester 5.7.1 is in + `V:\Git\WindowsAccessControl\output\RequiredModules\Pester\5.7.1`. + platyPS 0.14.2 and MarkdownLinkCheck 0.2.0 are under TEMP `ntfs-docs-tools`. + PSScriptAnalyzer and PSResourceGet are available in PowerShell 7. +- Use Desktop's module paths in Desktop children, not inherited Core-only + paths. Never import NTFSSecurity in the agent shell; every package/build + runs in a new process. Current prereleases share assembly version 5.0.0.0. +- GitHub CLI: `C:\Program Files\GitHub CLI\gh.exe`, signed in as raandree. + Read-only queries work; remote mutations belong to the maintainer. +- LabSources: `V:\LabSources`. All 13 deployed machines are Server 2025. + Windows 11 consumer/enterprise-evaluation media and Server 2019/2022 + ISO files exist. OS cache is empty; exact detected editions are not yet + verified. Do not equate present media with a deployed/tested OS matrix. ## Constraints -- `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 - PowerShell 5.1 and PowerShell 7.6. -- The module source at `master` differs from tag `4.2.6` by the changes - that `CHANGELOG.md` lists under `[Unreleased]`, the release notes of each - 5.0.0 prerelease. -- PowerShell Gallery versions (publish dates): 4.0.0 (2015-08-19), 4.2.2 - (2016-05-18), 4.2.3 (2016-05-19), 4.2.4 (2018-08-13), 4.2.5 (2019-07-11), - 4.2.6 (2019-07-12), none with release notes; 5.0.0-rc1 (2026-10-04), - 5.0.0-rc2 (2026-10-05), 5.0.0-rc3 and 5.0.0-rc4 (2026-10-06), 5.0.0-rc5 - (2026-10-08), published - by CI. Older versions were released on CodePlex only, and their dates are - lost. The git history starts on 2016-10-10, when the project moved from - CodePlex. -- Releases up to 4.2.6 were Debug builds published by hand, with the whole - output folder; their tags carry the previous version. From 5.0.0 on, CI - publishes on a version tag (Decision 12). GitHub releases attach - `NTFSSecurity.zip`. -- CI: GitHub Actions on pull requests, pushes to `master`, and version tags - (Decision 11); AppVeyor and Read the Docs aren't used (Decision 9). -- `CHANGELOG.md` lists user-visible changes only; CI and build-only changes - get no entry - ([Decision 7](decisions/0007-changelog-user-visible-only.md)). -- Remote mutations are the maintainer's: the user-level preToolUse hook - `Block-RemoteMutation.ps1` denies `git push` and mutating `gh` commands - (`pr create`, `pr close`, and others) from the agent session, even after - an explicit request. Its override, `COPILOT_ATELIER_ALLOW_REMOTE=1`, is - read from the environment that VS Code starts the hook with; setting it - inside an agent command has no effect (verified 2026-10-04). The hook - matches the whole command text, so a commit message that quotes such a - command is blocked too. Prepare the commands and descriptions; the - maintainer runs them. Hand over each command as its own fenced code block - at the end of the reply, which the chat shows with a copy button, and end - the turn there; the maintainer reports back in the chat. The question - dialog joins the lines of its text, has no copy button, and covers the - reply before it (maintainer, 2026-10-06). A long question also hides its - choices, so that it can't be answered: keep it to a few short sentences - (2026-10-07). A pull request description - names an issue without a closing keyword (fixes, closes, resolves) unless - the merge should close it: "fixes #34" in #112 closed #34. Simulated `gh` - commands in offline tests must print what the real ones print, such as - the URL of a new comment. +- Source manifest: ModuleVersion 5.0.0, prerelease rc7 on #116/follow-up. + Latest stable: 4.2.6; latest published prerelease: rc6 (2026-10-08). + GitHub rc6 release recovered 2026-10-09. rc7 publication is pending. +- Changed-section writes preserve unchanged owner/group/DACL/SACL (19). + Roots use root-folder APIs, not AlphaFS device security (#41). +- CHANGELOG contains user-visible changes only (7); tests and CI-only fixes + get no entry. No stable release until Decision 21 gates close. +- Honor separate topic branches, no amendment, two AI co-author trailers. + Never work around remote-mutation blocking. Provide each maintainer + command separately at reply end, no question dialog after commands. + Issue references use no closing keyword unless closure is intended. +- Lab passwords stay in memory and are lab-only; no secret in repository, + logs, or process arguments. Live ACL mutations occur only in the lab. +- Existing expired installation passwords of a.forest1/b.forest1 were + configured not to expire on 2026-10-07, matching the root domain. -## Validation +## Build and focused checks -- CI (`.github/workflows/ci.yml`): job `build` on `windows-2025` installs - platyPS 0.14.2, MarkdownLinkCheck 0.2.0, and Pester 5.7.1 for all users, - restores `packages.config` per project plus - `Microsoft.NETFramework.ReferenceAssemblies.net452` 1.0.3, builds - `NTFSSecurity.csproj` in Release with the MSBuild that `vswhere` finds, - 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, 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, - for `master` only. After the tests, `build` runs - `New-ModulePackage.ps1` and uploads the artifact `packages` (nupkg and - `NTFSSecurity.zip`). Job `release` runs only for tags matching - `[0-9]+.[0-9]+.[0-9]+` or `[0-9]+.[0-9]+.[0-9]+-*`, in the environment - `powershell-gallery` (secret `PSGALLERY_API_KEY`); see Decision 12. - Actions are pinned by commit SHA: `actions/checkout` v7.0.1, - `actions/upload-artifact` v7.0.1, `actions/download-artifact` v8.0.1; - Dependabot proposes updates weekly, one week after a release. -- Packaging needs PSResourceGet (`Compress-PSResource`, PowerShell 7.4 or - later); its tests skip in Windows PowerShell. Dry run locally: run - `New-ModulePackage.ps1` against `NTFSSecurity\bin\Release` into - `$env:TEMP`, then extract the nupkg into a folder and import it there. -- Read CI runs with `gh run list --repo raandree/NTFSSecurity --workflow - 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; 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+ - `-ProgressAction` noise. -- Placeholder check: no `{{` left in `Docs/Cmdlets/*.md`. -- Help file: `New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath - .\NTFSSecurity\en-US -Force` must leave `git status` unchanged. -- Pester: run detached (`Start-DetachedPowerShell.ps1`) in Windows - 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 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: - `--reportFormat=OpenCover`, AlphaFS and `System.Management.Automation` - 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 - the results to `$env:TEMP\NTFSSecurityLab\Results`. A run of two versions - in both editions takes about 30 minutes; `-RemoveFixture` removes its - accounts, share, and folders from the lab. For a check on the client as - an account without administrator rights, use `NtfsLiveServerAdmin` - (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-