From 64a6c90ec32438742ca62f8f30f55afea4435172 Mon Sep 17 00:00:00 2001 From: "Lutfi (fay)" <103249558+lutfidev@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:30:42 +0700 Subject: [PATCH] fix(freehire-search): drop the github.com URL from the User-Agent (#689) * fix(freehire-search): drop the github.com URL from the User-Agent #633 put a contact URL in freehire-search's User-Agent. /apply learns which hosts an installed portal serves from the host literals in its cli/src, so github.com became a freehire-search board host: any github.com link (a repo README or gist presented as a job posting) classified as an installed portal instead of an unverified source host. Keep the owner/project/version identifier freehire's API docs ask for and drop the optional contact URL. Pin github.com and gist.github.com as unverified in the host-check test. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01QhZWmcevg3UX9udYi1CsHC * changelog: place the #689 entry under [Unreleased] Co-Authored-By: Claude Opus 5.5 --------- Co-authored-by: Claude Opus 5.5 Co-authored-by: Mads Lorentzen --- .agents/skills/freehire-search/cli/src/helpers.ts | 13 ++++++++----- .agents/skills/freehire-search/url-reference.md | 3 ++- CHANGELOG.md | 10 ++++++++++ tests/test_apply_host_check.py | 5 +++++ 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.agents/skills/freehire-search/cli/src/helpers.ts b/.agents/skills/freehire-search/cli/src/helpers.ts index c75b5193..83ad3718 100644 --- a/.agents/skills/freehire-search/cli/src/helpers.ts +++ b/.agents/skills/freehire-search/cli/src/helpers.ts @@ -16,11 +16,14 @@ export function writeError(error: string, code: string): void { process.stderr.write(JSON.stringify({ error, code }) + "\n") } -// Names this project, the shape freehire's API docs ask for (owner/project/version -// plus a contact URL), so the API's operators can reach the maintainer before a -// limit or a field changes. The old value linked to freehire.me itself, which -// identified the API, not the caller. -const UA = "MadsLorentzen/ai-job-search/1.0 (+https://github.com/MadsLorentzen/ai-job-search; freehire-search)" +// Names this project in the owner/project/version shape freehire's API docs ask +// for, so the API's operators can find the maintainer before a limit or a field +// changes. The contact URL the docs make optional is left out on purpose: /apply +// learns which hosts a portal serves by reading the host literals in its +// cli/src, so a github.com URL here made every github.com link classify as an +// installed job board instead of an unverified host. The owner/project name +// already identifies the repo on GitHub. +const UA = "MadsLorentzen/ai-job-search/1.0 (freehire-search)" /** The shared API response envelope: {data, meta, error}. */ export interface Envelope { diff --git a/.agents/skills/freehire-search/url-reference.md b/.agents/skills/freehire-search/url-reference.md index ebc50924..d05e71e7 100644 --- a/.agents/skills/freehire-search/url-reference.md +++ b/.agents/skills/freehire-search/url-reference.md @@ -138,7 +138,8 @@ points users to (`?q=` scopes the counts). Example: serves HTML, which `cleanHtml` (`cli/src/helpers.ts`) strips into readable text. Search descriptions arrive already rendered by the API and are passed through verbatim — stripping them again would undo the Markdown structure. -- Fetch sends `User-Agent: MadsLorentzen/ai-job-search/1.0 (+https://github.com/MadsLorentzen/ai-job-search; freehire-search)` +- Fetch sends `User-Agent: MadsLorentzen/ai-job-search/1.0 (freehire-search)` (no contact + URL: a host literal in `cli/src` makes `/apply` treat that host as this portal's board) and `Accept: application/json`, and uses exponential backoff with jitter on 429/5xx (max 6 retries). A connection error (API unreachable) fails fast with a clear message — no retry, since it is not transient server load — which is the graceful-degradation contract: an outage diff --git a/CHANGELOG.md b/CHANGELOG.md index d5b7427d..3f405e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -253,6 +253,16 @@ per-file diff commands. or unknown label keeps the old result. The homoglyph check now sees Cyrillic letters on a windows-1251 page. Text input to the gate (`--text`) is unchanged. +- **freehire-search's User-Agent no longer makes github.com look like a job board** (#689, + `.agents/skills/freehire-search/cli/src/helpers.ts`, `url-reference.md`, + `tests/test_apply_host_check.py`) - `/apply` derives each installed portal's board hosts from the + host literals in its `cli/src`, and the contact URL added to freehire's User-Agent in #633 put + `github.com` among them, so a "posting" published in any GitHub repo or gist classified as an + installed portal instead of getting the `⚠ Unverified source host` warning. The User-Agent keeps + the `owner/project/version` name freehire's API docs ask for and drops the optional URL: + `MadsLorentzen/ai-job-search/1.0 (freehire-search)`. The host-check test now lists `github.com` and + `gist.github.com` postings among the hosts that must stay unverified. + ### Security - **CI no longer leaves the job token in `.git/config` or expands a PR-controlled name into a diff --git a/tests/test_apply_host_check.py b/tests/test_apply_host_check.py index 9fd76e28..b93be42a 100644 --- a/tests/test_apply_host_check.py +++ b/tests/test_apply_host_check.py @@ -292,6 +292,11 @@ class InstalledPortalsAreVerifiedTests(unittest.TestCase): "https://myworkdayjobs.com.phishing.net/login", "https://lever.co.attacker.org/apply", "https://unknown-board.example.com/posting/123", + # Anyone can publish a "job posting" in a GitHub repo or gist. A + # contact URL in a portal CLI's User-Agent string once made + # github.com an installed-portal host (#633), so pin it here. + "https://github.com/acme-careers/jobs/blob/main/README.md", + "https://gist.github.com/someone/0123456789abcdef", ] for url in suspicious: tier, host = classify_posting_host(url)