Corpus and Priors¶
TrustSight can use an AUR-derived seed for URL, maintainer, and dependency history. These corpus/state features are optional context signals, not a requirement for structural detection: without a seed or local history, the tool runs cold, keeps the relevant novelty and dependency signals silent or downweights them, and reports the resulting limitation where applicable. This avoids treating every first-seen value as suspicious while preserving useful context for operators who choose to import or accumulate it. Source buckets are separate: they are static configured domain lists, not corpus-derived frequency classifications.
How the snapshot is built¶
- Mirror pull: a full AUR mirror is pulled via rsync over the AUR archive (approximately 89k packages).
- Diff extraction: PKGBUILDs and related files (
.install,.patch, systemd service files) are extracted for every package. - Observation extraction: source URLs, maintainer identities, and dependency names are extracted and normalized for the seed's novelty and dependency history.
- Seed packaging: the resulting observations are hashed where required and packaged as a signed seed.
The snapshot is pinned via corpus.lock for reproducible benchmarking. This means a given version of the corpus produces identical results regardless of when or where it is run. When regeneration produces a new snapshot, the lock file is updated and the old snapshot is archived for reproducibility.
Static source buckets¶
Source buckets are intentionally not trained from corpus frequency. The
classifier checks static configured lists for raw-hosting, trusted-forge, and
official domains, then falls back to unknown; a targeted homograph check can
produce homograph_attack. This makes bucket assignment reproducible from the
configuration and prevents a domain becoming trusted merely by appearing often.
Examples¶
- The homograph check detects a mixed-script label that normalizes to a configured popular domain. It does not depend on how often the candidate appears in the corpus.
- A domain absent from every configured list is
unknown, whether it is new or long-established. Operators can review and deliberately classify domains through configuration.
How homograph detection works¶
Homograph detection compares each new domain against configured popular domains
using script-mixing and confusable-character normalization. A domain is
homograph_attack only when it is mixed-script and normalizes to a configured
target; there is no corpus-frequency threshold.
The detection is conservative. A domain that looks like github.com but uses a Cyrillic g is caught. A domain that looks like github.com but is a legitimate mirror on a different TLD is flagged as unknown, not homograph, unless visual similarity is high enough to trigger the heuristic.
This intentionally avoids treating every internationalized domain as hostile: single-script labels and configured compatible script combinations do not match.
How static buckets work on cold runs¶
Even on a cold first run (when novelty signals are inactive, see Cold Start and Maturity), URL classification works because the domain lists are static:
trusted_forge: configured forge domains. Neutral (weight 0) and reported as the declared-practice findingP007, never credited.official: configured upstream domains. Neutral modifier.raw_hosting: configured content-delivery domains. Positive modifier.unknown: everything else. Positive modifier.homograph_attack: a mixed-script confusable of a configured popular domain. Highest positive modifier.
A URL that resolves to an unknown or homograph_attack bucket triggers a
signal regardless of whether the local DB has ever seen this specific URL
before. Cold-run behavior comes from the static classifier, not local
observation history.
This is critical for the first-run use case. A user running trustsight review
for the first time gets the same deterministic bucket classification without
needing prior observations.
Local novelty and seeded global history¶
The composition the naive design misses: a URL that is first-seen in this package but known to the seeded global history is less interesting than one that is first-seen anywhere in the local or seeded observation store.
TrustSight tracks both:
| Signal | Condition | Full weight | Why the weight differs |
|---|---|---|---|
url_first_globally |
URL never seen in the local or seeded observation store | 10 | A globally novel URL is the strongest URL-novelty signal. |
url_first_in_package |
URL never seen in this specific package, but seen elsewhere | 5 | A per-package novel URL is weaker. It might mean the package is new to your observation set, not that the URL is unusual. |
The globally-first signal carries more weight because it is more specific. The per-package-first signal is weaker because it may just mean the package has not been observed before in the local database.
The composition in practice¶
A popular GitHub repository like https://github.com/torvalds/linux can be
known to the imported seed and therefore not fire url_first_globally. It
might fire url_first_in_package for a specific package new to the local
database; that signal weighs 5 at full maturity.
A package that adds a globally novel URL on an unknown domain can fire
url_first_globally (10 at full maturity) and the unknown source-bucket
modifier (20), for a combined contribution of 30. The two signals are
independent Tier B and Tier C evidence.
Seed coverage¶
The seed is a point-in-time observation baseline, not a source-bucket list. New URLs not present in it remain novel until imported or locally observed; their bucket remains the result of the static domain classifier.
The live corpus: cycles, the adoption feed, and watch mode¶
The bundled snapshot is an optional prior. trustsight full-aur is an optional
operator-run feature for installations that want to keep local corpus context
current; it is not required for ordinary package review, and it does more than
refresh priors.
Each run is one cycle: fetch the AUR metadata dump, diff it against the stored snapshot, analyse the PKGBUILDs of everything added or changed, then run the Class D corpus sweep across the whole delta. The sweep is the part that cannot be done per package. It asks who adopted ten packages this week, which unrelated packages started sharing a source repository, and whether the corpus-wide introduction rate jumped; it reports one finding per cluster with the members attached rather than repeating itself once per member. These are campaign-shape observations about coordinated timing, ownership, and shared metadata. They do not reveal, download, or inspect an upstream registry payload: if a build step resolves a package from npm, PyPI, or another registry at build time, the bytes the registry serves remain outside TrustSight's visibility.
Every cycle is also written to the adoption feed, a row per package per
cycle in cycle_events recording whether it was added, modified or removed and
who owned it. That feed is the baseline H073 measures a rate deviation against
and the history H058 compares a maintainer's activity to. It is why the first
cycle of a fresh install can never produce a Class D finding: there is nothing
to deviate from, and that silence is enforced by a calibration gate.
trustsight full-aur --watch repeats the cycle on an interval. The one thing
it adds beyond repetition is memory: an announced cluster is recorded in
alert_state by package and rule, so a cluster is reported the first time it
is seen and counted thereafter. Without that, a maintainer who adopted forty
packages overnight would be re-announced on every cycle until the metadata
changed again, and an operator learns to ignore a feed that repeats itself.
See the CLI reference for the flags and the Class D rules for what the sweep can find.