# This script creates a complete repository tree with policy packs, bindings, gates,
# SHACL shapes, Docker Compose + Kubernetes manifests for adapters, and a Grafana dashboard.
# It then zips the repo for download and prints a tree for quick inspection.
import os, json, textwrap, zipfile, pathlib, datetime, yaml
base = "/mnt/data/ucls-dns-packs"
os.makedirs(base, exist_ok=True)
# Helper to write files
def write(path, content):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
f.write(content.strip() + "\n")
# ---------- Contexts & Shapes ----------
contexts_dir = os.path.join(base, "schemas", "contexts")
shapes_dir = os.path.join(base, "schemas", "shacl")
os.makedirs(contexts_dir, exist_ok=True)
os.makedirs(shapes_dir, exist_ok=True)
context_core = {
"@context": {
"ucls": "https://ucls.org/terms#",
"PolicyPack": "ucls:PolicyPack",
"PolicyBinding": "ucls:PolicyBinding",
"appliesTo": {"@id":"ucls:appliesTo","@type":"@id"},
"requires": {"@id":"ucls:requires","@type":"@id"},
"enforces": {"@id":"ucls:enforces"},
"controls": {"@id":"ucls:controls"},
"metrics": {"@id":"ucls:metrics"},
"overrides": {"@id":"ucls:overrides","@type":"@id"},
"governedBy": {"@id":"ucls:governedBy","@type":"@id"},
"policyVersion": "ucls:policyVersion",
"packId": "ucls:packId",
"targetKind": "ucls:targetKind",
"selector": "ucls:selector",
"precedence": "ucls:precedence",
"DomainName": "ucls:DomainName",
"TLD": "ucls:TLD",
"Label": "ucls:Label",
"DNSAnchor": "ucls:DNSAnchor",
"EmailSecurity": "ucls:EmailSecurity",
"HTTPSPolicy": "ucls:HTTPSPolicy"
}
}
write(os.path.join(contexts_dir, "ucls-dns-context.jsonld"), json.dumps(context_core, indent=2))
# SHACL shapes
DomainNameShape = """
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix ucls: <https://ucls.org/terms#> .
ucls:DomainNameShape a sh:NodeShape ;
sh:targetClass ucls:DomainName ;
sh:property [
sh:path ucls:components ;
sh:minCount 1
] ;
sh:property [
sh:path ucls:components ;
sh:node [
sh:property [ sh:path ucls:punycode ; sh:datatype xsd:string ; sh:minCount 1 ] ;
sh:property [ sh:path ucls:unicode ; sh:datatype xsd:string ; sh:minCount 1 ] ;
sh:property [ sh:path ucls:tld ; sh:minCount 1 ]
]
] ;
sh:property [
sh:path ucls:anchor ;
sh:minCount 1 ;
sh:node ucls:DNSSECAnchorShape
] .
""".strip()
DNSSECAnchorShape = """
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ucls: <https://ucls.org/terms#> .
ucls:DNSSECAnchorShape a sh:NodeShape ;
sh:targetClass ucls:DNSAnchor ;
sh:property [ sh:path ucls:dsRecord ; sh:minCount 1 ] ;
sh:property [ sh:path ucls:dnskey ; sh:minCount 1 ] ;
sh:property [ sh:path ucls:rrsig ; sh:minCount 1 ] .
""".strip()
EmailSecurityShape = """
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix ucls: <https://ucls.org/terms#> .
ucls:EmailSecurityShape a sh:NodeShape ;
sh:targetClass ucls:EmailSecurity ;
sh:property [ sh:path ucls:spf ; sh:pattern "^v=spf1\\s" ] ;
sh:property [ sh:path ucls:dkim ; sh:minCount 1 ] ;
sh:property [ sh:path ucls:dmarc ; sh:pattern "v=DMARC1;" ] .
""".strip()
HTTPSPolicyShape = """
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ucls: <https://ucls.org/terms#> .
ucls:HTTPSPolicyShape a sh:NodeShape ;
sh:targetClass ucls:HTTPSPolicy ;
sh:property [ sh:path ucls:hsts ; sh:pattern "max-age=" ] ;
sh:property [ sh:path ucls:caa ; sh:minCount 1 ] .
""".strip()
TLDShape = """
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix ucls: <https://ucls.org/terms#> .
ucls:TLDShape a sh:NodeShape ;
sh:targetClass ucls:TLD ;
sh:property [ sh:path ucls:anchor ; sh:minCount 1 ; sh:node ucls:DNSSECAnchorShape ] .
""".strip()
write(os.path.join(shapes_dir, "DomainNameShape.ttl"), DomainNameShape)
write(os.path.join(shapes_dir, "DNSSECAnchorShape.ttl"), DNSSECAnchorShape)
write(os.path.join(shapes_dir, "EmailSecurityShape.ttl"), EmailSecurityShape)
write(os.path.join(shapes_dir, "HTTPSPolicyShape.ttl"), HTTPSPolicyShape)
write(os.path.join(shapes_dir, "TLDShape.ttl"), TLDShape)
# ---------- Packs ----------
packs_dir = os.path.join(base, "packs")
os.makedirs(packs_dir, exist_ok=True)
def dump_yaml(path, obj):
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
yaml.safe_dump(obj, f, sort_keys=False)
packs = {
"ICANN-Core-1.0.0.yaml": {
"packId": "ICANN-Core",
"policyVersion": "1.0.0",
"appliesTo": [{"targetKind":"DomainName"},{"targetKind":"TLD"}],
"requires": [],
"enforces": {
"governance": [
{"source":"ICANN-Bylaws"},
{"source":"RAA"},
{"source":"Base-Registry-Agreement"},
{"source":"UDRP"},
{"source":"URS"}
],
"operational": [
"RDAP availability >= 99.9%",
"Daily registry data escrow",
"Zone file access logging & hashing"
]
},
"controls": [
{"name":"SunriseClaims","rule":"Enforce TMCH sunrise/claims prior to GA"},
{"name":"NameCollisionBlock","rule":"Block collision strings; PRaaS exception only"},
{"name":"DNSSECRootChain","rule":"DS/DNSKEY continuity required"},
{"name":"RegistrarLock","rule":"Require registry lock for hi-risk labels"}
],
"metrics": [
{"key":"udrp_turnaround_days","target":20},
{"key":"rdap_uptime","target":">=99.9%"}
]
},
"TLD-Health-1.0.0.yaml": {
"packId":"TLD-Health",
"policyVersion":"1.0.0",
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline","IDN-Confusables"],
"appliesTo":[{"targetKind":"DomainName","tld":".health"}],
"enforces":{
"eligibility":["Healthcare org VC","Regulator VC or accreditation"],
"security":["HSTS: preload-required","DMARC: p=reject within 30 days","DNSSEC: mandatory"],
"content":["Prohibit misleading medical claims (PRaaS exception queue)"]
},
"controls":[
{"name":"MedicalTermReserve","rule":"Reserve critical terms; PRaaS approval to release"},
{"name":"SafeEmail","rule":"MTA-STS enforce + TLS-RPT monitored"}
],
"metrics":[
{"key":"dmarc_pass_rate","target":">=98%"},
{"key":"dnssec_validation_rate","target":">=99.9%"}
]
},
"TLD-Gov-1.0.0.yaml": {
"packId":"TLD-Gov",
"policyVersion":"1.0.0",
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline"],
"appliesTo":[{"targetKind":"DomainName","tld":".gov"}],
"enforces":{
"delegation":["Government VC with jurisdiction scope"],
"security":["HSTS: preload-required","CAA: locked to approved CAs","DNSSEC: mandatory"],
"provenance":["ACaaS: VC-based subdomain delegation"]
},
"controls":[{"name":"SubdomainDelegationRegister","rule":"All subdelegations recorded with VC proof"}],
"metrics":[{"key":"unauthorized_cert_issuance","target":"0"}]
},
"TLD-Edu-1.0.0.yaml": {
"packId":"TLD-Edu",
"policyVersion":"1.0.0",
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline","IDN-Confusables"],
"appliesTo":[{"targetKind":"DomainName","tld":".edu"}],
"enforces":{
"eligibility":["Accredited institution VC"],
"email":["DMARC: p=reject or staged plan <= 30 days"],
"research":["DOI/ORCID linkage recommended for scholarly subdomains"]
},
"metrics":[{"key":"student_phish_rate","target":"<=0.1%"}]
},
"TLD-Mil-1.0.0.yaml": {
"packId":"TLD-Mil",
"policyVersion":"1.0.0",
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline"],
"appliesTo":[{"targetKind":"DomainName","tld":".mil"}],
"enforces":{
"crypto":["DNSSEC: mandatory + rollover SOPs","DANE/TLSA: required for MX/SMTP"],
"mail":["DMARC: p=reject","ARC alignment"],
"ops":["Registry lock + out-of-band revocation protocol"]
},
"metrics":[{"key":"time_to_revoke_compromise","target":"<=1h (P95)"}]
},
"TLD-Brand-Starter-1.0.0.yaml": {
"packId":"TLD-Brand-Starter",
"policyVersion":"1.0.0",
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline","Phishing-Defense"],
"appliesTo":[{"targetKind":"DomainName","tld":".brand"}],
"enforces":{
"brand":["IDN variant bundles reserved","CAA: restrict to brand-approved CAs"],
"posture":["DMARC: p=reject","BIMI: allowed with trademark VC"]
},
"metrics":[{"key":"typosquat_surface","target":"decreasing week-over-week"}]
},
"TLD-ccTLD-Template-1.0.0.yaml": {
"packId":"TLD-ccTLD-Template",
"policyVersion":"1.0.0",
"parameters":["cc","registry","idnTableURI","reservedListURI"],
"requires":["ICANN-Core","Security-Baseline","Email-Auth-Baseline","IDN-Confusables"],
"appliesTo":[{"targetKind":"DomainName","tld":".{cc}"}],
"enforces":{
"idn":["Use idnTableURI; variant mapping required"],
"reserved":["reservedListURI enforced; public-interest override via PRaaS"]
}
},
"Security-Baseline-1.0.0.yaml": {
"packId":"Security-Baseline",
"policyVersion":"1.0.0",
"appliesTo":[{"targetKind":"DomainName"}],
"enforces":{
"dnssec":"required-for-critical-sectors",
"tls":["CT-logged certificates 100%","HSTS recommended; preload for high-risk sectors"],
"caa":"0 issue one-of [letsencrypt.org, digicert.com, entrust.net]"
},
"metrics":[{"key":"ct_gap_seconds","target":"<=300"}]
},
"Email-Auth-Baseline-1.0.0.yaml": {
"packId":"Email-Auth-Baseline",
"policyVersion":"1.0.0",
"appliesTo":[{"targetKind":"DomainName"}],
"enforces":{
"spf":"v=spf1 … -all",
"dkim":">=1 selector, 2048-bit",
"dmarc":"p=reject (or staged plan <=30 days)",
"mta-sts":"mode=enforce",
"tls-rpt":"required",
"bimi":"optional; requires trademark VC"
},
"metrics":[{"key":"dmarc_pass_rate","target":">=98%"}]
},
"IDN-Confusables-1.0.0.yaml": {
"packId":"IDN-Confusables",
"policyVersion":"1.0.0",
"appliesTo":[{"targetKind":"Label"}],
"enforces":[
"Detect confusables across scripts; block unless in same-entity bundle",
"Script-mixing disallowed except approved locales"
],
"controls":[{"name":"ConfusableBundle","rule":"Bundle variants to a single controller with VC"}],
"metrics":[{"key":"confusable_block_rate","target":">=99%"}]
},
"Phishing-Defense-1.0.0.yaml": {
"packId":"Phishing-Defense",
"policyVersion":"1.0.0",
"requires":["IDN-Confusables","Email-Auth-Baseline"],
"appliesTo":[{"targetKind":"DomainName"}],
"enforces":[
"Monitor homograph registrations across TLDs",
"Auto-open PRaaS case on high-risk near-match",
"Quarantine MX until DMARC reject in place"
],
"metrics":[{"key":"near_match_takedown_ttd","target":"<=24h"}]
}
}
for fname, obj in packs.items():
dump_yaml(os.path.join(packs_dir, fname), obj)
# ---------- Bindings ----------
bindings_dir = os.path.join(base, "bindings")
bindings = {
"bind-baseline-all.json": {
"@type":"PolicyBinding",
"bindingId":"bind:baseline-all",
"selector":{"kind":"DomainName"},
"packs":[
"ICANN-Core@1.0.0",
"Security-Baseline@1.0.0",
"Email-Auth-Baseline@1.0.0",
"IDN-Confusables@1.0.0",
"Phishing-Defense@1.0.0"
],
"precedence":10
},
"bind-tld-health.json": {
"@type":"PolicyBinding",
"bindingId":"bind:tld-health",
"selector":{"kind":"DomainName","tld":".health"},
"packs":["TLD-Health@1.0.0"],
"precedence":50
},
"bind-tld-gov.json": {
"@type":"PolicyBinding",
"bindingId":"bind:tld-gov",
"selector":{"kind":"DomainName","tld":".gov"},
"packs":["TLD-Gov@1.0.0"],
"precedence":50
},
"bind-tld-edu.json": {
"@type":"PolicyBinding",
"bindingId":"bind:tld-edu",
"selector":{"kind":"DomainName","tld":".edu"},
"packs":["TLD-Edu@1.0.0"],
"precedence":50
},
"bind-tld-mil.json": {
"@type":"PolicyBinding",
"bindingId":"bind:tld-mil",
"selector":{"kind":"DomainName","tld":".mil"},
"packs":["TLD-Mil@1.0.0"],
"precedence":50
},
"bind-tld-brand.json": {
"@type":"PolicyBinding",
"bindingId":"bind:tld-brand",
"selector":{"kind":"DomainName","tld":".brand"},
"packs":["TLD-Brand-Starter@1.0.0"],
"precedence":50
},
"bind-risk-critical.json": {
"@type":"PolicyBinding",
"bindingId":"bind:risk-critical",
"selector":{"kind":"DomainName","riskProfile":"critical"},
"packs":["Security-Baseline@1.0.0"],
"precedence":60
}
}
os.makedirs(bindings_dir, exist_ok=True)
for fname, obj in bindings.items():
write(os.path.join(bindings_dir, fname), json.dumps(obj, indent=2))
# ---------- Gates ----------
gates_dir = os.path.join(base, "gates")
gates = {
"gate-domain-core.json": {
"gateId":"gate:domain-core",
"targetKind":"DomainName",
"shapes":[
"ucls:DomainNameShape",
"ucls:EmailSecurityShape",
"ucls:HTTPSPolicyShape"
],
"packs":[
"ICANN-Core@1.0.0",
"Security-Baseline@1.0.0",
"Email-Auth-Baseline@1.0.0",
"IDN-Confusables@1.0.0"
],
"failureMode":"fail-closed",
"onFail":[{"action":"block-release"},{"action":"open-praas-case","severity":"high"}]
},
"gate-tld-core.json": {
"gateId":"gate:tld-core",
"targetKind":"TLD",
"shapes":["ucls:TLDShape","ucls:DNSSECAnchorShape"],
"packs":["ICANN-Core@1.0.0"],
"failureMode":"fail-closed"
}
}
os.makedirs(gates_dir, exist_ok=True)
for fname, obj in gates.items():
write(os.path.join(gates_dir, fname), json.dumps(obj, indent=2))
# ---------- Adapters: Docker Compose & K8s ----------
adapters_dir = os.path.join(base, "adapters")
compose_path = os.path.join(adapters_dir, "docker-compose.yml")
k8s_dir = os.path.join(adapters_dir, "k8s")
configs_dir = os.path.join(adapters_dir, "configs")
os.makedirs(k8s_dir, exist_ok=True)
os.makedirs(configs_dir, exist_ok=True)
docker_compose = """
version: "3.9"
services:
bus:
image: docker.redpanda.com/redpandadata/redpanda:latest
command: ["redpanda","start","--overprovisioned","--smp","1","--reserve-memory","0M"]
ports: ["9092:9092"]
rdap-ingestor:
image: ghcr.io/ucls/rdap-ingestor:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
volumes: ["./configs/rdap-config.yaml:/app/config.yaml:ro"]
depends_on: ["bus"]
doh-prober:
image: ghcr.io/ucls/doh-prober:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
ct-monitor:
image: ghcr.io/ucls/ct-monitor:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
volumes: ["./configs/ct-logs.yaml:/app/ct-logs.yaml:ro"]
dmarc-parser:
image: ghcr.io/ucls/dmarc-parser:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
mta-sts-parser:
image: ghcr.io/ucls/mta-sts-parser:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
tls-rpt-parser:
image: ghcr.io/ucls/tls-rpt-parser:latest
environment:
- UCLS_API_BASE=${UCLS_API_BASE:-http://ucls:8080}
- BUS_BROKER=bus:9092
networks:
default: {}
""".strip()
write(compose_path, docker_compose)
rdap_config = """
rdap:
registries:
- base: https://rdap.verisign.com/com/v1
- base: https://rdap.donuts.co/rdap
- base: https://rdap.publicinterestregistry.net/rdap
interval: 86400 # seconds
""".strip()
write(os.path.join(configs_dir, "rdap-config.yaml"), rdap_config)
ct_logs = """
logs:
- https://ct.googleapis.com/argon2024
- https://oak.ct.letsencrypt.org/2024
- https://ct.cloudflare.com/logs/nimbus2024
""".strip()
write(os.path.join(configs_dir, "ct-logs.yaml"), ct_logs)
def k8s_deploy(name, image, extra_env=None, volume=None, cm=None):
env = [{"name":"UCLS_API_BASE","value":"http://ucls:8080"},
{"name":"BUS_BROKER","value":"bus-kafka:9092"}]
if extra_env:
env.extend(extra_env)
spec = {
"apiVersion":"apps/v1",
"kind":"Deployment",
"metadata":{"name":name},
"spec":{
"replicas":1,
"selector":{"matchLabels":{"app":name}},
"template":{
"metadata":{"labels":{"app":name}},
"spec":{
"containers":[{
"name":name,"image":image,
"env":env
}]
}
}
}
}
if volume and cm:
spec["spec"]["template"]["spec"]["volumes"] = [{
"name":"config","configMap":{"name":cm}
}]
spec["spec"]["template"]["spec"]["containers"][0]["volumeMounts"] = [{
"name":"config","mountPath":"/app","readOnly":True
}]
return spec
def k8s_cm(name, data):
return {
"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":name},
"data": data
}
resources = [
("rdap-ingestor", "ghcr.io/ucls/rdap-ingestor:latest", None, True, "rdap-config-cm", {"config.yaml": rdap_config}),
("doh-prober", "ghcr.io/ucls/doh-prober:latest", None, False, None, None),
("ct-monitor", "ghcr.io/ucls/ct-monitor:latest", None, True, "ct-logs-cm", {"ct-logs.yaml": ct_logs}),
("dmarc-parser", "ghcr.io/ucls/dmarc-parser:latest", None, False, None, None),
("mta-sts-parser", "ghcr.io/ucls/mta-sts-parser:latest", None, False, None, None),
("tls-rpt-parser", "ghcr.io/ucls/tls-rpt-parser:latest", None, False, None, None),
]
for name, image, extra_env, has_cm, cm_name, cm_data in resources:
if has_cm and cm_name and cm_data:
write(os.path.join(k8s_dir, f"{cm_name}.yaml"), yaml.safe_dump(k8s_cm(cm_name, cm_data), sort_keys=False))
write(os.path.join(k8s_dir, f"{name}-deployment.yaml"), yaml.safe_dump(k8s_deploy(name, image, extra_env, True, cm_name), sort_keys=False))
else:
write(os.path.join(k8s_dir, f"{name}-deployment.yaml"), yaml.safe_dump(k8s_deploy(name, image), sort_keys=False))
# ---------- CI: tests + workflow ----------
ci_dir = os.path.join(base, "ci")
ghwf_dir = os.path.join(base, ".github", "workflows")
os.makedirs(ci_dir, exist_ok=True)
os.makedirs(ghwf_dir, exist_ok=True)
policy_tests = """
# Minimal policy tests: validate YAML structure & required keys.
tests:
- name: packs-parse
run: python ci/test_packs.py
- name: bindings-parse
run: python ci/test_bindings.py
- name: gates-parse
run: python ci/test_gates.py
""".strip()
write(os.path.join(ci_dir, "tests.yaml"), policy_tests)
test_packs_py = r"""
import os, sys, yaml, json
root = os.path.dirname(os.path.dirname(__file__))
packs_dir = os.path.join(root, "packs")
required = ["packId","policyVersion","appliesTo"]
for f in os.listdir(packs_dir):
if not f.endswith((".yaml",".yml")):
continue
with open(os.path.join(packs_dir,f), "r", encoding="utf-8") as fh:
data = yaml.safe_load(fh)
for k in required:
assert k in data, f"{f}: missing {k}"
print("OK: packs")
"""
write(os.path.join(ci_dir, "test_packs.py"), test_packs_py)
test_bindings_py = r"""
import os, json, sys
root = os.path.dirname(os.path.dirname(__file__))
bdir = os.path.join(root, "bindings")
for f in os.listdir(bdir):
if not f.endswith(".json"):
continue
with open(os.path.join(bdir,f), "r", encoding="utf-8") as fh:
data = json.load(fh)
assert data.get("@type") == "PolicyBinding", f"{f}: invalid type"
assert "selector" in data and "packs" in data, f"{f}: missing keys"
print("OK: bindings")
"""
write(os.path.join(ci_dir, "test_bindings.py"), test_bindings_py)
test_gates_py = r"""
import os, json, sys
root = os.path.dirname(os.path.dirname(__file__))
gdir = os.path.join(root, "gates")
for f in os.listdir(gdir):
if not f.endswith(".json"):
continue
with open(os.path.join(gdir,f), "r", encoding="utf-8") as fh:
data = json.load(fh)
for k in ["gateId","targetKind","shapes","packs","failureMode"]:
assert k in data, f"{f}: missing {k}"
print("OK: gates")
"""
write(os.path.join(ci_dir, "test_gates.py"), test_gates_py)
ghwf = """
name: UCLS DNS Packs CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install deps
run: pip install pyyaml
- name: Run tests
run: |
python ci/test_packs.py
python ci/test_bindings.py
python ci/test_gates.py
""".strip()
write(os.path.join(ghwf_dir, "ci.yml"), ghwf)
write(os.path.join(base, "README.md"), textwrap.dedent(f"""
# ucls-dns-packs
Policy packs, bindings, gates, shapes, and adapter manifests for DNS/TLD control inside UCLS.
## Layout
- `packs/` — policy packs (YAML)
- `bindings/` — policy bindings (JSON-LD-ish JSON)
- `gates/` — validation gates
- `schemas/contexts` — JSON-LD context
- `schemas/shacl` — SHACL shapes
- `adapters/` — Docker Compose + Kubernetes manifests + configs
- `ci/` — minimal tests; run with `python ci/test_*.py`
- `.github/workflows/ci.yml` — GitHub Actions
## Quickstart
1. Load packs into OaaS, sign via ProvAaaS, release via VaaS.
2. POST bindings to GaaS, create gates in ValaaS.
3. Deploy adapters (Compose or K8s). Point them at your UCLS API and bus.
4. Import Grafana dashboard from `dashboards/ucls-dns-posture.json`.
""").strip())
# ---------- Grafana Dashboard ----------
dash_dir = os.path.join(base, "dashboards")
os.makedirs(dash_dir, exist_ok=True)
grafana = {
"annotations": {"list":[]},
"editable": True,
"gnetId": None,
"graphTooltip": 0,
"id": None,
"links": [],
"panels": [
# Posture Score Heatmap
{
"type": "heatmap",
"title": "Domain Posture Heatmap",
"id": 1,
"datasource": {"type":"postgres","uid":"POSTGRES_DS"},
"targets": [{
"format": "table",
"rawSql": textwrap.dedent("""
SELECT tld AS metric, domain AS value, AVG(score) AS time
FROM domain_posture
WHERE $__timeFilter(ts)
GROUP BY tld, domain
""").strip(),
"refId": "A"
}],
"options": {"legend":{"show":True}},
"gridPos":{"h":10,"w":24,"x":0,"y":0}
},
# Confusable Radar (table for simplicity with high scores)
{
"type": "table",
"title": "Confusable Radar (Active Threats)",
"id": 2,
"datasource": {"type":"postgres","uid":"POSTGRES_DS"},
"targets": [{
"format":"table",
"rawSql": textwrap.dedent("""
SELECT domain_a, domain_b, score, status, first_seen
FROM confusable_edges
WHERE status IN ('new','open') AND score >= 0.85
ORDER BY score DESC
LIMIT 100
""").strip(),
"refId":"A"
}],
"gridPos":{"h":9,"w":24,"x":0,"y":10},
"options":{"showHeader":True}
},
# Dispute Queue (UDRP/URS)
{
"type":"table",
"title":"Dispute Queue (UDRP/URS)",
"id":3,
"datasource":{"type":"postgres","uid":"POSTGRES_DS"},
"targets":[{
"format":"table",
"rawSql": textwrap.dedent("""
SELECT case_id, domain, type, status,
DATE_PART('day', now() - opened_at) AS age_days,
sla_deadline
FROM governance_cases
WHERE status IN ('open','pending')
ORDER BY sla_deadline ASC
""").strip(),
"refId":"A"
}],
"gridPos":{"h":9,"w":24,"x":0,"y":19}
}
],
"refresh": "30s",
"schemaVersion": 38,
"style": "dark",
"tags": ["ucls","dns","policy"],
"templating": {
"list": [
{
"name": "ds",
"type": "datasource",
"query": "postgres",
"refresh": 1,
"current": {"text":"POSTGRES_DS","value":"POSTGRES_DS"},
"label": "Postgres DS (set UID)"
}
]
},
"time": {"from": "now-24h","to": "now"},
"timezone": "browser",
"title": "UCLS DNS Posture & Governance",
"version": 1
}
write(os.path.join(dash_dir, "ucls-dns-posture.json"), json.dumps(grafana, indent=2))
# ---------- Zip the repo ----------
zip_path = "/mnt/data/ucls-dns-packs.zip"
with zipfile.ZipFile(zip_path, "w", zipfile.ZIP_DEFLATED) as zf:
for folder, _, files in os.walk(base):
for f in files:
ap = os.path.join(folder, f)
zf.write(ap, os.path.relpath(ap, os.path.dirname(base)))
# Produce a readable tree listing
def tree(path):
result = []
for root, dirs, files in os.walk(path):
level = root.replace(path, '').count(os.sep)
indent = ' ' * level
result.append(f"{indent}{os.path.basename(root)}/")
for f in sorted(files):
result.append(f"{indent} {f}")
return "\n".join(result)
print(tree(base))
STDOUT/STDERR
ucls-dns-packs/
README.md
schemas/
contexts/
ucls-dns-context.jsonld
shacl/
DNSSECAnchorShape.ttl
DomainNameShape.ttl
EmailSecurityShape.ttl
HTTPSPolicyShape.ttl
TLDShape.ttl
packs/
Email-Auth-Baseline-1.0.0.yaml
ICANN-Core-1.0.0.yaml
IDN-Confusables-1.0.0.yaml
Phishing-Defense-1.0.0.yaml
Security-Baseline-1.0.0.yaml
TLD-Brand-Starter-1.0.0.yaml
TLD-Edu-1.0.0.yaml
TLD-Gov-1.0.0.yaml
TLD-Health-1.0.0.yaml
TLD-Mil-1.0.0.yaml
TLD-ccTLD-Template-1.0.0.yaml
bindings/
bind-baseline-all.json
bind-risk-critical.json
bind-tld-brand.json
bind-tld-edu.json
bind-tld-gov.json
bind-tld-health.json
bind-tld-mil.json
gates/
gate-domain-core.json
gate-tld-core.json
adapters/
docker-compose.yml
k8s/
ct-logs-cm.yaml
ct-monitor-deployment.yaml
dmarc-parser-deployment.yaml
doh-prober-deployment.yaml
mta-sts-parser-deployment.yaml
rdap-config-cm.yaml
rdap-ingestor-deployment.yaml
tls-rpt-parser-deployment.yaml
configs/
ct-logs.yaml
rdap-config.yaml
ci/
test_bindings.py
test_gates.py
test_packs.py
tests.yaml
.github/
workflows/
ci.yml
dashboards/
ucls-dns-posture.json
- Download the repo as a zip
- Or browse the generated files under
/mnt/data/ucls-dns-packs/in this workspace - The Grafana dashboard JSON is included at
dashboards/ucls-dns-posture.jsoninside the repo
What’s inside (high-level)
packs/— ICANN-Core + sector/TLD packs (.health,.gov,.edu,.mil,.brand,ccTLDtemplate) and Security/Email/IDN/Phishing baselines.bindings/— selectors that attach packs by TLD and risk.gates/— ValaaS gate configs forDomainNameandTLD.schemas/contexts+schemas/shacl— JSON-LD context and SHACL shapes.adapters/docker-compose.yml— Redpanda bus + RDAP, DoH, CT, DMARC, MTA-STS, TLS-RPT services.adapters/k8s/*.yaml— K8s Deployments + ConfigMaps (ready tokubectl apply -f).dashboards/ucls-dns-posture.json— Grafana with: Posture Heatmap, Confusable Radar, Dispute Queue.ci/+.github/workflows/ci.yml— minimal parsers/tests to keep the tree honest.
Hook-up notes
- Set your UCLS endpoint:
UCLS_API_BASEenv in compose/K8s. - Kafka/Redpanda broker assumed at
bus:9092(compose) orbus-kafka:9092(K8s example). - Grafana dashboard expects a Postgres datasource UID
POSTGRES_DS(rename if needed). Tables assumed:domain_posture(domain, ts, tld, score, …)confusable_edges(domain_a, domain_b, score, status, first_seen, …)governance_cases(case_id, domain, type, opened_at, status, sla_deadline, …)
If you want me to tailor this to your exact infra (e.g., NATS instead of Kafka, ClickHouse instead of Postgres, secrets managers, or your org’s image names), say the word and I’ll cut a variant.
Key terms in plain language
Open a term for a concise explanation of language used on this page.
API
An application programming interface is a defined way for software systems to exchange data or request functions from one another.
Cybersecurity
The practices and controls used to protect identities, devices, networks, applications, and data from unauthorized access, disruption, or manipulation.
Zero Trust
A security model that does not automatically trust a user or device because of its location. Access is continuously verified and limited to what is necessary.
SASE
Secure Access Service Edge combines networking and security capabilities in a cloud-delivered architecture so users and locations can receive consistent policy wherever they connect.
Identity and Access Management (IAM)
The systems and policies that determine who a user is, what resources they may access, and how that access is authenticated and reviewed.
Multi-Factor Authentication (MFA)
A login control requiring more than one form of verification, such as a password plus an authenticator app, security key, or biometric factor.