HH-446: restore auditable quality gates from current main (#102)

* HH-446: restore auditable quality gates

* test(HH-446): restore help center smoke contract

---------

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-22 15:45:58 +08:00
committed by GitHub
co-authored by rogee
parent f719529d66
commit 61376a57fd
7 changed files with 652 additions and 40 deletions
+166 -2
View File
@@ -41,6 +41,9 @@ jobs:
run: python -m pip install --require-hashes -r .github/requirements-browser-harness.txt
- name: Test Prometheus alert rules
run: docker run --rm --entrypoint promtool -v "$PWD/backend/configs:/configs:ro" prom/prometheus:v3.5.0@sha256:63805ebb8d2b3920190daf1cb14a60871b16fd38bed42b857a3182bc621f4996 test rules /configs/prometheus_alerts_test.yml
- name: Test quality gate failure contracts
working-directory: backend
run: python3 scripts/quality_gate_test.py
- name: Test
working-directory: backend
env:
@@ -55,7 +58,30 @@ jobs:
browser-harness <<'PY'
print(page_info())
PY
go test ./internal/... ./pkg/... ./cmd/...
GOCHAT_RACE=false \
GOCHAT_COLD_CACHE=true \
GOCHAT_MAX_DURATION_SECONDS=480 \
GOCHAT_QUALITY_DIR="$GITHUB_WORKSPACE/backend/quality/sqlite/cold-cache" \
./scripts/ci_quality_gate.sh
- name: Test critical race suites
working-directory: backend
env:
GOCHAT_TEST_DB: sqlite
run: |
GOCHAT_RACE=true \
GOCHAT_COLD_CACHE=true \
GOCHAT_TEST_PACKAGES='./internal/ws ./internal/handler/ws ./internal/worker ./internal/channel/...' \
GOCHAT_TEST_TIMEOUT=180s \
GOCHAT_MAX_DURATION_SECONDS=180 \
GOCHAT_QUALITY_DIR="$GITHUB_WORKSPACE/backend/quality/sqlite/race" \
./scripts/ci_quality_gate.sh
- name: Upload SQLite quality evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: backend-quality-sqlite
path: backend/quality/sqlite
if-no-files-found: error
- name: Build
working-directory: backend
run: go build ./...
@@ -105,6 +131,58 @@ jobs:
GOCHAT_TEST_DB: postgres
GOCHAT_TEST_DB_URL: postgres://postgres:postgres@localhost:5432/gochat_test?sslmode=disable
run: go test -count=1 -timeout 10m ./internal/... ./pkg/... ./cmd/...
- name: Test controlled service race budget
working-directory: backend
env:
GOCHAT_TEST_DB: postgres
GOCHAT_TEST_DB_URL: postgres://postgres:postgres@localhost:5432/gochat_test?sslmode=disable
run: |
set -euo pipefail
evidence="$GITHUB_WORKSPACE/backend/quality/postgres/service-race"
mkdir -p "$evidence"
start=$SECONDS
set +e
timeout 180s go test -race -count=1 -json -timeout 170s \
-run '^(TestCaptainPreferenceService_(Create|Create_DuplicateAccount|Get|Get_NotFound|Update|Delete)|TestEnsureCaptainAgentBotBindingConcurrentCallsStayUnique|TestTagCreate7_Cov35)$' \
./internal/service | tee "$evidence/test.jsonl"
test_status=${PIPESTATUS[0]}
set -e
elapsed=$((SECONDS - start))
python3 - "$evidence/test.jsonl" "$evidence/summary.json" "$test_status" "$elapsed" <<'PY'
import json, sys
required = {
"TestCaptainPreferenceService_Create",
"TestCaptainPreferenceService_Create_DuplicateAccount",
"TestCaptainPreferenceService_Get",
"TestCaptainPreferenceService_Get_NotFound",
"TestCaptainPreferenceService_Update",
"TestCaptainPreferenceService_Delete",
"TestEnsureCaptainAgentBotBindingConcurrentCallsStayUnique",
"TestTagCreate7_Cov35",
}
results = {}
with open(sys.argv[1], encoding="utf-8") as events:
for line in events:
event = json.loads(line)
if event.get("Test") in required and event.get("Action") in {"pass", "fail", "skip"}:
results[event["Test"]] = event["Action"]
status, elapsed = int(sys.argv[3]), int(sys.argv[4])
failures = [name for name in sorted(required) if results.get(name) != "pass"]
report = {
"status": "passed" if status == 0 and elapsed <= 180 and not failures else "failed",
"duration_seconds": elapsed,
"budget_seconds": 180,
"test_exit_code": status,
"required_tests": {name: results.get(name, "missing") for name in sorted(required)},
}
with open(sys.argv[2], "w", encoding="utf-8") as output:
json.dump(report, output, indent=2, sort_keys=True)
output.write("\n")
print(json.dumps(report, sort_keys=True))
if report["status"] != "passed":
raise SystemExit(1)
PY
- name: Test production upload migrations
working-directory: backend
env:
@@ -164,6 +242,13 @@ jobs:
if empty:
raise SystemExit(f"required E2E suites ran no passing subtests: {', '.join(empty)}")
PY
- name: Upload PostgreSQL quality evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: backend-quality-postgres
path: backend/quality/postgres
if-no-files-found: error
frontend:
name: Frontend Build
@@ -184,8 +269,85 @@ jobs:
- name: Build and verify artifacts
run: pnpm --dir frontend test:build
frontend-smoke:
name: Browser core smoke
needs: [frontend]
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg16@sha256:ccc6e83d6e35e931dc7c5def2022729d5a6c370318d099181995567ff1fb4d6b
env:
POSTGRES_DB: gochat_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d gochat_test"
--health-interval 5s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7.4.2-alpine@sha256:02419de7eddf55aa5bcf49efb74e88fa8d931b4d77c07eff8a6b2144472b6952
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5
with:
go-version: 1.25.13
cache-dependency-path: backend/go.sum
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 20.19.5
- uses: browser-actions/setup-chrome@48ad923757ca74d66703209fe939badbdf80f2f4 # v2
id: chrome
with:
chrome-version: 152.0.7977.54
- name: Test browser smoke failure contracts
run: node backend/scripts/parity_frontend_browser_smoke.mjs --self-test
- run: corepack enable && corepack prepare pnpm@10.2.0 --activate
- run: pnpm install --frozen-lockfile
- name: Run browser smoke
env:
CI: "true"
GOCHAT_ENV: development
GOCHAT_DATABASE_DSN: postgres://postgres:postgres@localhost:5432/gochat_test?sslmode=disable
GOCHAT_REDIS_DSN: redis://localhost:6379
GOCHAT_JWT_SECRET: gochat-smoke-jwt-secret-at-least-32-characters
CHATWOOT_DIR: ${{ github.workspace }}/frontend
GOCHAT_SMOKE_SEARCH_ENGINE: db
GOCHAT_SMOKE_LOG_DIR: ${{ github.workspace }}/backend/.tmp/frontend-smoke
GOCHAT_SMOKE_REPORT: ${{ github.workspace }}/docs/parity/frontend-smoke-report.md
GOCHAT_SMOKE_CHROME: ${{ steps.chrome.outputs.chrome-path }}
run: |
mkdir -p "$GOCHAT_SMOKE_LOG_DIR"
(cd backend && go run ./cmd/gochat serve >"$GOCHAT_SMOKE_LOG_DIR/gochat.log" 2>&1) &
backend_pid=$!
(cd frontend && VITE_API_HOST=http://127.0.0.1:3000 pnpm exec vite --host localhost --port 3036 >"$GOCHAT_SMOKE_LOG_DIR/vite.log" 2>&1) &
frontend_pid=$!
trap 'kill "$backend_pid" "$frontend_pid" 2>/dev/null || true' EXIT
curl --fail --silent --show-error --retry 60 --retry-connrefused --retry-delay 1 \
http://127.0.0.1:3000/health > /dev/null
backend/scripts/parity_frontend_smoke.sh --browser-smoke
- name: Upload browser smoke evidence
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: frontend-browser-smoke
path: |
backend/.tmp/frontend-smoke
docs/parity/frontend-smoke-report.md
if-no-files-found: error
security:
name: Security (SAST/SCA)
needs: [frontend-smoke]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
@@ -221,6 +383,7 @@ jobs:
production-smoke:
name: Production image smoke
if: github.event_name == 'pull_request' || startsWith(github.ref, 'refs/tags/v')
needs: [frontend-smoke]
runs-on: ubuntu-latest
env:
GOCHAT_IMAGE_REF: gochat:production-smoke
@@ -308,7 +471,8 @@ jobs:
container_id="$("${compose[@]}" ps -q "$service")"
test "$(docker inspect --format '{{.State.Health.Status}}' "$container_id")" = healthy
done
curl -fsS "http://127.0.0.1:$GOCHAT_PORT/health" | grep -q '"status":"healthy"'
curl -fsS "http://127.0.0.1:$GOCHAT_PORT/health" > "$RUNNER_TEMP/health.json"
python3 backend/scripts/validate_health_json.py "$RUNNER_TEMP/health.json"
curl -fsS "http://127.0.0.1:$GOCHAT_PORT/app" | grep -q '/assets/'
curl -fsS "http://127.0.0.1:$GOCHAT_PORT/runtime-config.js" | grep -q 'window.__GOCHAT_CONFIG__'
curl -fsS -o "$RUNNER_TEMP/favicon-32x32.png" "http://127.0.0.1:$GOCHAT_PORT/favicon-32x32.png"