Repository navigation
Harden StudentHubHelp chatbot reliability and controls #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e2cd34f
ea614ba
d39861f
8e3ad25
835c930
9238ca3
06c0a49
cd0da17
d8b5c9d
e11e4c4
d86fab1
a8cc46b
eee370b
20de096
7e96d58
9acec1c
2a00fa8
5482758
4fef81b
6f97cde
46ee0c2
7342b33
417b42c
ffd5c04
5d93c53
223bd8b
c7af7c4
f2c770b
f9e4874
3593a23
525857d
6a52597
6005d21
28ca5bb
6cf2d52
f68272b
dfdbd52
deb4212
e190d2a
b3f53a0
b36d1f6
e511548
181834b
5b4b871
9662fb9
fc93545
80dba35
7e42167
db068a4
c064b3b
731ebd5
5996c6b
6ce0573
6eb8fbe
25c33a8
4e9c746
746158a
164e7e7
3704adb
cdec1f5
b4abb7b
2f6a489
cece043
8cff683
d27e623
ab91fa5
3d9fd53
7c1f85f
8ed4101
6d91d55
e4fe3f5
3bc180c
651aa4c
3efbd01
8bb7de3
ee9d8b9
12af371
a4f8c86
e125349
7dd2110
1b18713
9ac35be
1a456f2
c82504b
1c2035b
8938619
878f3a5
a3039b6
34c0236
c1f2f3b
fc41c56
d31a1db
b480ade
de4b1bc
1a511c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| name: Chatbot PR validation | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - fix/chatbot-reliability-security | ||
| paths: | ||
| - 'supabase/functions/studenthubhelp-chat/**' | ||
| - 'supabase/migrations/*chatbot*' | ||
| - 'ai-chatbot/**' | ||
| - 'widget.js' | ||
| - '.github/workflows/chatbot-pr-check.yml' | ||
| pull_request: | ||
| paths: | ||
| - 'supabase/functions/studenthubhelp-chat/**' | ||
| - 'supabase/migrations/*chatbot*' | ||
| - 'ai-chatbot/**' | ||
| - 'widget.js' | ||
| - '.github/workflows/chatbot-pr-check.yml' | ||
|
|
||
| permissions: | ||
| contents: write | ||
|
|
||
| jobs: | ||
| edge-function-check: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: denoland/setup-deno@v2 | ||
| with: | ||
| deno-version: v2.x | ||
| - name: Type-check Supabase Edge Function | ||
| run: deno check supabase/functions/studenthubhelp-chat/index.ts | ||
|
|
||
| react-chatbot-check: | ||
| runs-on: ubuntu-latest | ||
| defaults: | ||
| run: | ||
| working-directory: ai-chatbot | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| - uses: actions/setup-node@v6 | ||
| with: | ||
| node-version: 20 | ||
| cache: npm | ||
| cache-dependency-path: ai-chatbot/package-lock.json | ||
| - name: Install dependencies | ||
| run: npm install --no-audit | ||
| - name: Update only audited vulnerable packages | ||
| run: npm update vite body-parser proxy-addr qs source-map-js --no-audit | ||
| - name: Persist patched dependency lockfile | ||
| env: | ||
| TARGET_BRANCH: ${{ github.head_ref || github.ref_name }} | ||
| HEAD_REPOSITORY: ${{ github.event.pull_request.head.repo.full_name || github.repository }} | ||
| run: | | ||
| if [ "$HEAD_REPOSITORY" = "$GITHUB_REPOSITORY" ] && [ -n "$TARGET_BRANCH" ]; then | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
| git add package-lock.json | ||
| if ! git diff --cached --quiet; then | ||
| git commit -m "chore(chatbot): patch audited dependencies [skip ci]" | ||
| git push origin "HEAD:$TARGET_BRANCH" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Suggestion: Assessment: 🟠 Prompt for AI Agent 🤖This is a comment left during a code review.
**Path:** .github/workflows/chatbot-pr-check.yml
**Line:** 64:64
**Comment:**
*Race Condition: `push` and `pull_request` both run for this branch; if `npm update` changes the lockfile, both workflows push from the same parent, so one push is rejected and its check fails.
Validate the correctness of the flagged issue. If correct, How can I resolve this? If you propose a fix, implement it and please make it concise.
Once fix is implemented, also check other comments on the same PR, and ask user if the user wants to fix the rest of the comments as well. if said yes, then fetch all the comments validate the correctness and implement a minimal fix |
||
| fi | ||
| fi | ||
| - name: Audit dependency tree | ||
| run: npm audit | ||
| - name: Report dependency advisories | ||
| if: always() | ||
| run: | | ||
| npm audit --json > /tmp/studenthubhelp-npm-audit.json || true | ||
| node - <<'NODE' | ||
| const fs = require('fs'); | ||
| const report = JSON.parse(fs.readFileSync('/tmp/studenthubhelp-npm-audit.json', 'utf8')); | ||
| const vulnerabilities = report.vulnerabilities || {}; | ||
| const entries = Object.entries(vulnerabilities); | ||
| console.log('npm audit summary:', JSON.stringify(report.metadata?.vulnerabilities || {})); | ||
| for (const [name, item] of entries) { | ||
| console.log(JSON.stringify({ | ||
| name, | ||
| severity: item.severity, | ||
| range: item.range, | ||
| direct: item.isDirect, | ||
| fixAvailable: item.fixAvailable, | ||
| via: item.via | ||
| })); | ||
| } | ||
| NODE | ||
| - name: Validate regression scripts and production API references | ||
| run: | | ||
| node --check tests/chatbot-regression.mjs | ||
| node --check ../widget.js | ||
| node --check public/widget.js | ||
| if grep -R -nE 'https?://(localhost|127\.0\.0\.1):3000' src; then echo 'Local Express API reference found in client source'; exit 1; fi | ||
| - name: Type-check React chatbot component | ||
| run: npx tsc --noEmit --skipLibCheck --jsx react-jsx --target ES2020 --module ESNext --moduleResolution bundler --allowImportingTsExtensions --types vite/client src/components/ChatWidget.tsx | ||
| - name: Restore Vite source entry for validation | ||
| run: | | ||
| cat > index.html <<'EOF' | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>StudentHubHelp AI Chatbot</title> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="/src/main.tsx"></script> | ||
| </body> | ||
| </html> | ||
| EOF | ||
| - name: Build chatbot | ||
| run: | | ||
| npm run build | ||
| test ! -f dist/server.cjs | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| VITE_CHAT_API_URL=https://idurlccrarznnnqixxsd.supabase.co/functions/v1/studenthubhelp-chat |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,39 +1,36 @@ | ||
| # StudentHubHelp AI Chatbot | ||
|
|
||
| Production-oriented StudentHubHelp AI chatbot based on Gemini 3.8 Flash and live Supabase data. | ||
| StudentHubHelp's public chatbot is served by the Supabase Edge Function and reads active listings from the category-specific Supabase tables. | ||
|
|
||
| ## Data rule | ||
| ## Production request path | ||
|
|
||
| Property recommendations are loaded from the StudentHubHelp public property tables: | ||
| - Public website embed: `widget.js` -> `/functions/v1/studenthubhelp-chat` | ||
| - React chatbot: `ai-chatbot/src/components/ChatWidget.tsx` -> the same Edge Function | ||
| - Edge Function: authoritative runtime config, rate limits, deterministic listing search, and optional Gemini response enhancement | ||
| - Supabase: `hostels`, `tiffins`, `libraries`, `cafes`, and `bookstores` | ||
|
|
||
| - `hostels` | ||
| - `tiffins` | ||
| - `libraries` | ||
| - `cafes` | ||
| - `bookstores` | ||
| Both browser clients use the same production endpoint. Do not point either client at the legacy Express `/api/chat` route. | ||
|
|
||
| Only rows whose `status` is `active` are exposed to the chatbot. No property records, prices, ratings, contacts or recommendations are hardcoded as demo data. | ||
| ## Database and security | ||
|
|
||
| - Only rows with `status = 'active'` are eligible for public recommendations. | ||
| - The Edge Function uses the private `chatbot_rate_limits` table through the `consume_chatbot_rate_limit` security-definer RPC. Apply the checked-in migration before deploying the Edge Function version that calls it. | ||
| - Keep the Supabase service-role key server-side only. Browser clients use the public/publishable key. | ||
| - The chatbot fails closed when its admin config is missing/unavailable. If Cloudflare's client-IP header is absent, it falls back to lower-threshold session/user-agent and explicitly untrusted proxy keys; this fallback is weaker than a verified edge IP and must be checked in staging. | ||
|
|
||
| ## Environment | ||
|
|
||
| Set: | ||
| For the Edge Function, configure the Supabase URL/key and Gemini key as Supabase Function secrets. The React build accepts `VITE_CHAT_API_URL` and `VITE_SUPABASE_ANON_KEY`; the default chat URL is the production Edge Function. | ||
|
|
||
| - `GEMINI_API_KEY` | ||
| - `SUPABASE_URL` | ||
| - `SUPABASE_ANON_KEY` | ||
| - `APP_URL` (optional) | ||
| ## Legacy Express preview | ||
|
|
||
| The Supabase key is used server-side for public active-listing reads. Never expose a service-role key in browser code. | ||
| `server.ts` and its `/api/*` routes are a legacy local preview harness, not the production source of truth. Its config and lead arrays are in-memory and reset when the process restarts. Do not deploy those endpoints as a public production API or use them for authoritative chatbot settings, leads, or property data. | ||
|
|
||
| ## Local run | ||
| Run the React UI locally with `npm run dev`. To intentionally start the isolated legacy Express preview, use `npm run dev:legacy-server`. The production build is static Vite output only; it does not bundle `server.ts` or the legacy `/api/*` routes. | ||
|
|
||
| ```bash | ||
| npm install | ||
| npm run dev | ||
| # Optional legacy preview only: | ||
| npm run dev:legacy-server | ||
| ``` | ||
|
|
||
| ## Production architecture | ||
|
|
||
| GitHub Pages / public website -> embedded `public/widget.js` -> deployed Node/Express API -> Gemini + Supabase. | ||
|
|
||
| The current project is prepared as the chatbot application. Public-site embedding and the admin AI section should be integrated after the live backend deployment endpoint is chosen. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: This grants write access to the token in pull-request runs while
npm installexecutes PR-controlled lifecycle scripts, letting those scripts push arbitrary commits to the repository.Assessment: 🔴
Critical· 🔁Occurrence: Rarely· 🏷️SecurityPrompt for AI Agent 🤖