Merge pull request #172 from Macnelson9/idempotency #184
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main, "feat/**", "fix/**"] | |
| pull_request: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # ── Soroban ABI golden-vector drift guard ──────────────────────────────── | |
| golden-vectors: | |
| name: Soroban ABI golden vectors | |
| runs-on: ubuntu-latest | |
| # Run whenever contracts or backend builder code changes | |
| if: | | |
| github.event_name == 'push' || | |
| contains(toJson(github.event.pull_request.changed_files), 'contracts/') || | |
| contains(toJson(github.event.pull_request.changed_files), 'backend/src/soroban/') || | |
| contains(toJson(github.event.pull_request.changed_files), 'backend/src/tx/') | |
| defaults: | |
| run: | |
| working-directory: backend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - run: npm install | |
| - name: Run golden-vector encoding tests | |
| run: npx jest --testPathPattern="golden-vectors" --no-coverage | |
| - name: Verify vectors are up-to-date (no uncommitted drift) | |
| run: | | |
| npx ts-node ../scripts/refresh-vectors.ts | |
| if ! git diff --exit-code backend/src/soroban/golden-vectors.json; then | |
| echo "::error::golden-vectors.json is stale. Run 'npm run refresh-vectors' locally, review the diff, and commit the updated file." | |
| exit 1 | |
| fi | |
| # ── Smart contract ──────────────────────────────────────────────────────── | |
| contract: | |
| name: Contract (Rust / Soroban) | |
| runs-on: ubuntu-latest | |
| env: | |
| RUSTFLAGS: "-D warnings" | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: wasm32-unknown-unknown | |
| components: rustfmt, clippy | |
| - uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| target | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} | |
| - run: cargo fmt --all -- --check | |
| - run: cargo clippy --target wasm32-unknown-unknown --release -- -D warnings | |
| - run: cargo test | |
| - run: cargo build --target wasm32-unknown-unknown --release | |
| - name: Record wasm SHA-256 | |
| run: sha256sum target/wasm32-unknown-unknown/release/niffyinsure.wasm | tee niffyinsure.wasm.sha256 | |
| - name: Simulate wasm drift (staging acceptance test) | |
| run: | | |
| ACTUAL=$(cat niffyinsure.wasm.sha256 | awk '{print $1}') | |
| EXPECTED=$(jq -r '.contracts[0].expectedWasmHash' contracts/deployment-registry.json) | |
| # In CI the registry holds a placeholder; drift is detected when they differ. | |
| # In staging, set NIFFYINSURE_EXPECTED_WASM_HASH to a known-wrong value to | |
| # verify the alert path fires. Exit 0 here — alerting is runtime, not build-time. | |
| if [ "$EXPECTED" = "\${NIFFYINSURE_EXPECTED_WASM_HASH}" ]; then | |
| echo "Registry uses env placeholder — skipping drift comparison in CI" | |
| elif [ "$ACTUAL" != "$EXPECTED" ]; then | |
| echo "::warning::Wasm drift detected: expected=$EXPECTED actual=$ACTUAL" | |
| else | |
| echo "Wasm hash matches registry: $ACTUAL" | |
| fi | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: niffyinsure-wasm-${{ github.sha }} | |
| path: | | |
| target/wasm32-unknown-unknown/release/niffyinsure.wasm | |
| niffyinsure.wasm.sha256 | |
| retention-days: 30 | |
| # ── Backend ─────────────────────────────────────────────────────────────── | |
| backend: | |
| name: Backend (Node / TypeScript) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: backend | |
| env: | |
| REDIS_HOST: 127.0.0.1 | |
| REDIS_PORT: 6379 | |
| NODE_ENV: test | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # Install Redis directly on the runner — avoids Docker Hub rate limits entirely | |
| - name: Start Redis | |
| run: | | |
| sudo apt-get update -qq | |
| sudo apt-get install -y redis-server | |
| sudo systemctl start redis-server | |
| redis-cli ping | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - run: npm install | |
| - run: npm run lint | |
| - run: npm run build | |
| - run: npm test | |
| # ── Dependency audit / supply-chain ───────────────────────────────────── | |
| # Policy: CRITICAL CVEs fail the build. HIGH CVEs produce a warning and | |
| # must be triaged within 7 days. Accepted risks require a signed-off entry | |
| # in docs/ops/audit-exceptions.md before the override label is applied. | |
| # Override process: | |
| # 1. Engineer opens a PR adding the CVE to audit-exceptions.md with | |
| # justification, mitigations, and a review-by date. | |
| # 2. A second engineer approves the PR. | |
| # 3. Add the GitHub label `audit-exception-approved` to the failing PR. | |
| # 4. Re-run this job — it will pass once the exception is documented. | |
| dependency-audit: | |
| name: Dependency Audit (npm / SBOM) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| - name: Audit backend dependencies | |
| working-directory: backend | |
| run: | | |
| npm install --ignore-scripts | |
| # Fail on critical; warn on high (exit 0 so we can capture output) | |
| npm audit --audit-level=critical | |
| npm audit --audit-level=high || echo "::warning::High-severity advisories found — triage within 7 days per audit policy" | |
| - name: Audit frontend dependencies | |
| working-directory: frontend | |
| run: | | |
| npm ci --ignore-scripts | |
| npm audit --audit-level=critical | |
| npm audit --audit-level=high || echo "::warning::High-severity advisories found — triage within 7 days per audit policy" | |
| - name: Generate SBOM (backend) | |
| working-directory: backend | |
| run: npx --yes @cyclonedx/cyclonedx-npm --output-format JSON --output-file ../sbom-backend.json | |
| - name: Generate SBOM (frontend) | |
| working-directory: frontend | |
| run: npx --yes @cyclonedx/cyclonedx-npm --output-format JSON --output-file ../sbom-frontend.json | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: sbom-${{ github.sha }} | |
| path: | | |
| sbom-backend.json | |
| sbom-frontend.json | |
| retention-days: 90 | |
| # ── Frontend ────────────────────────────────────────────────────────────── | |
| frontend: | |
| name: Frontend (Next.js / TypeScript) | |
| runs-on: ubuntu-latest | |
| defaults: | |
| run: | |
| working-directory: frontend | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| cache-dependency-path: frontend/package-lock.json | |
| - run: npm ci | |
| - run: npm run lint | |
| - run: npm run check-docs | |
| - run: npm run build | |
| - run: npm test |