chore: establish local platform baseline

This commit is contained in:
Codex Local
2026-08-26 06:41:54 +08:00
commit 29bdf4900f
575 changed files with 95644 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true
$projectRoot = Split-Path -Parent $PSScriptRoot
Set-Location -LiteralPath $projectRoot
$apiBase = 'http://localhost:58080'
$tokenUrl = 'http://localhost:58180/realms/voice-local/protocol/openid-connect/token'
$subjectId = '10000000-0000-0000-0000-000000000411'
$privacyRequestId = $null
function Get-LocalAccessToken([string]$Username) {
return (Invoke-RestMethod -Method Post -Uri $tokenUrl -ContentType 'application/x-www-form-urlencoded' -Body @{
grant_type = 'password'; client_id = 'voice-platform-web'; username = $Username
password = 'LocalOnly123!'; scope = 'openid'
}).access_token
}
function Assert-Equal([object]$Actual, [object]$Expected, [string]$Message) {
if ([string]$Actual -ne [string]$Expected) {
throw "$Message。实际值:$Actual;预期值:$Expected"
}
}
function Invoke-ExpectedStatus([scriptblock]$Action, [int]$ExpectedStatus) {
try {
$response = & $Action
Assert-Equal $response.StatusCode $ExpectedStatus 'HTTP状态不正确'
} catch {
if ($_.Exception.Response.StatusCode.value__ -ne $ExpectedStatus) { throw }
}
}
function Remove-PrivacyRequest([string]$PublicId) {
if ($PublicId -notmatch '^[0-9a-fA-F-]{36}$') { throw '拒绝清理格式不正确的隐私请求编号。' }
$sql = @"
BEGIN;
CREATE TEMP TABLE smoke_privacy_cleanup AS SELECT id,public_id FROM privacy_request WHERE public_id='$PublicId'::uuid;
DELETE FROM outbox_event WHERE aggregate_id IN (SELECT id FROM smoke_privacy_cleanup);
DELETE FROM audit_event WHERE resource_id IN (SELECT public_id FROM smoke_privacy_cleanup);
DELETE FROM privacy_request WHERE id IN (SELECT id FROM smoke_privacy_cleanup);
COMMIT;
"@
docker compose exec -T postgres psql -U voice -d voice_platform -v ON_ERROR_STOP=1 -q -c $sql | Out-Null
if ($LASTEXITCODE -ne 0) { throw '隐私请求冒烟数据清理失败。' }
}
try {
$health = Invoke-WebRequest -UseBasicParsing -Uri "$apiBase/health/ready"
Assert-Equal $health.StatusCode 200 'API就绪检查失败'
$ownerToken = Get-LocalAccessToken 'owner'
$editorToken = Get-LocalAccessToken 'editor'
$key = 'smoke-privacy-' + [Guid]::NewGuid().ToString('N')
$body = @{ request_type = 'ACCESS'; scope = @{ categories = @('profile', 'conversations', 'memories') } } | ConvertTo-Json -Compress -Depth 4
$headers = @{ Authorization = "Bearer $ownerToken"; 'Idempotency-Key' = $key }
$created = Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$apiBase/api/v1/subjects/$subjectId/privacy-requests" -Headers $headers -ContentType 'application/json' -Body $body
Assert-Equal $created.StatusCode 202 '隐私访问请求未进入后台队列'
$privacyRequestId = [string](($created.Content | ConvertFrom-Json).data.id)
if ($privacyRequestId -notmatch '^[0-9a-fA-F-]{36}$') { throw '隐私请求编号不正确。' }
$replay = Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$apiBase/api/v1/subjects/$subjectId/privacy-requests" -Headers $headers -ContentType 'application/json' -Body $body
Assert-Equal $replay.StatusCode 200 '幂等重放没有返回原请求'
Assert-Equal $replay.Headers['Idempotency-Replayed'][0] 'true' '幂等重放缺少响应标记'
Assert-Equal (($replay.Content | ConvertFrom-Json).data.id) $privacyRequestId '幂等重放创建了第二个请求'
$conflictingBody = @{ request_type = 'ACCESS'; scope = @{ categories = @('profile') } } | ConvertTo-Json -Compress -Depth 4
Invoke-ExpectedStatus { Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$apiBase/api/v1/subjects/$subjectId/privacy-requests" -Headers $headers -ContentType 'application/json' -Body $conflictingBody } 409
Invoke-ExpectedStatus { Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$apiBase/api/v1/subjects/$subjectId/privacy-requests" -Headers @{ Authorization = "Bearer $editorToken"; 'Idempotency-Key' = ('editor-denied-' + [Guid]::NewGuid().ToString('N')) } -ContentType 'application/json' -Body $body } 403
$deadline = [DateTime]::UtcNow.AddSeconds(20)
do {
Start-Sleep -Milliseconds 500
$detailResponse = Invoke-WebRequest -UseBasicParsing -Uri "$apiBase/api/v1/privacy-requests/$privacyRequestId" -Headers @{ Authorization = "Bearer $ownerToken" }
$detail = ($detailResponse.Content | ConvertFrom-Json).data
} while ($detail.status -notin @('COMPLETED', 'PARTIAL_FAILED') -and [DateTime]::UtcNow -lt $deadline)
Assert-Equal $detail.status 'COMPLETED' '隐私数据盘点没有完成'
Assert-Equal $detail.subtasks.Count 1 '隐私请求子任务数量不正确'
Assert-Equal $detail.subtasks[0].status 'COMPLETED' '隐私数据库盘点子任务未完成'
Assert-Equal $detail.result_summary.content_included $false '隐私盘点结果不应包含正文'
Assert-Equal @($detail.result_summary.inventory_counts.PSObject.Properties).Count 3 '隐私盘点没有按请求范围过滤'
if ($detail.result_summary.inventory_counts.profile -lt 1) { throw '隐私盘点没有返回长者档案记录。' }
$list = (Invoke-WebRequest -UseBasicParsing -Uri "$apiBase/api/v1/subjects/$subjectId/privacy-requests" -Headers @{ Authorization = "Bearer $ownerToken" }).Content | ConvertFrom-Json
if (-not ($list.data.items | Where-Object id -eq $privacyRequestId)) { throw '隐私请求列表没有返回刚创建的请求。' }
Write-Host "隐私请求端到端冒烟通过:$privacyRequestId"
Write-Host '权限拒绝、幂等重放/冲突、后台子任务、范围过滤和无正文盘点验证通过。'
} finally {
if ($privacyRequestId) {
Remove-PrivacyRequest $privacyRequestId
Write-Host "已清理本次隐私请求冒烟数据:$privacyRequestId"
}
}