Skip to content

Tests ensuring the server integrity when running third-party code #40

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

Merged
merged 2 commits into from
Nov 2, 2016
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ project/plugins/project/
# ensime
.ensime
.ensime_cache/
ensime.sbt

# Scala-IDE specific
.scala_dependencies
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ after_success:
echo "Deploying to Heroku";
docker login [email protected] --password=$heroku_token registry.heroku.com;
sbt dockerBuildAndPush;
sbt smoketests/test;
fi
- if [ "$TRAVIS_PULL_REQUEST" = "true" ]; then
echo "Not in master branch, skipping deploy and release";
Expand Down
18 changes: 17 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,22 @@ lazy val `evaluator-server` = (project in file("server"))
.settings(dockerSettings)
.settings(compilerDependencySettings: _*)

lazy val `smoketests` = (project in file("smoketests"))
.dependsOn(`evaluator-server`)
.settings(
name := "evaluator-server-smoke-tests",
libraryDependencies ++= Seq(
"org.scalatest" %% "scalatest" % v('scalaTest) % "test",
"org.http4s" %% "http4s-blaze-client" % v('http4s),
"org.http4s" %% "http4s-circe" % v('http4s),
"io.circe" %% "circe-core" % v('circe),
"io.circe" %% "circe-generic" % v('circe),
"io.circe" %% "circe-parser" % v('circe),
"com.pauldijou" %% "jwt-core" % v('jwtcore)
)

)

onLoad in Global := (Command.process("project evaluator-server", _: State)) compose (onLoad in Global).value
addCommandAlias("publishSignedAll", ";evaluator-sharedJS/publishSigned;evaluator-sharedJVM/publishSigned;evaluator-clientJS/publishSigned;evaluator-clientJVM/publishSigned")

Expand All @@ -99,7 +115,7 @@ lazy val dockerSettings = Seq(
.run("useradd", "-m", "evaluator")
.user("evaluator")
.add(artifact, artifactTargetPath)
.cmdRaw(s"java -Dhttp.port=$$PORT -jar $artifactTargetPath")
.cmdRaw(s"java -Dhttp.port=$$PORT -Deval.auth.secretKey=$$EVAL_SECRET_KEY -jar $artifactTargetPath")
},
imageNames in docker := Seq(ImageName(repository = "registry.heroku.com/scala-evaluator-sandbox/web"))
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.scalaexercises.evaluator

import org.scalatest._
import org.http4s._
import org.http4s.client.blaze._
import org.http4s.circe._
import io.circe.generic.auto._
import scalaz.concurrent.Task
import scala.concurrent.duration._

import pdi.jwt.{Jwt, JwtAlgorithm}

class Smoketests extends FunSpec with Matchers with CirceInstances {

case class EvaluatorResponse(msg: String,
value: String,
valueType: String,
compilationInfos: Map[String, String])

implicit val decoder: EntityDecoder[EvaluatorResponse] =
jsonOf[EvaluatorResponse]

val validToken = Jwt.encode(
"""{"user": "scala-exercises"}""",
auth.secretKey,
JwtAlgorithm.HS256)

def makeRequest(code: String)(
expectation: EvaluatorResponse => Unit,
failExpectation: Throwable => Unit = fail(_)): Unit = {

val request = new Request(
method = Method.POST,
uri = Uri.uri("http://scala-evaluator-sandbox.herokuapp.com/eval"),
headers = Headers(headers)
).withBody(
s"""{"resolvers" : [], "dependencies" : [], "code" : "$code"}""")

val task = client.expect[EvaluatorResponse](request)

val response = task.unsafePerformSyncAttemptFor(60.seconds)
response.fold(failExpectation, expectation)
}

val headers = List(
Header("Content-Type", "application/json").parsed,
Header("x-scala-eval-api-token", validToken).parsed
)

val client = PooledHttp1Client()

describe("Querying the /eval endpoint") {
it("should succeed for a simple request") {
makeRequest("1 + 1") { evaluatorResponse =>
evaluatorResponse.value shouldBe "2"
}
}

it("should continue to work after calling System.exit") {
makeRequest("System.exit(1)")(
expectation = _ => fail("Request should not succeed"),
failExpectation = _ => ()
)

makeRequest("1 + 1") { evaluatorResponse =>
evaluatorResponse.value shouldBe "2"
}
}

it("should not expose sensitive details by calling sys.env") {
val keywords = List("password", "key", "api")
makeRequest("sys.env") { evaluatorResponse =>
keywords.foreach(kw =>
evaluatorResponse.value.contains(kw) shouldBe false)
}

}
}
}