Files
rengine/shared/definitions/relations.py
T
Yogesh OjhaandClaude Opus 5 2ea061e713 feat(targets): a DNS modal that opens, and DNS as a relation
Clicking the DNS cell in the targets list opened the generic target dialog:
there was no DNS modal at all. There is one now, and it renders through the
same `dns-tab` the target page uses, so the records, the type filters, the
provider labels and the refresh are one component in two places.

DNS is also a relation. `dns_record` links two targets on a mail host, a zone
contact, an address or an SPF include - and only when the estate owns the
name. On the four unrelated estates here the only shared DNS values are
Google's MX hosts and an `include:mail.zendesk.com` that briefly linked
Shopify to HackerOne, which is the landlord problem in a new dress: a SaaS
sender is authorised by everyone. A mail host, a zone contact or an include
counts when its registrable domain is a target of the project, so
`mail.zendesk.com` says nothing and `serviceproviders.uber.com` says
everything. Measured: adding ubereats.com links it to uber.com on the SOA
contact alone, past nameservers (UltraDNS) and MX (Google) that say nothing.
An NS record is left to the WHOIS nameserver relation, so a fact appears once,
and an address that cdncheck flagged is not a shared machine.

`is_shared_host` folds the nameserver, shared-edge and mail-provider lists
into one judgement, so `aspmx.l.google.com`, `awsdns-hostmaster.amazon.com`
and `gold.foundationdns.com` are all recognised as rented.

The DNS and BGP modals carry a Shared with block through one
`related-targets` component: the other targets and the evidence, filtered to
the kinds that modal is about.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYop31s6BqDUt4TBs5mbwa
2026-09-12 23:21:11 +05:30

55 lines
1.8 KiB
Python

"""How two targets in one project can be shown to belong together."""
from __future__ import annotations
from enum import StrEnum
class TargetRelation(StrEnum):
CERTIFICATE = "certificate"
REGISTRANT = "registrant_name"
NETWORK = "network"
NAMESERVER = "nameserver"
DNS_RECORD = "dns_record"
NETWORK_CIDR = "network_cidr"
FAVICON = "favicon"
# strongest first
RELATION_ORDER: tuple[str, ...] = (
TargetRelation.CERTIFICATE.value,
TargetRelation.REGISTRANT.value,
TargetRelation.NETWORK.value,
TargetRelation.NAMESERVER.value,
TargetRelation.DNS_RECORD.value,
TargetRelation.NETWORK_CIDR.value,
TargetRelation.FAVICON.value,
)
RELATION_LABELS: dict[str, str] = {
TargetRelation.CERTIFICATE.value: "Certificate",
TargetRelation.REGISTRANT.value: "Registrant",
TargetRelation.NETWORK.value: "Network",
TargetRelation.NAMESERVER.value: "Nameserver",
TargetRelation.DNS_RECORD.value: "DNS record",
TargetRelation.NETWORK_CIDR.value: "Network block",
TargetRelation.FAVICON.value: "Favicon",
}
RELATION_HELP: dict[str, str] = {
TargetRelation.CERTIFICATE.value: "One certificate names both targets",
TargetRelation.REGISTRANT.value: "Registered to the same name",
TargetRelation.NETWORK.value: "Addresses in a network the organisation runs",
TargetRelation.NAMESERVER.value: "Answered by the same nameserver",
TargetRelation.DNS_RECORD.value: "A DNS record nobody rents, on both targets",
TargetRelation.NETWORK_CIDR.value: "Inside the same registered network block",
TargetRelation.FAVICON.value: "Serving the same favicon",
}
MAX_RELATED_TARGETS = 50
MAX_RELATION_EVIDENCE = 8
MAX_SAN_ROWS = 5000
MAX_COVERED_PROGRAMS = 20
# a favicon on more estates than this is a framework's, not an owner's
FAVICON_MAX_TARGETS = 4