generated from MrSphay/codex-agent-repository-kit
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 16e5d1377c | |||
| 7a2a643d15 | |||
| e885978aba | |||
| d6e2d5ab52 | |||
| 84a5df7216 | |||
| 01148f4703 | |||
| 93ca15a881 | |||
|
|
cf32e3b20e | ||
|
|
46026cb62c |
@@ -8,42 +8,72 @@ on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-windows:
|
||||
runs-on: windows-latest
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Verify PowerShell scripts
|
||||
shell: powershell
|
||||
- name: Setup .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: 8.0.x
|
||||
|
||||
- name: Build Windows EXE
|
||||
shell: bash
|
||||
run: |
|
||||
$scripts = @()
|
||||
$scripts += @(Get-ChildItem . -Filter *.ps1)
|
||||
$scripts += @(Get-ChildItem .\scripts -Filter *.ps1)
|
||||
foreach ($script in $scripts) {
|
||||
$tokens = $null
|
||||
$errors = $null
|
||||
[System.Management.Automation.Language.Parser]::ParseFile($script.FullName, [ref]$tokens, [ref]$errors) | Out-Null
|
||||
if ($errors) { throw $errors }
|
||||
}
|
||||
set -euo pipefail
|
||||
version="0.1.2"
|
||||
dotnet publish src/MrTrustLauncher.csproj \
|
||||
--configuration Release \
|
||||
--runtime win-x64 \
|
||||
--output dist/build \
|
||||
-p:EnableWindowsTargeting=true \
|
||||
-p:PublishSingleFile=true \
|
||||
-p:SelfContained=true
|
||||
cp dist/build/MrTrust.exe dist/MrTrust.exe
|
||||
|
||||
- name: Build release ZIP
|
||||
shell: powershell
|
||||
shell: bash
|
||||
run: |
|
||||
$arguments = @("-ExecutionPolicy", "Bypass", "-File", ".\scripts\New-MrTrustRelease.ps1", "-Version", "0.1.0")
|
||||
if ($env:MRTRUST_SIGNING_THUMBPRINT) {
|
||||
$arguments += @("-SigningThumbprint", $env:MRTRUST_SIGNING_THUMBPRINT)
|
||||
}
|
||||
powershell @arguments
|
||||
set -euo pipefail
|
||||
version="0.1.2"
|
||||
package_root="dist/MrTrust-${version}"
|
||||
rm -rf "$package_root" "dist/MrTrust-${version}.zip"
|
||||
mkdir -p "$package_root"
|
||||
cp dist/MrTrust.exe "$package_root/"
|
||||
cp README.md "$package_root/"
|
||||
(cd dist && zip -r "MrTrust-${version}.zip" "MrTrust-${version}")
|
||||
|
||||
- name: Show package contents
|
||||
shell: powershell
|
||||
shell: bash
|
||||
run: |
|
||||
Get-ChildItem .\dist -Recurse | Select-Object FullName, Length
|
||||
find dist -maxdepth 4 -type f -printf '%p %s bytes\n'
|
||||
|
||||
- name: Upload release artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: MrTrust-0.1.0
|
||||
path: dist/MrTrust-0.1.0.zip
|
||||
name: MrTrust-0.1.2
|
||||
path: dist/MrTrust-0.1.2.zip
|
||||
|
||||
- name: Attach ZIP to Gitea release
|
||||
if: github.ref == 'refs/heads/main'
|
||||
shell: bash
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
version="0.1.2"
|
||||
api="https://git.wilkensxl.de/api/v1/repos/MrSphay/MrTrust"
|
||||
release_json="$(curl -fsS -H "Authorization: token ${GITEA_TOKEN}" "${api}/releases/tags/v${version}")"
|
||||
release_id="$(printf '%s' "$release_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
|
||||
if [ -z "$release_id" ]; then
|
||||
echo "Could not resolve release id for v${version}" >&2
|
||||
exit 1
|
||||
fi
|
||||
curl -fsS \
|
||||
-X POST \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
-F "attachment=@dist/MrTrust-${version}.zip" \
|
||||
"${api}/releases/${release_id}/assets?name=MrTrust-${version}.zip"
|
||||
|
||||
@@ -16,8 +16,10 @@ MrTrust manages explicit Windows certificate trust for MrSphay software.
|
||||
- `assets/certificates/` contains public certificates only.
|
||||
- `private/` is ignored and may contain local signing material.
|
||||
- `docs/integration-prompt.md` is the prompt for adding MrTrust to other projects.
|
||||
- `docs/agent-target-integration.md` is the autonomous runbook for agents modifying target projects.
|
||||
- `mrtrust.integration.json` is the machine-readable integration contract.
|
||||
- `docs/security-model.md` documents the intended behavior and limits.
|
||||
- `MrTrust.ps1 gui` is the user-facing GUI entry point.
|
||||
- `MrTrust.exe` is the user-facing standalone trust installer. The PowerShell scripts are source/build internals.
|
||||
|
||||
## Verification
|
||||
|
||||
|
||||
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,9 +1,22 @@
|
||||
# Changelog
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- Made `MrTrust.exe` a standalone user-facing release artifact.
|
||||
- Added an autonomous target-project integration runbook for agents.
|
||||
- Added `mrtrust.integration.json` as a machine-readable integration contract.
|
||||
- Updated agent-facing documentation to prefer the standalone `MrTrust.exe` integration path.
|
||||
|
||||
## 0.1.1
|
||||
|
||||
- Added a custom MrTrust application icon and embedded it into the launcher.
|
||||
- Improved the GUI layout so status text is not clipped.
|
||||
- Updated the Gitea artifact version to `0.1.1`.
|
||||
|
||||
## 0.1.0
|
||||
|
||||
- Added MrTrust certificate generation, installation, removal, and signing scripts.
|
||||
- Added a simple Windows GUI for installing and removing MrTrust.
|
||||
- Added a Windows launcher EXE and Gitea Runner workflow for release ZIP builds.
|
||||
- Added a Windows launcher EXE and Ubuntu Gitea Runner workflow for release ZIP builds.
|
||||
- Added integration prompt for other Windows projects.
|
||||
- Added security model documentation.
|
||||
|
||||
50
README.md
50
README.md
@@ -13,13 +13,17 @@ MrTrust does not bypass Microsoft Defender or SmartScreen. Windows can still sca
|
||||
|
||||
## What It Contains
|
||||
|
||||
- `MrTrust.ps1 gui` opens a simple Windows interface for installing or removing trust.
|
||||
- `MrTrust.exe` opens a standalone Windows interface for installing or removing trust.
|
||||
- `MrTrust.ps1` and `scripts/` are source and maintainer tools for building, signing, and local development.
|
||||
- `scripts/New-MrTrustCertificate.ps1` creates a local root certificate and a code-signing certificate for the publisher.
|
||||
- `scripts/Install-MrTrust.ps1` installs the public trust certificate for the current user or the local machine.
|
||||
- `scripts/Uninstall-MrTrust.ps1` removes the MrTrust certificate again.
|
||||
- `scripts/Sign-MrTrustProject.ps1` signs `.exe`, `.msi`, `.ps1`, and other Authenticode-compatible files.
|
||||
- `scripts/New-MrTrustRelease.ps1` builds a distributable ZIP package.
|
||||
- `docs/integration-prompt.md` is a prompt you can paste into other Windows projects.
|
||||
- `docs/agent-target-integration.md` is the autonomous target-project integration runbook for agents.
|
||||
- `mrtrust.integration.json` is the machine-readable integration contract.
|
||||
- `MrTrust.exe` is standalone for normal users. It embeds the public certificates and runtime scripts.
|
||||
|
||||
## Quick Start For MrSphay
|
||||
|
||||
@@ -65,26 +69,14 @@ Remove the trust certificate:
|
||||
Build a user-facing ZIP release:
|
||||
|
||||
```powershell
|
||||
.\scripts\New-MrTrustRelease.ps1 -Version 0.1.0
|
||||
.\scripts\New-MrTrustRelease.ps1 -Version 0.1.2
|
||||
```
|
||||
|
||||
The Gitea workflow `.gitea/workflows/build.yml` builds the same ZIP on a Windows runner and uploads it as an artifact.
|
||||
If the Windows runner has the private signing certificate installed, set `MRTRUST_SIGNING_THUMBPRINT` to sign the launcher during the build.
|
||||
The Gitea workflow `.gitea/workflows/build.yml` builds the Windows launcher EXE on an `ubuntu-latest` runner with .NET Windows cross-targeting, then uploads the ZIP as an artifact.
|
||||
|
||||
## User Installation
|
||||
|
||||
For normal users, distribute MrTrust with the public certificate file:
|
||||
|
||||
```text
|
||||
assets\certificates\MrSphay-LocalTrust-Root.cer
|
||||
assets\certificates\MrSphay-CodeSigning.cer
|
||||
```
|
||||
|
||||
The user runs:
|
||||
|
||||
```powershell
|
||||
.\MrTrust.ps1 gui
|
||||
```
|
||||
For normal users, distribute `MrTrust.exe`. The executable embeds the public certificate files and opens the GUI by default.
|
||||
|
||||
By default, MrTrust installs trust only for the current Windows user:
|
||||
|
||||
@@ -96,18 +88,34 @@ Code-signing certificate -> Cert:\CurrentUser\TrustedPublisher
|
||||
For all users on the machine, run PowerShell as Administrator:
|
||||
|
||||
```powershell
|
||||
.\MrTrust.ps1 install -Scope LocalMachine
|
||||
.\MrTrust.exe
|
||||
```
|
||||
|
||||
Then choose the all-users option in the GUI.
|
||||
|
||||
## Using This Repo With Other Agents
|
||||
|
||||
Yes. Give another agent this repository URL and the target Windows project, then paste `docs/integration-prompt.md`.
|
||||
Yes. Give another agent this repository URL, the target Windows project, and `docs/integration-prompt.md`.
|
||||
|
||||
For autonomous work, the agent should read these files in order:
|
||||
|
||||
1. `mrtrust.integration.json`
|
||||
2. `docs/agent-target-integration.md`
|
||||
3. `docs/integration-prompt.md`
|
||||
|
||||
The agent's job is to modify the target project, not this repository:
|
||||
|
||||
- expose a visible "Open MrTrust" or trust setup path for users
|
||||
- link to or bundle the standalone `MrTrust.exe`
|
||||
- sign Windows release artifacts with the MrSphay code-signing certificate
|
||||
- keep trust installation explicit, reversible, and user-confirmed
|
||||
- keep private signing material out of the target repository and release artifacts
|
||||
|
||||
Both sides have to be wired:
|
||||
|
||||
- MrTrust side: users install the public trust certificates once.
|
||||
- Target project side: release artifacts are signed with the MrSphay code-signing certificate.
|
||||
- Installer side, optional: the target app can offer "Open MrTrust" or bundle the MrTrust ZIP, but it must not silently change trust.
|
||||
- Installer side, optional: the target app can offer "Open MrTrust" or bundle `MrTrust.exe`, but it must not silently change trust.
|
||||
|
||||
If the target project is not signed, MrTrust cannot make it trusted.
|
||||
|
||||
@@ -120,4 +128,6 @@ If the target project is not signed, MrTrust cannot make it trusted.
|
||||
|
||||
## Recommended Project Integration
|
||||
|
||||
Use `docs/integration-prompt.md` in another Windows project. The prompt tells Codex or another assistant to add a visible trust check, a link or bundled copy of MrTrust, and a signing step without hiding security changes from the user.
|
||||
Use `docs/integration-prompt.md` in another Windows project. The prompt tells Codex or another assistant to add a visible trust check, a link or bundled copy of the standalone `MrTrust.exe`, and a signing step without hiding security changes from the user.
|
||||
|
||||
For agents that can inspect files autonomously, `docs/agent-target-integration.md` gives the decision tree, installer patterns, signing commands, and completion checklist.
|
||||
|
||||
BIN
assets/MrTrust.ico
Normal file
BIN
assets/MrTrust.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
162
docs/agent-target-integration.md
Normal file
162
docs/agent-target-integration.md
Normal file
@@ -0,0 +1,162 @@
|
||||
# Agent Target Integration Runbook
|
||||
|
||||
Use this file when you are an agent modifying another Windows project to support MrTrust.
|
||||
|
||||
## Non-Negotiable Goal
|
||||
|
||||
Modify the target project so that, after a user has installed trust with `MrTrust.exe`, the target project's MrSphay-signed Windows release artifacts start and validate normally.
|
||||
|
||||
Do not modify Windows security policy, Defender, SmartScreen, UAC, or certificate stores silently. MrTrust must remain visible, optional, and reversible.
|
||||
|
||||
## Inputs To Read First
|
||||
|
||||
1. Read `mrtrust.integration.json`.
|
||||
2. Read `docs/integration-prompt.md`.
|
||||
3. Inspect the target project for:
|
||||
- build commands
|
||||
- release artifact paths
|
||||
- installer technology
|
||||
- existing signing steps
|
||||
- user-facing docs
|
||||
- CI workflows
|
||||
|
||||
If the target project already has equivalent trust or signing integration, update it instead of duplicating it.
|
||||
|
||||
## Required Target Project Changes
|
||||
|
||||
Apply every item that fits the target project:
|
||||
|
||||
1. Add a user-facing MrTrust entry point.
|
||||
- If the project has an installer, add an optional action named `Open MrTrust` or `Trust MrSphay signed apps`.
|
||||
- If the project has an app settings/about/help screen, add a button or menu item that launches `MrTrust.exe`.
|
||||
- If the project has no UI or installer, add release documentation linking to or bundling `MrTrust.exe`.
|
||||
|
||||
2. Bundle or link the standalone executable.
|
||||
- Preferred bundled path: `MrTrust\MrTrust.exe`.
|
||||
- Source repository: `https://git.wilkensxl.de/MrSphay/MrTrust`.
|
||||
- Release page: `https://git.wilkensxl.de/MrSphay/MrTrust/releases`.
|
||||
- Do not require users to run `MrTrust.ps1`.
|
||||
- Do not copy MrTrust source scripts into user-facing release output unless the target project explicitly ships source.
|
||||
|
||||
3. Add signing for Windows artifacts.
|
||||
- Sign `.exe`, `.msi`, `.dll`, `.ps1`, `.psm1`, `.psd1`, and `.cat` release artifacts.
|
||||
- Use the public thumbprint from `mrtrust.integration.json`.
|
||||
- Only run signing where private signing material is securely available.
|
||||
- Do not commit `.pfx`, private keys, passwords, tokens, or signing secrets.
|
||||
|
||||
4. Add verification.
|
||||
- Verify the target project still builds.
|
||||
- Verify the release output contains the app artifacts and either `MrTrust.exe` or clear MrTrust download instructions.
|
||||
- Verify signing status where the OS/tooling is available.
|
||||
- Verify no private signing material is tracked or present in release output.
|
||||
|
||||
## Default Commands
|
||||
|
||||
Open MrTrust from a bundled release:
|
||||
|
||||
```powershell
|
||||
.\MrTrust\MrTrust.exe
|
||||
```
|
||||
|
||||
Sign one artifact from a Windows release runner:
|
||||
|
||||
```powershell
|
||||
.\MrTrust\MrTrust.exe sign -Path .\dist\App.exe -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
```
|
||||
|
||||
Sign a release directory:
|
||||
|
||||
```powershell
|
||||
.\MrTrust\MrTrust.exe sign -Path .\dist -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
```
|
||||
|
||||
Check a signature:
|
||||
|
||||
```powershell
|
||||
Get-AuthenticodeSignature .\dist\App.exe | Format-List Status,SignerCertificate,StatusMessage
|
||||
```
|
||||
|
||||
## Installer Patterns
|
||||
|
||||
### Inno Setup
|
||||
|
||||
Bundle `MrTrust.exe` and add an optional task or post-install action:
|
||||
|
||||
```ini
|
||||
[Files]
|
||||
Source: "MrTrust\MrTrust.exe"; DestDir: "{app}\MrTrust"; Flags: ignoreversion
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\MrTrust\MrTrust.exe"; Description: "Open MrTrust"; Flags: postinstall skipifsilent nowait
|
||||
```
|
||||
|
||||
### NSIS
|
||||
|
||||
```nsis
|
||||
SetOutPath "$INSTDIR\MrTrust"
|
||||
File "MrTrust\MrTrust.exe"
|
||||
CreateShortcut "$SMPROGRAMS\$StartMenuFolder\Open MrTrust.lnk" "$INSTDIR\MrTrust\MrTrust.exe"
|
||||
```
|
||||
|
||||
### WiX
|
||||
|
||||
Install `MrTrust.exe` as a regular file under an application `MrTrust` folder and expose a Start Menu shortcut or installer UI action. Do not run it silently during install.
|
||||
|
||||
### Electron Builder
|
||||
|
||||
Add `MrTrust\MrTrust.exe` to `extraResources`, then add a Help/About action that launches the copied executable with the platform shell API. Keep the action user-initiated.
|
||||
|
||||
### Portable ZIP
|
||||
|
||||
Place `MrTrust.exe` next to the app under:
|
||||
|
||||
```text
|
||||
MrTrust\MrTrust.exe
|
||||
```
|
||||
|
||||
Document that users should run it once before launching signed MrSphay apps if Windows does not yet trust the publisher.
|
||||
|
||||
## CI Signing Patterns
|
||||
|
||||
### Gitea Actions On Windows Runner
|
||||
|
||||
```yaml
|
||||
- name: Sign Windows artifacts
|
||||
shell: powershell
|
||||
run: |
|
||||
.\MrTrust\MrTrust.exe sign -Path .\dist -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
```
|
||||
|
||||
Use this only on a runner where the matching private code-signing certificate is installed in `Cert:\CurrentUser\My` or `Cert:\LocalMachine\My`.
|
||||
|
||||
### Local Secure Release Machine
|
||||
|
||||
```powershell
|
||||
.\MrTrust\MrTrust.exe sign -Path .\dist -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
```
|
||||
|
||||
Run this after build and before packaging.
|
||||
|
||||
## Autonomy Rules
|
||||
|
||||
Make reasonable target-project-specific choices without asking the user when:
|
||||
|
||||
- artifact paths are discoverable from existing build scripts
|
||||
- installer technology is obvious from repository files
|
||||
- there is already a docs or release notes location
|
||||
- CI already has a Windows release job you can extend
|
||||
|
||||
Stop and ask the user only when:
|
||||
|
||||
- signing requires a private certificate that is not present and no secret mechanism exists
|
||||
- the target project has multiple conflicting release systems and no primary release path is identifiable
|
||||
- a requested change would silently alter trust or weaken security policy
|
||||
|
||||
## Completion Checklist
|
||||
|
||||
- Target project has a visible MrTrust user path.
|
||||
- Target project links to or bundles standalone `MrTrust.exe`.
|
||||
- Supported Windows release artifacts are signed or the blocker is explicitly documented.
|
||||
- User docs explain install and remove trust.
|
||||
- No private signing material is committed.
|
||||
- Target project build/release verification ran, or the exact blocker is documented.
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
Use this prompt in another Windows project when you want Codex or another agent to add MrTrust support.
|
||||
|
||||
Before changing the target project, read:
|
||||
- `mrtrust.integration.json`
|
||||
- `docs/agent-target-integration.md`
|
||||
|
||||
```text
|
||||
Integrate MrTrust support into this Windows project.
|
||||
|
||||
@@ -10,22 +14,31 @@ Goal:
|
||||
- The project must not disable Defender, SmartScreen, UAC, or Windows security policy.
|
||||
- All trust changes must be visible and require explicit user confirmation.
|
||||
|
||||
Agent contract:
|
||||
- You are modifying the target Windows project, not MrTrust itself.
|
||||
- Use `mrtrust.integration.json` and `docs/agent-target-integration.md` as the authoritative integration contract.
|
||||
- Add MrTrust as a visible, optional trust-onboarding path for users.
|
||||
- Add or update the target project's release/signing pipeline so produced Windows artifacts are signed.
|
||||
- Do not mark the task complete after only copying documentation. The target project needs user-facing integration and signing support where applicable.
|
||||
|
||||
Implementation requirements:
|
||||
- Add a docs section that explains MrTrust and links to or bundles the MrTrust release ZIP.
|
||||
- Treat `MrTrust.exe` from the release ZIP as the user-facing integration point. Do not require users to copy or run MrTrust PowerShell source files.
|
||||
- Add a build or release signing step that signs Windows artifacts with the MrSphay code-signing certificate.
|
||||
- Do not commit any .pfx file, private key, certificate password, or signing secret.
|
||||
- If the project has an installer, add an optional "Open MrTrust" action that runs:
|
||||
powershell.exe -ExecutionPolicy Bypass -File .\MrTrust\MrTrust.ps1 gui
|
||||
.\MrTrust\MrTrust.exe
|
||||
- Prefer CurrentUser certificate installation by default.
|
||||
- Only offer LocalMachine installation when the user explicitly chooses an all-users install and the process is elevated.
|
||||
- Add an uninstall path or documentation that runs:
|
||||
powershell.exe -ExecutionPolicy Bypass -File .\MrTrust\MrTrust.ps1 uninstall
|
||||
- Add an uninstall path or documentation that opens MrTrust again and tells the user to choose "Remove trust".
|
||||
- Keep the UI wording clear: the user is trusting MrSphay signed software, not bypassing Windows security.
|
||||
- If this project produces an .exe, .msi, .dll, .ps1, .psm1, .psd1, or .cat release artifact, sign it with:
|
||||
powershell.exe -ExecutionPolicy Bypass -File .\MrTrust\MrTrust.ps1 sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
.\MrTrust\MrTrust.exe sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B
|
||||
- Treat the certificate thumbprint as public metadata, but never commit private signing material.
|
||||
- If the target project needs automated signing, call MrTrust's signing script from CI or a secure local release machine where the private certificate is already installed or supplied through secrets. Do not put private signing material into the target repository or user-facing release ZIP.
|
||||
|
||||
Verification:
|
||||
- Confirm the target project's user-facing release contains either a link to the MrTrust release ZIP or a bundled copy of `MrTrust.exe`.
|
||||
- Confirm unsigned builds still show as unsigned.
|
||||
- Confirm signed builds validate after MrTrust installation.
|
||||
- Confirm the MrTrust certificate can be removed again.
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
{
|
||||
"name": "codex-agent-repository-kit",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.6",
|
||||
"description": "Universal repository baseline for Codex-assisted projects.",
|
||||
"mrtrustIntegration": {
|
||||
"contract": "mrtrust.integration.json",
|
||||
"agentRunbook": "docs/agent-target-integration.md",
|
||||
"prompt": "docs/integration-prompt.md",
|
||||
"standaloneExecutable": "MrTrust.exe",
|
||||
"publicThumbprint": "A024A89200469F099EC4A172B4F96F6428AFD41B",
|
||||
"sourceRepository": "https://git.wilkensxl.de/MrSphay/MrTrust",
|
||||
"releasePage": "https://git.wilkensxl.de/MrSphay/MrTrust/releases"
|
||||
},
|
||||
"agentResponsibilities": [
|
||||
"Read manifest.json before copying files.",
|
||||
"Use copyMap target paths unless the repository already has an equivalent convention.",
|
||||
|
||||
@@ -13,6 +13,34 @@
|
||||
"description": {
|
||||
"type": "string"
|
||||
},
|
||||
"mrtrustIntegration": {
|
||||
"type": "object",
|
||||
"required": ["contract", "agentRunbook", "prompt", "standaloneExecutable", "publicThumbprint"],
|
||||
"properties": {
|
||||
"contract": {
|
||||
"type": "string"
|
||||
},
|
||||
"agentRunbook": {
|
||||
"type": "string"
|
||||
},
|
||||
"prompt": {
|
||||
"type": "string"
|
||||
},
|
||||
"standaloneExecutable": {
|
||||
"type": "string"
|
||||
},
|
||||
"publicThumbprint": {
|
||||
"type": "string"
|
||||
},
|
||||
"sourceRepository": {
|
||||
"type": "string"
|
||||
},
|
||||
"releasePage": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": true
|
||||
},
|
||||
"agentResponsibilities": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
59
mrtrust.integration.json
Normal file
59
mrtrust.integration.json
Normal file
@@ -0,0 +1,59 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"name": "MrTrust",
|
||||
"purpose": "Add explicit MrSphay trust onboarding and signing support to Windows target projects.",
|
||||
"sourceRepository": "https://git.wilkensxl.de/MrSphay/MrTrust",
|
||||
"releasePage": "https://git.wilkensxl.de/MrSphay/MrTrust/releases",
|
||||
"userFacingReleaseArtifact": {
|
||||
"fileName": "MrTrust.exe",
|
||||
"releaseZipNamePattern": "MrTrust-<version>.zip",
|
||||
"recommendedBundledPath": "MrTrust\\MrTrust.exe",
|
||||
"distribution": "Bundle this file directly or link to the MrTrust release ZIP.",
|
||||
"launchCommand": ".\\MrTrust\\MrTrust.exe",
|
||||
"removeTrustInstruction": "Open MrTrust and choose Remove trust."
|
||||
},
|
||||
"certificate": {
|
||||
"publisher": "MrSphay",
|
||||
"publicThumbprint": "A024A89200469F099EC4A172B4F96F6428AFD41B",
|
||||
"defaultTrustScope": "CurrentUser",
|
||||
"allUsersTrustScope": "LocalMachine",
|
||||
"privateMaterialPolicy": "Never commit .pfx files, private keys, passwords, tokens, or signing secrets."
|
||||
},
|
||||
"signing": {
|
||||
"supportedExtensions": [
|
||||
".exe",
|
||||
".msi",
|
||||
".dll",
|
||||
".ps1",
|
||||
".psm1",
|
||||
".psd1",
|
||||
".cat"
|
||||
],
|
||||
"preferredCommand": ".\\MrTrust\\MrTrust.exe sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B",
|
||||
"ciGuidance": "Run signing only on a trusted Windows release runner or secure local release machine where the private certificate is already installed or supplied through secrets.",
|
||||
"unsignedBehavior": "Unsigned builds should remain unsigned. MrTrust only makes correctly signed MrSphay artifacts validate after the user has installed trust."
|
||||
},
|
||||
"targetProjectAgentContract": {
|
||||
"modifyTargetProject": true,
|
||||
"requiredOutcomes": [
|
||||
"Expose a visible optional Open MrTrust or trust setup path.",
|
||||
"Link to or bundle the standalone MrTrust.exe.",
|
||||
"Sign Windows release artifacts when the target project produces supported artifact types.",
|
||||
"Document how users install and remove MrTrust trust.",
|
||||
"Verify no private signing material is present in the target repository or release artifacts."
|
||||
],
|
||||
"forbiddenOutcomes": [
|
||||
"Do not silently install certificates.",
|
||||
"Do not bypass Defender, SmartScreen, UAC, firewall, or Windows security policy.",
|
||||
"Do not claim MrTrust makes unsigned software trusted.",
|
||||
"Do not commit private signing material."
|
||||
],
|
||||
"fallbackWhenNoInstallerExists": [
|
||||
"Add release documentation that links to or bundles MrTrust.exe.",
|
||||
"Add a release signing step for supported Windows artifacts.",
|
||||
"Add verification notes explaining that the app starts normally after the user installs MrTrust and the artifact signature validates."
|
||||
]
|
||||
},
|
||||
"agentRunbook": "docs/agent-target-integration.md",
|
||||
"prompt": "docs/integration-prompt.md"
|
||||
}
|
||||
@@ -13,13 +13,40 @@ function Resolve-FullPath {
|
||||
|
||||
$root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
$sourcePath = Join-Path $root "src\MrTrustLauncher.cs"
|
||||
$iconPath = Join-Path $root "assets\MrTrust.ico"
|
||||
$resolvedOutputPath = Resolve-FullPath $OutputPath
|
||||
$outputDirectory = Split-Path -Parent $resolvedOutputPath
|
||||
$payloadFiles = @(
|
||||
@{ Path = "MrTrust.ps1"; ResourceName = "MrTrust.Payload.MrTrust.ps1" },
|
||||
@{ Path = "scripts\Build-MrTrustExe.ps1"; ResourceName = "MrTrust.Payload.scripts.Build-MrTrustExe.ps1" },
|
||||
@{ Path = "scripts\Install-MrTrust.ps1"; ResourceName = "MrTrust.Payload.scripts.Install-MrTrust.ps1" },
|
||||
@{ Path = "scripts\New-MrTrustCertificate.ps1"; ResourceName = "MrTrust.Payload.scripts.New-MrTrustCertificate.ps1" },
|
||||
@{ Path = "scripts\New-MrTrustIcon.ps1"; ResourceName = "MrTrust.Payload.scripts.New-MrTrustIcon.ps1" },
|
||||
@{ Path = "scripts\New-MrTrustRelease.ps1"; ResourceName = "MrTrust.Payload.scripts.New-MrTrustRelease.ps1" },
|
||||
@{ Path = "scripts\Sign-MrTrustProject.ps1"; ResourceName = "MrTrust.Payload.scripts.Sign-MrTrustProject.ps1" },
|
||||
@{ Path = "scripts\Start-MrTrustGui.ps1"; ResourceName = "MrTrust.Payload.scripts.Start-MrTrustGui.ps1" },
|
||||
@{ Path = "scripts\Uninstall-MrTrust.ps1"; ResourceName = "MrTrust.Payload.scripts.Uninstall-MrTrust.ps1" },
|
||||
@{ Path = "assets\MrTrust.ico"; ResourceName = "MrTrust.Payload.assets.MrTrust.ico" },
|
||||
@{ Path = "assets\certificates\MrSphay-LocalTrust-Root.cer"; ResourceName = "MrTrust.Payload.assets.certificates.MrSphay-LocalTrust-Root.cer" },
|
||||
@{ Path = "assets\certificates\MrSphay-CodeSigning.cer"; ResourceName = "MrTrust.Payload.assets.certificates.MrSphay-CodeSigning.cer" },
|
||||
@{ Path = "assets\certificates\thumbprints.txt"; ResourceName = "MrTrust.Payload.assets.certificates.thumbprints.txt" }
|
||||
)
|
||||
|
||||
if (-not (Test-Path -LiteralPath $sourcePath)) {
|
||||
throw "Launcher source not found: $sourcePath"
|
||||
}
|
||||
|
||||
if (-not (Test-Path -LiteralPath $iconPath)) {
|
||||
& (Join-Path $root "scripts\New-MrTrustIcon.ps1") -OutputPath $iconPath
|
||||
}
|
||||
|
||||
foreach ($payloadFile in $payloadFiles) {
|
||||
$payloadPath = Join-Path $root $payloadFile.Path
|
||||
if (-not (Test-Path -LiteralPath $payloadPath)) {
|
||||
throw "Payload file not found: $payloadPath"
|
||||
}
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null
|
||||
|
||||
$compilerCandidates = @(
|
||||
@@ -32,19 +59,29 @@ if (-not $compiler) {
|
||||
throw "csc.exe was not found. Run this build on a Windows Gitea runner with .NET Framework installed."
|
||||
}
|
||||
|
||||
& $compiler `
|
||||
/nologo `
|
||||
/target:winexe `
|
||||
/optimize+ `
|
||||
/platform:anycpu `
|
||||
/out:$resolvedOutputPath `
|
||||
/reference:System.Windows.Forms.dll `
|
||||
/reference:System.Drawing.dll `
|
||||
$sourcePath
|
||||
$compilerArguments = @(
|
||||
"/nologo",
|
||||
"/target:winexe",
|
||||
"/optimize+",
|
||||
"/platform:anycpu",
|
||||
"/out:$resolvedOutputPath",
|
||||
"/win32icon:$iconPath",
|
||||
"/reference:System.Windows.Forms.dll",
|
||||
"/reference:System.Drawing.dll"
|
||||
)
|
||||
|
||||
foreach ($payloadFile in $payloadFiles) {
|
||||
$payloadPath = Join-Path $root $payloadFile.Path
|
||||
$compilerArguments += "/resource:$payloadPath,$($payloadFile.ResourceName)"
|
||||
}
|
||||
|
||||
$compilerArguments += $sourcePath
|
||||
|
||||
& $compiler @compilerArguments
|
||||
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "csc.exe failed with exit code $LASTEXITCODE."
|
||||
}
|
||||
|
||||
Write-Host "Created EXE:"
|
||||
Write-Host "Created standalone EXE:"
|
||||
Write-Host " $resolvedOutputPath"
|
||||
|
||||
61
scripts/New-MrTrustIcon.ps1
Normal file
61
scripts/New-MrTrustIcon.ps1
Normal file
@@ -0,0 +1,61 @@
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string]$OutputPath = ".\assets\MrTrust.ico"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
function Resolve-FullPath {
|
||||
param([Parameter(Mandatory)][string]$Path)
|
||||
|
||||
$executionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($Path)
|
||||
}
|
||||
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
$resolvedOutputPath = Resolve-FullPath $OutputPath
|
||||
$outputDirectory = Split-Path -Parent $resolvedOutputPath
|
||||
New-Item -ItemType Directory -Force -Path $outputDirectory | Out-Null
|
||||
|
||||
$bitmap = [Drawing.Bitmap]::new(64, 64)
|
||||
$graphics = [Drawing.Graphics]::FromImage($bitmap)
|
||||
$graphics.SmoothingMode = [Drawing.Drawing2D.SmoothingMode]::AntiAlias
|
||||
$graphics.Clear([Drawing.Color]::Transparent)
|
||||
|
||||
$backgroundBrush = [Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(27, 32, 35))
|
||||
$accentBrush = [Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(28, 185, 111))
|
||||
$lightBrush = [Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(225, 231, 227))
|
||||
$shadowBrush = [Drawing.SolidBrush]::new([Drawing.Color]::FromArgb(70, 0, 0, 0))
|
||||
$outlinePen = [Drawing.Pen]::new([Drawing.Color]::FromArgb(71, 84, 90), 3)
|
||||
|
||||
$graphics.FillRectangle($shadowBrush, 9, 10, 48, 48)
|
||||
$graphics.FillRectangle($backgroundBrush, 7, 7, 48, 48)
|
||||
$graphics.DrawRectangle($outlinePen, 7, 7, 48, 48)
|
||||
$graphics.FillRectangle($accentBrush, 13, 13, 12, 36)
|
||||
$graphics.FillRectangle($accentBrush, 13, 13, 30, 12)
|
||||
$graphics.FillRectangle($lightBrush, 31, 29, 14, 20)
|
||||
|
||||
$font = [Drawing.Font]::new("Segoe UI", 18, [Drawing.FontStyle]::Bold, [Drawing.GraphicsUnit]::Pixel)
|
||||
$graphics.DrawString("T", $font, $lightBrush, 32, 27)
|
||||
|
||||
$handle = $bitmap.GetHicon()
|
||||
$icon = [Drawing.Icon]::FromHandle($handle)
|
||||
$stream = [IO.File]::Open($resolvedOutputPath, [IO.FileMode]::Create)
|
||||
try {
|
||||
$icon.Save($stream)
|
||||
}
|
||||
finally {
|
||||
$stream.Dispose()
|
||||
$icon.Dispose()
|
||||
$font.Dispose()
|
||||
$outlinePen.Dispose()
|
||||
$shadowBrush.Dispose()
|
||||
$lightBrush.Dispose()
|
||||
$accentBrush.Dispose()
|
||||
$backgroundBrush.Dispose()
|
||||
$graphics.Dispose()
|
||||
$bitmap.Dispose()
|
||||
}
|
||||
|
||||
Write-Host "Created icon:"
|
||||
Write-Host " $resolvedOutputPath"
|
||||
@@ -20,15 +20,17 @@ $output = Resolve-FullPath $OutputDirectory
|
||||
$packageRoot = Join-Path $output "MrTrust-$Version"
|
||||
$zipPath = Join-Path $output "MrTrust-$Version.zip"
|
||||
$exePath = Join-Path $output "MrTrust.exe"
|
||||
$iconPath = Join-Path $root "assets\MrTrust.ico"
|
||||
|
||||
if (Test-Path -LiteralPath $packageRoot) {
|
||||
Remove-Item -LiteralPath $packageRoot -Recurse -Force
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $packageRoot | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot "scripts") | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot "assets\certificates") | Out-Null
|
||||
New-Item -ItemType Directory -Force -Path (Join-Path $packageRoot "docs") | Out-Null
|
||||
|
||||
if (-not (Test-Path -LiteralPath $iconPath)) {
|
||||
& (Join-Path $root "scripts\New-MrTrustIcon.ps1") -OutputPath $iconPath
|
||||
}
|
||||
|
||||
& (Join-Path $root "scripts\Build-MrTrustExe.ps1") -OutputPath $exePath
|
||||
|
||||
@@ -50,15 +52,7 @@ if ($SigningThumbprint) {
|
||||
}
|
||||
|
||||
Copy-Item -LiteralPath $exePath -Destination $packageRoot
|
||||
Copy-Item -LiteralPath (Join-Path $root "MrTrust.ps1") -Destination $packageRoot
|
||||
Copy-Item -LiteralPath (Join-Path $root "README.md") -Destination $packageRoot
|
||||
Copy-Item -LiteralPath (Join-Path $root "scripts\Install-MrTrust.ps1") -Destination (Join-Path $packageRoot "scripts")
|
||||
Copy-Item -LiteralPath (Join-Path $root "scripts\Uninstall-MrTrust.ps1") -Destination (Join-Path $packageRoot "scripts")
|
||||
Copy-Item -LiteralPath (Join-Path $root "scripts\Start-MrTrustGui.ps1") -Destination (Join-Path $packageRoot "scripts")
|
||||
Copy-Item -LiteralPath (Join-Path $root "assets\certificates\MrSphay-LocalTrust-Root.cer") -Destination (Join-Path $packageRoot "assets\certificates")
|
||||
Copy-Item -LiteralPath (Join-Path $root "assets\certificates\MrSphay-CodeSigning.cer") -Destination (Join-Path $packageRoot "assets\certificates")
|
||||
Copy-Item -LiteralPath (Join-Path $root "assets\certificates\thumbprints.txt") -Destination (Join-Path $packageRoot "assets\certificates")
|
||||
Copy-Item -LiteralPath (Join-Path $root "docs\security-model.md") -Destination (Join-Path $packageRoot "docs")
|
||||
|
||||
if (Test-Path -LiteralPath $zipPath) {
|
||||
Remove-Item -LiteralPath $zipPath -Force
|
||||
|
||||
@@ -9,6 +9,7 @@ Add-Type -AssemblyName System.Drawing
|
||||
$script:RootPath = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
||||
$script:RootCertificatePath = Join-Path $script:RootPath "assets\certificates\MrSphay-LocalTrust-Root.cer"
|
||||
$script:PublisherCertificatePath = Join-Path $script:RootPath "assets\certificates\MrSphay-CodeSigning.cer"
|
||||
$script:IconPath = Join-Path $script:RootPath "assets\MrTrust.ico"
|
||||
|
||||
function Test-IsAdministrator {
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
@@ -75,11 +76,11 @@ function Refresh-MrTrustStatus {
|
||||
$script:ExpiryLabel.Text = $rootCertificate.NotAfter.ToString("yyyy-MM-dd")
|
||||
|
||||
if ($rootInstalled -and $publisherInstalled) {
|
||||
Set-StatusText "Trusted for $scope"
|
||||
Set-StatusText "Trusted"
|
||||
$script:StatusPill.BackColor = [Drawing.Color]::FromArgb(28, 185, 111)
|
||||
}
|
||||
else {
|
||||
Set-StatusText "Not installed for $scope"
|
||||
Set-StatusText "Not installed"
|
||||
$script:StatusPill.BackColor = [Drawing.Color]::FromArgb(242, 153, 74)
|
||||
}
|
||||
}
|
||||
@@ -166,14 +167,17 @@ function Remove-MrTrustCertificates {
|
||||
$form = [Windows.Forms.Form]::new()
|
||||
$form.Text = "MrTrust"
|
||||
$form.StartPosition = "CenterScreen"
|
||||
$form.ClientSize = [Drawing.Size]::new(760, 520)
|
||||
$form.MinimumSize = [Drawing.Size]::new(720, 500)
|
||||
$form.ClientSize = [Drawing.Size]::new(900, 560)
|
||||
$form.MinimumSize = [Drawing.Size]::new(860, 540)
|
||||
$form.BackColor = [Drawing.Color]::FromArgb(22, 26, 29)
|
||||
$form.Font = [Drawing.Font]::new("Segoe UI", 10)
|
||||
if (Test-Path -LiteralPath $script:IconPath) {
|
||||
$form.Icon = [Drawing.Icon]::new($script:IconPath)
|
||||
}
|
||||
|
||||
$header = [Windows.Forms.Panel]::new()
|
||||
$header.Dock = "Top"
|
||||
$header.Height = 108
|
||||
$header.Height = 124
|
||||
$header.BackColor = [Drawing.Color]::FromArgb(27, 32, 35)
|
||||
$form.Controls.Add($header)
|
||||
|
||||
@@ -183,32 +187,50 @@ $accent.Width = 8
|
||||
$accent.BackColor = [Drawing.Color]::FromArgb(28, 185, 111)
|
||||
$header.Controls.Add($accent)
|
||||
|
||||
$logoBox = [Windows.Forms.PictureBox]::new()
|
||||
$logoBox.Size = [Drawing.Size]::new(44, 44)
|
||||
$logoBox.Location = [Drawing.Point]::new(34, 30)
|
||||
$logoBox.SizeMode = "StretchImage"
|
||||
if (Test-Path -LiteralPath $script:IconPath) {
|
||||
$logoBox.Image = [Drawing.Icon]::new($script:IconPath).ToBitmap()
|
||||
}
|
||||
$header.Controls.Add($logoBox)
|
||||
|
||||
$title = [Windows.Forms.Label]::new()
|
||||
$title.Text = "MrTrust"
|
||||
$title.ForeColor = [Drawing.Color]::White
|
||||
$title.Font = [Drawing.Font]::new("Segoe UI", 24, [Drawing.FontStyle]::Bold)
|
||||
$title.AutoSize = $true
|
||||
$title.Location = [Drawing.Point]::new(30, 18)
|
||||
$title.Location = [Drawing.Point]::new(92, 24)
|
||||
$header.Controls.Add($title)
|
||||
|
||||
$subtitle = [Windows.Forms.Label]::new()
|
||||
$subtitle.Text = "Trust setup for MrSphay signed Windows apps"
|
||||
$subtitle.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183)
|
||||
$subtitle.AutoSize = $true
|
||||
$subtitle.Location = [Drawing.Point]::new(34, 66)
|
||||
$subtitle.Location = [Drawing.Point]::new(96, 74)
|
||||
$header.Controls.Add($subtitle)
|
||||
|
||||
$statusText = [Windows.Forms.Label]::new()
|
||||
$statusText.Text = "Status"
|
||||
$statusText.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183)
|
||||
$statusText.AutoSize = $true
|
||||
$statusText.Location = [Drawing.Point]::new(646, 32)
|
||||
$header.Controls.Add($statusText)
|
||||
|
||||
$script:StatusPill = [Windows.Forms.Panel]::new()
|
||||
$script:StatusPill.Size = [Drawing.Size]::new(14, 14)
|
||||
$script:StatusPill.Location = [Drawing.Point]::new(610, 42)
|
||||
$script:StatusPill.Size = [Drawing.Size]::new(16, 16)
|
||||
$script:StatusPill.Location = [Drawing.Point]::new(646, 62)
|
||||
$script:StatusPill.BackColor = [Drawing.Color]::FromArgb(242, 153, 74)
|
||||
$header.Controls.Add($script:StatusPill)
|
||||
|
||||
$script:StatusLabel = [Windows.Forms.Label]::new()
|
||||
$script:StatusLabel.Text = "Checking..."
|
||||
$script:StatusLabel.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227)
|
||||
$script:StatusLabel.AutoSize = $true
|
||||
$script:StatusLabel.Location = [Drawing.Point]::new(632, 38)
|
||||
$script:StatusLabel.AutoSize = $false
|
||||
$script:StatusLabel.AutoEllipsis = $true
|
||||
$script:StatusLabel.Location = [Drawing.Point]::new(674, 57)
|
||||
$script:StatusLabel.Size = [Drawing.Size]::new(190, 28)
|
||||
$header.Controls.Add($script:StatusLabel)
|
||||
|
||||
$content = [Windows.Forms.Panel]::new()
|
||||
@@ -219,8 +241,8 @@ $form.Controls.Add($content)
|
||||
|
||||
$infoPanel = [Windows.Forms.Panel]::new()
|
||||
$infoPanel.BackColor = [Drawing.Color]::FromArgb(31, 37, 40)
|
||||
$infoPanel.Size = [Drawing.Size]::new(700, 210)
|
||||
$infoPanel.Location = [Drawing.Point]::new(30, 34)
|
||||
$infoPanel.Size = [Drawing.Size]::new(820, 226)
|
||||
$infoPanel.Location = [Drawing.Point]::new(40, 34)
|
||||
$content.Controls.Add($infoPanel)
|
||||
|
||||
$scopeLabel = [Windows.Forms.Label]::new()
|
||||
@@ -289,7 +311,7 @@ $installButton.BackColor = [Drawing.Color]::FromArgb(28, 185, 111)
|
||||
$installButton.ForeColor = [Drawing.Color]::White
|
||||
$installButton.FlatStyle = "Flat"
|
||||
$installButton.Size = [Drawing.Size]::new(180, 46)
|
||||
$installButton.Location = [Drawing.Point]::new(30, 274)
|
||||
$installButton.Location = [Drawing.Point]::new(40, 292)
|
||||
$installButton.Add_Click({ Install-MrTrustCertificates })
|
||||
$content.Controls.Add($installButton)
|
||||
|
||||
@@ -299,7 +321,7 @@ $removeButton.BackColor = [Drawing.Color]::FromArgb(44, 52, 56)
|
||||
$removeButton.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227)
|
||||
$removeButton.FlatStyle = "Flat"
|
||||
$removeButton.Size = [Drawing.Size]::new(180, 46)
|
||||
$removeButton.Location = [Drawing.Point]::new(230, 274)
|
||||
$removeButton.Location = [Drawing.Point]::new(240, 292)
|
||||
$removeButton.Add_Click({ Remove-MrTrustCertificates })
|
||||
$content.Controls.Add($removeButton)
|
||||
|
||||
@@ -309,15 +331,15 @@ $refreshButton.BackColor = [Drawing.Color]::FromArgb(44, 52, 56)
|
||||
$refreshButton.ForeColor = [Drawing.Color]::FromArgb(225, 231, 227)
|
||||
$refreshButton.FlatStyle = "Flat"
|
||||
$refreshButton.Size = [Drawing.Size]::new(140, 46)
|
||||
$refreshButton.Location = [Drawing.Point]::new(430, 274)
|
||||
$refreshButton.Location = [Drawing.Point]::new(440, 292)
|
||||
$refreshButton.Add_Click({ Refresh-MrTrustStatus })
|
||||
$content.Controls.Add($refreshButton)
|
||||
|
||||
$note = [Windows.Forms.Label]::new()
|
||||
$note.Text = "MrTrust installs public certificates only. It does not disable Defender, SmartScreen, UAC, or enterprise policies."
|
||||
$note.ForeColor = [Drawing.Color]::FromArgb(177, 190, 183)
|
||||
$note.Location = [Drawing.Point]::new(30, 352)
|
||||
$note.Size = [Drawing.Size]::new(700, 48)
|
||||
$note.Location = [Drawing.Point]::new(40, 376)
|
||||
$note.Size = [Drawing.Size]::new(820, 48)
|
||||
$content.Controls.Add($note)
|
||||
|
||||
$form.Add_Shown({ Refresh-MrTrustStatus })
|
||||
|
||||
@@ -1,34 +1,51 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
|
||||
#pragma warning disable CS8600, CS8602
|
||||
|
||||
namespace MrTrust
|
||||
{
|
||||
internal static class MrTrustLauncher
|
||||
{
|
||||
[STAThread]
|
||||
private static int Main()
|
||||
{
|
||||
string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||
string scriptPath = Path.Combine(baseDirectory, "MrTrust.ps1");
|
||||
private const string PayloadResourcePrefix = "MrTrust.Payload.";
|
||||
|
||||
if (!File.Exists(scriptPath))
|
||||
{
|
||||
MessageBox.Show(
|
||||
"MrTrust.ps1 was not found next to MrTrust.exe.",
|
||||
"MrTrust",
|
||||
MessageBoxButtons.OK,
|
||||
MessageBoxIcon.Error);
|
||||
return 1;
|
||||
}
|
||||
private static readonly PayloadFile[] PayloadFiles =
|
||||
{
|
||||
new PayloadFile("MrTrust.ps1", "MrTrust.ps1"),
|
||||
new PayloadFile("scripts.Build-MrTrustExe.ps1", Path.Combine("scripts", "Build-MrTrustExe.ps1")),
|
||||
new PayloadFile("scripts.Install-MrTrust.ps1", Path.Combine("scripts", "Install-MrTrust.ps1")),
|
||||
new PayloadFile("scripts.New-MrTrustCertificate.ps1", Path.Combine("scripts", "New-MrTrustCertificate.ps1")),
|
||||
new PayloadFile("scripts.New-MrTrustIcon.ps1", Path.Combine("scripts", "New-MrTrustIcon.ps1")),
|
||||
new PayloadFile("scripts.New-MrTrustRelease.ps1", Path.Combine("scripts", "New-MrTrustRelease.ps1")),
|
||||
new PayloadFile("scripts.Sign-MrTrustProject.ps1", Path.Combine("scripts", "Sign-MrTrustProject.ps1")),
|
||||
new PayloadFile("scripts.Start-MrTrustGui.ps1", Path.Combine("scripts", "Start-MrTrustGui.ps1")),
|
||||
new PayloadFile("scripts.Uninstall-MrTrust.ps1", Path.Combine("scripts", "Uninstall-MrTrust.ps1")),
|
||||
new PayloadFile("assets.MrTrust.ico", Path.Combine("assets", "MrTrust.ico")),
|
||||
new PayloadFile("assets.certificates.MrSphay-LocalTrust-Root.cer", Path.Combine("assets", "certificates", "MrSphay-LocalTrust-Root.cer")),
|
||||
new PayloadFile("assets.certificates.MrSphay-CodeSigning.cer", Path.Combine("assets", "certificates", "MrSphay-CodeSigning.cer")),
|
||||
new PayloadFile("assets.certificates.thumbprints.txt", Path.Combine("assets", "certificates", "thumbprints.txt"))
|
||||
};
|
||||
|
||||
[STAThread]
|
||||
private static int Main(string[] args)
|
||||
{
|
||||
string baseDirectory = string.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
baseDirectory = ExtractPayload();
|
||||
string scriptPath = Path.Combine(baseDirectory, "MrTrust.ps1");
|
||||
string commandArguments = BuildCommandArguments(args);
|
||||
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo
|
||||
{
|
||||
FileName = "powershell.exe",
|
||||
Arguments = "-NoProfile -ExecutionPolicy Bypass -File \"" + scriptPath + "\" gui",
|
||||
Arguments = "-NoProfile -ExecutionPolicy Bypass -File " + QuoteArgument(scriptPath) + " " + commandArguments,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true,
|
||||
WorkingDirectory = baseDirectory
|
||||
@@ -40,9 +57,10 @@ namespace MrTrust
|
||||
{
|
||||
throw new InvalidOperationException("PowerShell could not be started.");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
process.WaitForExit();
|
||||
return process.ExitCode;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -53,6 +71,123 @@ namespace MrTrust
|
||||
MessageBoxIcon.Error);
|
||||
return 1;
|
||||
}
|
||||
finally
|
||||
{
|
||||
TryDeleteDirectory(baseDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
private static string ExtractPayload()
|
||||
{
|
||||
Assembly assembly = Assembly.GetExecutingAssembly();
|
||||
string versionKey = GetPayloadVersionKey(assembly);
|
||||
string targetDirectory = Path.Combine(
|
||||
Path.GetTempPath(),
|
||||
"MrTrust",
|
||||
"standalone",
|
||||
versionKey,
|
||||
Guid.NewGuid().ToString("N"));
|
||||
|
||||
foreach (PayloadFile payloadFile in PayloadFiles)
|
||||
{
|
||||
string targetPath = Path.Combine(targetDirectory, payloadFile.RelativePath);
|
||||
string targetParent = Path.GetDirectoryName(targetPath);
|
||||
if (!string.IsNullOrEmpty(targetParent))
|
||||
{
|
||||
Directory.CreateDirectory(targetParent);
|
||||
}
|
||||
|
||||
using (Stream stream = assembly.GetManifestResourceStream(PayloadResourcePrefix + payloadFile.ResourceName))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
throw new FileNotFoundException("Embedded MrTrust payload file was not found.", payloadFile.RelativePath);
|
||||
}
|
||||
|
||||
using (FileStream file = File.Create(targetPath))
|
||||
{
|
||||
stream.CopyTo(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return targetDirectory;
|
||||
}
|
||||
|
||||
private static void TryDeleteDirectory(string directory)
|
||||
{
|
||||
if (string.IsNullOrEmpty(directory) || !Directory.Exists(directory))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Directory.Delete(directory, true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Best-effort cleanup only. A locked icon or antivirus scan should not mask the command result.
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPayloadVersionKey(Assembly assembly)
|
||||
{
|
||||
string location = Application.ExecutablePath;
|
||||
if (File.Exists(location))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(location);
|
||||
return fileInfo.Length.ToString("x") + "-" + fileInfo.LastWriteTimeUtc.Ticks.ToString("x");
|
||||
}
|
||||
|
||||
return assembly.GetName().Version.ToString();
|
||||
}
|
||||
|
||||
private static string BuildCommandArguments(string[] args)
|
||||
{
|
||||
string[] effectiveArgs = args.Length == 0 ? new[] { "gui" } : args;
|
||||
return string.Join(" ", effectiveArgs.Select(QuoteArgument).ToArray());
|
||||
}
|
||||
|
||||
private static string QuoteArgument(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return "\"\"";
|
||||
}
|
||||
|
||||
if (value.IndexOfAny(new[] { ' ', '\t', '\n', '\r', '"' }) < 0)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.Append('"');
|
||||
foreach (char character in value)
|
||||
{
|
||||
if (character == '"')
|
||||
{
|
||||
builder.Append('\\');
|
||||
}
|
||||
|
||||
builder.Append(character);
|
||||
}
|
||||
|
||||
builder.Append('"');
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
private sealed class PayloadFile
|
||||
{
|
||||
public PayloadFile(string resourceName, string relativePath)
|
||||
{
|
||||
ResourceName = resourceName;
|
||||
RelativePath = relativePath;
|
||||
}
|
||||
|
||||
public string ResourceName { get; private set; }
|
||||
|
||||
public string RelativePath { get; private set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
src/MrTrustLauncher.csproj
Normal file
31
src/MrTrustLauncher.csproj
Normal file
@@ -0,0 +1,31 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<EnableWindowsTargeting>true</EnableWindowsTargeting>
|
||||
<AssemblyName>MrTrust</AssemblyName>
|
||||
<RootNamespace>MrTrust</RootNamespace>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||
<ApplicationIcon>..\assets\MrTrust.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="..\MrTrust.ps1" LogicalName="MrTrust.Payload.MrTrust.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\Build-MrTrustExe.ps1" LogicalName="MrTrust.Payload.scripts.Build-MrTrustExe.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\Install-MrTrust.ps1" LogicalName="MrTrust.Payload.scripts.Install-MrTrust.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\New-MrTrustCertificate.ps1" LogicalName="MrTrust.Payload.scripts.New-MrTrustCertificate.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\New-MrTrustIcon.ps1" LogicalName="MrTrust.Payload.scripts.New-MrTrustIcon.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\New-MrTrustRelease.ps1" LogicalName="MrTrust.Payload.scripts.New-MrTrustRelease.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\Sign-MrTrustProject.ps1" LogicalName="MrTrust.Payload.scripts.Sign-MrTrustProject.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\Start-MrTrustGui.ps1" LogicalName="MrTrust.Payload.scripts.Start-MrTrustGui.ps1" />
|
||||
<EmbeddedResource Include="..\scripts\Uninstall-MrTrust.ps1" LogicalName="MrTrust.Payload.scripts.Uninstall-MrTrust.ps1" />
|
||||
<EmbeddedResource Include="..\assets\MrTrust.ico" LogicalName="MrTrust.Payload.assets.MrTrust.ico" />
|
||||
<EmbeddedResource Include="..\assets\certificates\MrSphay-LocalTrust-Root.cer" LogicalName="MrTrust.Payload.assets.certificates.MrSphay-LocalTrust-Root.cer" />
|
||||
<EmbeddedResource Include="..\assets\certificates\MrSphay-CodeSigning.cer" LogicalName="MrTrust.Payload.assets.certificates.MrSphay-CodeSigning.cer" />
|
||||
<EmbeddedResource Include="..\assets\certificates\thumbprints.txt" LogicalName="MrTrust.Payload.assets.certificates.thumbprints.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
Reference in New Issue
Block a user