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: