feat: establish v0.70 platform milestone
ci / verify (push) Canceled after 0s

This commit is contained in:
Codex Local
2026-08-29 21:56:51 +08:00
parent d97bbf7cf5
commit e652516147
133 changed files with 12907 additions and 801 deletions
+19 -4
View File
@@ -3,26 +3,41 @@ $PSNativeCommandUseErrorActionPreference = $true
$projectRoot = Split-Path -Parent $PSScriptRoot
Set-Location -LiteralPath $projectRoot
function Assert-NativeSuccess {
param([Parameter(Mandatory = $true)][string]$Operation)
if ($LASTEXITCODE -ne 0) {
throw "$Operation failed with exit code $LASTEXITCODE."
}
}
$unformatted = gofmt -l cmd internal
if ($unformatted) {
throw "The following Go files are not formatted:`n$($unformatted -join "`n")"
}
go vet ./...
# Database-backed packages share the seeded local tenant. Run packages
# sequentially whenever integration variables are present so temporary SaaS
# fixtures cannot become visible to identity assertions in another package.
go test -p 1 '-coverprofile=coverage.out' ./...
Assert-NativeSuccess -Operation 'go vet'
# Unit tests stay independent from local service state. Database-backed suites
# are executed by test-integration.ps1 against a disposable migrated database.
go test '-coverprofile=coverage.out' ./...
Assert-NativeSuccess -Operation 'go test'
& (Join-Path $PSScriptRoot 'test-integration.ps1')
Push-Location web
try {
npm ci
Assert-NativeSuccess -Operation 'npm ci'
npm run generate:api
Assert-NativeSuccess -Operation 'OpenAPI client generation'
npm run typecheck
Assert-NativeSuccess -Operation 'web typecheck'
npm run build
Assert-NativeSuccess -Operation 'web build'
} finally {
Pop-Location
}
docker compose config --quiet
Assert-NativeSuccess -Operation 'docker compose config'
Write-Host 'All local checks passed.'
+3 -3
View File
@@ -5,12 +5,12 @@ Set-Location -LiteralPath $projectRoot
docker compose config --quiet
docker compose up --build -d
Write-Host '等待 API 就绪...'
Write-Host 'Waiting for API readiness...'
for ($attempt = 1; $attempt -le 60; $attempt++) {
try {
$response = Invoke-RestMethod -Uri 'http://localhost:58080/health/ready' -TimeoutSec 2
if ($response.data.status -eq 'ready') {
Write-Host '本地环境已就绪:'
Write-Host 'Local environment is ready:'
Write-Host ' Web http://localhost:3100'
Write-Host ' API http://localhost:58080'
Write-Host ' Callbacks http://localhost:58081'
@@ -25,4 +25,4 @@ for ($attempt = 1; $attempt -le 60; $attempt++) {
}
docker compose ps
throw 'API在约定时间内未就绪,请执行 docker compose logs api postgres redis migrate 查看原因。'
throw 'API did not become ready in time. Run docker compose logs api postgres redis migrate for details.'
+3 -3
View File
@@ -10,7 +10,7 @@ $deviceSecret=[Text.Encoding]::UTF8.GetBytes('local-simulated-device-secret-32-b
$configIds=@();$resourceIds=@();$conversationId=$null;$groupId=$null
$key1='ops-config-'+[Guid]::NewGuid().ToString('N');$key2='ops-config-'+[Guid]::NewGuid().ToString('N');$rollbackKey='ops-rollback-'+[Guid]::NewGuid().ToString('N')
function Token([string]$name){(Invoke-RestMethod -Method Post -Uri $tokenUrl -ContentType 'application/x-www-form-urlencoded' -Body @{grant_type='password';client_id='voice-platform-web';username=$name;password='LocalOnly123!';scope='openid'}).access_token}
function Token([string]$name){$password=if($name-like'operator*'){'OpsLocalOnly123!'}else{'LocalOnly123!'};(Invoke-RestMethod -Method Post -Uri $tokenUrl -ContentType 'application/x-www-form-urlencoded' -Body @{grant_type='password';client_id='voice-platform-web';username=$name;password=$password;scope='openid'}).access_token}
function Expected([scriptblock]$call,[int]$status){try{&$call|Out-Null;throw "Expected HTTP $status"}catch{$actual=[int]$_.Exception.Response.StatusCode;if($actual-ne$status){throw}}}
function SignedPost([string]$path,[string]$body,[string]$key){$bytes=[Text.Encoding]::UTF8.GetBytes($body);$digest=[Convert]::ToHexString([Security.Cryptography.SHA256]::HashData($bytes)).ToLowerInvariant();$timestamp=[DateTime]::UtcNow.ToString('yyyy-MM-ddTHH:mm:ssZ');$nonce=[Guid]::NewGuid().ToString('N');$canonical="POST`n$path`n$timestamp`n$nonce`n$digest";$hmac=[Security.Cryptography.HMACSHA256]::new($deviceSecret);try{$signature=[Convert]::ToBase64String($hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes($canonical))).TrimEnd('=').Replace('+','-').Replace('/','_')}finally{$hmac.Dispose()};Invoke-WebRequest -UseBasicParsing -Method Post -Uri ($api+$path) -ContentType 'application/json' -Body $body -Headers @{'X-Device-Id'=$deviceId;'X-Device-Timestamp'=$timestamp;'X-Device-Nonce'=$nonce;'X-Device-Content-SHA256'=$digest;'X-Device-Signature'=$signature;'Idempotency-Key'=$key}}
function RolloutBody([string]$reason,[string]$scope,[string]$scopeId=''){@{reason=$reason;rollout=@{scope_type=$scope;rollout_percent=100;max_concurrent_calls=100}}|ForEach-Object{if($scopeId){$_.rollout.scope_id=$scopeId};$_|ConvertTo-Json -Compress -Depth 6}}
@@ -18,10 +18,10 @@ function AddEvaluation([string]$configId,[string]$suite,[string]$token){$body=@{
function AddResource([string]$type,[string]$name,[string]$display,[string]$token){$body=@{resource_type=$type;reference_name=$name;display_name=$display;verified_at=[DateTime]::UtcNow.ToString('o')}|ConvertTo-Json -Compress;(Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$api/api/v1/ops/resource-references" -Headers @{Authorization="Bearer $token";'X-Tenant-Id'=$tenantPublicId;'Idempotency-Key'=('ops-resource-'+[Guid]::NewGuid().ToString('N'))} -ContentType 'application/json' -Body $body).Content|ConvertFrom-Json}
try{
$owner=Token 'owner';$editor=Token 'editor';$outsider=Token 'outsider'
$owner=Token 'operator';$editor=Token 'operator-approver';$outsider=Token 'outsider'
$ownerMe=((Invoke-WebRequest -UseBasicParsing -Uri "$api/api/v1/me" -Headers @{Authorization="Bearer $owner"}).Content|ConvertFrom-Json).data
$editorMe=((Invoke-WebRequest -UseBasicParsing -Uri "$api/api/v1/me" -Headers @{Authorization="Bearer $editor"}).Content|ConvertFrom-Json).data
if($ownerMe.accounts[0].platform_role-ne'ops_admin'-or$editorMe.accounts[0].platform_role-ne'ops_approver'){throw 'Seeded operations roles were not exposed by /me'}
if($ownerMe.accounts[0].account_kind-ne'operator'-or$ownerMe.accounts[0].platform_role-ne'ops_admin'-or$editorMe.accounts[0].account_kind-ne'operator'-or$editorMe.accounts[0].platform_role-ne'ops_approver'){throw 'Dedicated operations accounts were not exposed by /me'}
Expected {Invoke-WebRequest -UseBasicParsing -Uri "$api/api/v1/ops/config-versions" -Headers @{Authorization="Bearer $outsider";'X-Tenant-Id'='20000000-0000-0000-0000-000000000010'}} 403
$groupBody=@{name=('本地灰度设备组-'+[Guid]::NewGuid().ToString('N').Substring(0,8));selector=@{source='smoke-test'};device_ids=@($deviceId)}|ConvertTo-Json -Compress -Depth 5
+84
View File
@@ -0,0 +1,84 @@
param(
[string[]]$Packages = @(
'./internal/deviceauth',
'./internal/saas',
'./internal/orchestration',
'./internal/extraction',
'./internal/privacy',
'./internal/media',
'./internal/retrieval'
),
[switch]$KeepDatabase
)
$ErrorActionPreference = 'Stop'
$PSNativeCommandUseErrorActionPreference = $true
$projectRoot = Split-Path -Parent $PSScriptRoot
Set-Location -LiteralPath $projectRoot
$databaseName = 'voice_platform_test_' + ([guid]::NewGuid().ToString('N'))
if ($databaseName -notmatch '^voice_platform_test_[0-9a-f]{32}$') {
throw "Refusing to use unexpected integration database name: $databaseName"
}
function Invoke-PostgresAdmin {
param([Parameter(Mandatory = $true)][string]$Sql)
docker compose exec -T postgres psql -v ON_ERROR_STOP=1 -U voice -d postgres -c $Sql
if ($LASTEXITCODE -ne 0) {
throw "PostgreSQL administration command failed with exit code $LASTEXITCODE."
}
}
try {
$postgresID = docker compose ps -q postgres
if (-not $postgresID) {
Write-Host 'Starting the local PostgreSQL service...'
docker compose up -d --wait postgres
if ($LASTEXITCODE -ne 0) {
throw "Starting PostgreSQL failed with exit code $LASTEXITCODE."
}
}
Write-Host "Creating isolated integration database $databaseName"
Invoke-PostgresAdmin -Sql "CREATE DATABASE `"$databaseName`" OWNER voice;"
$containerDatabaseURL = "postgres://voice:voice_dev_only@postgres:5432/$databaseName`?sslmode=disable"
docker compose run --rm --no-deps migrate `
-path=/migrations `
"-database=$containerDatabaseURL" `
up
if ($LASTEXITCODE -ne 0) {
throw "Database migration failed with exit code $LASTEXITCODE."
}
docker compose run --rm --no-deps `
-e PGPASSWORD=voice_dev_only `
seed psql -h postgres -U voice -d $databaseName -v ON_ERROR_STOP=1 -f /fixtures/local_seed.sql
if ($LASTEXITCODE -ne 0) {
throw "Database seed failed with exit code $LASTEXITCODE."
}
$previousTestDatabaseURL = $env:TEST_DATABASE_URL
$env:TEST_DATABASE_URL = "postgres://voice:voice_dev_only@127.0.0.1:55432/$databaseName`?sslmode=disable"
try {
Write-Host "Running database-backed packages against $databaseName"
go test -count=1 -p 1 @Packages
if ($LASTEXITCODE -ne 0) {
throw "Database integration tests failed with exit code $LASTEXITCODE."
}
} finally {
if ($null -eq $previousTestDatabaseURL) {
Remove-Item Env:TEST_DATABASE_URL -ErrorAction SilentlyContinue
} else {
$env:TEST_DATABASE_URL = $previousTestDatabaseURL
}
}
} finally {
if ($KeepDatabase) {
Write-Warning "Keeping isolated integration database for inspection: $databaseName"
} elseif ($databaseName -match '^voice_platform_test_[0-9a-f]{32}$') {
Write-Host "Dropping isolated integration database $databaseName"
Invoke-PostgresAdmin -Sql "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='$databaseName' AND pid <> pg_backend_pid();"
Invoke-PostgresAdmin -Sql "DROP DATABASE IF EXISTS `"$databaseName`";"
}
}