Skip to content

Commit dde5e1d

Browse files
committed
feat: add support for signed releases
Using SignPath automatic code signing to certify releases on build
1 parent 43e6274 commit dde5e1d

9 files changed

Lines changed: 115 additions & 16 deletions

File tree

.github/workflows/release.yml

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,57 @@ jobs:
3636
echo "version=$version" >> $env:GITHUB_OUTPUT
3737
echo "Version: $version"
3838
39-
- name: Build portable distribution for Scoop
39+
- name: Build portable distribution for Scoop (unsigned)
4040
shell: pwsh
4141
run: ./build-portable.ps1 -Version ${{ steps.version.outputs.version }}
4242

43-
- name: Create GitHub Release with portable ZIP
43+
- name: Upload unsigned portable artifacts
44+
id: upload-portable
45+
uses: actions/upload-artifact@v4
46+
with:
47+
name: unsigned-portable-${{ steps.version.outputs.version }}
48+
path: Symlinker/bin/portable/
49+
50+
- name: Sign portable executable
51+
id: signpath-portable
52+
uses: signpath/github-action-submit-signing-request@v1
53+
with:
54+
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
55+
organization-id: '${{ secrets.SIGNPATH_ORGANIZATION_ID }}'
56+
project-slug: '${{ secrets.SIGNPATH_PROJECT_SLUG }}'
57+
signing-policy-slug: '${{ secrets.SIGNPATH_SIGNING_POLICY_SLUG }}'
58+
artifact-configuration-slug: 'Portable'
59+
github-artifact-id: '${{ steps.upload-portable.outputs.artifact-id }}'
60+
wait-for-completion: true
61+
output-artifact-directory: 'Symlinker/bin/portable-signed'
62+
parameters: |
63+
{
64+
"version": "${{ steps.version.outputs.version }}"
65+
}
66+
67+
- name: Create signed portable ZIP
68+
shell: pwsh
69+
run: |
70+
$version = "${{ steps.version.outputs.version }}"
71+
$zipName = "symlinker-$version-portable.zip"
72+
73+
# Remove unsigned ZIP if exists
74+
if (Test-Path $zipName) {
75+
Remove-Item $zipName -Force
76+
}
77+
78+
# Create ZIP from signed artifacts
79+
Add-Type -AssemblyName System.IO.Compression.FileSystem
80+
[System.IO.Compression.ZipFile]::CreateFromDirectory(
81+
(Resolve-Path "Symlinker/bin/portable-signed").Path,
82+
(Join-Path (Get-Location) $zipName),
83+
[System.IO.Compression.CompressionLevel]::Optimal,
84+
$false
85+
)
86+
87+
Write-Output "Created signed portable ZIP: $zipName"
88+
89+
- name: Create GitHub Release with signed portable ZIP
4490
uses: softprops/action-gh-release@v1
4591
with:
4692
files: symlinker-${{ steps.version.outputs.version }}-portable.zip
@@ -50,6 +96,34 @@ jobs:
5096
env:
5197
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
5298

53-
- name: Run ClickOnce release script
99+
- name: Build ClickOnce package (unsigned)
100+
shell: pwsh
101+
run: ./release.ps1 -OnlyBuild
102+
103+
- name: Upload unsigned ClickOnce artifacts
104+
id: upload-clickonce
105+
uses: actions/upload-artifact@v4
106+
with:
107+
name: unsigned-clickonce-${{ steps.version.outputs.version }}
108+
path: Symlinker/bin/publish/
109+
110+
- name: Submit signing request to SignPath
111+
id: signpath
112+
uses: signpath/github-action-submit-signing-request@v1
113+
with:
114+
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
115+
organization-id: '${{ secrets.SIGNPATH_ORGANIZATION_ID }}'
116+
project-slug: '${{ secrets.SIGNPATH_PROJECT_SLUG }}'
117+
signing-policy-slug: '${{ secrets.SIGNPATH_SIGNING_POLICY_SLUG }}'
118+
artifact-configuration-slug: 'ClickOnce'
119+
github-artifact-id: '${{ steps.upload-clickonce.outputs.artifact-id }}'
120+
wait-for-completion: true
121+
output-artifact-directory: 'signed-clickonce'
122+
parameters: |
123+
{
124+
"version": "${{ steps.version.outputs.version }}"
125+
}
126+
127+
- name: Deploy signed ClickOnce to gh-pages
54128
shell: pwsh
55-
run: ./release.ps1
129+
run: ./release.ps1 -SignedArtifactDir "signed-clickonce"

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1+
## What's Changed
2+
* feat: add support for signed releases by @amd989
3+
* docs: :memo: update readme by @amd989
4+
* chore: add funding usernames by @amd989
5+
16
## What's Changed in 2.0.0
7+
* chore: ♻️ rename project by @amd989
8+
* ci: :construction_worker: add support for scoop.sh by @amd989 in [#27](https://github.com/amd989/Symlinker/pull/27)
9+
* docs: :memo: add changelog with gitcliff by @amd989
210
* ci: 💚 fix click once publish by @amd989
311
* docs: :page_facing_up: add mit license by @amd989 in [#26](https://github.com/amd989/Symlinker/pull/26)
412
* feat: modernize application by @amd989 in [#25](https://github.com/amd989/Symlinker/pull/25)

PRIVACY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,13 @@ See [CHANGELOG.md](CHANGELOG.md)
5555

5656
TODO
5757
----
58-
* Get a real code signing certificate
59-
* Rework the code to be better
58+
* Rework the code to be better
59+
60+
Acknowledgments
61+
---------------
62+
Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
63+
Committers and reviewers: [Contributors](https://github.com/amd989/Symlinker/graphs/contributors)
64+
65+
Privacy Policy
66+
--------------
67+
See [PRIVACY.md](PRIVACY.md)

Symlinker/Properties/PublishProfiles/ClickOnceProfile.pubxml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<Project>
44
<PropertyGroup>
55
<ApplicationRevision>0</ApplicationRevision>
6-
<ApplicationVersion>2.0.0.0</ApplicationVersion>
6+
<ApplicationVersion>2.1.0.0</ApplicationVersion>
77
<BootstrapperEnabled>True</BootstrapperEnabled>
88
<Configuration>Release</Configuration>
99
<CreateWebPageOnPublish>True</CreateWebPageOnPublish>
@@ -33,7 +33,7 @@
3333
</PropertyGroup>
3434
<ItemGroup>
3535
<BootstrapperPackage Include="Microsoft.NetCore.DesktopRuntime.8.0.x64">
36-
<Install>True</Install>
36+
<Install>true</Install>
3737
<ProductName>.NET Desktop Runtime 8.0.18 (x64)</ProductName>
3838
</BootstrapperPackage>
3939
</ItemGroup>

Symlinker/Symlinker.csproj

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,10 @@
33
<TargetFramework>net8.0-windows</TargetFramework>
44
<OutputType>WinExe</OutputType>
55
<RootNamespace>Symlinker</RootNamespace>
6-
<ManifestCertificateThumbprint>1545011842E7D72688AF686E0A94663E3A278CFA</ManifestCertificateThumbprint>
7-
<ManifestKeyFile>cert.pfx</ManifestKeyFile>
86
<GenerateManifests>false</GenerateManifests>
97
<SignManifests>false</SignManifests>
108
<IsWebBootstrapper>true</IsWebBootstrapper>
119
<ApplicationIcon>icon.ico</ApplicationIcon>
12-
<AssemblyOriginatorKeyFile>key.snk</AssemblyOriginatorKeyFile>
1310
<PublishUrl>ftp://ftp.alejandro.com/public_html/alejandro.md/publish/Symlinker/</PublishUrl>
1411
<Install>true</Install>
1512
<InstallFrom>Web</InstallFrom>
@@ -30,8 +27,6 @@
3027
<SuiteName>Symlinker</SuiteName>
3128
<CreateWebPageOnPublish>true</CreateWebPageOnPublish>
3229
<WebPage>publish.htm</WebPage>
33-
<ApplicationRevision>16</ApplicationRevision>
34-
<ApplicationVersion>1.1.2.%2a</ApplicationVersion>
3530
<UseApplicationTrust>false</UseApplicationTrust>
3631
<CreateDesktopShortcut>true</CreateDesktopShortcut>
3732
<PublishWizardCompleted>true</PublishWizardCompleted>
@@ -42,7 +37,7 @@
4237
<TargetZone>LocalIntranet</TargetZone>
4338
<ApplicationManifest>Properties\app.manifest</ApplicationManifest>
4439
<StartupObject>Symlinker.Program</StartupObject>
45-
<Version>2.0.0.0</Version>
40+
<Version>2.1.0.0</Version>
4641
<Description>Symbolic link creator app</Description>
4742
<Copyright>Copyright © Alejandro Mora 2025</Copyright>
4843
<PackageProjectUrl>https://github.com/amd989/Symlinker</PackageProjectUrl>

Symlinker/cert.pfx

-5.59 KB
Binary file not shown.

Symlinker/key.snk

-596 Bytes
Binary file not shown.

release.ps1

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
[CmdletBinding(PositionalBinding=$false)]
44
param (
5-
[switch]$OnlyBuild=$false
5+
[switch]$OnlyBuild=$false,
6+
[string]$SignedArtifactDir=""
67
)
78

89
$appName = "Symlinker"
@@ -64,6 +65,18 @@ if ($OnlyBuild) {
6465
exit
6566
}
6667

68+
# Determine which directory to deploy (signed or unsigned).
69+
$deployDir = $outDir
70+
if ($SignedArtifactDir) {
71+
if (-Not (Test-Path $SignedArtifactDir)) {
72+
throw "Signed artifact directory not found: $SignedArtifactDir"
73+
}
74+
$deployDir = $SignedArtifactDir
75+
Write-Output "Using signed artifacts from: $SignedArtifactDir"
76+
} else {
77+
Write-Output "Using unsigned artifacts from: $outDir"
78+
}
79+
6780
# Clone `gh-pages` branch.
6881
$ghPagesDir = "gh-pages"
6982
if (-Not (Test-Path $ghPagesDir)) {
@@ -84,7 +97,7 @@ try {
8497

8598
# Copy new application files.
8699
Write-Output "Copying new files..."
87-
Copy-Item -Path "../$outDir/Application Files","../$outDir/$appName.application" `
100+
Copy-Item -Path "../$deployDir/Application Files","../$deployDir/$appName.application" `
88101
-Destination . -Recurse
89102

90103
# Stage and commit.

0 commit comments

Comments
 (0)