-
Notifications
You must be signed in to change notification settings - Fork 2
671 lines (589 loc) · 23.2 KB
/
Copy pathchecks.yml
File metadata and controls
671 lines (589 loc) · 23.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
name: checks
on:
pull_request:
branches: [master, dev/delicious233]
push:
branches: [master, 'dev/**']
env:
GO_VERSION: "1.25.11"
GOLANGCI_LINT_VERSION: "v2.12.2"
NODE_VERSION: "22"
PNPM_VERSION: "10"
jobs:
# ── Go: Edge Server ──────────────────────────
go-edge:
runs-on: ubuntu-latest
defaults:
run:
working-directory: edge-server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: edge-server/go.sum
- name: Build
run: go build ./...
- name: Lint
continue-on-error: true
uses: golangci/golangci-lint-action@v9
with:
working-directory: edge-server
version: ${{ env.GOLANGCI_LINT_VERSION }}
args: --timeout=5m
- name: Test (unit only, skip integration)
timeout-minutes: 20
run: go test ./... -count=1 -short -coverprofile=coverage.out -covermode=atomic -timeout=15m
- name: Coverage check (informational)
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
echo "Overall coverage: ${COVERAGE}%"
echo "::notice::edge-server overall coverage: ${COVERAGE}%"
- name: Coverage per-package minimums
run: |
echo "=== Per-package coverage minimums ==="
check_pkg() {
local pattern="$1"
local min="$2"
local label="$3"
local cov
cov=$(go tool cover -func=coverage.out | grep "$pattern" | awk '{sum+=$NF; n++} END {if(n>0) printf "%.1f", sum/n; else print "0"}')
echo " ${label}: ${cov}% (min: ${min}%)"
if (( $(echo "$cov < $min" | bc -l) )); then
echo "::error::${label} coverage ${cov}% below ${min}% minimum"
return 1
fi
}
FAILED=0
check_pkg "edge-server/internal/security/" 70 "security" || FAILED=1
check_pkg "edge-server/internal/lifecycle/" 60 "lifecycle" || FAILED=1
check_pkg "edge-server/internal/adapters/" 55 "adapters" || FAILED=1
exit $FAILED
- name: Race detection
continue-on-error: true # fsnotify hot-reload tests have inherent goroutine races in CI
run: go test ./... -count=1 -short -race
- name: Security scan (gosec)
continue-on-error: true
run: go run github.com/securego/gosec/v2/cmd/gosec@latest ./...
- name: Vulnerability check (govulncheck)
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
- name: Vet
run: go vet ./...
- name: Commit message check (PR only)
if: github.event_name == 'pull_request'
run: |
TYPES="init|feat|fix|docs|refactor|chore|test|perf|ci|revert"
PATTERN="^($TYPES)(\([a-z0-9._-]+\))?: .+"
FAILED=0
for commit in $(git log --format="%H %s" "origin/${{ github.base_ref }}..HEAD" 2>/dev/null || echo ""); do
sha=$(echo "$commit" | cut -d' ' -f1)
msg=$(echo "$commit" | cut -d' ' -f2-)
if ! echo "$msg" | grep -qE "$PATTERN"; then
echo "::warning ::${sha:0:7} 不符合规范: $msg"
FAILED=1
fi
done
if [ $FAILED -eq 1 ]; then
echo "::error::提交信息需符合 Conventional Commits: type(scope): 中文摘要"
exit 1
fi
echo "✓ 所有提交信息格式正确"
# ── Go: Hub Server ──────────────────────────
go-hub:
runs-on: ubuntu-latest
defaults:
run:
working-directory: hub-server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: hub-server/go.sum
- name: Build
run: go build ./...
- name: Lint
continue-on-error: true
uses: golangci/golangci-lint-action@v9
with:
working-directory: hub-server
version: ${{ env.GOLANGCI_LINT_VERSION }}
args: --timeout=5m
- name: Test (unit only, skip integration)
run: go test ./... -count=1 -short -coverprofile=coverage.out -covermode=atomic
- name: Coverage check (overall >= 40%)
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
THRESHOLD=40
echo "Overall coverage: ${COVERAGE}% (threshold: ${THRESHOLD}%)"
if (( $(echo "$COVERAGE < $THRESHOLD" | bc -l) )); then
echo "::error::Coverage ${COVERAGE}% below ${THRESHOLD}% threshold"
exit 1
fi
- name: Race detection
run: go test ./... -count=1 -short -race
- name: Security scan (gosec)
continue-on-error: true
run: go run github.com/securego/gosec/v2/cmd/gosec@latest ./...
- name: Vulnerability check (govulncheck)
run: go run golang.org/x/vuln/cmd/govulncheck@latest ./...
- name: Vet
run: go vet ./...
# ── Backend E2E: Fixture-only ────────────────
backend-e2e-fixture:
name: Backend E2E (fixture-only)
runs-on: ubuntu-latest
defaults:
run:
working-directory: hub-server
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: hub-server/go.sum
- name: TeamRun fixture E2E
run: go test ./tests/teamrun -run '^TestTeamRunSmoke$' -count=1
- name: P0 remote-control fixture readiness
working-directory: .
run: pwsh -NoProfile -ExecutionPolicy Bypass -File ./scripts/verify/verify-p0-remote-control-fixture.ps1
# -- Backend: focused subset, no real CLI/model/services
backend-focused-subset:
name: Backend focused subset
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: |
hub-server/go.sum
edge-server/go.sum
- name: Hub focused backend packages
run: cd hub-server && go test ./internal/repository ./internal/service ./internal/app ./internal/handler ./internal/router -short -count=1
- name: Edge focused backend packages
run: cd edge-server && go test ./internal/store ./internal/api ./internal/lifecycle ./cmd/agenthub-edge -short -count=1
# ── Cross-Platform Build ─────────────────────
cross-build:
name: Cross-platform build
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: |
edge-server/go.sum
hub-server/go.sum
- name: Build edge-server
run: cd edge-server && go build ./...
- name: Build hub-server
run: cd hub-server && go build ./...
- name: Test edge-server
run: cd edge-server && go test ./... -short -count=1
- name: Test hub-server
run: cd hub-server && go test ./... -short -count=1
# ── Docker: Hub Server ───────────────────────
docker:
name: Docker build (Hub Server)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t agenthub-hub-server -f hub-server/deployments/Dockerfile .
- name: Verify image
run: docker images agenthub-hub-server
# ── Benchmark Regression ─────────────────────
benchmark:
name: Benchmark regression check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: |
edge-server/go.sum
hub-server/go.sum
- name: Run benchmarks
run: |
cd edge-server && go test -bench=. -benchtime=1s ./internal/events/ ./internal/adapters/
cd ../hub-server && go test -bench=. -benchtime=1s ./internal/service/ ./internal/jwtutil/
# ── Frontend: Desktop ────────────────────────
# Known debt: 15 pre-existing test failures (97.8% pass rate: 679/694).
# Tracked in docs/audit/comprehensive-audit-2026-06-17.md, Test Quality section.
# Failures are in desktop integration/edge-real tests and a few component tests.
# These are low-priority pre-existing issues, not regressions.
frontend-desktop:
runs-on: ubuntu-latest
defaults:
run:
working-directory: app/desktop
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/pnpm-lock.yaml
- name: Install
working-directory: app
run: pnpm install --frozen-lockfile
- name: Type check
run: pnpm typecheck
- name: Lint (debt visibility)
continue-on-error: true
run: pnpm lint --max-warnings 10
- name: Vuln audit (pnpm audit)
continue-on-error: true
run: pnpm audit --prod
- name: Test Desktop
run: pnpm test:ci
# ── Frontend: Web ────────────────────────────
frontend-web:
name: Frontend (web)
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./app/web
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/pnpm-lock.yaml
- name: Install
run: pnpm install --frozen-lockfile
- name: Lint Web
run: pnpm lint
- name: Vuln audit (pnpm audit)
continue-on-error: true
run: pnpm audit --prod
- name: Build Web
run: pnpm build
- name: Test
run: pnpm test -- --run
# ── Frontend: Mobile ──────────────────────────
frontend-mobile:
name: Frontend (mobile)
runs-on: ubuntu-latest
timeout-minutes: 45
defaults:
run:
working-directory: ./app
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/pnpm-lock.yaml
- name: Install
run: pnpm install --frozen-lockfile
- name: Type check (mobile)
run: pnpm --filter agenthub-mobile-rn typecheck
- name: Lint (mobile rules)
run: pnpm --filter agenthub-mobile-rn lint
# ── Hardened: Test with coverage reporting ──
- name: Install coverage provider (mobile)
run: pnpm --filter agenthub-mobile-rn add -D @vitest/coverage-v8
- name: Test with coverage (mobile)
run: |
pnpm --filter agenthub-mobile-rn exec vitest run --coverage \
--coverage.thresholds.lines=40 \
--coverage.thresholds.branches=30 \
--coverage.thresholds.functions=30 \
--coverage.thresholds.statements=40
echo "::notice::Mobile coverage report generated. Raise thresholds as coverage improves."
# ── Hardened: Bundle size check (Expo web export) ──
- name: Bundle size check (mobile web export)
run: |
echo "=== Mobile bundle size check ==="
cd mobile-rn
npx expo export --platform web --output-dir dist/web-export 2>&1
if [ -d dist/web-export ]; then
BUNDLE_SIZE_KB=$(du -sk dist/web-export | cut -f1)
MAX_SIZE_KB=153600
echo "Web export bundle size: ${BUNDLE_SIZE_KB} KB (max: ${MAX_SIZE_KB} KB)"
if [ "${BUNDLE_SIZE_KB}" -gt "${MAX_SIZE_KB}" ]; then
echo "::error::Web export bundle size ${BUNDLE_SIZE_KB} KB exceeds ${MAX_SIZE_KB} KB threshold"
exit 1
fi
echo "::notice::Bundle size check passed: ${BUNDLE_SIZE_KB} KB under ${MAX_SIZE_KB} KB"
else
echo "::error::Web export did not produce output directory"
exit 1
fi
# ── Hardened: Screenshot diff testing (visual QA) ──
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium
- name: Screenshot visual QA (mobile)
timeout-minutes: 12
run: |
echo "=== Mobile screenshot visual QA ==="
cd mobile-rn
node scripts/visual-qa.mjs
env:
AGENTHUB_MOBILE_MOCK_HUB_PORT: '8088'
CI: 'true'
- name: Upload mobile screenshots
if: always()
uses: actions/upload-artifact@v4
with:
name: mobile-visual-qa-screenshots
path: app/mobile-rn/screenshots/visual-qa/
retention-days: 7
- name: E2E (mock hub)
timeout-minutes: 10
run: |
node mobile-rn/scripts/mock-hub.mjs &
MOCK_HUB_PID=$!
# Wait for mock hub to accept connections
for i in $(seq 1 20); do
if curl -sf http://127.0.0.1:8088/health > /dev/null 2>&1; then
echo "Mock hub ready at http://127.0.0.1:8088"
break
fi
sleep 1
done
# Run vitest with mock hub available
AGENTHUB_MOBILE_MOCK_HUB_PORT=8088 pnpm --filter agenthub-mobile-rn test
E2E_EXIT_CODE=$?
kill $MOCK_HUB_PID 2>/dev/null || true
wait $MOCK_HUB_PID 2>/dev/null || true
exit $E2E_EXIT_CODE
- name: Verify Mobile RN
run: pnpm --filter agenthub-mobile-rn verify
- name: Expo Doctor
run: pnpm --filter agenthub-mobile-rn run doctor
- name: Native readiness
run: pnpm --filter agenthub-mobile-rn run native:check
- name: Mock Hub contract
run: pnpm --filter agenthub-mobile-rn run mock:hub:check
# ── E2E Smoke ─────────────────────────────────
e2e-smoke:
name: E2E Smoke
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/pnpm-lock.yaml
- name: Install
run: pnpm install --frozen-lockfile
working-directory: ./app
- name: Install Playwright browsers
run: pnpm exec playwright install --with-deps chromium
working-directory: ./app
- name: Build desktop
run: pnpm build
working-directory: ./app/desktop
- name: Smoke test
# Only smoke.spec.ts runs in CI (static page checks).
# chat-real.spec.ts requires live Hub (port 8080) + Edge (port 3210)
# services which are not available in the CI sandbox.
# Run chat-real.spec.ts locally with all services up:
# pnpm exec playwright test --config e2e/playwright.config.ts --project=chromium chat-real.spec.ts
run: pnpm exec playwright test --config e2e/playwright.config.ts --project=chromium smoke.spec.ts
working-directory: ./app
# ── Validation ───────────────────────────────
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check whitespace
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
git diff --check "origin/${{ github.base_ref }}...HEAD"
elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
git diff --check HEAD^..HEAD
else
git diff --check
fi
- name: Secret guard
run: |
if [ "${{ github.event_name }}" = "pull_request" ]; then
if [ "${{ github.base_ref }}" = "master" ] && [ "${{ github.head_ref }}" = "dev/delicious233" ]; then
bash scripts/verify/check-secrets.sh --range HEAD^2^..HEAD^2
else
bash scripts/verify/check-secrets.sh --range "origin/${{ github.base_ref }}...HEAD"
fi
elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
bash scripts/verify/check-secrets.sh --range HEAD^..HEAD
else
bash scripts/verify/check-secrets.sh --worktree
fi
- name: Verify CI gate policy
shell: pwsh
run: ./scripts/verify/verify-ci-gates.ps1
- name: Verify project skill whitelist
shell: pwsh
run: ./scripts/verify/verify-project-skills.ps1
- name: Verify doc SSOT
shell: pwsh
run: ./scripts/verify/verify-doc-ssot.ps1
- name: Verify real E2E contract
shell: pwsh
run: ./scripts/verify/verify-real-e2e-contract.ps1
- name: Validate OpenAPI YAML
run: |
python -m pip install --quiet PyYAML
python -c "import pathlib, yaml; yaml.safe_load(pathlib.Path('api/openapi.yaml').read_text(encoding='utf-8')); print('yaml ok')"
# ── Vuln Scan: JS (pnpm audit --prod) ─────────
vuln-scan-js:
name: Vuln scan (pnpm audit --prod)
runs-on: ubuntu-latest
defaults:
run:
working-directory: app
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: pnpm
cache-dependency-path: app/pnpm-lock.yaml
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: pnpm audit --prod (severity-gated)
shell: bash
run: |
set -o pipefail
AUDIT_OUTPUT=$(pnpm audit --prod --json 2>/dev/null) || true
if [ -z "$AUDIT_OUTPUT" ]; then
echo "::notice::No production vulnerabilities found (clean audit)"
exit 0
fi
echo "$AUDIT_OUTPUT" | python3 -c "
import json, sys
raw = sys.stdin.read().strip()
if not raw:
print('::notice::No production vulnerabilities found')
sys.exit(0)
try:
data = json.loads(raw)
except Exception:
# Non-JSON output usually means no vulnerabilities found
print('::notice::pnpm audit produced no actionable JSON (likely clean)')
sys.exit(0)
advisories = data.get('advisories', {}) if isinstance(data, dict) else {}
if not advisories:
print('::notice::No production vulnerabilities found')
sys.exit(0)
has_critical = False
for adv_id, adv in advisories.items():
severity = adv.get('severity', 'unknown')
title = adv.get('title', adv_id)
module_name = adv.get('module_name', '')
vulnerable = adv.get('vulnerable_versions', '')
msg = f'{module_name}: {title} (vulnerable: {vulnerable}) [{severity.upper()}]'
if severity == 'critical':
print(f'::error title=CRITICAL CVE::{msg}')
has_critical = True
else:
print(f'::warning title={severity.upper()} CVE (non-blocking)::{msg}')
if has_critical:
print('::error::Critical CVE(s) found in production dependencies — failing build')
sys.exit(1)
print('::notice::No critical CVEs found (non-critical warnings above are non-blocking)')
"
# ── Vuln Scan: Go (govulncheck) ───────────────
vuln-scan-go:
name: Vuln scan (govulncheck)
runs-on: ubuntu-latest
strategy:
matrix:
module: [hub-server, edge-server]
defaults:
run:
working-directory: ${{ matrix.module }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ env.GO_VERSION }}
cache: true
cache-dependency-path: ${{ matrix.module }}/go.sum
- name: govulncheck (severity-gated)
shell: bash
run: |
set -o pipefail
VULN_OUTPUT=$(go run golang.org/x/vuln/cmd/govulncheck@latest -json ./... 2>/dev/null) || true
if [ -z "$VULN_OUTPUT" ]; then
echo "::notice::No Go vulnerabilities found in ${{ matrix.module }}"
exit 0
fi
echo "$VULN_OUTPUT" | python3 -c "
import json, sys
raw = sys.stdin.read().strip()
if not raw:
print('::notice::No Go vulnerabilities found')
sys.exit(0)
try:
data = json.loads(raw)
except Exception:
print('::warning::Could not parse govulncheck JSON output')
sys.exit(0)
findings = data.get('findings', []) if isinstance(data, dict) else []
if not findings:
print('::notice::No Go vulnerabilities found')
sys.exit(0)
has_critical = False
for f in findings:
osv = f.get('osv', {})
aliases = ', '.join(osv.get('aliases', [])[:3]) or 'N/A'
summary = osv.get('summary', '') or osv.get('details', '')[:200]
sev = 'unknown'
# Try database_specific severity field first
db_sev = osv.get('database_specific', {}).get('severity', '')
combined = f'{db_sev} {summary}'.lower()
if 'critical' in combined:
sev = 'critical'
elif 'high' in combined:
sev = 'high'
elif 'medium' in combined or 'moderate' in combined:
sev = 'medium'
elif 'low' in combined:
sev = 'low'
msg = f'{aliases}: {summary[:180]} [{sev.upper()}]'
if sev == 'critical':
print(f'::error title=CRITICAL Go CVE::{msg}')
has_critical = True
elif sev in ('high', 'medium'):
print(f'::warning title=Go CVE ({sev})::{msg}')
else:
print(f'::warning title=Go CVE::{msg}')
if has_critical:
print('::error::Critical Go CVE(s) found — failing build')
sys.exit(1)
print('::notice::No critical Go CVEs found (non-critical warnings above are non-blocking)')
"