## Move editor under `frontend/editor/`
Pure restructure: `frontend/` becomes the workspace, `frontend/editor/`
holds
the PDF editor. 1775 file renames + 40 wiring edits. No logic changes.
### Why
`frontend/` is currently the editor — its `src/`, `public/`,
`src-tauri/`,
config files all sit at the root. Promoting `frontend/` to a
workspace and putting the editor in a sibling folder leaves room for
future
apps to drop in alongside it, sharing one `package.json` /
`node_modules` /
lint config / Storybook.
### What moves
frontend/
├── editor/ ← NEW: everything editor-specific
│ ├── src/ ← was frontend/src/
│ ├── public/ ← was frontend/public/
│ ├── src-tauri/ ← was frontend/src-tauri/
│ ├── index.html, vite.config.ts, vitest.config.ts, playwright.config.ts
│ ├── tsconfig*.json, tailwind.config.js, postcss.config.js
│ ├── scripts/
│ ├── .env, .env.desktop, .env.saas
│ └── DeveloperGuide.md
├── package.json, package-lock.json, node_modules/ ← workspace install
├── eslint.config.mjs, .prettierrc, .prettierignore ← shared tooling
├── .gitignore
└── README.md
### Wiring edits (40 files)
- `.taskfiles/frontend.yml`, `desktop.yml`, `e2e.yml`
- `build.gradle`, `app/core/build.gradle`
- `eslint.config.mjs`, `frontend/package.json`, `.gitignore`,
`.prettierignore`
- `docker/frontend/Dockerfile`
- 8 `.github/workflows/*.yml`, plus `.github/dependabot.yml`,
`.github/config/.files.yaml`, `.github/labeler-config-srvaroa.yml`
- `scripts/translations/**`
- Docs: `AGENTS.md`, `CLAUDE.md`, `ADDING_TOOLS.md`,
`DeveloperGuide.md`,
`WINDOWS_SIGNING.md`, `devGuide/HowToAddNewLanguage.md`,
`frontend/README.md`,
`frontend/editor/DeveloperGuide.md`
Plus 3 renamed + edited: `editor/vite.config.ts` (env path +
node_modules
walk-up), `editor/scripts/setup-env.mts` (renamed from `.ts` for
`import.meta.url`), `editor/scripts/build-provisioner.mjs` (resolve
src-tauri
relative to script).
### Verification
| Check | Result |
|---|---|
| `task frontend:typecheck:all` (6 variants) | exit 0 |
| `task frontend:lint` (eslint + dpdm) | exit 0 |
| `task frontend:format:check` | exit 0 |
| `task frontend:test` | 657 tests pass, 50 files |
| `task frontend:build:{core,proprietary,saas,desktop,prototypes}` | all
green |
| `task desktop:build` | full Tauri pipeline →
`Stirling-PDF_2.11.0_x64_en-US.msi` |
| `playwright test --list --project=stubbed` | 172 tests discovered |
`task desktop:build` exercises the heaviest path — Rust + WiX + MSI
bundle
against the moved `editor/src-tauri/`. If anything in the restructure
was
wrong it wouldn't have built.
### Test plan
- [ ] `frontend-validation.yml` green
- [ ] `e2e-stubbed.yml` green
- [ ] `tauri-build.yml` green on at least one platform
- [ ] `check_toml.yml` runs on a translation-touching PR
---------
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
7.6 KiB
Windows Code Signing Setup Guide
This guide explains how to set up Windows code signing for Stirling-PDF desktop application builds.
Overview
Windows code signing is essential for:
- Preventing Windows SmartScreen warnings
- Building trust with users
- Enabling Microsoft Store distribution
- Professional application distribution
Certificate Types
OV Certificate (Organization Validated)
- More affordable option
- Requires business verification
- May trigger SmartScreen warnings initially until reputation builds
- Suitable for most independent software vendors
EV Certificate (Extended Validation)
- Premium option with immediate SmartScreen reputation
- Requires hardware security module (HSM) or cloud-based signing
- Higher cost but provides immediate trust
- Required since June 2023 for new certificates
Obtaining a Certificate
Certificate Authorities
Popular certificate authorities for Windows code signing:
- DigiCert
- Sectigo (formerly Comodo)
- GlobalSign
- SSL.com
Certificate Format
You'll receive a certificate in one of these formats:
.pfxor.p12(preferred - contains both certificate and private key).cer+ private key (needs conversion to .pfx)
Converting to PFX (if needed)
If you have separate certificate and private key files:
openssl pkcs12 -export -out certificate.pfx -inkey private-key.key -in certificate.cer
Setting Up GitHub Secrets
Required Secrets
Navigate to your GitHub repository → Settings → Secrets and variables → Actions
Add the following secrets:
1. WINDOWS_CERTIFICATE
- Description: Base64-encoded .pfx certificate file
- How to create:
On macOS/Linux:
base64 -i certificate.pfx | pbcopy # Copies to clipboard
On Windows (PowerShell):
[Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.pfx")) | Set-Clipboard
Paste the entire base64 string into the GitHub secret.
2. WINDOWS_CERTIFICATE_PASSWORD
- Description: Password for the .pfx certificate
- Value: The password you set when creating/exporting the .pfx file
Optional Secrets for Tauri Updater
If you're using Tauri's built-in updater feature:
TAURI_SIGNING_PRIVATE_KEY
- Generated using Tauri CLI:
npm run tauri signer generate - Used for update package verification
TAURI_SIGNING_PRIVATE_KEY_PASSWORD
- Password for the Tauri signing key
Configuration Files
1. Tauri Configuration (frontend/editor/src-tauri/tauri.conf.json)
The Windows signing configuration is already set up:
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": "http://timestamp.digicert.com"
}
Configuration Options:
certificateThumbprint: Automatically extracted from imported certificate (leave asnull)digestAlgorithm: Hashing algorithm -sha256is recommendedtimestampUrl: Timestamp server to prove signing time (survives certificate expiration)
Alternative Timestamp Servers:
- DigiCert:
http://timestamp.digicert.com - Sectigo:
http://timestamp.sectigo.com - GlobalSign:
http://timestamp.globalsign.com
2. GitHub Workflow (.github/workflows/tauri-build.yml)
The workflow includes three Windows signing steps:
- Import Certificate: Decodes and imports the .pfx certificate into Windows certificate store
- Build Tauri App: Builds and signs the application using the imported certificate
- Verify Signature: Validates that both .exe and .msi files are properly signed
Testing the Setup
1. Local Testing (Windows Only)
Before pushing to GitHub, test locally:
# Set environment variables
$env:WINDOWS_CERTIFICATE = [Convert]::ToBase64String([IO.File]::ReadAllBytes("certificate.pfx"))
$env:WINDOWS_CERTIFICATE_PASSWORD = "your-certificate-password"
# Build the application
cd frontend
npm run tauri build
# Verify the signature
Get-AuthenticodeSignature "./src-tauri/target/release/bundle/msi/Stirling-PDF_*.msi"
2. GitHub Actions Testing
- Push your changes to a branch
- Manually trigger the workflow:
- Go to Actions → Build Tauri Applications
- Click "Run workflow"
- Select "windows" platform
- Check the build logs for:
- ✅ Certificate import success
- ✅ Build completion
- ✅ Signature verification
3. Verifying Signed Binaries
After downloading the built artifacts:
Windows (PowerShell):
Get-AuthenticodeSignature "Stirling-PDF-windows-x86_64.exe"
Get-AuthenticodeSignature "Stirling-PDF-windows-x86_64.msi"
Look for:
- Status:
Valid - Signer: Your organization name
- Timestamp: Recent date/time
Windows (GUI):
- Right-click the .exe or .msi file
- Select "Properties"
- Go to "Digital Signatures" tab
- Verify signature details
Troubleshooting
"HashMismatch" Status
- Certificate doesn't match the binary
- Possible file corruption during download
- Re-download and verify
"NotSigned" Status
- Certificate wasn't imported correctly
- Check GitHub secrets are set correctly
- Verify base64 encoding is complete (no truncation)
"UnknownError" Status
- Timestamp server unreachable
- Try alternative timestamp URL in tauri.conf.json
- Check network connectivity in GitHub Actions
SmartScreen Still Shows Warnings
- Normal for OV certificates initially
- Reputation builds over time with user downloads
- Consider EV certificate for immediate reputation
Certificate Not Found During Build
- Verify
WINDOWS_CERTIFICATEsecret is set - Check base64 encoding is correct (no extra whitespace)
- Ensure password is correct
Security Best Practices
-
Never commit certificates to version control
- Keep .pfx files secure and backed up
- Use GitHub secrets for CI/CD
-
Rotate certificates before expiration
- Set calendar reminders
- Update GitHub secrets with new certificate
-
Use strong passwords
- Certificate password should be complex
- Store securely (password manager)
-
Monitor certificate usage
- Review GitHub Actions logs
- Set up notifications for failed builds
-
Limit access to secrets
- Only repository admins should access secrets
- Audit secret access regularly
Certificate Lifecycle
Before Expiration
- Obtain new certificate from CA (typically annual renewal)
- Convert to .pfx format if needed
- Update
WINDOWS_CERTIFICATEsecret with new base64-encoded certificate - Update
WINDOWS_CERTIFICATE_PASSWORDif password changed - Test build to verify new certificate works
Expired Certificates
- Signed binaries remain valid (timestamp proves signing time)
- New builds will fail until certificate is renewed
- Users can still install previously signed versions
Cost Considerations
Certificate Costs (Annual, as of 2024)
- OV Certificate: $100-400/year
- EV Certificate: $400-1000/year
Choosing the Right Certificate
- Open source / early stage: Start with OV
- Commercial / enterprise: Consider EV for better trust
- Microsoft Store: EV certificate required
Additional Resources
- Tauri Windows Signing Documentation
- Microsoft Code Signing Overview
- DigiCert Code Signing Guide
- Windows SmartScreen FAQ
Support
If you encounter issues with Windows code signing:
- Check GitHub Actions logs for detailed error messages
- Verify all secrets are set correctly
- Test certificate locally first (Windows environment required)
- Open an issue in the repository with relevant logs (remove sensitive data)