From a93af6e7335480b89d10c78b4a3e97286e8436e4 Mon Sep 17 00:00:00 2001
From: Brett Hazen <2651260+bhazen@users.noreply.github.com>
Date: Mon, 3 Mar 2025 15:44:37 -0600
Subject: [PATCH 1/4] Revert change which was causing cookies to be re-issued
unnecessarily with wrong expiry
---
src/IdentityServer/Services/Default/DefaultUserSession.cs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/src/IdentityServer/Services/Default/DefaultUserSession.cs b/src/IdentityServer/Services/Default/DefaultUserSession.cs
index 83231296d..50d02a561 100644
--- a/src/IdentityServer/Services/Default/DefaultUserSession.cs
+++ b/src/IdentityServer/Services/Default/DefaultUserSession.cs
@@ -310,8 +310,12 @@ public class DefaultUserSession : IUserSession
await AuthenticateAsync();
if (Properties != null)
{
- Properties.AddClientId(clientId);
- await UpdateSessionCookie();
+ var clientIds = Properties.GetClientList();
+ if (!clientIds.Contains(clientId))
+ {
+ Properties.AddClientId(clientId);
+ await UpdateSessionCookie();
+ }
}
}
From 156e31a11b579f804494408110b6ebb9b65bcf70 Mon Sep 17 00:00:00 2001
From: Brett Hazen <2651260+bhazen@users.noreply.github.com>
Date: Tue, 4 Mar 2025 13:32:05 -0600
Subject: [PATCH 2/4] Backported workflow changes from main
---
.github/workflow-gen/Program.cs | 538 ++++++++++++++++++
.../Properties/launchSettings.json | 8 +
.github/workflow-gen/workflow-gen.csproj | 17 +
.github/workflows/identity-server-ci.yml | 106 ++--
.github/workflows/identity-server-release.yml | 118 ++++
5 files changed, 750 insertions(+), 37 deletions(-)
create mode 100644 .github/workflow-gen/Program.cs
create mode 100644 .github/workflow-gen/Properties/launchSettings.json
create mode 100644 .github/workflow-gen/workflow-gen.csproj
create mode 100644 .github/workflows/identity-server-release.yml
diff --git a/.github/workflow-gen/Program.cs b/.github/workflow-gen/Program.cs
new file mode 100644
index 000000000..ed0f5ee62
--- /dev/null
+++ b/.github/workflow-gen/Program.cs
@@ -0,0 +1,538 @@
+// Copyright (c) Duende Software. All rights reserved.
+// Licensed under the Apache License, Version 2.0.
+
+using Logicality.GitHub.Actions.Workflow;
+using static GitHubContexts;
+
+var contexts = Instance;
+
+{
+ Product identityServer = new("identity-server", "Duende.IdentityServer.sln", "is");
+ GenerateIdentityServerWorkflow(identityServer);
+ GenerateIdentityServerReleaseWorkflow(identityServer);
+ // GenerateCodeQlWorkflow(identityServer, "38 15 * * 0");
+}
+
+void GenerateIdentityServerWorkflow(Product product)
+{
+ var workflow = new Workflow($"{product.Name}/ci");
+ var paths = new[]
+ {
+ $".github/workflows/{product.Name}-**",
+ $"{product.Name}/**",
+ "Directory.Packages.props"
+ };
+
+ workflow.On
+ .WorkflowDispatch();
+ workflow.On
+ .Push()
+ .Paths(paths);
+ workflow.On
+ .PullRequest()
+ .Paths(paths);
+
+ workflow.EnvDefaults();
+
+ var job = workflow
+ .Job("build")
+ .RunEitherOnBranchOrAsPR()
+ .Name("Build")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Defaults().Run("bash", ".")
+ .Job;
+
+ job.Permissions(
+ actions: Permission.Read,
+ contents: Permission.Read,
+ checks: Permission.Write,
+ packages: Permission.Write);
+
+ job.TimeoutMinutes(15);
+
+ job.Step()
+ .ActionsCheckout();
+
+ job.StepSetupDotNet();
+
+ job.StepBuild(product.Solution);
+
+ job.StepTest(product.Solution);
+
+ job.StepToolRestore();
+
+ job.StepPack(product.Solution);
+
+ job.StepSign();
+
+ job.StepPushToGithub(contexts);
+
+ job.StepUploadArtifacts(product.Name);
+
+ var fileName = $"{product.Name}-ci";
+ WriteWorkflow(workflow, fileName);
+}
+void GenerateIdentityServerReleaseWorkflow(Product product)
+{
+ var workflow = new Workflow($"{product.Name}/release");
+
+ workflow.On
+ .WorkflowDispatch()
+ .InputVersionBranchAndTagOverride();
+
+ workflow.EnvDefaults();
+
+ var job = workflow
+ .Job("tag")
+ .Name("Tag and Pack")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Permissions(contents: Permission.Write, packages: Permission.Write)
+ .Defaults().Run("bash", ".").Job;
+
+ job.Step()
+ .ActionsCheckout();
+
+ job.StepGitCheckoutCustomBranch();
+ job.StepGitConfig();
+ job.StepGitRemoveExistingTagIfConfigured(product, contexts);
+ job.StepGitPushTag(product, contexts);
+
+ job.StepSetupDotNet();
+
+ job.Step()
+ .Name("Git tag")
+ .Run($@"git config --global user.email ""github-bot@duendesoftware.com""
+git config --global user.name ""Duende Software GitHub Bot""
+git tag -a {product.TagPrefix}-{contexts.Event.Input.Version} -m ""Release v{contexts.Event.Input.Version}""
+git push origin {product.TagPrefix}-{contexts.Event.Input.Version}");
+
+ job.StepPack(product.Solution);
+
+ job.StepToolRestore();
+
+ job.StepSign(always: true);
+
+ job.StepPushToGithub(contexts, pushAlways: true);
+
+ job.StepUploadArtifacts(product.Name, uploadAlways: true);
+
+ var publishJob = workflow.Job("publish")
+ .Name("Publish to nuget.org")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Needs("tag")
+ .Environment("nuget.org", "");
+
+ publishJob.Step()
+ .Uses("actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16") // 4.1.8
+ .With(("name", "artifacts"), ("path", "artifacts"));
+
+ publishJob.StepSetupDotNet();
+
+ publishJob.Step()
+ .Name("List files")
+ .Shell("bash")
+ .Run("tree");
+
+ publishJob.StepPushToNuget(pushAlways: true);
+
+ var fileName = $"{product.Name}-release";
+ WriteWorkflow(workflow, fileName);
+}
+
+#pragma warning disable CS8321 // Local function is declared but never used
+void GenerateCodeQlWorkflow(Product system, string cronSchedule)
+#pragma warning restore CS8321 // Local function is declared but never used
+{
+ var workflow = new Workflow($"{system.Name}/codeql");
+ var branches = new[] { "main" };
+ var paths = new[] { $"{system.Name}/**" };
+
+ workflow.On
+ .WorkflowDispatch();
+ workflow.On
+ .Push()
+ .Branches(branches)
+ .Paths(paths);
+ workflow.On
+ .PullRequest()
+ .Paths(paths);
+ workflow.On
+ .Schedule(cronSchedule);
+
+ var job = workflow
+ .Job("analyze")
+ .Name("Analyze")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Defaults().Run("bash", ".")
+ .Job;
+
+ job.Permissions(
+ actions: Permission.Read,
+ contents: Permission.Read,
+ securityEvents: Permission.Write);
+
+ job.Step()
+ .ActionsCheckout();
+
+ job.StepInitializeCodeQl();
+
+ job.StepSetupDotNet();
+
+ job.StepBuild(system.Solution);
+
+ job.StepPerformCodeQlAnalysis();
+
+ var fileName = $"{system.Name}-codeql-analysis";
+ WriteWorkflow(workflow, fileName);
+}
+
+#pragma warning disable CS8321 // Local function is declared but never used
+void GenerateTemplatesReleaseWorkflow(Product product)
+#pragma warning restore CS8321 // Local function is declared but never used
+{
+ var workflow = new Workflow($"{product.Name}/release");
+
+ workflow.On
+ .WorkflowDispatch()
+ .Inputs(new StringInput("version", "Version in format X.Y.Z or X.Y.Z-preview.", true, "0.0.0"));
+
+ workflow.EnvDefaults();
+
+ var job = workflow
+ .Job("tag")
+ .Name("Tag and Pack")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Permissions(contents: Permission.Write, packages: Permission.Write)
+ .Defaults().Run("bash", product.Name).Job;
+
+ job.Step()
+ .ActionsCheckout();
+
+ job.StepSetupDotNet();
+
+ job.StepGitCheckoutCustomBranch();
+ job.StepGitConfig();
+ job.StepGitRemoveExistingTagIfConfigured(product, contexts);
+ job.StepGitPushTag(product, contexts);
+
+ job.Step()
+ .Name("build templates")
+ .Run("dotnet run --project build");
+
+ job.StepToolRestore();
+
+ job.StepSign(always: true);
+
+ job.StepPushToGithub(contexts, pushAlways: true);
+
+ job.StepUploadArtifacts(product.Name, uploadAlways: true);
+
+ var publishJob = workflow.Job("publish")
+ .Name("Publish to nuget.org")
+ .RunsOn(GitHubHostedRunners.UbuntuLatest)
+ .Needs("tag")
+ .Environment("nuget.org", "");
+
+ publishJob.Step()
+ .Uses("actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16") // 4.1.8
+ .With(("name", "artifacts"), ("path", "artifacts"));
+
+ publishJob.StepSetupDotNet();
+
+ publishJob.Step()
+ .Name("List files")
+ .Shell("bash")
+ .Run("tree");
+
+ publishJob.StepPushToNuget(pushAlways: true);
+
+ var fileName = $"{product.Name}-release";
+ WriteWorkflow(workflow, fileName);
+}
+
+void WriteWorkflow(Workflow workflow, string fileName)
+{
+ var filePath = $"../workflows/{fileName}.yml";
+ workflow.WriteYaml(filePath);
+ Console.WriteLine($"Wrote workflow to {filePath}");
+}
+
+record Product(string Name, string Solution, string TagPrefix)
+{
+}
+
+public static class StepExtensions
+{
+ public static void EnvDefaults(this Workflow workflow)
+ => workflow.Env(
+ ("DOTNET_NOLOGO", "true"),
+ ("DOTNET_CLI_TELEMETRY_OPTOUT", "true"));
+
+ public static void StepSetupDotNet(this Job job)
+ => job.Step()
+ .Name("Setup .NET")
+ .ActionsSetupDotNet("3e891b0cb619bf60e2c25674b222b8940e2c1c25", ["6.0.x", "8.0.x", "9.0.x"]); // v4.1.0
+
+ ///
+ /// Only run this for a main build
+ ///
+ public static Step IfRefMain(this Step step)
+ => step.If("github.ref == 'refs/heads/main'");
+
+ ///
+ /// Only run this if the build is triggered on a branch IN the same repo
+ /// this means it's from a trusted contributor.
+ ///
+ public static Step IfGithubEventIsPush(this Step step)
+ => step.If("github.event == 'push'");
+
+ public static void StepDotNetDevCerts(this Job job)
+ => job.Step()
+ .Name("Dotnet devcerts")
+ .Run("dotnet dev-certs https --trust");
+
+ public static void StepInstallPlayWright(this Job job)
+ => job.Step()
+ .Name("Install Playwright")
+ .Run("pwsh test/Hosts.Tests/bin/Release/net9.0/playwright.ps1 install --with-deps");
+
+ public static void StepToolRestore(this Job job)
+ => job.Step()
+ .Name("Tool restore")
+ .Run("dotnet tool restore");
+
+ public static void StepPack(this Job job, string target)
+ {
+ job.Step()
+ .Name($"Pack {target}")
+ .Run($"dotnet pack -c Release {target} -o artifacts");
+ }
+
+ public static Step StepBuild(this Job job, string solution)
+ => job.Step()
+ .Name("Build")
+ .Run($"dotnet build {solution} -c Release");
+
+ public static void StepTest(this Job job, string solution)
+ {
+ var logFileName = "Tests.trx";
+ var loggingFlags = $"--logger \"console;verbosity=normal\" " +
+ $"--logger \"trx;LogFileName={logFileName}\" " +
+ $"--collect:\"XPlat Code Coverage\"";
+
+ job.Step()
+ .Name("Test")
+ .Run($"dotnet test {solution} -c Release --no-build {loggingFlags}");
+
+ job.Step()
+ .Name("Test report")
+ .WorkingDirectory("test")
+ .Uses("dorny/test-reporter@31a54ee7ebcacc03a09ea97a7e5465a47b84aea5") // v1.9.1
+ .If("github.event == 'push' && (success() || failure())")
+ .With(
+ ("name", "Test Report"),
+ ("path", "**/Tests.trx"),
+ ("reporter", "dotnet-trx"),
+ ("fail-on-error", "true"),
+ ("fail-on-empty", "true"));
+ }
+
+ public static Step StepPushToNuget(this Job job, bool pushAlways = false)
+ => job.StepPush("nuget.org", "https://api.nuget.org/v3/index.json", "NUGET_ORG_API_KEY", pushAlways);
+
+ public static Step StepPushToGithub(this Job job, GitHubContexts contexts, bool pushAlways = false)
+ => job.StepPush("GitHub", "https://nuget.pkg.github.com/DuendeSoftware/index.json", "GITHUB_TOKEN", pushAlways)
+ .Env(("GITHUB_TOKEN", contexts.Secrets.GitHubToken),
+ ("NUGET_AUTH_TOKEN", contexts.Secrets.GitHubToken));
+
+
+ public static void StepSign(this Job job, bool always = false)
+ {
+ var flags = "--file-digest sha256 " +
+ "--timestamp-rfc3161 http://timestamp.digicert.com " +
+ "--azure-key-vault-url https://duendecodesigninghsm.vault.azure.net/ " +
+ "--azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 " +
+ "--azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 " +
+ "--azure-key-vault-client-secret ${{ secrets.SignClientSecret }} " +
+ "--azure-key-vault-certificate NuGetPackageSigning";
+ var step = job.Step()
+ .Name("Sign packages");
+ if (!always)
+ {
+ step = step.IfGithubEventIsPush();
+ }
+ step.Run($"""
+ for file in artifacts/*.nupkg; do
+ dotnet NuGetKeyVaultSignTool sign "$file" {flags}
+ done
+ """);
+ }
+
+ public static Step StepPush(this Job job, string destination, string sourceUrl, string secretName, bool pushAlways = false)
+ {
+ var apiKey = $"${{{{ secrets.{secretName} }}}}";
+ var step = job.Step()
+ .Name($"Push packages to {destination}");
+
+ if (!pushAlways)
+ {
+ step.IfRefMain();
+ }
+ return step.Run($"dotnet nuget push artifacts/*.nupkg --source {sourceUrl} --api-key {apiKey} --skip-duplicate");
+ }
+
+ public static Step StepGitCheckoutCustomBranch(this Job job)
+ {
+ return job.Step()
+ .Name("Checkout target branch")
+ .If("github.event.inputs.branch != 'main'")
+ .Run("git checkout ${{ github.event.inputs.branch }}");
+ }
+
+ public static Step StepGitConfig(this Job job)
+ {
+ return job.Step()
+ .Name("Git Config")
+ .Run("""
+ git config --global user.email "github-bot@duendesoftware.com"
+ git config --global user.name "Duende Software GitHub Bot"
+ """);
+ }
+ internal static Step StepGitRemoveExistingTagIfConfigured(this Job job, Product component, GitHubContexts contexts)
+ {
+ return job.Step()
+ .Name("Git Config")
+ .If("github.event.inputs['remove-tag-if-exists'] == 'true'")
+ .Run($"""
+ if git rev-parse {component.TagPrefix}-{contexts.Event.Input.Version} >/dev/null 2>&1; then
+ git tag -d {component.TagPrefix}-{contexts.Event.Input.Version}
+ git push --delete origin {component.TagPrefix}-{contexts.Event.Input.Version}
+ else
+ echo 'Tag {component.TagPrefix}-{contexts.Event.Input.Version} does not exist.'
+ fi
+ """);
+ }
+ internal static Step StepGitPushTag(this Job job, Product component, GitHubContexts contexts)
+ {
+ return job.Step()
+ .Name("Git Config")
+ .Run($"""
+ git tag -a {component.TagPrefix}-{contexts.Event.Input.Version} -m "Release v{contexts.Event.Input.Version}"
+ git push origin {component.TagPrefix}-{contexts.Event.Input.Version}
+ """);
+ }
+
+ public static WorkflowDispatch InputVersionBranchAndTagOverride(this WorkflowDispatch workflow)
+ {
+ return workflow.Inputs(
+ new StringInput("version", "Version in format X.Y.Z or X.Y.Z-preview.", true, "0.0.0"),
+ new StringInput("branch", "(Optional) the name of the branch to release from", false, "main"),
+ new BooleanInput("remove-tag-if-exists", "If set, will remove the existing tag. Use this if you have issues with the previous release action", false, false));
+ }
+
+ public static Step StepUploadPlaywrightTestTraces(this Job job, string componentName)
+ {
+ var path = $"{componentName}/test/**/playwright-traces/*.zip";
+ return job.Step()
+ .Name("Upload playwright traces")
+ .If("success() || failure()")
+ .Uses("actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882") // 4.4.3
+ .With(
+ ("name", "playwright-traces"),
+ ("path", path),
+ ("overwrite", "true"),
+ ("retention-days", "15"));
+ }
+
+
+ public static void StepUploadArtifacts(this Job job, string componentName, bool uploadAlways = false)
+ {
+ var path = $"{componentName}/artifacts/*.nupkg";
+ var step = job.Step()
+ .Name("Upload Artifacts");
+
+ if (!uploadAlways)
+ {
+ step.IfRefMain();
+ }
+
+ step.Uses("actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882") // 4.4.3
+ .With(
+ ("name", "artifacts"),
+ ("path", path),
+ ("overwrite", "true"),
+ ("retention-days", "15"));
+ }
+
+ ///
+ /// The build triggers both on branch AND on pull_request.
+ ///
+ /// Only (trusted) contributors can open branches in the main repo, so these builds can run with a higher trust level.
+ /// So, they are running with trigger 'push'. These builds have access to the secrets and thus they can do things like
+ /// sign, push the packages, etc..
+ ///
+ /// External contributors can only create branches on external repo's. These builds run with a lower trust level.
+ /// So, they are running with trigger 'pull_request'. These builds do not have access to the secrets and thus they can't
+ /// sign, push the packages, etc..
+ ///
+ /// Now, if a trusted contributor creates a branch in the main repo, then creates a PR, we don't want to run the build twice.
+ /// This prevents that. The build will only run once, on the branch with the higher trust level.
+ ///
+ ///
+ public static Job RunEitherOnBranchOrAsPR(this Job job)
+ => job.If(
+ "(github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) || (github.event_name == 'push') || (github.event_name == 'workflow_dispatch')");
+
+ public static void StepInitializeCodeQl(this Job job)
+ {
+ job.Step()
+ .Name("Initialize CodeQL")
+ .Uses("github/codeql-action/init@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0") // 3.28.9
+ .With(
+ ("languages", "csharp"),
+ ("build-mode", "manual"));
+ }
+
+ public static void StepPerformCodeQlAnalysis(this Job job)
+ {
+ job.Step()
+ .Name("Perform CodeQL Analysis")
+ .Uses("github/codeql-action/analyze@9e8d0789d4a0fa9ceb6b1738f7e269594bdd67f0") // 3.28.9
+ .With(
+ ("category", "/language:csharp"));
+ }
+}
+
+public class GitHubContexts
+{
+ public static GitHubContexts Instance { get; } = new();
+ public virtual GitHubContext GitHub { get; } = new();
+ public virtual SecretsContext Secrets { get; } = new();
+ public virtual EventContext Event { get; } = new();
+
+ public abstract class Context(string name)
+ {
+ protected string Name => name;
+
+ protected string Expression(string s) => "${{ " + s + " }}";
+ }
+
+ public class GitHubContext() : Context("github")
+ {
+ }
+
+ public class SecretsContext() : Context("secrets")
+ {
+ public string GitHubToken => Expression($"{Name}.GITHUB_TOKEN");
+ }
+
+ public class EventContext() : Context("github.event")
+ {
+ public EventsInputContext Input { get; } = new ();
+ }
+
+ public class EventsInputContext() : Context("github.event.inputs")
+ {
+ public string Version => Expression($"{Name}.version");
+ }
+}
diff --git a/.github/workflow-gen/Properties/launchSettings.json b/.github/workflow-gen/Properties/launchSettings.json
new file mode 100644
index 000000000..b014caa47
--- /dev/null
+++ b/.github/workflow-gen/Properties/launchSettings.json
@@ -0,0 +1,8 @@
+{
+ "profiles": {
+ "workflow-gen": {
+ "commandName": "Project",
+ "workingDirectory": "$(ProjectDir)"
+ }
+ }
+}
\ No newline at end of file
diff --git a/.github/workflow-gen/workflow-gen.csproj b/.github/workflow-gen/workflow-gen.csproj
new file mode 100644
index 000000000..555b52c92
--- /dev/null
+++ b/.github/workflow-gen/workflow-gen.csproj
@@ -0,0 +1,17 @@
+
+
+
+ Exe
+ net8.0
+ workflow_gen
+ enable
+ enable
+ false
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/identity-server-ci.yml b/.github/workflows/identity-server-ci.yml
index b42f9810e..c6805ebde 100644
--- a/.github/workflows/identity-server-ci.yml
+++ b/.github/workflows/identity-server-ci.yml
@@ -1,50 +1,82 @@
-name: "identity-server-ci"
+# This was generated by tool. Edits will be overwritten.
+name: identity-server/ci
on:
- workflow_dispatch:
+ workflow_dispatch:
push:
- branches:
- - main
- - releases/is/**
- tags:
- - 'is-*.*.*'
+ paths:
+ - .github/workflows/identity-server-**
+ - identity-server/**
+ - Directory.Packages.props
pull_request:
-
+ paths:
+ - .github/workflows/identity-server-**
+ - identity-server/**
+ - Directory.Packages.props
env:
DOTNET_NOLOGO: true
-
-permissions:
- contents: read
-
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build:
- strategy:
- fail-fast: false
- matrix:
- runs-on: [macOS-latest, ubuntu-latest, windows-latest]
- name: ${{ matrix.runs-on }}
- runs-on: ${{ matrix.runs-on }}
+ name: Build
+ if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository) || (github.event_name == 'push') || (github.event_name == 'workflow_dispatch')
+ runs-on: ubuntu-latest
+ permissions:
+ actions: read
+ checks: write
+ contents: read
+ packages: write
+ defaults:
+ run:
+ shell: bash
+ working-directory: .
+ timeout-minutes: 15
steps:
- - uses: actions/checkout@v3
+ - name: Checkout
+ uses: actions/checkout@v4
with:
fetch-depth: 0
-
- - name: Setup dotnet (main)
- uses: actions/setup-dotnet@v4
+ - name: Setup Dotnet
+ uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25
with:
- dotnet-version: |
- 8.0.x
- 9.0.x
-
- - run: dotnet --info
-
- - if: contains(matrix.runs-on, 'macOS') || contains(matrix.runs-on, 'ubuntu')
- run: ./build.sh
- - if: matrix.runs-on == 'windows-latest' && github.ref != 'refs/heads/main' && !contains(github.ref, 'refs/tags/')
- run: ./build.ps1
- - if: (matrix.runs-on == 'windows-latest') && (github.ref == 'refs/heads/main' || contains(github.ref, 'refs/tags/'))
+ dotnet-version: |-
+ 6.0.x
+ 8.0.x
+ 9.0.x
+ - name: Build
+ run: dotnet build Duende.IdentityServer.sln -c Release
+ - name: Test
+ run: dotnet test Duende.IdentityServer.sln -c Release --no-build --logger "console;verbosity=normal" --logger "trx;LogFileName=Tests.trx" --collect:"XPlat Code Coverage"
+ - name: Test report
+ if: github.event == 'push' && (success() || failure())
+ uses: dorny/test-reporter@31a54ee7ebcacc03a09ea97a7e5465a47b84aea5
+ with:
+ name: Test Report
+ path: '**/Tests.trx'
+ reporter: dotnet-trx
+ fail-on-error: true
+ fail-on-empty: true
+ - name: Tool restore
+ run: dotnet tool restore
+ - name: Pack Duende.IdentityServer.sln
+ run: dotnet pack -c Release Duende.IdentityServer.sln -o artifacts
+ - name: Sign packages
+ if: github.event == 'push'
+ run: |-
+ for file in artifacts/*.nupkg; do
+ dotnet NuGetKeyVaultSignTool sign "$file" --file-digest sha256 --timestamp-rfc3161 http://timestamp.digicert.com --azure-key-vault-url https://duendecodesigninghsm.vault.azure.net/ --azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 --azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 --azure-key-vault-client-secret ${{ secrets.SignClientSecret }} --azure-key-vault-certificate NuGetPackageSigning
+ done
+ - name: Push packages to GitHub
+ if: github.ref == 'refs/heads/main'
+ run: dotnet nuget push artifacts/*.nupkg --source https://nuget.pkg.github.com/DuendeSoftware/index.json --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
env:
- SignClientSecret: ${{ secrets.SIGNCLIENTSECRET }}
- run: |
- ./build.ps1 sign
- dotnet nuget push .\artifacts\*.nupkg -s https://www.myget.org/F/duende_identityserver/api/v2/package -k ${{ secrets.MYGET }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload Artifacts
+ if: github.ref == 'refs/heads/main'
+ uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
+ with:
+ name: artifacts
+ path: identity-server/artifacts/*.nupkg
+ overwrite: true
+ retention-days: 15
diff --git a/.github/workflows/identity-server-release.yml b/.github/workflows/identity-server-release.yml
new file mode 100644
index 000000000..5f65b55fa
--- /dev/null
+++ b/.github/workflows/identity-server-release.yml
@@ -0,0 +1,118 @@
+# This was generated by tool. Edits will be overwritten.
+
+name: identity-server/release
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: 'Version in format X.Y.Z or X.Y.Z-preview.'
+ type: string
+ required: true
+ default: '0.0.0'
+ branch:
+ description: '(Optional) the name of the branch to release from'
+ type: string
+ required: false
+ default: 'main'
+ remove-tag-if-exists:
+ description: 'If set, will remove the existing tag. Use this if you have issues with the previous release action'
+ type: boolean
+ required: false
+ default: false
+env:
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+jobs:
+ tag:
+ name: Tag and Pack
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ packages: write
+ defaults:
+ run:
+ shell: bash
+ working-directory: .
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+ - name: Checkout target branch
+ if: github.event.inputs.branch != 'main'
+ run: git checkout ${{ github.event.inputs.branch }}
+ - name: Git Config
+ run: |-
+ git config --global user.email "github-bot@duendesoftware.com"
+ git config --global user.name "Duende Software GitHub Bot"
+ - name: Git Config
+ if: github.event.inputs['remove-tag-if-exists'] == 'true'
+ run: |-
+ if git rev-parse is-${{ github.event.inputs.version }} >/dev/null 2>&1; then
+ git tag -d is-${{ github.event.inputs.version }}
+ git push --delete origin is-${{ github.event.inputs.version }}
+ else
+ echo 'Tag is-${{ github.event.inputs.version }} does not exist.'
+ fi
+ - name: Git Config
+ run: |-
+ git tag -a is-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
+ git push origin is-${{ github.event.inputs.version }}
+ - name: Setup Dotnet
+ uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25
+ with:
+ dotnet-version: |-
+ 6.0.x
+ 8.0.x
+ 9.0.x
+ - name: Git tag
+ run: |-
+ git config --global user.email "github-bot@duendesoftware.com"
+ git config --global user.name "Duende Software GitHub Bot"
+ git tag -a is-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
+ git push origin is-${{ github.event.inputs.version }}
+ - name: Pack Duende.IdentityServer.sln
+ run: dotnet pack -c Release Duende.IdentityServer.sln -o artifacts
+ - name: Tool restore
+ run: dotnet tool restore
+ - name: Sign packages
+ run: |-
+ for file in artifacts/*.nupkg; do
+ dotnet NuGetKeyVaultSignTool sign "$file" --file-digest sha256 --timestamp-rfc3161 http://timestamp.digicert.com --azure-key-vault-url https://duendecodesigninghsm.vault.azure.net/ --azure-key-vault-client-id 18e3de68-2556-4345-8076-a46fad79e474 --azure-key-vault-tenant-id ed3089f0-5401-4758-90eb-066124e2d907 --azure-key-vault-client-secret ${{ secrets.SignClientSecret }} --azure-key-vault-certificate NuGetPackageSigning
+ done
+ - name: Push packages to GitHub
+ run: dotnet nuget push artifacts/*.nupkg --source https://nuget.pkg.github.com/DuendeSoftware/index.json --api-key ${{ secrets.GITHUB_TOKEN }} --skip-duplicate
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ NUGET_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload Artifacts
+ uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
+ with:
+ name: artifacts
+ path: identity-server/artifacts/*.nupkg
+ overwrite: true
+ retention-days: 15
+ publish:
+ name: Publish to nuget.org
+ needs:
+ - tag
+ runs-on: ubuntu-latest
+ environment:
+ name: nuget.org
+ steps:
+ - uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16
+ with:
+ name: artifacts
+ path: artifacts
+ - name: Setup Dotnet
+ uses: actions/setup-dotnet@3e891b0cb619bf60e2c25674b222b8940e2c1c25
+ with:
+ dotnet-version: |-
+ 6.0.x
+ 8.0.x
+ 9.0.x
+ - name: List files
+ run: tree
+ shell: bash
+ - name: Push packages to nuget.org
+ run: dotnet nuget push artifacts/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_ORG_API_KEY }} --skip-duplicate
From 1365b658f8789e66c66d4a8a16d513104624f055 Mon Sep 17 00:00:00 2001
From: Brett Hazen <2651260+bhazen@users.noreply.github.com>
Date: Tue, 4 Mar 2025 13:59:56 -0600
Subject: [PATCH 3/4] Removing redundant tag step in release workflow
---
.github/workflow-gen/Program.cs | 9 +--------
.github/workflows/identity-server-release.yml | 8 +-------
2 files changed, 2 insertions(+), 15 deletions(-)
diff --git a/.github/workflow-gen/Program.cs b/.github/workflow-gen/Program.cs
index ed0f5ee62..b194769c8 100644
--- a/.github/workflow-gen/Program.cs
+++ b/.github/workflow-gen/Program.cs
@@ -99,13 +99,6 @@ void GenerateIdentityServerReleaseWorkflow(Product product)
job.StepSetupDotNet();
- job.Step()
- .Name("Git tag")
- .Run($@"git config --global user.email ""github-bot@duendesoftware.com""
-git config --global user.name ""Duende Software GitHub Bot""
-git tag -a {product.TagPrefix}-{contexts.Event.Input.Version} -m ""Release v{contexts.Event.Input.Version}""
-git push origin {product.TagPrefix}-{contexts.Event.Input.Version}");
-
job.StepPack(product.Solution);
job.StepToolRestore();
@@ -415,7 +408,7 @@ public static class StepExtensions
internal static Step StepGitPushTag(this Job job, Product component, GitHubContexts contexts)
{
return job.Step()
- .Name("Git Config")
+ .Name("Git Tag")
.Run($"""
git tag -a {component.TagPrefix}-{contexts.Event.Input.Version} -m "Release v{contexts.Event.Input.Version}"
git push origin {component.TagPrefix}-{contexts.Event.Input.Version}
diff --git a/.github/workflows/identity-server-release.yml b/.github/workflows/identity-server-release.yml
index 5f65b55fa..aad92c4c4 100644
--- a/.github/workflows/identity-server-release.yml
+++ b/.github/workflows/identity-server-release.yml
@@ -54,7 +54,7 @@ jobs:
else
echo 'Tag is-${{ github.event.inputs.version }} does not exist.'
fi
- - name: Git Config
+ - name: Git Tag
run: |-
git tag -a is-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
git push origin is-${{ github.event.inputs.version }}
@@ -65,12 +65,6 @@ jobs:
6.0.x
8.0.x
9.0.x
- - name: Git tag
- run: |-
- git config --global user.email "github-bot@duendesoftware.com"
- git config --global user.name "Duende Software GitHub Bot"
- git tag -a is-${{ github.event.inputs.version }} -m "Release v${{ github.event.inputs.version }}"
- git push origin is-${{ github.event.inputs.version }}
- name: Pack Duende.IdentityServer.sln
run: dotnet pack -c Release Duende.IdentityServer.sln -o artifacts
- name: Tool restore
From 73f8f4ce6c507e9ef26913eb297f4ac0c1832c78 Mon Sep 17 00:00:00 2001
From: Joe DeCock
Date: Tue, 4 Mar 2025 14:20:06 -0600
Subject: [PATCH 4/4] Change path for where to find artifacts
---
.github/workflow-gen/Program.cs | 2 +-
.github/workflows/identity-server-ci.yml | 2 +-
.github/workflows/identity-server-release.yml | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/.github/workflow-gen/Program.cs b/.github/workflow-gen/Program.cs
index b194769c8..2a6dee625 100644
--- a/.github/workflow-gen/Program.cs
+++ b/.github/workflow-gen/Program.cs
@@ -440,7 +440,7 @@ public static class StepExtensions
public static void StepUploadArtifacts(this Job job, string componentName, bool uploadAlways = false)
{
- var path = $"{componentName}/artifacts/*.nupkg";
+ var path = $"artifacts/*.nupkg";
var step = job.Step()
.Name("Upload Artifacts");
diff --git a/.github/workflows/identity-server-ci.yml b/.github/workflows/identity-server-ci.yml
index c6805ebde..10752cb51 100644
--- a/.github/workflows/identity-server-ci.yml
+++ b/.github/workflows/identity-server-ci.yml
@@ -77,6 +77,6 @@ jobs:
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
with:
name: artifacts
- path: identity-server/artifacts/*.nupkg
+ path: artifacts/*.nupkg
overwrite: true
retention-days: 15
diff --git a/.github/workflows/identity-server-release.yml b/.github/workflows/identity-server-release.yml
index aad92c4c4..ed78016a0 100644
--- a/.github/workflows/identity-server-release.yml
+++ b/.github/workflows/identity-server-release.yml
@@ -83,7 +83,7 @@ jobs:
uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882
with:
name: artifacts
- path: identity-server/artifacts/*.nupkg
+ path: artifacts/*.nupkg
overwrite: true
retention-days: 15
publish: