diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..7eb43ba --- /dev/null +++ b/.dockerignore @@ -0,0 +1,6 @@ +# flyctl launch added from .gitignore + +**/.DS_Store +**/*.class +**/target +fly.toml diff --git a/src/main/kotlin/gov/nist/secauto/oscal/tools/server/OscalVerticle.kt b/src/main/kotlin/gov/nist/secauto/oscal/tools/server/OscalVerticle.kt index 9ddb874..9dd3e3c 100644 --- a/src/main/kotlin/gov/nist/secauto/oscal/tools/server/OscalVerticle.kt +++ b/src/main/kotlin/gov/nist/secauto/oscal/tools/server/OscalVerticle.kt @@ -44,7 +44,7 @@ class OscalVerticle : CoroutineVerticle() { val options = OpenAPILoaderOptions() val routerBuilder = RouterBuilder.create(vertx, "openapi.yaml", options).coAwait() logger.info("Router builder created") - routerBuilder.operation("oscal").handler { ctx -> handleCliRequest(ctx) } + routerBuilder.operation("validate").handler { ctx -> handleValidateRequest(ctx) } val router = routerBuilder.createRouter() router.route("/*").handler(StaticHandler.create("webroot")) return router @@ -61,15 +61,15 @@ class OscalVerticle : CoroutineVerticle() { } } - private fun handleCliRequest(ctx: RoutingContext) { + private fun handleValidateRequest(ctx: RoutingContext) { launch { try { logger.info("Handling CLI request") - val command = ctx.queryParam("command").firstOrNull() - if (command != null) { + val content = ctx.queryParam("content").firstOrNull() + if (content != null) { // Use async for parallelism val result = async { - executeCommand(parseCommandToArgs(command)) + executeCommand(parseCommandToArgs("validate "+content)) }.await() // Wait for the result of the async execution logger.info(result.second) sendSuccessResponse(ctx, result.first, result.second) @@ -172,10 +172,11 @@ class OscalVerticle : CoroutineVerticle() { """.trimIndent() } private fun sendSuccessResponse(ctx: RoutingContext, exitStatus: ExitStatus, sarifFilePath: String) { + val fileContent = File(sarifFilePath).readText() ctx.response() .setStatusCode(200) // HTTP 200 OK .putHeader("Content-Type", "application/json") - .sendFile(sarifFilePath) + .end(fileContent) } private fun sendErrorResponse(ctx: RoutingContext, statusCode: Int, message: String) { diff --git a/src/main/resources/openapi.yaml b/src/main/resources/openapi.yaml index 3c5084a..52c9307 100644 --- a/src/main/resources/openapi.yaml +++ b/src/main/resources/openapi.yaml @@ -4,13 +4,13 @@ info: version: 1.0.0 description: API for running OSCAL Tools CLI commands paths: - /oscal: + /validate: get: - operationId: oscal - summary: Run an OSCAL Tools CLI command + operationId: validate + summary: Validate Oscal remote document parameters: - in: query - name: command + name: content required: true schema: type: string @@ -23,15 +23,9 @@ paths: schema: type: object properties: - exitCode: - type: integer - status: - type: string - output: - type: string - errors: - type: string - sarif: + runs: + type: array + version: type: string '400': description: Bad request diff --git a/src/test/kotlin/gov/nist/secauto/oscal/tools/server/TestOscalVerticle.kt b/src/test/kotlin/gov/nist/secauto/oscal/tools/server/TestOscalVerticle.kt index b3a611d..7dfafbe 100644 --- a/src/test/kotlin/gov/nist/secauto/oscal/tools/server/TestOscalVerticle.kt +++ b/src/test/kotlin/gov/nist/secauto/oscal/tools/server/TestOscalVerticle.kt @@ -41,14 +41,16 @@ class TestOscalVerticle { fun test_oscal_command(testContext: TestContext) { val async = testContext.async() - webClient.get("/oscal") - .addQueryParam("command", "validate https://raw.githubusercontent.com/GSA/fedramp-automation/refs/heads/develop/src/validations/constraints/content/ssp-all-VALID.xml") + webClient.get("/validate") + .addQueryParam("content", "https://raw.githubusercontent.com/GSA/fedramp-automation/refs/heads/develop/src/validations/constraints/content/ssp-all-VALID.xml") .send { ar -> if (ar.succeeded()) { val response = ar.result() testContext.assertEquals(200, response.statusCode()) val body = response.bodyAsJsonObject() testContext.assertNotNull(body) + testContext.assertTrue(body.containsKey("runs")) + // New assertion to check output length async.complete() } else { testContext.fail(ar.cause())