Skip to content

Feat MVP#1

Merged
JMR-dev merged 13 commits into
mainfrom
feat-mvp
Apr 29, 2026
Merged

Feat MVP#1
JMR-dev merged 13 commits into
mainfrom
feat-mvp

Conversation

@JMR-dev

@JMR-dev JMR-dev commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Implementation of covenant-setup, a deterministic Windows installer engine.

JMR-dev and others added 10 commits March 27, 2026 21:18
Replace the hardcoded "c:\\program files" / "c:\\windows" prefix
heuristic with a PathResolver::requires_admin method that matches
against runtime-resolved FOLDERID_ProgramFilesX64,
FOLDERID_ProgramFilesX86, and FOLDERID_Windows. Honors the MVP
"no hardcoded paths" rule, catches Program Files (x86) explicitly,
and works on non-C: Windows installs.

Match logic uses path-component boundaries so "C:\\Program Files
Custom" no longer false-positives against "C:\\Program Files".

Adds unit tests for the new method via a #[cfg(test)] constructor
that lets us seed roots without invoking Win32.
program_files_x86 and windows_dir were stored but never read after
construction; only their string forms via admin_roots are used.
Compute them as locals in PathResolver::new instead, silencing the
dead_code warning without expanding the public surface.
Wine runs the test binary cleanly when targeting x86_64-pc-windows-gnu,
so wire that target's runner to wine in .cargo/config.toml. The default
windows-msvc build is unaffected.

README gains a 'Linux Cross-Build (Optional)' section with the dotnet
10 / mingw-w64 / wine prerequisites and the EnableWindowsTargeting=true
recipe needed to cross-build the net8.0-windows C# UI from Linux.
The previous implementation joined std::env::args() with single spaces,
which silently broke any argument containing whitespace, double quotes,
or trailing backslashes — most importantly manifest paths under
'C:\Program Files' or 'C:\Users\<name with space>'. After elevation
the relaunched process saw a different argv than the original.

quote_command_line_arg follows the standard MSVCRT / CommandLineToArgvW
encoding: quote on space/tab/quote/empty, escape embedded quotes with a
preceding backslash, and double any run of backslashes that would
otherwise be consumed by a following quote (including the closing one).

Tests cover the canonical edge cases plus a round-trip that re-parses
each encoded form with a reference argv parser to confirm fidelity.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements the MVP for covenant-setup: a deterministic Windows installer/uninstaller engine in Rust with a bundled single-file packager, a C# WinForms UI over named-pipe IPC, and Windows VM harnesses/docs to validate real Win32 boundaries.

Changes:

  • Added core Win32 capabilities in Rust (path resolution, elevation/relaunch, filesystem + registry mutations, shortcut creation, Restart Manager + MoveFileEx fallback).
  • Added a C# WinForms UI sidecar/embedded helper (named-pipe server + JSONL protocol) plus xUnit coverage for protocol/helpers.
  • Added Vagrant-based smoke/coverage scripts, CI workflow, and extensive documentation/examples for packaging, install/uninstall, and debugging.

Reviewed changes

Copilot reviewed 31 out of 39 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
vm/self-test/install.toml Self-test manifest for VM smoke/coverage scenarios.
ui/Covenant.Setup.Ui/app.manifest WinForms app manifest (asInvoker).
ui/Covenant.Setup.Ui/Program.cs WinForms UI + named-pipe server and JSON message handling.
ui/Covenant.Setup.Ui/Covenant.Setup.Ui.csproj C# UI project definition (WinExe, WinForms, internals visible to tests).
ui/Covenant.Setup.Ui.Tests/UiMessageJsonTests.cs Tests for UI message/response JSON contract.
ui/Covenant.Setup.Ui.Tests/ProgramTests.cs Tests for CLI arg parsing (--pipe).
ui/Covenant.Setup.Ui.Tests/InstallerUiFormHelperTests.cs Tests for UI helper functions (errata JSON, mappings, safe summaries).
ui/Covenant.Setup.Ui.Tests/Covenant.Setup.Ui.Tests.csproj C# test project setup and dependencies.
src/win.rs Win32 boundary wrappers (known folders, elevation, registry, shortcuts, Restart Manager, file ops) + unit tests.
src/ui.rs Rust-side UI session management (extract/launch C# UI, pipe protocol, prompts, progress sink).
src/sys.rs Sys trait boundary abstraction and WinSys production implementation.
scripts/windows-vm/coverage/uac.ps1 Guest scenario: UAC/elevation coverage assertions.
scripts/windows-vm/coverage/self-test.ps1 Guest scenario: baseline install/uninstall + journal assertions.
scripts/windows-vm/coverage/reboot.ps1 Guest scenario: locked-file uninstall requiring reboot fallback signals.
scripts/windows-vm/coverage/hklm-registry.ps1 Guest scenario: HKLM registry writes forcing admin path.
scripts/windows-vm/coverage/bundled-exec.ps1 Guest scenario: packaged/bundled installer execution path.
scripts/windows-vm/Start-InteractiveSelfInstall.ps1 Guest interactive scheduled-task harness for install+uninstall verification + diagnostics.
scripts/windows-vm/Invoke-InteractiveInstaller.ps1 Guest wrapper that launches installer/uninstaller and captures diagnostics/trace.
scripts/windows-vm/Abort-SmokeDiagnostics.ps1 Guest abort/cleanup + trace bundle capture.
scripts/run-windows-vm-smoke.ps1 Host orchestrator for interactive VM smoke test (package, upload, run, collect traces).
scripts/run-windows-vm-coverage.ps1 Host orchestrator for multi-scenario VM coverage run.
project_mvp.md MVP requirements/reference document.
examples/payload/sample_app.cmd Example payload for demo installs.
examples/payload/post_install.ps1 Example post-install payload script.
examples/install.toml Example manifest covering directories/files/registry/shortcut/script/purge.
examples/README.md Example usage instructions for packaging/install/uninstall.
docs/vagrant-smoke-debugging-notes.md Deep-dive notes for diagnosing VM smoke failures/hangs.
docs/integration-tests-architecture.md Integration testing architecture and scenario coverage overview.
docs/implementation-notes.md Implementation/review notes capturing decisions and fixes.
build.rs Builds/embeds C# UI helper via dotnet publish + embeds application manifest.
Vagrantfile Windows 11 VM configuration for Hyper-V/WinRM based testing.
README.md Project overview, usage, UI modes, VM harness docs.
Cargo.toml Rust crate dependencies and build dependency configuration.
Cargo.lock Locked dependency graph for reproducible builds.
CLAUDE.md Repository build/run/conventions guidance.
.gitignore Ignore rules for build artifacts/VM artifacts.
.github/workflows/ci.yml Windows CI: build, Rust tests, C# UI tests, quality gate.
.cargo/config.toml Windows MSVC static CRT linking + optional GNU target runner configuration.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread README.md Outdated
Comment thread ui/Covenant.Setup.Ui/Program.cs
Comment thread ui/Covenant.Setup.Ui.Tests/ProgramTests.cs
Comment thread project_mvp.md
Comment thread README.md Outdated
Comment thread src/win.rs Outdated
Comment thread src/win.rs Outdated
@JMR-dev

JMR-dev commented Apr 29, 2026

Copy link
Copy Markdown
Owner Author

@copilot apply changes based on the comments in this thread

Copilot AI commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

Applied all changes from the review thread in commit 74e37e8:

  • README.md: Reworded the "observing" bullets to accurately describe declared-action journaling (not ETW observation); replaced the broken absolute Windows path with the repo-relative link src/win.rs.
  • project_mvp.md: Replaced glassbox CLI name with covenant-setup in the example subcommands.
  • Program.cs ReadPipeName: Now strips the \\.\pipe\ prefix if present, so NamedPipeServerStream always receives a plain pipe name regardless of how the argument is passed.
  • ProgramTests.cs: Updated the existing test to pass a plain name ("foo"); added a new ReadPipeName_strips_full_pipe_path_prefix test that verifies \\.\pipe\foo is normalized to foo.
  • src/win.rs is_elevated: Restructured to capture the GetTokenInformation result without ?, always call close_handle, then propagate the error — eliminating the token handle leak on error paths.
  • src/win.rs known_folder: Restructured to call pwstr_to_path and store the result, always call CoTaskMemFree, then return the stored result — eliminating the PWSTR memory leak when UTF-16 decoding fails.

@JMR-dev
JMR-dev merged commit ba9ff79 into main Apr 29, 2026
5 checks passed
@JMR-dev
JMR-dev deleted the feat-mvp branch April 29, 2026 02:16
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.

4 participants