Added Ubuntu-runner signing support through osslsigncode and PFX secrets.
This commit is contained in:
2026-05-16 03:08:43 +02:00
parent 16e5d1377c
commit 631a66dab1
9 changed files with 122 additions and 12 deletions

View File

@@ -24,7 +24,7 @@ jobs:
shell: bash shell: bash
run: | run: |
set -euo pipefail set -euo pipefail
version="0.1.2" version="0.1.3"
dotnet publish src/MrTrustLauncher.csproj \ dotnet publish src/MrTrustLauncher.csproj \
--configuration Release \ --configuration Release \
--runtime win-x64 \ --runtime win-x64 \
@@ -38,7 +38,7 @@ jobs:
shell: bash shell: bash
run: | run: |
set -euo pipefail set -euo pipefail
version="0.1.2" version="0.1.3"
package_root="dist/MrTrust-${version}" package_root="dist/MrTrust-${version}"
rm -rf "$package_root" "dist/MrTrust-${version}.zip" rm -rf "$package_root" "dist/MrTrust-${version}.zip"
mkdir -p "$package_root" mkdir -p "$package_root"
@@ -54,8 +54,8 @@ jobs:
- name: Upload release artifact - name: Upload release artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: MrTrust-0.1.2 name: MrTrust-0.1.3
path: dist/MrTrust-0.1.2.zip path: dist/MrTrust-0.1.3.zip
- name: Attach ZIP to Gitea release - name: Attach ZIP to Gitea release
if: github.ref == 'refs/heads/main' if: github.ref == 'refs/heads/main'
@@ -64,9 +64,35 @@ jobs:
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: | run: |
set -euo pipefail set -euo pipefail
version="0.1.2" version="0.1.3"
api="https://git.wilkensxl.de/api/v1/repos/MrSphay/MrTrust" 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_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="$(python3 - <<PY
import json
version = "${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,
}))
PY
)"
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"])')" release_id="$(printf '%s' "$release_json" | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])')"
if [ -z "$release_id" ]; then if [ -z "$release_id" ]; then
echo "Could not resolve release id for v${version}" >&2 echo "Could not resolve release id for v${version}" >&2

View File

@@ -1,5 +1,9 @@
# Changelog # Changelog
## 0.1.3
- Added Ubuntu-runner signing support through `osslsigncode` and PFX secrets.
## 0.1.2 ## 0.1.2
- Made `MrTrust.exe` a standalone user-facing release artifact. - Made `MrTrust.exe` a standalone user-facing release artifact.

View File

@@ -19,6 +19,7 @@ MrTrust does not bypass Microsoft Defender or SmartScreen. Windows can still sca
- `scripts/Install-MrTrust.ps1` installs the public trust certificate for the current user or the local machine. - `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/Uninstall-MrTrust.ps1` removes the MrTrust certificate again.
- `scripts/Sign-MrTrustProject.ps1` signs `.exe`, `.msi`, `.ps1`, and other Authenticode-compatible files. - `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. - `scripts/New-MrTrustRelease.ps1` builds a distributable ZIP package.
- `docs/integration-prompt.md` is a prompt you can paste into other Windows projects. - `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. - `docs/agent-target-integration.md` is the autonomous target-project integration runbook for agents.
@@ -69,7 +70,7 @@ Remove the trust certificate:
Build a user-facing ZIP release: Build a user-facing ZIP release:
```powershell ```powershell
.\scripts\New-MrTrustRelease.ps1 -Version 0.1.2 .\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. 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.

View File

@@ -43,6 +43,8 @@ Apply every item that fits the target project:
- Use the public thumbprint from `mrtrust.integration.json`. - Use the public thumbprint from `mrtrust.integration.json`.
- Only run signing where private signing material is securely available. - Only run signing where private signing material is securely available.
- Do not commit `.pfx`, private keys, passwords, tokens, or signing secrets. - 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. 4. Add verification.
- Verify the target project still builds. - Verify the target project still builds.
@@ -76,6 +78,12 @@ Check a signature:
Get-AuthenticodeSignature .\dist\App.exe | Format-List Status,SignerCertificate,StatusMessage 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 ## Installer Patterns
### Inno Setup ### Inno Setup
@@ -118,6 +126,45 @@ Document that users should run it once before launching signed MrSphay apps if W
## CI Signing Patterns ## 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 ### Gitea Actions On Windows Runner
```yaml ```yaml

View File

@@ -32,10 +32,12 @@ Implementation requirements:
- Only offer LocalMachine installation when the user explicitly chooses an all-users install and the process is elevated. - 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 opens MrTrust again and tells the user to choose "Remove trust". - 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. - 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: - If this project produces an .exe, .msi, .dll, or .cat release artifact on an Ubuntu Gitea runner, sign it with:
.\MrTrust\MrTrust.exe sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B bash ./MrTrust/scripts/Sign-MrTrustProjectLinux.sh <artifact-path>
- Treat the certificate thumbprint as public metadata, but never commit private signing material. - 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. - 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: 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 the target project's user-facing release contains either a link to the MrTrust release ZIP or a bundled copy of `MrTrust.exe`.

View File

@@ -29,8 +29,35 @@
".psd1", ".psd1",
".cat" ".cat"
], ],
"preferredCommand": ".\\MrTrust\\MrTrust.exe sign -Path <artifact-path> -CertificateThumbprint A024A89200469F099EC4A172B4F96F6428AFD41B", "ubuntuRunner": {
"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.", "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." "unsignedBehavior": "Unsigned builds should remain unsigned. MrTrust only makes correctly signed MrSphay artifacts validate after the user has installed trust."
}, },
"targetProjectAgentContract": { "targetProjectAgentContract": {

View File

@@ -24,6 +24,7 @@ $payloadFiles = @(
@{ Path = "scripts\New-MrTrustIcon.ps1"; ResourceName = "MrTrust.Payload.scripts.New-MrTrustIcon.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\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-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\Start-MrTrustGui.ps1"; ResourceName = "MrTrust.Payload.scripts.Start-MrTrustGui.ps1" },
@{ Path = "scripts\Uninstall-MrTrust.ps1"; ResourceName = "MrTrust.Payload.scripts.Uninstall-MrTrust.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\MrTrust.ico"; ResourceName = "MrTrust.Payload.assets.MrTrust.ico" },

View File

@@ -23,6 +23,7 @@ namespace MrTrust
new PayloadFile("scripts.New-MrTrustIcon.ps1", Path.Combine("scripts", "New-MrTrustIcon.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.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-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.Start-MrTrustGui.ps1", Path.Combine("scripts", "Start-MrTrustGui.ps1")),
new PayloadFile("scripts.Uninstall-MrTrust.ps1", Path.Combine("scripts", "Uninstall-MrTrust.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.MrTrust.ico", Path.Combine("assets", "MrTrust.ico")),

View File

@@ -21,6 +21,7 @@
<EmbeddedResource Include="..\scripts\New-MrTrustIcon.ps1" LogicalName="MrTrust.Payload.scripts.New-MrTrustIcon.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\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-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\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="..\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\MrTrust.ico" LogicalName="MrTrust.Payload.assets.MrTrust.ico" />