Skip to content

Port the startup work onto main and fix the November production audit - #13

Merged
26zl merged 2 commits into
mainfrom
production-audit-2026-11
Nov 1, 2026
Merged

26zl merged 2 commits into
mainfrom
production-audit-2026-11

Conversation

@26zl

@26zl 26zl commented Nov 1, 2026 •

Copy link
Copy Markdown
Owner

Summary

Ports the startup work done on 2026-11-01 onto main and fixes the findings of a production-readiness audit (security, CLI behavior, repository and code hygiene).

User-visible changes

  • Faster interactive start: lazy PSFzf and completers, cached continuation prompt, prefetched first prompt, native JSON first, a no-GC region until the first prompt, and the portable Oh My Posh build (pinned, SHA-256 and Authenticode signer checked) instead of the MSIX build.

  • Oh My Posh older than 29.35.1 (CVE-2026-73505, template code from folder names) never renders the prompt. The managed portable build takes over, psp-doctor reports FAIL, and setup and Update-Tools install the portable build next to the old one.

  • A theme that can run commands (command segments, template functions such as cmd/readFile/getHostByName, or extends) is refused unless theme.allowCommands is set.

  • Uninstall-Profile never replaces or deletes a profile that is not this one.

  • genpass keeps passwords out of Windows clipboard history and cloud sync.

  • pwsh -File/-Command runs without -NoExit count as non-interactive and skip prompt setup.

  • Setup asks explicitly before it installs a missing editor with winget, and checks local release files against a SHA256SUMS.txt next to them.

  • Update-Tools keeps a newer Oh My Posh, uses --exact, and reports tools winget did not install as preserved.

  • Startup no longer imports Microsoft.PowerShell.Management (about 27 ms): the load path, the prompt, the tab-title hook and the cached zoxide init use .NET and session-state calls, so the module loads at the first cd or ls.

Security hardening: quoting doubles typographic quotes, lint always passes its own settings, wider envload deny list and history filter, wslpath without the distro shell, serve skips npm install scripts, wt -d never receives a folder with ;, and release.yml requires the tagged commit to be on main.

Repository: CHANGELOG.md, CODE_OF_CONDUCT.md and .mailmap are removed and AGENTS.md is no longer tracked. Release notes are generated from merged pull requests, grouped by the new .github/release.yml.

Tests (local, Windows 11)

  • tests/lint.ps1 with PSScriptAnalyzer 1.25.0: clean
  • tests/unit.ps1: 106/106 on PowerShell 7.6.9 and 106/106 on Windows PowerShell 5.1 (20 new regression cases)
  • tests/smoke.ps1: median load 131 ms (PS7), 121 ms (PS5)
  • tests/test.ps1: 27 passed, 0 failed, 1 skipped (install verification, no setup install on that machine)
  • tests/ci-functional.ps1: 5/5, full command coverage
  • Interactive start (hidden console, median of 7): 675-681 ms to the first prompt (715-719 ms before the second commit); 18 ms per prompt.

Not in this PR (owner actions)

  • Tag v1.0.0 after merge; the README install command needs that release.
  • Repository settings: bypass actors on the main ruleset, a tag ruleset, immutable releases, read-only default workflow permissions.

@26zl 26zl self-assigned this Nov 1, 2026
Startup and Oh My Posh
- Faster interactive start: lazy PSFzf and completers, cached continuation
  prompt, prefetched first prompt, native JSON first, a no-GC region until
  the first prompt, and the portable Oh My Posh build (pinned, SHA-256 and
  signer checked) instead of the slower MSIX build.
- Oh My Posh older than 29.35.1 (CVE-2026-73505) never renders the prompt;
  the managed portable build takes over, psp-doctor reports FAIL, and setup
  and Update-Tools install the portable build next to it.
- Runs of a script or command (-File/-Command without -NoExit) count as
  non-interactive, so they skip prompt setup.

Security
- The theme guard scans the whole theme for command segments, template
  functions that run programs and extends (opt-in: theme.allowCommands).
- Quoting doubles typographic quotes too; lint always passes its own
  settings; envload and the history filter cover more names and key
  formats; wslpath runs without the distro shell; serve skips npm install
  scripts; wt -d never gets a folder with ';'; local release files are
  checked against the SHA256SUMS.txt next to them; release.yml requires the
  tagged commit to be on main; genpass keeps passwords out of clipboard
  history.

Fixes
- Uninstall-Profile never replaces or deletes a profile that is not this
  one.
- Keybinding ids keep punctuation keys apart, and a binding the profile no
  longer sets is retired on the next Update-Profile.
- Update-Tools keeps a newer Oh My Posh, uses --exact and reports tools
  winget did not install as preserved; PATH refresh appends instead of
  replacing; zoxide init generates its cache once; Update-Profile parses a
  download before installing it and records the commit when up to date;
  setup falls back to the default font when the wizard font fails; file,
  entropy, vtscan and defscan accept PowerShell drive paths.

Repository
- CHANGELOG.md, CODE_OF_CONDUCT.md and .mailmap are removed and AGENTS.md
  is no longer tracked; release notes come from merged pull requests
  (.github/release.yml).
- Docs, issue templates, attribution for Open-Meteo and tldr, and test
  hygiene; 17 new regression tests (tests/unit.ps1 now has 103).
@26zl
26zl force-pushed the production-audit-2026-11 branch from 0688d9e to 165d2f4 Compare November 1, 2026 22:06
Importing Microsoft.PowerShell.Management costs about 27 ms, and startup
triggered it through Test-Path and Join-Path in the profile, zoxide's init
(Get-Location in __zoxide_pwd) and the tab-title hook, which also ran
Join-Path, Test-Path and Get-Item on every prompt. These now use .NET and
session-state calls, and the zoxide cache rewrites __zoxide_pwd the same
way (a "; psp 2" header suffix regenerates older caches), so the module
loads at the first cd or ls instead.

Also at startup: the startup message is written through the host instead
of the first Write-PspHost call (about 10 ms), user-settings.json and
theme.json are read directly instead of through Read-JsonFile, the trust
state is built only when trust keys exist, and the _psp variables are
removed with one wildcard Remove-Variable.

Time to the first prompt (hidden interactive console, median of 7):
675-681 ms, down from 715-719 ms; per prompt unchanged at 18 ms.
@26zl
26zl merged commit 81ade1a into main Nov 1, 2026
5 checks passed
@26zl
26zl deleted the production-audit-2026-11 branch November 1, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant