Skip to content

Audit fixes: broken features, browser agent, security, performance, cleanup - #4

Merged
coderback merged 8 commits into
mainfrom
fix/audit-priorities
Oct 9, 2026
Merged

coderback merged 8 commits into
mainfrom
fix/audit-priorities

Conversation

@coderback

Copy link
Copy Markdown
Owner

Fixes from a full audit of the codebase, one commit per priority. Each commit builds and imports on its own.

Commits

Commit What
3336a91 Claude LLM backend and backend switching (from feature/agent-model, which was never pushed)
ac58fb3 Persona export (JSON / Markdown / PDF) and paste-a-job-link import
c633f09 P1, broken features: the ATS search never returned results, jobs were marked Applied without a confirmed submission, certifications were missing from CVs, JWT_SECRET had a hard-coded fallback, shared job rows could be rewritten from a client-supplied URL
8756de2 P2, browser agent: ported to browser-use 0.11 (the screencast and takeover were silently dead, and every application leaked a Chromium process); version pinned; the agent now stops before submitting so the user can review first
159f791 P3, security: job-site password encrypted with Fernet (CREDENTIALS_KEY); LLMs only see an allowlisted persona; SSRF guard on server-side fetches; password passed to the agent as a placeholder so the LLM never sees it (the judge call is disabled because it leaked it); internal hosts blocked
6adfc64 P4, performance: live discovery runs in a background process pool; batched embeddings; filters and pagination done in SQL; one shared TLS context (creating a client per request was stalling the event loop)
ed6df96 P5, cleanup: removed the dead /stream pipeline and the unused jobs-mcp / civic-guardrails services; status updates are scoped to the owning user (fixes an IDOR); uploaded CVs are kept; pytest suite and CI added; README rewritten

Breaking changes / deploy notes

  • JWT_SECRET and CREDENTIALS_KEY are now required. Docker compose won't start without them. Generate a key with:
    python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
  • Any plaintext job-site passwords are encrypted automatically on first start.
  • JOB_EMAIL / JOB_PASSWORD env vars and the jobs-mcp / civic-guardrails services have been removed.
  • browser-use is pinned to 0.11.13, and the langchain-* packages are gone.

Testing

  • cd api && pytest: 94 passed (fast suite, browser tests deselected)
  • pytest -m browser: 8 passed against a local headless Chromium (fill, review, takeover, submit / done / skip, disconnect cleanup, internal-host blocking, password placeholder never sent to the model)
  • CI (.github/workflows/ci.yml) runs the api, browser and frontend jobs.

- GET /persona/export downloads the persona as JSON, Markdown or a CV-style PDF
- POST /jobs/from-url scrapes an arbitrary job posting (ATS API, JSON-LD,
  OpenGraph) into a job for the normal analysis flow
- Profile "Download Twin" menu and a paste-a-link form on the job feed
- Pass the query as a list to the ATS level of live search; it iterated the
  string's characters, so the 60+ ATS job boards never returned anything
- Only mark an application Applied when the browser session reports a
  confirmed submission (skip, cancel, timeout and errors used to count)
- Map persona certification fields (issuing_organization / issue_date)
  into generated CVs
- Require JWT_SECRET instead of falling back to a hard-coded default;
  docker compose fails fast without it
- Only refresh a shared job description from the stored job's own URL,
  never from a client-supplied id/URL
- Pass BRAVE_SEARCH_API_KEY through docker compose
- Use browser-use's own Chat* LLM wrappers (0.11 rejects LangChain models);
  drop the langchain packages and pin browser-use==0.11.13
- Reimplement the live screencast and user takeover on the CDP API
  (0.11 removed Playwright, so both were silently dead)
- The agent fills the form and stops before the final submit; the user
  reviews, then submit / done / skip
- Always kill() the browser, including on client disconnect (0.11 has no
  close(), so every application leaked a Chromium process)
…rompts

- Encrypt the job-site password with Fernet (CREDENTIALS_KEY) in its own
  column, migrating any plaintext; GET /persona only returns a mask
- Send LLMs an allowlisted persona: no credentials, date of birth, contact
  details, diversity data or salary
- Guard server-side fetches of user-influenced URLs: public IPs only, every
  redirect re-checked; validate the /apply job URL
- Browser agent: password via a host-scoped sensitive_data placeholder,
  judge call disabled (it saw unredacted step history), raw IPs and internal
  hosts blocked, disable_security removed, job page opened explicitly
- Strip credential fields at any depth in tool inputs
- Live discovery runs in a background worker process, one run per
  query/location with a cooldown; /jobs reports `discovering` and the feed
  re-polls page 1
- Embed only new or vector-less jobs, in batched Ollama /api/embed calls,
  without holding the DB write lock; short embedding timeout for requests
- Query, tags and category now filter in SQL; whole-word location matching;
  hidden jobs excluded before pagination; correct has_more
- Share one TLS context across httpx clients (each new client loaded the CA
  bundle synchronously, stalling the event loop)
- Parse Greenhouse boards off the event loop; never persist fixture jobs;
  route Adzuna by whole-word country names; bound in-memory caches
- Remove jobs-mcp and civic-guardrails (nothing called them), the /stream
  agent pipeline, /guardrails/audit, unused models and frontend components
- Scope application status updates to the owning user; mark previously
  saved jobs Applied on submit; close the connection after a duplicate
  insert (it left applications.db locked)
- Keep each user's uploaded CV and use it when applying without a tailored CV
- Drop the unused JOB_EMAIL / JOB_PASSWORD env vars; rewrite the README
- Add a pytest suite (fast + browser-marked) and GitHub Actions CI
- Add pydantic-settings: browser-use 0.11.13 imports it at package import
  but does not declare it, so a fresh install (CI, Docker) failed
- Put api/ on pytest's path so a bare `pytest` can import `app`
@coderback
coderback merged commit e789c71 into main Oct 9, 2026
3 checks passed
@coderback
coderback deleted the fix/audit-priorities branch October 9, 2026 09:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant