Skip to content

Commit

Permalink
Remove warning about missing password in config, prevent secret value…
Browse files Browse the repository at this point in the history
…s leaking to publish-conf.scala
  • Loading branch information
MaciejG604 committed Apr 4, 2023
1 parent f0e7f2a commit a0570a0
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 22 deletions.
Expand Up @@ -19,4 +19,14 @@ object WarningMessages {

def experimentalConfigKeyUsed(name: String): String =
experimentalFeatureUsed(s"The '$name' configuration key")

def rawValueNotWrittenToPublishFile(
rawValue: String,
valueName: String,
directiveName: String
): String =
s"""The value of $valueName ${Console.BOLD}will not${Console.RESET} be written to a potentially public file!
|Provide it as an option to the publish subcommand with:
| $directiveName value:$rawValue
|""".stripMargin
}
Expand Up @@ -11,6 +11,7 @@ import scala.build.EitherCps.{either, value}
import scala.build.Logger
import scala.build.Ops.*
import scala.build.errors.{BuildException, CompositeBuildException, MalformedCliInputError}
import scala.build.internal.util.WarningMessages
import scala.build.options.publish.ConfigPasswordOption
import scala.build.options.publish.ConfigPasswordOption.*
import scala.build.options.PublishOptions as BPublishOptions
Expand Down Expand Up @@ -321,8 +322,6 @@ final case class PgpSecretKeyCheck(

if (keysFromConfig.publicKeyOpt.isEmpty)
logger.message(" warning: no PGP public key found in config")
if (keysFromConfig.secretKeyPasswordOpt.isEmpty)
logger.message(" warning: no PGP secret key password found in config")

(keysFromConfig, true)
}
Expand Down Expand Up @@ -392,34 +391,50 @@ final case class PgpSecretKeyCheck(
scala.util.Try(path.relativeTo(os.pwd))
.map(p => s"file:${p.toString}")
.getOrElse(optionValue)

}
else optionValue
case ConfigOption(fullName) => s"config:$fullName"
}

val passwordDirectives = getDirectiveValue(setupKeys.secretKeyPasswordOpt).map {
"publish.secretKeyPassword" -> _
}.toSeq

val secretKeyDirValue = getDirectiveValue(setupKeys.secretKeyOpt)
val rawValueRegex = "^value:(.*)".r

// Prevent potential leakage of a secret value
val passwordDirectives = getDirectiveValue(setupKeys.secretKeyPasswordOpt)
.flatMap {
case rawValueRegex(rawValue) =>
logger.diagnostic(
WarningMessages.rawValueNotWrittenToPublishFile(
rawValue,
"PGP password",
"--secret-key-password"
)
)
None
case secretOption => Some("publish.secretKeyPassword" -> secretOption)
}
.toSeq

// Prevent potential leakage of a secret value
val secretKeyDirValue = getDirectiveValue(setupKeys.secretKeyOpt).flatMap {
case rawValueRegex(rawValue) =>
logger.diagnostic(
WarningMessages.rawValueNotWrittenToPublishFile(
rawValue,
"PGP secret key",
"--secret-key"
)
)
None
case secretOption => Some(secretOption)
}

// This is safe to be publicly available
val publicKeyDirective = getDirectiveValue(setupKeys.publicKeyOpt).map {
"publish.publicKey" -> _
}.toSeq

val extraDirectives = passwordDirectives ++ publicKeyDirective

if (passwordDirectives.exists(_._2.startsWith("value:")))
logger.diagnostic(
"The secret value of PGP private key password will be written to a potentially public file!"
)

if (secretKeyDirValue.exists(_.startsWith("value:")))
logger.diagnostic(
"The secret value of PGP private key will be written to a potentially public file!"
)

OptionCheck.DefaultValue(
() => uploadKey(publicKeyOpt).map(_ => secretKeyDirValue),
extraDirectives,
Expand Down
Expand Up @@ -439,7 +439,19 @@ class PublishSetupTests extends ScalaCliSuite {
}
}

test("local secret value written") {
test("local secret value NOT written") {
val expectedDirectives = Map(
"publish.versionControl" -> Seq(s"github:$ghUserName/tests"),
"publish.organization" -> Seq(s"io.github.$ghUserName"),
"publish.developer" -> Seq(s"$devName|$devMail|$devUrl"),
"publish.repository" -> Seq("central-s01"),
"publish.url" -> Seq(s"https://github.com/$ghUserName/tests"),
"publish.name" -> Seq(projName),
"publish.computeVersion" -> Seq("git:tag"),
"publish.license" -> Seq("Apache-2.0")
// SHOULD NOT BE HERE "publish.secretKey" -> Seq("value:whatever")
)

testInputs.fromRoot { root =>
configSetup(root / configFile, root)
gitInit(root / projDir)
Expand All @@ -457,11 +469,22 @@ class PublishSetupTests extends ScalaCliSuite {
cwd = root,
mergeErrIntoOut = true,
env = envs
)
).out.text()

expect(res.out.text().contains(
"The secret value of PGP private key will be written to a potentially public file!"
expect(res.contains(
s"The value of PGP secret key ${Console.BOLD}will not${Console.RESET} be written to a potentially public file!"
))

val ghSecrets = res
.linesIterator
.filter(_.startsWith("Would have set GitHub secret "))
.map(_.stripPrefix("Would have set GitHub secret "))
.toSet
val directives0 = directives(os.read(root / projDir / "publish-conf.scala"))
expect(directives0 == expectedDirectives)
expect(ghSecrets.isEmpty)
expect(!res.contains("found keys in config"))
expect(res.contains("Warning: no public key passed, not checking"))
}
}

Expand Down

0 comments on commit a0570a0

Please sign in to comment.