feat: enforce Guanghu-native HoloLake runtime laws
This commit is contained in:
parent
ccee303355
commit
67e6fcdd38
57 changed files with 1765 additions and 1504 deletions
|
|
@ -1,133 +1,15 @@
|
|||
# CI/CD Setup
|
||||
# HoloLake 原生工程流水线
|
||||
|
||||
## GitHub Actions Workflow
|
||||
流水线执行 HoloLake 已登记的光湖原生工程门,不调用外部评分服务,也不把
|
||||
托管平台的状态当作光湖事实。
|
||||
|
||||
Il workflow `ci.yml` esegue i seguenti check automatici:
|
||||
## 当前执行顺序
|
||||
|
||||
### 1. Tests
|
||||
- Frontend: `pnpm test`
|
||||
- Rust backend: `cargo test`
|
||||
1. 回读产品工程档案和固定的 `REPO-012` 协议注册表提交。
|
||||
2. 验证第三方评分规则没有重新进入现行权威面。
|
||||
3. 验证人格系统输入、类型化输出、能力登记和证据回执合同。
|
||||
4. 运行产品单元、集成、格式、静态检查、脚本语法和构建门。
|
||||
5. 对精确提交与源码树汇总 `GHNQG_PASS_100` 或 `GHNQG_FAIL_0`。
|
||||
|
||||
### 2. Test Coverage
|
||||
- Frontend: vitest con coverage reporting
|
||||
- Upload automatico su Codecov dai report LCOV frontend + Rust
|
||||
- Threshold configurabile in `vitest.config.ts`
|
||||
|
||||
### 3. Code Health (CodeScene)
|
||||
- Delta analysis su ogni PR/push
|
||||
- Fail se il code health diminuisce
|
||||
- Richiede secrets configurati (vedi sotto)
|
||||
|
||||
### 4. Documentation Check
|
||||
- Verifica che se cambia codice in `src/` o `src-tauri/`, anche `docs/` viene aggiornato
|
||||
- **Warning only** — non blocca il merge, solo un reminder
|
||||
- Skip con `[skip docs]` nel commit message
|
||||
- Aggiorna docs solo se la modifica invalida architettura/astrazioni/design già documentati
|
||||
|
||||
### 5. Lint & Format
|
||||
- ESLint per frontend
|
||||
- Clippy + rustfmt per Rust
|
||||
|
||||
## Setup Required
|
||||
|
||||
### CodeScene Secrets
|
||||
Aggiungi questi secrets nel repository GitHub (Settings → Secrets → Actions):
|
||||
|
||||
```
|
||||
CODESCENE_TOKEN=<your-codescene-pat>
|
||||
CODESCENE_PROJECT_ID=<your-project-id>
|
||||
```
|
||||
|
||||
Il PAT di CodeScene è lo stesso che usi localmente (~/.codescene/token).
|
||||
Il project ID lo trovi nella dashboard CodeScene.
|
||||
|
||||
### Codecov Setup
|
||||
- Installa/attiva il repo in Codecov una volta sola tramite GitHub App / import del repository.
|
||||
- Nessun `CODECOV_TOKEN` richiesto in GitHub Actions: `ci.yml` usa OIDC (`id-token: write` + `use_oidc: true`).
|
||||
- Il workflow carica `coverage/lcov.info` (Vitest) e `coverage/rust.lcov` (cargo-llvm-cov).
|
||||
- L'action Codecov resta con integrity validation attiva. Se Codecov ruota la chiave GPG del CLI, aggiorna il pin dell'action invece di usare `skip_validation`.
|
||||
|
||||
### Telemetry Secrets For Release Builds
|
||||
Aggiungi anche questi secrets per i workflow `release.yml` e `release-stable.yml`:
|
||||
|
||||
```
|
||||
VITE_SENTRY_DSN=<frontend sentry dsn>
|
||||
SENTRY_DSN=<same dsn for rust/native crash reporting>
|
||||
VITE_POSTHOG_KEY=<posthog project api key>
|
||||
VITE_POSTHOG_HOST=https://eu.i.posthog.com
|
||||
```
|
||||
|
||||
Senza questi valori, i build distribuiti possono mantenere i toggle telemetry nelle Settings ma non inizializzare davvero PostHog/Sentry.
|
||||
|
||||
### Windows Authenticode Secrets For Release Builds
|
||||
Windows alpha e stable release builds usano sempre le firme Tauri updater. Se i secret Authenticode sono presenti, il workflow firma anche gli installer Windows e verifica le firme; se mancano, emette un warning e pubblica gli artifact Windows senza Authenticode finche' il certificato non e' pronto.
|
||||
|
||||
```
|
||||
WINDOWS_CODE_SIGNING_CERTIFICATE=<base64-encoded pfx>
|
||||
WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD=<pfx password>
|
||||
```
|
||||
|
||||
Opzionale:
|
||||
|
||||
```
|
||||
WINDOWS_CODE_SIGNING_CERTIFICATE_THUMBPRINT=<expected thumbprint>
|
||||
WINDOWS_CODE_SIGNING_TIMESTAMP_URL=https://timestamp.digicert.com
|
||||
```
|
||||
|
||||
Il certificato deve essere un certificato di code signing trusted; un certificato self-signed non e' adatto per i release artifact pubblici.
|
||||
|
||||
### Coverage Thresholds
|
||||
Configura in `vitest.config.ts`:
|
||||
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
test: {
|
||||
coverage: {
|
||||
lines: 80,
|
||||
functions: 80,
|
||||
branches: 80,
|
||||
statements: 80,
|
||||
// Fail CI se sotto threshold
|
||||
thresholds: {
|
||||
lines: 80,
|
||||
functions: 80,
|
||||
branches: 80,
|
||||
statements: 80
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## Local Testing
|
||||
|
||||
Prima di pushare, puoi testare localmente:
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pnpm test && cargo test
|
||||
|
||||
# Check coverage
|
||||
pnpm test:coverage
|
||||
|
||||
# Lint
|
||||
pnpm lint
|
||||
cargo clippy
|
||||
cargo fmt --check
|
||||
|
||||
# CodeScene (local)
|
||||
codescene delta-analysis --base-revision origin/main
|
||||
```
|
||||
|
||||
## Workflow Triggers
|
||||
|
||||
- **Push**: su `main`
|
||||
- **Pull Request**: verso `main`
|
||||
- **Manuale**: `workflow_dispatch`
|
||||
|
||||
Nota: l'upload a Codecov gira su push a `main` e sulle PR dello stesso repository. Le PR da fork saltano l'upload per evitare problemi di permessi OIDC.
|
||||
|
||||
## Status Checks
|
||||
|
||||
Tutti i check devono passare prima di poter fare merge.
|
||||
Se un check fallisce, vedrai il dettaglio nei logs di GitHub Actions.
|
||||
流水线通过只证明该源码树完成了已声明的工程门,不证明已经上传、部署、在线、
|
||||
出生或取得服务器权限。部署与运行状态必须由目标节点自己的回执独立证明。
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Full history for CodeScene
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@f40ffcd9367d9f12939873eb1018b921a783ffaa
|
||||
|
|
@ -72,43 +72,8 @@ jobs:
|
|||
if: steps.docs-changes.outputs.should-build == 'true'
|
||||
run: pnpm docs:build
|
||||
|
||||
# ── 1. Code Health (CodeScene — Hotspot + Average Code Health gates) ──
|
||||
# Enforces minimum floors on BOTH hotspot and average code health.
|
||||
# Thresholds come from .codescene-thresholds so CI and local hooks match.
|
||||
- name: Code Health gates
|
||||
env:
|
||||
CODESCENE_PAT: ${{ secrets.CODESCENE_PAT }}
|
||||
CODESCENE_PROJECT_ID: ${{ secrets.CODESCENE_PROJECT_ID }}
|
||||
run: |
|
||||
HOTSPOT_THRESHOLD=$(grep '^HOTSPOT_THRESHOLD=' .codescene-thresholds | cut -d= -f2)
|
||||
AVERAGE_THRESHOLD=$(grep '^AVERAGE_THRESHOLD=' .codescene-thresholds | cut -d= -f2)
|
||||
API_RESPONSE=$(curl -sf \
|
||||
-H "Authorization: Bearer $CODESCENE_PAT" \
|
||||
-H "Accept: application/json" \
|
||||
"https://api.codescene.io/v2/projects/$CODESCENE_PROJECT_ID")
|
||||
HOTSPOT_SCORE=$(echo "$API_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['analysis']['hotspot_code_health']['now'])")
|
||||
AVERAGE_SCORE=$(echo "$API_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['analysis']['code_health']['now'])")
|
||||
echo "Hotspot Code Health: $HOTSPOT_SCORE (threshold: $HOTSPOT_THRESHOLD)"
|
||||
echo "Average Code Health: $AVERAGE_SCORE (threshold: $AVERAGE_THRESHOLD)"
|
||||
python3 -c "
|
||||
hotspot = float('$HOTSPOT_SCORE')
|
||||
average = float('$AVERAGE_SCORE')
|
||||
ht = float('$HOTSPOT_THRESHOLD')
|
||||
at = float('$AVERAGE_THRESHOLD')
|
||||
failed = False
|
||||
if hotspot < ht:
|
||||
print(f'❌ Hotspot Code Health {hotspot:.2f} is below threshold {ht}')
|
||||
failed = True
|
||||
else:
|
||||
print(f'✅ Hotspot Code Health {hotspot:.2f} ≥ {ht}')
|
||||
if average < at:
|
||||
print(f'❌ Average Code Health {average:.2f} is below threshold {at}')
|
||||
failed = True
|
||||
else:
|
||||
print(f'✅ Average Code Health {average:.2f} ≥ {at}')
|
||||
if failed:
|
||||
exit(1)
|
||||
"
|
||||
- name: Guanghu native authority contract
|
||||
run: pnpm test:native-authority && pnpm test:native-core
|
||||
|
||||
# ── 2. Documentation check (warning only — does not fail build) ───────
|
||||
- name: Check docs are updated
|
||||
|
|
@ -133,7 +98,7 @@ jobs:
|
|||
run: pnpm lint
|
||||
|
||||
frontend-tests:
|
||||
name: Frontend Tests & Coverage
|
||||
name: Frontend Tests
|
||||
runs-on: macos-15
|
||||
|
||||
steps:
|
||||
|
|
@ -153,25 +118,11 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
# The coverage command runs the canonical frontend test suite.
|
||||
- name: Bundle MCP server resources (required by Tauri build)
|
||||
run: node scripts/bundle-mcp-server.mjs
|
||||
|
||||
- name: Frontend tests + coverage (≥70% lines/functions/branches/statements)
|
||||
run: pnpm test:coverage
|
||||
# Thresholds configured in vite.config.ts — exits non-zero if coverage drops
|
||||
|
||||
- name: Upload frontend coverage to Codecov
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: codecov/codecov-action@5975040f7f7d40edaff8d784b576fd65ae95c073
|
||||
with:
|
||||
use_oidc: true
|
||||
fail_ci_if_error: true
|
||||
disable_search: true
|
||||
files: ./coverage/lcov.info
|
||||
flags: frontend
|
||||
verbose: true
|
||||
# OIDC avoids long-lived CODECOV_TOKEN secrets.
|
||||
- name: Frontend tests
|
||||
run: pnpm test
|
||||
|
||||
rust-quality:
|
||||
name: Rust Tests & Quality Checks
|
||||
|
|
@ -196,32 +147,11 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-cargo-${{ env.RUST_TARGET_CACHE_VERSION }}-
|
||||
|
||||
- name: Install cargo-llvm-cov
|
||||
- name: Install native coverage executor
|
||||
uses: taiki-e/install-action@e5de28abeb52d916c5e5875d54b21a9e738b61ec
|
||||
|
||||
- name: Rust tests + coverage (≥85% lines)
|
||||
run: |
|
||||
mkdir -p coverage
|
||||
cargo llvm-cov \
|
||||
--manifest-path src-tauri/Cargo.toml \
|
||||
--ignore-filename-regex 'lib\.rs|main\.rs|menu\.rs' \
|
||||
--lcov \
|
||||
--output-path coverage/rust.lcov \
|
||||
--fail-under-lines 85
|
||||
# cargo-llvm-cov exits non-zero if line coverage drops below 85%
|
||||
# lib.rs/main.rs/menu.rs are Tauri boilerplate -- not meaningfully unit-testable.
|
||||
|
||||
- name: Upload Rust coverage to Codecov
|
||||
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: codecov/codecov-action@5975040f7f7d40edaff8d784b576fd65ae95c073
|
||||
with:
|
||||
use_oidc: true
|
||||
fail_ci_if_error: true
|
||||
disable_search: true
|
||||
files: ./coverage/rust.lcov
|
||||
flags: rust
|
||||
verbose: true
|
||||
# OIDC avoids long-lived CODECOV_TOKEN secrets.
|
||||
- name: Rust tests
|
||||
run: cargo test --manifest-path src-tauri/Cargo.toml
|
||||
|
||||
- name: Clippy (Rust)
|
||||
run: cargo clippy --manifest-path=src-tauri/Cargo.toml -- -D warnings
|
||||
|
|
@ -229,6 +159,13 @@ jobs:
|
|||
- name: Format check (Rust)
|
||||
run: cargo fmt --manifest-path=src-tauri/Cargo.toml -- --check
|
||||
|
||||
- name: GLS-0844 HoloLake native quality receipt
|
||||
run: |
|
||||
mkdir -p "$RUNNER_TEMP/ghnqg"
|
||||
bash scripts/run-hololake-native-quality-gate.sh \
|
||||
"$RUNNER_TEMP/ghnqg/GHNQG-${GITHUB_SHA}.hldp"
|
||||
grep -Fxq 'result: PASS_100' "$RUNNER_TEMP/ghnqg/GHNQG-${GITHUB_SHA}.hldp"
|
||||
|
||||
linux-build:
|
||||
name: Linux build verification
|
||||
# Keep the normal push CI lane under the 10-minute target. The release
|
||||
|
|
|
|||
Loading…
Reference in a new issue