diff --git a/.github/workflows/audit-check.yml b/.github/workflows/audit-check.yml index 515e41fd..ed347dde 100644 --- a/.github/workflows/audit-check.yml +++ b/.github/workflows/audit-check.yml @@ -6,7 +6,7 @@ on: push: branches: [main, develop] schedule: - - cron: "0 0 * * 0" # Weekly on Sunday + - cron: "0 0 * * 0" # Weekly on Sunday jobs: audit: @@ -18,10 +18,10 @@ jobs: steps: - name: 📥 Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + uses: actions/checkout@v4 - name: 🟢 Setup Node.js - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + uses: actions/setup-node@v4 with: node-version: "20" @@ -31,15 +31,15 @@ jobs: run: | npm install --prefer-offline --no-audit 2>&1 | head -20 AUDIT_JSON=$(npm audit --json 2>/dev/null || echo '{"metadata":{"vulnerabilities":{"critical":0,"high":0,"moderate":0}}}') - + CRITICAL=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.critical // 0') HIGH=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.high // 0') MODERATE=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.moderate // 0') - + echo "backend_critical=$CRITICAL" >> $GITHUB_OUTPUT echo "backend_high=$HIGH" >> $GITHUB_OUTPUT echo "backend_moderate=$MODERATE" >> $GITHUB_OUTPUT - + echo "### 🔍 Backend Audit Results" >> $GITHUB_STEP_SUMMARY echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY @@ -47,7 +47,7 @@ jobs: echo "| High | $HIGH |" >> $GITHUB_STEP_SUMMARY echo "| Moderate | $MODERATE |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - + if (( CRITICAL > 0 )); then echo "❌ **CRITICAL vulnerabilities detected**" >> $GITHUB_STEP_SUMMARY echo "::error::Critical vulnerabilities in backend: $CRITICAL" @@ -65,15 +65,15 @@ jobs: run: | npm install --prefer-offline --no-audit 2>&1 | head -20 AUDIT_JSON=$(npm audit --json 2>/dev/null || echo '{"metadata":{"vulnerabilities":{"critical":0,"high":0,"moderate":0}}}') - + CRITICAL=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.critical // 0') HIGH=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.high // 0') MODERATE=$(echo "$AUDIT_JSON" | jq '.metadata.vulnerabilities.moderate // 0') - + echo "frontend_critical=$CRITICAL" >> $GITHUB_OUTPUT echo "frontend_high=$HIGH" >> $GITHUB_OUTPUT echo "frontend_moderate=$MODERATE" >> $GITHUB_OUTPUT - + echo "### 🔍 Frontend Audit Results" >> $GITHUB_STEP_SUMMARY echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY @@ -81,7 +81,7 @@ jobs: echo "| High | $HIGH |" >> $GITHUB_STEP_SUMMARY echo "| Moderate | $MODERATE |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - + if (( CRITICAL > 0 )); then echo "❌ **CRITICAL vulnerabilities detected**" >> $GITHUB_STEP_SUMMARY echo "::error::Critical vulnerabilities in frontend: $CRITICAL" @@ -95,10 +95,10 @@ jobs: - name: 💬 Comment on PR with audit summary if: github.event_name == 'pull_request' && always() - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} - script: >- + script: | const backendCritical = '${{ steps.backend-audit.outputs.backend_critical }}' || '0'; const backendHigh = '${{ steps.backend-audit.outputs.backend_high }}' || '0'; const frontendCritical = '${{ steps.frontend-audit.outputs.frontend_critical }}' || '0'; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 09aa0fc9..20cabdcf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -221,6 +221,8 @@ jobs: - name: Backup / restore drill run: ./scripts/pg-backup-restore.sh drill + # Futurenet deploy is intentionally NOT part of this job. + # Use the manual "Futurenet Smoke (manual)" workflow_dispatch instead. contract: name: Contract (Rust) runs-on: ubuntu-latest diff --git a/.github/workflows/futurenet-smoke.yml b/.github/workflows/futurenet-smoke.yml new file mode 100644 index 00000000..63e722e5 --- /dev/null +++ b/.github/workflows/futurenet-smoke.yml @@ -0,0 +1,88 @@ +name: Futurenet Smoke (manual) + +# Manual-only: never runs on push/pull_request so it cannot block PR CI. +# Trigger via: Actions → "Futurenet Smoke (manual)" → Run workflow +on: + workflow_dispatch: + inputs: + stellar_cli: + description: "stellar-cli version (e.g. 25.2.0)" + required: false + default: "25.2.0" + +# Prevent two smoke runs from racing on the same network identity. +concurrency: + group: futurenet-smoke + cancel-in-progress: false + +jobs: + smoke: + name: Deploy & verify on Futurenet + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - name: Install system dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y libdbus-1-dev libudev-dev pkg-config + + - name: Install Rust (stable) + uses: dtolnay/rust-toolchain@stable + with: + targets: wasm32-unknown-unknown,wasm32v1-none + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + workspaces: contract + prefix-key: futurenet-smoke + + - name: Cache stellar CLI binary + id: stellar-cache + uses: actions/cache@v4 + with: + path: ~/.cargo/bin/stellar + key: stellar-cli-${{ inputs.stellar_cli }}-${{ runner.os }}-v1 + + - name: Install Stellar CLI + if: steps.stellar-cache.outputs.cache-hit != 'true' + run: cargo install stellar-cli --locked --version ${{ inputs.stellar_cli }} + + - name: Deploy and verify on Futurenet + id: deploy + run: | + ./scripts/deploy.sh \ + --network futurenet \ + --source "ci-${{ github.run_id }}-${{ github.run_attempt }}" \ + --out "./deployed-futurenet-smoke.json" \ + --env-out "./.env.deployed-futurenet-smoke" + working-directory: contract + + - name: Smoke summary + if: always() + run: | + echo "## Futurenet Smoke" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [[ "${{ steps.deploy.outcome }}" == "success" ]]; then + echo "✅ Deploy + post-deploy verification passed." >> $GITHUB_STEP_SUMMARY + if [[ -f contract/deployed-futurenet-smoke.json ]]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo '```json' >> $GITHUB_STEP_SUMMARY + cat contract/deployed-futurenet-smoke.json >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + fi + else + echo "❌ Deploy step failed — check logs above." >> $GITHUB_STEP_SUMMARY + fi + + - name: Upload deployment artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: futurenet-smoke-${{ github.run_id }} + path: | + contract/deployed-futurenet-smoke.json + contract/.env.deployed-futurenet-smoke + retention-days: 7 diff --git a/docs/release/FUTURENET_SMOKE_CHECKLIST.md b/docs/release/FUTURENET_SMOKE_CHECKLIST.md new file mode 100644 index 00000000..b7f4a8f3 --- /dev/null +++ b/docs/release/FUTURENET_SMOKE_CHECKLIST.md @@ -0,0 +1,50 @@ +# Futurenet Smoke – Manual Checklist + +This workflow is **manual-only** (`workflow_dispatch`). It never runs on push or +pull_request, so it cannot block PR CI. + +## How to trigger + +1. Go to **Actions → Futurenet Smoke (manual) → Run workflow**. +2. Optionally override the `stellar_cli` version (default `25.2.0`). +3. Click **Run workflow**. + +## What it does + +| Step | Description | +|------|-------------| +| Build | Compiles all five contracts to WASM (`myfans-token`, `creator-registry`, `subscription`, `content-access`, `earnings`) | +| Deploy | Deploys each contract to Futurenet using a fresh ephemeral identity (`ci--`) | +| Init | Initialises each contract in dependency order | +| Smoke | Calls read-only methods (`admin`, `is-paused`, `has-access`) and asserts expected values | +| Artifacts | Uploads `deployed-futurenet-smoke.json` and `.env.deployed-futurenet-smoke` (7-day retention) | + +## Pass criteria + +- All five contracts deploy without error. +- `token.admin` returns the deployer public key. +- `subscription.is-paused` returns `false`. +- `content-access.has-access` returns `false` for the deployer self-check. +- `earnings.admin` returns the deployer public key. +- Artifacts are uploaded and downloadable from the run summary. + +## Concurrency + +Only one smoke run executes at a time (`concurrency: futurenet-smoke`, +`cancel-in-progress: false`). A second trigger will queue until the first +finishes. + +## Relationship to PR CI + +The `ci.yml` workflow (triggered on push/PR) only runs `cargo build` and +`cargo test` for contracts — it does **not** deploy to any network. Futurenet +deploy is intentionally gated behind this manual workflow. + +## Troubleshooting + +| Symptom | Likely cause | Fix | +|---------|-------------|-----| +| `stellar: command not found` | CLI cache miss + install failed | Re-run; cache will rebuild | +| `Unable to locate wasm for package` | Build failed silently | Check the "Build" step logs | +| `SMOKE FAIL: token.admin` | Init call failed or wrong contract deployed | Check "initializing" step logs | +| Futurenet RPC timeout | Network instability | Re-trigger the workflow |