From 773cecf28dacccd2108a96c0f9693b94f0b5b769 Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Sun, 8 Mar 2026 08:23:11 -0400 Subject: [PATCH 1/4] Added permissions --- .../CompletePipelineTest.cs | 102 ++++++++++++++++++ .../Models/GitHubActionsRoot.cs | 1 + src/GitHubActionsDotNet/Models/Job.cs | 1 + src/GitHubActionsDotNet/Models/Permissions.cs | 20 ++++ .../GitHubActionsSerialization.cs | 6 ++ 5 files changed, 130 insertions(+) create mode 100644 src/GitHubActionsDotNet/Models/Permissions.cs diff --git a/src/GitHubActionsDotNet.Tests/CompletePipelineTest.cs b/src/GitHubActionsDotNet.Tests/CompletePipelineTest.cs index 775547e..00f7c1e 100644 --- a/src/GitHubActionsDotNet.Tests/CompletePipelineTest.cs +++ b/src/GitHubActionsDotNet.Tests/CompletePipelineTest.cs @@ -154,6 +154,108 @@ public void WorkflowDispatchWithInputsExampleTest() steps: - name: Deploy run: echo 'Deploying version ${{ github.event.inputs.version }} to ${{ github.event.inputs.environment }}' +"; + expected = UtilityTests.TrimNewLines(expected); + Assert.AreEqual(expected, yaml); + } + + [TestMethod] + public void WorkflowWithTopLevelPermissionsTest() + { + //Arrange + JobHelper jobHelper = new(); + GitHubActionsRoot root = new() + { + name = "CI", + on = TriggerHelper.AddStandardPushAndPullTrigger(), + permissions = new Permissions + { + contents = "read", + packages = "write" + }, + jobs = new() + }; + Step[] buildSteps = new Step[] { + CommonStepHelper.AddCheckoutStep(), + }; + Job buildJob = jobHelper.AddJob( + null, + "ubuntu-latest", + buildSteps); + root.jobs.Add("build", buildJob); + + //Act + string yaml = Serialization.GitHubActionsSerialization.Serialize(root); + + //Assert + string expected = @" +name: CI +on: + push: + branches: + - main + pull_request: + branches: + - main +permissions: + contents: read + packages: write +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 +"; + expected = UtilityTests.TrimNewLines(expected); + Assert.AreEqual(expected, yaml); + } + + [TestMethod] + public void JobWithPermissionsTest() + { + //Arrange + JobHelper jobHelper = new(); + GitHubActionsRoot root = new() + { + name = "CI", + on = TriggerHelper.AddStandardPushAndPullTrigger(), + jobs = new() + }; + Step[] buildSteps = new Step[] { + CommonStepHelper.AddCheckoutStep(), + }; + Job buildJob = jobHelper.AddJob( + null, + "ubuntu-latest", + buildSteps); + buildJob.permissions = new Permissions + { + issues = "write", + pull_requests = "write" + }; + root.jobs.Add("stale", buildJob); + + //Act + string yaml = Serialization.GitHubActionsSerialization.Serialize(root); + + //Assert + string expected = @" +name: CI +on: + push: + branches: + - main + pull_request: + branches: + - main +jobs: + stale: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/checkout@v4 "; expected = UtilityTests.TrimNewLines(expected); Assert.AreEqual(expected, yaml); diff --git a/src/GitHubActionsDotNet/Models/GitHubActionsRoot.cs b/src/GitHubActionsDotNet/Models/GitHubActionsRoot.cs index be5a0b1..2753ece 100644 --- a/src/GitHubActionsDotNet/Models/GitHubActionsRoot.cs +++ b/src/GitHubActionsDotNet/Models/GitHubActionsRoot.cs @@ -7,6 +7,7 @@ public class GitHubActionsRoot { public string name { get; set; } public Trigger on { get; set; } + public Permissions permissions { get; set; } public Dictionary env { get; set; } public Dictionary jobs { get; set; } diff --git a/src/GitHubActionsDotNet/Models/Job.cs b/src/GitHubActionsDotNet/Models/Job.cs index bd0d73c..c8907dc 100644 --- a/src/GitHubActionsDotNet/Models/Job.cs +++ b/src/GitHubActionsDotNet/Models/Job.cs @@ -5,6 +5,7 @@ namespace GitHubActionsDotNet.Models public class Job { public string name { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idname + public Permissions permissions { get; set; } //https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idpermissions public Strategy strategy { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstrategy public string runs_on { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idruns-on //public T container { get; set; } diff --git a/src/GitHubActionsDotNet/Models/Permissions.cs b/src/GitHubActionsDotNet/Models/Permissions.cs new file mode 100644 index 0000000..de1369a --- /dev/null +++ b/src/GitHubActionsDotNet/Models/Permissions.cs @@ -0,0 +1,20 @@ +namespace GitHubActionsDotNet.Models +{ + public class Permissions + { + public string actions { get; set; } + public string attestations { get; set; } + public string checks { get; set; } + public string contents { get; set; } + public string deployments { get; set; } + public string discussions { get; set; } + public string id_token { get; set; } + public string issues { get; set; } + public string models { get; set; } + public string packages { get; set; } + public string pages { get; set; } + public string pull_requests { get; set; } + public string security_events { get; set; } + public string statuses { get; set; } + } +} diff --git a/src/GitHubActionsDotNet/Serialization/GitHubActionsSerialization.cs b/src/GitHubActionsDotNet/Serialization/GitHubActionsSerialization.cs index ab05cb8..6fb416b 100644 --- a/src/GitHubActionsDotNet/Serialization/GitHubActionsSerialization.cs +++ b/src/GitHubActionsDotNet/Serialization/GitHubActionsSerialization.cs @@ -104,6 +104,9 @@ private static GitHubActionsRoot DeserializeGitHubActionsYaml(string yaml) yaml = yaml.Replace("ref", "_ref"); yaml = yaml.Replace("continue-on-error", "continue_on_error"); yaml = yaml.Replace("timeout-minutes", "timeout_minutes"); + yaml = yaml.Replace("id-token", "id_token"); + yaml = yaml.Replace("pull-requests", "pull_requests"); + yaml = yaml.Replace("security-events", "security_events"); return YamlSerialization.DeserializeYaml(yaml); } @@ -124,6 +127,9 @@ private static string PrepareYamlPropertiesForGitHubSerialization(string yaml) yaml = yaml.Replace("continue_on_error", "continue-on-error"); yaml = yaml.Replace("timeout_minutes", "timeout-minutes"); yaml = yaml.Replace("_default", "default"); + yaml = yaml.Replace("id_token", "id-token"); + yaml = yaml.Replace("pull_requests", "pull-requests"); + yaml = yaml.Replace("security_events", "security-events"); yaml = yaml.Replace("step_message:", "#"); yaml = yaml.Replace("job_message:", "#"); yaml = yaml.Replace("step_message", "#"); From 0177fbf6bd6b72078be35418764d43e68c941606 Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Sun, 8 Mar 2026 08:23:20 -0400 Subject: [PATCH 2/4] updated github actions --- .github/workflows/CICD.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/CICD.yml b/.github/workflows/CICD.yml index 418f5fd..e6bbd60 100644 --- a/.github/workflows/CICD.yml +++ b/.github/workflows/CICD.yml @@ -25,12 +25,12 @@ jobs: #Install and calculate the new version with GitVersion - name: Install GitVersion - uses: gittools/actions/gitversion/setup@v4.2.0 + uses: gittools/actions/gitversion/setup@v4.3.0 with: versionSpec: 6.x - name: Determine Version - uses: gittools/actions/gitversion/execute@v4.2.0 + uses: gittools/actions/gitversion/execute@v4.3.0 id: gitversion # step id used as reference for output values - name: Display GitVersion outputs From 537513cee7465d1ac7c361d51a1028c6b6714b49 Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Sun, 8 Mar 2026 08:23:53 -0400 Subject: [PATCH 3/4] updated packages --- .../GitHubActionsDotNet.Tests.csproj | 10 +++++----- src/GitHubActionsDotNet/GitHubActionsDotNet.csproj | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/GitHubActionsDotNet.Tests/GitHubActionsDotNet.Tests.csproj b/src/GitHubActionsDotNet.Tests/GitHubActionsDotNet.Tests.csproj index 50ac5e7..1fe3191 100644 --- a/src/GitHubActionsDotNet.Tests/GitHubActionsDotNet.Tests.csproj +++ b/src/GitHubActionsDotNet.Tests/GitHubActionsDotNet.Tests.csproj @@ -8,17 +8,17 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + diff --git a/src/GitHubActionsDotNet/GitHubActionsDotNet.csproj b/src/GitHubActionsDotNet/GitHubActionsDotNet.csproj index 99f1b53..ca893ce 100644 --- a/src/GitHubActionsDotNet/GitHubActionsDotNet.csproj +++ b/src/GitHubActionsDotNet/GitHubActionsDotNet.csproj @@ -12,7 +12,7 @@ - + From ef4a4995a0959f92735d3d6f17d51103c30688eb Mon Sep 17 00:00:00 2001 From: Sam Smith Date: Sun, 8 Mar 2026 08:39:13 -0400 Subject: [PATCH 4/4] Fix to permissions order in jobs --- src/GitHubActionsDotNet/Models/Job.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHubActionsDotNet/Models/Job.cs b/src/GitHubActionsDotNet/Models/Job.cs index c8907dc..1a797db 100644 --- a/src/GitHubActionsDotNet/Models/Job.cs +++ b/src/GitHubActionsDotNet/Models/Job.cs @@ -5,9 +5,9 @@ namespace GitHubActionsDotNet.Models public class Job { public string name { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idname - public Permissions permissions { get; set; } //https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idpermissions public Strategy strategy { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idstrategy public string runs_on { get; set; } //https://help.github.com/en/articles/workflow-syntax-for-github-actions#jobsjob_idruns-on + public Permissions permissions { get; set; } //https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idpermissions //public T container { get; set; } public Dictionary outputs { get; set; } //https://docs.github.com/en/actions/learn-github-actions/workflow-syntax-for-github-actions#jobsjob_idoutputs public Container container { get; set; } //https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schemaview=azure-devops&tabs=schema#job