Skip to content

Add validate-dnr-rules CLI tool with cross-platform CI#4

Merged
chrmod merged 1 commit intoghosteryfrom
validator
Apr 21, 2026
Merged

Add validate-dnr-rules CLI tool with cross-platform CI#4
chrmod merged 1 commit intoghosteryfrom
validator

Conversation

@chrmod
Copy link
Copy Markdown
Member

@chrmod chrmod commented Apr 20, 2026

Summary

Adds a CLI tool that validates Declarative Net Request rulesets against WebKit's actual URL filter parser — the same code Safari runs at match time — so extension developers find out which rules will silently fail to block before shipping to Safari users.

Both regexFilter and Chrome-style urlFilter patterns (e.g. ||tracker.example.com^) are checked. urlFilter rules go through the same anchor/escape/wildcard conversion WebKit applies at runtime; errors are reported against the pattern the author wrote, not the converted form.

What's included

ghostery/validate-dnr-rules/ — Standalone C++ tool that links against WebKit's own WTF library and compiles URLFilterParser.cpp directly. Builds into a single ~900 KB binary on Linux and macOS via WebKit's existing CMake (-DPORT=JSCOnly -DUSE_SYSTEM_MALLOC=ON). No WebKit source is duplicated — every commit on this fork stays in sync automatically.

.github/workflows/validate-dnr-rules.yml — Builds on ubuntu-24.04 (x64) and macOS arm64 on pushes and PRs to ghostery. On merge to ghostery, publishes a GitHub Release with both binaries attached (macOS ad-hoc signed for Gatekeeper).

Tools/Scripts/validate-dnr-rules — Shell wrapper that compiles a small ObjC++ tool on-the-fly against a locally-built WebKit.framework. Exercises the full DNR translator pipeline (JSON → WebKit-native rules → content-blocker bytecode) and optionally compiles end-to-end with --compile. Useful for WebKit developers iterating on DNR/content-extension changes:

Tools/Scripts/build-webkit --debug
Tools/Scripts/validate-dnr-rules [--compile] path/to/dnr-rules.json

CMakeLists.txt — one-line hook to add_subdirectory(ghostery/validate-dnr-rules) at the repo root.

Usage

$ ./validate-dnr-rules-linux-x64 dnr-ads.json
=== dnr-ads.json ===
Rules: 17826
  ERROR: Rule 320 [regex]: Arbitrary atom repetitions are not supported. — ^https:\/\/business-component\.[a-z]+(-[a-z]+){2}\.com\/
  ERROR: Rule 4849 [regex]: Character class is not supported. — \.workers\.dev\/help\/\d{14,19}\b
  ERROR: Rule 10535 [regex]: Disjunctions are not supported yet. — ^https:\/\/(?:appeal|contact|page)\.[a-z]{15,}\.com\/appeal_case_id\b
  ...
Valid: 17696/17826

FAILED: 130 error(s) found.

Each error is tagged [regex] or [url] so authors know which field the failing pattern came from. Exit code is 0 on success, 1 with per-rule details on failure — suitable for extension CI pipelines.

Test plan

  • Download a release binary from github.com/ghostery/WebKit/releases and run it against a real ruleset (e.g. dist/rule_resources/dnr-ads.json from the ghostery-extension build). Verify the tool reports per-rule errors, ends with FAILED: N error(s) found., and exits non-zero.
  • Run the same binary against a clean ruleset (or a one-rule file with a supported pattern like ||example.com^). Verify it prints OK: All rules validated successfully. and exits 0.
  • On merge to ghostery, confirm a new release appears with both the Linux x64 and macOS arm64 binaries attached, and that the macOS binary runs without a Gatekeeper prompt on Apple Silicon.

Standalone tool for validating Declarative Net Request rulesets against
WebKit's content extension translator. Ships prebuilt Linux x64 and
macOS arm64 binaries from a GitHub Actions release workflow so Ghostery
engineers can vet rulesets without a full WebKit build.

bool characterClassMayContainStrings(BuiltInCharacterClassID)
{
return false;
Copy link
Copy Markdown
Member

@philipp-classen philipp-classen Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is expected to be never called, you can crash (in all three cases):

std::abort();

When I try, it is not reached. But then you have guarantees that it was never called in a run.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be the idea: #5

@chrmod chrmod merged commit 0a0d4ba into ghostery Apr 21, 2026
3 checks passed
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.

2 participants