Establish secure account and managed AI backend
Provide the production foundation for Apple identity, immutable credits, referrals, integrity checks, managed providers, and hardened Docker deployment.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
package com.osglab.account.config
|
||||
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import io.kotest.matchers.string.shouldNotContain
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
|
||||
class DeploymentConsistencyTest : FunSpec({
|
||||
val root = Path.of(System.getProperty("user.dir"))
|
||||
|
||||
test("OpenAPI documents every mounted public route") {
|
||||
val openApi = root.read("docs/openapi.yaml")
|
||||
val documentedPaths = Regex("""(?m)^ (/[^:]+):\s*$""")
|
||||
.findAll(openApi)
|
||||
.map { it.groupValues[1] }
|
||||
.toSet()
|
||||
|
||||
documentedPaths shouldBe EXPECTED_PUBLIC_PATHS
|
||||
}
|
||||
|
||||
test("production Compose reuses private MySQL and hardens the application container") {
|
||||
val compose = root.read("compose.yaml")
|
||||
|
||||
compose shouldContain "127.0.0.1:\${ACCOUNT_BIND_PORT:-18080}:8080"
|
||||
compose shouldContain "external: true"
|
||||
compose shouldContain "account-egress:"
|
||||
compose shouldContain "user: \"10001:10001\""
|
||||
compose shouldContain "read_only: true"
|
||||
compose shouldContain "cap_drop:"
|
||||
compose shouldContain "no-new-privileges:true"
|
||||
compose shouldNotContain "image: mysql"
|
||||
compose shouldNotContain "3306:3306"
|
||||
compose shouldNotContain "0.0.0.0:"
|
||||
}
|
||||
|
||||
test("container image remains non-root and read-only compatible") {
|
||||
val dockerfile = root.read("Dockerfile")
|
||||
|
||||
dockerfile shouldContain "USER 10001:10001"
|
||||
dockerfile shouldContain "ENV HOME=/tmp"
|
||||
dockerfile shouldNotContain "ENTRYPOINT [\"sh\""
|
||||
}
|
||||
|
||||
test("OpenResty proxies HTTP WebSocket invitations and both AASA paths safely") {
|
||||
val openResty = root.read("deploy/openresty-account.conf")
|
||||
|
||||
openResty shouldContain "proxy_set_header Upgrade \$http_upgrade;"
|
||||
openResty shouldContain "proxy_set_header Connection \$connection_upgrade;"
|
||||
openResty shouldContain "location = /.well-known/apple-app-site-association"
|
||||
openResty shouldContain "location = /apple-app-site-association"
|
||||
openResty shouldContain "location ^~ /i/"
|
||||
Regex("""location \^~ /i/ \{\s+access_log off;""").containsMatchIn(openResty) shouldBe true
|
||||
openResty shouldNotContain "alias /www/wwwroot/osglab.com/apple-app-site-association"
|
||||
}
|
||||
|
||||
test("CI definition is singular and leaves MySQL lifecycle to Testcontainers") {
|
||||
val ci = root.read(".github/workflows/ci.yml")
|
||||
|
||||
Regex("""(?m)^name: CI$""").findAll(ci).count() shouldBe 1
|
||||
Regex("""(?m)^jobs:$""").findAll(ci).count() shouldBe 1
|
||||
ci shouldContain "docker compose -f compose.yaml config --quiet"
|
||||
ci shouldContain "./gradlew --no-daemon clean test"
|
||||
ci shouldContain "./gradlew --no-daemon buildFatJar"
|
||||
ci shouldNotContain "3306:3306"
|
||||
ci shouldNotContain "TEST_DB_"
|
||||
}
|
||||
|
||||
test("AASA has one runtime template and no deploy-time identifier placeholder") {
|
||||
val aasa = root.read("src/main/resources/invite/apple-app-site-association.json")
|
||||
|
||||
aasa shouldContain "\"{{APPLE_APP_ID}}\""
|
||||
aasa shouldContain "\"/i/*\""
|
||||
Files.exists(root.resolve("deploy/apple-app-site-association")) shouldBe false
|
||||
}
|
||||
})
|
||||
|
||||
private fun Path.read(relativePath: String): String =
|
||||
Files.readString(resolve(relativePath))
|
||||
|
||||
private val EXPECTED_PUBLIC_PATHS = setOf(
|
||||
"/health",
|
||||
"/health/live",
|
||||
"/health/ready",
|
||||
"/v1/auth/apple",
|
||||
"/v1/auth/refresh",
|
||||
"/v1/auth/logout",
|
||||
"/v1/account",
|
||||
"/v1/apple/events",
|
||||
"/v1/credits/balance",
|
||||
"/v1/credits/ledger",
|
||||
"/v1/credits/rates",
|
||||
"/v1/credits/reservations",
|
||||
"/v1/credits/reservations/{reservationId}",
|
||||
"/v1/credits/reservations/{reservationId}/settle",
|
||||
"/v1/credits/reservations/{reservationId}/release",
|
||||
"/v1/credits/reservations/{reservationId}/refund",
|
||||
"/v1/referrals",
|
||||
"/v1/referrals/me",
|
||||
"/v1/referrals/code",
|
||||
"/v1/referrals/redeem",
|
||||
"/v1/referrals/bind",
|
||||
"/v1/referrals/campaigns",
|
||||
"/v1/integrity/challenges",
|
||||
"/v1/integrity/attest",
|
||||
"/v1/integrity/assert",
|
||||
"/v1/gateway/catalog",
|
||||
"/v1/gateway/grants",
|
||||
"/v1/gateway/grants/refresh",
|
||||
"/v1/gateway/grants/{grantId}",
|
||||
"/v1/gateway/llm/{capability}",
|
||||
"/v1/gateway/asr",
|
||||
"/v1/gateway/asr/sessions",
|
||||
"/v1/gateway/asr/sessions/{sessionId}/stream",
|
||||
"/.well-known/apple-app-site-association",
|
||||
"/apple-app-site-association",
|
||||
"/i/{code}",
|
||||
)
|
||||
Reference in New Issue
Block a user