Add managed content and keyboard usage insights
Introduce versioned official content workflows and privacy-safe keyboard analytics, while preventing repeat DeviceCheck sign-ins from incorrectly restricting eligible accounts.
This commit is contained in:
@@ -39,6 +39,40 @@ class DeploymentConsistencyTest : FunSpec({
|
||||
openApi shouldContain "referralCode"
|
||||
}
|
||||
|
||||
test("official content contract migration and runtime grants stay aligned") {
|
||||
val openApi = root.read("docs/openapi.yaml")
|
||||
val migration = root.read(
|
||||
"src/main/resources/db/migration/V22__official_content_management.sql",
|
||||
)
|
||||
val privileges = root.read("docs/mysql-minimum-privileges.sql")
|
||||
val smokePrivileges = root.read("deploy/smoke/runtime-grants.sql")
|
||||
|
||||
migration shouldContain "CREATE TABLE official_content_catalog"
|
||||
migration shouldContain "CREATE TABLE official_skills"
|
||||
migration shouldContain "CREATE TABLE official_skill_localizations"
|
||||
migration shouldContain "CREATE TABLE official_hint_packs"
|
||||
migration shouldContain "locale IN ('zh', 'en')"
|
||||
openApi shouldContain "schemaVersion: { type: integer, const: 1 }"
|
||||
openApi shouldContain "pattern: \"^official\\\\."
|
||||
openApi shouldContain "Cache-Control: { schema: { type: string, const: \"public,max-age=300\" } }"
|
||||
val skillSchemas = openApi
|
||||
.substringAfter(" SkillLocalization:")
|
||||
.substringBefore(" AIHintCard:")
|
||||
skillSchemas shouldContain "name: { type: string, minLength: 1, maxLength: 40 }"
|
||||
skillSchemas shouldContain "summary: { type: string, minLength: 1, maxLength: 200 }"
|
||||
skillSchemas shouldContain "prompt: { type: string, minLength: 1, maxLength: 6000 }"
|
||||
skillSchemas shouldContain "systemImage: { type: string, minLength: 1, maxLength: 100 }"
|
||||
skillSchemas shouldContain "sortOrder: { type: integer, minimum: 0, maximum: 100000 }"
|
||||
skillSchemas shouldContain "maxItems: 100"
|
||||
listOf(privileges, smokePrivileges).forEach { grants ->
|
||||
grants shouldContain "SELECT ON osg_account"
|
||||
grants shouldContain "official_content_catalog"
|
||||
grants shouldContain "official_skills"
|
||||
grants shouldContain "official_skill_localizations"
|
||||
grants shouldContain "official_hint_packs"
|
||||
}
|
||||
}
|
||||
|
||||
test("admin ledger operations stay indexed exact and privacy minimized") {
|
||||
val migration = root.read(
|
||||
"src/main/resources/db/migration/V19__admin_ledger_operations.sql",
|
||||
@@ -165,7 +199,7 @@ class DeploymentConsistencyTest : FunSpec({
|
||||
val openApi = root.read("docs/openapi.yaml")
|
||||
val eventSchema = openApi
|
||||
.substringAfter(" ProductAnalyticsEvent:")
|
||||
.substringBefore(" AdminSessionState:")
|
||||
.substringBefore(" SkillLocalization:")
|
||||
eventSchema shouldContain "additionalProperties: false"
|
||||
eventSchema shouldContain "AI_FEATURE_SUCCEEDED"
|
||||
eventSchema shouldContain "INSUFFICIENT_CREDITS"
|
||||
@@ -174,6 +208,26 @@ class DeploymentConsistencyTest : FunSpec({
|
||||
eventSchema shouldNotContain "audio"
|
||||
eventSchema shouldNotContain "modelOutput"
|
||||
openApi shouldContain "schema: { \$ref: \"#/components/schemas/AdminProductAnalytics\" }"
|
||||
|
||||
val keyboardMigration = root.read(
|
||||
"src/main/resources/db/migration/V23__keyboard_usage_daily_summaries.sql",
|
||||
)
|
||||
keyboardMigration shouldContain "keyboard_usage_daily_summaries"
|
||||
keyboardMigration shouldContain
|
||||
"UNIQUE KEY uq_keyboard_usage_installation_date (installation_hash, summary_date)"
|
||||
keyboardMigration shouldContain "ON DELETE CASCADE"
|
||||
keyboardMigration shouldNotContain "input_text"
|
||||
keyboardMigration shouldNotContain "host_application"
|
||||
|
||||
val keyboardSchema = openApi
|
||||
.substringAfter(" KeyboardUsageSummary:")
|
||||
.substringBefore(" ProductAnalyticsBatchResponse:")
|
||||
keyboardSchema shouldContain "additionalProperties: false"
|
||||
keyboardSchema shouldContain "chineseCharacterCount"
|
||||
keyboardSchema shouldContain "mixedLanguageSessionCount"
|
||||
keyboardSchema shouldNotContain "userText"
|
||||
keyboardSchema shouldNotContain "keystrokes"
|
||||
keyboardSchema shouldNotContain "hostApplication"
|
||||
}
|
||||
|
||||
test("production Compose reuses private MySQL and hardens the application container") {
|
||||
@@ -301,6 +355,7 @@ private val EXPECTED_PUBLIC_PATHS = setOf(
|
||||
"/v1/account",
|
||||
"/v1/apple/events",
|
||||
"/v1/analytics/events",
|
||||
"/v1/analytics/keyboard-usage",
|
||||
"/v1/credits/balance",
|
||||
"/v1/credits/ledger",
|
||||
"/v1/credits/rates",
|
||||
@@ -323,6 +378,16 @@ private val EXPECTED_PUBLIC_PATHS = setOf(
|
||||
"/v1/gateway/asr",
|
||||
"/v1/gateway/asr/sessions",
|
||||
"/v1/gateway/asr/sessions/{sessionId}/stream",
|
||||
"/v1/content/skills",
|
||||
"/v1/content/hints/manifest",
|
||||
"/v1/content/hints/{locale}",
|
||||
"/hints/manifest.json",
|
||||
"/hints/hints-{locale}.json",
|
||||
"/v1/admin/content/skills",
|
||||
"/v1/admin/content/skills/{id}",
|
||||
"/v1/admin/content/skills/{id}/enable",
|
||||
"/v1/admin/content/skills/{id}/disable",
|
||||
"/v1/admin/content/hints/{locale}",
|
||||
"/v1/admin/auth/session",
|
||||
"/v1/admin/auth/login",
|
||||
"/v1/admin/auth/logout",
|
||||
|
||||
Reference in New Issue
Block a user