diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..b303c07 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,21 @@ +version: 2 +updates: + # Grouped and monthly on purpose: this is a small team, and a wall of open PRs + # gets ignored, which is worse than a slightly older lockfile. Security + # advisories still arrive immediately, separately from this schedule. + - package-ecosystem: npm + directory: "/" + schedule: + interval: monthly + open-pull-requests-limit: 5 + groups: + dev-dependencies: + dependency-type: development + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: monthly + - package-ecosystem: pip + directory: "/" + schedule: + interval: monthly diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..3f5a528 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,108 @@ +name: CI + +# Aide moves real money and is driven by a model, for users who cannot see the +# screen to notice something went wrong. Every push runs the same gates a +# reviewer would run by hand, in parallel, so a red check is visible before a +# merge rather than after a withdrawal. +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +# A second push to the same branch makes the first run irrelevant. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + +env: + # lib/env.ts refuses to load without these, so `next build` cannot even import + # the payment routes unless they are present. CI never reaches a real + # provider — placeholders are the point: they prove the wiring, not the keys. + MONNIFY_API_KEY: ci-placeholder + MONNIFY_SECRET_KEY: ci-placeholder + MONNIFY_CONTRACT_CODE: "0000000000" + DEEPSEEK_API_KEY: ci-placeholder + NEXT_PUBLIC_CONVEX_URL: https://ci-placeholder.convex.cloud + +jobs: + typecheck: + name: Types + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run typecheck + + test: + name: Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + # Two vitest projects run here: plain Node for the money, agent and speech + # suites, and an edge-runtime VM for the Convex functions, which is the + # only environment convex-test can drive. + - run: npm test + + build: + name: Production build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + - run: npm ci + - run: npm run build + + speech: + name: Speech worker + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + cache: pip + # The neural voice is not a nice-to-have here — it is the entire + # interface. Both speech entry points guard their entry behind + # __main__, so importing them is safe and proves more than a syntax + # check: that edge-tts still installs and that the names these files + # reach for still exist. A break here would otherwise reach the user as + # the robotic browser fallback voice, with nothing on screen to explain it. + - run: pip install -r requirements.txt + - name: Import both speech entry points + run: | + python -c "import sys; sys.path[:0] = ['scripts', 'api']; import tts_worker, speak" + + secrets: + name: No secrets committed + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Refuse tracked env files and local Convex state + run: | + bad=$(git ls-files | grep -E '^(\.env($|\..*)|\.convex/)' | grep -v '^\.env\.example$' || true) + if [ -n "$bad" ]; then + echo "::error::These must never be committed:"; echo "$bad"; exit 1 + fi + - name: Refuse live-looking credentials + run: | + # .env.example carries placeholders only (MK_TEST_xxx, sk-xxxxxxxx), + # so these patterns match real keys and nothing else. + if git grep -nIE 'MK_PROD_[A-Za-z0-9]{6,}|sk-[A-Za-z0-9]{24,}|-----BEGIN [A-Z ]*PRIVATE KEY-----' -- . ':!.github/workflows/ci.yml'; then + echo "::error::A live-looking credential is committed."; exit 1 + fi diff --git a/.gitignore b/.gitignore index 6704187..dd203dc 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,10 @@ tts-env/ venv/ .venv/ .vercel + +# Throwaway build dirs used by side-by-side test servers (see AIDE_DIST_DIR) +.next-*/ + +# Python bytecode from the TTS worker / speak function +__pycache__/ +*.pyc diff --git a/README.md b/README.md index acdbfc2..e698a9e 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ A worker talks; Aide does the rest — finds jobs, runs a spoken skill assessmen real bank account, confirms incoming pay, and reads the balance back aloud. No screen required. +[![CI](https://github.com/David-Pjs/Aide/actions/workflows/ci.yml/badge.svg)](https://github.com/David-Pjs/Aide/actions/workflows/ci.yml) + [**Live demo →** aide-ng.vercel.app](https://aide-ng.vercel.app) · Open in Chrome and just talk. --- @@ -268,6 +270,26 @@ npm run balance # wallet balance check `npm run proof` prints `SUCCESS` or the documented `PENDING_AUTHORIZATION` sandbox state +### Continuous integration + +Every push and pull request runs five checks in parallel +([`.github/workflows/ci.yml`](.github/workflows/ci.yml)). They run against placeholder +credentials, never a real provider — what they prove is the wiring, not the keys. + +| Check | What it protects | +|---|---| +| **Types** | `tsc --noEmit` across app, Convex functions, and tests. | +| **Tests** | 267 tests over two vitest projects — plain Node for money, agent, and speech; an edge-runtime VM for the Convex functions, which is the only environment `convex-test` can drive. | +| **Production build** | A full `next build`, so a route that only breaks when compiled cannot reach a deploy. | +| **Speech worker** | Installs `edge-tts` and imports both speech entry points. A break here would otherwise reach a blind user as the robotic fallback voice, with nothing on screen to explain it. | +| **No secrets committed** | Fails on a tracked `.env`, on local Convex state (it holds an admin key), or on anything shaped like a live credential. | + +Run the same gates locally: + +```bash +npm run typecheck && npm test && npm run build +``` + ### Troubleshooting | Symptom | Fix | @@ -358,6 +380,24 @@ contrast. speech and incoming messages are announced automatically, `role="alert"` on errors, properly associated `