Commit Graph

74 Commits

Author SHA1 Message Date
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
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
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
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
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
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
sysadmin
6aa963f024 docs(tests): document branding test suite + elevation requirement
ci(branding): run branding Pester suite before Build packed ISO step
2026-06-09 14:14:13 +01:00
sysadmin
bd5d82f6b4 feat(build): wire branding into Invoke-ServiceWim (offline hive bake) 2026-06-09 14:13:30 +01:00
sysadmin
50856b8f28 feat(branding): Apply-Branding orchestrator (offline/online) + placeholder assets 2026-06-09 14:12:45 +01:00
sysadmin
320b4c675a feat(branding): OEM/lockscreen/desktop/bitlocker layer writers + tests 2026-06-09 14:10:17 +01:00
sysadmin
7de5262c43 feat(branding): registry helper + Pester harness 2026-06-09 14:08:34 +01:00
sysadmin
73d6611ab5 feat(branding): manifest + module skeleton for SilverMetal Windows branding 2026-06-09 14:06:46 +01:00
sysadmin
e4241f7f59 docs(windows): first-boot branding implementation plan
Phased TDD plan: A (branding module, hardware-free), B (kiosk: Shell
Launcher v2 + Keyboard Filter), C (MAUI fullscreen glass presentation),
D (build integration + VM e2e). Bite-sized tasks with complete code.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:59:29 +01:00
sysadmin
66e7fd4ae8 docs(windows): first-boot experience & branding design spec
Design for SilverMetal Windows first-boot: declarative branding build
(4 layers baked offline into the WIM, shared dual-mode module), hardened
onboarding kiosk (Shell Launcher v2 + Keyboard Filter for the one-time
sm-bootstrap session), and the Hybrid fullscreen glass-card presentation
for the Welcome app. Fills the empty Invoke-Brand stub (M4 branding).

Approved in brainstorming. Next: writing-plans.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-09 13:53:58 +01:00
sysadmin
bf21eababe fix(welcome): make bootstrap teardown best-effort (LogonCount=1 already disables auto-logon; cleanup must not fail the apply)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m32s
2026-06-09 12:15:56 +01:00
sysadmin
25b02d20ff fix(welcome): eject optical install media before BitLocker enroll (it refuses TPM+PIN with bootable media present — found in live e2e)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m35s
2026-06-09 11:47:38 +01:00
sysadmin
2b2214c124 fix(welcome): apply services check PowerShell exit codes + throw on failure (no more silent privileged-op failures)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m30s
2026-06-09 11:21:46 +01:00
sysadmin
a47345887c fix(welcome): enforce BitLocker TPM+PIN — set FVE startup-PIN policy, add protector if auto-DE pre-encrypted, strip TPM-only protector
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m31s
2026-06-09 11:15:13 +01:00
sysadmin
4f3e25e816 docs(welcome): record VM e2e validation + 3 bugs found/fixed + BitLocker-PIN follow-up
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m37s
2026-06-09 11:02:52 +01:00
sysadmin
4a5bd96ef8 fix(welcome): notify wizard host on AccountStep validity change so Next enables (live e2e blocker) + regression test
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m35s
AccountStep now exposes OnValidityChanged EventCallback<bool> and fires it at the end of every Validate() call (including OnInitialized). Routes.razor drops the @ref/IsValid polling pattern in favour of _accountValid updated via the callback + StateHasChanged, matching the existing OnRunningChanged pattern used by ApplyStep. Adds 5 bUnit regression tests covering: initial-invalid, all-valid, re-invalid on clear, short/non-numeric PIN, and pre-populated state on Back→Forward re-mount.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 10:25:38 +01:00
sysadmin
166e4d8d0c fix(welcome): silent admin elevation via offline UAC auto-approve policy + Start-Process RunAs launch (scheduled-task approach failed un-elevated)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m31s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 09:51:24 +01:00
sysadmin
4435f6e1c4 fix(welcome): redirect WebView2 data dir off Program Files + launch wizard elevated via scheduled task
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 09:43:46 +01:00
sysadmin
b1226d2bed fix(welcome): extract wizard components to Razor Class Library so bUnit tests don't load WindowsAppSDK (fixes CI DllNotFound on clean runner)
All checks were successful
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Successful in 4m30s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 08:12:37 +01:00
sysadmin
ee3528f360 ci(welcome): fail the build if the Welcome payload isn't baked (guard against green-but-broken image)
Some checks failed
Build SilverMetal Enhanced - Windows ISO / build (pull_request) Failing after 1m17s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 04:02:50 +01:00
sysadmin
bafdf88fa9 feat(welcome): build bakes the published Welcome app + flavours into the image
Adds Invoke-PublishWelcome (dotnet publish win-x64 self-contained, runs pre-mount)
and Copy-WelcomePayload (copies publish output + flavours/*.json into $mount while
install.wim is open) called from Invoke-ServiceWim's try block. Both are gated on
SILVERMETAL_WELCOME_ENABLED != '0' (enabled by default). Hardening staging unchanged.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 03:46:02 +01:00
sysadmin
5715e55694 feat(welcome): SetupComplete defers hardening to Welcome when present 2026-06-09 03:41:45 +01:00
sysadmin
efdaffa73f feat(welcome): bootstrap auto-login launches the Welcome app
Rename the unattend LocalAccount from silvermetal → sm-bootstrap
(Administrators), add a one-time AutoLogon and a FirstLogonCommands
entry that launches SilverOS.Welcome.App.exe on first boot. The
Welcome app's ApplyService tears down AutoAdminLogon + removes
sm-bootstrap on successful onboarding.
2026-06-09 03:36:46 +01:00
sysadmin
346abc3676 fix(welcome): apply re-entrancy guard, scrub error output, lock nav during apply, offline-bundle fonts
- ApplyStep: guard StartAsync against double-invocation (_running check at top)
- ApplyService: replace raw StdErr dump with scrubbed message (exit code + first non-empty line, ≤200 chars)
- ApplyStep: SanitiseForDisplay strips newlines and caps error at 200 chars before rendering
- ApplyStep: add OnRunningChanged EventCallback<bool>; Routes.razor disables Back while _applyRunning
- Routes.razor: AdvanceToDone uses _stepTitles.Length - 1 instead of magic literal 5
- app.css: replace Google Fonts CDN @import with local @font-face rules; bundle DM Mono (300/400/500 + italic 300) and Inter (300/400/500) latin woff2 files under wwwroot/fonts/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 03:34:34 +01:00
sysadmin
ea5adacac3 feat(welcome): apply step wiring + Mercury styling
Wire ApplyStep with public StartAsync(), IProgress<ApplyProgress> marshalled
via InvokeAsync(StateHasChanged), OnComplete EventCallback (host advances to
Done), and failure surface + Retry button. Add _Imports.razor Apply using.
Wire Routes.razor AdvanceToDone handler. Add Mercury CSS: slate-void palette,
DM Mono typography, layered radial gradients, staggered step-enter animation,
styled wizard chrome/cards/fields/progress bar/buttons. 17/17 tests green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 03:20:39 +01:00
sysadmin
a393ded7c6 fix(welcome): touched-gated account errors, flavour-load retry, flavour Next-gate, drop dead inject 2026-06-09 03:12:41 +01:00
sysadmin
1630bde1ee feat(welcome): wizard steps + flavour selection UI
Six wizard step components (Welcome/Flavour/Account/Prefs/Apply/Done),
Routes.razor wizard host with Next/Back navigation and IFlavourLoader
wiring, bUnit FlavourStepTests (TDD red→green), AccountStep field
validation (username/password/admin-password required; BitLocker PIN
numeric ≥6 digits). Test project upgraded to Razor SDK /
net9.0-windows10.0.19041.0 + UseMaui=true to reference the MAUI app
assembly. Non-Windows platform folders removed; demo pages removed.
All 14 tests pass (13 existing + 1 new bUnit).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 03:03:13 +01:00
sysadmin
1f8ada3a45 feat(welcome): MAUI Blazor app skeleton + DI wiring
Adds SilverOS.Welcome.App (net9.0-windows10.0.19041.0 only), registers
all Core services in MauiProgram.cs, and introduces WizardState scoped
service for the wizard host.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 02:50:42 +01:00
sysadmin
b1b278bb8d fix(welcome): correct -Modules arg encoding so hardening subset actually runs (+ real integration test)
powershell.exe -File binds a single-quoted comma list like '00','03','05' as ONE string element,
not a [string[]] array, so Invoke-Hardening.ps1's -contains filter matched nothing and all
hardening modules were silently skipped.

Fix: adopt a CSV-split contract — Invoke-Hardening.ps1 now accepts [string]$Modules and splits
on ',' internally ($ModuleList = $Modules -split ','); ApplyService passes a bare CSV token
(e.g. 00,03,05) with no surrounding quotes. Empirically verified via ProcessStartInfo: candidate
(a) '00','03','05' → COUNT=1 (bug); candidate (b) 00,03,05 → single string, correctly split by
the script; candidate (c) space-separated → PS positional-parameter error. PARSE OK confirmed.

Adds ApplyServiceHardeningIntegrationTests: copies the real Invoke-Hardening.ps1 into a temp
dir with harmless dummy 0*.ps1 stubs, runs ApplyService with the real ProcessRunner for modules
["00","05"], and asserts ran.txt contains RAN 00 and RAN 05 but NOT RAN 03 or RAN 07.
Test fails on the old encoding and passes with the fix (regression-checked).
2026-06-09 02:46:00 +01:00
sysadmin
8fe577e0bf feat(welcome): ApplyService orchestrator (modules->accounts->bitlocker->teardown) 2026-06-09 02:33:39 +01:00
sysadmin
3be703d5c9 fix(welcome): escape bootstrapUser + assert daily user is not admin 2026-06-09 02:30:35 +01:00
sysadmin
62f66490d1 feat(welcome): account + BitLocker + bootstrap services 2026-06-09 02:26:35 +01:00