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,153 @@
|
||||
package com.osglab.account.config
|
||||
|
||||
import io.ktor.server.config.MapApplicationConfig
|
||||
import io.kotest.assertions.throwables.shouldThrow
|
||||
import io.kotest.core.spec.style.FunSpec
|
||||
import io.kotest.matchers.shouldBe
|
||||
import io.kotest.matchers.string.shouldContain
|
||||
import java.util.Base64
|
||||
|
||||
class AppConfigTest : FunSpec({
|
||||
test("test configuration can be injected without Apple client credentials") {
|
||||
val config = AppConfig.from(validConfig("test"))
|
||||
|
||||
config.environment shouldBe Environment.TEST
|
||||
config.apple.clientCredentialsAvailable shouldBe false
|
||||
config.encryption.key.size shouldBe 32
|
||||
}
|
||||
|
||||
test("production rejects placeholder secrets") {
|
||||
val config = validProductionConfig().apply {
|
||||
put("app.session.secret", "replace-with-secret")
|
||||
}
|
||||
|
||||
shouldThrow<ConfigValidationException> {
|
||||
AppConfig.from(config)
|
||||
}
|
||||
}
|
||||
|
||||
test("production accepts complete independent configuration") {
|
||||
val config = AppConfig.from(validProductionConfig())
|
||||
|
||||
config.environment shouldBe Environment.PRODUCTION
|
||||
config.database.username shouldBe "test"
|
||||
config.database.migrationUsername shouldBe "test_migrator"
|
||||
}
|
||||
|
||||
test("production fails fast when Apple signing credentials are missing") {
|
||||
val config = validProductionConfig().apply {
|
||||
put("app.apple.keyId", "")
|
||||
}
|
||||
|
||||
shouldThrow<ConfigValidationException> {
|
||||
AppConfig.from(config)
|
||||
}.message.orEmpty() shouldContain "app.apple.keyId"
|
||||
}
|
||||
|
||||
test("production rejects monitor-only integrity configuration") {
|
||||
val config = validProductionConfig().apply {
|
||||
put("app.providers.volcengine.apiKey", "volcengine-key")
|
||||
put("app.providers.deepseek.apiKey", "deepseek-key")
|
||||
put("app.integrity.enforceDeviceCheck", "false")
|
||||
put("app.integrity.enforceAppAttest", "false")
|
||||
}
|
||||
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(config)
|
||||
}.message.orEmpty() shouldContain "must enforce both DeviceCheck and App Attest"
|
||||
}
|
||||
|
||||
test("production rejects provider endpoints outside the exact host allowlist") {
|
||||
val config = validProductionConfig().apply {
|
||||
put("app.providers.deepseek.endpoint", "https://127.0.0.1/v1")
|
||||
}
|
||||
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(config)
|
||||
}.message.orEmpty() shouldContain "DeepSeek endpoint"
|
||||
}
|
||||
|
||||
test("production requires separate migration credentials") {
|
||||
val missingMigrator = validProductionConfig().apply {
|
||||
put("app.database.migrationUsername", "")
|
||||
}
|
||||
shouldThrow<ConfigValidationException> {
|
||||
AppConfig.from(missingMigrator)
|
||||
}.message.orEmpty() shouldContain "app.database.migrationUsername"
|
||||
|
||||
val reusedPassword = validProductionConfig().apply {
|
||||
put("app.database.migrationPassword", "database-password")
|
||||
}
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(reusedPassword)
|
||||
}.message.orEmpty() shouldContain "passwords must be distinct"
|
||||
}
|
||||
|
||||
test("production requires independent cryptographic secrets") {
|
||||
val config = validProductionConfig().apply {
|
||||
put(
|
||||
"app.antiAbuse.identityHmacKeyBase64",
|
||||
Base64.getEncoder().encodeToString(ByteArray(32) { 7 }),
|
||||
)
|
||||
}
|
||||
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(config)
|
||||
}.message.orEmpty() shouldContain "must be distinct"
|
||||
}
|
||||
|
||||
test("production requires exact public and App Store URLs") {
|
||||
val publicUrl = validProductionConfig().apply {
|
||||
put("app.publicBaseUrl", "https://account.osglab.com.evil.example")
|
||||
}
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(publicUrl)
|
||||
}.message.orEmpty() shouldContain "PUBLIC_BASE_URL"
|
||||
|
||||
val appStoreUrl = validProductionConfig().apply {
|
||||
put("app.appStoreUrl", "https://apps.apple.com/app/id0000000000")
|
||||
}
|
||||
shouldThrow<IllegalArgumentException> {
|
||||
AppConfig.from(appStoreUrl)
|
||||
}.message.orEmpty() shouldContain "APP_STORE_URL"
|
||||
}
|
||||
})
|
||||
|
||||
private fun validConfig(environment: String) = MapApplicationConfig(
|
||||
"app.environment" to environment,
|
||||
"app.database.jdbcUrl" to "jdbc:mysql://localhost:3306/test",
|
||||
"app.database.username" to "test",
|
||||
"app.database.password" to "database-password",
|
||||
"app.database.migrationUsername" to "test_migrator",
|
||||
"app.database.migrationPassword" to "migration-password",
|
||||
"app.database.maximumPoolSize" to "4",
|
||||
"app.session.issuer" to "https://issuer.example",
|
||||
"app.session.audience" to "ios-app",
|
||||
"app.session.secret" to "01234567890123456789012345678901",
|
||||
"app.session.accessMinutes" to "15",
|
||||
"app.session.refreshDays" to "30",
|
||||
"app.encryption.keyBase64" to Base64.getEncoder().encodeToString(ByteArray(32) { 7 }),
|
||||
"app.antiAbuse.identityHmacKeyBase64" to
|
||||
Base64.getEncoder().encodeToString(ByteArray(32) { 8 }),
|
||||
"app.apple.clientId" to "com.example.app",
|
||||
"app.apple.jwksUrl" to "https://appleid.apple.com/auth/keys",
|
||||
"app.apple.tokenUrl" to "https://appleid.apple.com/auth/token",
|
||||
"app.apple.revokeUrl" to "https://appleid.apple.com/auth/revoke",
|
||||
"app.integrity.enforceDeviceCheck" to "false",
|
||||
"app.integrity.enforceAppAttest" to "false",
|
||||
)
|
||||
|
||||
private fun validProductionConfig() = validConfig("production").apply {
|
||||
put("app.publicBaseUrl", "https://account.osglab.com")
|
||||
put("app.inviteBaseUrl", "https://osglab.com/i")
|
||||
put("app.appStoreUrl", "https://apps.apple.com/app/id1234567890")
|
||||
put("app.apple.teamId", APP_ATTEST_TEAM_ID)
|
||||
put("app.apple.keyId", "APPLE_KEY")
|
||||
put("app.apple.clientId", APP_ATTEST_BUNDLE_ID)
|
||||
put("app.apple.privateKeyPem", "private-key-material")
|
||||
put("app.integrity.appleEnvironment", "production")
|
||||
put("app.integrity.enforceDeviceCheck", "true")
|
||||
put("app.integrity.enforceAppAttest", "true")
|
||||
put("app.providers.volcengine.apiKey", "volcengine-key")
|
||||
put("app.providers.deepseek.apiKey", "deepseek-key")
|
||||
}
|
||||
Reference in New Issue
Block a user