8000 Carry the Commons licence in DocumentSource and block single URLs by daoudclarke · Pull Request #648 · mwmbl/mwmbl · GitHub
[go: up one dir, main page]

Skip to content

Carry the Commons licence in DocumentSource and block single URLs - #648

Merged
daoudclarke merged 4 commits into
mainfrom
seed-images-prod-store-slim
Nov 12, 2026
Merged

daoudclarke merged 4 commits into
mainfrom
seed-images-prod-store-slim

Conversation

@daoudclarke
@daoudclarke daoudclarke commented Nov 12, 2026 •
Copy link
Copy Markdown
Contributor

From Claude:

Alternative to #633. Same goal, without the CommonsImage table. Opened separately so the two can be compared; #633 is untouched. PR 5 of the #610 plan. Only one of #633 and this PR should merge (both add migration 0053).

Why

#633 stores every safe file in Postgres, with a revoke/lift state machine and a recheck command (#634). That was built for swapped-file vandalism, and a sample of Commons upload logs doesn't show it as common: about 1.3–1.8k overwrites a day across about 150M files (29 and 16 on the two days sampled were reverts). In a 200-event sample, 80% were by the original uploader, mostly bot imports (maps, charts, Lingua Libre audio); I saw no NSFW swaps, but 200 events can't rule out a rate of around 1%. Standard search also can't read Postgres or make extra requests (up to 5M requests a day), so a table can't gate display anyway. This PR keeps what the later PRs need on that path, in the index and the existing blacklist.

What changed

  • Licence in DocumentSource. Eleven new members, from 100: public domain, CC0, CC BY and CC BY-SA at 2.0, 2.5, 3.0 and 4.0, and COMMONS_OTHER. Across 17,607 seed candidates there are 62 distinct licence names, and the ten listed ones cover 94.3%. The rest go to COMMONS_OTHER. Wire label is "commons". mwmbl/imagesearch/licences.py maps Commons' LicenseShortName to a member. It adds no field to the index. Nothing sets the source on a Commons document yet (that is PR 6), so this half is unused until then.
  • Block one URL. BlockedUrl (admin) holds an exact URL, keyed by canonical page URL for Commons files, so every Commons spelling is caught; any other URL is keyed by itself minus its fragment. Its hash goes into the existing blacklist snapshot with a url: prefix, so there is no new Redis key and no format change. Retrieval (find_blacklisted_urls), indexing (filter_blacklisted_documents), the purge task and the Seed Search strip all check it, so a blocked file is dropped from results, removed from the index, and not re-added. Saving or deleting a block schedules a snapshot rebuild; a block is not instant (a few minutes plus each worker's next check). Standard search still doesn't touch Postgres.
  • commons_file_key moves to mwmbl/imagesearch/commons.py and normalises first-letter case, Image:, underscores/spaces, the mobile host, /w/index.php?title= URLs and NFC. A URL that can't be parsed gives no key rather than an error.
  • The crawler publishes its own snapshot with no database, so blocked URLs are read only when HAS_DATABASE is set. The crawler's snapshot therefore carries no URL blocks.

Known gaps

  • No revocation or recheck. A file swapped to something unsafe after it was judged stays indexed until an operator blocks it. There is 7438 no report path or sampled recheck in this PR; if one is wanted it should come with PR 6 or later. The judged title and description are also frozen at index time.
  • Blocks are exact. A renamed or re-uploaded file, a redirect title, localised namespace aliases (Datei:), Special:FilePath URLs and non-Commons URLs that differ by scheme, query string or trailing slash are different URLs and are not blocked. A bare domain is refused by the admin form.
  • Attribution. Only the licence is carried. CC BY and CC BY-SA also need the author credited, so the result has to link to the file page, which names the author. No author, caption or thumbnail data is stored, so PR 9 (standard-search display) needs a plan for those that doesn't use a table or a request-time fetch.
  • Downstream. Recheck stored Commons files against Commons and the NSFW judge #634 (recheck) and the branches that read CommonsImage have nothing to build on if this replaces Store every Commons file Seed Search judges safe #633. The new DocumentSource values must be deployed to every worker before PR 6 writes any, because Document raises on an unknown source.
  • The Rust DocumentSource enum on the rust_crawl branch isn't mirrored; it isn't on main.
  • The added query-path cost is estimated from the existing 94µs figure, not measured.
  • Block reasons are visible only in the admin; there is no public list of removals.

Verification

  • make check passes. Full make test passes: 1909 passed, 10 skipped. CI's crawler smoke job failed on the first push (the crawler has no database); fixed in ef7f803.
  • New tests: test/test_blocked_urls.py (key spellings, fragments, NFC, unparseable URLs, snapshot lookups, domain not blocked, retrieval, indexing, purge, the Seed Search strip, admin validation, rebuild scheduling, building without a database) and test/test_licences.py.
  • Reviews (subagents): code and security found the crawler bug above, the unparseable-URL exception, admin 500s, fragment evasion and a None key in the web-result filter, all fixed here; and a few low items left as known gaps above. Trust and safety and holistic found the strip not honouring blocks (fixed), the licence-coverage figure being stated wrong (fixed), and the gaps above.

Part of #610

🤖 Generated with Claude Code

The licence of an indexed Commons file is one of eleven new DocumentSource members, so
the result page can credit it without a database read or another request. A moderator can
block one URL (BlockedUrl, admin): the URL's hash goes into the existing blacklist
snapshot, and retrieval, indexing and the background purge all check it, so a blocked file
is dropped, removed and not re-added. commons_file_key moves to imagesearch.commons and
normalises one canonical URL.

No functional changes to the crawler.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@codecov
codecov Bot commented Nov 12, 2026 •
Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.58824% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
mwmbl/blocked_urls.py 84.61% 2 Missing ⚠️
mwmbl/imagesearch/commons.py 92.59% 2 Missing ⚠️
mwmbl/indexer/blacklist_snapshot.py 95.65% 1 Missing ⚠️
mwmbl/models.py 93.75% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

daoudclarke and others added 3 commits November 12, 2026 12:04
The standalone crawler publishes its own blacklist snapshot with no database, so
build_snapshot raised ImproperlyConfigured there and the crawler smoke test failed. Guard the
read with HAS_DATABASE, as get_curated_domains does, and test that a snapshot builds without one.

No functional changes to the crawler.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
An unparseable URL no longer raises in retrieval, indexing or the web-result filter; the
admin refuses a bare domain, an over-long URL and a second spelling of a blocked file; a
fragment no longer evades a block; and titles are matched in NFC. The Seed Search strip now
skips blocked files, and a web result is no longer dropped when a shown image has no key.
Licence coverage is stated correctly (ten licences, 94%).

No functional changes to the crawler.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
test_blocked_urls imported make_image from another test module, which resolved locally but not
in CI, where `test` is not a package, so collection failed for the whole run.

No functional changes to the crawler.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@daoudclarke
daoudclarke merged commit 29763f4 into main Nov 12, 2026
7 checks passed
@daoudclarke
daoudclarke deleted the seed-images-prod-store-slim branch November 12, 2026 12:45
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

0