domain-pre-flight 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- domain_pre_flight-0.9.0/.claude/skills/domain-pre-flight/SKILL.md +196 -0
- domain_pre_flight-0.9.0/.github/ISSUE_TEMPLATE/bug_report.md +34 -0
- domain_pre_flight-0.9.0/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- domain_pre_flight-0.9.0/.github/pull_request_template.md +22 -0
- domain_pre_flight-0.9.0/.github/workflows/publish.yml +40 -0
- domain_pre_flight-0.9.0/.github/workflows/refresh-known-brands.yml +42 -0
- domain_pre_flight-0.9.0/.github/workflows/refresh-tld-risk.yml +41 -0
- domain_pre_flight-0.9.0/.github/workflows/release.yml +41 -0
- domain_pre_flight-0.9.0/.github/workflows/test.yml +57 -0
- domain_pre_flight-0.9.0/.gitignore +22 -0
- domain_pre_flight-0.9.0/CHANGELOG.md +63 -0
- domain_pre_flight-0.9.0/CLAUDE.md +118 -0
- domain_pre_flight-0.9.0/CODE_OF_CONDUCT.md +23 -0
- domain_pre_flight-0.9.0/CONTRIBUTING.md +50 -0
- domain_pre_flight-0.9.0/LICENSE +21 -0
- domain_pre_flight-0.9.0/PKG-INFO +241 -0
- domain_pre_flight-0.9.0/README.md +202 -0
- domain_pre_flight-0.9.0/SECURITY.md +26 -0
- domain_pre_flight-0.9.0/docs/agents/README.md +13 -0
- domain_pre_flight-0.9.0/docs/agents/adding-platforms.md +119 -0
- domain_pre_flight-0.9.0/docs/agents/data-updates.md +130 -0
- domain_pre_flight-0.9.0/docs/agents/extending-checks.md +179 -0
- domain_pre_flight-0.9.0/docs/agents/tuning-scores.md +95 -0
- domain_pre_flight-0.9.0/docs/agents/writing-tests.md +91 -0
- domain_pre_flight-0.9.0/docs/architecture.md +156 -0
- domain_pre_flight-0.9.0/docs/context-cards/README.md +38 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-basic.md +65 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-handles.md +89 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-history.md +61 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-llmo.md +65 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-score.md +100 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-semantics.md +66 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-trademark.md +79 -0
- domain_pre_flight-0.9.0/docs/context-cards/checks-typosquat.md +77 -0
- domain_pre_flight-0.9.0/docs/context-cards/cli.md +86 -0
- domain_pre_flight-0.9.0/docs/decisions/0001-tldextract-for-psl-parsing.md +24 -0
- domain_pre_flight-0.9.0/docs/decisions/0002-band-as-str-enum-not-strenum.md +30 -0
- domain_pre_flight-0.9.0/docs/decisions/0003-tld-risk-as-json-bundle.md +31 -0
- domain_pre_flight-0.9.0/docs/decisions/0004-wayback-bounded-count.md +40 -0
- domain_pre_flight-0.9.0/docs/decisions/0005-bot-walled-platforms-return-unknown.md +33 -0
- domain_pre_flight-0.9.0/docs/decisions/0006-trademark-default-off.md +32 -0
- domain_pre_flight-0.9.0/docs/decisions/0007-score-weights-centralised.md +30 -0
- domain_pre_flight-0.9.0/docs/decisions/0008-llmo-experimental-marker.md +28 -0
- domain_pre_flight-0.9.0/docs/decisions/0009-trademark-deeplink-only.md +52 -0
- domain_pre_flight-0.9.0/docs/decisions/README.md +44 -0
- domain_pre_flight-0.9.0/docs/guide/usage.md +362 -0
- domain_pre_flight-0.9.0/examples/subprocess-variant/README.md +34 -0
- domain_pre_flight-0.9.0/examples/subprocess-variant/bench.py +83 -0
- domain_pre_flight-0.9.0/examples/subprocess-variant/server.py +99 -0
- domain_pre_flight-0.9.0/pyproject.toml +97 -0
- domain_pre_flight-0.9.0/scripts/refresh_known_brands.py +142 -0
- domain_pre_flight-0.9.0/scripts/refresh_tld_risk.py +112 -0
- domain_pre_flight-0.9.0/scripts/smoke.sh +122 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/__init__.py +3 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/__init__.py +1 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/basic.py +149 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/dns_sanity.py +157 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/handles.py +178 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/history.py +106 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/idn_homograph.py +110 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/llmo.py +189 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/permutations.py +162 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/rdap.py +174 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/score.py +219 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/semantics.py +117 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/trademark.py +124 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/checks/typosquat.py +148 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/cli.py +569 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/__init__.py +0 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/known_brands.txt +158 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/__init__.py +0 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/ar.txt +9 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/en.txt +23 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/es.txt +15 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/hi.txt +12 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/id.txt +11 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/ja.txt +16 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/ko.txt +9 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/pt.txt +12 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/th.txt +7 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/vi.txt +8 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/negative_meanings/zh.txt +11 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/data/tld_risk.json +45 -0
- domain_pre_flight-0.9.0/src/domain_pre_flight/mcp_server.py +139 -0
- domain_pre_flight-0.9.0/tests/__init__.py +0 -0
- domain_pre_flight-0.9.0/tests/test_basic.py +59 -0
- domain_pre_flight-0.9.0/tests/test_cli.py +281 -0
- domain_pre_flight-0.9.0/tests/test_dns_sanity.py +119 -0
- domain_pre_flight-0.9.0/tests/test_handles.py +178 -0
- domain_pre_flight-0.9.0/tests/test_idn_homograph.py +44 -0
- domain_pre_flight-0.9.0/tests/test_llmo.py +62 -0
- domain_pre_flight-0.9.0/tests/test_mcp_server.py +68 -0
- domain_pre_flight-0.9.0/tests/test_permutations.py +51 -0
- domain_pre_flight-0.9.0/tests/test_rdap.py +116 -0
- domain_pre_flight-0.9.0/tests/test_score.py +30 -0
- domain_pre_flight-0.9.0/tests/test_semantics.py +65 -0
- domain_pre_flight-0.9.0/tests/test_tld_risk_bundle.py +39 -0
- domain_pre_flight-0.9.0/tests/test_trademark.py +57 -0
- domain_pre_flight-0.9.0/tests/test_typosquat.py +64 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: domain-pre-flight
|
|
3
|
+
description: Pre-flight checks before registering a domain for a new site or app. Runs structural / history / typosquat / multi-language / LLMO checks against one or more candidates, optionally adds same-name handle availability and trademark deeplinks, and returns per-domain verdict bands plus (when given multiple candidates) a comparison table and a top-3 trademark verify checklist. Use when the user is choosing a domain, evaluating a brainstorm shortlist, or wants a sanity check before pulling the trigger on a registrar.
|
|
4
|
+
argument-hint: <domain> [<domain> ...] [--full] [--handles] [--trademark]
|
|
5
|
+
allowed-tools: Bash, Read
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# domain-pre-flight skill
|
|
9
|
+
|
|
10
|
+
Run pre-flight checks before the user registers a new domain. The CLI lives at https://github.com/kenimo49/domain-pre-flight; this skill is the conversational wrapper around it.
|
|
11
|
+
|
|
12
|
+
## When to invoke
|
|
13
|
+
|
|
14
|
+
Use this skill when the user:
|
|
15
|
+
|
|
16
|
+
- explicitly asks "is this domain safe to register" / "can I take X.com" / "ドメイン取って大丈夫?"
|
|
17
|
+
- gives a list of candidate domains and asks which one to pick
|
|
18
|
+
- mentions registering a name and you want to add a sanity check before they spend money
|
|
19
|
+
- references the companion book `domain-hunter-engineer-collab` or "domain hunter" workflow
|
|
20
|
+
|
|
21
|
+
Do NOT invoke when:
|
|
22
|
+
|
|
23
|
+
- the user is asking about a domain they already own (use the trademark / typosquat subcommands manually if needed, but the full pre-flight is for unregistered candidates)
|
|
24
|
+
- the question is about domain investing / aftermarket / drop-catching (out of scope for this tool)
|
|
25
|
+
|
|
26
|
+
## How it works
|
|
27
|
+
|
|
28
|
+
1. **Resolve the CLI.** Try in this order and use the first that exists:
|
|
29
|
+
```bash
|
|
30
|
+
DPF=$(command -v dpf 2>/dev/null \
|
|
31
|
+
|| command -v domain-pre-flight 2>/dev/null \
|
|
32
|
+
|| ([ -x "$HOME/repos/domain-pre-flight/.venv/bin/dpf" ] && echo "$HOME/repos/domain-pre-flight/.venv/bin/dpf"))
|
|
33
|
+
```
|
|
34
|
+
If `$DPF` is empty, see the install section below.
|
|
35
|
+
2. **Detect single vs multi.** If the user gave one domain, follow the [single-domain](#single-domain) flow. If two or more, follow the [multi-domain](#multi-domain) flow.
|
|
36
|
+
3. **Always pass `--json`** to the CLI and parse with `python3 -c 'import json, sys; ...'`. Never read coloured terminal output.
|
|
37
|
+
|
|
38
|
+
## Install (only if `$DPF` did not resolve)
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Recommended — pipx isolates the CLI in its own venv but exposes `dpf` on PATH
|
|
42
|
+
pipx install git+https://github.com/kenimo49/domain-pre-flight.git
|
|
43
|
+
|
|
44
|
+
# Or, from a local clone in editable mode
|
|
45
|
+
pip install -e /home/iris/repos/domain-pre-flight
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Single-domain
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
"$DPF" check "$domain" --json # quick (default)
|
|
52
|
+
"$DPF" check "$domain" --check-handles --check-trademark --json # full pre-flight
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Runs basic + history + typosquat + semantics + llmo (`--json` always). The `--check-handles` and `--check-trademark` flags are opt-in for slower / network-heavy / manual-verify paths.
|
|
56
|
+
|
|
57
|
+
Summarise in 3–6 lines:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
**<domain>**: <band> — score <N>/100
|
|
61
|
+
|
|
62
|
+
What flagged:
|
|
63
|
+
- <deduction reason 1>: -<points>
|
|
64
|
+
- <deduction reason 2>: -<points>
|
|
65
|
+
|
|
66
|
+
Recommendation: <one sentence — register, walk away, or run a deeper check>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Keep the report under ~6 lines unless the user asks for the full breakdown. The `verdict.deductions` list in the JSON is the source of truth — quote it directly rather than paraphrasing (the wording is calibrated).
|
|
70
|
+
|
|
71
|
+
If a check returned `lookup_failed` or `unknown` (e.g. handles bot wall), say so explicitly. Do not pretend you got a clean answer.
|
|
72
|
+
|
|
73
|
+
## Multi-domain
|
|
74
|
+
|
|
75
|
+
Run the candidates in parallel via background bash jobs, write each to a temp JSON, then aggregate. Pattern:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p /tmp/dpf-batch
|
|
79
|
+
DOMAINS=("$@") # the user's argument list
|
|
80
|
+
for d in "${DOMAINS[@]}"; do
|
|
81
|
+
"$DPF" check "$d" --check-handles --check-trademark --json \
|
|
82
|
+
> "/tmp/dpf-batch/$d.json" 2> "/tmp/dpf-batch/$d.err" &
|
|
83
|
+
done
|
|
84
|
+
wait
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
8 candidates running in parallel typically finish inside 30–60 seconds. Read each JSON with `python3 -c 'import json, sys; ...'` and assemble the [output](#multi-domain-output).
|
|
88
|
+
|
|
89
|
+
For ad-hoc shortlists (≤16 candidates) parallel runs are fine. For larger lists chunk into batches of 8 to avoid overwhelming Wayback / public APIs.
|
|
90
|
+
|
|
91
|
+
### Multi-domain output
|
|
92
|
+
|
|
93
|
+
Produce three sections, in this order:
|
|
94
|
+
|
|
95
|
+
#### 1. Comparison table
|
|
96
|
+
|
|
97
|
+
One row per candidate. Columns:
|
|
98
|
+
|
|
99
|
+
| domain | band | score | top deductions | github | npm | pypi | x/ig | tld notes |
|
|
100
|
+
|
|
101
|
+
- `band` uses the colour emoji: 🟢 GREEN / 🟡 YELLOW / 🟠 ORANGE / 🔴 RED.
|
|
102
|
+
- `top deductions` keeps the 1–2 highest-points entries from `verdict.deductions` (verbatim).
|
|
103
|
+
- `github` / `npm` / `pypi` show ✅ for `available`, ❌ for `taken`, ❓ for `unknown`.
|
|
104
|
+
- `x/ig` is collapsed because both X and Instagram are bot-walled and frequently `unknown` — render as `❓/❓` unless one of them came back `available` (404), then show the actual symbols.
|
|
105
|
+
- `tld notes` flags new gTLDs (`.engineer`, `.app`, etc.) that have a known SEO ramp-up disadvantage even when the band is green.
|
|
106
|
+
|
|
107
|
+
#### 2. Ranking
|
|
108
|
+
|
|
109
|
+
Pick the **top 3** candidates by:
|
|
110
|
+
|
|
111
|
+
1. Verdict band (GREEN > YELLOW > ORANGE > RED).
|
|
112
|
+
2. Within band, by `verdict.score` desc.
|
|
113
|
+
3. Tie-breaker by handles availability (more ✅ wins).
|
|
114
|
+
|
|
115
|
+
For each top-3 entry, give:
|
|
116
|
+
|
|
117
|
+
- 🥇 / 🥈 / 🥉 medal + domain
|
|
118
|
+
- 1-line strategic rationale (relate to the user's stated project goals if known)
|
|
119
|
+
- 1-line weakness or risk
|
|
120
|
+
- handles status summary
|
|
121
|
+
|
|
122
|
+
#### 3. Top-3 trademark verify checklist
|
|
123
|
+
|
|
124
|
+
**This is the headline UX of multi-domain mode.** Render only the **top 3** candidates' trademark deeplinks, as a 3×3 markdown table:
|
|
125
|
+
|
|
126
|
+
| candidate | USPTO | EUIPO | J-PlatPat |
|
|
127
|
+
|-----------|-------|-------|-----------|
|
|
128
|
+
| **<domain1>** | [search](url) | [search](url) | [search](url) |
|
|
129
|
+
| <domain2> | [search](url) | [search](url) | [search](url) |
|
|
130
|
+
| <domain3> | [search](url) | [search](url) | [search](url) |
|
|
131
|
+
|
|
132
|
+
The deeplink URLs come straight from the CLI's `trademark.jurisdictions[].deeplink` field — do not reconstruct them by hand.
|
|
133
|
+
|
|
134
|
+
Tell the user: **trademark verification is manual** (per ADR 0009 — none of the registries publishes a stable public search API). 9 link clicks for the top 3 candidates is the minimum honest verify pass; anything beyond top 3 is over-clicking unless a top-3 entry hits a conflict and the next candidate inherits the slot.
|
|
135
|
+
|
|
136
|
+
For the **bottom candidates (rank 4+)**, do NOT render their trademark deeplinks. Only flag if the entire top 3 has issues, in which case re-run the verify checklist for ranks 4–6 explicitly when asked.
|
|
137
|
+
|
|
138
|
+
#### 4. Falsifiable next step
|
|
139
|
+
|
|
140
|
+
End with one sentence telling the user what to do next: e.g. *"Click the 9 links above; if any USPTO/EUIPO entry returns a hit in class 9 / 33 / 35, the candidate falls out and rank #4 takes its slot."* Make it concrete enough that the user knows when they are done.
|
|
141
|
+
|
|
142
|
+
## Targeted single-axis checks
|
|
143
|
+
|
|
144
|
+
When the user only cares about one axis, call the corresponding subcommand directly:
|
|
145
|
+
|
|
146
|
+
| User intent | Run |
|
|
147
|
+
| --------------------------------------- | -------------------------------------- |
|
|
148
|
+
| "Is the GitHub / npm name free?" | `"$DPF" handles <domain> --json` |
|
|
149
|
+
| "Does this name look like a typosquat?" | `"$DPF" typosquat <domain> --json` |
|
|
150
|
+
| "Get me the trademark deeplinks." | `"$DPF" trademark <domain> --jurisdictions us,eu --json` |
|
|
151
|
+
| "How does this read in Spanish?" | `"$DPF" semantics <domain> --languages es --json` |
|
|
152
|
+
| "Is this name memorable for voice?" | `"$DPF" llmo <domain> --json` |
|
|
153
|
+
| "Has this domain been used before?" | `"$DPF" history <domain> --json` |
|
|
154
|
+
| "Is the structure valid at all?" | `"$DPF" basic <domain> --json` |
|
|
155
|
+
|
|
156
|
+
These can also be batched — same parallel pattern as multi-domain `check`.
|
|
157
|
+
|
|
158
|
+
## Trademark output (every mode)
|
|
159
|
+
|
|
160
|
+
Every trademark check returns `status="not_supported"` with a populated `deeplink`. **This is not a bug** — see ADR 0009. The CLI no longer attempts live queries against USPTO / EUIPO / J-PlatPat because none of those registries publishes a stable, documented, no-auth search API.
|
|
161
|
+
|
|
162
|
+
When summarising:
|
|
163
|
+
|
|
164
|
+
- Single-domain mode: surface the 3 deeplinks inline (one for each jurisdiction).
|
|
165
|
+
- Multi-domain mode: surface the **top-3** candidates' deeplinks in the verify checklist (9 total). Skip ranks 4+.
|
|
166
|
+
- Always tell the user trademark verification is **manual** — clicking a deeplink opens the official search UI pre-filled with the SLD.
|
|
167
|
+
- Never say "no trademark conflict found" — the CLI cannot determine that.
|
|
168
|
+
|
|
169
|
+
## Error handling
|
|
170
|
+
|
|
171
|
+
- **CLI not installed**: tell the user how to install (see install section above).
|
|
172
|
+
- **Network error during `--check-handles`**: re-run the same command once before reporting failure; if still failing, surface the unknown entries in the summary as `❓` and note "transport error" inline.
|
|
173
|
+
- **Wayback CDX timeout**: a single ReadTimeout is common; for new / freshly-registered domains, "no Wayback snapshots" is the expected outcome anyway. Note the timeout but do not block on it.
|
|
174
|
+
- **Domain has obvious syntactic issues** (`-foo-.com`): the `basic` check returns RED with `is_valid_syntax = false`; pass that signal up immediately rather than running the rest.
|
|
175
|
+
|
|
176
|
+
## Exit-code conventions
|
|
177
|
+
|
|
178
|
+
`dpf check` exit codes encode the band:
|
|
179
|
+
- `0` — GREEN or YELLOW (proceed / proceed with caution)
|
|
180
|
+
- `1` — ORANGE (mitigate before proceeding)
|
|
181
|
+
- `2` — RED (do not register without manual review)
|
|
182
|
+
|
|
183
|
+
In a shell script, `if dpf check "$d" --json > out.json; then ...` works because both clean bands return 0. In multi-domain mode, do **not** rely on the per-call exit code to abort early — collect all results, then rank.
|
|
184
|
+
|
|
185
|
+
## Related docs
|
|
186
|
+
|
|
187
|
+
- Full CLI walkthrough: `docs/guide/usage.md` in the repo
|
|
188
|
+
- Architecture: `docs/architecture.md`
|
|
189
|
+
- ADRs: `docs/decisions/` (especially 0009 for trademark)
|
|
190
|
+
|
|
191
|
+
## Stylistic notes
|
|
192
|
+
|
|
193
|
+
- Mirror the user's language (English in / English out, 日本語 in / 日本語 out).
|
|
194
|
+
- The tool flags candidates, not legal opinions — when surfacing trademark hits, never claim infringement; say "consult counsel" if the user asks for a verdict on the legal angle.
|
|
195
|
+
- Treat the LLMO score as one input among many; it is permanently marked experimental.
|
|
196
|
+
- Multi-domain output is dense. Resist the urge to add filler explanation between the table, the ranking, and the verify checklist — the user will read them in order, not as one long paragraph.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something is wrong with the CLI or a check
|
|
4
|
+
title: "[bug] "
|
|
5
|
+
labels: bug
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What happened
|
|
9
|
+
|
|
10
|
+
A clear, single-paragraph description of the actual behaviour.
|
|
11
|
+
|
|
12
|
+
## What I expected
|
|
13
|
+
|
|
14
|
+
What the docs or your intuition said *should* have happened.
|
|
15
|
+
|
|
16
|
+
## Reproduction
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# the exact CLI invocation
|
|
20
|
+
dpf check ...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
If the bug is data-driven (a specific domain trips a wrong band, a brand list miss, etc.), include the domain.
|
|
24
|
+
|
|
25
|
+
## Output
|
|
26
|
+
|
|
27
|
+
The relevant stdout / JSON. If the report is large, paste the `verdict.deductions` array and the offending check section only.
|
|
28
|
+
|
|
29
|
+
## Environment
|
|
30
|
+
|
|
31
|
+
- domain-pre-flight version: `dpf --version`
|
|
32
|
+
- Python: `python --version`
|
|
33
|
+
- OS:
|
|
34
|
+
- Install method: `pipx install` / `pip install -e` / other
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a new check, flag, platform, or data update
|
|
4
|
+
title: "[feature] "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What you want
|
|
9
|
+
|
|
10
|
+
One paragraph describing the feature.
|
|
11
|
+
|
|
12
|
+
## Why it matters
|
|
13
|
+
|
|
14
|
+
The decision the feature would help the user make. "Make X possible" is OK; "tool would be more complete" is not.
|
|
15
|
+
|
|
16
|
+
## What it should NOT do
|
|
17
|
+
|
|
18
|
+
Things that are out of scope. (See README for the project's stated boundaries.)
|
|
19
|
+
|
|
20
|
+
## How it might fit
|
|
21
|
+
|
|
22
|
+
If you have an opinion on which existing check / module / data file this slots into, mention it. The maintainer will route otherwise.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## What this PR does
|
|
2
|
+
|
|
3
|
+
One paragraph; the imperative form ("add ...", "fix ...", "refactor ...").
|
|
4
|
+
|
|
5
|
+
## Why
|
|
6
|
+
|
|
7
|
+
Linked issue or one-line motivation.
|
|
8
|
+
|
|
9
|
+
## Tests
|
|
10
|
+
|
|
11
|
+
- [ ] `pytest -q` passes
|
|
12
|
+
- [ ] `ruff check src tests scripts` clean
|
|
13
|
+
- [ ] `mypy src/domain_pre_flight` clean
|
|
14
|
+
- [ ] `bash scripts/smoke.sh --offline` passes
|
|
15
|
+
- [ ] Coverage stays at ≥70% for the cli-omitted bundle
|
|
16
|
+
|
|
17
|
+
## Checklist (delete what doesn't apply)
|
|
18
|
+
|
|
19
|
+
- [ ] No new runtime dependency added (or, if added, justified in the commit message).
|
|
20
|
+
- [ ] If a new check: `score.py` updated with a `_<name>_deductions` function; `cli.py` integrated.
|
|
21
|
+
- [ ] If a doc-bearing design choice: ADR added under `docs/decisions/`.
|
|
22
|
+
- [ ] CHANGELOG.md updated.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
name: publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build-and-publish:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
environment:
|
|
13
|
+
name: pypi
|
|
14
|
+
url: https://pypi.org/p/domain-pre-flight
|
|
15
|
+
permissions:
|
|
16
|
+
id-token: write
|
|
17
|
+
contents: read
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
with:
|
|
21
|
+
fetch-depth: 0
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
|
|
28
|
+
- name: Install build tooling
|
|
29
|
+
run: |
|
|
30
|
+
python -m pip install --upgrade pip
|
|
31
|
+
pip install build twine
|
|
32
|
+
|
|
33
|
+
- name: Build sdist + wheel
|
|
34
|
+
run: python -m build
|
|
35
|
+
|
|
36
|
+
- name: Verify package metadata
|
|
37
|
+
run: twine check dist/*
|
|
38
|
+
|
|
39
|
+
- name: Publish to PyPI (Trusted Publisher OIDC)
|
|
40
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: refresh-known-brands
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# First Tuesday of each month at 03:30 UTC (offset from refresh-tld-risk).
|
|
6
|
+
- cron: "30 3 1-7 * 2"
|
|
7
|
+
workflow_dispatch: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
refresh:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
pull-requests: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
cache: pip
|
|
23
|
+
|
|
24
|
+
- name: Install runtime deps
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install requests tldextract
|
|
28
|
+
|
|
29
|
+
- name: Refresh brand list from Tranco
|
|
30
|
+
run: python scripts/refresh_known_brands.py --top 2000
|
|
31
|
+
|
|
32
|
+
- name: Open PR if data changed
|
|
33
|
+
uses: peter-evans/create-pull-request@v6
|
|
34
|
+
with:
|
|
35
|
+
commit-message: "data: refresh known_brands.txt from Tranco"
|
|
36
|
+
title: "data: refresh known_brands.txt (auto, Tranco top 2000)"
|
|
37
|
+
body: |
|
|
38
|
+
Automated monthly refresh of `src/domain_pre_flight/data/known_brands.txt`.
|
|
39
|
+
Pulls the latest Tranco top 2000 and unions stems with the curated
|
|
40
|
+
baseline. Manually re-run with `python scripts/refresh_known_brands.py`.
|
|
41
|
+
branch: auto/known-brands-refresh
|
|
42
|
+
delete-branch: true
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: refresh-tld-risk
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# First Monday of each month at 03:00 UTC.
|
|
6
|
+
- cron: "0 3 1-7 * 1"
|
|
7
|
+
workflow_dispatch: {}
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
refresh:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
permissions:
|
|
13
|
+
contents: write
|
|
14
|
+
pull-requests: write
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
cache: pip
|
|
23
|
+
|
|
24
|
+
- name: Install runtime deps
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install --upgrade pip
|
|
27
|
+
pip install requests
|
|
28
|
+
|
|
29
|
+
- name: Refresh TLD risk bundle
|
|
30
|
+
run: python scripts/refresh_tld_risk.py
|
|
31
|
+
|
|
32
|
+
- name: Open PR if data changed
|
|
33
|
+
uses: peter-evans/create-pull-request@v6
|
|
34
|
+
with:
|
|
35
|
+
commit-message: "data: refresh tld_risk.json"
|
|
36
|
+
title: "data: refresh tld_risk.json (auto)"
|
|
37
|
+
body: |
|
|
38
|
+
Automated monthly refresh of `src/domain_pre_flight/data/tld_risk.json`.
|
|
39
|
+
Re-run locally with `python scripts/refresh_tld_risk.py`.
|
|
40
|
+
branch: auto/tld-risk-refresh
|
|
41
|
+
delete-branch: true
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
publish:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
with:
|
|
16
|
+
fetch-depth: 0
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Install build tooling
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
pip install build twine
|
|
27
|
+
|
|
28
|
+
- name: Build sdist + wheel
|
|
29
|
+
run: python -m build
|
|
30
|
+
|
|
31
|
+
- name: Verify package metadata
|
|
32
|
+
run: twine check dist/*
|
|
33
|
+
|
|
34
|
+
- name: Upload to GitHub Release
|
|
35
|
+
env:
|
|
36
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
run: |
|
|
38
|
+
gh release upload "${GITHUB_REF##*/}" dist/* --clobber
|
|
39
|
+
|
|
40
|
+
# PyPI publishing is handled by publish.yml (Trusted Publisher / OIDC).
|
|
41
|
+
# This workflow only uploads the sdist + wheel to the GitHub Release.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: ${{ matrix.python-version }}
|
|
23
|
+
cache: pip
|
|
24
|
+
|
|
25
|
+
- name: Install package and dev dependencies
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
pip install -e ".[dev]"
|
|
29
|
+
|
|
30
|
+
- name: Run pytest with coverage
|
|
31
|
+
run: pytest --cov --cov-report=term-missing --cov-fail-under=70
|
|
32
|
+
|
|
33
|
+
- name: Run smoke tests (offline)
|
|
34
|
+
if: matrix.python-version == '3.12'
|
|
35
|
+
run: bash scripts/smoke.sh --offline
|
|
36
|
+
|
|
37
|
+
lint:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/checkout@v4
|
|
41
|
+
|
|
42
|
+
- name: Set up Python
|
|
43
|
+
uses: actions/setup-python@v5
|
|
44
|
+
with:
|
|
45
|
+
python-version: "3.12"
|
|
46
|
+
cache: pip
|
|
47
|
+
|
|
48
|
+
- name: Install dev dependencies
|
|
49
|
+
run: |
|
|
50
|
+
python -m pip install --upgrade pip
|
|
51
|
+
pip install -e ".[dev]"
|
|
52
|
+
|
|
53
|
+
- name: Ruff check
|
|
54
|
+
run: ruff check src tests scripts
|
|
55
|
+
|
|
56
|
+
- name: Mypy check
|
|
57
|
+
run: mypy src/domain_pre_flight
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*$py.class
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
.venv/
|
|
9
|
+
venv/
|
|
10
|
+
env/
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.pytest_cache/
|
|
14
|
+
.mypy_cache/
|
|
15
|
+
.ruff_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
.tox/
|
|
19
|
+
.idea/
|
|
20
|
+
.vscode/
|
|
21
|
+
*.swp
|
|
22
|
+
.DS_Store
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **domain-pre-flight** are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) loosely; versions follow [SemVer](https://semver.org/) with the convention that **0.x is experimental** — breaking changes can land on a minor bump.
|
|
4
|
+
|
|
5
|
+
## [0.9.0] — 2026-07-07
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **MCP server** (`domain-pre-flight[mcp]`) — new optional extra and `domain-pre-flight-mcp` entry point. Ships an MCP (Model Context Protocol) server built on FastMCP so AI assistants (Claude Code / Cursor / Claude Desktop) can call the checks as tools. Exposes 4 use-case-oriented tools rather than mapping every CLI flag: `check_domain`, `check_handles`, `check_trademark`, `list_typo_permutations`.
|
|
10
|
+
- **Subprocess-variant reference implementation** — `examples/subprocess-variant/` ships a deliberately naive subprocess-based MCP server plus a benchmark script (`bench.py`) as the "before" half of a security / latency comparison. Not for production.
|
|
11
|
+
- **PyPI publishing workflow** — `.github/workflows/publish.yml` publishes to PyPI via Trusted Publisher OIDC on every `v*` tag push; no long-lived API tokens.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- `pyproject.toml` gains `[project.optional-dependencies].mcp = ["mcp>=1.2"]` and `[project.scripts].domain-pre-flight-mcp = "..."`. Core CLI users are unaffected — the `mcp` dependency only installs when `[mcp]` is requested.
|
|
16
|
+
- `release.yml` no longer holds a `PYPI_API_TOKEN` fallback path; PyPI publishing is centralised in `publish.yml`.
|
|
17
|
+
|
|
18
|
+
## [0.8.0] — 2026-05-08
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **IDN homograph detection** — new `dpf homograph` subcommand and `--no-homograph` flag. UTS #39 confusable matching against the brand list. `gооgle.com` (Cyrillic о) is flagged as a brand collision.
|
|
23
|
+
- **RDAP lifecycle check** — new `dpf rdap` subcommand and `--check-rdap` flag. Surfaces creation date, expiration date, registrar, and registry status (clientHold / redemptionPeriod / etc.) via the rdap.org public gateway.
|
|
24
|
+
- **DNS hygiene check** — new `dpf dns` subcommand and `--check-dns` flag. Probes MX / SPF / DMARC / DKIM presence; flags MX-without-SPF / MX-without-DMARC as deductions.
|
|
25
|
+
- **dnstwist-style permutations** — new `dpf permutations` subcommand. Generates 8 kinds of typo / spoof variants (omission, transposition, doubling, homoglyph, keyboard_adjacent, substitution, addition, hyphenation).
|
|
26
|
+
- **GitLab handle availability** — added to `dpf handles` defaults.
|
|
27
|
+
- **5 new languages** in semantics: Hindi (`hi`), Arabic (`ar`), Vietnamese (`vi`), Thai (`th`), Indonesian (`id`). Romanised forms only.
|
|
28
|
+
- **LLMO locale profile** — `--llmo-locale en|neutral`. Neutral mode relaxes the cluster ceiling so transliterated names (roomaji, pinyin) aren't unfairly penalised.
|
|
29
|
+
- **Tranco-driven brand list refresh** — `scripts/refresh_known_brands.py` + monthly `refresh-known-brands` workflow.
|
|
30
|
+
- **CI quality gates** — ruff lint job, mypy type job, pytest with `--cov-fail-under=70` (cli.py omitted from coverage).
|
|
31
|
+
- **Project hygiene files** — `CHANGELOG.md`, `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `.github/ISSUE_TEMPLATE/*`, `.github/pull_request_template.md`, `release.yml` workflow.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- **Trademark module** — every jurisdiction now resolves to `not_supported` + deeplink (no live API queries). See ADR 0009. Doc drift in `CLAUDE.md`, `docs/architecture.md`, and `docs/guide/usage.md` swept to match.
|
|
36
|
+
- **Skill** — `argument-hint` accepts multiple domains; multi-domain output spec added (comparison table → ranking → top-3 trademark verify checklist → next step).
|
|
37
|
+
|
|
38
|
+
### Fixed
|
|
39
|
+
|
|
40
|
+
- `_de_confuse` previously rewrote ASCII characters into other confusables; now only non-Latin characters are de-confused (preserves Latin SLDs unchanged).
|
|
41
|
+
|
|
42
|
+
### Internal
|
|
43
|
+
|
|
44
|
+
- `basic.normalise(domain) → (domain, sld, tld)` shared helper, replaces 5 duplicated normalisation passes across check modules.
|
|
45
|
+
- Ten check modules now share consistent shapes (`check_<name>(domain) → <Name>Report` returning `issues` + `notes`).
|
|
46
|
+
|
|
47
|
+
## [0.7.2] — 2026-05-08
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
|
|
51
|
+
- Skill multi-domain mode + top-3 trademark verify checklist (9 links instead of 24).
|
|
52
|
+
|
|
53
|
+
## [0.7.0] — 2026-05-08
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- ROADMAP issues #1–#6 all shipped: same-name handle availability, typosquat / brand similarity, trademark deeplinks, multi-language semantics, refreshable TLD risk JSON, LLMO fitness heuristic.
|
|
58
|
+
|
|
59
|
+
## [0.1.0] — 2026-05-08
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Initial public release. `dpf check / basic / history`, scoring engine, GREEN / YELLOW / ORANGE / RED bands.
|