Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Accept authenticated proxy params via Scala CLI config file #1593

Merged
merged 3 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions modules/cli/src/main/scala/scala/cli/ScalaCli.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package scala.cli

import coursier.proxy.SetupProxy
import sun.misc.{Signal, SignalHandler}

import java.io.{ByteArrayOutputStream, File, PrintStream}
Expand Down Expand Up @@ -173,7 +172,7 @@ object ScalaCli {

(new BouncycastleSignerMaker).maybeInit()

SetupProxy.setup()
coursier.Resolve.proxySetup()

// Getting killed by SIGPIPE quite often when on musl (in the "static" native
// image), but also sometimes on glibc, or even on macOS, when we use domain
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ package scala.cli.integration

import com.eed3si9n.expecty.Expecty.expect

import java.io.File
import java.util.Locale

import scala.util.Properties

class ConfigTests extends ScalaCliSuite {
Expand Down Expand Up @@ -104,30 +101,9 @@ class ConfigTests extends ScalaCliSuite {
if (!Properties.isWin)
os.perms.set(confDir, "rwx------")

val extraEnv = {
val (pathVarName, currentPath) = sys.env
.find(_._1.toLowerCase(Locale.ROOT) == "path")
.getOrElse(("PATH", ""))
val binDir = root / "bin"
if (Properties.isWin) {
val script =
s"""@echo off
|"${TestUtil.cs}" %*
|""".stripMargin
os.write(binDir / "cs.bat", script, createFolders = true)
}
else {
val script =
s"""#!/usr/bin/env bash
|exec "${TestUtil.cs}" "$$@"
|""".stripMargin
os.write(binDir / "cs", script, "rwxr-xr-x", createFolders = true)
}
Map(
"SCALA_CLI_CONFIG" -> confFile.toString,
pathVarName -> s"$binDir${File.pathSeparator}$currentPath"
)
}
val extraEnv =
Map("SCALA_CLI_CONFIG" -> confFile.toString) ++
TestUtil.putCsInPathViaEnv(root / "bin")

val res = os.proc(TestUtil.cli, "config", "httpProxy.address")
.call(cwd = root, env = extraEnv)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -733,7 +733,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
sudoTest()
}

def authProxyTest(): Unit = {
def authProxyTest(legacySetup: Boolean): Unit = {
val okDir = os.rel / "ok"
val wrongDir = os.rel / "wrong"
val inputs = TestInputs(
Expand All @@ -759,10 +759,44 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
s"-D$scheme.proxyProtocol=http"
)
}
val proxyArgs = authProperties("localhost", 9083, "jack", "insecure")
val wrongProxyArgs = authProperties("localhost", 9084, "wrong", "nope")
val image = Constants.authProxyTestImage
val proxyArgs =
if (legacySetup) authProperties("localhost", 9083, "jack", "insecure")
else Nil
val wrongProxyArgs =
if (legacySetup) authProperties("localhost", 9084, "wrong", "nope")
else Nil
def setupProxyConfig(
cwd: os.Path,
env: Map[String, String],
host: String,
port: Int,
user: String,
password: String
): Unit = {
os.proc(TestUtil.cli, "config", "httpProxy.address", s"http://$host:$port")
.call(cwd = cwd, env = env)
os.proc(TestUtil.cli, "config", "httpProxy.user", s"value:$user")
.call(cwd = cwd, env = env)
os.proc(TestUtil.cli, "config", "httpProxy.password", s"value:$password")
.call(cwd = cwd, env = env)
}
val image = Constants.authProxyTestImage
inputs.fromRoot { root =>
val configDir = root / "configs"
os.makeDir(configDir, "rwx------")
val configFile = configDir / "config.json"
val wrongConfigFile = configDir / "wrong-config.json"
val (configEnv, wrongConfigEnv) =
if (legacySetup)
(Map.empty[String, String], Map.empty[String, String])
else {
val csEnv = TestUtil.putCsInPathViaEnv(root / "bin")
val configEnv0 = Map("SCALA_CLI_CONFIG" -> configFile.toString) ++ csEnv
val wrongConfigEnv0 = Map("SCALA_CLI_CONFIG" -> wrongConfigFile.toString) ++ csEnv
setupProxyConfig(root, configEnv0, "localhost", 9083, "jack", "insecure")
setupProxyConfig(root, wrongConfigEnv0, "localhost", 9084, "wrong", "nope")
(configEnv0, wrongConfigEnv0)
}
DockerServer.withServer(image, root.toString, 80 -> 9083) { _ =>
DockerServer.withServer(image, root.toString, 80 -> 9084) { _ =>

Expand All @@ -775,7 +809,7 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
"--cache",
os.rel / "tmp-cache-ok"
)
.call(cwd = root / okDir)
.call(cwd = root / okDir, env = configEnv)
val okOutput = okRes.out.trim()
expect(okOutput == "Hello proxy")

Expand All @@ -788,7 +822,12 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
"--cache",
os.rel / "tmp-cache-wrong"
)
.call(cwd = root / wrongDir, mergeErrIntoOut = true, check = false)
.call(
cwd = root / wrongDir,
env = wrongConfigEnv,
mergeErrIntoOut = true,
check = false
)
val wrongOutput = wrongRes.out.trim()
expect(wrongRes.exitCode == 1)
expect(wrongOutput.contains(
Expand All @@ -799,14 +838,21 @@ abstract class RunTestDefinitions(val scalaVersionOpt: Option[String])
}
}

def runAuthProxyTest: Boolean =
def runAuthProxyTests: Boolean =
Properties.isLinux || (Properties.isMac && !TestUtil.isCI)
if (runAuthProxyTest)
if (runAuthProxyTests) {
test("auth proxy (legacy)") {
TestUtil.retry() {
authProxyTest(legacySetup = true)
}
}

test("auth proxy") {
TestUtil.retry() {
authProxyTest()
authProxyTest(legacySetup = false)
}
}
}

test("UTF-8") {
val message = "Hello from TestÅÄÖåäö"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import os.{CommandResult, Path}

import java.io.File
import java.net.ServerSocket
import java.util.Locale
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.{ExecutorService, Executors, ScheduledExecutorService, ThreadFactory}

Expand Down Expand Up @@ -222,4 +223,32 @@ object TestUtil {
}
}
}

def putCsInPathViaEnv(binDir: os.Path): Map[String, String] = {

val (pathVarName, currentPath) = sys.env
.find(_._1.toLowerCase(Locale.ROOT) == "path")
.getOrElse(("PATH", ""))
if (Properties.isWin) {
val dest = binDir / "cs.bat"
if (!os.exists(dest)) {
val script =
s"""@echo off
|"${TestUtil.cs}" %*
|""".stripMargin
os.write(dest, script, createFolders = true)
}
}
else {
val dest = binDir / "cs"
if (!os.exists(dest)) {
val script =
s"""#!/usr/bin/env bash
|exec "${TestUtil.cs}" "$$@"
|""".stripMargin
os.write(dest, script, "rwxr-xr-x", createFolders = true)
}
}
Map(pathVarName -> s"$binDir${File.pathSeparator}$currentPath")
}
}
2 changes: 1 addition & 1 deletion website/docs/guides/configuration.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Configuration
sidebar_position: 9
sidebar_position: 7
---

`scala-cli` can be configured in two ways:
Expand Down
50 changes: 50 additions & 0 deletions website/docs/guides/proxies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: Proxies
sidebar_position: 8
---

## HTTP proxies

### Configuration

If you can only download artifacts through a proxy, you need to configure it beforehand, like
```text
scala-cli config httpProxy.address http://proxy.company.com
```

Replace `proxy.company.com` by the address of your proxy.

Change `http://` to `https://` if your proxy is accessible via HTTPS.

### Authentication

If your proxy requires authentication, set your user and password with
```text
scala-cli config httpProxy.user _encoded_user_
scala-cli config httpProxy.password _encoded_password_
```

Replace `_encoded_user_` and `_encoded_password_` by your actual user and password, following
the [password option format](../reference/password-options.md). They should typically look like
`env:ENV_VAR_NAME`, `file:/path/to/file`, or `command:command to run`.

## Default repositories

If you don't rely on proxies, but rather download artifacts through different Maven repositories,
set those repositories like:
```text
scala-cli config repositories.default https://first-repo.company.com https://second-repo.company.com
```

## Mirrors

If you're fine directly downloading artifacts from the internet, but would rather have some
repositories requests go through a repository of yours, configure mirror repositories, like
```text
scala-cli config repositories.mirrors https://repo1.maven.org/maven2=https://repository.company.com/maven
```

To have all requests to a Maven repository go through a repository of yours, do
```text
scala-cli config repositories.mirrors maven:*=https://repository.company.com/maven
```