feat(security): give the de-privileged runner a writable plugin-state dir

The LocalService runner cannot write anywhere under %ProgramData%\punktfunk
(the config dir is Users-read-only), so a state-writing plugin's saveCache /
config-edit / first-run mkdir all fail EPERM — proven on-glass (rom-manager
only looked fine because its state dir was pre-created by an admin run and a
0-title reconcile skipped the write).

Add the one writable grant the model was missing, keeping the split crisp —
code dirs RX+WA, secrets R, and now a dedicated state root RW:

- plugins enable / build-scripting.ps1: create %ProgramData%\punktfunk  plugin-state and grant LocalService (OI)(CI)(M); disable revokes. Users stay
  read-only, so another non-admin still can't tamper with a plugin's launch
  templates.
- SDK: export pluginStateDir(name) -> <config_dir>/plugin-state/<name>. Same
  path on Linux (the systemd --user runner owns the config dir, writable with
  no grant), so plugins use one branch-free helper.

Plugins must persist under pluginStateDir(), not straight under the config dir.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 23:23:48 +02:00
parent 5cd6e8f572
commit 73ec6ed9ef
6 changed files with 117 additions and 1 deletions
+7
View File
@@ -139,6 +139,13 @@ if ($existing) {
& "$env:SystemRoot\System32\icacls.exe" $dirPath /grant:r '*S-1-5-19:(OI)(CI)(RX,WA)' | Out-Null
if ($LASTEXITCODE -ne 0) { Write-Host "warn : icacls grant failed on $dirPath" }
}
# State root gets inheritable Modify - the ONE writable grant, so a plugin can persist its
# config/cache under plugin-state\<name> (@punktfunk/host's pluginStateDir). Code dirs stay
# RX+WA, secrets stay R; only this dir is writable.
$stateDir = Join-Path $cfg 'plugin-state'
New-Item -ItemType Directory -Force -Path $stateDir | Out-Null
& "$env:SystemRoot\System32\icacls.exe" $stateDir /grant:r '*S-1-5-19:(OI)(CI)(M)' | Out-Null
if ($LASTEXITCODE -ne 0) { Write-Host "warn : icacls grant failed on $stateDir" }
}
# --- 4. the opt-in scheduled task -------------------------------------------------------------