mirror of
https://github.com/MadsLorentzen/ai-job-search.git
synced 2026-11-08 16:07:40 +00:00
fix(linkedin-search): reject detail URLs on other hosts instead of fetching the posting with that number (#500)
normalizeId took the first 6+-digit path segment from ANY URL, so a Greenhouse or Lever apply link - the kind a posting's own page hands out and a user pastes back into detail - was reduced to that number and the handler fetched jobPosting/<number> from LinkedIn: whatever job carried that id came back with exit 0, or NOT_FOUND if none did, never an error about the input. Driving the real handler with a stubbed fetch, https://boards.greenhouse.io/acme/jobs/4567890 requested .../jobPosting/4567890. Every other portal CLI rejects an off-host detail URL with BAD_ID (the #447 shape); linkedin was the one still trusting the digits. Parse URLs for real: a linkedin.com host (apex or any subdomain, scheme optional) plus a /jobs/view/<slug->id path yields the id; other hosts, look-alike and userinfo hosts, and linkedin.com profile or search URLs exit 1 with the stderr-JSON BAD_ID contract before any request. Bare ids, URNs, and slash-free title slugs are unchanged. Four new normalizeId cases and a new detail-input.test.ts that drives runDetail and the CLI with fetch stubbed; five cases fail on the old pattern.
This commit is contained in:
1 parent
a62af6a068
commit
8cbab6823e
4 files changed
+147
-7
No files matched your search
@@ -267,6 +267,30 @@ describe("normalizeId", () => {
|
||||
expect(normalizeId("https://dk.linkedin.com/jobs/view/data-scientist-9876543210/")).toBe("9876543210");
|
||||
});
|
||||
|
||||
test("accepts a scheme-less linkedin.com job URL and a bare title slug", () => {
|
||||
expect(normalizeId("www.linkedin.com/jobs/view/1234567890")).toBe("1234567890");
|
||||
expect(normalizeId("software-engineer-1234567890")).toBe("1234567890");
|
||||
});
|
||||
|
||||
test("rejects a job URL on any other host instead of extracting its digits", () => {
|
||||
// The old pattern took the first 6+-digit path segment from any URL, so an
|
||||
// ATS apply link fetched an unrelated LinkedIn posting with that number.
|
||||
expect(normalizeId("https://boards.greenhouse.io/acme/jobs/4567890")).toBeNull();
|
||||
expect(normalizeId("https://jobs.lever.co/acme/1234567")).toBeNull();
|
||||
expect(normalizeId("https://example.com/jobs/view/1234567890")).toBeNull();
|
||||
});
|
||||
|
||||
test("rejects look-alike and userinfo hosts", () => {
|
||||
expect(normalizeId("https://linkedin.com.evil.io/jobs/view/1234567890")).toBeNull();
|
||||
expect(normalizeId("https://notlinkedin.com/jobs/view/1234567890")).toBeNull();
|
||||
expect(normalizeId("https://www.linkedin.com@evil.io/jobs/view/1234567890")).toBeNull();
|
||||
});
|
||||
|
||||
test("rejects a linkedin.com URL that is not a job view", () => {
|
||||
expect(normalizeId("https://www.linkedin.com/in/someone-1234567890/")).toBeNull();
|
||||
expect(normalizeId("https://www.linkedin.com/jobs/search/?currentJobId=1234567890")).toBeNull();
|
||||
});
|
||||
|
||||
test("returns null for non-job URLs and invalid strings", () => {
|
||||
expect(normalizeId("https://www.linkedin.com/feed/")).toBeNull();
|
||||
expect(normalizeId("not-a-url")).toBeNull();
|
||||
|
||||
Reference in new issue
Block a user