Browse Source

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 <ai@example.com>
pull/117/head
Raimund Andree 3 days ago
parent
commit
f11ff41294
  1. 103
      .memory-bank/activeContext.md
  2. 288
      .memory-bank/progress.md
  3. 148
      .memory-bank/systemPatterns.md
  4. 375
      .memory-bank/techContext.md

103
.memory-bank/activeContext.md

@ -1,6 +1,6 @@
--- ---
status: current status: current
last-verified: 2026-10-08 last-verified: 2026-10-09
owner: active-agent owner: active-agent
source: current task evidence source: current task evidence
--- ---
@ -9,62 +9,57 @@ source: current task evidence
## Current focus ## Current focus
5.0.0-rc6 is on the PowerShell Gallery (tag `5.0.0-rc6` on `b51d970`, the Quality-gate follow-up is implemented and validated locally on
merge of #115); its GitHub release waits for a rerun of the failed Release `ai/quality-gate-coverage`, based on `d25647d` of #116. Code/test baseline
job. #116 (`ai/release-5.0.0-rc7`, base `master`) holds the behavior `3442194`, lab regression/acceptance `7594e0c`; final records follow.
changes that Phase 2 found, decided as assumptions for the maintainer's No remote mutation. Architecture/cmdlet-design choices remain deferred;
review (Decision 22), and waits for that review. Then 5.0.0-rc7, Phase 3, Decision 22 is still proposed. Stable 5.0.0 is not ready (Decision 21).
and 5.0.0; after 5.0.0 the repository is archived in favor of
WindowsAccessControl (Decision 18).
## Evidence ## Evidence
- 2026-10-08, 5.0.0-rc6: the Release job of the tag (run `37839669028`) - rc6 Release run `37839669028`, attempt 2, succeeded; GitHub prerelease
published the package at 20:40 UTC and failed after it, because with zip appeared 2026-10-09 07:01:34 UTC. First attempt proves HTTP 409
`Publish-PSResource` gave up waiting after 100 seconds and its retry got after Gallery publication, not the previously assumed retry chronology.
409 (`progress.md`, open work 8). The live tests of rc7 ran with - #116 is open, base master, head `d25647d`, CI build/wiki passed. rc7
`-Version 5.0.0-rc6`, which checks the hash of the Gallery, in both publication is pending. The follow-up does not change that PR's head.
editions, 20:43 to 21:00 UTC: all passed except the warning text that - Local changes: deletion/ownership guards (`a97e46f`); all scopes and
rc7 changed, which matches the live tests of rc6. The fixture was inheritance (`e7ee203`); absolute basic-user results (`51dec86`);
removed at 21:03 UTC and its removal checked. exact-package publication recovery (`95b827e`); first-hidden-item fix
- 2026-10-08, #116, 11 commits on `be04cb7` (`3899228` to `1063b29`) and (`d610372`); Force/descriptor guards (`3442194`); SMB regression above.
commits of records: - Hidden omission was reproduced in all four configurations before the
- Decision 22: items 1, 2, 5, 6, 7, and 8 changed, 7 and 8 breaking (the fix. No parameter/design change. Publication tests are wholly mocked;
link cmdlets require `-Path` and `-Target` and write non-terminating exact ordinal SHA-512 identity is required, no real upload occurred.
errors); items 3, 4, 9, and 10 kept, 9 with an FAQ entry. New defects, - Final uninstrumented suite: 914 each, zero failed. Passed/skipped:
fixed with a regression test that failed first: `Move-Item2` deleted elevated Desktop 890/24, Core 860/54; basic Desktop 749/165, Core 719/195.
an empty folder that it moved to another volume (AlphaFS emulated the Frozen aggregate: 2,641/3,559 sequence (74.21%), 974/1,933 branches
move); the link cmdlets failed with `GetDefaultValueFailed` for every (50.39%); NTFSSecurity assembly 84.28%. All skipped templates have
piped object; `Get-NTFSSimpleAccess` failed for a folder that came executed counterparts; mutations restored exactly before green builds.
after its parent folder a second time. - Live packaged candidate, 09:20 to 09:51 UTC: 330 passed, zero failed,
- One `security-reviewer` pass over `be04cb7..4ee01e5`: no Blocker or two expected Server-module skips. Published rc6: 326 passed, four
Major. Minor 1 to 5 and Nits 7 to 9 fixed test-first in `7936d9f` to expected failures (Hidden and rc7 warning text in each edition), two
`1063b29`; Nit 7, the warning of `Get-NTFSEffectiveAccess` for names skips. Tested folder and all 11 ZIP files are byte-identical.
of this computer, was reproduced first. Nit 6 declined (Decision 22). - Temporary host result verifier failed on Desktop JSON wrapping/full
- Suite of `1063b29`: 712 tests. Elevated: 688 passed and 24 skipped in test names; corrected verification passed on unchanged raw results in
Windows PowerShell 5.1, 658 and 54 in PowerShell 7. As a basic user: both editions. Cleanup wrapper's broad Error.Count was not acceptance
612 and 100, 582 and 130. No failure, none skipped in all four. proof. Independent probes verified all fixture objects/members/profiles
- Lab acceptance of `dc6e9f5` after the checkpoint gone from six machines. Raw failing markers and corrected evidence kept.
`ntfs-rc7-dc6e9f5-before-acceptance`, 16:24 to 16:40 UTC: 326 tests in - One read-only independent code review approved, high confidence, no
both editions, none failed, 2 skipped as in rc6 significant findings or confirmed exploit. Custom reviewer could not
(`Tests/Lab/Acceptance-2026-10-08-5.0.0-rc7.md`). The code of start (model unavailable); built-in code-review performed the one pass.
`4ee01e5` and a first run of `dc6e9f5` without the checkpoint had the - Six checkpoints exist but report Standard, even after a successful
same counts. The fixture was removed at 16:21 and 16:44 UTC, and its temporary ProductionOnly probe; policy restored, no restore performed.
removal checked each time. Do not claim verified Production rollback evidence.
- #115 passed CI in all four configurations on `be04cb7`, with the first - Wider matrix not deployed: 13 Server 2025 VMs; Windows 11/2019/2022
runs of `Invoke-TestsAsBasicUser.ps1` on GitHub runners; #116 passed CI media present, OS detection cache empty. #34 has no reply since Oct 6.
on `ebe91fe` against the rc6 branch. - Full evidence: session artifact `quality-gate-3442194-20261009`;
- #34: no reply from the tester since 2026-10-06. repository report `Tests/Lab/Acceptance-2026-10-09-quality-gate.md`.
## Next step ## Next step
1. The maintainer reruns the failed Release job of 5.0.0-rc6, which skips 1. Maintainer pushes/reviews this follow-up; retain separate commits and
the published package and creates the GitHub release, and closes #110. stacked-PR merge order (15). #116's Decision 22 review remains required.
2. He pushes the records to #116 and reviews the choices of Decision 22, 2. Integrate and pass CI, then publish/test the next candidate package.
each its own commit, above all the two breaking changes of the link 3. Close the remaining-path inventory (918 points, 562 for finer review),
cmdlets. After the CI of the push, he merges #116 with a merge commit decide/provision the OS matrix, obtain or explicitly accept #34 feedback.
(Decision 15) and tags `5.0.0-rc7`; the live tests then run against the 4. Only then release 5.0.0 through documented CI steps; never claim the
published package (`-Version 5.0.0-rc7`). current coverage percentage alone meets the quality gate.
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).

288
.memory-bank/progress.md

@ -1,203 +1,121 @@
--- ---
status: current status: current
last-verified: 2026-10-08 last-verified: 2026-10-09
owner: active-agent owner: active-agent
source: repository evidence source: repository and validation evidence
--- ---
# Progress # Progress
## Current status ## Current status
5.0.0-rc6 is on the PowerShell Gallery, published by CI on 2026-10-08 at 5.0.0-rc6 is published on the Gallery and GitHub; its failed Release job
20:40 UTC from the tag `5.0.0-rc6` on `master` (`b51d970`, the merge of recovered in attempt 2 on 2026-10-09. #116 (rc7, `d25647d`, base `master`)
pull request #115; Decision 12). The Release job failed after the upload, is open and green, not merged or published. Further quality-gate work is
so the GitHub release waits for a rerun of the failed job. The published local on `ai/quality-gate-coverage`; Phase 2 is not complete while the
package passed the live tests. Phase 2 of the quality gate (Decision 21) remaining-path inventory is open. Stable Gallery version: 4.2.6.
is complete. The pull request #116 (`ai/release-5.0.0-rc7`) holds the After 5.0.0, archive in favor of WindowsAccessControl (Decision 18).
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).
## Recent milestones ## Recent milestones
- 2026-10-02 to 2026-10-04: #91 to #97 aligned the docs with the code, - 2026-10-02 to 2026-10-06: documentation/help aligned with source, CI and
shipped the help file, kept the docs on GitHub, set version 5.0.0, moved wiki moved to GitHub Actions, versioning/release automation established,
CI and a wiki generated from `Docs` to GitHub Actions, and completed the and prereleases rc1 to rc4 published. Earlier detail is in git,
version history (Decisions 6 to 11). `CHANGELOG.md`, `Docs/Version-History.md`, and Decisions 1 to 19.
- 2026-10-04: #98 (`e0f5366`) added releases on a version tag through CI - 2026-10-07: lab comparison of rc2/rc4 reproduced #34 over SMB and proved
(Decision 12). The tag `5.0.0-rc1` published to the Gallery and created changed-section writes preserve the owner. Remote effective-access
the GitHub prerelease; the installed module passed the full suite. fallback returned no result; fixed test-first for rc5 (Decision 20).
- 2026-10-05, overnight run: the 24 code defects of work package 5 and the - 2026-10-08: #114 merged (`fcb370e`), rc5 published and live-tested.
issues #3, #4, #5, #17, #74, #82, #86, and #88 fixed with regression Decision 21 established the quality gate. Corrected four-run coverage:
tests, plus what one security review per PR found; the 37 open issues rc5 58.1% sequence points/38.0% branches, not the initial one-run result.
triaged; `Docs/FAQ.md`, Dependabot for the actions, and the label `rc2`. - 2026-10-08: rc6 Phase 2 added basic-user CI, parameter-set/error tests,
#5 and #82 are breaking changes, like the change of Decision 13. expanded domain/SMB cases, and fixes for privilege cleanup, path
- 2026-10-05: the first CI runs of the eight PRs found a defect that the resolution, ownership retries, item conflicts, output equality, and
workstation had skipped, fixed in `629f4e7` (audit inheritance of an item inherited flags. Suite: 677; coverage 68.14% sequence/44.32% branches.
without a SACL). The PRs #99 to #106 were merged in order with merge Lab acceptance of `7b0781f` passed; two independent review passes.
commits, CI on `master` passed, and the tag `5.0.0-rc2` published the - 2026-10-08: rc7 implemented proposed Decision 22, including breaking
prerelease; GitHub's Actions outage that day cancelled the first two link binding/error changes, SimpleAccess traversal, cross-volume folder
attempts of the release run before they started. Repository hardening is preservation, and named effective-access warnings. Suite: 712, no
optional (Decision 14); the merge rule and the maintainer's rule for failures or test skipped everywhere. One review: no Blocker/Major.
fixes are Decisions 15 and 16. Lab candidate `dc6e9f5`: 326 passed, 2 skipped, cleanup verified.
- 2026-10-06: the issues got their labels (Decision 17). The maintainer - 2026-10-08: #115 merged (`b51d970`) and tagged rc6. Release run
decided to publish 5.0.0-rc3 before 5.0.0 and to archive the project in `37839669028` failed with HTTP 409 after Gallery publication. The log
favor of WindowsAccessControl (Decision 18); the README, the docs home, does not establish the previously assumed initial timeout/retry cause.
and the changelog announce it. Published rc6 live tests differed only in rc7's warning expectation.
- 2026-10-06: 5.0.0-rc3 (#112): the access and audit cmdlets write only - 2026-10-09: release attempt 2 succeeded; rc6 GitHub prerelease and zip
the section that they change, which fixes #34 and the inherited entries appeared at 07:01:34 UTC. #116 passed CI on `d25647d`.
that elevated sessions copied as explicit ones (Decision 19). #67 has its - 2026-10-09: autonomous follow-up on `ai/quality-gate-coverage`, through
cause outside the module (a share root over UNC can't re-inherit), is `3442194`, adds 202 cases above rc7: deletion/owner failures, all 13
explained in `Docs/FAQ.md`, and was closed as not planned. One scopes, inheritance transitions, enumeration, forced replacement,
`security-reviewer` pass approved the branch. The PR description said descriptor failures, and offline CI recovery. Reproduced/fixed rooted
"fixes #34", so the merge closed #34; it was reopened for a tester. result-path handling and first-hidden-item omission. Publication recovery
- 2026-10-06: 5.0.0-rc4 (#113), test-first: drive and volume roots read verifies exact SHA-512 identity, not merely version existence.
and change their root folder, not the device (#41); the audit cmdlets - 2026-10-09: final uninstrumented suite: 914 per configuration, zero
reject a descriptor without the audit entries (#109); `-WhatIf` previews failures; coverage: 2,641/3,559 sequence points (74.21%) and 974/1,933
`Copy-Item2` and `Move-Item2` despite an existing destination (#108); branches (50.39%), aggregate of four runs without AltCover `--save`.
small items (#111). One `security-reviewer` pass approved it; its Minor All skipped templates have executed counterparts. Mutation guards were
findings R1, R2, R6, and R8 were fixed before the merge. #41, #108, proved and production source restored; Release build/checks pass.
#109, and #111 closed as completed, #90 and #107 as not planned. - 2026-10-09: live comparison, 09:20 to 09:51 UTC: candidate 330 passed,
- 2026-10-07: live tests in the lab of WindowsAccessControl (Decision 20) zero failed, two expected skips; published rc6 four expected Hidden/
against 5.0.0-rc2 and 5.0.0-rc4 in both editions: rc2 fails #34 over SMB warning-text failures only. Independent cleanup probes verified fixture
with error 1307 for `Add-NTFSAccess`, `Clear-NTFSAccess`, and absence; raw host-verifier failures retained with corrected verification.
`Set-NTFSSecurityDescriptor`; rc4 passes the four cases, except Lab guards/acceptance committed in `7594e0c`. One independent code review
`Get-NTFSEffectiveAccess -ServerName` with a computer that can't be approved with no significant finding (custom model unavailable; built-in
reached, which returned no access since before rc1. The maintainer chose fallback). All 11 tested files match the ZIP. OS/path gates stay open.
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`.
## Stable capabilities ## Stable capabilities
- 36 cmdlets: access (7), audit (5), inheritance (6), owner and security - 36 cmdlets: access, audit, inheritance, owners/descriptors, privileges,
descriptor (4), privileges (3), long-path items (6), links, hash, and long-path items, links, hash, and disk space.
disk space (5). - Windows PowerShell 5.1 and PowerShell 7; RIPEMD160 and MACTripleDES are
- Works in Windows PowerShell 5.1 and PowerShell 7. In PowerShell 7, available only in Desktop. Both editions run elevated/basic-user in CI.
`Get-FileHash2` lacks `RIPEMD160` and `MACTripleDES`, which .NET lacks. - Pester fixtures use `Tests/TestHelpers.psm1` TEMP sandboxes. Live tests
- Pester tests in `Tests\` run in `$env:TEMP` sandboxes through are excluded from CI and run only on approved lab client/server targets.
`Tests\TestHelpers.psm1`; tests that need privileges skip without them
and run in CI, whose runners are elevated.
## Open work ## Open work
1. Quality gate before 5.0.0 (Decision 21): the maintainer reruns the 1. Decision 21 gate: review Decision 22, integrate reviewed quality-gate
failed Release job of 5.0.0-rc6, which creates the GitHub release; follow-up, publish the next candidate, and test the published package.
reviews the choices of Decision 22 in #116; merges #116 and tags Do not release 5.0.0 until the remaining-path and OS-matrix gates close.
5.0.0-rc7, whose published package then runs the live tests. Phase 3 Release steps: `Docs/Contributing/05-Releasing.md`; remove prerelease
runs the live tests on more operating systems. Then release 5.0.0 label, date `[5.0.0]`, update `$publishedVersions`, tag through CI.
through CI (Decision 12): remove the label, date 2. Issues: #110's seven items were addressed by rc6, but #115 deliberately
`[Unreleased]` as `[5.0.0]`, add the last prerelease to used no closing keyword. #34 stays open for non-Windows owner feedback
`$publishedVersions`, and tag `5.0.0` (steps in or maintainer acceptance. #16, #21, #45, #89 await reporters. #68 tracks
`Docs/Contributing/05-Releasing.md`). #34 stays open with Bug and Help ShouldProcess for security cmdlets; enhancements #22/#49/#68/#77/#87
Wanted until a tester with a file server that refuses the owner are not planned for 5.0.0. Labels follow Decision 17.
confirms the fix, or until 5.0.0 ships. 3. Deferred reviews (not silently accepted): rc3 extra DACL read/SDDL
2. Issues: 5.0.0-rc6 addresses the seven items of #110 (tests); #115 snapshots/duplicate SACL check; rc4 findings listed in #113, including
named it without a closing keyword, so the maintainer closes it now. library-only RemoveAll account filters; rc5 unchecked Authz errors and
#21 (a misleading error of `Move-Item2`) got lab-controller hardening; rc6 failed privilege-disable retry (not
a fix in rc6 that names the missing destination folder; the folder reproduced); rc7 audit missing-path error IDs declined in Decision 22.
moves to another volume that rc7 fixes are a different defect. #68 4. Architecture/cmdlet design: Decision 22 remains proposed; two link
tracks `-WhatIf` and `-Confirm` for every cmdlet that changes security. changes are breaking. Keep unused classes/helper overloads until a
The labels follow Decision 17; #16, #21, #45, and #89 wait for their maintainer decision; do not remove them to improve coverage percentages.
reporters (Needs Info). Not planned for 5.0.0: the enhancements #22, 5. ARM64 workstation: PowerShell 7.6.1 crashed under x64 emulation without
#49, #68, #77, #87. module frames; native-x64 CI did not reproduce it.
3. Review findings, not filed: of rc3, an extra DACL read and four SDDL 6. Optional maintainer cleanup: obsolete AppVeyor/Read the Docs access,
snapshots on read paths, and a duplicate SACL check; of rc4, R3 to R5, wiki editing restrictions, `test/transfer`, and old lab checkpoints
R7, and five older defects, listed in the description of #113, among when no longer needed. No remote changes or snapshot restores here.
them the accounts filter that `RemoveFileSystemAccessRuleAll` and 7. Fresh coverage inventory at `3442194`: 918 unvisited sequence points.
`RemoveFileSystemAuditRuleAll` ignore, which no cmdlet passes; of rc5, Of these, 244 are in classes unused by cmdlets and 112 in parameter
the bare `catch` in `Win32.GetEffectiveAccess`, the unchecked getters; 562 remain for finer review/testing, including unused overloads,
`AUTHZ_ACCESS_REPLY.Error`, and hardening of the lab controller (guards defensive/native failures, and environment-specific branches. High-value
in the setup blocks, interpolated `-EncodedCommand` paths, CredSSP by local gaps closed: folders/Force/DeleteError, RestoreOwnerError, all
IP address, the password string in memory, disabling the role accounts scopes, file/folder inheritance, enumeration/depth/link skipping,
after a run); of rc6, a privilege that fails to be disabled isn't tried descriptor write failures, and forced file replacement. Remaining
again by `Dispose` (finding 2, not reproducible); of rc7, one error ID candidates: audit ownership-retry failures, SD inheritance edge cases,
for a missing path in the audit cmdlets (declined, Decision 22). effective-access unresolved identity, recursive denial/error surfaces,
4. Behavior changes found in Phase 2 (Decision 16): decided in Decision 22 output-object comparisons/formatting. A conditional ACE display remains
as assumptions for the maintainer's review, on `ai/release-5.0.0-rc7`; a .NET representation limit, not evidence of unconditional permissions.
two of them are breaking changes of the link cmdlets. Left for Phase 3: 8. Publication recovery is implemented locally in `95b827e`, with 14 offline
400 points of code that nothing calls besides the 244 lines of unused tests and exact artifact SHA-512 verification. Original upload errors
classes. remain errors for missing/different/unverifiable outcomes. Not deployed
5. `pwsh` 7.6.1 crashed three times during test runs on the ARM64 until the maintainer merges/pushes; no publication was performed here.
workstation (x64 emulation), without module frames; none of the CI runs 9. Phase 3: choose OS scope (proposed Windows 11 client/2019/2022 servers),
on native x64 on 2026-10-05 crashed. detect ISO editions, provision without repurposing shared VMs, then run
6. Optional for the maintainer: delete the AppVeyor project and revoke its published-package acceptance. #34 has no new reply since 2026-10-06.
GitHub authorization, restrict wiki editing to collaborators, ask 10. Lab rollback evidence: new checkpoints exist but report Standard even
`Sup3rlativ3` to delete the Read the Docs project, and delete the branch after a successful temporary ProductionOnly probe. Classification is
`test/transfer`. In the lab, delete the checkpoints unresolved; original VM policy restored, no checkpoint restored. Do
`ntfs-rc6-*-before-acceptance` and `ntfs-rc7-*-before-acceptance` of the not represent these as verified Production snapshots.
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.

148
.memory-bank/systemPatterns.md

@ -1,57 +1,27 @@
--- ---
status: current status: current
last-verified: 2026-10-08 last-verified: 2026-10-09
owner: active-agent owner: active-agent
source: repository evidence source: repository and regression evidence
--- ---
# System patterns # System patterns
## Architecture ## Architecture
```text | Component | Responsibility |
NTFSSecurity.psd1 ─┬─ ScriptsToProcess: NTFSSecurity.Init.ps1 | --- | --- |
│ Add-Type: Security2.dll, PrivilegeControl.dll, | `NTFSSecurity.psd1` | Root script, nested binary, initialization, types, help |
│ ProcessPrivileges.dll, inline NTFS.DriveInfoExt; | `NTFSSecurity.Init.ps1` | Loads Security2/privilege assemblies and prepends formatting |
│ Update-FormatData -PrependPath format.ps1xml | `NTFSSecurity.dll` | 36 PowerShell cmdlets; BaseCmdlet path/privilege behavior |
├─ TypesToProcess: NTFSSecurity.types.ps1xml | `Security2.dll` | DACL/SACL objects, owners, inheritance, effective access, Win32 |
│ (Owner, IsInheritanceBlocked, LengthOnDisk on | AlphaFS | Long-path files/directories/links |
│ FileInfo/DirectoryInfo; AccountType on ACEs) | PrivilegeControl / ProcessPrivileges | Token privilege operations |
├─ RootModule: NTFSSecurity.psm1 (aliases) | `en-US/NTFSSecurity.dll-Help.xml` | Committed help generated from cmdlet Markdown |
├─ 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`.
## Decisions ## Decisions
Each Decision record is a file in `decisions/`; read only the relevant ones. Read only task-relevant records; the index controls routing.
| # | Decision | | # | Decision |
| --- | --- | | --- | --- |
@ -80,65 +50,45 @@ Each Decision record is a file in `decisions/`; read only the relevant ones.
## Patterns ## Patterns
### Writing cmdlets ### Cmdlets and security sections
- A parameter that takes pipeline input needs a getter that doesn't - BaseCmdlet resolves relative paths against the current filesystem
throw: PowerShell reads it before it binds each input object, and an location; file-object input binds FullName through path transformation.
exception turns every object into `GetDefaultValueFailed` (the link - Write only changed/read sections (Decision 19); a descriptor parameter
cmdlets before 5.0.0-rc7). changes memory until `Set-NTFSSecurityDescriptor` persists it.
- An error for one item is non-terminating, so that the cmdlet goes on - Access denial can retry through InvokeAsOwner; restore the previous owner
with the next path or pipeline object; since 5.0.0-rc7, the link cmdlets on every exit, except a successful descriptor write that intentionally
too. Its message names the item, and its target object is the item that sets the owner. Restoration failures must report RestoreOwnerError.
the cmdlet was asked to process. Resolving a path can throw in Windows - Privilege cleanup runs in EndProcessing and Dispose, reads current states,
PowerShell for an invalid character, so that belongs inside the attempts all cleanup, and preserves explicit enables. Dispose has no stream.
per-item error handling. - Pipeline getters never throw; per-item errors name input and allow continuation.
- Folders move without `MoveOptions.CopyAllowed`: for another volume, - Folder moves never use CopyAllowed; preserve cross-volume source folders.
AlphaFS then copies and deletes, which lost empty folders. Windows - Apply implied Hidden/Force before deciding to emit, including the first item.
refuses such a move with `NotSameDeviceException` (17). Tests reach
another volume through `\\localhost\C$`, elevated only.
### Verifying documentation ### Tests and documentation
- Run platyPS in Windows PowerShell 5.1 against a Release build; a copy of - Tests import Release in isolated processes, both editions and privilege
`Docs/Cmdlets` must round-trip through `Update-MarkdownHelp` unchanged. modes. File/ACL/link fixtures use shared sandbox guards and cleanup.
Keep cmdlet pages ASCII-only. platyPS takes `Position` and `Required` from Privilege-dependent skips must have eligible counterparts in the matrix.
the shipped help file: after such a change, edit the page YAML, run - Assert persisted state, errors/targets, continuation, and no failed
`New-ExternalHelp`, rebuild, and check the round trip. PassThru output. Prove new characterization guards with bounded mutations;
- MarkdownLinkCheck checks relative `Docs` links, `Tests\Wiki.Tests.ps1` restore source exactly and rebuild before green validation or packaging.
the wiki links and anchors. The wiki is generated from `Docs` (never edit - Fixture DACLs use .NET SetAccessControl, not Set-Acl's unintended SACL writes.
it); `Docs/README.md` becomes Home, its cmdlet groups the sidebar. - Scope/descendant expectations are independent of the production converter.
- In cmdlet pages, end a sentence with a link (platyPS drops the space - Desktop platyPS: generate help, rebuild, round-trip unchanged, check links.
after it). Verify examples in a `$env:TEMP` sandbox, never on real data. - 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 - Use Path.Combine then GetFullPath for a rooted-or-repository-relative
them in Windows PowerShell 5.1 and PowerShell 7 (Decision 11). result path; Join-Path appends even a rooted child and corrupts it.
- A test that changes files, links, or security descriptors uses - Discovery handles only expected PackageNotFound as absence; repository,
`Tests\TestHelpers.psm1`: its own sandbox, `Assert-TestSandboxPath` authentication, and network errors remain failures.
before each change, `Remove-TestSandbox`. Cases that need a privilege - Rerun/uncertain-upload success requires Gallery SHA-512 equality with the
skip with `Test-PrivilegeHeld`, cases that need its absence skip when exact build artifact. Base64 is case-sensitive: use ordinal comparison.
elevated; CI runs the suite elevated and as a basic user in both Missing/different/unverifiable metadata preserves the upload error.
editions, so each case runs somewhere. `Block-Test*` make a read or a - Secrets stay by environment reference, never in process arguments/logs.
write fail without elevation; `Set-TestOwner` with Test all external publication commands with mocks; no test may upload.
`EnablePrivileges = $false` reproduces an owner the user can't assign. - AltCover aggregates all four sequential runs without --save. Report
- Fixtures write a DACL with `SetAccessControl`, never with `Set-Acl`: sequence points, not unique source lines; keep unmatched paths visible.
`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.

375
.memory-bank/techContext.md

@ -1,251 +1,156 @@
--- ---
status: current status: current
last-verified: 2026-10-08 last-verified: 2026-10-09
owner: active-agent owner: active-agent
source: repository evidence source: repository and executable evidence
--- ---
# Tech context # Tech context
## Stack ## Stack
- C# class libraries, old-style `.csproj`, .NET Framework 4.5.2, - Legacy C# projects, .NET Framework 4.5.2, `NTFSSecurity.sln`.
solution `NTFSSecurity.sln` (Visual Studio 2017 format). Cmdlets depend on Security2, PrivilegeControl/ProcessPrivileges, and
- Projects: `NTFSSecurity` (cmdlets), `Security2` (ACL object model, Win32 AlphaFS 2.2.x. System.Management.Automation reference: 10.0.10586.0.
interop), `PrivilegeControl` and `ProcessPrivileges` (token privileges), - Module supports Windows PowerShell 5.1 and PowerShell 7; 36 cmdlets.
`Log`, `TestClient`, `NTFSSecurityTest` (MSTest, minimal coverage). Manifest initializes helper assemblies, aliases, type data, formatting,
- NuGet (`packages.config`): AlphaFS 2.2.x for long paths; and committed help generated from `Docs/Cmdlets` (platyPS 0.14/schema 2).
`System.Management.Automation.dll` 10.0.10586.0. For a drive or volume - CI: `.github/workflows/ci.yml`, scripts in `.github/scripts`; GitHub
root, AlphaFS `DirectoryInfo` reaches the device object, while renders Docs and publishes a generated wiki. No separate docs site.
`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).
## Environment ## Current environment
- Windows only (NTFS, Win32 security APIs). - Host `ExHost`: Windows Server 2025 VM, native x64, elevated agent;
- The Debug build writes straight into repository `V:\Git\NTFSSecurity`. AutomatedLab 5.61.704, Hyper-V,
`C:\Program Files\WindowsPowerShell\Modules\NTFSSecurity\`. approved lab `WindowsAccessControlLab` (Decision 20).
- No Visual Studio MSBuild or .NET Framework targeting pack on the - Build Release only: Debug writes to Program Files. Native .NET Framework
workstation. A local build works with the .NET Framework MSBuild MSBuild plus Roslyn `Microsoft.Net.Compilers` 4.2.0 and .NET 4.5.2
(`%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\MSBuild.exe`) plus reference assemblies work; legacy compiler fails CS0136, dotnet MSBuild
`/p:CscToolPath` to the Roslyn `csc.exe` of the `Microsoft.Net.Compilers` fails binary resources MSB3822/MSB3823. Build packages are already cached
package; the legacy C# 5 compiler fails with CS0136. `dotnet msbuild` in `packages`; compiler/tools are under TEMP `ntfs-build`.
fails on the binary resources in `Resources.resx` (MSB3822, MSB3823). - Pester 5.7.1 is in
- platyPS 0.14.2, Pester 5.7.1, PSScriptAnalyzer, and powershell-yaml are `V:\Git\WindowsAccessControl\output\RequiredModules\Pester\5.7.1`.
installed only for PowerShell 7. Windows PowerShell 5.1, started from platyPS 0.14.2 and MarkdownLinkCheck 0.2.0 are under TEMP `ntfs-docs-tools`.
PowerShell 7, imports platyPS and Pester by full path PSScriptAnalyzer and PSResourceGet are available in PowerShell 7.
(`~\OneDrive\Documents\PowerShell\Modules\platyPS\0.14.2`, - Use Desktop's module paths in Desktop children, not inherited Core-only
`C:\Program Files\PowerShell\Modules\Pester\5.7.1`). Leave paths. Never import NTFSSecurity in the agent shell; every package/build
`$env:PSModulePath` alone: PowerShell 7 hands the child the Windows runs in a new process. Current prereleases share assembly version 5.0.0.0.
PowerShell default path, and clearing it leaves Windows PowerShell without - GitHub CLI: `C:\Program Files\GitHub CLI\gh.exe`, signed in as raandree.
its core modules (Pester fails: `Add-Member` not found). Read-only queries work; remote mutations belong to the maintainer.
- MarkdownLinkCheck is not installed, and `Save-Module` crashed (FailFast) - LabSources: `V:\LabSources`. All 13 deployed machines are Server 2025.
in PowerShell 7.6 on 2026-10-04. Download the 0.2.0 package from Windows 11 consumer/enterprise-evaluation media and Server 2019/2022
`https://www.powershellgallery.com/api/v2/package/MarkdownLinkCheck/0.2.0` ISO files exist. OS cache is empty; exact detected editions are not yet
into `$env:TEMP`, extract it, and import it by path. verified. Do not equate present media with a deployed/tested OS matrix.
- 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\<Id>.<Version>`, 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/<id>/<version>/<id>.<version>.nupkg`,
extract the first three into `packages\<Id>.<Version>` 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/<id>/<version>.json`,
then `catalogEntry`), and each Gallery package against `PackageHash` of
`api/v2/Packages(Id='<id>',Version='<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`.
## Constraints ## Constraints
- `ModuleVersion` is `5.0.0` with the prerelease label `rc6` on the branch - Source manifest: ModuleVersion 5.0.0, prerelease rc7 on #116/follow-up.
`ai/release-5.0.0-rc6` (`rc5` on `master`). Latest stable: 4.2.6; latest published prerelease: rc6 (2026-10-08).
The latest stable tag and Gallery release is `4.2.6`. The manifest GitHub rc6 release recovered 2026-10-09. rc7 publication is pending.
requires PowerShell 5.1 and .NET Framework 4.5.2, uses `RootModule`, and - Changed-section writes preserve unchanged owner/group/DACL/SACL (19).
lists exactly 36 cmdlets; `Test-ModuleManifest` passes in Windows Roots use root-folder APIs, not AlphaFS device security (#41).
PowerShell 5.1 and PowerShell 7.6. - CHANGELOG contains user-visible changes only (7); tests and CI-only fixes
- The module source at `master` differs from tag `4.2.6` by the changes get no entry. No stable release until Decision 21 gates close.
that `CHANGELOG.md` lists under `[Unreleased]`, the release notes of each - Honor separate topic branches, no amendment, two AI co-author trailers.
5.0.0 prerelease. Never work around remote-mutation blocking. Provide each maintainer
- PowerShell Gallery versions (publish dates): 4.0.0 (2015-08-19), 4.2.2 command separately at reply end, no question dialog after commands.
(2016-05-18), 4.2.3 (2016-05-19), 4.2.4 (2018-08-13), 4.2.5 (2019-07-11), Issue references use no closing keyword unless closure is intended.
4.2.6 (2019-07-12), none with release notes; 5.0.0-rc1 (2026-10-04), - Lab passwords stay in memory and are lab-only; no secret in repository,
5.0.0-rc2 (2026-10-05), 5.0.0-rc3 and 5.0.0-rc4 (2026-10-06), 5.0.0-rc5 logs, or process arguments. Live ACL mutations occur only in the lab.
(2026-10-08), published - Existing expired installation passwords of a.forest1/b.forest1 were
by CI. Older versions were released on CodePlex only, and their dates are configured not to expire on 2026-10-07, matching the root domain.
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.
## Validation ## Build and focused checks
- CI (`.github/workflows/ci.yml`): job `build` on `windows-2025` installs - Build `NTFSSecurity\NTFSSecurity.csproj` with Configuration=Release,
platyPS 0.14.2, MarkdownLinkCheck 0.2.0, and Pester 5.7.1 for all users, Framework MSBuild, TargetFrameworkRootPath/FrameworkPathOverride to
restores `packages.config` per project plus `packages\Microsoft.NETFramework.ReferenceAssemblies.net452.1.0.3\build`,
`Microsoft.NETFramework.ReferenceAssemblies.net452` 1.0.3, builds CscToolPath to the cached compiler. Expected legacy CS1591/CS0618 warnings
`NTFSSecurity.csproj` in Release with the MSBuild that `vswhere` finds, are not new failures. Never copy a mutated DLL into acceptance artifacts.
then: 01 `Update-MarkdownHelp` and fail on `git diff -- Docs/Cmdlets`; 02 - Pester/builds run in detached monitored child processes through
`Get-MarkdownLink -BrokenOnly`; 03 regenerate the help file and fail on `Start-DetachedPowerShell.ps1`; use unique TEMP logs/result paths and an
`git status --porcelain -- NTFSSecurity/en-US`; 04 `Invoke-Tests.ps1` in explicit-PID watcher. No foreground sleep/poll loop. Long payloads use
Windows PowerShell 5.1 and in PowerShell 7, then a script file: nested Base64 encoding can exceed Windows command limits.
`Invoke-TestsAsBasicUser.ps1` in both editions (since 5.0.0-rc6). Job - Focused helper: TEMP `ntfs-focused\Start-FocusedRuns.ps1`; detach that
`wiki` on `ubuntu-latest` driver too because its internal wait loop must not block the agent shell.
(read-only) clones the wiki (`gh auth setup-git` with the built-in token), - TEMP `ntfs-docs-tools\Invoke-ChangeChecks.ps1 -File <relative paths>`
runs `Export-WikiContent.ps1`, and lists the changed pages in the job performs AST/analyzer/lint/help checks. Absolute input paths misroute
summary; job `publish-wiki` (`contents: write`) repeats that and publishes, cmdlet pages. Check actual analyzer/lint output, not just helper exit.
for `master` only. After the tests, `build` runs - actionlint 1.7.12 checks the workflow. Script changes use AST parse and
`New-ModulePackage.ps1` and uploads the artifact `packages` (nupkg and PSScriptAnalyzer; prose Markdown uses MD013 and changelog siblings-only
`NTFSSecurity.zip`). Job `release` runs only for tags matching repeated-heading allowance. Native error codes must be checked explicitly.
`[0-9]+.[0-9]+.[0-9]+` or `[0-9]+.[0-9]+.[0-9]+-*`, in the environment - Documentation: run platyPS in Desktop, generate external help, rebuild,
`powershell-gallery` (secret `PSGALLERY_API_KEY`); see Decision 12. require an unchanged Markdown round trip. Links in Docs are checked
Actions are pinned by commit SHA: `actions/checkout` v7.0.1, relatively; Wiki tests cover generated anchors, not arbitrary web URLs.
`actions/upload-artifact` v7.0.1, `actions/download-artifact` v8.0.1;
Dependabot proposes updates weekly, one week after a release. ## CI and packaging
- Packaging needs PSResourceGet (`Compress-PSResource`, PowerShell 7.4 or
later); its tests skip in Windows PowerShell. Dry run locally: run - CI `build` on windows-2025 installs tools, restores dependencies, builds
`New-ModulePackage.ps1` against `NTFSSecurity\bin\Release` into Release, round-trips pages/help, checks links, and runs the suite in
`$env:TEMP`, then extract the nupkg into a folder and import it there. Desktop/Core, elevated/basic user. Lab tests are explicitly excluded.
- Read CI runs with `gh run list --repo raandree/NTFSSecurity --workflow - `.github/scripts/Invoke-TestsAsBasicUser.ps1` launches a SAFER Normal User
ci.yml`, `gh pr checks <number>`, and `gh run view <id> --log-failed` token. Result paths may be absolute or repository-relative: Path.Combine
(read-only). then GetFullPath, not Join-Path with a rooted child.
- Workflow lint: actionlint (download the release zip into `$env:TEMP` and - Packaging needs Compress-PSResource (Core 7.4+). New-ModulePackage copies
check its SHA-256 against the checksum file; 1.7.12 on 2026-10-08); only FileList, validates the manifest, creates nupkg plus NTFSSecurity.zip.
PowerShell steps check Check package/file hashes and test the extracted artifact, not build extras.
`$LASTEXITCODE` after every native command, because GitHub checks only - Release runs only for validated version tags in powershell-gallery.
the last one. API key stays as PSGALLERY_API_KEY environment reference. Helper
- Run platyPS in Windows PowerShell 5.1 to avoid PowerShell 7.4+ Publish-ModulePackage treats only PackageNotFound as expected absence;
`-ProgressAction` noise. existing-version skip and uncertain-upload recovery require exact Gallery
- Placeholder check: no `{{` left in `Docs/Cmdlets/*.md`. SHA-512 equality. Base64 comparison is case-sensitive. Unverifiable,
- Help file: `New-ExternalHelp -Path .\Docs\Cmdlets -OutputPath missing, and different outcomes preserve errors. No test uploads.
.\NTFSSecurity\en-US -Force` must leave `git status` unchanged. - Read status through gh pr checks / gh run view --log-failed. A successful
- Pester: run detached (`Start-DetachedPowerShell.ps1`) in Windows Gallery upload followed by HTTP 409 does not prove its retry chronology.
PowerShell 5.1: the launcher starts `pwsh`, and its payload runs
`powershell.exe -NoProfile -EncodedCommand` with Pester imported by full ## Coverage and test eligibility
path. A run without `bin\Release\en-US` must fail.
- Tests that run only without a privilege skip in an elevated session. - AltCover 9.0.145 net472 instruments a copied Release build with PDBs,
`.github\scripts\Invoke-TestsAsBasicUser.ps1` runs the suite from an OpenCover format, localSource, excluding AlphaFS/System.Management.Automation.
elevated session with a token of the SAFER level Normal User, like Do not use --save: collection previously retained only one process's hits.
`runas /trustlevel:0x20000`, and CI runs it in both editions. For a - Freeze a git worktree, instrument its NTFSSecurity\bin\Release, run all
single file, `runas /trustlevel:0x20000` works too; give Windows four configurations sequentially with the real CI wrappers, then
PowerShell its own `PSModulePath`, and note that `runas` returns at once, AltCover runner --collect recalculates the report. Compute option paths
so the script it starts writes its own log. Both tokens hold only the before passing native arguments, not inline Join-Path expressions.
privilege to bypass traverse checking. - Report sequence points, not unique source lines. Four-run baselines:
Pester reports a skipped `-ForEach` test under its template name, such as rc5 2,020/3,476 (58.1%), branches 711/1,873 (38.0%);
`<_> should ...`, and a test that ran under the expanded name: compare rc6 2,412/3,540 (68.14%), branches 850/1,918 (44.32%);
runs by template. follow-up `3442194` 2,641/3,559 (74.21%), 974/1,933 (50.39%).
- C# coverage (Decision 21): AltCover 9.0.145 (`tools\net472\AltCover.exe` NTFSSecurity assembly: 1,769/2,099 (84.28%). Different code changes
of the nuget.org package) instruments a copy of the local Release build, denominators; never present these as same-source incremental percentages.
which has the PDB files that the published package lacks: - Final suite: 914 per configuration, zero failures. Passed/skipped:
`--reportFormat=OpenCover`, AlphaFS and `System.Management.Automation` elevated Desktop 890/24, Core 860/54; basic Desktop 749/165, Core 719/195.
excluded with `--assemblyFilter`, and no `--save`: then every process - NUnit skipped ForEach names retain placeholders and parameter tuples,
writes its hits into the report when it exits. With `--save`, each executed names expand them. Strip trailing data tuples and match templates;
process writes a recorder file, and `runner --collect` keeps only the raw-name intersection or positional alignment is invalid across editions.
first one (verified 2026-10-08), so the numbers measured that way held 139 skipped templates have eligible executed counterparts. Inspect input
only the main process of the elevated Windows PowerShell run. Put the eligibility when an individual data row has a condition of its own.
instrumented module in `NTFSSecurity\bin\Release` of a `git worktree`, - Remaining inventory: 918 points, including 244 in cmdlet-unused classes,
run `.github\scripts\Invoke-Tests.ps1` elevated and 112 parameter-getter points, and 562 awaiting finer classification/testing.
`Invoke-TestsAsBasicUser.ps1` in both editions, then Preserve raw XML, eligibility CSV, logs, commit identity, and build hashes.
`AltCover.exe runner --collect --recorderDirectory=<the instrumented
folder>`, which recalculates the summary of the report from the hits. ## Lab acceptance
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 - Defaults: F1ADC1 (domain), F1AFile2 (server), F1AFile1 (client), all in
244 lines in classes that no cmdlet calls; the rc6 candidate (`1b9edbb`) a.forest1.net. Foreign accounts use F1BDC1, F2DC1, F3DC1 and existing trusts.
68.1% of the lines (2,412 of 3,540) and 44.3% of the branches (850 of Controller accepts alternate machines; changing topology/OS scope waits
1,918), 73.2% without those classes, the `NTFSSecurity` assembly 78.1%. for a maintainer decision. Do not repurpose another project's shared VMs.
The earlier figures, 55.9% for rc5 and 65.6% for rc6, used `--save`. - Before a run: authenticated WinRM, LDAP RootDSE, Kerberos tickets, member
- Live tests (Decision 20): in an elevated Windows PowerShell 5.1 session secure channels, clocks; checkpoint only approved targets. Inspect actual
on the lab host, `Tests\Lab\Invoke-NTFSSecurityLabTest.ps1` with checkpoint kind: new checkpoints reported Standard even after a successful
`-Version` for Gallery packages or `-ModulePath` for a build; it writes temporary ProductionOnly request. Policy restored; no rollback performed;
the results to `$env:TEMP\NTFSSecurityLab\Results`. A run of two versions Production classification remains unverified, not a passed safety check.
in both editions takes about 30 minutes; `-RemoveFixture` removes its - Run Tests\Lab\Invoke-NTFSSecurityLabTest.ps1 in elevated Desktop with
accounts, share, and folders from the lab. For a check on the client as -Version for hash-checked Gallery packages or -ModulePath for the extracted
an account without administrator rights, use `NtfsLiveServerAdmin` build artifact, both editions. Per version/edition: Delegate, ServerAdmin,
(Remote Management Users on the client, CredSSP by IP address like the Admin on client, then Server independently checks persisted state.
controller): reset its password on the PDC emulator to a random value - Controller writes Summary.json even when tests fail: validate every role,
in memory; the next run of the controller sets a new one anyway. exit code, failure name, and total; DONE alone is not acceptance evidence.
- Lab acceptance of a candidate (modeled on the WindowsAccessControl Desktop ConvertFrom-Json can wrap arrays; explicitly enumerate the result
handoff 07): build once, package it with `New-ModulePackage.ps1`, and and compare full Describe-prefixed names. Never gate cleanup on the global
record the SHA-256 of the packages and module files; check WinRM, LDAP Error.Count, which includes handled errors; independently verify footprint.
(RootDSE), Kerberos (`klist get`), the secure channel, and the clock of - Remote Authz answers administrators and Access Control Assistance
the six VMs; take a Production checkpoint named Operators (S-1-5-32-579); other accounts get access denied. Check firewall
`ntfs-<label>-<commit>-before-acceptance` of `F1ADC1`, `F1BDC1`, when remote resource-manager RPC fails. Expected rights use S4U tokens.
`F2DC1`, `F3DC1`, `F1AFile1`, and `F1AFile2`; run the controller with - RemoveFixture after the run; verify OUs/accounts, share, folders, local
`-ModulePath` of the extracted `NTFSSecurity.zip` in both editions; then memberships, and test profiles removed. Credentials must never be printed.
`-RemoveFixture` and check that the accounts, share, folders, group
memberships, and profiles are gone.
- `Get-NTFSEffectiveAccess -ServerName`: the authorization manager of the
named computer answers only its administrators and the members of its
group Access Control Assistance Operators (S-1-5-32-579); others get
"Access is denied" (5). Lab probe of 2026-10-08 on `F1AFile2`.
- Markdown lint: `npx markdownlint-cli2` with `MD013` limited to prose
(tables, code, and headings excluded) on the conceptual pages; for
`CHANGELOG.md` also `MD024` with `siblings_only: true`, because every
version repeats the category headings.
- Gallery packages: download
`https://www.powershellgallery.com/api/v2/package/NTFSSecurity/<version>`
into `$env:TEMP` and extract it; dates come from the OData endpoint
`api/v2/FindPackagesById()?id='NTFSSecurity'`. Import each version in its
own process: every version's `NTFSSecurity.dll` has assembly version
4.2.1.0, so a second version in the same process reuses the first DLL.
- YAML: `ConvertFrom-Yaml` (powershell-yaml) on `.github/workflows/ci.yml`.
- Links: the CI step 02 (MarkdownLinkCheck 0.2.0) checks only relative
links in `Docs`; it strips anchors and skips absolute URLs.
`Wiki.Tests.ps1` checks the wiki links with their anchors; check the
links in `README.md` and `CHANGELOG.md` with a script.

Loading…
Cancel
Save