milestone 17: real deadlines, validator holes, upstream editor, trusted proxies, contract samples, badvers
CI / test (push) Successful in 1m22s
CI / test-aarch64 (push) Successful in 4m55s
CI / frontend (push) Successful in 39s
CI / cross (push) Successful in 7m57s
CI / docker (push) Failing after 1h10m42s

This commit is contained in:
2026-08-07 17:55:59 +02:00
parent 9b12dbaaa0
commit c50c6d285a
57 changed files with 2926 additions and 126 deletions
+701
View File
@@ -0,0 +1,701 @@
// Generated file — do not edit by hand.
//
// Every value below is a real response from the web server, captured by the
// contract-sample test in src/web/web_integration_test.zig and canonicalized:
// object keys sorted, every number 0, strings and booleans as the deterministic
// seed produced them, repeated array elements collapsed to the first. The type
// annotations are the ones api.ts hands to its own `request<T>`, so `tsc`
// refuses a field the wire does not send, a wire field types.ts does not
// declare, and a string outside a literal union.
//
// Regenerate with:
// zig build test -Dintegration -Dcontract-samples-out="$PWD/web/src/lib/contractSamples.gen.ts"
import type {
Blocklist,
BlocklistEcho,
Client,
ClientPrefix,
ErrorEnvelope,
ForwardZone,
Group,
Health,
LocalRecord,
LoginResponse,
LogoutResponse,
LookupResult,
PauseState,
QueriesPage,
Rule,
RuleEcho,
SettingsEnvelope,
SourceStatus,
StatsTimeseries,
StatsTotals,
Upstream,
UpstreamEcho,
UpstreamHealth,
Version,
} from "@/lib/types";
export const sample_get_health: Health = {
disk: {
db_bytes: 0,
free_bytes: 0,
log_bytes: 0,
sample_failures: 0,
state: "ok",
},
queries_dropped: 0,
refreshes_gated: 0,
snapshot_generation: 0,
status: "ok",
upstreams: {
available: 0,
total: 0,
},
writer_failed: false,
};
export const sample_get_version: Version = {
git_commit: "<build>",
uptime_seconds: 0,
version: "w10-test",
zig_version: "<build>",
};
export const sample_login: LoginResponse = {
auth_required: false,
authenticated: true,
};
export const sample_logout: LogoutResponse = {
authenticated: false,
};
export const sample_create_blocklist: BlocklistEcho = {
enabled: false,
id: 0,
is_suggested: false,
name: "ads",
url: "https://lists.example/ads.txt",
};
export const sample_list_blocklists: { blocklists: Blocklist[] } = {
blocklists: [
{
checksum: null,
domain_count: 0,
enabled: false,
id: 0,
is_suggested: false,
last_updated: null,
name: "ads",
skipped_regex_count: 0,
url: "https://lists.example/ads.txt",
wildcard_count: 0,
},
],
};
export const sample_update_blocklist: BlocklistEcho = {
enabled: false,
id: 0,
is_suggested: false,
name: "ads2",
url: "https://lists.example/ads.txt",
};
export const sample_update_blocklists_now: { sources: SourceStatus[] } = {
sources: [
{
domains: 0,
id: 0,
last_attempt: 0,
last_error: "",
last_success: 0,
loaded: false,
skipped_regex: 0,
state: "never_fetched",
url: "https://lists.example/ads.txt",
wildcards: 0,
},
],
};
export const sample_list_groups: { groups: Group[] } = {
groups: [
{
id: 0,
name: "default",
safe_search: false,
},
],
};
export const sample_create_group: Group = {
id: 0,
name: "kids",
safe_search: false,
};
export const sample_update_group: Group = {
id: 0,
name: "teens",
safe_search: true,
};
export const sample_put_group_sources: { source_ids: number[] } = {
source_ids: [0],
};
export const sample_get_group_sources: { source_ids: number[] } = {
source_ids: [0],
};
export const sample_create_rule: RuleEcho = {
action: "block",
group_id: 0,
id: 0,
kind: "exact",
pattern: "ads.example",
};
export const sample_list_rules: { rules: Rule[] } = {
rules: [
{
action: "block",
created_at: 0,
group: "default",
group_id: 0,
id: 0,
kind: "exact",
pattern: "ads.example",
},
],
};
export const sample_update_rule: RuleEcho = {
action: "block",
group_id: 0,
id: 0,
kind: "wildcard",
pattern: "*.ads.example",
};
export const sample_get_lookup: LookupResult = {
blocked: true,
domain: "sub.ads.example",
forward_zone: null,
group_id: 0,
local_records: false,
matched: "*.ads.example",
reason: "rule_block_wildcard",
safe_search_rewrite: null,
source_url: null,
};
export const sample_create_local_record: LocalRecord = {
id: 0,
name: "nas.lan",
rtype: "A",
ttl: 0,
value: "192.168.1.10",
};
export const sample_list_local_records: { local_records: LocalRecord[] } = {
local_records: [
{
id: 0,
name: "nas.lan",
rtype: "A",
ttl: 0,
value: "192.168.1.10",
},
],
};
export const sample_update_local_record: LocalRecord = {
id: 0,
name: "nas.lan",
rtype: "A",
ttl: 0,
value: "192.168.1.11",
};
export const sample_create_forward_zone: ForwardZone = {
id: 0,
resolver: "udp://10.0.0.1:53",
zone: "lan",
};
export const sample_list_forward_zones: { forward_zones: ForwardZone[] } = {
forward_zones: [
{
id: 0,
resolver: "udp://10.0.0.1:53",
zone: "lan",
},
],
};
export const sample_update_forward_zone: ForwardZone = {
id: 0,
resolver: "udp://10.0.0.2:53",
zone: "lan",
};
export const sample_list_clients: { clients: Client[] } = {
clients: [
{
first_seen: 0,
group: "default",
group_id: 0,
hand_edited: false,
id: 0,
ip: "192.168.1.50",
last_seen: 0,
name: "laptop",
},
],
};
export const sample_update_client: Client = {
first_seen: 0,
group: "default",
group_id: 0,
hand_edited: true,
id: 0,
ip: "192.168.1.50",
last_seen: 0,
name: "laptop-renamed",
};
export const sample_put_client_prefixes: { client_prefixes: ClientPrefix[] } = {
client_prefixes: [
{
group: "default",
group_id: 0,
id: 0,
prefix: "192.168.1.0/24",
priority: 0,
},
],
};
export const sample_list_client_prefixes: { client_prefixes: ClientPrefix[] } = {
client_prefixes: [
{
group: "default",
group_id: 0,
id: 0,
prefix: "192.168.1.0/24",
priority: 0,
},
],
};
export const sample_list_upstreams: { upstreams: Upstream[] } = {
upstreams: [
{
enabled: true,
id: 0,
priority: 0,
tls_name: "",
url: "https://dns.example/dns-query",
},
],
};
export const sample_create_upstream: UpstreamEcho = {
enabled: true,
id: 0,
priority: 0,
restart_required: true,
tls_name: "",
url: "https://dns2.example/dns-query",
};
export const sample_update_upstream: UpstreamEcho = {
enabled: true,
id: 0,
priority: 0,
restart_required: true,
tls_name: "",
url: "https://dns.example/dns-query",
};
export const sample_get_upstream_health: UpstreamHealth = {
available: 0,
total: 0,
upstreams: [
{
available: true,
consecutive_failures: 0,
enabled: true,
last_error: "",
success_rate: 0,
total_failures: 0,
total_successes: 0,
url: "https://dns.example/dns-query",
},
],
};
export const sample_get_queries: QueriesPage = {
next_before: 0,
queries: [
{
block_reason: "",
blocked: false,
cache_hit: true,
client_ip: "192.0.2.10",
domain: "d24.example",
id: 0,
qtype: 0,
response_time_us: 0,
ts: 0,
upstream: "https://dns.example/dns-query",
},
{
block_reason: "",
blocked: false,
cache_hit: false,
client_ip: "192.0.2.10",
domain: "d23.example",
id: 0,
qtype: 0,
response_time_us: 0,
ts: 0,
upstream: "https://dns.example/dns-query",
},
{
block_reason: "",
blocked: false,
cache_hit: true,
client_ip: "192.0.2.10",
domain: "d22.example",
id: 0,
qtype: 0,
response_time_us: 0,
ts: 0,
upstream: "https://dns.example/dns-query",
},
{
block_reason: "",
blocked: false,
cache_hit: false,
client_ip: "192.0.2.10",
domain: "d21.example",
id: 0,
qtype: 0,
response_time_us: 0,
ts: 0,
upstream: "https://dns.example/dns-query",
},
{
block_reason: "blocklist_domain",
blocked: true,
cache_hit: null,
client_ip: "192.0.2.10",
domain: "d20.example",
id: 0,
qtype: 0,
response_time_us: 0,
ts: 0,
upstream: "",
},
],
};
export const sample_get_stats: StatsTotals = {
avg_response_time_us: null,
blocked: 0,
cached: 0,
clients: 0,
period: "1h",
queries: 0,
since: 0,
until: 0,
};
export const sample_get_stats_timeseries: StatsTimeseries = {
bucket_seconds: 0,
buckets: [
{
blocked: 0,
cached: 0,
queries: 0,
ts: 0,
},
],
period: "1h",
since: 0,
until: 0,
};
export const sample_get_pause: PauseState = {
paused: false,
until: null,
};
export const sample_post_pause: PauseState = {
paused: true,
until: 0,
};
export const sample_get_settings: SettingsEnvelope = {
restart_required: [
"upstream.attempt_timeout_ms",
"upstream.read_timeout_ms",
"upstream.total_timeout_ms",
"dns.bind_ipv4",
"dns.bind_ipv6",
"dns.port",
"dns.rate_limit",
"dns.rate_window_seconds",
"blocking.response",
"blocking.ttl",
"cache.size",
"cache.negative_ttl_max",
"web.enabled",
"web.bind",
"web.port",
"web.session_ttl_hours",
"web.api_rate_limit_per_min",
"web.api_localhost_exempt",
"web.sse_max_connections_per_ip",
"web.trusted_proxies",
"doh_server.enabled",
"doh_server.bind",
"doh_server.port",
"doh_server.cert_path",
"doh_server.key_path",
"dot_server.enabled",
"dot_server.bind",
"dot_server.port",
"dot_server.cert_path",
"dot_server.key_path",
"edns.ecs_mode",
"logging.level",
"logging.retention_days",
"logging.query_log_buffer_max",
"logging.hide_domains",
"logging.hide_client_ips",
"logging.output",
"logging.file_path",
"logging.max_size_mb",
"logging.max_files",
"disk.min_free_mb",
"disk.warn_free_mb",
"blocklist_update.enabled",
"blocklist_update.interval_hours",
],
settings: {
blocking: {
response: "zero",
ttl: 0,
},
blocklist_update: {
enabled: true,
interval_hours: 0,
},
cache: {
negative_ttl_max: 0,
size: 0,
},
disk: {
min_free_mb: 0,
warn_free_mb: 0,
},
dns: {
bind_ipv4: "0.0.0.0",
bind_ipv6: "::",
port: 0,
rate_limit: 0,
rate_window_seconds: 0,
},
doh_server: {
bind: "0.0.0.0",
cert_path: "/etc/nxdns/cert.pem",
enabled: false,
key_path: "/etc/nxdns/key.pem",
port: 0,
},
dot_server: {
bind: "0.0.0.0",
cert_path: "/etc/nxdns/cert.pem",
enabled: false,
key_path: "/etc/nxdns/key.pem",
port: 0,
},
edns: {
ecs_mode: "strip",
},
logging: {
file_path: "/var/log/nxdns/nxdns.log",
hide_client_ips: false,
hide_domains: false,
level: "info",
max_files: 0,
max_size_mb: 0,
output: "stderr",
query_log_buffer_max: 0,
retention_days: 0,
},
upstream: {
attempt_timeout_ms: 0,
read_timeout_ms: 0,
total_timeout_ms: 0,
},
web: {
api_localhost_exempt: true,
api_rate_limit_per_min: 0,
auth_enabled: false,
bind: "0.0.0.0",
enabled: true,
port: 0,
session_ttl_hours: 0,
sse_max_connections_per_ip: 0,
trusted_proxies: "",
},
},
};
export const sample_put_settings: SettingsEnvelope = {
restart_required: [
"upstream.attempt_timeout_ms",
"upstream.read_timeout_ms",
"upstream.total_timeout_ms",
"dns.bind_ipv4",
"dns.bind_ipv6",
"dns.port",
"dns.rate_limit",
"dns.rate_window_seconds",
"blocking.response",
"blocking.ttl",
"cache.size",
"cache.negative_ttl_max",
"web.enabled",
"web.bind",
"web.port",
"web.session_ttl_hours",
"web.api_rate_limit_per_min",
"web.api_localhost_exempt",
"web.sse_max_connections_per_ip",
"web.trusted_proxies",
"doh_server.enabled",
"doh_server.bind",
"doh_server.port",
"doh_server.cert_path",
"doh_server.key_path",
"dot_server.enabled",
"dot_server.bind",
"dot_server.port",
"dot_server.cert_path",
"dot_server.key_path",
"edns.ecs_mode",
"logging.level",
"logging.retention_days",
"logging.query_log_buffer_max",
"logging.hide_domains",
"logging.hide_client_ips",
"logging.output",
"logging.file_path",
"logging.max_size_mb",
"logging.max_files",
"disk.min_free_mb",
"disk.warn_free_mb",
"blocklist_update.enabled",
"blocklist_update.interval_hours",
],
settings: {
blocking: {
response: "zero",
ttl: 0,
},
blocklist_update: {
enabled: true,
interval_hours: 0,
},
cache: {
negative_ttl_max: 0,
size: 0,
},
disk: {
min_free_mb: 0,
warn_free_mb: 0,
},
dns: {
bind_ipv4: "0.0.0.0",
bind_ipv6: "::",
port: 0,
rate_limit: 0,
rate_window_seconds: 0,
},
doh_server: {
bind: "0.0.0.0",
cert_path: "/etc/nxdns/cert.pem",
enabled: false,
key_path: "/etc/nxdns/key.pem",
port: 0,
},
dot_server: {
bind: "0.0.0.0",
cert_path: "/etc/nxdns/cert.pem",
enabled: false,
key_path: "/etc/nxdns/key.pem",
port: 0,
},
edns: {
ecs_mode: "strip",
},
logging: {
file_path: "/var/log/nxdns/nxdns.log",
hide_client_ips: false,
hide_domains: false,
level: "info",
max_files: 0,
max_size_mb: 0,
output: "stderr",
query_log_buffer_max: 0,
retention_days: 0,
},
upstream: {
attempt_timeout_ms: 0,
read_timeout_ms: 0,
total_timeout_ms: 0,
},
web: {
api_localhost_exempt: true,
api_rate_limit_per_min: 0,
auth_enabled: false,
bind: "0.0.0.0",
enabled: true,
port: 0,
session_ttl_hours: 0,
sse_max_connections_per_ip: 0,
trusted_proxies: "",
},
},
};
export const sample_error_bad_request: ErrorEnvelope = {
error: "logging.level: not one of the values this setting accepts",
};
export const sample_error_conflict: ErrorEnvelope = {
error: "an upstream with that url already exists",
};
export const sample_error_not_found: ErrorEnvelope = {
error: "not found",
};
export const sample_error_unauthorized: ErrorEnvelope = {
error: "authentication required",
};
export const sample_error_rate_limited: ErrorEnvelope = {
error: "rate limited",
};