ApertoID reference implementation — Layer 1: record parser
Python reference parser for ApertoID DNS TXT records, implemented strictly
from draft-ferro-dnsop-apertoid-00,
Section 5 (Record Syntax).
This is Layer 1 only: it parses and validates a single record string. It
does not do DNS lookups, include= delegation resolution, exp expiry
checks against wall-clock time, URL matching, or Ed25519 signature
verification. Those belong to the Section 11 verification algorithm (Layer 2)
and are intentionally not built yet.
Method
The parser is implemented from the spec, not from intuition. Where the Section 5.1 ABNF and the surrounding prose disagree, the parser follows the ABNF as literally written and emits a diagnostic pointing at the contradiction, rather than silently reconciling it. Surfacing these contradictions is a goal — see FINDINGS.md.
Layout
src/apertoid/parser.py the parser (parse_record, validate_selector)
tests/test_draft_examples.py every example record in the draft
tests/test_rules.py targeted MUST-rule / value-format tests
spec/ the draft text this was built from
FINDINGS.md 12 spec ambiguities/contradictions found
Usage
from apertoid import parse_record
rec = parse_record("v=APERTOID1; p=reject; rua=mailto:apertoid@example.com")
print(rec.record_type) # RecordType.POLICY
print(rec.is_valid) # True
print(rec.get("p")) # "reject"
for d in rec.diagnostics:
print(d) # [severity:code] message
parse_record never raises on malformed input; it returns a ParsedRecord
whose .errors / .warnings / .is_valid describe the outcome. This mirrors
the spec's permerror posture (malformed syntax is a result, not a crash).
Running
python3 -m venv .venv && .venv/bin/pip install pytest
.venv/bin/python -m pytest -q # full suite (47 tests)
.venv/bin/python tests/test_draft_examples.py # human-readable draft-example table
Draft-example results
All 13 example records across §6.2, §7.2, §8, §10.1, §10.2, and Appendix A.1/A.2/A.3 parse as the spec text dictates. Notably, the parser reports that:
- Every
pk=andprev=value in the draft is invalid — wrong length and/or SPKI-wrapped rather than the raw 32-byte key §9.1 requires (FINDINGS F1, F2). - Both
include=delegation targets in the draft fail thedomain-nameABNF, because_apertoidstarts with an underscore, whichlabelforbids (FINDINGS F9). - The revocation record (
v=APERTOID1; status=revoked) has neitherurlnorinclude, contradicting §8's "MUST contain either" (FINDINGS F5).
The policy records (§6.2, A.1, A.2) are the only fully conforming examples in the draft.
Status
Layer 1 complete. Not committed. Layers 2+ (verification, delegation, signing) not started.
Metadata
Release files for apertoid 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| apertoid-0.1.0.tar.gz | 25.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| apertoid-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 39.8 kB
Release files / apertoid-0.1.0.tar.gz
| Download URL | apertoid-0.1.0.tar.gz |
|---|---|
| Size | 25.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35b1e3f48328e7cc37b896d1d2b53c89c419016ad990b387496f96db24dff1e5
|
|
BLAKE2b-256 checksum How to use checksums |
2db3a7760d5859a92d4230fd545f3e012d52dedb2630eccd40c29a65ca1c76cf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|
Release files / apertoid-0.1.0-py3-none-any.whl
| Download URL | apertoid-0.1.0-py3-none-any.whl |
|---|---|
| Size | 14.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
835e1b5ac366b01094c70dc99d32bb673731216cd741136d648c507d66d46404
|
|
BLAKE2b-256 checksum How to use checksums |
33e1841e628ef95771a2cbf9fb61bee98540cdc0b943169c0dd5765a02a87db5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.6
|