Commit Graph

208 Commits

Author SHA1 Message Date
sysadmin
260023a1a5 feat(apps): catalog.json + chromium configure + winget bootstrap + build staging
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 6m36s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:41:18 +01:00
sysadmin
3c7654f128 feat(apps): install selected apps during Apply (after accounts, before BitLocker)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:36:54 +01:00
sysadmin
de18ee8dd2 feat(apps): insert Apps step after Flavour + seed per-role defaults
Insert AppsStep as wizard index 2 (renumbering Account/Prefs/Apply/Done
to 3-6), load the app catalog alongside flavours, seed the per-role
default selection on entering the step, and register IAppCatalog in DI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:27:18 +01:00
sysadmin
993d4028a2 feat(apps): AppsStep grouped checkboxes
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:27:11 +01:00
sysadmin
52d7187991 feat(apps): WizardState.SelectedApps
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 00:27:06 +01:00
sysadmin
cd3808de64 feat(apps): winget install engine (bootstrap + per-app + configure, continue-on-failure)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:22:19 +01:00
sysadmin
18eb42324a feat(apps): AppCatalog loader + role filtering 2026-06-10 00:18:58 +01:00
sysadmin
bfb53bd295 feat(apps): AppCatalogEntry record + test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:16:10 +01:00
sysadmin
1e59029e53 docs(welcome): app-recipes implementation plan 2026-06-10 00:14:30 +01:00
sysadmin
58d261cc6b style(hardening): ascii-ify em-dash in kernel-credential comment 2026-06-10 00:14:30 +01:00
sysadmin
583ed4400c docs(welcome): role app-recipes design spec
Per-role app-install picker for the Welcome wizard: catalog.json + AppsStep + winget
install engine (phased, swappable source for a future curated mirror). Stack stays
auto-installed; picker adds role apps + privacy-trimmed essentials. Approved in
brainstorming. Next: writing-plans.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:58:37 +01:00
efdf5888ac Merge pull request 'fix(kiosk): keyboard filter covers admins + taskbar auto-hide + instant sm-bootstrap disable' (#16) from fix/kiosk-lockdown-polish into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m43s
2026-06-09 22:36:42 +00:00
sysadmin
e83ce6bcf0 fix(kiosk): keyboard filter covers admins + taskbar auto-hide + disable sm-bootstrap in-session
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m0s
Live e2e: in the sm-bootstrap session the taskbar showed and Win/Start worked.
- Keyboard Filter EXEMPTS administrators by default and sm-bootstrap is an admin, so
  Win/Start/Alt-Tab etc. were never blocked. Set WEKF_Settings
  DisableKeyboardFilterForAdministrators=false so the filter applies to it.
- Auto-hide the taskbar (default-user StuckRects3, inherited by sm-bootstrap) so it
  doesn't peek over the fullscreen wizard.
- TearDownAsync now Disable-LocalUser's sm-bootstrap in-session (immediate) so it's
  unusable at once; the deferred SYSTEM task still deletes it on next boot (SAM-confirmed
  the delete works now).

Verified: Configure-Kiosk parses under Windows PowerShell 5.1 (ASCII-clean); welcome 29/29.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 23:30:43 +01:00
sysadmin
6124448003 fix(first-boot): branding-online parse crash (em-dash/encoding) + bootstrap cleanup task + recovery QR
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m47s
Found by reading the unencrypted VM disk after run #7:
1. Online branding never ran: Apply-Branding.ps1 had a UTF-8 em-dash in a Write-Warning
   STRING; Windows PowerShell 5.1 (SetupComplete) reads .ps1 as ANSI, mangled it, broke
   the string terminator -> whole script failed to parse -> lock/login/wallpaper branding
   never re-applied. Fix: ASCII-ify the em-dash AND save the branding scripts UTF-8-with-BOM
   so PS5.1 always decodes them correctly (verified parses under PS5.1 + PS7).
2. sm-bootstrap never removed: TearDownAsync used schtasks /tr with an inline -EncodedCommand,
   which silently fails past the ~261-char /tr limit, so the cleanup task was never created
   (confirmed NO_TASK on disk). Fix: Register-ScheduledTask (no length limit).
3. Done step: show a QR code of the BitLocker recovery key (QRCoder) for phone backup, and
   lay key+QR side-by-side so the Restart button no longer overflows below the fold.

Verified: welcome solution builds, 29/29 tests; branding Pester 6/6 unit (offline-integration
needs elevation, runs in CI).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 22:41:30 +01:00
5f0df87405 Merge pull request 'fix(welcome): BitLocker PIN first-boot + recovery-key display + FlavourStep Next' (#14) from feat/wizard-recipes into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 6m3s
Reviewed-on: #14
2026-06-09 21:05:40 +00:00
sysadmin
a3623b1fbb fix(welcome): BitLocker PIN works first boot (drop -SkipHardwareTest) + show recovery key
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 7m5s
- BitLocker: remove -SkipHardwareTest so BitLocker validates the TPM+PIN unseal via
  its hardware test on the next reboot (the wizard's end-of-flow reboot) before
  encrypting — fixes the E_FVE_SECURE_BOOT_CHANGED / PCR-11 drop-to-recovery on the
  first post-enroll boot. The PIN now works first time instead of needing recovery.
- Done step now DISPLAYS the 48-digit BitLocker recovery key (read from the file the
  enrollment saves) with a 'save this' warning — previously it was never surfaced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 21:57:47 +01:00
94de283495 Merge pull request 'fix(first-boot): online branding re-apply + deferred sm-bootstrap cleanup' (#13) from fix/branding-online-and-bootstrap-cleanup into main
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (push) Failing after 6m19s
Reviewed-on: #13
2026-06-09 20:57:29 +00:00
sysadmin
6d6eb2cdc8 fix(welcome): FlavourStep notifies host on select so Next enables immediately
WIP on local branch feat/wizard-recipes (NOT pushed) — holding per operator while
more wizard changes (role app-recipes) are designed.
2026-06-09 21:45:20 +01:00
sysadmin
daac231148 fix(first-boot): re-apply personalization branding online + defer sm-bootstrap cleanup
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m37s
VM e2e findings on the real-user desktop:
1. Lock/login screen + wallpaper NOT branded (OEM About WAS) — Windows resets the
   offline-baked personalization (PersonalizationCSP / default-user wallpaper / FVE)
   during OOBE, same class as the UAC reset. Fix: stage windows/branding/ into the
   image and re-run Apply-Branding -Mode Online from SetupComplete (post-OOBE, as
   SYSTEM) where it sticks. OEM About re-asserted harmlessly.
2. sm-bootstrap account still present after onboarding — TearDownAsync's in-session
   Remove-LocalUser no-ops (can't delete the account you're logged in as). Fix: keep
   the best-effort in-session attempt, but DEFER the real removal to a SYSTEM
   AtStartup scheduled task that runs on next boot (sm-bootstrap not logged on),
   removes the account + Win32_UserProfile, then deletes itself.

(Network 'no adapter' in the VM was a Proxmox NIC-model regression to virtio — fixed
by switching the VM to Intel e1000; not a SilverMetal change.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 21:27:24 +01:00
66ab2e1aed Merge pull request 'fix(bitlocker): add recovery-password protector + save key (TPM+PIN-only was unrecoverable)' (#12) from fix/bitlocker-recovery-key into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m22s
Reviewed-on: #12
2026-06-09 20:24:36 +00:00
sysadmin
3f1ea6aa63 fix(bitlocker): add recovery-password protector + save the key (was unrecoverable)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 6m17s
VM e2e: full wizard ran end-to-end and enrolled TPM+PIN, but BitLockerService only
created TPM+PIN with NO recovery protector — a forgotten/mistyped PIN bricks the
drive (hit exactly that on the VM). Add a RecoveryPassword protector and save the
48-digit key to ProgramData AND the unencrypted EFI System Partition (readable even
when the OS volume is locked, e.g. for offline recovery/verification).

PRODUCT TODO (follow-up): escrow the recovery key to SilverSync + display it in the
wizard's Done step so the end-user records it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 20:15:49 +01:00
2dc7882483 Merge pull request 'fix(kiosk): pivot to Explorer + policy lockdown (WebView2 blank as SL shell)' (#11) from fix/kiosk-explorer-lockdown into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 9m41s
2026-06-09 18:00:15 +00:00
sysadmin
e3b010530c fix(kiosk): pivot to Explorer + policy lockdown (WebView2 wizard renders blank as the SL shell)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 7m31s
5th VM e2e: with the kiosk fully working mechanically (SL engages, silent UAC,
app launches fullscreen as the shell), the MAUI/WebView2 wizard STILL renders
blank — WebView2 never initializes when the app is the bare Shell Launcher shell
with no Explorer (the same app rendered fine in the earlier build launched with
Explorer present). Operator decision: pivot.

- autounattend.xml: restore FirstLogonCommands to launch the wizard elevated over
  the normal (Explorer) first-logon session — where WebView2 works.
- Configure-Kiosk.ps1: drop Shell-Launcher-as-shell entirely; keep the lockdown —
  Keyboard Filter (Win/Start/lock/task-switch/Task-Mgr/Alt+F4), DisableTaskMgr /
  LockWorkstation / FastUserSwitch, and silent-elevation UAC. The wizard runs
  fullscreen-topmost over the locked-down Explorer (covers the taskbar).
- RevertKioskAsync: disable the Keyboard Filter rules for the real user (no SL to
  undo); keep escape-policy + secure-UAC restore. Tests updated.

Keeps the diagnostics from #10 (welcome.log) to confirm the wizard renders.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:52:15 +01:00
3c072a4edb Merge pull request 'fix(welcome): harden kiosk chrome + WebView2 diagnostics (4th e2e — blank wizard)' (#10) from fix/welcome-blank-instrument into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 4m56s
2026-06-09 17:18:08 +00:00
sysadmin
d54a5cb8db fix(kiosk): re-assert UAC auto-approve online (OOBE resets the offline bake)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m6s
4th e2e showed a UAC consent prompt for the unsigned Welcome app — the offline-baked
ConsentPromptBehaviorAdmin=0 is reset by Windows during OOBE. Re-assert it (and
PromptOnSecureDesktop=0) ONLINE in Configure-Kiosk.ps1, which runs right before the
sm-bootstrap autologon, so 'Start-Process -Verb RunAs' elevates silently. RevertKioskAsync
restores SECURE UAC (ConsentPromptBehaviorAdmin=2, PromptOnSecureDesktop=1) for the real user.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:12:57 +01:00
sysadmin
159cea0019 fix(welcome): harden kiosk chrome + add startup/WebView2 diagnostics
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 5m29s
4th VM e2e: kiosk shell engages + the app launches fullscreen, but the Blazor
wizard renders BLANK and the kiosk chrome didn't apply (title bar present) — the
app didn't crash, so there's no log to read. Two changes:

1) ApplyKioskChrome made defensive (null-guard HWND/AppWindow, FullScreen presenter
   only, returns bool) and wrapped in try/catch at the call site, so a chrome
   failure can never stall app/WebView startup (the likely cause of the blank).
2) Always-on file log at C:\ProgramData\SilverMetal\welcome.log: app ctor, window
   create, chrome result, unhandled exceptions, and the BlazorWebView/WebView2
   lifecycle (Initialized, NavigationCompleted, ProcessFailed). If the wizard is
   still blank next run, this pinpoints whether WebView2 env creation failed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 18:09:24 +01:00
6d90f41f8f Merge pull request 'fix(kiosk): Start-Process -FilePath not -LiteralPath (3rd e2e — kiosk now engages)' (#9) from fix/kiosk-start-process-filepath into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 6m0s
2026-06-09 16:47:35 +00:00
sysadmin
37bfbae2e2 fix(kiosk): Start-Process uses -FilePath, not -LiteralPath (app never launched)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m42s
3rd VM e2e: Shell Launcher now ENGAGES (kiosk shell up, no Explorer), but the
launcher's 'Start-Process -LiteralPath ...' errored — Start-Process has no
-LiteralPath parameter (that was an unvalidated review tweak; the proven form
is -FilePath). So the kiosk shell ran but the Welcome app never started. Revert
both the launcher and the RunOnce fallback to -FilePath. Single-quote escaping
of the path is unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 17:42:21 +01:00
09216d6cfb Merge pull request 'fix(kiosk): WESL DefaultAction is sint32 not uint32 (2nd e2e finding)' (#8) from fix/kiosk-defaultaction-type into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 5m21s
2026-06-09 15:46:29 +00:00
sysadmin
cc6369e3b3 fix(kiosk): WESL DefaultAction is sint32, not uint32 (config failed -> fail-open, no kiosk)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m39s
2nd VM e2e: Shell Launcher config still failed with 'Type mismatch for parameter
DefaultAction'. WESL_UserSetting.SetCustomShell/SetDefaultShell take sint32 (Int32)
DefaultAction, but we passed [uint32]0. The fail-open rollback worked (no brick,
booted to Explorer) but the kiosk never engaged. Pass [int32]0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:40:09 +01:00
863be56d15 Merge pull request 'fix(kiosk): WESL class-level calls — first-boot reboot loop found in VM e2e' (#7) from fix/kiosk-wesl-classlevel into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 4m47s
2026-06-09 15:11:00 +00:00
sysadmin
45939e1e9f fix(kiosk): call WESL_UserSetting methods class-level (was bricking first boot)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m45s
VM e2e caught a reboot loop: Configure-Kiosk used `Invoke-CimMethod -InputObject $wesl`
for SetDefaultShell/SetCustomShell, but WESL_UserSetting exposes STATIC methods and
Get-CimInstance returns null — so those calls threw "InputObject is null" while the
class-level SetEnabled($true) had already succeeded. Result: Shell Launcher enabled with
NO shell configured -> every logon (incl. OOBE defaultuser0) gets a broken shell -> the
"Why did my PC restart?" OOBE loop.

Fix: call SetEnabled/SetDefaultShell/SetCustomShell all class-level (-Namespace/-ClassName).
Setting the DEFAULT shell to explorer.exe is what keeps OOBE/normal logons alive; only
sm-bootstrap gets the kiosk launcher. Added GetCustomShell verification + a fail-open
rollback (SetEnabled false + RunOnce launch of the Welcome app) so a WMI hiccup can never
brick the box again. Same class-level fix applied to BootstrapService.RevertKioskAsync.

Found via VM 102 disk logs (silvermetal-firstboot.log + silvermetal-kiosk.log).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 16:05:28 +01:00
864c99edcd Merge pull request 'SilverMetal Windows: first-boot experience &amp; branding' (#6) from feat/first-boot-branding into main
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (push) Successful in 4m35s
2026-06-09 14:30:04 +00:00
sysadmin
4e46f81f3e Merge remote-tracking branch 'origin/main' into feat/first-boot-branding
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m35s
# Conflicts:
#	windows/welcome/src/SilverOS.Welcome.Core/Apply/BootstrapService.cs
2026-06-09 15:24:40 +01:00
sysadmin
bc847ea6d9 fix(build): discard stale image mounts at startup + ephemeral CI WorkDir
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m54s
A prior aborted build left a DISM image mounted in the fixed WorkDir,
locking install.wim and breaking the Stage 2 extract clean-up. Add a
Stage 0 that discards any orphaned SilverMetal mounts + loaded hives
before recreating the work dirs, and run CI in an ephemeral per-job
RUNNER_TEMP WorkDir so concurrent/aborted runs can't collide.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 15:14:48 +01:00
sysadmin
500e21f186 ci(branding): force Pester 5 + use v5 config object (fix -Output ambiguity vs Pester 3)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 46s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 15:10:52 +01:00
sysadmin
9e9af94dfd fix(branding): opaque ARGB/ABGR accent DWORDs; fix stage labels + stale launch comments
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 43s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 15:05:50 +01:00
sysadmin
83ee152277 feat(welcome): frosted glass-card framing for wizard on void wall
Replace the full-viewport .wizard rule with a fixed-inset frosted-glass card
(backdrop-filter blur, semi-transparent surface, rounded corners, inset shadow)
so the Mercury void/gradient wall shows behind and around the card. Adds
@keyframes sm-rise entrance animation and a body::after SILVERMETAL wordmark
watermark on the wall. Targets the real .wizard class in SilverOS.Welcome.UI/
Components/Routes.razor — no App-project markup touched.
2026-06-09 14:51:48 +01:00
sysadmin
f314dccf53 fix(welcome): remove dead Phase C artifacts (silvermetal.css, App-project layout edits)
Delete wwwroot/css/silvermetal.css (sm-* selectors targeting no markup),
remove its <link> from index.html, and restore App-project stock Layout/Pages
components (MainLayout, NavMenu, Home) to their pre-Phase-C state at 2d8b651.
These files are unused dead-code — the wizard shell lives in SilverOS.Welcome.UI.
2026-06-09 14:51:40 +01:00
sysadmin
65de29c58b chore(welcome): remove stock template nav from kiosk shell 2026-06-09 14:41:29 +01:00
sysadmin
395e86137b feat(welcome): Hybrid glass-card shell in MainLayout 2026-06-09 14:40:49 +01:00
sysadmin
bb7b4b0fed feat(welcome): SilverMetal void/cyan glass stylesheet 2026-06-09 14:40:15 +01:00
sysadmin
64ae04d56c feat(welcome): borderless fullscreen non-closable kiosk window 2026-06-09 14:39:30 +01:00
sysadmin
2d8b651e34 fix(kiosk): re-fetch WESL after enable, robust launcher quoting, intent comments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 14:36:14 +01:00
sysadmin
ee2d6fd8f2 feat(kiosk): revert kiosk (shell launcher + escapes) on wizard success 2026-06-09 14:29:07 +01:00
sysadmin
c14fcf67b1 feat(kiosk): drop FirstLogonCommands launch (Shell Launcher owns launch) 2026-06-09 14:27:37 +01:00
sysadmin
a8d7522a70 feat(kiosk): configure kiosk from SetupComplete before first logon 2026-06-09 14:27:13 +01:00
sysadmin
f199981cf1 feat(build): enable kiosk features offline + stage Configure-Kiosk.ps1 2026-06-09 14:26:57 +01:00
sysadmin
f00ef19578 feat(kiosk): Configure-Kiosk.ps1 (Shell Launcher v2 + Keyboard Filter + escapes) 2026-06-09 14:26:33 +01:00
sysadmin
4ff12ab543 fix(branding): guard reg unload, set ErrorAction in libs, accent field rename, test hive unload + assertions 2026-06-09 14:23:50 +01:00