Skip to content

Commit 9c25757

Browse files
authored
Merge pull request #1 from SignPath/full-sample
Full sample
2 parents 3442268 + a9da584 commit 9c25757

21 files changed

+2927
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This workflow is a demo of how to use the Gihub Actions workflow steps for SignPath. For a complete documentation,
22
# view https://github.com/SignPath/github-actions
33

4-
name: sign-with-signpath
4+
name: build-and-sign
55
run-name: Demo workflow signing with SignPath
66
on:
77
push:
@@ -11,21 +11,29 @@ on:
1111
workflow_dispatch: # Allows you to run this workflow manually from the Actions tab
1212

1313
jobs:
14-
build-and-sign:
14+
build_and_sign:
1515
runs-on: windows-latest
1616
steps:
1717

1818
- name: checkout
1919
uses: actions/checkout@v3
20+
with:
21+
fetch-depth: 0
2022

2123
- name: build
22-
run: "echo \"This is a dummy build step that creates build-output/hello-world.exe\""
24+
run: ./src/Build.ps1
25+
26+
- name: create SBOM
27+
run: ./sbom/Create-SBOM.ps1
28+
29+
- name: package artifacts
30+
run: Compress-Archive -Path .\_BuildResult-unsigned\DemoExample.msi,.\_BuildResult-unsigned\bom.xml -DestinationPath .\_BuildResult-unsigned.zip -Force
2331

2432
- name: upload-unsigned-artifact
2533
uses: actions/upload-artifact@v3
2634
with:
27-
name: "hello-world"
28-
path: "./build-output/hello-world.exe"
35+
name: "demo-application-unsigned"
36+
path: "./_BuildResult-unsigned.zip"
2937
if-no-files-found: error
3038

3139
- name: sign
@@ -34,15 +42,18 @@ jobs:
3442
github-token: '${{ secrets.GITHUB_TOKEN }}'
3543
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
3644
organization-id: '${{ vars.SIGNPATH_ORGANIZATION_ID }}'
37-
project-slug: 'Executable'
38-
signing-policy-slug: 'test-signing'
39-
artifact-configuration-slug: 'initial'
40-
artifact-name: "hello-world"
41-
signed-artifact-destination-path: "build-output/hello-world-signed.exe"
45+
project-slug: 'Demo_Application'
46+
signing-policy-slug: ${{ github.ref == 'refs/heads/main' && 'release-signing' || 'test-signing' }}
47+
artifact-configuration-slug: 'v1'
48+
artifact-name: "demo-application-unsigned"
49+
signed-artifact-destination-path: "_BuildResult-signed.zip"
50+
51+
- name: decompress signed artifact
52+
run: Expand-Archive -Path .\_BuildResult-signed.zip -DestinationPath _BuildResult-signed
4253

4354
- name: upload-signed-artifact
4455
uses: actions/upload-artifact@v3
4556
with:
46-
name: "hello-world-signed"
47-
path: "./build-output/hello-world-signed.exe"
57+
name: "demo-application-signed"
58+
path: "_BuildResult-signed"
4859
if-no-files-found: error

.gitignore

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
.store
2+
.vs
3+
bin
4+
node_modules
5+
obj
6+
src/wwwroot/js
7+
_temp
8+
bom.xml
9+
verification
10+
_BuildResult*

build-output/hello-world.exe

-200 KB
Binary file not shown.

build-output/sample.dll

-4 KB
Binary file not shown.

sbom/Create-SBOM.ps1

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# PowerShell script that will create the SBOM file
2+
3+
# 1 Preparation
4+
# 1.a general settings
5+
$ErrorActionPreference = "Stop"
6+
function Fail-On-Error {
7+
param(
8+
$description
9+
)
10+
11+
if ($LASTEXITCODE -ne 0) {
12+
Write-Host "Executing '$description' failed with exit code $LASTEXITCODE."
13+
exit 1
14+
}
15+
}
16+
17+
# 1.b Create a temporary folder
18+
$tempPath = Join-Path $PSScriptRoot "_temp"
19+
New-Item -ItemType Directory -Force -Path $tempPath
20+
21+
# 2 Create NuGet SBOM
22+
# 2.a install the .Net tool
23+
dotnet tool install cyclonedx --tool-path $tempPath
24+
25+
# 2.b create nuget bom
26+
$cyclonDxToolPath = Join-Path $tempPath "dotnet-CycloneDX.exe"
27+
& "${cyclonDxToolPath}" --output "${tempPath}" -f "nuget.bom.xml" --exclude-dev src\DemoExample.csproj
28+
29+
# 3 Create NPM SBOM
30+
$packageJsonPath = Join-Path $PSScriptRoot ".." "src" "package.json"
31+
$npmBomPath = Join-Path $tempPath "npm.bom.xml"
32+
33+
# 3.a make sure the package is installed
34+
Push-Location (Join-Path $PSScriptRoot ".." "src")
35+
npm install --omit=optional
36+
Fail-On-Error "npm install"
37+
Pop-Location
38+
39+
# 3.b. create actual NPM SBOM
40+
npx --yes "@cyclonedx/cyclonedx-npm" "${packageJsonPath}" --omit dev --output-format XML --output-file "${npmBomPath}"
41+
Fail-On-Error "cyclonedx-npm"
42+
43+
# 4 Merge SBOMs
44+
# 4.a download cyclonedx-cli.exe
45+
$cycloneDxCliToolPath = Join-Path $tempPath "cyclonedx-cli.exe"
46+
if (-Not (Test-Path $cycloneDxCliToolPath)) {
47+
$releases = Invoke-RestMethod -Uri "https://api.github.com/repos/CycloneDX/cyclonedx-cli/releases"
48+
$asset = ($releases | Select-Object -First 1).assets | ? { $_.name -eq "cyclonedx-win-x64.exe" }
49+
Invoke-WebRequest -Uri ($asset.browser_download_url) -OutFile "${cycloneDxCliToolPath}"
50+
}
51+
52+
# 4.b merge both SBOMs into a final one
53+
$nugetBomPath = Join-Path $tempPath "nuget.bom.xml"
54+
$finalBomPath = Join-Path $PSScriptRoot ".." "_BuildResult-unsigned" "bom.xml"
55+
& "${cycloneDxCliToolPath}" merge --input-files "${npmBomPath}" "${nugetBomPath}" --output-format "xml" --output-file "${finalBomPath}" --group "com.SignPath.demos" --name "SignPath Demo Application" --version "1.0.0"

sbom/Verify-SBOM.ps1

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
New-Item -ItemType Directory -Force -Path verification
2+
3+
# Get signing request details
4+
$signingRequestDetails = Invoke-RestMethod -Headers @{ Authorization = "Bearer ${env:SIGNPATH_CI_USER_TOKEN}" } `
5+
"https://app.signpath.io/Api/v1/${env:SIGNPATH_ORGANIZATION_ID}/SigningRequests/${env:SIGNPATH_SIGNING_REQUEST_ID}"
6+
# Get project details
7+
$projectDetails = Invoke-RestMethod -Headers @{ Authorization = "Bearer ${env:SIGNPATH_CI_USER_TOKEN}" } `
8+
"https://app.signpath.io/Api/v1-pre/${env:SIGNPATH_ORGANIZATION_ID}/Projects/$($signingRequestDetails.projectSlug)"
9+
# Extract signing policy from project details
10+
$signingPolicyDetails = $projectDetails.signingPolicies `
11+
| Where-Object {$_.metadata.slug -eq $signingRequestDetails.signingPolicySlug} `
12+
| Select -First 1
13+
14+
# Download certificate
15+
Invoke-WebRequest -Headers @{ Authorization = "Bearer ${env:SIGNPATH_CI_USER_TOKEN}" } `
16+
"$($signingPolicyDetails.certificateUrl)/X509Certificate" -OutFile verification/certificate.cer
17+
# Extract public key
18+
openssl x509 -pubkey -noout -in verification/certificate.cer -inform DER -out verification/public_key.pem
19+
20+
# Download verify tool
21+
$releases = Invoke-RestMethod -Uri "https://api.github.com/repos/signpath/cyclonedx-cli/releases"
22+
$asset = ($releases | Select-Object -First 1).assets | ? { $_.name -eq "cyclonedx-win-x64.exe" }
23+
Invoke-WebRequest -Uri ($asset.browser_download_url) -OutFile "verification/cyclonedx-cli.exe"
24+
25+
# Actual verification
26+
& ./verification/cyclonedx-cli.exe verify all ./_BuildResult-signed/bom.xml --key-file ./verification/public_key.pem

src/Build.ps1

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# build .Net application
2+
dotnet build --configuration Release src/DemoExample.csproj
3+
4+
# build MSI installer
5+
Copy-Item .\src\installer\description.wxs .\src\bin\Release\net7.0\description.wxs -Force
6+
Push-Location .\src\bin\Release\net7.0
7+
& "${env:WIX}bin\candle.exe" description.wxs
8+
& "${env:WIX}bin\light.exe" description.wixobj -out DemoExample.msi
9+
Pop-Location
10+
11+
# copy build to output directory
12+
New-Item -ItemType Directory -Path "_BuildResult-unsigned"
13+
Copy-Item src\bin\Release\net7.0\DemoExample.msi _BuildResult-unsigned\DemoExample.msi

src/DemoExample.csproj

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net7.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
11+
</ItemGroup>
12+
13+
<Target Name="BuildClientAssets" BeforeTargets="Build">
14+
<Exec Command="npm install" />
15+
<Exec Command="npm run build" />
16+
</Target>
17+
18+
</Project>

src/Pages/Index.cshtml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
@page
2+
3+
<div>
4+
<svg xmlns="http://www.w3.org/2000/svg" id="logo" viewbox="0,0,620.2,124.6" width="620.20001" height="124.6">
5+
<title>SignPath GmbH</title>
6+
<g id="g3684" transform="translate(-27.1 -22.8)">
7+
<path id="path3682" fill="#fff" d="M133.4 22.8H62.6L27.1 84.2l35.4 61.4h70.9l35.4-61.4zm1.7 68.6c-.7 1.6-2.3 2.6-4.1 2.6H94.2c-2.5 0-4.5-2-4.5-4.5s2-4.5 4.5-4.5H121l-10.5-11.9a4.43 4.43 0 0 1 0-5.9L121 55.3H76.7v71.2c0 2.5-2 4.5-4.5 4.5s-4.5-2-4.5-4.5V41.7c0-2.5 2-4.5 4.5-4.5s4.5 2 4.5 4.5v4.6H131c1.8 0 3.4 1 4.1 2.6.7 1.6.4 3.5-.7 4.8L120 70.1l14.4 16.4c1.1 1.4 1.4 3.3.7 4.9z"/>
8+
</g>
9+
<g id="Inhalt" transform="translate(-27.1 -22.8)">
10+
<g id="g3705">
11+
<g id="g3703">
12+
<path id="path3687" stroke="#fff" stroke-width="3" fill="none" d="M208.4 104c7.3 5.8 16 9.2 25.3 9.2 9.1 0 15.5-3.2 15.5-10.4 0-6.2-4-8.7-11.2-11.4l-11.6-4.2c-10.6-3.9-18.7-9.6-18.7-22.7 0-14 12.2-21.7 26.9-21.7 9 0 17.1 2.3 23.5 6.5v13.9c-6.6-5.1-13.9-8.6-23.2-8.6-8.1 0-14 3.1-14 9.6 0 5.8 3.8 8.2 10.4 10.5l12.9 4.7c12.5 4.5 18.2 11.6 18.2 23.1 0 14.5-12.3 22.6-28.6 22.6-10.6 0-19.7-3.1-25.3-7z"/>
13+
<path id="path3689" stroke="#fff" stroke-width="3" fill="none" d="M280.5 56.7c-4.3 0-8.1-3.5-8.1-7.9s3.8-7.9 8.1-7.9 8.1 3.5 8.1 7.9-3.8 7.9-8.1 7.9zm6.5 67.2h-13V66.2h13z"/>
14+
<path id="path3691" stroke="#fff" stroke-width="3" fill="none" d="M339.1 118.2c-2.6 3.1-8.1 6-14.5 6-17 0-26.6-14.2-26.6-29.6 0-15.4 9.6-29.6 26.6-29.6 6.5 0 11.9 2.9 14.5 6v-4.7h13v52.9c0 21-16 28.2-29.6 28.2-7.7 0-14.5-1.9-19.2-4.9v-13.8c6 5.3 11.9 7.3 19.2 7.3 9.2 0 16.6-5.5 16.6-15.8zm0-35c-2.2-3.9-6.9-6.9-12.3-6.9-10 0-15.7 7.7-15.7 18.2s5.7 18.2 15.7 18.2c5.5 0 10.1-3 12.3-6.9z"/>
15+
<path id="path3693" stroke="#fff" stroke-width="3" fill="none" d="M367 66.2h13v5.5c3.1-3.6 8.8-6.8 15.6-6.8 13.1 0 20.4 8.7 20.4 21.4v37.5h-13V88.6c0-7.1-3.5-11.8-10.9-11.8-5.6 0-10.6 3.5-12.1 9.2v37.9h-13z"/>
16+
<path id="path3695" stroke="#fff" stroke-width="3" fill="none" d="M445 94.1v29.7h-13.5V44.1h30.8c16.5 0 27.3 8.6 27.3 25.1 0 16.2-10.8 24.9-27.3 24.9zm17.1-38.3h-17v26.6h17c9.4 0 14.2-5.6 14.2-13.2-.1-7.9-4.9-13.4-14.2-13.4z"/>
17+
<path id="path3697" stroke="#fff" stroke-width="3" fill="none" d="M530.1 87c0-6.5-5.2-10.3-13.2-10.3-6.2 0-11.3 1.9-16 5.1V69.9c3.8-2.7 11-4.9 18.3-4.9 14.9 0 23.4 8.1 23.4 21.2V124h-12.5v-3.2c-1.9 1.9-7.7 4.3-14.2 4.3-11.8 0-21.6-7-21.6-18.8 0-10.9 9.7-18.6 22.5-18.6 5.2 0 10.9 1.8 13.2 3.5zm0 16.8c-1.4-3.6-6.5-5.8-11.7-5.8-5.8 0-11.9 2.5-11.9 8.2 0 5.8 6.1 8.3 11.9 8.3 5.2 0 10.3-2.2 11.7-5.8z"/>
18+
<path id="path3699" stroke="#fff" stroke-width="3" fill="none" d="M575.8 123.9h-13V77h-11.7V66.2h11.7V50.8h13v15.5h13V77h-13z"/>
19+
<path id="path3701" stroke="#fff" stroke-width="3" fill="none" d="M598.3 39.5h13v32.2c3.1-3.6 8.8-6.8 15.6-6.8 13.1 0 20.4 8.7 20.4 21.4v37.5h-13V88.6c0-7.1-3.5-11.8-10.9-11.8-5.6 0-10.7 3.5-12.1 9.2v37.9h-13z"/>
20+
</g>
21+
</g>
22+
</g>
23+
</svg>
24+
<span id='slogan'></span>
25+
</div>

src/Pages/Index.cshtml.cs

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Microsoft.AspNetCore.Mvc;
2+
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
4+
namespace DemoExample.Pages;
5+
6+
public class IndexModel : PageModel
7+
{
8+
private readonly ILogger<IndexModel> _logger;
9+
10+
public IndexModel(ILogger<IndexModel> logger)
11+
{
12+
_logger = logger;
13+
}
14+
15+
public void OnGet()
16+
{
17+
_logger.LogInformation("Home page was called");
18+
}
19+
}

src/Pages/Shared/_Layout.cshtml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>SignPath Demo Example App</title>
7+
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
8+
<script src="~/js/main.js"></script>
9+
</head>
10+
<body>
11+
<div>
12+
<main role="main">
13+
@RenderBody()
14+
</main>
15+
</div>
16+
</body>
17+
</html>

src/Pages/_ViewImports.cshtml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@using DemoExample
2+
@namespace DemoExample.Pages
3+
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

src/Pages/_ViewStart.cshtml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@{
2+
Layout = "_Layout";
3+
}

src/Program.cs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using Serilog;
2+
3+
var builder = WebApplication.CreateBuilder(args);
4+
5+
builder.Host.UseSerilog((context, configuration) => configuration.ReadFrom.Configuration(context.Configuration));
6+
7+
// Add services to the container.
8+
builder.Services.AddRazorPages();
9+
10+
var app = builder.Build();
11+
12+
// Configure the HTTP request pipeline.
13+
if (!app.Environment.IsDevelopment())
14+
{
15+
app.UseExceptionHandler("/Error");
16+
}
17+
18+
app.UseSerilogRequestLogging();
19+
20+
app.UseStaticFiles();
21+
22+
app.UseRouting();
23+
24+
app.UseAuthorization();
25+
26+
app.MapRazorPages();
27+
28+
app.Run();

src/appsettings.json

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"Logging": {
3+
"LogLevel": {
4+
"Default": "Information",
5+
"Microsoft.AspNetCore": "Warning"
6+
}
7+
},
8+
"AllowedHosts": "*",
9+
"Serilog": {
10+
"Using": [ "Serilog.Sinks.File", "Serilog.Sinks.Console" ],
11+
"MinimumLevel": {
12+
"Default": "Information",
13+
"Override": {
14+
"Microsoft": "Warning",
15+
"System": "Warning"
16+
}
17+
},
18+
"WriteTo": [
19+
{
20+
"Name": "Console"
21+
},
22+
{
23+
"Name": "File",
24+
"Args": {
25+
"path": "/logs/log-.txt",
26+
"rollOnFileSizeLimit": true,
27+
"formatter": "Serilog.Formatting.Compact.CompactJsonFormatter,Serilog.Formatting.Compact",
28+
"rollingInterval": "Day"
29+
}
30+
}
31+
],
32+
"Enrich": [ "FromLogContext", "WithThreadId", "WithMachineName" ]
33+
}
34+
}

src/index.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Vivus from 'vivus';
2+
import Typed from 'typed.js';
3+
4+
document.addEventListener('DOMContentLoaded', function() {
5+
new Vivus('logo', {duration: 100} );
6+
7+
new Typed('#slogan', {
8+
strings: ['Built. Signed. Delivered.'],
9+
typeSpeed: 50,
10+
showCursor: false,
11+
autoInsertCss: false
12+
});
13+
});

0 commit comments

Comments
 (0)