Archived
ingest: suppress Google-news shared placeholder image (googleusercontent) -> null -> category cover fallback
Root cause: Google News RSS items carry no enclosures; pipeline fell back to og:image from the news.google.com interstitial, which serves ONE shared Google-branded tile (lh3.googleusercontent.com/J6_coFbo...) for every article. 601 rows shared that URL (maple 243 / finance 358). New image-guard blocks *.googleusercontent.com images at ingest; 16/16 regression tests; prod DBs migrated tile->NULL; images rebuilt technews:10 finance:4 maple-brief:11 and deployed.
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Placeholder-image guard tests (offline — no network).
|
||||
*
|
||||
* Contract under test (src/lib/ingest/image-guard.ts):
|
||||
* - the ONE shared Google-branded tile observed in production (exact URL
|
||||
* from the 2026-08-18 finance/maple cleanup, lh3.googleusercontent.com
|
||||
* /J6_coFbogxh...) is ALWAYS blocked, in every variant (resize suffixes,
|
||||
* host rotation lh2/lh3/lh4, case, extra query strings)
|
||||
* - real publisher article photos on googleusercontent-lookalike or normal
|
||||
* publisher hosts are NEVER blocked (must-pass: false positives here
|
||||
* would strip legitimate images)
|
||||
*
|
||||
* Runner: `tsx tests/image-guard.test.ts` -> exit 1 on failure.
|
||||
*/
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { isPlaceholderImage } from '@/lib/ingest/image-guard';
|
||||
|
||||
let passed = 0;
|
||||
let failed = 0;
|
||||
|
||||
function check(name: string, fn: () => void): void {
|
||||
try {
|
||||
fn();
|
||||
passed += 1;
|
||||
console.log(`ok ${passed} - ${name}`);
|
||||
} catch (e) {
|
||||
failed += 1;
|
||||
console.error(`not ok ${passed + failed} - ${name}`);
|
||||
console.error(String((e as Error).stack ?? e));
|
||||
}
|
||||
}
|
||||
|
||||
// The exact shared tile URL stored on 601 production rows (2026-08-18).
|
||||
const TILE =
|
||||
'https://lh3.googleusercontent.com/J6_coFbogxhRI9iM864NL_liGXvsQp2Aups' +
|
||||
'Kei7z0cNNfDvGUmWUy20nuUhkREQyrpY4bEeIBuc=s0-w300';
|
||||
|
||||
check('MUST-BLOCK: exact prod shared tile url', () => {
|
||||
assert.equal(isPlaceholderImage(TILE).blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: -rw resize variant', () => {
|
||||
assert.equal(isPlaceholderImage(`${TILE}-rw`).blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: lh4 host rotation', () => {
|
||||
assert.equal(isPlaceholderImage('https://lh4.googleusercontent.com/xyz123=s900').blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: lh2 host rotation', () => {
|
||||
assert.equal(isPlaceholderImage('https://lh2.googleusercontent.com/xyz123').blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: uppercase host', () => {
|
||||
assert.equal(isPlaceholderImage('https://LH3.GOOGLEUSERCONTENT.COM/J6_coFbo=s0').blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: extra query string / fragment', () => {
|
||||
assert.equal(isPlaceholderImage(TILE + '&dummy=1#f').blocked, true);
|
||||
});
|
||||
check('MUST-BLOCK: unknown key (not the known tile) still blocked by host rule', () => {
|
||||
assert.equal(
|
||||
isPlaceholderImage('https://lh3.googleusercontent.com/someOtherKeyWq9aB=s64').blocked,
|
||||
true,
|
||||
);
|
||||
});
|
||||
check('MUST-BLOCK: whitespace-wrapped url', () => {
|
||||
assert.equal(isPlaceholderImage(` ${TILE} `).blocked, true);
|
||||
});
|
||||
|
||||
check('MUST-PASS: wired photo (publisher CDN)', () => {
|
||||
assert.equal(
|
||||
isPlaceholderImage('https://media.wired.com/photos/6a84a2c1/191:100/w_1280/c_limit/x.jpg').blocked,
|
||||
false,
|
||||
);
|
||||
});
|
||||
check('MUST-PASS: cnbcfm photo (publisher CDN)', () => {
|
||||
assert.equal(isPlaceholderImage('https://media.cnbcfm.com/i/2026/08/robo.jpg').blocked, false);
|
||||
});
|
||||
check('MUST-PASS: google.com logo asset (NOT googleusercontent)', () => {
|
||||
assert.equal(isPlaceholderImage('https://www.google.com/logos/2026/xx512.png').blocked, false);
|
||||
});
|
||||
check('MUST-PASS: example.com path segment merely containing the host string', () => {
|
||||
assert.equal(
|
||||
isPlaceholderImage('https://cdn.example.com/googleusercontent.com/img.png').blocked,
|
||||
false,
|
||||
);
|
||||
});
|
||||
check('MUST-PASS: null', () => {
|
||||
assert.equal(isPlaceholderImage(null).blocked, false);
|
||||
});
|
||||
check('MUST-PASS: undefined', () => {
|
||||
assert.equal(isPlaceholderImage(undefined).blocked, false);
|
||||
});
|
||||
check('MUST-PASS: empty string', () => {
|
||||
assert.equal(isPlaceholderImage('').blocked, false);
|
||||
});
|
||||
check('MUST-PASS: not a URL', () => {
|
||||
assert.equal(isPlaceholderImage('not a url').blocked, false);
|
||||
});
|
||||
|
||||
console.log(`\nimage-guard: ${passed} passed, ${failed} failed`);
|
||||
if (failed > 0) process.exit(1);
|
||||
Reference in New Issue
Block a user