Files
Sharepoint-Toolbox/.planning/phases/02-permissions/02-VERIFICATION.md
2026-04-02 14:29:22 +02:00

13 KiB

phase, verified, status, score, human_verification
phase verified status score human_verification
02-permissions 2026-04-02T14:30:00Z human_needed 6/7 must-haves verified automatically
test expected why_human
Run the application and confirm all 7 UI checklist items in Plan 07 Permissions tab visible with scan options, DataGrid, export buttons disabled when empty, French locale translates all labels, Cancel button disabled at idle, View Sites opens SitePickerDialog UI layout, localization rendering, live dialog behavior, and button enabled-state cannot be verified programmatically
test expected why_human
Confirm Export CSV / Export HTML buttons are localized (or intentionally hardcoded) Buttons either use the rad.csv.perms / rad.html.perms localization keys, or the decision to use hardcoded 'Export CSV' / 'Export HTML' was intentional XAML uses hardcoded English strings 'Export CSV' and 'Export HTML' instead of localization bindings — minor i18n gap that needs human decision on whether it is acceptable

Phase 2: Permissions Verification Report

Phase Goal: Implement the Permissions tab — a full SharePoint permissions scanner with multi-site support, CSV/HTML export, and scan options. Port of the PowerShell Generate-PnPSitePermissionRpt function. Verified: 2026-04-02T14:30:00Z Status: human_needed Re-verification: No — initial verification


Goal Achievement

Observable Truths

# Truth Status Evidence
1 User can scan permissions on a single SharePoint site with configurable depth (PERM-01) VERIFIED PermissionsService.ScanSiteAsync fully implemented; SiteUrl bound in XAML; ScanOptions(FolderDepth) passed through
2 User can scan permissions across multiple selected sites in one operation (PERM-02) VERIFIED PermissionsViewModel.RunOperationAsync loops over SelectedSites; PermissionsViewModelTests.StartScanAsync_WithMultipleSiteUrls_CallsServiceOncePerUrl passes; SiteListService + SitePickerDialog wired end-to-end
3 Permissions scan includes owners, members, guests, external users, and broken inheritance (PERM-03) VERIFIED PermissionsService scans site collection admins, web, lists, folders; #EXT# detection in PermissionEntryHelper.IsExternalUser; PrincipalType set correctly; 7 classification tests pass
4 User can choose to include or exclude inherited permissions (PERM-04) VERIFIED IncludeInherited bool bound in XAML via {Binding IncludeInherited}; passed to ScanOptions; ExtractPermissionsAsync skips non-unique objects when IncludeInherited=false
5 User can export permissions report to CSV (PERM-05) VERIFIED CsvExportService.BuildCsv + WriteAsync implemented; UTF-8 BOM; merges rows by (Users, PermissionLevels, GrantedThrough); all 3 CsvExportServiceTests pass
6 User can export permissions report to interactive HTML (PERM-06) VERIFIED HtmlExportService.BuildHtml produces self-contained HTML with inline CSS/JS, stats cards, type badges, external-user pills; all 3 HtmlExportServiceTests pass
7 SharePoint 5,000-item list view threshold handled via pagination — no silent failures (PERM-07) VERIFIED PermissionsService.GetFolderPermissionsAsync uses SharePointPaginationHelper.GetAllItemsAsync with RowLimit 500 pagination — never raw list enumeration (grep confirmed line 222)

Score: 7/7 truths verified (all automated; 2 items need human confirmation for UI/i18n quality)


Required Artifacts

Artifact Provided By Status Details
SharepointToolbox/Core/Models/PermissionEntry.cs Plan 02 VERIFIED 9-field record; compiles; referenced by tests
SharepointToolbox/Core/Models/ScanOptions.cs Plan 02 VERIFIED Immutable record with correct defaults
SharepointToolbox/Core/Models/SiteInfo.cs Plan 03 VERIFIED record SiteInfo(string Url, string Title)
SharepointToolbox/Services/IPermissionsService.cs Plan 02 VERIFIED Interface with ScanSiteAsync signature
SharepointToolbox/Services/PermissionsService.cs Plan 02 VERIFIED 341 lines; implements all 5 scan paths
SharepointToolbox/Services/ISiteListService.cs Plan 03 VERIFIED Interface with GetSitesAsync signature
SharepointToolbox/Services/SiteListService.cs Plan 03 VERIFIED DeriveAdminUrl implemented; error wrapping present
SharepointToolbox/Services/Export/CsvExportService.cs Plan 04 VERIFIED Merge logic + RFC 4180 escaping + UTF-8 BOM
SharepointToolbox/Services/Export/HtmlExportService.cs Plan 04 VERIFIED Self-contained HTML; no external deps; external-user class
SharepointToolbox/Core/Helpers/PermissionEntryHelper.cs Plan 01 VERIFIED IsExternalUser, FilterPermissionLevels, IsSharingLinksGroup
SharepointToolbox/ViewModels/Tabs/PermissionsViewModel.cs Plan 06 VERIFIED FeatureViewModelBase subclass; 309 lines; all commands present
SharepointToolbox/Views/Dialogs/SitePickerDialog.xaml.cs Plan 06 VERIFIED Loads sites via ISiteListService; filter; CheckBox; OK/Cancel
SharepointToolbox/Views/Tabs/PermissionsView.xaml Plan 07 VERIFIED Left config panel + right DataGrid + StatusBar; localized
SharepointToolbox/Views/Tabs/PermissionsView.xaml.cs Plan 07 VERIFIED DI wiring; GetRequiredService<PermissionsViewModel>(); dialog factory
SharepointToolbox/App.xaml.cs Plan 07 VERIFIED All Phase 2 DI registrations present; Func<TenantProfile, SitePickerDialog> factory registered
SharepointToolbox/MainWindow.xaml Plan 07 VERIFIED PermissionsTabItem uses x:Name; no FeatureTabBase stub
SharepointToolbox/MainWindow.xaml.cs Plan 07 VERIFIED PermissionsTabItem.Content = serviceProvider.GetRequiredService<PermissionsView>()
SharepointToolbox/Localization/Strings.resx Plan 05 VERIFIED 15 Phase 2 keys present (grp.scan.opts, btn.gen.perms, perm.sites.selected, etc.)
SharepointToolbox/Localization/Strings.fr.resx Plan 05 VERIFIED 15 keys with French translations (e.g., "Options d'analyse", "Analyser les dossiers")
SharepointToolbox/Localization/Strings.Designer.cs Plan 05 PARTIAL 15 new static properties present; tab_permissions property absent (key exists in resx, MainWindow binds via TranslationSource directly — low impact)
Test scaffold (5 files) Plan 01 VERIFIED All exist; classification tests pass; ViewModel test passes

From To Via Status Evidence
PermissionsService.cs SharePointPaginationHelper.GetAllItemsAsync Folder enumeration WIRED Line 222: await foreach (var item in SharePointPaginationHelper.GetAllItemsAsync(...))
PermissionsService.cs ExecuteQueryRetryHelper.ExecuteQueryRetryAsync All CSOM round-trips WIRED 7 call sites in service (lines 52, 86, 125, 217, 245, 283)
PermissionsService.cs PermissionEntryHelper.IsExternalUser User classification WIRED Line 314
PermissionsService.cs PermissionEntryHelper.FilterPermissionLevels Level filtering WIRED Line 304
PermissionsService.cs PermissionEntryHelper.IsSharingLinksGroup Group skipping WIRED Line 299
SiteListService.cs SessionManager.GetOrCreateContextAsync Admin context acquisition WIRED Line 41
SiteListService.cs Microsoft.Online.SharePoint.TenantAdministration.Tenant GetSitePropertiesFromSharePoint WIRED Line 49: new Tenant(adminCtx)
PermissionsViewModel.cs IPermissionsService.ScanSiteAsync RunOperationAsync loop WIRED Line 189
PermissionsViewModel.cs CsvExportService.WriteAsync ExportCsvCommand handler WIRED Line 252
PermissionsViewModel.cs HtmlExportService.WriteAsync ExportHtmlCommand handler WIRED Line 275
SitePickerDialog.xaml.cs ISiteListService.GetSitesAsync Window.Loaded handler WIRED Line 42
PermissionsView.xaml.cs PermissionsViewModel GetRequiredService<PermissionsViewModel>() WIRED Line 14
PermissionsView.xaml.cs SitePickerDialog OpenSitePickerDialog factory WIRED Lines 16-19
App.xaml.cs Phase 2 services AddTransient<IPermissionsService, PermissionsService>() etc. WIRED Lines 92-100

Requirements Coverage

Requirement Source Plans Description Status Evidence
PERM-01 02-01, 02-02, 02-05, 02-06, 02-07 Single-site scan with configurable depth SATISFIED PermissionsService.ScanSiteAsync; SiteUrl XAML binding; ScanOptions wired
PERM-02 02-01, 02-03, 02-06, 02-07 Multi-site scan SATISFIED SiteListService; SitePickerDialog; loop in RunOperationAsync; test passes
PERM-03 02-01, 02-02, 02-07 Owners, members, guests, external users, broken inheritance SATISFIED Site collection admins path; #EXT# detection; PrincipalType assignment; 7 classification tests pass
PERM-04 02-01, 02-02, 02-05, 02-06, 02-07 Include/exclude inherited permissions SATISFIED IncludeInherited checkbox bound; ScanOptions record passed; ExtractPermissionsAsync gate
PERM-05 02-01, 02-04, 02-07 CSV export SATISFIED CsvExportService with merge, RFC 4180 escaping, UTF-8 BOM; 3 tests pass; ExportCsvCommand wired
PERM-06 02-01, 02-04, 02-07 HTML export SATISFIED HtmlExportService self-contained HTML; inline CSS/JS; stats cards; external-user pills; 3 tests pass; ExportHtmlCommand wired
PERM-07 02-02, 02-07 5,000-item list view threshold — pagination SATISFIED SharePointPaginationHelper.GetAllItemsAsync called in GetFolderPermissionsAsync; RowLimit 500 CAML

All 7 PERM requirements: SATISFIED


Anti-Patterns Found

File Line Pattern Severity Impact
PermissionsView.xaml 80, 84 Hardcoded Content="Export CSV" and Content="Export HTML" instead of localization bindings Info French locale users see English button labels; rad.csv.perms and rad.html.perms keys exist in resx and Designer.cs but are unused in XAML
Strings.Designer.cs n/a Missing tab_permissions static property (key exists in resx) Info No functional impact — TranslationSource.Instance["tab.permissions"] resolves correctly at runtime via ResourceManager; Designer.cs property is just a typed convenience accessor

No Blocker or Warning severity anti-patterns found.


Human Verification Required

1. Full UI visual checkpoint

Test: Run the application (dotnet run --project SharepointToolbox or F5). Navigate to the Permissions tab. Expected:

  • Tab is labelled "Permissions" (or "Permissions" in French) and shows scan options panel + empty DataGrid, not "Coming soon"
  • Scan Options panel shows: Site URL input, "View Sites" button, "Scan Folders" checkbox, "Include Inherited Permissions" checkbox, "Recursive (subsites)" checkbox, "Folder depth" input, "Maximum (all levels)" checkbox
  • "Generate Report" and "Cancel" buttons present
  • "Export CSV" and "Export HTML" buttons are disabled (grayed out) with no results
  • Click "View Sites" — SitePickerDialog opens (auth error expected if not connected — must not crash)
  • Switch to French (Settings tab) — all labels in Permissions tab change to French text Why human: Visual appearance, disabled-state behavior, and locale rendering cannot be verified programmatically.

2. Export button localization decision

Test: In the running application (French locale), check the text on the Export buttons. Expected: Either the buttons read "CSV" / "HTML" (acceptable if intentional) or the team decides to bind them to rad.csv.perms / rad.html.perms. Why human: The XAML has Content="Export CSV" and Content="Export HTML" hardcoded — the localization keys exist but are not used. This is a minor i18n gap requiring a team decision, not a blocker.


Test Results

Test class Tests Passed Skipped Failed
PermissionEntryClassificationTests 7 7 0 0
CsvExportServiceTests 3 3 0 0
HtmlExportServiceTests 3 3 0 0
PermissionsViewModelTests 1 1 0 0
SiteListServiceTests 2 2 0 0
PermissionsServiceTests 2 0 2 0
Full suite 63 60 3 0

Skipped tests are intentional live-CSOM stubs (require a real SharePoint context).


Gaps Summary

No gaps blocking goal achievement. All 7 PERM requirements are implemented with real, substantive code. All key links are wired. All critical service chains are verified.

Two minor informational items were found:

  1. Export buttons in PermissionsView.xaml use hardcoded English strings instead of the localization keys that exist in the resx files. This causes the buttons to stay in English when switching to French. The keys rad.csv.perms ("CSV") and rad.html.perms ("HTML") do exist and resolve correctly — they just aren't bound. This is a cosmetic i18n gap, not a functional failure.
  2. Strings.Designer.cs is missing the tab_permissions typed property (the key exists in both resx files and the MainWindow binding resolves it correctly at runtime via TranslationSource).

Verified: 2026-04-02T14:30:00Z Verifier: Claude (gsd-verifier)