Skip to content

Latest commit

 

History

History
527 lines (358 loc) · 47 KB

File metadata and controls

527 lines (358 loc) · 47 KB

QuickVoice Audit

Historical snapshot: this report describes the repository at the June 19, 2026 commit listed below. Its findings were remediated in the subsequent hardening work and are retained as point-in-time evidence, not as a current defect list.

Executive Summary

  • Repository: /home/ubuntu/rahul/quickvoice
  • Commit: d0284076a776a80bc39f06d90d56b4c650e366ac
  • Started: 2026-06-19T06:22:07+00:00
  • Finished: 2026-06-19T06:58:32+00:00
  • Module session status: 6 passed

This report was generated by scripts/codex_module_audit.py, which runs one isolated Codex audit session per module and aggregates the final module reports.

Module Status

Module Status Return Code Duration Logs
root-tooling passed 0 448.7s .audit_runs/2026-06-19T062207+0000/root-tooling.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/root-tooling.stderr.log
apps-web passed 0 412.6s .audit_runs/2026-06-19T062207+0000/apps-web.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/apps-web.stderr.log
apps-console passed 0 360.3s .audit_runs/2026-06-19T062207+0000/apps-console.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/apps-console.stderr.log
apps-server passed 0 317.7s .audit_runs/2026-06-19T062207+0000/apps-server.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/apps-server.stderr.log
apps-ai passed 0 410.4s .audit_runs/2026-06-19T062207+0000/apps-ai.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/apps-ai.stderr.log
packages-config passed 0 236.0s .audit_runs/2026-06-19T062207+0000/packages-config.stdout.jsonl, .audit_runs/2026-06-19T062207+0000/packages-config.stderr.log

Findings By Module

root-tooling: Root tooling, CI, and developer experience

  • Status: passed
  • Return code: 0
  • Duration: 448.7s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/root-tooling.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/root-tooling.stderr.log

Summary

Audited root-tooling at commit d0284076a776a80bc39f06d90d56b4c650e366ac. Highest risk areas are broken local env bootstrap, missing PR build/test gates, and a security audit workflow that passes despite known high advisories. No tracked files were changed by the audit.

Critical/High Findings

  • High: Local development bootstrap is broken. scripts/dev-env.sh:19-23 copies apps/server/.env.dev.example, apps/console/.env.dev.example, and apps/web/.env.dev.example, but those files are absent. Repro: ./scripts/dev-env.sh fails with cp: cannot stat ... apps/server/.env.dev.example; node --test tests/dev-orchestration.test.mjs also fails at tests/dev-orchestration.test.mjs:49-60. Impact: task env:dev and task up:dev cannot reliably onboard developers. Fix: add the missing templates or stop copying them, and preflight all sources before creating any destination files.

  • High: PRs are not gated by build, lint, typecheck, or tests. server-build.yml:3-14 and ai-build.yml:3-9 run only on push to main or manual dispatch. The only PR workflow is security-audit.yml:6-7, and it does not run package.json:12-17 scripts. Impact: broken app code can merge, and Docker image failures are discovered after merge. Fix: add a required PR CI workflow running frozen install, lint, typecheck, builds, JS tests, and Python tests; make deploy workflows depend on that signal.

  • High: Security audit passes while high vulnerabilities exist. .github/workflows/security-audit.yml:31-32 uses pnpm audit --audit-level critical. Repro: that command exited 0 while reporting 105 vulnerabilities found including 47 high; pnpm audit --audit-level moderate exited 1. Examples include high advisories for next, axios, minimatch, flatted, and protobufjs. Fix: fail at least on high, triage dev-only vs prod paths, and track suppressions explicitly.

Medium Findings

  • Medium: Root quality scripts have coverage gaps. pnpm check-types only runs server#check-types; Turborepo dry-run showed console#check-types and web#check-types as <NONEXISTENT>. pnpm lint skips the server because apps/server/package.json:10-17 has no lint script. Fix: add missing package scripts and make CI fail on missing expected tasks.

  • Medium: Dev Postgres is exposed on all host interfaces with static credentials. docker-compose.dev.yml:8-13 publishes 5432:5432 with quickvoice/quickvoice. Impact: on many Docker hosts this is reachable beyond localhost. Fix: bind 127.0.0.1:5432:5432 and document dev-only credentials.

  • Medium: Local Docker dependencies omit Redis. docker-compose.dev.yml:3-24 only starts Postgres, while apps/server/src/config/redis.ts:3 defaults to redis://localhost:6379 and BullMQ uses it at apps/server/src/queues/kb.queue.ts:22-23. Impact: KB queue paths fail in local dev unless Redis is installed separately. Fix: add a Redis service and REDIS_URL env template entry.

  • Medium: Deploy workflows publish mutable latest without promotion controls. server-build.yml:51-55 and ai-build.yml:46-50 tag every main build as both SHA and latest; neither workflow has environment, concurrency, smoke tests, image scan, or rollback metadata. Fix: use protected environments, immutable promotion tags, concurrency, and post-build validation.

Low Findings

  • Low: Mixed lockfiles undermine pnpm dependency hygiene. package.json:24 declares pnpm@9.0.0, but tracked npm lockfiles also exist; root package-lock.json:8-14 even pins better-auth differently from package.json:28-30. Fix: keep one authoritative lockfile strategy and remove stale package-manager locks.

  • Low: Local dependency install can rewrite the lockfile. scripts/dev-node-deps.sh:24 runs plain pnpm install. Fix: default to pnpm install --frozen-lockfile and add an explicit update task for lockfile changes.

UI/UX Issues

  • Dev startup prints the wrong AI API URL. Root .env.dev.example:8-9 sets AI_API_PORT=8000, but apps/ai/.env.dev.example:2 sets 5555; scripts/dev-up.sh:53-58 sources the AI env in the child process while scripts/dev-up.sh:83 prints the root value. Impact: users are told to open :8000 while the service can run on :5555. Fix: make one port source authoritative.

Missing Features

  • No required PR workflow for root build, lint, check-types, JS tests, Python tests, and Docker build validation.
  • No root aggregate test or ci script; package.json:17 only exposes test:dev-orchestration.
  • Dependabot only covers npm at / (.github/dependabot.yml:3-4); it does not cover GitHub Actions, Docker images, or apps/ai/requirements.txt.
  • No SBOM, image signing/provenance, or container vulnerability scanning in deploy workflows.

New Feature Opportunities

  • Add task ci / pnpm ci:local to run the same checks as required PR CI.
  • Add task doctor checks for missing env templates, port conflicts, Redis availability, and Docker Compose health.
  • Add Docker Compose profiles for optional local services such as Redis and local object-storage/mail substitutes.

Checks Run

  • git rev-parse HEAD matched the requested commit.
  • bash -n scripts/dev-clear-processes.sh scripts/dev-doctor.sh scripts/dev-env.sh scripts/dev-node-deps.sh scripts/dev-up.sh passed.
  • docker compose -f docker-compose.dev.yml --env-file .env.dev.example config passed.
  • task --list passed.
  • node --test tests/dev-orchestration.test.mjs failed as described.
  • node --test tests/kb-worker-config.test.mjs passed.
  • pnpm audit --audit-level critical exited 0; pnpm audit --audit-level moderate exited 1.
  • pnpm dlx turbo@2.8.20 run {check-types,lint,build} --dry=json used for task graph inspection only.

Blocked Or Unverified

  • Full install/build/lint/typecheck were not run because node_modules is absent and pnpm install would create repository files.
  • Docker image builds and AWS/ECR deploy paths were not executed because they require external credentials and push side effects.
  • Docker services were not started because that would create containers/volumes.
  • Worktree had pre-existing changes: modified .gitignore, untracked scripts/codex_module_audit.py, and untracked tests/test_codex_module_audit.py.

apps-web: Marketing website and public UX

  • Status: passed
  • Return code: 0
  • Duration: 412.6s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/apps-web.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/apps-web.stderr.log

Summary

Audited apps/web at commit d0284076a776a80bc39f06d90d56b4c650e366ac. No files were modified. Main risks are broken conversion paths, future-dated content being publicly indexed, missing public assets, and inconsistent compliance/pricing claims.

Critical/High Findings

  • High: Contact form submit path is broken. Proven: contact-us-form-section.tsx:96 posts to /api/contact, but apps/web/src/app has no API route. Repro: submit /company/contact; request 404s and likely falls into the generic error path. Fix: add app/api/contact/route.ts, use a server action, or replace the form with a working external lead-capture flow.

  • High: Public CTAs link to nonexistent routes. Proven: /use-cases/appointment-scheduling renders /contact and /demo links at appointment-scheduling-cta-section.tsx:60 and 68; /use-cases/customer-support does the same at customer-support-cta-section.tsx:58. Those routes do not exist. Fix: use /company/contact and DEMO_BOOKING_URL.

  • High: Future-dated blog posts are published and treated as latest. Proven: getAllPosts() returns all markdown without filtering dates at blog.ts:48, and the blog index selects the last sorted post as “Latest Article” at blog/page.tsx:96. Static scan found 36 posts dated after June 19, 2026, up to week-52:4. Fix: filter future dates unless explicitly previewing/scheduling.

Medium Findings

  • Missing social and visible image assets. /og-image.png is referenced across many pages, e.g. blog/page.tsx:19, but is not in public/. Visible next/image sources such as careers-hero-section.tsx:192 and operations-automation-why-section.tsx:102 also point to missing /images/... files. Impact: broken page imagery and broken social previews.

  • Compliance and pricing copy contradict each other. Pricing says BAA is Enterprise-only at pricing/page.tsx:201, while the HIPAA page says every healthcare customer gets a BAA at hipaa/page.tsx:53 and 419. Fix: align legal/commercial wording before publishing.

  • Free-trial allowance is inconsistent. Pricing says Free includes 15 minutes/month at pricing/page.tsx:31, but homepage FAQ says up to 100 minutes at faq-2.tsx:89. Impact: trust and support friction.

  • Desktop dropdown navigation is hover-only. Dropdowns open via mouse enter/leave at header-1.tsx:162, with parent links set to # at header-1.tsx:27. Impact: keyboard users cannot reliably access nested navigation.

Low Findings

  • Nested landmarks and duplicate main-content. Layout wraps every page in <main id="main-content"> at layout.tsx:91, while pages also render <main>, including duplicate id="main-content" on the homepage at page.tsx:145. Fix: keep the landmark/id in one place.

  • Manifest icons 404. manifest.ts:15 references /icon and manifest.ts:20 references /apple-icon, but no matching files/routes exist.

  • Global preload is applied to every route. layout.tsx:62 preloads /dashboard.png globally, although it is homepage-specific. Fix: move preload/priority handling to the component/page that needs it.

UI/UX Issues

Missing Features

  • Working contact/demo lead submission backend.
  • Content publish-state handling for draft/scheduled blog posts.
  • Centralized CTA route validation for /register, /login, demo, and contact URLs.
  • Accessible keyboard-first dropdown/accordion components.

New Feature Opportunities

  • Per-page OG image generation or a real shared /og-image.png.
  • Blog search/filter UI to match the declared SearchAction.
  • Conversion analytics for contact/demo/signup CTAs.
  • Scheduled content workflow with preview mode and sitemap exclusion.

Checks Run

  • git rev-parse HEAD confirmed d0284076a776a80bc39f06d90d56b4c650e366ac.
  • git status --short showed unrelated dirty files outside apps/web; untouched.
  • Static file/route inspection with find, rg, nl.
  • Node frontmatter scan: 90 blog posts, 36 future-dated after June 19, 2026.
  • Asset inventory: only dashboard.png, earth.webp, logos, robots.txt, and llms.txt exist in apps/web/public.

Blocked Or Unverified

  • pnpm --filter web lint blocked: eslint not found; dependencies not installed.
  • pnpm --filter web exec tsc --noEmit --incremental false blocked: tsc not found.
  • Did not run next build, next dev, or rendered browser QA because those would create .next/ artifacts, violating the no-create rule.
  • External services and production env were not verified: NEXT_PUBLIC_CONSOLE_URL, TidyCal, analytics, and compliance certification claims.

apps-console: Authenticated console UX and frontend logic

  • Status: passed
  • Return code: 0
  • Duration: 360.3s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/apps-console.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/apps-console.stderr.log

Summary

Audited apps/console at commit d0284076a776a80bc39f06d90d56b4c650e366ac. No files under apps/console were modified.

Main risks: onboarding can navigate to an invalid org after create failure, phone-number buying sends the wrong provider value, roles/access-control UI is not actually wired, and several data pages render failed API loads as empty/zero states.

Critical/High Findings

  • Proven: create-organization failure still shows success and navigates to /orgs/undefined. CreateOrg.tsx:43 handles error but does not return or throw; CreateOrg.tsx:51 still toasts success and CreateOrg.tsx:52 pushes data?.id. Repro with duplicate/invalid org slug. Fix by returning/throwing on error, requiring data.id, and not clearing the error in finally.

  • Proven: buy-number flow sends upper-case provider values despite lower-case console API types. TelephonyProvider is "twilio" | "telnyx" in types.ts:6, but the form uses "TWILIO" | "TELNYX" in BuyNumberDrawer.tsx:44 and casts that runtime value at BuyNumberDrawer.tsx:70. Impact: search/buy requests can fail or hit wrong provider handling. Use lower-case form values or transform before API calls.

  • Proven: roles page is a UI shell, not functional role management. roles/page.tsx:61 notes wiring is follow-up; roles/page.tsx:63 hardcodes roles to [], and delete has no handler at roles/page.tsx:216. Impact: custom access control cannot be viewed or managed. Wire list/create/delete/update to the auth API with real loading/error states.

Medium Findings

  • Proven: multiple API failures render as empty or zero data. Examples: dashboard ignores isError and shows 0 values at dashboard/page.tsx:22, agents defaults to [] at agents/page.tsx:11, calls shows “No calls match” after query failure at CallsTable.tsx:263, and KB does the same at kb/page.tsx:13. Add explicit isError states with retry.

  • Proven: enabled webhooks can be saved with blank URLs. Schema allows "" at WebhooksTab.tsx:34, then submit builds enabled webhook objects at WebhooksTab.tsx:78. Add conditional validation: URL required when enabled.

  • Proven code risk: MCP setup opens external pages without noopener. mcp.ts:13 uses window.open(setupUrl, "_blank"); setting opener = null after open at mcp.ts:19 is weaker than opening with noopener,noreferrer. Use the third window.open argument and validate setup URLs.

  • Proven: agent template picker is ignored. selectedTemplate is maintained at NewAgentDialog.tsx:80, but submit always sends templateId: null at NewAgentDialog.tsx:89. Send the selected template or remove the picker.

Low Findings

  • Proven: “Forgot password?” links to a missing route. login-form.tsx:119 links /forgot-password, but no matching app route exists.

  • Proven: registration has weak submit/error handling. register-form.tsx:40 has no try/finally, logs auth errors at register-form.tsx:47, and the submit button is not disabled while loading at register-form.tsx:157.

  • Proven: tool parameter/header validation permits empty keys and names. ToolSheet.tsx:41 uses bare z.string() for key/value and param fields. Add minimum validation or filter blank rows before submit.

UI/UX Issues

Missing Features

  • Password reset/forgot-password screens and handlers.
  • Real custom role listing/edit/delete and member role changes.
  • Agent delete is disabled in both table/detail flows.
  • Per-agent limits tab exists but is not included in AgentTabs; current page only says roadmap.
  • Billing usage is a TODO at billing/page.tsx:202.
  • Campaign outbound UI is absent despite campaignSchema at campaign.ts:3.

New Feature Opportunities

  • Audit log for org settings, API keys, members, roles, billing, and destructive actions.
  • Agent test-call/simulation flow; table currently has disabled “Test”.
  • Pending invites management, ownership transfer, and role reassignment.
  • Mobile card views for calls, agents, KB, and numbers instead of squeezed tables.
  • Billing usage forecasts and overage warnings.

Checks Run

  • git rev-parse HEAD -> d0284076a776a80bc39f06d90d56b4c650e366ac
  • git diff -- apps/console --stat -> no output
  • Static inspection with rg, find, sed, and nl -ba
  • pnpm --dir apps/console lint -> blocked: eslint: not found, node_modules missing
  • pnpm --dir apps/console exec tsc --noEmit -p tsconfig.json -> blocked: tsc not found

Blocked Or Unverified

  • Lint, typecheck, build, and browser/a11y verification were not completed because dependencies are not installed.
  • API contract assumptions beyond console-local types were not verified against live services or credentials.
  • Existing dirty worktree entries are outside apps/console and were not touched.

apps-server: API server, auth, data model, and integrations

  • Status: passed
  • Return code: 0
  • Duration: 317.7s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/apps-server.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/apps-server.stderr.log

Summary

Audited apps/server at d0284076a776a80bc39f06d90d56b4c650e366ac read-only. Main risks: API keys bypass RBAC, KB creation can write with caller-supplied tenant context, and webhook/tool “secret” values are stored/returned as plaintext.

Critical/High Findings

  • High: API keys bypass all per-route RBAC. Evidence: valid API keys become authMethod: "apiKey" in auth.middleware.ts:96, then requirePermission returns without checking the requested permission in authorize.middleware.ts:69. Repro: use any valid org API key against mutating routes such as POST /api/v1/numbers or DELETE /api/v1/calls/:id; the route permission is skipped. Impact: leaked/low-scope API keys can mutate org resources and trigger paid telephony/MCP actions. Fix: verify API-key permissions/scopes against permissions, or map API keys to a user/member role and call the same permission engine.

  • High: KB creation trusts caller-supplied organizationId and userId. Evidence: controller passes raw body in kb.controller.ts:10; schema requires client userId/organizationId in kb.schema.ts:39; repository writes them directly in kb.repository.ts:14. Repro: authenticated org A admin posts /api/v1/kb with organizationId or agentId from another org. Impact: cross-tenant KB rows, queue jobs, and knowledgeSourcesCount corruption. Fix: inject req.auth.activeOrganizationId/req.auth.userId, remove those body fields, and verify agentId belongs to the active org in the same transaction.

  • High: integration secrets are stored and returned as normal JSON/plaintext. Evidence: webhook fields accept { value, type: "Secret" } in agent.schema.ts:50, then are persisted unchanged in agent.repository.ts:69 and returned by config reads in agent.controller.ts:80. Tool headers/body are JSON fields in schema.prisma:536; Secret.value is also plain String at schema.prisma:653. Impact: DB compromise or read-capable org members can recover API keys/webhook secrets. Fix: envelope-encrypt secrets, store references not values, redact reads, and resolve secrets only at execution time.

Medium Findings

Low Findings

UI/UX Issues

  • Public Swagger docs expose internal auth schemes and persist auth in browser storage: index.ts:32, swagger.ts:60.
  • Swagger tells users to provide KB userId and organizationId, matching the security bug: swagger.ts:270.
  • Error responses are inconsistent: rate limit returns { success, message }, global errors return { message }.

Missing Features

  • No observed server-side enforcement of plan minutes/quotas from plans.ts:1.
  • No Stripe metered usage reporting found for call minutes/costs.
  • No retention job for transcripts, recordings, MCP logs, or KB data.
  • KB delete TODOs leave S3/vector cleanup unimplemented in kb.service.ts:38.
  • Number release/delete route is commented out.

New Feature Opportunities

  • Org-scoped audit log for API-key use, config changes, telephony purchases, MCP execution, and internal calls.
  • Central secret manager with rotation, redaction, and execution-time resolution.
  • Per-org rate limits and quota dashboards tied to billing plans.
  • Readiness checks for DB, Redis, S3, Stripe, Twilio/Telnyx, LiveKit, and Smithery.

Checks Run

  • git rev-parse HEAD confirmed d0284076a776a80bc39f06d90d56b4c650e366ac.
  • git status --short checked before/after; existing .gitignore modification and untracked audit helper files were not touched.
  • Static inspection with rg, find, sed, and nl.
  • pnpm --dir apps/server check-types attempted.

Blocked Or Unverified

  • Typecheck blocked: tsc: not found; apps/server/node_modules is missing. I did not install dependencies because that would write files.
  • Tests/builds not run for the same dependency reason.
  • DB, Redis, Stripe, Twilio, Telnyx, LiveKit, S3, Inngest, and Smithery integration behavior was not exercised due missing credentials/services.
  • Inngest endpoint auth/signature behavior remains unverified.

apps-ai: Python AI service, LiveKit worker, and RAG runtime

  • Status: passed
  • Return code: 0
  • Duration: 410.4s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/apps-ai.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/apps-ai.stderr.log

Summary

Audited apps/ai at d0284076a776a80bc39f06d90d56b4c650e366ac in read-only mode. No apps/ai files were changed. Highest risk areas are internal API auth, KB URL/file ingestion, call finalization, RAG failure behavior, and PII-heavy logging.

Critical/High Findings

  • High: unauthenticated FastAPI config proxy can leak runtime agent config. api.py:30 exposes GET /agents/{agent_id}/config without _verify_internal, while config_handler.py:52 calls the backend with the internal bearer key. Repro: run AI API with SERVER_API_URL and INTERNAL_API_KEY, then request /agents/<id>/config without auth. Impact: system prompts, variables, webhooks, and MCP connection metadata can be exposed. Fix: require internal auth on this route and fail startup if the key is absent outside explicit dev mode.

  • High: KB ingestion permits SSRF and unbounded server-side downloads. kb_handler.py:39 and kb_handler.py:49 fetch caller-provided url/presignedUrl with redirects and no scheme, host, IP, content-type, or size restrictions. Combined with optional auth in api.py:17, this can hit metadata services/internal hosts or ingest huge files into Gemini/Pinecone. Fix: fail-closed auth, block private/link-local IPs, allowlist schemes/hosts where possible, stream with byte limits, and cap chunks/embeddings per job.

Medium Findings

  • Call logs can be dropped during shutdown. Finalization only runs from participant_disconnected and is launched via asyncio.create_task in main.py:281. There is no ctx.add_shutdown_callback, so SIGTERM, worker recycle, network disconnects, or early job shutdown can skip transcripts/log posting. Fix: make finalization idempotent, register it with LiveKit job shutdown, await it, and retry via a durable queue.

  • Transcript timestamps are wrong for LiveKit messages. livekit_handler.py:40 passes msg.created_at, which LiveKit documents as a float timestamp, but calllog_handler.py:103 only preserves strings or datetime; floats become “now”. Reproduced locally: a 1704067200.0 transcript timestamp became the current audit time. Fix: handle numeric epoch seconds.

  • Re-indexing shorter KB documents leaves stale Pinecone chunks. kb_handler.py:162 uses stable IDs kbId#i and kb_handler.py:176 only upserts. Old higher-index chunks remain after a shorter replacement, so RAG can cite deleted content. Fix: delete by kbId before re-upsert or version documents and filter current versions.

  • RAG provider failures silently degrade into no-context answers. rag_handler.py:60 catches all exceptions and returns ""; main.py:147 then proceeds without a user-visible failure. Impact: agents can hallucinate when KB is unavailable. Fix: distinguish “no matches” from “retrieval failed”, emit metrics, and inject/return a clear KB-unavailable signal.

  • PII and sensitive runtime data are logged at INFO. Full config payloads, call context, message objects, and transcripts are logged at config_handler.py:59, main.py:222, and livekit_handler.py:30. logger.py:24 also enables diagnostic trace detail. Fix: redact phone numbers, transcripts, prompts, headers, webhook URLs, and disable diagnose=True in production.

  • MCP execution lacks AI-side guardrails. The LLM can call main.py:187 with arbitrary arguments; server-side org/agent attachment checks reduce cross-tenant risk, but prompt injection can still trigger connected tools and return unbounded tool output into the conversation. Fix: enforce local allowlists from config["mcp_connections"], classify side-effect tools, require confirmation where needed, and truncate/redact outputs.

  • Runtime config fetch fails open to a generic agent. If SERVER_API_URL or INTERNAL_API_KEY is missing, config_handler.py:50 falls back to defaults. Production calls can run with the wrong prompt and later fail call logging due missing org/user fields. Fix: fail closed in worker/API runtime except explicit local dev.

Low Findings

  • livekit_handler.py:53 does not close LiveKitAPI in a finally path if egress startup fails after client creation.
  • api.py:56 says it returns 207 Multi-Status, but FastAPI returns the default 200.
  • requirements.txt has mostly unpinned dependencies and no lock/constraints or dev requirements, making Python builds hard to reproduce.

UI/UX Issues

  • KB failures and “no KB match” collapse into similar behavior, so users get confident answers or “no matching context” without knowing the KB backend failed.
  • The bot can run with the default generic prompt on config misconfiguration, instead of telling callers the agent is unavailable.
  • KB processing returns success: true even when individual documents fail, which can create confusing status unless every caller inspects per-document results.

Missing Features

  • Fail-closed internal auth middleware for all non-health FastAPI routes.
  • Privacy controls in the AI runtime for store_call_audio, zero_pii_retention, and retention settings; main.py:277 always starts recording.
  • Durable call-log delivery with retry/backoff and dead-letter visibility.
  • Metrics/tracing for provider latency, RAG hit/miss/error, KB document size/chunk count, recording failures, and MCP execution.
  • Tests for FastAPI auth, SSRF validation, shutdown finalization, stale vector cleanup, provider failures, and PII redaction.

New Feature Opportunities

  • Add KB citations with document name, page/sheet, chunk ID, and score.
  • Add hybrid keyword/vector search and optional reranking for better RAG precision.
  • Add per-agent KB ingestion budgets and cost controls.
  • Add an admin reindex/delete workflow that removes stale vectors safely.
  • Add MCP tool governance: read-only vs write tools, confirmation prompts, and audit summaries.

Checks Run

  • Verified commit with git rev-parse HEAD.
  • Read apps/ai files with line-numbered inspection and scoped ripgrep searches.
  • Ran dependency-free syntax check: syntax ok for 17 python files.
  • Ran PYTHONDONTWRITEBYTECODE=1 python3 -m unittest discover -s tests -p 'test_*.py' -v: 3 call-log tests passed; 5 test modules blocked by missing dependencies.
  • Reproduced numeric transcript timestamp bug with build_call_log_payload.
  • Confirmed apps/ai remained clean with git status --short -- apps/ai and no cache files were created.
  • Referenced official LiveKit docs for ChatContext.created_at and JobContext.add_shutdown_callback: https://docs.livekit.io/reference/python/livekit/agents/

Blocked Or Unverified

  • Full test suite blocked: pytest, loguru, livekit, and dotenv are not installed.
  • LiveKit, Pinecone, Google embedding, and backend API integrations were not exercised because credentials/services are unavailable.
  • No actual SSRF, provider, recording, or MCP network calls were attempted.
  • I did not generate security-scan artifacts because the audit rules prohibit creating files.

packages-config: Shared lint and TypeScript configuration

  • Status: passed
  • Return code: 0
  • Duration: 236.0s
  • Stdout log: .audit_runs/2026-06-19T062207+0000/packages-config.stdout.jsonl
  • Stderr log: .audit_runs/2026-06-19T062207+0000/packages-config.stderr.log

Summary

Audited only packages/eslint-config and packages/typescript-config at commit d0284076a776a80bc39f06d90d56b4c650e366ac. No repository files were changed. The main risks are weak lint gates, unused shared ESLint config, and TypeScript defaults that leak browser globals into the server.

Critical/High Findings

  • High: Shared ESLint config downgrades all lint failures to warnings. Proven in base.js and base.js: eslint-plugin-only-warn is included in the base preset, and turbo/no-undeclared-env-vars is explicitly only warn at base.js. Any consumer of @repo/eslint-config/base, next-js, or react-internal can pass CI with lint violations unless every lint command also uses --max-warnings=0. Fix: remove only-warn from shared CI presets, keep it only in a local/dev preset if needed, and make cache-affecting rules such as turbo/no-undeclared-env-vars errors in CI.

Medium Findings

  • Medium: Shared ESLint package is not consumed by the workspace apps. apps/web and apps/console import eslint-config-next directly in eslint.config.mjs and eslint.config.mjs. rg found no dependency or import of @repo/eslint-config outside its own package. Impact: changes to packages/eslint-config do not protect current app linting. Fix: either adopt the shared package in app configs or remove/rename it until it is part of the quality gate.

  • Medium: Server inherits DOM typings from the shared TypeScript base. base.json includes DOM and DOM.Iterable; apps/server/tsconfig.json extends that base. Impact: server code can typecheck accidental browser APIs such as window/document, hiding runtime errors. Fix: make base.json runtime-neutral and add separate node.json / browser.json / nextjs.json presets.

  • Medium: Shared Next ESLint preset is weaker than the app presets. next.js wires only @next/next rules plus React hooks; it does not use eslint-config-next/core-web-vitals or eslint-config-next/typescript, unlike the apps. Lockfile data also shows the shared package resolves @next/eslint-plugin-next@16.2.0 while apps use eslint-config-next@16.2.1. Impact: adopting the shared preset may lose import, accessibility, and exact Next rule coverage. Fix: base the shared Next preset on eslint-config-next or fully mirror its plugin set and versions.

Low Findings

  • Low: TypeScript config package has no explicit export map. package.json exposes no exports for ./base.json, ./nextjs.json, or ./react-library.json. Fix: add explicit JSON subpath exports to define the supported public surface.

  • Low: Package metadata is inconsistent. @repo/typescript-config is private: true but also has publishConfig.access: public in package.json. The ESLint README still says @turbo/eslint-config in README.md. Fix: remove stale publish metadata or document publishing intent, and update README naming/usage examples.

UI/UX Issues

No direct UI surface in this module. Indirect UI risk: the shared Next ESLint preset does not clearly preserve the current apps’ accessibility lint coverage.

Missing Features

  • Package-level smoke tests that import each ESLint export and validate each TS config.
  • CI task that runs lint/config validation when packages/eslint-config/** changes.
  • Runtime-specific TS presets for Node server, Next app, and React library.
  • --max-warnings=0 or equivalent strict lint gate.

New Feature Opportunities

  • Add stricter optional TS presets covering noUnusedLocals, noUnusedParameters, noImplicitReturns, noFallthroughCasesInSwitch, and exactOptionalPropertyTypes.
  • Add README examples for each exported config and expected consumer package dependencies.

Checks Run

  • Verified commit with git rev-parse HEAD.
  • Inspected scoped files, app consumers, root workspace config, lockfile, and CI workflows.
  • Searched usages with rg for @repo/eslint-config and @repo/typescript-config.
  • Ran node --check on all ESLint config JS files: passed.
  • Parsed all scoped JSON config/package files with JSON.parse: passed.

Blocked Or Unverified

  • pnpm --filter server check-types, pnpm --filter web lint, and pnpm --filter console lint were blocked because node_modules is missing (tsc/eslint not found). I did not run pnpm install because it would write repository files.
  • ESLint config runtime import checks were also blocked by missing installed dependencies.

Appendix: Runner Notes

  • Each module prompt explicitly instructed Codex not to edit repository files.
  • Generated logs are stored under .audit_runs/ and ignored by git.
  • A changed_files status means a module session modified tracked files and requires manual inspection before trusting the report.