11 Commits

Author SHA1 Message Date
MrSphay
a5cea35069 Add Linux signing helper payload
All checks were successful
Build MrTrust / build (push) Successful in 5m9s
2026-05-16 03:20:41 +02:00
MrSphay
f3c353b821 Fix Gitea workflow YAML parsing
Some checks failed
Build MrTrust / build (push) Failing after 40s
2026-05-16 03:16:28 +02:00
MrSphay
d3234e03b8 Make release asset upload idempotent 2026-05-16 03:14:48 +02:00
631a66dab1 0.1.3
Added Ubuntu-runner signing support through osslsigncode and PFX secrets.
2026-05-16 03:08:43 +02:00
16e5d1377c Parse Gitea release id as JSON
All checks were successful
Build MrTrust / build (push) Successful in 4m20s
2026-05-16 02:42:55 +02:00
7a2a643d15 Use public Gitea API for release asset upload
Some checks failed
Build MrTrust / build (push) Failing after 4m22s
2026-05-16 02:37:41 +02:00
e885978aba Attach release ZIP from runner
Some checks failed
Build MrTrust / build (push) Failing after 2m47s
2026-05-16 02:33:38 +02:00
d6e2d5ab52 Prepare MrTrust 0.1.2 release
All checks were successful
Build MrTrust / build (push) Successful in 2m37s
2026-05-16 02:28:20 +02:00
84a5df7216 Add autonomous MrTrust target integration contract
All checks were successful
Build MrTrust / build (push) Successful in 2m45s
2026-05-16 02:03:25 +02:00
01148f4703 Clarify MrTrust target project integration for agents
All checks were successful
Build MrTrust / build (push) Successful in 2m31s
2026-05-16 01:46:36 +02:00
93ca15a881 Make MrTrust executable standalone
All checks were successful
Build MrTrust / build (push) Successful in 3m49s
2026-05-16 01:21:52 +02:00
14 changed files with 731 additions and 79 deletions

View File

@@ -10,6 +10,8 @@ on:
jobs:
build:
runs-on: ubuntu-latest
env:
MRTRUST_VERSION: 0.1.3
steps:
- name: Checkout
@@ -24,32 +26,25 @@ jobs:
shell: bash
run: |
set -euo pipefail
version="0.1.1"
dotnet publish src/MrTrustLauncher.csproj \
--configuration Release \
--runtime win-x64 \
--output dist/build \
-p:EnableWindowsTargeting=true \
-p:PublishSingleFile=true \
-p:SelfContained=false
-p:SelfContained=true
cp dist/build/MrTrust.exe dist/MrTrust.exe
- name: Build release ZIP
shell: bash
run: |
set -euo pipefail
version="0.1.1"
version="${MRTRUST_VERSION}"
package_root="dist/MrTrust-${version}"
rm -rf "$package_root" "dist/MrTrust-${version}.zip"
mkdir -p "$package_root/scripts" "$package_root/assets/certificates" "$package_root/docs"
mkdir -p "$package_root"
cp dist/MrTrust.exe "$package_root/"
cp MrTrust.ps1 README.md "$package_root/"
cp assets/MrTrust.ico "$package_root/assets/"
cp scripts/Install-MrTrust.ps1 scripts/Uninstall-MrTrust.ps1 scripts/Start-MrTrustGui.ps1 "$package_root/scripts/"
cp assets/certificates/MrSphay-LocalTrust-Root.cer "$package_root/assets/certificates/"
cp assets/certificates/MrSphay-CodeSigning.cer "$package_root/assets/certificates/"
cp assets/certificates/thumbprints.txt "$package_root/assets/certificates/"
cp docs/security-model.md "$package_root/docs/"
cp README.md "$package_root/"
(cd dist && zip -r "MrTrust-${version}.zip" "MrTrust-${version}")
- name: Show package contents
@@ -60,5 +55,48 @@ jobs:
- name: Upload release artifact
uses: actions/upload-artifact@v3
with:
name: MrTrust-0.1.1
path: dist/MrTrust-0.1.1.zip
name: MrTrust-${{ env.MRTRUST_VERSION }}
path: dist/MrTrust-${{ env.MRTRUST_VERSION }}.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="${MRTRUST_VERSION}"
asset_name="MrTrust-${version}.zip"
api="https://git.wilkensxl.de/api/v1/repos/MrSphay/MrTrust"
release_response="$(mktemp)"
status="$(curl -sS -o "$release_response" -w "%{http_code}" -H "Authorization: token ${GITEA_TOKEN}" "${api}/releases/tags/v${version}")"
if [ "$status" = "404" ]; then
release_json="$(VERSION="$version" python3 -c 'import json, os; version = os.environ["VERSION"]; print(json.dumps({"tag_name": f"v{version}", "target_commitish": "main", "name": f"MrTrust v{version}", "body": f"MrTrust v{version} release built by the Gitea runner.", "draft": False, "prerelease": False}))')"
curl -fsS \
-X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$release_json" \
"${api}/releases" > "$release_response"
elif [ "$status" != "200" ]; then
cat "$release_response" >&2
exit 1
fi
release_json="$(cat "$release_response")"
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
existing_asset_id="$(RELEASE_JSON="$release_json" ASSET_NAME="$asset_name" python3 -c 'import json, os; release = json.loads(os.environ["RELEASE_JSON"]); asset_name = os.environ["ASSET_NAME"]; print(next((str(asset.get("id", "")) for asset in release.get("assets", []) if asset.get("name") == asset_name), ""))')"
if [ -n "$existing_asset_id" ]; then
curl -fsS \
-X DELETE \
-H "Authorization: token ${GITEA_TOKEN}" \
"${api}/releases/${release_id}/assets/${existing_asset_id}"
fi
curl -fsS \
-X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-F "attachment=@dist/${asset_name}" \
"${api}/releases/${release_id}/assets?name=${asset_name}"

View File

@@ -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

View File

@@ -1,5 +1,16 @@
# Changelog
## 0.1.3
- Added Ubuntu-runner signing support through `osslsigncode` and PFX secrets.
## 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.

View File

@@ -13,13 +13,18 @@ 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/Sign-MrTrustProjectLinux.sh` signs Windows PE/MSI/CAT artifacts on Ubuntu Gitea runners with `osslsigncode`.
- `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,25 +70,14 @@ Remove the trust certificate:
Build a user-facing ZIP release:
```powershell
.\scripts\New-MrTrustRelease.ps1 -Version 0.1.1
.\scripts\New-MrTrustRelease.ps1 -Version 0.1.3
```
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:
@@ -95,18 +89,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.
@@ -119,4 +129,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.

View File

@@ -0,0 +1,209 @@
# 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.
- On the available `ubuntu-latest` Gitea runners, use `osslsigncode` with PFX secrets for `.exe`, `.dll`, `.msi`, and `.cat`.
- PowerShell script signing (`.ps1`, `.psm1`, `.psd1`) still requires a Windows signing environment. If no Windows runner exists, document that limitation instead of blocking PE/MSI signing.
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
```
Sign a release directory on an Ubuntu Gitea runner:
```bash
bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh ./dist
```
## 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 Ubuntu Runner
Use this when only `ubuntu-latest`, `ubuntu-24.04`, or `ubuntu-22.04` runners are available.
Required Gitea secrets:
```text
MRTRUST_CODESIGN_PFX_BASE64
MRTRUST_CODESIGN_PFX_PASSWORD
```
Create `MRTRUST_CODESIGN_PFX_BASE64` locally from the private `.pfx`:
```powershell
[Convert]::ToBase64String([IO.File]::ReadAllBytes(".\private\MrSphay-CodeSigning.pfx")) | Set-Clipboard
```
Then paste the clipboard value into the Gitea secret. Do not commit the `.pfx` or the base64 value.
Ubuntu workflow step:
```yaml
- name: Install signing tool
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y osslsigncode
- name: Sign Windows artifacts
shell: bash
env:
MRTRUST_CODESIGN_PFX_BASE64: ${{ secrets.MRTRUST_CODESIGN_PFX_BASE64 }}
MRTRUST_CODESIGN_PFX_PASSWORD: ${{ secrets.MRTRUST_CODESIGN_PFX_PASSWORD }}
run: |
bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh ./dist
```
This signs `.exe`, `.dll`, `.msi`, and `.cat` artifacts. It does not sign PowerShell script files.
### 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.

View File

@@ -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,33 @@ 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
- If this project produces an .exe, .msi, .dll, or .cat release artifact on an Ubuntu Gitea runner, sign it with:
bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh <artifact-path>
- Treat the certificate thumbprint as public metadata, but never commit private signing material.
- Configure Gitea secrets `MRTRUST_CODESIGN_PFX_BASE64` and `MRTRUST_CODESIGN_PFX_PASSWORD` for Ubuntu runner signing.
- If the target project needs .ps1, .psm1, or .psd1 signing, use a Windows signing environment or document that script signing is not available on the current Ubuntu-only runners.
- 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.

View File

@@ -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.",

View File

@@ -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": {

86
mrtrust.integration.json Normal file
View File

@@ -0,0 +1,86 @@
{
"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"
],
"ubuntuRunner": {
"supportedExtensions": [
".exe",
".msi",
".dll",
".cat"
],
"requiredTool": "osslsigncode",
"helperScript": "scripts/Sign-MrTrustProjectLinux.sh",
"requiredSecrets": [
"MRTRUST_CODESIGN_PFX_BASE64",
"MRTRUST_CODESIGN_PFX_PASSWORD"
],
"preferredCommand": "bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh <artifact-path>"
},
"windowsRunner": {
"supportedExtensions": [
".exe",
".msi",
".dll",
".ps1",
".psm1",
".psd1",
".cat"
],
"preferredCommand": ".\\MrTrust\\MrTrust.exe sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B"
},
"preferredCommand": "bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh <artifact-path>",
"ciGuidance": "On ubuntu-latest runners, sign PE/MSI/CAT artifacts with osslsigncode using a PFX stored in Gitea secrets. Use Windows runners only when signing PowerShell scripts or when Windows certificate store signing is required.",
"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"
}

View File

@@ -16,6 +16,22 @@ $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\Sign-MrTrustProjectLinux.sh"; ResourceName = "MrTrust.Payload.scripts.Sign-MrTrustProjectLinux.sh" },
@{ 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"
@@ -25,6 +41,13 @@ 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 = @(
@@ -37,20 +60,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 `
/win32icon:$iconPath `
/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"

View File

@@ -27,9 +27,6 @@ if (Test-Path -LiteralPath $packageRoot) {
}
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
@@ -55,16 +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 $iconPath -Destination (Join-Path $packageRoot "assets")
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

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env bash
set -euo pipefail
if [ "$#" -lt 1 ]; then
echo "Usage: Sign-MrTrustProjectLinux.sh <artifact> [artifact...]" >&2
exit 2
fi
if [ -z "${MRTRUST_CODESIGN_PFX_BASE64:-}" ]; then
echo "MRTRUST_CODESIGN_PFX_BASE64 is required." >&2
exit 2
fi
if [ -z "${MRTRUST_CODESIGN_PFX_PASSWORD:-}" ]; then
echo "MRTRUST_CODESIGN_PFX_PASSWORD is required." >&2
exit 2
fi
if ! command -v osslsigncode >/dev/null 2>&1; then
if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y osslsigncode
else
echo "osslsigncode is not installed and apt-get is unavailable." >&2
exit 2
fi
fi
work_dir="$(mktemp -d)"
trap 'rm -rf "$work_dir"' EXIT
pfx_path="$work_dir/mrtrust-codesign.pfx"
printf '%s' "$MRTRUST_CODESIGN_PFX_BASE64" | base64 -d > "$pfx_path"
timestamp_url="${MRTRUST_TIMESTAMP_URL:-http://timestamp.digicert.com}"
for artifact in "$@"; do
if [ ! -f "$artifact" ]; then
echo "Artifact not found: $artifact" >&2
exit 2
fi
case "${artifact##*.}" in
exe|EXE|msi|MSI|dll|DLL|cat|CAT)
;;
*)
echo "Unsupported artifact for osslsigncode: $artifact" >&2
exit 2
;;
esac
signed_path="$work_dir/$(basename "$artifact").signed"
args=(
sign
-pkcs12 "$pfx_path"
-pass "$MRTRUST_CODESIGN_PFX_PASSWORD"
-n "MrSphay"
-i "https://git.wilkensxl.de/MrSphay"
-in "$artifact"
-out "$signed_path"
)
if [ -n "$timestamp_url" ]; then
args+=( -t "$timestamp_url" )
fi
osslsigncode "${args[@]}"
mv "$signed_path" "$artifact"
echo "Signed $artifact"
done

View File

@@ -1,34 +1,50 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows.Forms;
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.Sign-MrTrustProjectLinux.sh", Path.Combine("scripts", "Sign-MrTrustProjectLinux.sh")),
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 +56,10 @@ namespace MrTrust
{
throw new InvalidOperationException("PowerShell could not be started.");
}
}
return 0;
process.WaitForExit();
return process.ExitCode;
}
}
catch (Exception ex)
{
@@ -53,6 +70,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; }
}
}
}

View File

@@ -9,7 +9,24 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<PublishSingleFile>true</PublishSingleFile>
<SelfContained>false</SelfContained>
<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\Sign-MrTrustProjectLinux.sh" LogicalName="MrTrust.Payload.scripts.Sign-MrTrustProjectLinux.sh" />
<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>