From e34d00cc349f406380cb84d963526bb671739d10 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 25 Sep 2023 15:09:12 -0500 Subject: [PATCH 01/11] switch to sbt-typelevel --- .github/workflows/ci.yml | 143 ++++++++++++++++++++++++++---------- .github/workflows/clean.yml | 3 +- .mergify.yml | 45 ++++-------- build.sbt | 55 +++++--------- project/plugins.sbt | 6 +- 5 files changed, 141 insertions(+), 111 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df75b82..4ba1028 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,30 +9,41 @@ name: Continuous Integration on: pull_request: - branches: ['**'] + branches: ['**', '!update/**', '!pr/**'] push: - branches: ['**'] + branches: ['**', '!update/**', '!pr/**'] tags: [v*] env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +concurrency: + group: ${{ github.workflow }} @ ${{ github.ref }} + cancel-in-progress: true + jobs: build: name: Build and Test strategy: matrix: os: [ubuntu-latest] - scala: [2.13.14, 2.12.20] - java: [temurin@8, temurin@11] + scala: [2.13, 2.12] + java: [temurin@8] runs-on: ${{ matrix.os }} + timeout-minutes: 60 steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Java (temurin@8) + id: setup-java-temurin-8 if: matrix.java == 'temurin@8' uses: actions/setup-java@v4 with: @@ -40,29 +51,37 @@ jobs: java-version: 8 cache: sbt - - name: Setup Java (temurin@11) - if: matrix.java == 'temurin@11' - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 11 - cache: sbt - - - name: Setup sbt - uses: sbt/setup-sbt@v1 + - name: sbt update + if: matrix.java == 'temurin@8' && steps.setup-java-temurin-8.outputs.cache-hit == 'false' + run: sbt +update - name: Check that workflows are up to date - run: sbt '++ ${{ matrix.scala }}' githubWorkflowCheck + run: sbt githubWorkflowCheck + + - name: Test + run: sbt '++ ${{ matrix.scala }}' test + + - name: Check binary compatibility + if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' + run: sbt '++ ${{ matrix.scala }}' mimaReportBinaryIssues + + - name: Generate API documentation + if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' + run: sbt '++ ${{ matrix.scala }}' doc - - run: sbt '++ ${{ matrix.scala }}' test doc + - name: Make target directories + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) + run: mkdir -p target project/target - name: Compress target directories + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) run: tar cf targets.tar target project/target - name: Upload target directories + if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) uses: actions/upload-artifact@v4 with: - name: target-${{ matrix.os }}-${{ matrix.scala }}-${{ matrix.java }} + name: target-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.scala }} path: targets.tar publish: @@ -72,16 +91,20 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13.14] java: [temurin@8] runs-on: ${{ matrix.os }} steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + - name: Checkout current branch (full) uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Java (temurin@8) + id: setup-java-temurin-8 if: matrix.java == 'temurin@8' uses: actions/setup-java@v4 with: @@ -89,40 +112,86 @@ jobs: java-version: 8 cache: sbt - - name: Setup Java (temurin@11) - if: matrix.java == 'temurin@11' - uses: actions/setup-java@v4 - with: - distribution: temurin - java-version: 11 - cache: sbt - - - name: Setup sbt - uses: sbt/setup-sbt@v1 + - name: sbt update + if: matrix.java == 'temurin@8' && steps.setup-java-temurin-8.outputs.cache-hit == 'false' + run: sbt +update - - name: Download target directories (2.13.14) + - name: Download target directories (2.13) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-2.13.14-${{ matrix.java }} + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13 - - name: Inflate target directories (2.13.14) + - name: Inflate target directories (2.13) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.12.20) + - name: Download target directories (2.12) uses: actions/download-artifact@v4 with: - name: target-${{ matrix.os }}-2.12.20-${{ matrix.java }} + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12 - - name: Inflate target directories (2.12.20) + - name: Inflate target directories (2.12) run: | tar xf targets.tar rm targets.tar - - env: + - name: Import signing key + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' + env: + PGP_SECRET: ${{ secrets.PGP_SECRET }} PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + run: echo $PGP_SECRET | base64 -d -i - | gpg --import + + - name: Import signing key and strip passphrase + if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE != '' + env: PGP_SECRET: ${{ secrets.PGP_SECRET }} - SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }} + run: | + echo "$PGP_SECRET" | base64 -d -i - > /tmp/signing-key.gpg + echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg + (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) + + - name: Publish + env: SONATYPE_USERNAME: ${{ secrets.SONATYPE_USERNAME }} - run: sbt ci-release + SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + SONATYPE_CREDENTIAL_HOST: ${{ secrets.SONATYPE_CREDENTIAL_HOST }} + run: sbt tlCiRelease + + dependency-submission: + name: Submit Dependencies + if: github.event.repository.fork == false && github.event_name != 'pull_request' + strategy: + matrix: + os: [ubuntu-latest] + java: [temurin@8] + runs-on: ${{ matrix.os }} + steps: + - name: Install sbt + if: contains(runner.os, 'macos') + run: brew install sbt + + - name: Checkout current branch (full) + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java (temurin@8) + id: setup-java-temurin-8 + if: matrix.java == 'temurin@8' + uses: actions/setup-java@v4 + with: + distribution: temurin + java-version: 8 + cache: sbt + + - name: sbt update + if: matrix.java == 'temurin@8' && steps.setup-java-temurin-8.outputs.cache-hit == 'false' + run: sbt +update + + - name: Submit Dependencies + uses: scalacenter/sbt-dependency-submission@v2 + with: + configs-ignore: test scala-tool scala-doc-tool test-internal diff --git a/.github/workflows/clean.yml b/.github/workflows/clean.yml index bfc865d..547aaa4 100644 --- a/.github/workflows/clean.yml +++ b/.github/workflows/clean.yml @@ -17,7 +17,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} steps: - name: Delete artifacts - shell: bash {0} run: | # Customize those three lines with your repository and credentials: REPO=${GITHUB_API_URL}/repos/${{ github.repository }} @@ -26,7 +25,7 @@ jobs: ghapi() { curl --silent --location --user _:$GITHUB_TOKEN "$@"; } # A temporary file which receives HTTP response headers. - TMPFILE=$(mktemp) + TMPFILE=/tmp/tmp.$$ # An associative array, key: artifact name, value: number of artifacts of that name. declare -A ARTCOUNT diff --git a/.mergify.yml b/.mergify.yml index 961764c..a37af35 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -1,33 +1,16 @@ -queue_rules: - - name: default - conditions: - - status-success=Build and Test (ubuntu-latest, 2.13.10, temurin@8) - - status-success=Build and Test (ubuntu-latest, 2.13.10, temurin@11) - - status-success=Build and Test (ubuntu-latest, 2.12.17, temurin@8) - - status-success=Build and Test (ubuntu-latest, 2.12.17, temurin@11) +# This file was automatically generated by sbt-typelevel-mergify using the +# mergifyGenerate task. You should add and commit this file to +# your git repository. It goes without saying that you shouldn't edit +# this file by hand! Instead, if you wish to make changes, you should +# change your sbt build configuration to revise the mergify configuration +# to meet your needs, then regenerate this file. pull_request_rules: - - name: assign and label scala-steward's PRs - conditions: - - author=dwolla-oss-scala-steward[bot] - actions: - label: - add: [dependency-update] - - name: automatic update pull requests - conditions: - - author=dwolla-oss-scala-steward[bot] - - -conflict # skip PRs with conflicts - - -draft # filter-out GH draft PRs - actions: - update: - - name: merge scala-steward's PRs - conditions: - - author=dwolla-oss-scala-steward[bot] - - status-success=Build and Test (ubuntu-latest, 2.13.10, temurin@8) - - status-success=Build and Test (ubuntu-latest, 2.13.10, temurin@11) - - status-success=Build and Test (ubuntu-latest, 2.12.17, temurin@8) - - status-success=Build and Test (ubuntu-latest, 2.12.17, temurin@11) - actions: - queue: - method: squash - name: default +- name: merge scala-steward's PRs + conditions: + - author=scala-steward + - body~=labels:.*early-semver-patch + - status-success=Build and Test (ubuntu-latest, 2.13, temurin@8) + - status-success=Build and Test (ubuntu-latest, 2.12, temurin@8) + actions: + merge: {} diff --git a/build.sbt b/build.sbt index 0a371b8..0f4b832 100644 --- a/build.sbt +++ b/build.sbt @@ -1,47 +1,26 @@ -inThisBuild(List( - organization := "com.dwolla", - description := "Adds support for decrypting values in TypeSafe Config files", - homepage := Some(url("https://github.com/Dwolla/scala-secure-config")), - licenses += ("MIT", url("http://opensource.org/licenses/MIT")), - developers := List( - Developer( - "bpholt", - "Brian Holt", - "bholt+github@dwolla.com", - url("https://dwolla.com") - ), +ThisBuild / organization := "com.dwolla" +ThisBuild / description := "Adds support for decrypting values in TypeSafe Config files" +ThisBuild / homepage := Some(url("https://github.com/Dwolla/scala-secure-config")) +ThisBuild / licenses += ("MIT", url("http://opensource.org/licenses/MIT")) +ThisBuild / developers := List( + Developer( + "bpholt", + "Brian Holt", + "bholt+github@dwolla.com", + url("https://dwolla.com") ), - crossScalaVersions := Seq("2.13.14", "2.12.20"), - scalaVersion := crossScalaVersions.value.head, - startYear := Option(2018), - addCompilerPlugin("org.typelevel" %% "kind-projector" % "0.13.3" cross CrossVersion.full), - addCompilerPlugin("com.olegpy" %% "better-monadic-for" % "0.3.1"), - - githubWorkflowBuild := Seq(WorkflowStep.Sbt(List("test", "doc"))), - githubWorkflowJavaVersions := Seq(JavaSpec.temurin("8"), JavaSpec.temurin("11")), - githubWorkflowTargetTags ++= Seq("v*"), - githubWorkflowPublishTargetBranches := - Seq(RefPredicate.StartsWith(Ref.Tag("v"))), - githubWorkflowPublish := Seq( - WorkflowStep.Sbt( - List("ci-release"), - env = Map( - "PGP_PASSPHRASE" -> "${{ secrets.PGP_PASSPHRASE }}", - "PGP_SECRET" -> "${{ secrets.PGP_SECRET }}", - "SONATYPE_PASSWORD" -> "${{ secrets.SONATYPE_PASSWORD }}", - "SONATYPE_USERNAME" -> "${{ secrets.SONATYPE_USERNAME }}" - ) - ) - ), -)) +) +ThisBuild / crossScalaVersions := Seq("2.13.14", "2.12.20") +ThisBuild / scalaVersion := crossScalaVersions.value.head +ThisBuild / startYear := Option(2018) +ThisBuild / tlBaseVersion := "0.4" +ThisBuild / tlJdkRelease := Some(8) lazy val `secure-config` = (project in file(".")) .settings( libraryDependencies ++= { Seq( - "com.github.pureconfig" %% "pureconfig-cats-effect", - ).map(_ % "0.17.1") ++ - Seq( + "com.github.pureconfig" %% "pureconfig-cats-effect" % "0.17.4", "com.chuusai" %% "shapeless" % "2.3.12", "com.dwolla" %% "fs2-aws-java-sdk2" % "3.0.0-RC2", ) diff --git a/project/plugins.sbt b/project/plugins.sbt index adb4b88..5326750 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,3 @@ -addSbtPlugin("com.github.sbt" % "sbt-ci-release" % "1.6.1") -addSbtPlugin("org.typelevel" % "sbt-tpolecat" % "0.5.2") -addSbtPlugin("com.github.sbt" % "sbt-github-actions" % "0.24.0") +addSbtPlugin("org.typelevel" % "sbt-typelevel-ci-release" % "0.7.3") +addSbtPlugin("org.typelevel" % "sbt-typelevel-settings" % "0.7.3") +addSbtPlugin("org.typelevel" % "sbt-typelevel-mergify" % "0.7.3") From 31c6598e658bbd04eb0945afc569f3dfa25c5365 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 25 Sep 2023 15:15:44 -0500 Subject: [PATCH 02/11] update Scala 2.13 to 2.13.12 --- build.sbt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 0f4b832..1c27524 100644 --- a/build.sbt +++ b/build.sbt @@ -10,7 +10,10 @@ ThisBuild / developers := List( url("https://dwolla.com") ), ) -ThisBuild / crossScalaVersions := Seq("2.13.14", "2.12.20") +ThisBuild / crossScalaVersions := Seq( + "2.13.14", + "2.12.20", +) ThisBuild / scalaVersion := crossScalaVersions.value.head ThisBuild / startYear := Option(2018) ThisBuild / tlBaseVersion := "0.4" From eee1869723e71c41c65ddaec24285667e1ad69d5 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 25 Sep 2023 15:16:03 -0500 Subject: [PATCH 03/11] Drop Scala 2.12 support --- .github/workflows/ci.yml | 12 +----------- .mergify.yml | 1 - build.sbt | 1 - 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4ba1028..64cefcc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13, 2.12] + scala: [2.13] java: [temurin@8] runs-on: ${{ matrix.os }} timeout-minutes: 60 @@ -126,16 +126,6 @@ jobs: tar xf targets.tar rm targets.tar - - name: Download target directories (2.12) - uses: actions/download-artifact@v4 - with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.12 - - - name: Inflate target directories (2.12) - run: | - tar xf targets.tar - rm targets.tar - - name: Import signing key if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' env: diff --git a/.mergify.yml b/.mergify.yml index a37af35..a5e5363 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -11,6 +11,5 @@ pull_request_rules: - author=scala-steward - body~=labels:.*early-semver-patch - status-success=Build and Test (ubuntu-latest, 2.13, temurin@8) - - status-success=Build and Test (ubuntu-latest, 2.12, temurin@8) actions: merge: {} diff --git a/build.sbt b/build.sbt index 1c27524..5bfecf7 100644 --- a/build.sbt +++ b/build.sbt @@ -12,7 +12,6 @@ ThisBuild / developers := List( ) ThisBuild / crossScalaVersions := Seq( "2.13.14", - "2.12.20", ) ThisBuild / scalaVersion := crossScalaVersions.value.head ThisBuild / startYear := Option(2018) From 8f2aa281f30e17f07be3bfdc1260ced848d3b5b2 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 11 Dec 2023 14:09:35 -0600 Subject: [PATCH 04/11] Add Scala 3 support --- .github/workflows/ci.yml | 12 +++++++++++- .mergify.yml | 1 + build.sbt | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 64cefcc..81aa1df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13] + scala: [2.13, 3] java: [temurin@8] runs-on: ${{ matrix.os }} timeout-minutes: 60 @@ -126,6 +126,16 @@ jobs: tar xf targets.tar rm targets.tar + - name: Download target directories (3) + uses: actions/download-artifact@v4 + with: + name: target-${{ matrix.os }}-${{ matrix.java }}-3 + + - name: Inflate target directories (3) + run: | + tar xf targets.tar + rm targets.tar + - name: Import signing key if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE == '' env: diff --git a/.mergify.yml b/.mergify.yml index a5e5363..66071e2 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -11,5 +11,6 @@ pull_request_rules: - author=scala-steward - body~=labels:.*early-semver-patch - status-success=Build and Test (ubuntu-latest, 2.13, temurin@8) + - status-success=Build and Test (ubuntu-latest, 3, temurin@8) actions: merge: {} diff --git a/build.sbt b/build.sbt index 5bfecf7..2c2916d 100644 --- a/build.sbt +++ b/build.sbt @@ -12,6 +12,7 @@ ThisBuild / developers := List( ) ThisBuild / crossScalaVersions := Seq( "2.13.14", + "3.3.3", ) ThisBuild / scalaVersion := crossScalaVersions.value.head ThisBuild / startYear := Option(2018) From f578e8efa52739416ea616c9aebbd9014f65fcac Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 25 Sep 2023 15:18:30 -0500 Subject: [PATCH 05/11] switch from Shapeless tagged types to Monix Newtypes this is a step towards Scala 3 support --- README.md | 2 +- build.sbt | 2 +- .../scala/com/dwolla/config/package.scala | 21 +++++++------------ 3 files changed, 10 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 1ea87c7..8e95c56 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![Dwolla/scala-secure-config CI](https://github.com/Dwolla/scala-secure-config/actions/workflows/ci.yml/badge.svg) [![license](https://img.shields.io/github/license/Dwolla/scala-secure-config.svg?style=flat-square)](https://github.com/Dwolla/scala-secure-config/blob/master/LICENSE) -Tagged type and [PureConfig](https://pureconfig.github.io) [ConfigReader](https://github.com/pureconfig/pureconfig/blob/master/core/src/main/scala/pureconfig/ConfigReader.scala) for automatically decrypting encrypted config values in TypeSafe Config files. + [PureConfig](https://pureconfig.github.io) [ConfigReader](https://github.com/pureconfig/pureconfig/blob/master/core/src/main/scala/pureconfig/ConfigReader.scala) for automatically decrypting encrypted config values using AWS KMS. ## Artifacts diff --git a/build.sbt b/build.sbt index 2c2916d..95d8ec4 100644 --- a/build.sbt +++ b/build.sbt @@ -24,7 +24,7 @@ lazy val `secure-config` = (project in file(".")) libraryDependencies ++= { Seq( "com.github.pureconfig" %% "pureconfig-cats-effect" % "0.17.4", - "com.chuusai" %% "shapeless" % "2.3.12", + "io.monix" %% "newtypes-core" % "0.3.0", "com.dwolla" %% "fs2-aws-java-sdk2" % "3.0.0-RC2", ) }, diff --git a/src/main/scala/com/dwolla/config/package.scala b/src/main/scala/com/dwolla/config/package.scala index 6c40c5d..9fca398 100644 --- a/src/main/scala/com/dwolla/config/package.scala +++ b/src/main/scala/com/dwolla/config/package.scala @@ -1,11 +1,10 @@ package com.dwolla -import cats._ -import cats.syntax.all._ -import com.dwolla.fs2aws.kms._ +import cats.* +import cats.syntax.all.* +import com.dwolla.fs2aws.kms.* +import monix.newtypes.NewtypeWrapped import pureconfig.ConfigReader -import shapeless.tag -import shapeless.tag.@@ package object config { private[this] val secureStringRegex = "^SECURE: (.+)".r @@ -15,14 +14,10 @@ package object config { case secureStringRegex(cryptotext) => for { bytes <- decryptionClient.decrypt(cryptotext) - } yield tagSecurableString(bytes) - case s => tagSecurableString(s).pure[F] + } yield SecurableString(bytes) + case s => SecurableString(s).pure[F] } - type SecurableString = String @@ SecurableStringTag - val tagSecurableString: String => SecurableString = tag[SecurableStringTag][String](_) -} - -package config { - trait SecurableStringTag + type SecurableString = SecurableString.Type + object SecurableString extends NewtypeWrapped[String] } From 11868976369ee61ace9bda155e1560103e804c6e Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Thu, 16 Nov 2023 13:24:58 -0600 Subject: [PATCH 06/11] WIP: Switch from AWS SDK to Smithy4s --- build.sbt | 9 ++++++++- project/plugins.sbt | 1 + src/main/scala/com/dwolla/config/package.scala | 16 +++++++++++----- src/main/smithy/kms.smithy | 7 +++++++ 4 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 src/main/smithy/kms.smithy diff --git a/build.sbt b/build.sbt index 95d8ec4..1e46be6 100644 --- a/build.sbt +++ b/build.sbt @@ -25,7 +25,14 @@ lazy val `secure-config` = (project in file(".")) Seq( "com.github.pureconfig" %% "pureconfig-cats-effect" % "0.17.4", "io.monix" %% "newtypes-core" % "0.3.0", - "com.dwolla" %% "fs2-aws-java-sdk2" % "3.0.0-RC2", + "com.disneystreaming.smithy4s" %% "smithy4s-http4s" % smithy4sVersion.value, + "com.disneystreaming.smithy4s" %% "smithy4s-aws-http4s" % smithy4sVersion.value, + "org.typelevel" %% "mouse" % "1.3.1", ) }, + smithy4sAwsSpecs ++= Seq(AWS.kms), // TODO can we put this into its own package to avoid clashing with generated code downstream? + scalacOptions += "-Wconf:src=src_managed/.*:s", + ) + .enablePlugins( + Smithy4sCodegenPlugin, ) diff --git a/project/plugins.sbt b/project/plugins.sbt index 5326750..ca1fdeb 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,3 +1,4 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-ci-release" % "0.7.3") addSbtPlugin("org.typelevel" % "sbt-typelevel-settings" % "0.7.3") addSbtPlugin("org.typelevel" % "sbt-typelevel-mergify" % "0.7.3") +addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.18.24") diff --git a/src/main/scala/com/dwolla/config/package.scala b/src/main/scala/com/dwolla/config/package.scala index 9fca398..96b77e2 100644 --- a/src/main/scala/com/dwolla/config/package.scala +++ b/src/main/scala/com/dwolla/config/package.scala @@ -2,19 +2,25 @@ package com.dwolla import cats.* import cats.syntax.all.* -import com.dwolla.fs2aws.kms.* +import com.amazonaws.kms.{CiphertextType, KMS} import monix.newtypes.NewtypeWrapped +import mouse.all.* import pureconfig.ConfigReader +import smithy4s.Blob package object config { private[this] val secureStringRegex = "^SECURE: (.+)".r - def SecureReader[F[_] : Monad](decryptionClient: KmsAlg[F]): ConfigReader[F[SecurableString]] = + def SecureReader[F[_] : MonadThrow](kms: KMS[F]): ConfigReader[F[SecurableString]] = ConfigReader[String].map { case secureStringRegex(cryptotext) => - for { - bytes <- decryptionClient.decrypt(cryptotext) - } yield SecurableString(bytes) + kms.decrypt(CiphertextType(Blob(cryptotext.getBytes()))) + .map(_.plaintext) // TODO does this need to be base64-decoded? + .liftOptionT + .getOrRaise(new RuntimeException("boom")) // TODO convert to a better exception + .map(_.value.toUTF8String) + .map(SecurableString(_)) + case s => SecurableString(s).pure[F] } diff --git a/src/main/smithy/kms.smithy b/src/main/smithy/kms.smithy new file mode 100644 index 0000000..dfb80ff --- /dev/null +++ b/src/main/smithy/kms.smithy @@ -0,0 +1,7 @@ +$version: "1.0" + +namespace com.dwolla.aws.kms + +use smithy4s.meta#only + +apply com.amazonaws.kms#Decrypt @only From 30f11ab0d1e39c46b89a47476cf16dc8aea0955b Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 23 Sep 2024 15:27:21 -0500 Subject: [PATCH 07/11] modify constructor to only use binary-stable types --- .../scala/com/dwolla/config/package.scala | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/scala/com/dwolla/config/package.scala b/src/main/scala/com/dwolla/config/package.scala index 96b77e2..6a99a30 100644 --- a/src/main/scala/com/dwolla/config/package.scala +++ b/src/main/scala/com/dwolla/config/package.scala @@ -1,27 +1,31 @@ package com.dwolla -import cats.* +import cats.effect.* import cats.syntax.all.* import com.amazonaws.kms.{CiphertextType, KMS} +import fs2.compression.Compression import monix.newtypes.NewtypeWrapped import mouse.all.* import pureconfig.ConfigReader import smithy4s.Blob +import smithy4s.aws.{AwsClient, AwsEnvironment} package object config { private[this] val secureStringRegex = "^SECURE: (.+)".r - def SecureReader[F[_] : MonadThrow](kms: KMS[F]): ConfigReader[F[SecurableString]] = - ConfigReader[String].map { - case secureStringRegex(cryptotext) => - kms.decrypt(CiphertextType(Blob(cryptotext.getBytes()))) - .map(_.plaintext) // TODO does this need to be base64-decoded? - .liftOptionT - .getOrRaise(new RuntimeException("boom")) // TODO convert to a better exception - .map(_.value.toUTF8String) - .map(SecurableString(_)) + def SecureReader[F[_] : Async : Compression](awsEnv: AwsEnvironment[F]): Resource[F, ConfigReader[F[SecurableString]]] = + AwsClient(KMS, awsEnv).map { kms => + ConfigReader[String].map { + case secureStringRegex(cryptotext) => + kms.decrypt(CiphertextType(Blob(cryptotext.getBytes()))) + .map(_.plaintext) // TODO does this need to be base64-decoded? + .liftOptionT + .getOrRaise(new RuntimeException("boom")) // TODO convert to a better exception + .map(_.value.toUTF8String) + .map(SecurableString(_)) - case s => SecurableString(s).pure[F] + case s => SecurableString(s).pure[F] + } } type SecurableString = SecurableString.Type From bcf47df169664143eef6779c96ff06bfc3b1d6d7 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Mon, 23 Sep 2024 16:42:59 -0500 Subject: [PATCH 08/11] add preprocessor to rename the KMS service namespace --- .github/workflows/ci.yml | 1 + .mergify.yml | 8 ++++++ build.sbt | 18 ++++++++++++- ....amazon.smithy.build.ProjectionTransformer | 1 + .../com/dwolla/smithy/ShadeNamespace.scala | 27 +++++++++++++++++++ .../scala/com/dwolla/config/package.scala | 2 +- 6 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer create mode 100644 smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81aa1df..c0e7a9c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -194,4 +194,5 @@ jobs: - name: Submit Dependencies uses: scalacenter/sbt-dependency-submission@v2 with: + modules-ignore: smithy4s-preprocessors_2.12 configs-ignore: test scala-tool scala-doc-tool test-internal diff --git a/.mergify.yml b/.mergify.yml index 66071e2..3e50559 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -14,3 +14,11 @@ pull_request_rules: - status-success=Build and Test (ubuntu-latest, 3, temurin@8) actions: merge: {} +- name: Label smithy4s-preprocessors PRs + conditions: + - files~=^smithy4s-preprocessors/ + actions: + label: + add: + - smithy4s-preprocessors + remove: [] diff --git a/build.sbt b/build.sbt index 1e46be6..84be70a 100644 --- a/build.sbt +++ b/build.sbt @@ -19,6 +19,20 @@ ThisBuild / startYear := Option(2018) ThisBuild / tlBaseVersion := "0.4" ThisBuild / tlJdkRelease := Some(8) +lazy val `smithy4s-preprocessors` = project + .in(file("smithy4s-preprocessors")) + .settings( + scalaVersion := "2.12.13", // 2.12 to match what SBT uses + scalacOptions -= "-source:future", + libraryDependencies ++= { + Seq( + "org.typelevel" %% "cats-core" % "2.10.0", + "software.amazon.smithy" % "smithy-build" % smithy4s.codegen.BuildInfo.smithyVersion, + ) + }, + ) + .enablePlugins(NoPublishPlugin) + lazy val `secure-config` = (project in file(".")) .settings( libraryDependencies ++= { @@ -30,8 +44,10 @@ lazy val `secure-config` = (project in file(".")) "org.typelevel" %% "mouse" % "1.3.1", ) }, - smithy4sAwsSpecs ++= Seq(AWS.kms), // TODO can we put this into its own package to avoid clashing with generated code downstream? + smithy4sAwsSpecs ++= Seq(AWS.kms), scalacOptions += "-Wconf:src=src_managed/.*:s", + Compile / smithy4sModelTransformers += "com.dwolla.smithy.ShadeNamespace", + Compile / smithy4sAllDependenciesAsJars += (`smithy4s-preprocessors` / Compile / packageBin).value, ) .enablePlugins( Smithy4sCodegenPlugin, diff --git a/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer b/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer new file mode 100644 index 0000000..40485c7 --- /dev/null +++ b/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer @@ -0,0 +1 @@ +com.dwolla.smithy.ShadeNamespace diff --git a/smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala b/smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala new file mode 100644 index 0000000..65089ea --- /dev/null +++ b/smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala @@ -0,0 +1,27 @@ +package com.dwolla.smithy + +import cats.syntax.all._ +import software.amazon.smithy.build.{ProjectionTransformer, TransformContext} +import software.amazon.smithy.model.Model +import software.amazon.smithy.model.shapes.Shape + +import java.util.stream.Collectors +import scala.collection.JavaConverters._ + +class ShadeNamespace extends ProjectionTransformer { + override def getName: String = "com.dwolla.smithy.ShadeNamespace" + + private val namespacesToRename: Set[String] = Set("com.amazonaws.kms") + + override def transform(context: TransformContext): Model = { + val renames = + context.getModel + .shapes().collect(Collectors.toList[Shape]).asScala.toList + .map(_.getId) + .filter(id => namespacesToRename.contains(id.getNamespace)) + .fproduct(id => id.withNamespace(s"com.dwolla.smithy_shaded.${id.getNamespace}")) + .toMap.asJava + + context.getTransformer.renameShapes(context.getModel, renames) + } +} diff --git a/src/main/scala/com/dwolla/config/package.scala b/src/main/scala/com/dwolla/config/package.scala index 6a99a30..d2fe56b 100644 --- a/src/main/scala/com/dwolla/config/package.scala +++ b/src/main/scala/com/dwolla/config/package.scala @@ -2,7 +2,7 @@ package com.dwolla import cats.effect.* import cats.syntax.all.* -import com.amazonaws.kms.{CiphertextType, KMS} +import com.dwolla.smithy_shaded.com.amazonaws.kms.{CiphertextType, KMS} import fs2.compression.Compression import monix.newtypes.NewtypeWrapped import mouse.all.* From f53295dfd178e6c843086fe494c641bddd5e8e8c Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Tue, 24 Sep 2024 17:49:50 -0500 Subject: [PATCH 09/11] add Scalafix to mark generated code as package-private --- .github/workflows/ci.yml | 4 +- .mergify.yml | 8 +++ .scalafix.conf | 1 + build.sbt | 24 +++++++- project/plugins.sbt | 1 + .../META-INF/services/scalafix.v1.Rule | 1 + .../smithy4s/PrivatizeGeneratedCode.scala | 57 +++++++++++++++++++ ....amazon.smithy.build.ProjectionTransformer | 2 +- .../{ => config}/smithy/ShadeNamespace.scala | 10 ++-- .../scala/com/dwolla/config/package.scala | 2 +- 10 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 .scalafix.conf create mode 100644 scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule create mode 100644 scalafix/rules/src/main/scala/com/dwolla/scalafix/smithy4s/PrivatizeGeneratedCode.scala rename smithy4s-preprocessors/src/main/scala/com/dwolla/{ => config}/smithy/ShadeNamespace.scala (71%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0e7a9c..5a2e859 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,11 +71,11 @@ jobs: - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) - run: mkdir -p target project/target + run: mkdir -p target scalafix/rules/target project/target - name: Compress target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) - run: tar cf targets.tar target project/target + run: tar cf targets.tar target scalafix/rules/target project/target - name: Upload target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) diff --git a/.mergify.yml b/.mergify.yml index 3e50559..743895c 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -14,6 +14,14 @@ pull_request_rules: - status-success=Build and Test (ubuntu-latest, 3, temurin@8) actions: merge: {} +- name: Label rules PRs + conditions: + - files~=^scalafix/rules/ + actions: + label: + add: + - rules + remove: [] - name: Label smithy4s-preprocessors PRs conditions: - files~=^smithy4s-preprocessors/ diff --git a/.scalafix.conf b/.scalafix.conf new file mode 100644 index 0000000..0b7a1bb --- /dev/null +++ b/.scalafix.conf @@ -0,0 +1 @@ +triggered.rules = [ com.dwolla.scalafix.smithy4s.PrivatizeGeneratedCode ] diff --git a/build.sbt b/build.sbt index 84be70a..0d2b081 100644 --- a/build.sbt +++ b/build.sbt @@ -22,7 +22,7 @@ ThisBuild / tlJdkRelease := Some(8) lazy val `smithy4s-preprocessors` = project .in(file("smithy4s-preprocessors")) .settings( - scalaVersion := "2.12.13", // 2.12 to match what SBT uses + scalaVersion := "2.12.20", // 2.12 to match what SBT uses scalacOptions -= "-source:future", libraryDependencies ++= { Seq( @@ -33,6 +33,22 @@ lazy val `smithy4s-preprocessors` = project ) .enablePlugins(NoPublishPlugin) +// TODO add tests for this +lazy val `scalafix-rules` = project.in(file("scalafix/rules")) + .settings( + libraryDependencies ++= Seq( + "ch.epfl.scala" %% "scalafix-core" % _root_.scalafix.sbt.BuildInfo.scalafixVersion cross CrossVersion.for3Use2_13, + "org.scalameta" %% "munit" % "1.0.0" % Test, + "com.eed3si9n.expecty" %% "expecty" % "0.16.0" % Test, + ), + scalacOptions ~= { + _.filterNot(_ == "-Xfatal-warnings") + }, + ) + +ThisBuild / semanticdbEnabled := true +ThisBuild / semanticdbVersion := scalafixSemanticdb.revision + lazy val `secure-config` = (project in file(".")) .settings( libraryDependencies ++= { @@ -46,9 +62,13 @@ lazy val `secure-config` = (project in file(".")) }, smithy4sAwsSpecs ++= Seq(AWS.kms), scalacOptions += "-Wconf:src=src_managed/.*:s", - Compile / smithy4sModelTransformers += "com.dwolla.smithy.ShadeNamespace", + Compile / smithy4sModelTransformers += "com.dwolla.config.smithy.ShadeNamespace", Compile / smithy4sAllDependenciesAsJars += (`smithy4s-preprocessors` / Compile / packageBin).value, + Compile / smithy4sSmithyLibrary := false, + Compile / scalafix / unmanagedSources := (Compile / sources).value, + scalafixOnCompile := true, ) .enablePlugins( Smithy4sCodegenPlugin, ) + .dependsOn(`scalafix-rules` % ScalafixConfig) diff --git a/project/plugins.sbt b/project/plugins.sbt index ca1fdeb..fc60823 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -2,3 +2,4 @@ addSbtPlugin("org.typelevel" % "sbt-typelevel-ci-release" % "0.7.3") addSbtPlugin("org.typelevel" % "sbt-typelevel-settings" % "0.7.3") addSbtPlugin("org.typelevel" % "sbt-typelevel-mergify" % "0.7.3") addSbtPlugin("com.disneystreaming.smithy4s" % "smithy4s-sbt-codegen" % "0.18.24") +addSbtPlugin("ch.epfl.scala" % "sbt-scalafix" % "0.12.1") diff --git a/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule new file mode 100644 index 0000000..2a6e1a7 --- /dev/null +++ b/scalafix/rules/src/main/resources/META-INF/services/scalafix.v1.Rule @@ -0,0 +1 @@ +com.dwolla.scalafix.smithy4s.PrivatizeGeneratedCode diff --git a/scalafix/rules/src/main/scala/com/dwolla/scalafix/smithy4s/PrivatizeGeneratedCode.scala b/scalafix/rules/src/main/scala/com/dwolla/scalafix/smithy4s/PrivatizeGeneratedCode.scala new file mode 100644 index 0000000..dc631c9 --- /dev/null +++ b/scalafix/rules/src/main/scala/com/dwolla/scalafix/smithy4s/PrivatizeGeneratedCode.scala @@ -0,0 +1,57 @@ +package com.dwolla.scalafix.smithy4s + +import com.dwolla.scalafix.smithy4s.PrivatizeGeneratedCode.{basePackage, packageScope} +import scalafix.v1 +import scalafix.v1.* + +import scala.annotation.nowarn +import scala.meta.* +import scala.meta.Mod.Private +import scala.meta.internal.semanticdb.Scala.* + +@nowarn // due to reflectiveCalls being unused on Scala 2 and deprecated but needed on Scala 3 +class PrivatizeGeneratedCode extends SemanticRule("com.dwolla.scalafix.smithy4s.PrivatizeGeneratedCode") { + import scala.language.reflectiveCalls + + override def description: String = s"Adds private[$packageScope] to members in the $basePackage package" + + private type HasMods = {def mods: List[Mod]} + + private def isMemberOfCorrectPackage(t: Defn)(implicit doc: SemanticDocument): Boolean = + t.symbol.owner.value.startsWith(basePackage) + + private def isAlreadyPrivate[T <: Defn & HasMods](t: T): Boolean = + t.mods.exists(_.is[Private]) + + private def isDefinedAtPackageLevel(t: Defn)(implicit doc: SemanticDocument): Boolean = + t.symbol.owner.value.isPackage || t.symbol.owner.value.endsWith("package.") + + private def shouldBePrivate[T <: Defn & HasMods](t: T) + (implicit doc: SemanticDocument): Boolean = + isMemberOfCorrectPackage(t) && !isAlreadyPrivate(t) && isDefinedAtPackageLevel(t) + + override def fix(implicit doc: SemanticDocument): v1.Patch = { + doc + .tree + .collect { + case t: Defn.Type if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + case t: Defn.Val if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + case t: Defn.Def if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + case t: Defn.Object if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + case t: Defn.Class if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + case t: Defn.Trait if shouldBePrivate(t) => + Patch.addLeft(t, s"private[$packageScope] ") + } + .asPatch + } +} + +object PrivatizeGeneratedCode { + val packageScope: String = "config" + val basePackage = (s"com/dwolla/$packageScope/smithy_shaded") +} diff --git a/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer b/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer index 40485c7..2dee4ec 100644 --- a/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer +++ b/smithy4s-preprocessors/src/main/resources/META-INF/services/software.amazon.smithy.build.ProjectionTransformer @@ -1 +1 @@ -com.dwolla.smithy.ShadeNamespace +com.dwolla.config.smithy.ShadeNamespace diff --git a/smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala b/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala similarity index 71% rename from smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala rename to smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala index 65089ea..82a3cf2 100644 --- a/smithy4s-preprocessors/src/main/scala/com/dwolla/smithy/ShadeNamespace.scala +++ b/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala @@ -1,15 +1,15 @@ -package com.dwolla.smithy +package com.dwolla.config.smithy -import cats.syntax.all._ +import cats.syntax.all.* import software.amazon.smithy.build.{ProjectionTransformer, TransformContext} import software.amazon.smithy.model.Model import software.amazon.smithy.model.shapes.Shape import java.util.stream.Collectors -import scala.collection.JavaConverters._ +import scala.collection.JavaConverters.* class ShadeNamespace extends ProjectionTransformer { - override def getName: String = "com.dwolla.smithy.ShadeNamespace" + override def getName: String = "com.dwolla.config.smithy.ShadeNamespace" private val namespacesToRename: Set[String] = Set("com.amazonaws.kms") @@ -19,7 +19,7 @@ class ShadeNamespace extends ProjectionTransformer { .shapes().collect(Collectors.toList[Shape]).asScala.toList .map(_.getId) .filter(id => namespacesToRename.contains(id.getNamespace)) - .fproduct(id => id.withNamespace(s"com.dwolla.smithy_shaded.${id.getNamespace}")) + .fproduct(id => id.withNamespace(s"com.dwolla.config.smithy_shaded.${id.getNamespace}")) .toMap.asJava context.getTransformer.renameShapes(context.getModel, renames) diff --git a/src/main/scala/com/dwolla/config/package.scala b/src/main/scala/com/dwolla/config/package.scala index d2fe56b..c4390df 100644 --- a/src/main/scala/com/dwolla/config/package.scala +++ b/src/main/scala/com/dwolla/config/package.scala @@ -2,7 +2,7 @@ package com.dwolla import cats.effect.* import cats.syntax.all.* -import com.dwolla.smithy_shaded.com.amazonaws.kms.{CiphertextType, KMS} +import com.dwolla.config.smithy_shaded.com.amazonaws.kms.{CiphertextType, KMS} import fs2.compression.Compression import monix.newtypes.NewtypeWrapped import mouse.all.* From 0b48305ac9e25604bb23d3037be96d89984fcb12 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Tue, 24 Sep 2024 18:11:57 -0500 Subject: [PATCH 10/11] use FlattenNamespaces instead of hacking our own via renameShapes --- .../dwolla/config/smithy/ShadeNamespace.scala | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala b/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala index 82a3cf2..8337d7f 100644 --- a/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala +++ b/smithy4s-preprocessors/src/main/scala/com/dwolla/config/smithy/ShadeNamespace.scala @@ -1,27 +1,28 @@ package com.dwolla.config.smithy -import cats.syntax.all.* +import software.amazon.smithy.build.transforms.FlattenNamespaces import software.amazon.smithy.build.{ProjectionTransformer, TransformContext} import software.amazon.smithy.model.Model -import software.amazon.smithy.model.shapes.Shape - -import java.util.stream.Collectors -import scala.collection.JavaConverters.* +import software.amazon.smithy.model.node.ObjectNode class ShadeNamespace extends ProjectionTransformer { override def getName: String = "com.dwolla.config.smithy.ShadeNamespace" - private val namespacesToRename: Set[String] = Set("com.amazonaws.kms") - - override def transform(context: TransformContext): Model = { - val renames = - context.getModel - .shapes().collect(Collectors.toList[Shape]).asScala.toList - .map(_.getId) - .filter(id => namespacesToRename.contains(id.getNamespace)) - .fproduct(id => id.withNamespace(s"com.dwolla.config.smithy_shaded.${id.getNamespace}")) - .toMap.asJava + val sourceService: String = "TrentService" + val sourceNamespace: String = "com.amazonaws.kms" + val targetNamespacePrefix: String = "com.dwolla.config.smithy_shaded" - context.getTransformer.renameShapes(context.getModel, renames) - } + override def transform(context: TransformContext): Model = + new FlattenNamespaces().transform { + context + .toBuilder + .projectionName(getName) + .settings { + ObjectNode.builder() + .withMember("namespace", s"$targetNamespacePrefix.$sourceNamespace") + .withMember("service", s"$sourceNamespace#$sourceService") + .build() + } + .build() + } } From 5ce6549ffed312f6dc62e90324e8b3add715c8e9 Mon Sep 17 00:00:00 2001 From: Brian Holt Date: Tue, 24 Sep 2024 19:27:32 -0500 Subject: [PATCH 11/11] add tests to assert that code outside com.dwolla.config doesn't have access to the generated code --- .github/workflows/ci.yml | 11 +------ build.sbt | 4 +++ .../bincompat/ShadedGeneratedSmithySpec.scala | 21 +++++++++++++ .../bincompat/ShadedGeneratedSmithySpec.scala | 31 +++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) create mode 100644 src/test/scala-2/bincompat/ShadedGeneratedSmithySpec.scala create mode 100644 src/test/scala-3/bincompat/ShadedGeneratedSmithySpec.scala diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a2e859..94635f8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,16 +58,7 @@ jobs: - name: Check that workflows are up to date run: sbt githubWorkflowCheck - - name: Test - run: sbt '++ ${{ matrix.scala }}' test - - - name: Check binary compatibility - if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' - run: sbt '++ ${{ matrix.scala }}' mimaReportBinaryIssues - - - name: Generate API documentation - if: matrix.java == 'temurin@8' && matrix.os == 'ubuntu-latest' - run: sbt '++ ${{ matrix.scala }}' doc + - run: sbt '++ ${{ matrix.scala }}' compile test - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v')) diff --git a/build.sbt b/build.sbt index 0d2b081..bfff201 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +import org.typelevel.sbt.gha.WorkflowStep.Sbt + ThisBuild / organization := "com.dwolla" ThisBuild / description := "Adds support for decrypting values in TypeSafe Config files" ThisBuild / homepage := Some(url("https://github.com/Dwolla/scala-secure-config")) @@ -18,6 +20,7 @@ ThisBuild / scalaVersion := crossScalaVersions.value.head ThisBuild / startYear := Option(2018) ThisBuild / tlBaseVersion := "0.4" ThisBuild / tlJdkRelease := Some(8) +ThisBuild / githubWorkflowBuild := List(Sbt(List("compile", "test"))) lazy val `smithy4s-preprocessors` = project .in(file("smithy4s-preprocessors")) @@ -58,6 +61,7 @@ lazy val `secure-config` = (project in file(".")) "com.disneystreaming.smithy4s" %% "smithy4s-http4s" % smithy4sVersion.value, "com.disneystreaming.smithy4s" %% "smithy4s-aws-http4s" % smithy4sVersion.value, "org.typelevel" %% "mouse" % "1.3.1", + "org.scalameta" %% "munit" % "1.0.2" % Test, ) }, smithy4sAwsSpecs ++= Seq(AWS.kms), diff --git a/src/test/scala-2/bincompat/ShadedGeneratedSmithySpec.scala b/src/test/scala-2/bincompat/ShadedGeneratedSmithySpec.scala new file mode 100644 index 0000000..59940d8 --- /dev/null +++ b/src/test/scala-2/bincompat/ShadedGeneratedSmithySpec.scala @@ -0,0 +1,21 @@ +package bincompat + +import munit.* + +class ShadedGeneratedSmithySpec extends FunSuite { + test("we don't have access to the generated KMS objects in their original package") { + assertNoDiff(compileErrors("""com.amazonaws.kms.KMS.id == smithy4s.ShapeId("com.amazonaws.kms", "TrentService")"""), + """error: object amazonaws is not a member of package com + |com.amazonaws.kms.KMS.id == smithy4s.ShapeId("com.amazonaws.kms", "TrentService") + | ^ + |""".stripMargin) + } + + test("we don't have access to the generated KMS objects in the shaded package") { + assertNoDiff(compileErrors("""assertEquals(com.dwolla.config.smithy_shaded.com.amazonaws.kms.KMS.id, smithy4s.ShapeId("com.dwolla.config.smithy_shaded.com.amazonaws.kms", "TrentService"))"""), + """error: value KMS in package kms cannot be accessed as a member of object com.dwolla.config.smithy_shaded.com.amazonaws.kms.package from class ShadedGeneratedSmithySpec in package bincompat + |assertEquals(com.dwolla.config.smithy_shaded.com.amazonaws.kms.KMS.id, smithy4s.ShapeId("com.dwolla.config.smithy_shaded.com.amazonaws.kms", "TrentService")) + | ^ + |""".stripMargin) + } +} diff --git a/src/test/scala-3/bincompat/ShadedGeneratedSmithySpec.scala b/src/test/scala-3/bincompat/ShadedGeneratedSmithySpec.scala new file mode 100644 index 0000000..da93a0b --- /dev/null +++ b/src/test/scala-3/bincompat/ShadedGeneratedSmithySpec.scala @@ -0,0 +1,31 @@ +package bincompat + +import munit.* + +class ShadedGeneratedSmithySpec extends FunSuite { + test("we don't have access to the generated KMS objects in their original package") { + assertNoDiff(compileErrors("""com.amazonaws.kms.KMS.id == smithy4s.ShapeId("com.amazonaws.kms", "TrentService")"""), + """error: + |value amazonaws is not a member of com, but could be made available as an extension method. + | + |The following import might make progress towards fixing the problem: + | + | import munit.Clue.generate + | + |com.amazonaws.kms.KMS.id == smithy4s.ShapeId("com.amazonaws.kms", "TrentService") + | ^ + |""".stripMargin) + } + + test("we don't have access to the generated KMS objects in the shaded package") { + assertNoDiff(compileErrors("""assertEquals(com.dwolla.config.smithy_shaded.com.amazonaws.kms.KMS.id, smithy4s.ShapeId("com.dwolla.config.smithy_shaded.com.amazonaws.kms", "TrentService"))"""), + """error: + |value KMS in package com.dwolla.config.smithy_shaded.com².amazonaws.kms cannot be accessed as a member of com.dwolla.config.smithy_shaded.com².amazonaws.kms.type from class ShadedGeneratedSmithySpec. + | + |where: com is a package + | com² is a package in package com.dwolla.config.smithy_shaded + |assertEquals(com.dwolla.config.smithy_shaded.com.amazonaws.kms.KMS.id, smithy4s.ShapeId("com.dwolla.config.smithy_shaded.com.amazonaws.kms", "TrentService")) + | ^ + |""".stripMargin) + } +}