From 17da299a748aa65ea73f255a7531d4be9d4f83e8 Mon Sep 17 00:00:00 2001 From: Matthew de Detrich Date: Wed, 27 Apr 2022 15:38:34 +0200 Subject: [PATCH] Add global permissions --- .../scala/sbtghactions/GenerativeKeys.scala | 1 + .../scala/sbtghactions/GenerativePlugin.scala | 25 ++++++++++++++++++- .../sbtghactions/GenerativePluginSpec.scala | 19 ++++++++++---- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/main/scala/sbtghactions/GenerativeKeys.scala b/src/main/scala/sbtghactions/GenerativeKeys.scala index 93b338c..6e7ebea 100644 --- a/src/main/scala/sbtghactions/GenerativeKeys.scala +++ b/src/main/scala/sbtghactions/GenerativeKeys.scala @@ -62,6 +62,7 @@ trait GenerativeKeys { lazy val githubWorkflowJobSetup = settingKey[Seq[WorkflowStep]]("The automatically-generated checkout, setup, and cache steps which are common to all jobs which touch the build (default: autogenerated)") lazy val githubWorkflowEnv = settingKey[Map[String, String]](s"A map of static environment variable assignments global to the workflow (default: { GITHUB_TOKEN: $${{ secrets.GITHUB_TOKEN }} })") + lazy val githubWorkflowPermissions = settingKey[Map[String, String]](s"A map of static permissions for the global workflow (default: {})") lazy val githubWorkflowAddedJobs = settingKey[Seq[WorkflowJob]]("A list of additional jobs to add to the CI workflow (default: [])") } diff --git a/src/main/scala/sbtghactions/GenerativePlugin.scala b/src/main/scala/sbtghactions/GenerativePlugin.scala index f635db0..d62abed 100644 --- a/src/main/scala/sbtghactions/GenerativePlugin.scala +++ b/src/main/scala/sbtghactions/GenerativePlugin.scala @@ -183,6 +183,21 @@ object GenerativePlugin extends AutoPlugin { s"""$key: ${wrap(value)}""" } s"""$prefix: +${indent(rendered.mkString("\n"), 1)}""" + } + + def compilePermissions(permissions: Map[String, String]): String = + if (permissions.isEmpty) { + "" + } else { + val rendered = permissions map { + case (key, value) => + if (!isSafeString(key) || key.indexOf(' ') >= 0) + sys.error(s"'$key' is not a valid permission name") + + s"""$key: ${wrap(value)}""" + } + s"""permissions: ${indent(rendered.mkString("\n"), 1)}""" } @@ -421,15 +436,21 @@ ${indent(job.steps.map(compileStep(_, sbt, declareShell = declareShell)).mkStrin paths: Paths, prEventTypes: List[PREventType], env: Map[String, String], + permissions: Map[String, String], jobs: List[WorkflowJob], sbt: String) : String = { + val renderedPermissionsPre = compilePermissions(permissions) val renderedEnvPre = compileEnv(env) val renderedEnv = if (renderedEnvPre.isEmpty) "" else renderedEnvPre + "\n\n" + val renderedPerm = if (renderedPermissionsPre.isEmpty) + "" + else + renderedPermissionsPre + "\n\n" val renderedTypesPre = prEventTypes.map(compilePREventType).mkString("[", ", ", "]") val renderedTypes = if (prEventTypes.sortBy(_.toString) == PREventType.Defaults) @@ -467,7 +488,7 @@ on: push: branches: [${branches.map(wrap).mkString(", ")}]$renderedTags$renderedPaths -${renderedEnv}jobs: +${renderedPerm}${renderedEnv}jobs: ${indent(jobs.map(compileJob(_, sbt)).mkString("\n\n"), 1)} """ } @@ -504,6 +525,7 @@ ${indent(jobs.map(compileJob(_, sbt)).mkString("\n\n"), 1)} githubWorkflowTargetPaths := Paths.None, githubWorkflowEnv := Map("GITHUB_TOKEN" -> s"$${{ secrets.GITHUB_TOKEN }}"), + githubWorkflowPermissions := Map.empty[String, String], githubWorkflowAddedJobs := Seq()) private lazy val internalTargetAggregation = settingKey[Seq[File]]("Aggregates target directories from all subprojects") @@ -698,6 +720,7 @@ ${indent(jobs.map(compileJob(_, sbt)).mkString("\n\n"), 1)} githubWorkflowTargetPaths.value, githubWorkflowPREventTypes.value.toList, githubWorkflowEnv.value, + githubWorkflowPermissions.value, githubWorkflowGeneratedCI.value.toList, sbt) } diff --git a/src/test/scala/sbtghactions/GenerativePluginSpec.scala b/src/test/scala/sbtghactions/GenerativePluginSpec.scala index e544d96..b38886d 100644 --- a/src/test/scala/sbtghactions/GenerativePluginSpec.scala +++ b/src/test/scala/sbtghactions/GenerativePluginSpec.scala @@ -46,7 +46,7 @@ class GenerativePluginSpec extends Specification { |${" " * 2} |""".stripMargin - compileWorkflow("test", List("main"), Nil, Paths.None, PREventType.Defaults, Map(), Nil, "sbt") mustEqual expected + compileWorkflow("test", List("main"), Nil, Paths.None, PREventType.Defaults, Map(), Map(), Nil, "sbt") mustEqual expected } "produce the appropriate skeleton around a zero-job workflow with non-empty tags" in { @@ -64,7 +64,7 @@ class GenerativePluginSpec extends Specification { |${" " * 2} |""".stripMargin - compileWorkflow("test", List("main"), List("howdy"), Paths.None, PREventType.Defaults, Map(), Nil, "sbt") mustEqual expected + compileWorkflow("test", List("main"), List("howdy"), Paths.None, PREventType.Defaults, Map(), Map(), Nil, "sbt") mustEqual expected } "respect non-default pr types" in { @@ -82,7 +82,7 @@ class GenerativePluginSpec extends Specification { |${" " * 2} |""".stripMargin - compileWorkflow("test", List("main"), Nil, Paths.None, List(PREventType.ReadyForReview, PREventType.ReviewRequested, PREventType.Opened), Map(), Nil, "sbt") mustEqual expected + compileWorkflow("test", List("main"), Nil, Paths.None, List(PREventType.ReadyForReview, PREventType.ReviewRequested, PREventType.Opened), Map(), Map(), Nil, "sbt") mustEqual expected } "compile a one-job workflow targeting multiple branch patterns with a environment variables" in { @@ -95,6 +95,9 @@ class GenerativePluginSpec extends Specification { | push: | branches: [main, backport/v*] | + |permissions: + | id-token: write + | |env: | GITHUB_TOKEN: $${{ secrets.GITHUB_TOKEN }} | @@ -119,6 +122,9 @@ class GenerativePluginSpec extends Specification { PREventType.Defaults, Map( "GITHUB_TOKEN" -> s"$${{ secrets.GITHUB_TOKEN }}"), + Map( + "id-token" -> "write" + ), List( WorkflowJob( "build", @@ -168,6 +174,7 @@ class GenerativePluginSpec extends Specification { Paths.None, PREventType.Defaults, Map(), + Map(), List( WorkflowJob( "build", @@ -212,6 +219,7 @@ class GenerativePluginSpec extends Specification { Paths.None, PREventType.Defaults, Map(), + Map(), List( WorkflowJob( "build", @@ -263,6 +271,7 @@ class GenerativePluginSpec extends Specification { Paths.None, PREventType.Defaults, Map(), + Map(), List( WorkflowJob( "build", @@ -295,7 +304,7 @@ class GenerativePluginSpec extends Specification { |${" " * 2} |""".stripMargin - compileWorkflow("test", List("main"), Nil, Paths.Include(List("**.scala", "**.sbt")), PREventType.Defaults, Map(), Nil, "sbt") mustEqual expected + compileWorkflow("test", List("main"), Nil, Paths.Include(List("**.scala", "**.sbt")), PREventType.Defaults, Map(), Map(), Nil, "sbt") mustEqual expected } "render ignored paths on pull_request and push" in { @@ -314,7 +323,7 @@ class GenerativePluginSpec extends Specification { |${" " * 2} |""".stripMargin - compileWorkflow("test", List("main"), Nil, Paths.Ignore(List("docs/**")), PREventType.Defaults, Map(), Nil, "sbt") mustEqual expected + compileWorkflow("test", List("main"), Nil, Paths.Ignore(List("docs/**")), PREventType.Defaults, Map(), Map(), Nil, "sbt") mustEqual expected } }