Files
RustProxy/tools/checks/check_source.py
T
2026-10-14 16:07:58 +02:00

1640 lines
124 KiB
Python
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Static package checks only. Does not compile or validate Rust types/behavior."""
from pathlib import Path
import ast
import json
import re
import sqlite3
import subprocess
import tomllib
from preflight import check as preflight
from rust_source import rust_source
from web_assets import read_app_js, read_vhosts_js
root = Path(__file__).resolve().parents[2]
def read_cache_source() -> str:
return rust_source(root, "src/cache/mod.rs")
def read_deploy_source() -> str:
return "\n".join((root / name).read_text(encoding="utf-8") for name in ("scripts/deploy/deploy_core.py", "scripts/deploy/deploy_runtime.py", "scripts/deploy/deploy.py"))
def read_docker_agent_source() -> str:
return "\n".join(path.read_text(encoding="utf-8") for path in sorted((root / "docker-agent").glob("*.go")) if not path.name.endswith("_test.go"))
preflight(root)
manifest = tomllib.loads((root / "Cargo.toml").read_text())
assert manifest["package"]["version"] == "0.32.7"
assert manifest["dependencies"]["quinn"]["version"] == "0.11.12"
h3dep = manifest["dependencies"]["h3"]
assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.20" and "quinn" in h3dep["features"]
assert "h3-quinn" not in manifest["dependencies"]
lock_path = root / "Cargo.lock"
if lock_path.exists():
lock = lock_path.read_text()
assert 'name = "rust-proxy"\nversion = "0.32.7"' in lock
assert 'name = "systemstat"' in lock and 'name = "metrics-process"' in lock and 'name = "sysinfo"' in lock, "Cargo.lock must be resolver-generated after adding cross-platform statistics libraries"
for release_doc, marker in {
"README.md": "# RustProxy 0.32.7",
"CHANGELOG.md": "## 0.32.7",
"ROADMAP.md": "## 0.32.7",
"AGENTS.md": "Current source version: 0.32.7.",
"docs/TEST_REPORT.md": "# Verification report - RustProxy 0.32.7",
}.items():
assert marker in (root / release_doc).read_text(), f"stale release identity in {release_doc}"
assert tomllib.loads((root / "rust-toolchain.toml").read_text())["toolchain"]["channel"] == "stable"
update_defaults = tomllib.loads((root / "UPDATE_CHECK.toml").read_text())
assert update_defaults == {
"repository_url": "https://git.linuxiarz.pl/gru/RustProxy",
"version_url": "https://git.linuxiarz.pl/gru/RustProxy/raw/branch/master/Cargo.toml",
"interval_seconds": 3600,
}
update_check_source = rust_source(root, "src/update_check.rs")
for marker in [
'include_str!("../UPDATE_CHECK.toml")',
'pub async fn poll_loop',
'tokio::time::sleep(interval)',
'Cargo.toml [package] version was not found',
'MAX_VERSION_DOCUMENT_BYTES',
'update check failed; retrying on the next interval',
]:
assert marker in update_check_source, marker
assert 'update version document is too large or incomplete: {error}' in update_check_source
assert '.context("update version document is too large or incomplete")' not in update_check_source
for marker in [
'tracing::warn!(',
'MAX_REDIRECTS: usize = 5',
'SSL_CERT_FILE',
'CURL_CA_BUNDLE',
'/usr/local/share/certs/ca-root-nss.crt',
'response.status().is_redirection()',
'redirect_target(&current, location)',
'update version redirect must not downgrade HTTPS to HTTP',
]:
assert marker in update_check_source, marker
assert 'pub last_error:' not in update_check_source, "update-check errors must not change dashboard/API state"
for name in ["README.md", "ROADMAP.md", "AGENTS.md", "CHANGELOG.md", "UPDATE_CHECK.toml", "Dockerfile", ".dockerignore", "docs/TEST_REPORT.md", "docs/LIVE_LOGS.md", "docs/README.md", "docs/API.md", "docs/ARCHITECTURE.md", "docs/WEB_SERVER.md", "docs/PHP_FPM.md", "docs/VHOSTS.md", "docs/STREAMS.md", "docs/REDIRECTS.md", "docs/CONTAINER.md", "docs/NPM_MIGRATION.md", "docs/DOCKER_DISCOVERY.md", "docker-agent/main.go", "docker-agent/main_test.go", "docker-agent/rustproxy-docker-agent.service", "docker-agent/docker-agent.env.example", "docker-agent/install.sh", "src/docker.rs", "src/admin/web/docker.js", "scripts/migration/migrate_npm.py", "docs/CUSTOM_LOCATIONS.md", "nagios/README.md", "nagios/check_rustproxy.py", "nagios/check_rustproxy_api", "nagios/check_rustproxy_backends", "nagios/check_rustproxy_latency", "nagios/check_rustproxy_queues", "src/admin/web/error_401.html", "src/admin/web/error_404.html", "src/admin/web/streams.js", "src/admin/web/redirects.js", "src/admin/web/host404.js", "docs/NOT_FOUND_HOSTS.md", "grafana/rustproxy-overview.json", "grafana/README.md"]:
assert (root / name).is_file(), name
npm_doc = (root / "docs/NPM_MIGRATION.md").read_text(encoding="utf-8")
for marker in ["scripts/migration/migrate_npm_core.py", "scripts/migration/migrate_npm_api.py", '-v "$PWD/scripts/migration:/rustproxy-migration:ro"', "python /rustproxy-migration/migrate_npm.py"]:
assert marker in npm_doc, marker
for module in ["scripts/migration/migrate_npm.py", "scripts/migration/migrate_npm_core.py", "scripts/migration/migrate_npm_api.py"]:
assert (root / module).is_file(), module
for path in (root / "examples").glob("*.json"):
data = json.loads(path.read_text())
assert isinstance(data, dict), path
assert isinstance(data.get("vhosts"), list), path
assert "backends" not in data and "routes" not in data, path
for key in ("backends", "routes", "vhosts"):
assert isinstance(data.get(key, []), list), (path, key)
for path in (root / "src").rglob("*.rs"):
source = path.read_text()
for target in re.findall(r'include_str!\("([^"]+)"\)', source):
assert (path.parent / target).is_file(), (path, target)
lines = source.splitlines()
for index in range(len(lines) - 1):
assert not (lines[index].lstrip().startswith("#[derive(") and lines[index + 1].lstrip().startswith("#[derive(")), f"consecutive derive attributes in {path}:{index + 1}"
html = (root / "src/admin/web/index.html").read_text()
js = "\n".join(p.read_text() for p in (root / "src/admin/web").rglob("*.js") if p.name not in ("login.js", "docs.js"))
ids = re.findall(r'id="([^"]+)"', html)
assert len(ids) == len(set(ids)), "duplicate HTML IDs"
for identifier in set(re.findall(r'\$\("([^"]+)"\)', js)):
assert identifier in ids, f"unknown frontend ID: {identifier}"
python_sources = [root / "make_zip.py", *(root / "scripts").rglob("*.py"), *(root / "tools").rglob("*.py")]
for path in python_sources:
ast.parse(path.read_text(), str(path))
subprocess.run(["bash", "-n", str(root / "dev.sh")], check=True)
subprocess.run(["bash", "-n", str(root / "upgrade.sh")], check=True)
for name in ["install.sh", "install-debian13.sh", "update.sh", "nagios/check_rustproxy_api", "nagios/check_rustproxy_backends", "nagios/check_rustproxy_latency", "nagios/check_rustproxy_queues", "docker-agent/install.sh"]:
subprocess.run(["bash", "-n", str(root / name)], check=True)
bootstrap = (root / "install-debian13.sh").read_text()
for marker in [
'MODE="${1:-auto}"',
'auto|install|update',
'MODE=update',
'bash update.sh',
'--prefix "$PREFIX"',
'python3-venv',
'python3-pip',
]:
assert marker in bootstrap, marker
assert 'curl ' not in bootstrap, 'Debian bootstrap must use wget instead of curl'
dev = (root / "dev.sh").read_text()
assert 'cargo generate-lockfile' in dev and r'version = "0\.9\.0"' not in dev
assert dev.count('cargo generate-lockfile') == 1, "dev.sh must only create Cargo.lock when it is missing"
unit = (root / "deploy/rustproxy.service").read_text()
assert "LogsDirectory=rustproxy" in unit and "/var/log/rustproxy" in unit
assert "ReadOnlyPaths=-/etc/letsencrypt -/etc/ssl" in unit
assert "Environment=MALLOC_ARENA_MAX=2" in unit
assert "Environment=MALLOC_ARENA_MAX=2" in read_deploy_source()
assert not re.search(r"\b20\d{2}[-/]\d{1,2}[-/]\d{1,2}\b", (root / "CHANGELOG.md").read_text()), "changelog contains a release date"
subprocess.run(["python3", str(root / "tools/checks/langs_check.py")], check=True)
subprocess.run(["python3", str(root / "tools/checks/web_server_contracts.py")], check=True)
subprocess.run(["python3", str(root / "tools/checks/rust_module_contracts.py")], check=True)
subprocess.run(["python3", str(root / "tools/checks/source_module_contracts.py")], check=True)
dockerfile = (root / "Dockerfile").read_text()
assert "cargo generate-lockfile" in dockerfile and "cargo build --locked --release" in dockerfile
assert "USER rustproxy:rustproxy" in dockerfile
assert 'VOLUME ["/var/lib/rustproxy"]' in dockerfile
assert "COPY . ." in dockerfile
for marker in [
"python3-venv",
"python3-pip",
"certbot",
"python3-certbot-dns-cloudflare",
"python3-certbot-dns-ovh",
"python3-certbot-dns-rfc2136",
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
]:
assert marker in dockerfile, marker
assert "data" in (root / ".dockerignore").read_text().splitlines()
css = (root / "src/admin/web/style.css").read_text()
assert ".logging-grid fieldset" not in css, "logging sinks must reuse shared card styling"
assert re.search(r"dialog\.config-history-dialog,\s*dialog\.config-history-json-dialog,\s*dialog\.logs-dialog,", css), "Revision History and JSON comparison must use shared dialog styling"
assert ".config-history-dialog::backdrop" not in css, "Revision History must not duplicate the shared dialog backdrop"
history_dialog_css = re.search(r"^\.config-history-dialog\s*\{([^}]*)\}", css, re.M).group(1)
assert "border-radius:" not in history_dialog_css, "Revision History dialog must stay square-cornered"
for selector in ["config-history-month", "config-history-day", "config-history-change"]:
block = re.search(rf"^\.{selector}\s*\{{([^}}]*)\}}", css, re.M).group(1)
assert "border-radius:" not in block, f"{selector} must stay square-cornered"
assert ".vhost-chart-line" in css and ".host-chip-editor" in css
assert 'class="vhost-dialog logging-format-dialog"' in html
assert 'data-panel="streams"' in html and 'id="panel-streams"' in html
for marker in ['id="vhost-sort"', 'id="vhost-sort-direction"', 'id="docker-vhost-sort"', 'id="docker-vhost-sort-direction"', 'id="redirect-sort"', 'id="redirect-sort-direction"', 'id="notfound-sort"', 'id="notfound-sort-direction"', 'id="stream-sort"', 'id="stream-sort-direction"']:
assert marker in html, marker
preferences_source = rust_source(root, "src/admin/preferences.rs")
for marker in ['vhost_list_sort', 'docker_vhost_sort', 'redirect_list_sort', 'notfound_list_sort', 'stream_list_sort', 'VHOST_LIST_SORT_COLUMNS', 'DOCKER_VHOST_SORT_COLUMNS', 'REDIRECT_LIST_SORT_COLUMNS', 'NOTFOUND_LIST_SORT_COLUMNS', 'STREAM_LIST_SORT_COLUMNS']:
assert marker in preferences_source, marker
for source_name, markers in {
"src/admin/web/vhosts/render.js": ["vhost_list_sort", "vhost_list_descending"],
"src/admin/web/docker.js": ["docker_vhost_sort", "docker_vhost_descending", "sortServiceRows"],
"src/admin/web/redirects.js": ["redirect_list_sort", "redirect_list_descending"],
"src/admin/web/host404.js": ["notfound_list_sort", "notfound_list_descending"],
"src/admin/web/streams.js": ["stream_list_sort", "stream_list_descending"],
}.items():
source_text = (root / source_name).read_text(encoding="utf-8")
for marker in markers:
assert marker in source_text, (source_name, marker)
assert 'data-panel="docker-vhosts"' in html and 'id="panel-docker-vhosts"' in html
assert 'id="settings-tab-docker-agents"' in html and 'id="settings-page-docker-agents"' in html
assert 'include_str!("web/docker.js")' in (root / 'src/admin/router.rs').read_text() and 'cache-live-toggle' in html
assert 'expose-revision' not in html and 'hideRevision' not in js and 'diagRevision' not in js
for path in ['src/settings.rs', 'src/admin/mod.rs', 'src/cache/mod.rs', 'src/headers.rs', 'src/tinyauth.rs', 'src/admin/web/vhosts/core.js']:
text = rust_source(root, path) if path.endswith('.rs') else (root / path).read_text()
assert 'x-rust-proxy-revision' not in text.lower(), f'legacy revision-header logic remains in {path}'
assert './dev.sh admin reset-password' not in html and re.search(r'rust-proxy\s+admin reset-password locally', html)
assert 'data-panel="redirects"' in html and 'id="panel-redirects"' in html
assert 'data-panel="configuration"' not in html and 'id="panel-configuration"' not in html
assert 'id="settings-tab-manual-config"' in html and 'id="settings-page-manual-config"' in html
assert 'id="security-audit-open"' in html and 'id="audit-dialog"' in html and 'id="audit-dialog-close"' in html
assert 'id="security-password-editor"' in html and 'id="security-policy-editor"' in html
assert 'docker-service-editor' in (root / "src/admin/web/docker.js").read_text() and 'docker-agent-details' in (root / "src/admin/web/docker.js").read_text()
balance_source = rust_source(root, "src/balance.rs")
assert 'mode: HealthMode::Tcp' in balance_source
assert 'member.backend.client.maintain_rotation();' in balance_source
assert 'member.backend.websocket_client.maintain_rotation();' in balance_source
upstream_client_source = rust_source(root, "src/upstream/client.rs")
assert 'fn maintain_rotation(&self)' in upstream_client_source
assert 'self.rotate(self.generation.load(Ordering::Acquire), "age", false);' in upstream_client_source
assert 'fn reusable_with(&self, other: &Self) -> bool' in upstream_client_source
assert 'member.backend = old.backend.clone();' in balance_source
assert 'compatible_pool_rebuild_reuses_upstream_clients' in balance_source
for marker in [
'pub struct PassiveHealth', 'enabled: false', 'pub passive_health: PassiveHealth',
'passive_health_failures_total', 'http_5xx_total', 'timeouts_total',
'connect_errors_total', 'io_errors_total', 'slow_responses_total',
'passive_health_is_opt_in_and_uses_separate_thresholds',
'unhealthy_source_hands_off_when_the_original_health_domain_recovers',
]:
assert marker in balance_source, marker
assert 'id="config-editor"' in html and 'id="save-json"' in html and 'id="export-config"' in html
assert 'toast(t("saved"));' in js and 'toast(t("saved") + envelope.revision);' not in js
for lang_name in ["en_US.json", "pl_pl.json"]:
translations = json.loads((root / "langs" / lang_name).read_text())["translations"]
assert translations["saved"] in {"Configuration applied.", "Zastosowano konfigurację."}
assert "revision" not in translations["saved"].lower() and "rewizj" not in translations["saved"].lower()
assert html.index('data-panel="vhosts"') < html.index('data-panel="redirects"') < html.index('data-panel="notfound"') < html.index('data-panel="streams"') < html.index('data-panel="acl-profiles"')
assert 'id="stream-dialog"' in html and 'id="stream-list"' in html and 'id="stream-search"' in html
assert 'id="settings-page-streams"' not in html and 'id="streams-form"' not in html
assert all(f'include_str!("web/{name}.js")' in (root / 'src/admin/router.rs').read_text() for name in ('streams', 'redirects', 'host404'))
vhosts_js = read_vhosts_js(root)
assert '"force-ssl", "vhForceSsl"' in vhosts_js and 'force_ssl: yes("force-ssl")' in vhosts_js
assert 'vhForceSslNeedsHttp' in vhosts_js and 'tlsPorts.has(443)' in vhosts_js
assert '"forward-client-ip", "vhForwardClientIp"' in vhosts_js and 'forward_client_ip: yes("forward-client-ip")' in vhosts_js
assert 'id="vhost-search"' in html and '$("vhost-search").addEventListener("input", render)' in vhosts_js
for marker in ['id="pool-search"', 'id="pool-sort"', 'data-pool-column-toggle="vhost"', 'data-pool-column="generationAge"']:
assert marker in html, marker
for marker in ['toggleVhostEnabled', 'vhQuickEnable', 'vhQuickDisable', 'backend_table_columns', 'applyPoolTableView', 'saveSection("vhosts", next.vhosts || [])', 'rustProxyEnableControl']:
assert marker in vhosts_js, marker
assert 'rustproxy-backend-table-v1' not in vhosts_js and 'poolTablePreferenceKey' not in vhosts_js
assert 'window.rustProxyPreferences.update({' in vhosts_js and 'backend_table_sort' in vhosts_js and 'backend_table_descending' in vhosts_js
style_ui = (root / 'src/admin/web/style.css').read_text()
for marker in ['--scrollbar-thumb', '::-webkit-scrollbar-thumb', '.backend-table-tools', '.vh-enable-control', '.vhost-quick-toggle', '.dashboard-widget-toggle', '--toolbar-control-height: min(var(--button-min-height), var(--ui-field-min-height))', 'height: var(--toolbar-control-height)']:
assert marker in style_ui, marker
preferences_js = (root / "src/admin/web/app/preferences.js").read_text()
assert 'dashboard-widget-toggle' in preferences_js and 'visible.type = "checkbox"' not in preferences_js
assert 'window.rustProxyVhosts?.applyPreferences(normalized);' in preferences_js, "saved backend table preferences must be reapplied from the shared account preference path"
core_js = (root / "src/admin/web/app/core.js").read_text()
assert 'window.rustProxyEnableControl = enhanceEnabledControl' in core_js
assert 'id="admin-session-days"' in html and 'min="7" max="30"' in html
assert 'member-local-risk' in vhosts_js and 'vhLocalListenerRiskConfirm' in vhosts_js
assert 'accept_local_listener_risk: yes("member-local-risk", row)' in vhosts_js
assert 'function administrationListenCandidates()' in vhosts_js and 'function adminListenerBackendCandidate(raw)' in vhosts_js
for marker in ['latestStatus?.administration?.locked_listen', 'latestStatus?.administration?.active?.listen', 'latestStatus?.admin_listen', "value === 'localhost'", '/^127(?:\\.\\d{1,3}){3}$/.test(value)', 'riskGate.hidden = show !== true', 'row.syncLocalRisk = () => syncRisk(false)']:
assert marker in vhosts_js, marker
assert 'const saved = editing ? (envelope?.config.vhosts || []).find(item => item.id === editing) : null;' in vhosts_js
assert 'load(saved ? structuredClone(saved) : defaults());' in vhosts_js
assert 'backends: [{ id: "origin-1", url: ""' in vhosts_js, "new backend drafts must require an explicit origin URL"
assert 'preserve_host: true' in vhosts_js, "new ordinary HTTP/1.1 backends must preserve public Host by default"
for marker in ['vhBackendDiagnostics', 'backend_header: yes("backend-header")', 'backend_timing_header: yes("backend-timing-header")', 'protocol-toggle-row', 'auth-subcard', 'vh-cache-options', 'syncCacheVisibility']:
assert marker in vhosts_js, marker
assert 'cache: { enabled: false }' in vhosts_js, "new vhost drafts must default cache off"
docker_js = (root / "src/admin/web/docker.js").read_text()
assert 'preserve.checked = assignment?.preserve_host !== false' in docker_js, "new Docker backends must preserve public Host by default"
for marker in ['saveSection("docker-agents"', '/api/docker/refresh', 'docker-publish', 'docker-hostname', 'host-chip-editor docker-alias-editor', 'docker-target-ip', 'default_target_ip', 'docker-agent-fingerprint', 'docker-agent-certificate', 'docker-health-mode', 'docker-passive-enabled', 'docker-passive-5xx', 'docker-search', 'docker-show-hidden', 'dockerHideVhost', 'pool_routes', 'rustProxyRefresh.register("docker"']:
assert marker in docker_js, marker
docker_source = rust_source(root, "src/docker.rs")
for marker in ['pub struct Settings', 'pub struct Observation', 'pub struct HostAddress', 'pub struct Binding', 'aliases: Vec<String>', 'target_ip: Option<IpAddr>', 'tls_fingerprint_sha256', 'certificate_id: Option<String>', 'health_check: crate::balance::HealthCheck', 'passive_health: crate::balance::PassiveHealth', 'PinnedCertificateVerifier', 'fingerprint mismatch', 'effective_config', 'poll_loop', 'address_allowlist']:
assert marker in docker_source, marker
agent_source = read_docker_agent_source()
for marker in ['/v1/inventory', 'Authorization', '/containers/json?all=0', 'IsLoopback', 'localHostAddresses', 'detectedAddresses', 'Bindings', 'RUSTPROXY_DOCKER_AGENT_TOKEN', 'ensureSelfSignedCertificate', 'ListenAndServeTLS', 'RUSTPROXY_DOCKER_AGENT_TLS', 'CertificateSHA256']:
assert marker in agent_source, marker
assert 'pool-vhost-disabled' in vhosts_js and '.pool-vhost-disabled' in css
streams_js = (root / "src/admin/web/streams.js").read_text()
redirects_js = (root / "src/admin/web/redirects.js").read_text()
for marker in ["rustProxyRedirects", "redirectTargetType", "status_code", "cache_seconds", 'saveSection("redirects"']:
assert marker in redirects_js, marker
for marker in ["rustProxyStreams", "streamTrafficChart", "streamPendingRestart", "stream-listener-add", "chartHistory", "sessions_total", "bytes_in", "bytes_out"]:
assert marker in streams_js, marker
assert '$("stream-listener-add").addEventListener("click", () => { setPanel("settings"); window.rustProxySettings?.select("listeners"); });' in streams_js
integrations_js = (root / "src/admin/web/integrations.js").read_text()
assert "addressTagEditor" in integrations_js and "listener-address-chip-editor" in integrations_js
assert "stream-host-rows" not in integrations_js
assert 'const http80 = prefer(false, 80);' in integrations_js
assert 'if (http80) autoIds.add(http80.id);' in integrations_js and 'candidates.find(endpoint => !endpoint.binding?.tls)' in integrations_js
assert 'https443' not in integrations_js
assert 'window.rustProxyIntegrations.bindings(holder, selected, !editing)' in redirects_js
assert 'window.rustProxyIntegrations.hostnames(hostHolder' in redirects_js
assert 'id="redirect-hosts-editor"' in html
assert 'class="protocol-toggle-row"' in html
for marker in ['.vh-backend-card', '.auth-subcard', '.vh-cache-options[hidden]', '.protocol-toggle-row', '.listener-choices']:
assert marker in css, marker
openapi = (root / "src/admin/openapi.json").read_text()
assert '"load_balancing"' in openapi and '"LoadBalancingConfig"' in openapi and '"PassiveHealthConfig"' in openapi
assert 'Opt-in health decisions based on ordinary user traffic. Defaults to disabled.' in openapi
assert '"force_ssl"' in openapi and '"forward_client_ip"' in openapi
assert '"backend_header"' in openapi and '"backend_timing_header"' in openapi
assert '"StreamMetrics"' in openapi and '"streams"' in openapi
for marker in ['"version": "0.32.7"', '"/api/traffic"', '"capture_user_agent"', '"capture_country"', '"hot_auto_trim_enabled"', '"hot_auto_trim_after_seconds"', '"hot_auto_trim_target_percent"', '"/api/config/{section}"', '"ConfigSectionUpdate"', '"cold_on_idle"', '"cold_on_age"', '"cold_max_hot_seconds"', '"cold_on_lru"', '"cold_on_shutdown"', '"cold_gc_interval_seconds"', '"cold_gc_max_delete"', '"collapse_enabled"', '"collapse_wait_timeout_ms"', '"collapse_timeout_fallback"', '"stale_if_error_timeout"', '"stale_if_error_connection"', '"stale_if_error_dns"', '"stale_if_error_tls"', '"stale_if_error_statuses"', '"proactive_refresh_enabled"', '"proactive_refresh_before_expiry_seconds"', '"proactive_refresh_percent"', '"proactive_refresh_max_inflight"', '"TransformSettings"', '"TransformOverrides"', '"/api/cache/cold/cleanup"', '"/api/cache/invalidate"', '"/api/cache/bans"', '"/api/cache/bans/{id}"', '"CacheInvalidationRequest"', '"CacheInvalidationResponse"', '"ColdCleanupJob"', '"match_type"', '"regex_insensitive"', '"rewrite"', '"response"', '"covered_hosts"', '"default": true']:
assert marker in openapi, marker
for marker in ['"NotFoundHost"', '"not_found_hosts"', '"PrometheusSettings"', '"allow_trusted_network_without_token"', '"include_docker_vhosts"', '"include_streams"', '"include_logging"']:
assert marker in openapi, marker
assert 'id="panel-notfound"' in html and 'id="notfound-dialog"' in html and 'id="notfound-hosts-editor"' in html
host404_js = (root / "src/admin/web/host404.js").read_text()
for marker in ['rustProxyNotFound', 'saveSection("not_found_hosts"', 'rustProxyIntegrations.hostnames', 'rustProxyIntegrations.bindings', 'BUILTIN_STATUSES', 'ERROR_STATUSES', 'rustProxyDrafts.register("notfound"', 'rustProxyEnableControl($("notfound-enabled"))']:
assert marker in host404_js, marker
assert 'for (let code = 200; code <= 599; code++)' not in host404_js
assert 'preserve_host: true' in vhosts_js, "new HTTP/1.1 backend drafts must preserve the public Host"
assert 'id="panel-acl-profiles"' in html and 'id="acl-profile-form"' in html
for marker in ['id="acl-profile-rule-rows"', 'id="acl-profile-rule-add"', 'id="acl-profile-import-rules"', 'id="acl-profile-mode-options"', 'id="acl-profile-preview-flow"', 'id="acl-profile-country-enabled"']:
assert marker in html, marker
management = (root / "src/admin/web/management.js").read_text()
for marker in ['collectRuleRows', 'parseBulkRules', 'guidedAction', 'allow_exceptions', 'block_exceptions', 'renderPreview', 'normalizeNetwork']:
assert marker in management, marker
for marker in ['function refreshTranslations()', 'refreshTranslations }']:
assert marker in management, marker
assert 'window.rustProxyAclProfiles?.refreshTranslations?.();' in js
assert 'normalizeAclRuleText' in js and 'ruleSyntaxLine' in js
cache_source = read_cache_source()
assert not (root / "src/cache.rs").exists()
for fragment in ["mod.rs", "model.rs", "lifecycle.rs", "cold.rs", "dashboard.rs", "tickets.rs", "lookup.rs", "policy.rs", "fill.rs", "collapse.rs", "range.rs", "invalidation.rs", "tests.rs"]:
assert (root / "src/cache" / fragment).is_file(), fragment
cache_mod = rust_source(root, "src/cache/mod.rs")
assert 'impl Cache {\n include!(' not in cache_mod, "include! cannot be used directly as Cache impl items"
for fragment in ["lifecycle.rs", "cold.rs", "dashboard.rs", "tickets.rs", "lookup.rs"]:
assert rust_source(root, f"src/cache/{fragment}").lstrip().startswith("impl Cache {"), fragment
assert 'disabled_cache_strips_diagnostics_without_exposing_bypass_headers' in cache_source
for marker in ['pub enum MemoryPreset', 'pub enum ColdPreset', 'BACKGROUND_REVALIDATION_LIMIT', 'cleanup_slots']:
assert marker in cache_source, marker
for marker in ['selectedCacheMemoryPreset', 'selectedCacheColdPreset', 'applyRecommendedColdCachePreset', 'data-cache-cold-preset="recommended"']:
assert marker in js or marker in html, marker
assert 'if !self.enabled' in cache_source
proxy_source = rust_source(root, "src/proxy/mod.rs")
assert 'response.extensions().get::<LocalHostResponse>().is_none()' in proxy_source
assert '"cdn-cache-control"' in proxy_source and '"x-cache-resident-age"' in proxy_source
for marker in [
'cold_policy_can_disable_lru_demotion',
'cold_policy_can_disable_idle_demotion',
'cold_policy_can_demote_by_total_hot_residency_age',
'cold_on_age',
'cold_max_hot_seconds',
'graceful_shutdown_flush_moves_hot_objects_and_releases_resident_bytes',
'graceful_shutdown_flush_can_be_disabled',
'managed_update_flush_ignores_shutdown_toggle_when_cold_tier_is_enabled',
'pub async fn flush_hot_to_cold',
'pub async fn flush_hot_to_cold_for_update',
'cold_on_shutdown',
'vary_selects_variants_without_fragmenting_the_primary_hash',
'vary_schema_change_removes_incompatible_fallbacks',
'varnish_primary_hash_uses_host_and_url_not_unrelated_request_headers',
'resident_age_survives_successful_revalidation',
'COLD_FORMAT_VERSION: u8 = 3',
'cold_cache_uses_two_hex_character_shards',
'legacy_flat_cold_cache_is_not_migrated',
'manual_cold_cleanup_reports_removed_objects_and_freed_bytes',
'rfc5861_windows_and_revalidation_flags_are_separate_metadata',
'request_max_stale_is_bounded_and_respects_revalidation_flags',
'stale_if_error_is_only_available_inside_its_window',
'transformed_etag_is_never_used_as_an_origin_validator',
'Deduplicate only the exact cached',
'matching_hot_key',
'matching_cold_key',
'concurrent_miss_single_flight_waits_until_fill_is_published',
'single_flight_timeout_and_leader_drop_release_the_key',
'cancelled_single_flight_waiter_releases_waiter_metric',
'single_flight_retries_after_another_vary_representation_is_published',
'cached_single_range_returns_206_and_preserves_validators',
'cached_range_supports_suffix_open_unsatisfied_and_if_range',
'range_parser_rejects_multipart_and_duplicate_fields_and_if_range_date_allows_older_representation',
'stale_if_error_policy_is_configurable_by_error_class_and_status',
'proactive_refresh_guards_deduplicate_and_bound_parallel_work',
'selective_purge_exact_prefix_tag_cache_key_and_query_are_precise',
'selective_purge_is_a_barrier_for_a_fill_started_before_the_purge',
'purge_of_one_vary_variant_removes_the_whole_variant_family',
'ban_is_lazy_blocks_old_object_allows_new_fill_and_can_be_removed',
'regex_and_root_prefix_require_explicit_wide_confirmation',
'selective_purge_removes_matching_cold_object',
]:
assert marker in cache_source, marker
transform_source = rust_source(root, "src/transform/mod.rs")
for marker in [
'pub struct Settings',
'pub struct Overrides',
'resolved.enabled = global.enabled && self.enabled',
'pub fn no_transform',
'OriginValidators',
"fn decode<'a>",
'Cow::Borrowed(body)',
'trim_allocator_after_large_transform',
'pub memory_budget_bytes: usize',
'pub max_inflight: usize',
'Preset::Uber',
'try_reserve_transform_memory(required_memory, settings.memory_budget_bytes)',
'try_reserve_transform_slot(settings.max_inflight)',
'drop(decoded);',
'drop(raw);',
'rustproxy-',
]:
assert marker in transform_source, marker
assert 'collect bounded static response for transformation: {error}' in transform_source
assert '.context("collect bounded static response for transformation")' not in transform_source
lookup_source = rust_source(root, 'src/cache/lookup.rs')
model_source = rust_source(root, 'src/cache/model.rs')
css_minifier_source = rust_source(root, 'src/transform/css.rs')
assert 'let Some(_read_lease) = self.try_reserve_transient' in lookup_source
assert 'struct TransientLease {\n _inner: Arc<TransientLeaseInner>,' in model_source
assert 'struct TransientLease(Arc<TransientLeaseInner>);' not in model_source
assert 'last_char = out.chars().last();' not in css_minifier_source
assert css_minifier_source.count("last_char = Some(' ');") == 1
for name in ['js.rs', 'css.rs', 'html.rs', 'svg.rs', 'json.rs']:
assert (root / 'src/transform' / name).is_file(), name
for name in ['js.rs', 'css.rs']:
minifier_source = (root / 'src/transform' / name).read_text()
assert 'Vec<char>' not in minifier_source and '.chars().collect' not in minifier_source, name
assert 'into_bytes()' in minifier_source, name
assert 'pub mod transform;' in rust_source(root, 'src/lib.rs')
for marker in ['cache-cold-gc-interval', 'cache-cold-gc-max-delete', 'settings-tab-transform', 'transform-form', 'transform-memory-budget', 'transform-max-inflight', 'data-transform-preset="uber"', 'cache-cleanup-dialog']:
assert marker in html, marker
for marker in ['cache-transient-memory', 'cache-cold-queue-bytes', 'cache-eviction-limit', 'data-cache-memory-preset="recommended"', 'cache-memory-warning']:
assert marker in html, marker
for marker in ['effectiveCacheMemory', 'cacheMemoryHeadroom', 'cachePresetValues', 'applyCacheMemoryPreset', 'cacheMemoryPresetTooSmall', 'cacheObjectOverTransientWarning', 'cgroup_memory_max_bytes', 'transient_max_bytes', 'cold_queue_max_bytes', 'hot_eviction_max_objects']:
assert marker in js, marker
for marker in ['selectedTransformPreset', 'transformPresetValues', 'applyTransformPreset', 'updateTransformResourceSizing', 'memory_budget_bytes', 'max_inflight']:
assert marker in js, marker
assert 'envelope?.config.cache?.enabled === true && cacheToggle.value !== "off"' in vhosts_js
for marker in ['transform: { enabled: false }', 'vhTransform', 'collectTransform', 'compression: { enabled: null, gzip: null, br: null, zstd: null, deflate: null }', 'vh-compression-enabled', 'vh-compression-zstd', 'vh-compression-br', 'vh-compression-gzip', 'vh-compression-deflate', 'collectCompression']:
assert marker in vhosts_js, marker
docker_js = (root / 'src/admin/web/docker.js').read_text()
assert 'transform_enabled' in docker_js
cache_panel_js = (root / 'src/admin/web/cache-panel.js').read_text()
for marker in ['/api/cache/cold/cleanup', 'removed_entries', 'freed_bytes', '/api/cache/invalidate', '/api/cache/bans', 'cache-invalidation-operation', 'cache-invalidation-selector', 'cache-ban-ttl', 'confirm_wide', 'cachePurgeUrl']:
assert marker in cache_panel_js or marker in html, marker
for marker in ['cp-hot-entries-meter', 'cp-memory', 'cp-cold-entries-meter', 'cp-cold-disk']:
assert marker in html and marker in cache_panel_js, marker
for marker in ['data.settings?.max_entries', 'data.settings?.cold_max_entries', 'data.settings?.cold_max_bytes', 'setMeter(']:
assert marker in cache_panel_js, marker
compact_css = css.replace(" ", "")
for marker in ['progress::-webkit-progress-bar', 'progress::-webkit-progress-value', 'progress::-moz-progress-bar', '-webkit-appearance:none']:
assert marker in compact_css, marker
transform_panel_js = (root / 'src/admin/web/transform-panel.js').read_text()
for marker in ['/api/transform', 'tp-cache-hits', 'transform-reason-list']:
assert marker in transform_panel_js, marker
for marker in ['id="cache-live-chart"', 'id="cache-live-activity-chart"', 'id="cache-live-hit-line"', 'id="cache-live-miss-line"', 'id="cache-live-bypass-line"', 'id="cache-live-samples"', 'data-i18n="cacheLiveChartTitle"']:
assert marker in html, marker
for marker in ['id="transform-live-chart"', 'id="transform-live-activity-chart"', 'id="transform-live-applied-line"', 'id="transform-live-cache-line"', 'id="transform-live-skipped-line"', 'id="transform-live-error-line"', 'id="transform-live-samples"', 'data-i18n="transformLiveChartTitle"']:
assert marker in html, marker
assert '<details class="card function-live-chart" id="cache-live-chart">' in html and '<details class="card function-live-chart" id="transform-live-chart">' in html
for marker in ['liveChartSamples = { hits: [], misses: [], bypasses: [] }', 'LIVE_CHART_LIMITS = new Set([60, 120, 300, 600])', 'rustproxy.cache.liveChartSamples', 'performance.now()', 'sparklinePoints(liveChartSamples.hits, 900, 180, 10, peak)', 'slice(-liveChartLimit)']:
assert marker in cache_panel_js, marker
for marker in ['liveChartSamples = { applied: [], cache_hits: [], skipped: [], errors: [] }', 'LIVE_CHART_LIMITS = new Set([60, 120, 300, 600])', 'rustproxy.transform.liveChartSamples', 'performance.now()', 'sparklinePoints(liveChartSamples.applied, 900, 180, 10, peak)', 'slice(-liveChartLimit)']:
assert marker in transform_panel_js, marker
admin_cache_source = rust_source(root, 'src/admin/mod.rs')
for marker in ['"transform" => {', 'transform_status', 'cache_cold_cleanup', 'cache_cold_cleanup_job', 'cache_invalidate', 'cache_bans', 'cache_ban_delete', 'selective_cache_invalidation_api_manages_bans_and_rejects_wide_rules_without_confirmation']:
assert marker in admin_cache_source, marker
for marker in [
'fill_bytes_active',
'cold_queue_items',
'cold_queue_bytes',
'cold_write_bytes_active',
'cold_read_bytes_active',
'transient_bytes',
'transient_max_bytes',
'cold_queue_max_bytes',
'hot_eviction_max_objects',
'hot_logical_bytes',
'hot_allocated_bytes',
'memory_pressure_rejections',
'struct FillGauge',
'struct TransientLease',
'reserve_fill_allocation',
'release_allocator_memory()',
]:
assert marker in cache_source, marker
assert 'impl Drop for Candidate' not in cache_source, 'fill accounting must not block moving Candidate fields during finish'
redirect_source = rust_source(root, "src/redirect.rs")
for marker in ["pub struct Host", "pub struct Rule", "strip_prefix", "cache_seconds", "unconditional self-redirect"]:
assert marker in redirect_source, marker
proxy_source = rust_source(root, "src/proxy/mod.rs")
assert 'state.cache.purge(None)' not in proxy_source, 'proxy requests must not globally purge cache'
assert 'request.method() == Method::HEAD && cache_ticket.is_some()' in proxy_source
assert 'RangeSelection::Single' in proxy_source and 'request_range(request.method(), request.headers())' in proxy_source
assert 'claim_fill(ticket, cache_settings)' in proxy_source and 'cache_collapse_timeout_origin' in proxy_source
assert 'schedule_proactive_refresh' in proxy_source and 'cache_proactive_refreshed' in proxy_source
assert 'classify_stale_error' in proxy_source and 'allows_stale_error_status' in proxy_source
assert 'Varnish built-in behavior treats non-GET/HEAD methods as pass' in proxy_source
config_source = rust_source(root, "src/config.rs")
assert 'plain HTTP listener' in config_source and 'tls_ports.contains(&443)' in config_source
assert '#[serde(default)]\n pub tls_verify: bool' in config_source
assert 'backend_tls_verification_defaults_off_and_can_be_enabled_explicitly' in config_source
assert 'backend TLS server name must be the DNS name present in the certificate' in config_source
assert 'pub accept_local_listener_risk: bool' in config_source
assert 'accept_local_listener_risk = true' in config_source
for marker in [
'fallbacks: HashMap<String, Vec<CompiledRoute>>',
'id: format!("{}/main", host.id)',
'custom_locations_override_but_main_vhost_remains_fallback',
'direct_admin_listener_backend_is_marked_for_guarded_control_plane_use',
'pub targets_admin_listener: bool',
'backend_diagnostic_flags_compile_to_frontend',
'backend_header: host.backend_header',
'backend_timing_header: host.backend_timing_header',
]:
assert marker in config_source, marker
vhost_source = rust_source(root, "src/vhost.rs")
assert 'is_legacy_main_fallback' in vhost_source
assert 'values.length ? values : [{ id: "root"' not in vhosts_js
for marker in [
'OriginBackend',
'apply_backend_diagnostic_headers',
'x-rustproxy-backend-time',
'backend_diagnostics_are_opt_in_and_strip_spoofed_values',
'admin_session_passthrough',
'admin_control_plane',
'Some("admin_control_plane")',
'restore_admin_cookie',
'BEFORE returning a successful RFC 9220 response',
'websocket_phase("tunnel_ready")',
]:
assert marker in proxy_source, marker
generic_headers_source = rust_source(root, "src/headers.rs")
assert '"x-rust-proxy-backend"' in generic_headers_source and '"x-rustproxy-backend-time"' in generic_headers_source
headers_source = rust_source(root, "src/proxy/headers.rs")
for marker in ['pub fn restore_admin_cookie', 'admin_cookie_can_be_restored_only_from_captured_fragment']:
assert marker in headers_source, marker
settings_source = rust_source(root, "src/settings.rs")
for marker in ['pub session_days: u16', 'session_days: 30', '(7..=30).contains(&self.session_days)', 'administration_session_lifetime_is_7_to_30_days_and_hot_apply_only']:
assert marker in settings_source, marker
auth_source = rust_source(root, "src/auth/mod.rs")
auth_store = rust_source(root, "src/auth/store.rs")
for marker in ['30 * 24 * 60 * 60', 'session_cookie(secret: &str, secure: bool, max_age_seconds: i64)', 'browser_session_lifetime_is_configurable_without_sliding_expiry', 'session_cookie_uses_configured_remaining_lifetime']:
assert marker in auth_source, marker
for marker in ['create_browser_session', 'session_at_with_browser_lifetime', 'browser session lifetime must be 7..30 days', "created_at + ?"]:
assert marker in auth_store, marker
upstream_source = rust_source(root, "src/upstream.rs")
for marker in ['pub accept_local_listener_risk: bool', '!self_target || self.accept_local_listener_risk', 'explicit_risk_acceptance_allows_local_listener_but_not_private_policy_bypass']:
assert marker in upstream_source, marker
transport_tests = (root / "tests/transport_config.rs").read_text()
assert 'local_listener_backend_requires_explicit_risk_acceptance' in transport_tests and '127.0.0.1:9090' in transport_tests
runtime_source = rust_source(root, "src/runtime.rs")
for marker in ['fn cache_revision', 'CacheInvalidation::None', 'operational_saves_keep_cache_identity_but_cache_affecting_saves_rotate_it']:
assert marker in runtime_source, marker
admin = rust_source(root, "src/admin/mod.rs")
for marker in [
"fn admin_request_authority",
"Version::HTTP_2 | Version::HTTP_3",
"request.uri().authority().ok_or(())?",
"administration_https_health_accepts_http2_authority_without_host_header",
]:
assert marker in admin, marker
assert '"/assets/streams.js"' in (root / 'src/admin/panel_assets.rs').read_text() and '"metrics": stream_metrics' in admin
for marker in ['"/api/config/{section}"', 'async fn update_section', 'section_updates_are_revisioned_and_do_not_require_full_config_payloads', 'panel_subpage_routes_survive_browser_refresh', 'fn panel_document_path', 'panel_document_path(&path)', 'certificate_metadata', 'inspected_metadata', 'session_at_with_browser_lifetime', 'session_lifetime_seconds', 'HeaderValue::from_str(&auth::session_cookie(']:
assert marker in admin, marker
for route in ['/overview', '/vhosts', '/redirects', '/404-hosts', '/streams', '/acl-profiles', '/configuration', '/tls', '/cache', '/transform', '/logging', '/settings']:
assert f'.route("{route}", get(public::index))' in admin, route
app_js = read_app_js(root)
for marker in ['const PANEL_PATHS', 'history.pushState', 'window.addEventListener("popstate"', 'async function saveSection', 'function revalidateSession', 'Object.values(PANEL_PATHS), "/configuration"', 'certificateCovers', 'covered_hosts', 'refreshCertificateInventory', 'certificateDetails', 'certificate-domain-pills', 'certificateIssuerName', 'certificateDaysRemaining', 'certificateRenewalStatus', 'recoverInvalidOrigin', 'auth.invalid_origin', 'ORIGIN_RECOVERY_KEY']:
assert marker in app_js, marker
for marker in ['.certificate-details', '.certificate-domain-pills', '.certificate-card .pill', '.certificate-operation-card', '.renewal-meta', '#panel-tls .certificate-tabs']:
assert marker in css, marker
acme_js = (root / "src/admin/web/acme.js").read_text()
for marker in ['data-certificate-tab="installed"', 'data-certificate-tab="renewal"', 'data-certificate-tab="generate"', 'id="certificate-page-installed"', 'id="certificate-page-renewal"', 'id="certificate-page-generate"']:
assert marker in html, marker
assert 'id="certificate-dialog"' not in html and 'id="certificate-close"' not in html
for marker in ['function selectTab(name, focus = false, persist = true)', 'log_directories', 'certbotLogs', 'value?.kind?.startsWith("renewal")', 'selectTab("installed")']:
assert marker in acme_js, marker
for marker in ['resetIssueFormJob = value.job?.id || null', 'value.status === "ready"', 'resetIssueForm(); resetIssueFormJob = null', 'value.status === "failed"']:
assert marker in acme_js, marker
assert 'render(value.job); resetIssueForm();' not in acme_js, "ACME form must not reset before issuance actually succeeds"
for marker in ['id="acme-runtime-card"', 'id="acme-runtime-message"', 'id="acme-runtime-state"', 'id="acme-runtime-path"']:
assert marker in html, marker
for marker in ['function renderRuntime(value)', 'runtimeAvailable', 'certificateRuntimeUnavailable', 'acme.runtime_checking']:
assert marker in acme_js, marker
assert 'rust-proxy --data-dir ./data admin setup-token' in html
assert 'rust-proxy --data-dir /var/lib/rustproxy admin setup-token' in html
login_html_source = (root / "src/admin/web/login.html").read_text(encoding="utf-8")
assert 'rust-proxy --data-dir ./data admin setup-token' in login_html_source
assert 'rust-proxy --data-dir /var/lib/rustproxy admin setup-token' in login_html_source
login_js = (root / "src/admin/web/login.js").read_text()
assert 'const panelPaths = new Set' in login_js and 'panelPaths.has(location.pathname)' in login_js
assert '"/404-hosts"' in login_js
assert 'async function redirectExistingSession' in login_js and '/api/auth/session' in login_js
settings_js = (root / "src/admin/web/settings.js").read_text()
certificate_settings_js = (root / "src/admin/web/certificate-api.js").read_text()
assert '["/settings", "/configuration", "/logging"].includes(location.pathname)' in settings_js
assert 'new URLSearchParams(location.search).get("tab")' in settings_js and 'function syncLocation()' in settings_js and 'history.replaceState' in settings_js
assert 'url.pathname = "/settings"' in settings_js and 'url.searchParams.set("tab", active)' in settings_js
assert 'data-settings-tab="certificate-api"' in html and 'id="settings-page-certificate-api"' in html
for marker in ['data-cache-settings-tab="general"', 'data-cache-settings-tab="resilience"', 'data-cache-settings-tab="cold"', 'data-cache-settings-tab="diagnostics"']:
assert marker in html, marker
for marker in ['data-settings-tab="connections"', 'data-http-settings-tab="http2"', 'data-http-settings-tab="http3"', 'id="http2-form"', 'id="http2-listener-rows"', 'id="http3-form"', 'id="http3-listener-rows"']:
assert marker in html, marker
for marker in ['const tabAliases = { http2: "connections", headers: "policies", response: "policies" }', 'data-http-settings-tab', 'selectHttpTab("http2")']:
assert marker in settings_js or marker in html, marker
for marker in ['renderHttp2Settings', 'collectHttp2Listeners', 'http2SettingsControls', 'preservedHttp2', 'listener-h2', 'h2Configure', 'selectHttpTab?.("http2")', 'renderHttp3Settings', 'collectHttp3Listeners', 'http3SettingsControls', 'preservedHttp3', 'listener-h3', 'h3Configure', 'selectHttpTab?.("http3")']:
assert marker in integrations_js, marker
h2_settings_controls = integrations_js.split('function http2SettingsControls', 1)[1].split('const h3Defaults', 1)[0]
assert 'listener-h2' not in h2_settings_controls, 'HTTP/2 enablement belongs to the listener editor, not the tuning page'
h3_settings_controls = integrations_js.split('function http3SettingsControls', 1)[1].split('function addRow', 1)[0]
assert 'h3Enable' not in h3_settings_controls, 'HTTP/3 enablement belongs to the listener editor, not the tuning page'
for marker in ['https://git.linuxiarz.pl/gru/RustProxy', 'https://rustproxy.linuxiarz.pl/', 'data-settings-tab="system-info"', 'id="runtime-python"', 'id="acme-runtime-components"']:
assert marker in html, marker
for language in ['langs/en_US.json', 'langs/pl_pl.json']:
language_text = (root / language).read_text(encoding='utf-8')
assert './dev.sh tls deploy' not in language_text
assert '/api/certificates/{certificate_id}/reload' in language_text
assert '/etc/letsencrypt/live/example.com/fullchain.pem' in language_text
startup_source = rust_source(root, 'src/main/admin_runtime.rs')
for marker in ['https://git.linuxiarz.pl/gru/RustProxy', 'https://rustproxy.linuxiarz.pl/']:
assert marker in startup_source, marker
assert 'Python: {} (ACME mode:' not in startup_source, 'startup banner must not print speculative ACME runtime state'
for marker in ['const protocols = ["H1"]', 'endpoint.http2', 'protocols.push("H2")', 'endpoint.h2c', 'protocols.push("H2C")', 'protocols.push("H3/UDP")']:
assert marker in app_js, marker
for document in ['docs/RENEWAL.md', 'docs/INSTALL.md', 'docs/API.md']:
document_text = (root / document).read_text(encoding='utf-8')
assert './dev.sh tls deploy' not in document_text
assert '/opt/rustproxy/current/rust-proxy --data-dir /var/lib/rustproxy tls deploy' in document_text
assert '"certificate_runtime": state.acme.runtime_view()' in rust_source(root, 'src/admin/status.rs')
assert 'data-i18n="processDiagnostics">Process<' in html
for marker in ['function setOptionalMetric', 'setOptionalMetric("process-rss-anon"', 'setOptionalMetric("system-swap"', 'closest(".mini-live-chart").hidden']:
assert marker in app_js, marker
for marker in ['/api/certificate-api', 'certificate-api-form', 'certificate-api-revoke-all', 'certificate-api-credentials', 'data-cache-settings-tab']:
assert marker in settings_js or marker in certificate_settings_js or marker in html, marker
db_source = rust_source(root, "src/db.rs")
acme_source = rust_source(root, "src/acme.rs")
acme_runtime_source = (root / "src/acme/runtime_env.rs").read_text(encoding="utf-8") + (root / "src/acme/runtime_bootstrap.rs").read_text(encoding="utf-8")
assert 'runtime_setup_once' in acme_source
assert 'include!("acme/runtime_env.rs")' in (root / "src/acme.rs").read_text(encoding="utf-8")
assert 'include!("runtime_bootstrap.rs")' in (root / "src/acme/runtime_env.rs").read_text(encoding="utf-8")
for marker in ['CERTBOT_PACKAGES', 'certbot==5.8.0', 'certbot-dns-cloudflare==5.8.0', 'certbot-dns-ovh==5.8.0', 'certbot-dns-rfc2136==5.8.0', 'join("acme-python")', 'virtualenv>=20,<21', 'system_has_pip', 'distro_certbot_available', 'acme.runtime_python_missing', 'acme.runtime_pip_missing', 'acme.runtime_venv_failed', 'acme.runtime_certbot_install_failed', '--break-system-packages']:
assert marker in acme_runtime_source, marker
for marker in ['venv_certbot', 'version.arg("--version")', 'RUSTPROXY_CERTBOT_EXECUTABLE', 'managed_certbot_executable']:
assert marker in acme_runtime_source, marker
for marker in ['ACME runtime check complete', 'status = runtime.status', 'mode = runtime.mode', 'python = runtime.python', 'pip = runtime.pip', 'certbot = runtime.certbot', 'managed_env = runtime.managed_directory.as_deref().unwrap_or("-")']:
assert marker in acme_runtime_source, marker
main_source = rust_source(root, "src/main.rs")
logging_source = rust_source(root, "src/logging.rs")
secret_store_source = rust_source(root, "src/secret_store.rs")
backup_source = rust_source(root, "src/backup.rs")
config_source = rust_source(root, "src/config.rs")
acme_worker_source = (root / "scripts/runtime/acme_provider.py").read_text()
for marker in ['def certbot_prefix', 'RUSTPROXY_CERTBOT_EXECUTABLE', 'return [managed_certbot]', '[*command_prefix, "renew"', 'certbot_command(value, work, credential_file, command_prefix)']:
assert marker in acme_worker_source, marker
for feature_marker in [
"AES_256_GCM", "master.key", "O_NOFOLLOW", "migrate_acme_credentials",
"secret_store", "SecretMetadata",
]:
assert feature_marker in secret_store_source or feature_marker in db_source, feature_marker
for feature_marker in [
"Argon2", "RPROXYB1", "RPROXYA1", "backup create", "secret-store-key.enc",
"validate_backup_version", "stage", "ARCHIVE_VERSION: u32 = 2", "EntryKind::Symlink",
"try_lock_directory", "validate_snapshot_symlinks", "validate_symlink_target",
]:
assert feature_marker in backup_source or feature_marker in main_source, feature_marker
assert "VACUUM INTO" in db_source and "consistent SQLite snapshot" in db_source
for feature_marker in [
"ErrorLogSettings", "ERROR_LOG_QUEUE", "RedactingStderr", "open_error_file",
"ErrorLogLayer", "ERROR",
]:
assert feature_marker in logging_source, feature_marker
assert 'regex::Regex::new(r#"(?i)((?:authorization|' in logging_source, "KV redaction regex must use a hash-delimited raw string"
assert '[^\\s,;\"\']+" )' not in logging_source, "do not reintroduce the unterminated raw-string form in KV redaction"
assert "pub error_log: crate::logging::ErrorLogSettings" in config_source
assert "credential_ini_b64" in acme_source and "credential_ini_b64" in acme_worker_source
assert "STANDARD.encode(credential.as_slice())" in acme_source, "Base64 input must be an unambiguous byte slice"
assert "STANDARD.encode(credential.as_ref())" not in acme_source, "Zeroizing<Vec<u8>>::as_ref() is ambiguous for Engine::encode"
assert "&mut *ciphertext" in secret_store_source, "ring seal must receive the underlying Vec<u8>, not an ambiguous AsMut target"
assert "&mut *encrypted" in backup_source, "ring seal must receive the underlying Vec<u8>, not an ambiguous AsMut target"
assert "seal_in_place_append_tag(\n Nonce::assume_unique_for_key(nonce),\n Aad::from(aad(secret_id, provider)),\n ciphertext.as_mut()," not in secret_store_source
assert "seal_in_place_append_tag(\n Nonce::assume_unique_for_key(nonce_bytes),\n Aad::from(KEY_AAD),\n encrypted.as_mut()," not in backup_source
assert "finally:" in acme_worker_source and "credential_file.unlink" in acme_worker_source
for marker in ['certificate_api_credentials', 'upsert_certificate_api_credential', 'revoke_certificate_api_credential', 'verify_certificate_api_credential', '0005_certificate_api.sql', '0006_certificate_api_credentials.sql']:
assert marker in db_source, marker
for marker in ['/api/certificate-api', 'certificate_api_credentials', 'certificate_api_operation', '/api/live-logs', 'CertificateApiBearer']:
assert marker in admin or marker in openapi, marker
for marker in ['/api/certificates/{certificate_id}/reload', 'certificate_reload_one', 'reload_certificate(&certificate_id)', 'CertificateReloadOneResult', '/api/certificate-api/{key_id}']:
assert marker in admin or marker in openapi, marker
for marker in ['metric-bytes-down', 'metric-bytes-up', 'connection-chart', 'network-interface-hide', 'rp-hidden-network-interfaces']:
assert marker in html or marker in app_js or marker in (root / 'src/admin/web/style.css').read_text(), marker
assert 'valid_certificate_api_key_id' in admin and 'sleep_until(next_auth_check)' in admin
for marker in [
'livelogs: bool', 'LiveLogFilters', 'handle_live_command', 'live_logs_command',
'create_live_log_session', 'command_input_open', 'buffer.extend_from_slice(&data)',
'sse_parser_tolerates_utf8_split_across_transport_frames',
'LocalAdminCertificateVerifier', 'detect_local_admin_scheme',
'local_admin_scheme_from_probe', 'admin.uri("/api/live-logs")',
]:
assert marker in main_source or marker in rust_source(root, 'src/auth/store.rs'), marker
assert '.uri(format!("http://{addr}/api/live-logs"))' not in main_source
assert 'http://{addr}/healthz' in main_source and 'StatusCode::PERMANENT_REDIRECT' in main_source
assert 'Ok(line) if command_tx.send(line).is_ok()' not in main_source, 'do not move String from a match guard in --livelogs stdin handling'
assert 'Ok(line) => {' in main_source and 'command_tx.send(line).is_err()' in main_source
for marker in ['LIVE_STREAM_CAPACITY', 'broadcast::Sender<LogEntry>', 'pub fn subscribe']:
assert marker in logging_source, marker
assert 'SCHEMA_VERSION: i64 = 9' in db_source and 'certificate_renewals' in db_source and '0004_admin_preferences.sql' in db_source and '0005_certificate_api.sql' in db_source and '0006_certificate_api_credentials.sql' in db_source and '0007_secret_store.sql' in db_source and '0008_config_history.sql' in db_source and '0009_certificate_api_grants.sql' in db_source
for marker in ['replace_as_restore', 'config.restore', 'source_revision']:
assert marker in db_source, marker
for marker in ['restore_config_history', '/api/config/history/restore', 'expected_revision']:
assert marker in admin, marker
for marker in ['pub async fn restore_as', 'replace_as_restore']:
assert marker in runtime_source, marker
for marker in ['restoreConfigRevision', 'config-history-restore', 'configHistoryRestoreConfirm']:
assert marker in app_js or marker in html, marker
assert '"/api/config/history/restore"' in openapi
assert 'load_renewal_observations' not in acme_source and 'renewals.json' not in acme_source
for marker in ['pub kind: &\'static str', 'pub log_directory: String', 'pub(crate) fn certbot_log_directory', 'kind: "issue"', '"renewal-dry-run"']:
assert marker in acme_source, marker
assert '"log_directories":log_directories' in admin and 'crate::acme::certbot_log_directory' in admin
assert '"runtime":state.acme.runtime_view()' in admin
assert 'let cert_dir = Some(directory.clone());' in main_source, 'certificate directory must remain available after ValidationPolicy construction'
assert 'accept-remote-admin-risk' in main_source and 'hide = true' in main_source
for marker in [
'RUST_PROXY_UPDATE_REPOSITORY_URL',
'RUST_PROXY_UPDATE_VERSION_URL',
'RUST_PROXY_UPDATE_CHECK_INTERVAL_SECS',
'rust_proxy::update_check::Config::embedded()?.with_overrides(',
'state.start_update_check(update_check);',
]:
assert marker in main_source, marker
runtime_source = rust_source(root, "src/runtime.rs")
assert 'pub software_update: Arc<crate::update_check::SharedStatus>' in runtime_source
assert 'pub fn start_update_check(self: &Arc<Self>, config: crate::update_check::Config)' in runtime_source
assert 'payload["software_update"] = json!(state.software_update.snapshot());' in admin
settings_rust = rust_source(root, 'src/settings.rs')
assert 'pub struct StartupLocks' in settings_rust and 'fixed by systemd/startup' in settings_rust
logging_rust = rust_source(root, 'src/logging.rs')
assert 'pub per_vhost: bool' in logging_rust and 'default_vhost_log_directory' in logging_rust and '_unmatched' in logging_rust
pages_rust = rust_source(root, 'src/pages.rs')
assert 'validate_local_response' in pages_rust and '(200..=599).contains(&status)' in pages_rust and '204 | 205 | 304' in pages_rust
assert 'store.load_certificate_renewals().await?' in main_source and 'state.acme.restore_renewals(renewal_observations)' in main_source
assert 'renewals.json' not in main_source
upgrade_source = (root / 'scripts/deploy/upgrade.py').read_text()
assert 'legacy = certs_dir / "renewals.json"' in upgrade_source and 'removed_obsolete_runtime_state' in upgrade_source and 'legacy-data' not in upgrade_source and 'certs_dir.is_symlink()' in upgrade_source
assert '.managed-update' in main_source and 'flush_hot_to_cold_for_update' in main_source
tls_source = rust_source(root, "src/tls.rs")
assert 'pub fn validate_certificate_removals' in tls_source and 'administration panel' in tls_source
assert 'pub fn effective_cipher_suites' in tls_source
vhost_source = rust_source(root, 'src/vhost.rs')
assert 'pub websocket_rfc9220: bool' in vhost_source and 'RFC 9220 requires WebSocket support to be enabled' in vhost_source
for marker in ['pub struct ProxyTimeouts', 'connect_timeout_seconds', 'response_header_timeout_seconds', 'read_timeout_seconds', 'send_timeout_seconds']:
assert marker in vhost_source, marker
docker_source = rust_source(root, 'src/docker.rs')
for marker in ['pub poll_interval_seconds: u64', 'pub acl_profile_id: Option<String>', 'pub proxy_timeouts: crate::vhost::ProxyTimeouts', 'refresh(&self, settings: &Settings, force: bool)', 'poll_interval_seconds.saturating_mul(1000)']:
assert marker in docker_source, marker
docker_js = (root / 'src/admin/web/docker.js').read_text()
for marker in ['docker-live-refresh', 'saveAssignment(agentId, row, publish)', 'docker-acl-profile', 'docker-proxy-read', 'poll_interval_seconds']:
assert marker in docker_js, marker
agent_installer = (root / 'docker-agent/install.sh').read_text()
assert 'Bearer token:' in agent_installer and 'RUSTPROXY_DOCKER_AGENT_TOKEN=' in agent_installer
assert 'Kind::Builtin' in pages_rust and 'builtin_application_page' in pages_rust
assert 'pub covered_hosts: Vec<String>' in tls_source and 'fn certificate_dns_names' in tls_source and 'pub fn certificate_covered_hosts' in tls_source and 'legacy_certificate_coverage_can_be_read_from_existing_pem' in tls_source and 'assert_eq!(a.covered_hosts' in tls_source
acl_source = rust_source(root, 'src/acl.rs')
assert '/Ubuntu%2014.04%20LTS/' in acl_source and 'repeated_slashes_are_normalized_for_routing' in acl_source and 'merge_slashes' in acl_source
for marker in ['pub fn allows_with_country(', 'ip_action == Some(Action::Deny)', 'CountryMode::Allow', 'ip_action == Some(Action::Allow) || country_listed', 'country_allow_and_ip_allow_are_alternatives_inside_one_scope', 'country_block_and_ip_deny_are_alternatives_inside_one_scope', 'plain_host_addresses_are_valid_acl_rules', 'fn parse_network(']:
assert marker in acl_source, marker
policies_source = (root / 'tests/policies.rs').read_text()
assert 'percent_encoded_spaces_are_valid_request_paths' in policies_source and 'repeated_slashes_route_normally_but_reach_upstream_unchanged' in policies_source and 'local_location_response_uses_response_rules_without_opening_backend' in policies_source and 'local_location_response_still_respects_route_acl' in policies_source
http3_source = rust_source(root, "src/http3.rs")
drop_impl = http3_source.split('impl Drop for ReceiveBody', 1)[1].split('#[cfg(test)]', 1)[0]
assert 'self.stream.stop_sending(' not in drop_impl
for marker in ['h3::quinn::RecvStream', 'websocket_rfc9220_on(local)', 'run_h3', 'H3_REQUEST_CANCELLED']:
assert marker in http3_source or marker in rust_source(root, 'src/proxy/websocket.rs'), marker
assert 'h3_quinn' not in http3_source and 'h3_quinn' not in (root / 'tests/http3.rs').read_text()
h3_test = (root / 'tests/http3.rs').read_text()
assert 'RFC 9220: Extended CONNECT negotiates WebSocket on the same H3 stream.' in h3_test and '"websocket_rfc9220":true' in h3_test
assert 'Method::CONNECT' in h3_test and 'h3::ext::Protocol' in h3_test and '.send_data(' in h3_test
admin_source = rust_source(root, 'src/admin/mod.rs')
for marker in ['external_admin_authority', 'external_admin_scheme', 'trusted_admin_forwarded_proto', 'reverse_proxy_dns_allowlist_uses_external_port_and_keeps_direct_port_available', 'trusted_https_reverse_proxy_accepts_external_origin_and_refreshes_secure_cookie']:
assert marker in admin_source, marker
ws_source = rust_source(root, 'src/proxy/websocket.rs')
assert 'upstream: Upgraded' in ws_source
assert 'timeout(Duration::from_secs(10), upstream)' not in ws_source
for marker in ['websocket_phase("tunnel_started")', 'websocket_phase("tunnel_closed")', 'h3_reset("H3_REQUEST_CANCELLED")']:
assert marker in ws_source, marker
for marker in ['http_version', 'transport', 'websocket_bootstrap', 'websocket_phase', 'websocket_error', 'h3_reset_code', 'upstream_status']:
assert marker in rust_source(root, 'src/logging.rs'), marker
diagnostics_source = rust_source(root, 'src/diagnostics.rs') + rust_source(root, 'src/system_stats/mod.rs') + rust_source(root, 'src/system_stats/linux.rs')
for marker in ['process_rss_anon_bytes', 'process_rss_file_bytes', 'process_rss_shmem_bytes', 'process_data_bytes', 'process_swap_bytes', 'RssAnon', 'RssFile', 'RssShmem', 'VmData', 'VmSwap']:
assert marker in diagnostics_source, marker
prometheus_source = rust_source(root, 'src/prometheus.rs')
for marker in ['allow_trusted_network_without_token', 'include_traffic', 'include_docker_vhosts', 'include_streams', 'include_logging', 'rust_proxy_docker_vhost_{name}', 'rust_proxy_docker_backend_{name}', 'rust_proxy_geoip_loaded', 'not_after_timestamp_seconds', 'ewma_latency_seconds', 'passive_failures', 'active_health_failures_total', 'passive_health_failures_total', 'passive_http_5xx_total', 'passive_timeouts_total', 'passive_connect_errors_total', 'passive_io_errors_total', 'passive_slow_total', 'http_5xx_total', 'timeouts_total', 'connect_errors_total', 'io_errors_total', 'slow_responses_total', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_not_found_hosts_configured', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests', 'rust_proxy_web_services_configured', 'rust_proxy_web_service_info', 'rust_proxy_vhost_source_info', 'retry_attempts_total', 'retry_successes_total', 'upstream_client_generation', 'upstream_client_generation_requests', 'upstream_client_generation_age_seconds', 'upstream_client_rotations_total']:
assert marker in prometheus_source, marker
assert 'if docker_targets.contains_key(&pool.id)' in prometheus_source
assert 'if docker_targets.contains_key(id)' in prometheus_source
assert 'rust_proxy_docker_vhost_exchange_duration_seconds' in prometheus_source
settings_source = (root / 'src/admin/web/settings.js').read_text()
assert 'prom-trusted-no-token' in settings_source and 'include_traffic' in settings_source and 'prom-traffic' in settings_source and 'include_docker_vhosts' in settings_source and 'include_streams' in settings_source and 'include_logging' in settings_source
for marker in ['cache-memory-breakdown', 'cache-transient-breakdown', 'cache-cold-storage', 'cache-transient-sparkline', 'cache-fill-sparkline', 'cache-queue-sparkline', 'cache-io-sparkline', 'cache-cold-sparkline', 'metric-info', 'process-rss-total', 'memory-cache-hot', 'memory-cache-transient', 'memory-transform', 'memory-transform-inflight', 'memory-non-cache-rss', 'process-rss-anon', 'process-rss-file', 'process-data-swap', 'memoryAccountingHint']:
assert marker in html, marker
for marker in ['validate_h3', 'H3Tunnel', 'h3_client_to_backend', 'backend_to_h3', 'rfc9220_bootstrap_uses_extended_connect_without_h1_proof_headers']:
assert marker in ws_source, marker
for marker in ['PrefixPriority', 'RegexInsensitive', 'LocationResponse', 'pub rewrite: PathRewrite']:
assert marker in rust_source(root, 'src/vhost.rs'), marker
for marker in ['rewritten_path', 'nginx_style_location_precedence_exact_priority_regex_prefix', 'location_rewrites_are_normalized_and_regex_captures_expand', 'custom_location_response_is_validated']:
assert marker in config_source, marker
for marker in ['local_location_response', 'route.rewritten_path(&path)', 'encoded_origin_path', 'client_ip.to_string()']:
assert marker in proxy_source, marker
assert proxy_source.index('RustProxy: denied by access policy') < proxy_source.index('if let Some(spec) = &route.response') < proxy_source.index('let (backend, backend_lease, affinity_cookie)')
for marker in ['location-help-dialog', 'cache-memory-sparkline', 'cache-hit-sparkline', 'cache-miss-sparkline', 'cache-bypass-sparkline', 'process-cpu-sparkline', 'process-rss-sparkline', 'network-rx-sparkline', 'latency-sparkline', 'sourceIp']:
assert marker in html, marker
for marker in ['locationMatchRegex', 'headersVisualBuilder', 'headersAdvancedJson', 'openLocationHelp', 'locationPreviewTitle', 'location-preview-grid', 'vh-header-rule-fields', 'cloudflare-client-ip', 'timing-headers']:
assert marker in vhosts_js, marker
for marker in ['lastApiLatencyMs', 'cacheMemorySamples', 'cacheTransientSamples', 'cacheColdStorageSamples', 'cacheHitSamples', 'processCpuSamples', 'processRssSamples', 'networkRxSamples', 'responseLatencySamples', 'client_ip']:
assert marker in app_js, marker
logging_source = rust_source(root, 'src/logging.rs')
assert 'pub client_ip: Option<String>' in logging_source and '"client_ip" => entry' in logging_source and '.client_ip' in logging_source
for marker in ['check_rustproxy_api', 'response time', 'backend']:
assert marker in (root / 'nagios/README.md').read_text(), marker
stream_source = rust_source(root, "src/stream.rs")
for marker in ["pub struct Metrics", "pub struct MetricsView", "struct ActiveSession", "sessions_total", "sessions_completed", "packets_in", "packets_out", "metrics_view_reports_l4_counters"]:
assert marker in stream_source, marker
transport_doc = (root / "docs/TRANSPORT.md").read_text()
security_doc = (root / "docs/SECURITY.md").read_text()
api_access_doc = (root / "docs/API_ACCESS.md").read_text()
assert 'accept_local_listener_risk: true' in transport_doc and '127.0.0.1:9090' in transport_doc
assert 'accept_local_listener_risk=true' in security_doc and 'including port 9090' in security_doc
assert '7–30' in api_access_doc and 'default 30' in api_access_doc
not_found_source = rust_source(root, 'src/not_found.rs')
for marker in ['pub struct Host', 'pub struct CompiledHost', 'default_status', 'crate::pages::Page']:
assert marker in not_found_source, marker
pages_source = rust_source(root, 'src/pages.rs')
assert 'pub struct MinimalWelcome' in pages_source and 'HeaderValue::from_static("no-store")' in pages_source
assert 'builtin_welcome_is_minimal_and_never_cacheable' in pages_source
assert 'minimal_welcome' in proxy_source and 'cache-control' in proxy_source
make_zip = (root / "make_zip.py").read_text()
for marker in ["SOURCE_DATE_EPOCH", "ZipInfo", "deterministic_mode", "compresslevel=9"]:
assert marker in make_zip, marker
assert "'debian'" not in make_zip and "'grafana'" in make_zip and "'docker-agent'" in make_zip
assert "'UPDATE_CHECK.toml'" in make_zip
# Debian packaging is maintained outside this source tree.
assert not (root / 'debian').exists()
grafana = json.loads((root / 'grafana/rustproxy-overview.json').read_text())
assert grafana['uid'] == 'rustproxy-0170' and grafana['schemaVersion'] >= 39
expressions = '\n'.join(target.get('expr','') for panel in grafana['panels'] for target in panel.get('targets',[]))
for marker in ['rust_proxy_process_rss_bytes', 'rust_proxy_cache_transient_bytes', 'rust_proxy_backend_latency_seconds', 'rust_proxy_stream_active', 'rust_proxy_log_sink_queue_dropped_total', 'rust_proxy_traffic_source_requests_total', 'rust_proxy_traffic_country_requests', 'rust_proxy_traffic_user_agent_family_requests_total', 'rust_proxy_traffic_country_capture_enabled', 'rust_proxy_traffic_user_agent_capture_enabled', 'rust_proxy_traffic_route_requests', 'rust_proxy_backend_upstream_client_generation_requests', 'rust_proxy_backend_upstream_client_generation_age_seconds', 'rust_proxy_backend_retry_attempts_total', 'rust_proxy_backend_upstream_client_rotations_total', 'rust_proxy_docker_backend_upstream_client_generation_requests', 'rust_proxy_docker_backend_retry_attempts_total']:
assert marker in expressions, marker
assert any(variable.get('name') == 'traffic_vhost' for variable in grafana['templating']['list'])
assert any(panel.get('title') == 'Traffic analytics and Web Server' for panel in grafana['panels'])
assert any(panel.get('title') == 'Traffic capture state' for panel in grafana['panels'])
assert any(panel.get('title') == 'Top configured routes' for panel in grafana['panels'])
# 0.27.3 compression/protocol/dashboard UX regressions.
compression_source = rust_source(root, "src/compression.rs")
route_cache_source = rust_source(root, "src/proxy/forward/route_cache.rs")
backup_source = rust_source(root, "src/backup.rs")
rate_limit_source = rust_source(root, "src/rate_limit.rs")
metrics_source = rust_source(root, "src/metrics.rs")
admin_source = rust_source(root, "src/admin/mod.rs")
style_source = (root / "src/admin/web/style.css").read_text()
docker_ui = (root / "src/admin/web/docker.js").read_text()
for marker in ["pub enum AppliedEncoding", "AppliedEncoding::Gzip", "AppliedEncoding::Brotli", "AppliedEncoding::Zstd", "AppliedEncoding::Deflate"]:
assert marker in compression_source, marker
for marker in [
"gzip: true", "br: true", "zstd: true", "deflate: false",
"const PREFERENCE: [Self; 4] = [Self::Zstd, Self::Brotli, Self::Gzip, Self::Deflate]",
"fn preferred_encoding", "pub struct Overrides", "pub fn scoped", "pub fn resolve",
"defaults_enable_modern_compression_without_deflate",
"equal_quality_uses_zstd_then_br_then_gzip_then_deflate",
"quality_weights_win_before_server_priority",
"cookies_authorization_and_private_cache_policy_do_not_disable_compression",
"existing_content_encoding_is_never_recompressed",
"no_transform_range_and_sse_are_not_compressed",
"age_header_survives_downstream_compression",
"CompressionLevel::Fastest",
]:
assert marker in compression_source, marker
assert "request.method() == Method::GET || request.method() == Method::HEAD" in route_cache_source
for marker in ['"acme-python"', '"acme_python"']:
assert marker in backup_source, marker
for marker in [
"buckets: HashMap<String, HashMap<IpAddr, Bucket>>",
"state.sweep_expired(now, false)",
"state.sweep_expired(now, true)",
]:
assert marker in rate_limit_source, marker
for forbidden in ["pub struct AllowCookie", "private_or_no_transform"]:
assert forbidden not in compression_source, forbidden
compression_finalize_source = rust_source(root, "src/proxy/upstream_helpers.rs")
assert "let global_compression = &snapshot.envelope.config.compression" in compression_finalize_source
for selector in ("frontend", "service"):
# rustfmt splits member chains across lines; check the expression, not its layout.
assert re.search(rf"\b{selector}\s*\.\s*compression\s*\.\s*resolve\(global_compression, &compression\)", compression_finalize_source), selector
assert "AllowCookie" not in compression_finalize_source
openapi_0270 = json.loads((root / "src/admin/openapi.json").read_text())
compression_override_properties = openapi_0270["components"]["schemas"]["CompressionOverrides"]["properties"]
for prop in ["enabled", "zstd", "br", "gzip", "deflate"]:
assert prop in compression_override_properties, prop
docker_assignment_properties = openapi_0270["components"]["schemas"]["DockerAssignment"]["properties"]
for prop in ["compression_enabled", "compression_zstd", "compression_br", "compression_gzip", "compression_deflate"]:
assert prop in docker_assignment_properties, prop
web_service_ui_0270 = (root / "src/admin/web/web-server.js").read_text()
for marker in [
'vh-compression-options',
'compressionOptions.hidden = disabled',
'input.disabled = disabled',
]:
assert marker in vhosts_js, marker
for marker in [
'compressionEnabled.checked = assignment?.compression_enabled !== false',
'compression_zstd: null, compression_br: null, compression_gzip: null, compression_deflate: null',
'switches.append(preserveLabel, forceSslField, websocketField, cacheField, compressionField, transformField)',
]:
assert marker in docker_ui, marker
for forbidden in ['.docker-compression-zstd', '.docker-compression-br', '.docker-compression-gzip', '.docker-compression-deflate', 'compressionSelect(']:
assert forbidden not in docker_ui, forbidden
assert 'id="web-service-compression-options"' in html
for marker in [
'function syncCompression()',
'$("web-service-compression-options").hidden = disabled',
'$(`web-service-compression-${name}`).disabled = disabled',
'$("web-service-compression").addEventListener("change", syncCompression)',
]:
assert marker in web_service_ui_0270, marker
settings_source_0270 = rust_source(root, "src/settings.rs")
config_model_0270 = rust_source(root, "src/config/model.rs")
for marker in ['mode: ServerMode::Custom', 'value: "RustProxy".into()', 'legacy_compat_default']:
assert marker in settings_source_0270, marker
assert 'default = "legacy_server_header_default"' in config_model_0270
headers_source_0267 = rust_source(root, "src/headers.rs")
vhost_core_0267 = (root / "src/admin/web/vhosts/core.js").read_text()
for marker in [
'pub fn apply_wire_age',
'wire_only: bool',
'wire_only: direction == Direction::Response',
'rule.name.eq_ignore_ascii_case("age")',
'if !rule.wire_only',
]:
assert marker in headers_source_0267, marker
assert '["host", "connection", "content-length"' in vhost_core_0267, "UI protected header set must stay intact"
assert '["host", "age", "connection"' not in vhost_core_0267, "0.26.6 Age rules must remain UI-loadable"
assert 'apply_response_age_rules(' in compression_finalize_source, "Age wire rules must run in final response stage"
compression_tester_0267 = (root / "tools/dev/test_compression.py").read_text()
for marker in ["--revalidate", "if revalidate:", 'headers["Cache-Control"] = "no-cache"', "headers.get('Age', '-')"]:
assert marker in compression_tester_0267, marker
assert "cache_hit_and_dashboard_age_advance_from_storage_clock" in read_cache_source()
diagnostics_source = rust_source(root, "src/diagnostics.rs") + rust_source(root, "src/system_stats/mod.rs") + rust_source(root, "src/system_stats/linux.rs")
for marker in ["pub struct NetworkInterfaceView", "pub network_interfaces: Vec<NetworkInterfaceView>", "sysinfo::Networks::new_with_refreshed_list", "system.network_stats", "collect_network_systemstat", "normalize_network_interfaces", "merge_network_interfaces"]:
assert marker in diagnostics_source, marker
assert "interfaces.truncate(64)" not in diagnostics_source, "network inventory must not silently truncate interfaces"
for marker in ["pub http1_requests: AtomicU64", "pub fn record_compression", "each_codec_has_an_independent_counter", "http1_requests_total"]:
assert marker in metrics_source, marker
assert "state.metrics.record_compression(encoding)" in proxy_source
assert "sparkline-h1" in html and "sparkline-h2" in html and "sparkline-h3" in html
assert 'id="open-proxy"' not in html and '$("open-proxy")' not in app_js
assert "protocolSamples" in app_js and "m.http1_requests" in app_js
assert "renderNetworkInterfaceCharts" in app_js and "networkInterfaceSamples" in app_js
assert 'id="network-interface-charts"' in html
assert 'compressionCountersHelp' not in html
assert "dockerOpenApp" in docker_ui and "proxiedUrl(agent, hostname)" in docker_ui
# 0.19.0 Docker-vhost controls: chip aliases, default agent ACL, redirect/WebSockets/cache.
docker_source = rust_source(root, "src/docker.rs")
management_ui = (root / "src/admin/web/management.js").read_text()
for marker in ["function aliasEditor(", "host-chip-editor docker-alias-editor", ".docker-force-ssl", ".docker-websockets", ".docker-cache-enabled", ".docker-compression-enabled", ".docker-agent-acl-profile"]:
assert marker in docker_ui, marker
for marker in ['"force_ssl": assignment.force_ssl.unwrap_or(false)', '"websockets": assignment.websockets', '"enabled": assignment.compression_enabled', '"cache": {"enabled": assignment.cache_enabled}', 'assignment.acl_profile_id.clone().or_else(|| agent.acl_profile_id.clone())', 'host.transient_unavailable = target.is_none()', 'inventory: previous_inventory']:
assert marker in docker_source, marker
for marker in ["published_assignment_stays_routable_as_503_when_service_is_missing", "failed_agent_observation_with_last_inventory_keeps_backend_materialized", "disabling_agent_stops_discovery_but_keeps_published_hostname_as_503"]:
assert marker in docker_source, marker
route_cache_0270 = rust_source(root, "src/proxy/forward/route_cache.rs")
for marker in ['if route.unavailable', 'StatusCode::SERVICE_UNAVAILABLE', 'published Docker service is currently unavailable', 'retry-after']:
assert marker in route_cache_0270, marker
assert "agent.acl_profile_id === profile.id" in management_ui
assert 'payload["backend_pool_domains"]' in admin_source and "status.backend_pool_domains" in vhosts_js
assert 'body[data-density="compact"]' in style_source and '--ui-control: 22px' in style_source
assert 'rust_proxy_http1_requests_total' in expressions
vhost_source = rust_source(root, "src/vhost.rs")
for marker in ["DEFAULT_PROXY_CONNECT_TIMEOUT_SECONDS: u64 = 10", "DEFAULT_PROXY_RESPONSE_HEADER_TIMEOUT_SECONDS: u64 = 120", "DEFAULT_PROXY_READ_TIMEOUT_SECONDS: u64 = 60", "DEFAULT_PROXY_SEND_TIMEOUT_SECONDS: u64 = 60", "proxy_timeouts_have_explicit_safe_defaults_but_keep_null_compatibility"]:
assert marker in vhost_source, marker
assert 'defaultProxyTimeouts = () => ({ connect_timeout_seconds: 10, response_header_timeout_seconds: 120, read_timeout_seconds: 60, send_timeout_seconds: 60 })' in vhosts_js
assert 'actions.append(enabledLabel, stateBadge, remove)' in docker_ui
assert 'row._readListeners = listenerControl.read' in docker_ui and '.docker-agent-listeners' not in docker_ui
assert 'docker-agent-status-badge' in style_source and 'justify-content: center' in style_source
assert '.docker-agent-grid>label' in style_source and '#docker-agent-add' in style_source and 'margin-top: 14px' in style_source
assert '<details class="mini-live-chart mini-live-chart-collapsible">' not in html
assert 'data-i18n="responseLatencyHistory"' in html and 'data-i18n="responseLatencyHint"' in html and 'data-i18n-aria="responseLatencyInfo"' in html
assert 'viewBox: "0 0 300 60"' in app_js and 'M0 15H300 M0 30H300 M0 45H300' in app_js
assert '.network-interface-row {' in style_source and 'background: transparent' in style_source
assert 'function checkboxField(key, control)' in docker_ui and 'checkboxField("dockerPreserveHost", preserve)' in docker_ui and 'checkboxField("dockerAclInline", inline)' in docker_ui
assert 'label = el("label", undefined, "check vh-check")' in docker_ui and 'check compact-check' not in docker_ui.split('function checkboxField(key, control)', 1)[1].split('function aliasEditor(', 1)[0]
assert '.docker-route-grid input:not([type="checkbox"])' in style_source and '.docker-checkbox-field .vh-check {' in style_source
assert 'docker-switch-row' in docker_ui and '.docker-switch-row {' in style_source and 'repeat(5, minmax(110px, 160px))' in style_source
assert '.docker-passive-health-editor .docker-health-grid {' in style_source
assert '.docker-health-grid input:not([type="checkbox"])' in style_source and '.docker-passive-health-editor .docker-checkbox-field input[type="checkbox"]' in style_source
assert 'id="sparkline-transform"' in html and 'id="rate-transform"' in html and 'liveTransformed' in html
assert 'payload["transform_metrics"] = json!(state.transform_metrics.total())' in admin_source
for marker in ['payload["transform_resources"]', 'payload["memory_accounting"]', 'non_cache_rss_includes_transform']:
assert marker in admin_source, marker
assert 'const transformed = s.transform_metrics || {}' in app_js and 'transformSamples.push(rates.transform)' in app_js
for marker in ['status.memory_accounting || {}', 'memory.cache_hot_bytes', 'memory.transform_reserved_bytes', 'cache-cold-storage']:
assert marker in app_js, marker
for marker in ['data?.resources || {}', 'tp-memory', 'tp-inflight']:
assert marker in transform_panel_js, marker
assert 'function uptime(value)' in app_js and 'setOptionalMetric("process-uptime", status.uptime_seconds != null' in app_js
assert 'connection-uptime-footer' not in html and 'id="process-uptime"' in html
assert 'id="panel-transform"' in html and 'data-panel="transform"' in html and 'include_str!("web/transform-panel.js")' in (root / 'src/admin/router.rs').read_text()
assert '/api/transform' in transform_panel_js and 'tp-cache-hits' in transform_panel_js and 'transform-reason-list' in transform_panel_js
assert '--transform-chart:' in css and '--chart-quaternary:' in css and 'stroke: var(--chart-quaternary)' in css and 'background: var(--transform-chart)' in css
assert '.cache-transform-badge {' in css and 'border: 1px solid var(--pill-line)' in css and 'border-radius: 3px' in css
assert 'pub transformed: bool' in cache_source and 'annotate_transformed' in cache_source and 'format!("{base}; transformed")' in cache_source
assert 'x-cache-status' in cache_source and 'Cache-Status (RFC 9211)' in html
assert 'generated_vhost_inherits_global_server_header_policy' in docker_source and 'effective.vhosts[0].server_header.is_none()' in docker_source
assert '.insert("x-rustproxy-backend-time", value)' in proxy_source and '.insert("x-rust-proxy-backend-time", value)' not in proxy_source
assert 'x-rustproxy-backend-time' in rust_source(root, "src/headers.rs")
# Expanded upstream connection diagnostics must retain nested Hyper/rustls/io causes.
for marker in [
"fn format_error_chain(",
"MAX_UPSTREAM_ERROR_DETAIL: usize = 2048",
"error_chain={chain}",
"request_origin={}",
"tls_verify={}",
"upstream_error_chain_keeps_nested_connector_cause",
"tracing::warn!(",
]:
assert marker in proxy_source, marker
assert "pub tls_verify: bool" in config_source and "tls_verify: backend.tls_verify" in config_source
assert 'data-i18n="logUpstreamError"' in html and 'e.upstream_error || "-"' in management_ui
assert '.route("/api/preferences", get(preferences).put(update_preferences))' in admin
assert 'admin_preferences' in (root / "migrations/0004_admin_preferences.sql").read_text()
assert 'id="log-column-options"' in html and 'data-log-column="upstream_error"' in html
assert 'check log-column-option' in management_ui
assert 'input[type="checkbox"],\ninput[type="radio"] {' in style_source and 'width: 15px;' in style_source and '.log-column-option input[type="checkbox"]' not in style_source
assert '.log-tools input:not([type="checkbox"]):not([type="radio"])' in style_source
assert '.log-tools input {\n' not in style_source, "Live Logs text-input rules must not match checkbox/radio controls"
footer_block = app_js.split('function renderFooter(s) {', 1)[1].split('let lastLogs', 1)[0]
assert 'SQLite / HTTP/1.1' not in footer_block and 'coldQ:' not in footer_block and 'streamFallback' not in footer_block
assert '`${apiLatency} / ${t("logsDropped")}: ${s.logs_dropped}`' in footer_block
assert 'update?.update_available && update.latest_version' in footer_block and 'footer-update' in footer_block
assert '.page-footer .footer-update {' in style_source
assert '.logs-dialog {' in style_source and 'overflow: visible' in style_source
assert '/api/preferences' in app_js and 'live_log_columns' in management_ui and 'ADMIN_THEMES = new Set(["dark", "ultra_dark", "light", "cream"])' in app_js
assert 'id="ui-theme"' in html and 'data-i18n="themeLight"' in html
assert 'html[data-theme="light"] {' in style_source and '--field-bg:' in style_source and '--sidebar-bg:' in style_source
assert 'overflow: visible;' in style_source and 'max-height: min(38dvh, 220px)' not in style_source
assert 'body[data-density="compact"] input:not([type="checkbox"]):not([type="radio"])' in style_source
assert 'input:not([type="checkbox"]):not([type="radio"]),\nselect,\ntextarea {' in style_source
assert '#[serde(default = "default_admin_theme")]' in admin_source and re.search(r'matches!\(\s*preferences\.theme\.as_str\(\),\s*"dark" \| "ultra_dark" \| "light" \| "cream"\s*\)', admin_source)
# 0.22.3 dashboard/config/cache/log-history regressions.
assert 'bindSettingsForm("pages-form", next => { next.pages = global.read(); }, "pages")' in management_ui
assert '"pages" => {' in admin_source and 'config.pages =' in admin_source
assert 'default_pages_section_accepts_the_standard_value_payload' in admin_source
logging_source = rust_source(root, "src/logging.rs")
assert 'pub const LIVE_WINDOW: usize = 256;' in logging_source
assert 'pub const HISTORY_CAPACITY: usize = 4096;' in logging_source
assert 'retained_history_is_larger_than_the_live_snapshot_but_still_bounded' in logging_source
assert 'id="logs-load-history"' in html and 'api("/api/logs?limit=4096")' in management_ui
assert 'const STATUS_NAMES = { 200: "OK"' in management_ui and '404: "Not Found"' in management_ui and 'statusLabel(code)' in management_ui
assert 'let paused = null, expanded = null' in management_ui and 'function mergeExpanded(data)' in management_ui and 'entries.length >= 4096' in management_ui
assert 'dialog.addEventListener("close", () => { if (pinning) return; expanded = null; paused = null;' in management_ui
cache_source = read_cache_source()
assert 'hash_scheme.as_bytes()' in cache_source and 'cache_key_separates_frontend_scheme' in cache_source
assert 'function rateBytes(value)' in app_js and 'if (value === 0) return "0.0 KiB";' in app_js and 'return "<0.1 KiB";' in app_js
assert 'function backendTrafficRate(' in vhosts_js and 'member.bytes_in' in vhosts_js and 'member.bytes_out' in vhosts_js and 'rateBytes(memberTraffic)' in vhosts_js and 'rateBytes(d.traffic)' in vhosts_js
cache_panel_js = (root / "src/admin/web/cache-panel.js").read_text()
traffic_panel_js = (root / "src/admin/web/traffic-panel.js").read_text()
assert 'id="panel-traffic"' in html and 'data-panel="traffic"' in html
for marker in ['/api/traffic', 'trafficTopCountries', 'trafficTopUserAgents', 'trafficTopClientIps', 'traffic-donut', 'rustProxyTrafficPanel']:
assert marker in traffic_panel_js or marker in html, marker
traffic_source = rust_source(root, "src/traffic.rs")
for marker in ['QUEUE_CAPACITY: usize = 2048', 'TOP_CAPACITY: usize = 32', 'MAX_VHOSTS: usize = 64', 'self.tx.try_send(sample)', 'client_ips: TopTable']:
assert marker in traffic_source, marker
forwarding_source = rust_source(root, "src/forwarding.rs")
for marker in ['pub fn cloudflare_country', 'headers.get_all("cf-ipcountry")', 'country != "XX"']:
assert marker in forwarding_source, marker
forward_entry_source = rust_source(root, "src/proxy/forward_entry.rs")
for marker in ['cloudflare_country = crate::forwarding::cloudflare_country', '.or_else(|| state.geoip.load().country(context.client_ip))']:
assert marker in forward_entry_source, marker
assert forward_entry_source.count('crate::acl::allows_with_country(') >= 4, "profile/vhost/location access scopes must use composed IP+country evaluation"
route_cache_source = rust_source(root, "src/proxy/forward/route_cache.rs")
assert 'Do not re-evaluate IP ACLs in isolation here' in route_cache_source
assert 'if (envelope) render();' in (root / "src/admin/web/web-server.js").read_text()
assert 'pub capture_user_agent: bool' in logging_source and 'pub capture_country: bool' in logging_source
assert 'spawn_blocking(crate::diagnostics::trim_allocator)' in rust_source(root, 'src/runtime.rs')
assert 'fn trim_hot_idle(&self)' in cache_source and 'hot_auto_trim_target_percent' in cache_source
assert 'id="cache-domain-filter"' in html and 'cacheDomainFilterEnabled' in html and 'cacheDomainFilterDisabled' in html
assert 'const visibleDomains = (data, groups) =>' in cache_panel_js and 'scoped?.settings?.enabled ?? data.settings?.enabled ?? false' in cache_panel_js
assert 'groups = d.domains || [], shownGroups = visibleDomains(data, groups)' in cache_panel_js
assert 'replaceChildren(...shownGroups.map(row =>' in cache_panel_js
balance_source = rust_source(root, 'src/balance.rs')
assert 'traffic_rate_drops_to_zero_after_an_idle_sample_window' in balance_source and 'if delta == 0 {' in balance_source and 'sample.rate = 0.0;' in balance_source
all_admin_js = "\n".join(path.read_text() for path in (root / "src/admin/web").glob("*.js"))
assert not re.search(r'(?<![A-Za-z])(?:window\.)?(?:alert|confirm)\s*\(', all_admin_js), "native browser alert/confirm returned"
assert 'function appConfirm(message, options = {})' in app_js and 'function apiErrorMessage(path, response, value)' in app_js
assert '.app-confirm-dialog {' in style_source and '.login-section #auth-message.error {' in style_source
assert 'classList.toggle("error", Boolean(value))' in login_js
assert 'class="auth-page auth-loading"' in (root / 'src/admin/web/login.html').read_text() and 'const reveal = () => document.body.classList.remove("auth-loading")' in login_js
assert '"/docker-vhosts"' in login_js and 'settingsTabs = new Set' in login_js and '`/settings?tab=${encodeURIComponent(tab)}`' in login_js
assert 'class="app-loading"' in html and 'document.documentElement.classList.remove("app-loading")' in app_js
assert 'id="mobile-menu-toggle"' in html and 'id="main-navigation"' in html and 'aria-controls="main-navigation"' in html
assert '.sidebar.mobile-nav-open .main-navigation' in style_source and 'display: none;' in style_source and 'grid-template-columns: repeat(2, minmax(0, 1fr))' in style_source
assert 'function setMobileMenu(open)' in app_js and 'setPanel(button.dataset.panel); setMobileMenu(false);' in app_js and 'event.key === "Escape"' in app_js
assert 'id="about-open"' in html and 'id="about-dialog"' in html and 'Mateusz Gruszczynski' in html
assert 'https://git.linuxiarz.pl/gru/RustProxy' in html and 'data-i18n="documentation" id="api-docs"' in html
assert '$("about-open").addEventListener("click"' in app_js and '$("about-close").addEventListener("click"' in app_js
assert '.about-dialog {' in style_source and '.about-meta {' in style_source and '.top-actions {\n width: 100%;\n flex-wrap: wrap;' in style_source
assert 'function withFormSubmitState(form, submitter, task)' in app_js and 'button.textContent = t("saving")' in app_js
assert 'function fieldError(target, message)' in app_js and 'function showFieldError(error, form = null)' in app_js
assert 'function authReturnDestination()' in app_js and 'pendingAuthDestination || authReturnDestination()' in app_js
assert '$("login").hidden = navigating' in app_js and 'id="auth-message"' in html
assert 'settings-tabs button.has-unsaved::after' in style_source and 'function syncSettingsDirtyIndicators()' in app_js
assert 'setSettingsDirty("config-editor")' in app_js and '!settingsDirty.has("config-editor")' in app_js
assert 'throw fieldError($("tls-policy-12")' in settings_js
integrations_ui_0194 = (root / 'src/admin/web/integrations.js').read_text()
docker_ui_0194 = (root / 'src/admin/web/docker.js').read_text()
assert 'readAddresses.input' in integrations_ui_0194
assert 'form.reset(); window.rustProxyCertificates?.close();' in integrations_ui_0194
assert '$("cert-import-pem").value = ""' not in integrations_ui_0194 and '$("cert-import-key").value = ""' not in integrations_ui_0194
assert 'throw fieldError(row.querySelector(".docker-agent-listener-choices")' in docker_ui_0194
assert '#docker-agents-form>.form-actions {' in style_source and 'justify-content: flex-start' in style_source
deploy_source = read_deploy_source()
assert "SHELL_PATH_PROFILE = Path('/etc/profile.d/rustproxy-path.sh')" in deploy_source
assert 'install_shell_path(prefix)' in deploy_source and 'check_shell_path(prefix)' in deploy_source and 'install_logrotate(' in deploy_source and "'shell_path_action':'install-or-repair'" in deploy_source
assert 'grid-template-columns: minmax(0, 1fr)' in style_source and '.log-column-option:hover' in style_source
assert '.check>span {' in style_source and 'transform: translateY(-1px)' in style_source and '.cache-toolbar-status .check' in style_source and '.docker-toolbar .check' in style_source and 'grid-column: span 3' in style_source
assert '.docker-alias-field>span:first-child {' in style_source and 'margin-bottom: 0' in style_source and '.docker-alias-editor {' in style_source and 'min-height: 38px' in style_source and 'height: 30px' in style_source
assert 'field.append(box, el("small", t("dockerAliasesHelp")' not in docker_ui
assert 'readOnly: !!editing' not in vhosts_js and 'vhIdRenameConfirm' in vhosts_js and 'v.id === value.id && v.id !== editing' in vhosts_js
assert 'enforce_local_page_no_cache' in proxy_source and 'LocalGeneratedResponse' in proxy_source and 'get::<crate::pages::PageServed>()' in proxy_source and '.is_none()' in proxy_source
assert 'locally_generated_pages_remove_cache_metadata' in proxy_source and '"x-cache-reason"' in proxy_source and '"cache-status"' in proxy_source
assert 'local_page_method_rejection_is_still_marked_non_cacheable' in pages_rust and 'response.extensions_mut().insert(PageServed);' in pages_rust
assert "rel.as_posix() == 'docker-agent/docker-agent'" in (root / 'make_zip.py').read_text()
screenshots = {path.name for path in (root / "docs/screenshots").iterdir() if path.is_file()}
assert "README.md" in screenshots, screenshots
assert screenshots <= {"README.md", "login.png", "location-headers.png"}, screenshots
assert 'Historical or version-labelled context' in (root / "docs/README.md").read_text()
assert '<span class="version">' not in html, "duplicate top-right version label returned"
assert '<div class="edition">INDEPENDENT BY DESIGN <span>' not in html, "release version returned beside the dashboard brand"
assert '<div class="edition">INDEPENDENT BY DESIGN</div>' in html
# tls_verify=false must not feed legacy appliance certificates back through webpki.
upstream_source = rust_source(root, "src/upstream.rs")
assert "BackendCertificateVerificationDisabled" in upstream_source and "supported_schemes" in upstream_source
disabled_verifier = upstream_source.split("impl ServerCertVerifier for BackendCertificateVerificationDisabled", 1)[1].split("pub fn client(", 1)[0]
assert disabled_verifier.count("Ok(HandshakeSignatureValid::assertion())") == 2
assert "WebPkiServerVerifier" not in disabled_verifier
assert '.docker-route-grid {' in style_source and 'align-items: start' in style_source and '.docker-acl-grid {' in style_source
# 0.22.3 cache-modal, RFC8441/h2c and active-tunnel contracts.
server_source = rust_source(root, "src/server.rs")
websocket_source = rust_source(root, "src/proxy/websocket.rs")
vhost_source = rust_source(root, "src/vhost.rs")
integrations_0221 = (root / "src/admin/web/integrations.js").read_text()
http2_test = (root / "tests/http2.rs").read_text()
transport_test = (root / "tests/transport_config.rs").read_text()
for marker_0221 in [
'id="cache-invalidation-open"', 'id="cache-bans-open"',
'id="cache-invalidation-dialog"', 'id="cache-bans-dialog"',
'id="cache-toolbar-operation-status"', 'id="tunnels-dialog"',
'id="tunnel-kill-reason"', 'id="metric-ws-h1"', 'id="metric-ws-h2"',
'id="metric-ws-h3"', 'id="metric-ws-total"',
]:
assert marker_0221 in html, marker_0221
for marker_0221 in [
'const operationMessage = (id, value = "", error = false) => {',
'if (!box) return;', 'cache-toolbar-operation-status',
'runInvalidation(payload, messageTarget = "cache-invalidation-status")',
'async function copyText(value)', 'function makeCopyCell(value)',
'target = makeCopyCell(targetValue)', 'makeCopyCell(keyTags)',
]:
assert marker_0221 in cache_panel_js, marker_0221
assert re.search(r'class="[^"]*\bstats-grid\b[^"]*"', html) is not None
assert 'stats-grid transport-stats' not in html and 'transport-websocket' not in html
assert 'transport-action' not in html and '.transport-grid .transport-action' not in style_source
assert '#panel-cache .cache-copy-cell' in style_source and 'cursor: copy' in style_source
assert '.operation-message' in style_source and '.operation-message.error' in style_source
for marker_0221 in [
'api("/api/tunnels", context?.signal ? { signal: context.signal } : {})', 'tunnel-kill-reason', 'tunnelKillReasonDefault',
'api(`/api/tunnels/${encodeURIComponent(item.id)}/kill`', 'startTunnelRefresh()',
]:
assert marker_0221 in app_js, marker_0221
assert 'pub websocket_rfc8441: bool' in vhost_source
assert 'pub h2c: bool' in vhost_source
assert 'h2c is available only on cleartext listeners' in vhost_source
for marker_0221 in [
'websocket_rfc8441_on(&self, local: SocketAddr, tls: bool)',
'binding.h2c', 'HTTP/2-capable listener',
'websocket_rfc8441: host.websocket_rfc8441',
]:
assert marker_0221 in config_source, marker_0221
for marker_0221 in [
'HTTP2_PRIOR_KNOWLEDGE_PREFACE', 'h2_prior_knowledge_prefix',
'builder.enable_connect_protocol()', 'websocket_rfc8441_on(local, false)',
'websocket_rfc8441_on(local, true)',
]:
assert marker_0221 in server_source, marker_0221
for marker_0223 in [
'StatusCode::SWITCHING_PROTOCOLS', 'H2cUpgradeIo', 'HTTP2-Settings',
'h2c_upgrade_bootstraps_request_as_http2_stream_one',
'malformed_h2c_upgrade_is_rejected_before_switching_protocols',
]:
assert marker_0223 in server_source, marker_0223
for memory_marker_0230 in [
'H2ConnectionState', 'H2ActivityIo', 'ActiveHttp2Connection',
'http2_active_connections',
]:
assert memory_marker_0230 in server_source or memory_marker_0230 in metrics_source, memory_marker_0230
cache_fill_0230 = rust_source(root, 'src/cache/fill.rs')
assert 'let allocated = self.data.capacity().max(self.data.len());' in cache_fill_0230
assert 'shared_allocated' in cache_fill_0230 and 'try_into_mut()' in cache_fill_0230
assert 'let cost = hot_entry_cost(' in cache_fill_0230
assert 'fn hot_entry_cost(' in cache_source
for marker_0221 in [
'pub fn validate_h2(request: &Request)', 'hyper::ext::Protocol',
'bridge_h2_to_h1', 'pub struct TunnelInfo', 'pub struct TunnelRegistry',
'register_pending', 'spawn_h2_idle_watch', 'h2-rfc8441-h1-upstream',
'h2-rfc8441-h2-upstream', 'h3-rfc9220',
]:
assert marker_0221 in websocket_source, marker_0221
for marker_0221 in [
'websocket_upstream_h2', 'validate_h2_response', 'wrap_h2_request_body',
'wrap_h2_response_body', 'bridge_h2_to_h1',
]:
assert marker_0221 in proxy_source, marker_0221
for marker_0221 in [
'.route("/api/tunnels", get(active_tunnels))',
'"/api/tunnels/{id}/kill"', '"tunnel.kill"',
'reason.len() > 256', 'state.tunnel_registry.kill(id)',
]:
assert marker_0221 in admin, marker_0221
for marker_0221 in [
'websocket_h1_tunnels_total', 'websocket_h1_tunnels_active',
'websocket_h2_rfc8441_tunnels_total', 'websocket_h2_rfc8441_tunnels_active',
'websocket_h3_rfc9220_tunnels_total', 'websocket_h3_rfc9220_tunnels_active',
]:
assert marker_0221 in metrics_source, marker_0221
for marker_0221 in [
'"websocket_rfc8441"', '"/api/tunnels"', '"/api/tunnels/{id}/kill"',
'"TunnelInfo"', '"TunnelKillRequest"',
]:
assert marker_0221 in openapi, marker_0221
for marker_0233 in [
'pub websocket_legacy_support: bool',
'legacy WebSocket compatibility requires WebSocket support to be enabled',
]:
assert marker_0233 in vhost_source, marker_0233
for marker_0233 in [
'pub websocket_legacy_support: bool',
'websocket_legacy_support: host.websocket_legacy_support',
]:
assert marker_0233 in config_source, marker_0233
for marker_0233 in [
'fn legacy_websocket_origin(',
'websocket_legacy_support && !websocket_upstream_h2',
'request.headers_mut().insert("origin", origin)',
'websocket::validate_response(',
]:
assert marker_0233 in proxy_source, marker_0233
for marker_0233 in [
'legacy_support: bool',
'legacy 101 response declared a non-zero body',
'legacy_upstream_response_accepts_old_101_syntax_but_keeps_accept_proof_strict',
]:
assert marker_0233 in websocket_source, marker_0233
for marker_0233 in [
'websocket_legacy_support', 'vhWebsocketLegacySupport', 'vhWebsocketLegacySupportHelp',
]:
assert marker_0233 in js or marker_0233 in openapi, marker_0233
assert 'hyper::ext::Protocol::from_static(protocol)' in http2_test
assert 'rfc8441_requires_an_h2_capable_listener_and_h2c_is_explicit' in transport_test
assert 'h2c' in integrations_0221 and 'H2C' in integrations_0221
transport_doc = (root / "docs/TRANSPORT.md").read_text()
assert 'prior knowledge' in transport_doc and 'Upgrade: h2c' in transport_doc and 'stream 1' in transport_doc
# Historical V0.22-0.24 audits are not required for active transport tests.
# 0.22.3 replay-safe retry and ordinary H2 upstream contracts.
balance_0222 = rust_source(root, "src/balance.rs")
for marker_0222 in [
"pub struct RetryPolicy", "pub max_retries: u8", "pub retry_statuses: Vec<u16>",
"pub fn select_retry", "retry_attempts_total", "retry_successes_total",
"failover_selection_never_reuses_an_attempted_backend",
]:
assert marker_0222 in balance_0222, marker_0222
for marker_0222 in [
"fn retry_safe_method", "Method::GET", "Method::HEAD", "Method::OPTIONS",
"request_body_empty", "route.backend_id.is_none()", "select_retry_wait(",
"upstream_request_version", "retrying replay-safe request on another backend",
"explicit_http2_backend_uses_http2_request_version",
]:
assert marker_0222 in proxy_source, marker_0222
upstream_0222 = rust_source(root, "src/upstream.rs")
assert "explicit_h2c_backend_uses_http2_prior_knowledge" in upstream_0222
vhosts_0222 = read_vhosts_js(root)
for marker_0222 in ["retry-max", "retry-connect", "retry-timeouts", "retry-statuses"]:
assert marker_0222 in vhosts_0222, marker_0222
for marker_0222 in [
'"max_retries"', '"retry_connect_errors"', '"retry_timeouts"', '"retry_statuses"'
]:
assert marker_0222 in openapi, marker_0222
for marker_0222 in [
"max_concurrent_requests", "queue_timeout_ms", "capacity_rejections_total",
"dns_errors_total", "last_failure_detail", "last_recovered_ms",
"backend_concurrency_limit_queues_then_rejects_and_recovers",
]:
assert marker_0222 in balance_0222, marker_0222
assert "let mut item = serde_json::Map::new();" in balance_0222
assert 'json!({"id":m.definition.id, "url":m.definition.url' not in balance_0222
for marker_0222 in ["member-max-concurrent", "member-queue-timeout", "vhLastFailure", "vhLastRecovery", "vhClientGeneration", "vhGenerationRequests", "vhGenerationAge", "vhClientRotations"]:
assert marker_0222 in vhosts_0222 or marker_0222 in html, marker_0222
for marker_0256 in ["upstream_client_generation", "upstream_client_generation_requests", "upstream_client_generation_age_seconds", "upstream_client_rotations_total"]:
assert marker_0256 in vhosts_0222, marker_0256
for marker_0222 in ["CertificateMetadata", "certificate_public_metadata", "x509_time_parser_handles_utc_and_generalized_time_with_offsets"]:
assert marker_0222 in rust_source(root, "src/tls.rs"), marker_0222
for marker_0222 in [
'"max_concurrent_requests"', '"queue_timeout_ms"', '"certificate_issuer"',
'"days_remaining"', '"expiry_status"', '"last_renewal_error"'
]:
assert marker_0222 in openapi, marker_0222
for path in (root / "src/admin/web").glob("*.js"):
subprocess.run(["node", "--check", str(path)], check=True)
connection = sqlite3.connect(":memory:")
connection.executescript((root / "migrations/0002_admin.sql").read_text())
connection.executescript((root / "migrations/0003_certificate_renewals.sql").read_text())
connection.executescript((root / "migrations/0004_admin_preferences.sql").read_text())
connection.executescript((root / "migrations/0005_certificate_api.sql").read_text())
connection.executescript((root / "migrations/0006_certificate_api_credentials.sql").read_text())
connection.executescript((root / "migrations/0007_secret_store.sql").read_text())
connection.executescript((root / "migrations/0008_config_history.sql").read_text())
connection.executescript((root / "migrations/0009_certificate_api_grants.sql").read_text())
connection.execute("PRAGMA user_version = 9")
assert connection.execute("PRAGMA quick_check").fetchone()[0] == "ok"
assert connection.execute("SELECT COUNT(*) FROM auth_throttle WHERE id=1").fetchone()[0] == 1
assert connection.execute("SELECT COUNT(*) FROM certificate_renewals").fetchone()[0] == 0
assert connection.execute("SELECT COUNT(*) FROM admin_preferences").fetchone()[0] == 0
assert connection.execute("PRAGMA user_version").fetchone()[0] == 9
connection.close()
for marker_0223 in [
'"/api/certificates/reload"', 'certificate_reload',
'"/api/certificates/deploy"', 'certificate_deploy', 'certificate.deploy',
'certificate.reload', 'reload_certificates().await',
'"operation": "unchanged"', 'config.tls.certificates.push(crate::tls::Certificate',
]:
assert marker_0223 in admin, marker_0223
runtime_0223 = rust_source(root, 'src/runtime.rs')
for marker_0223 in ['pub async fn reload_certificates', 'configured certificates reloaded from disk']:
assert marker_0223 in runtime_0223, marker_0223
main_0223 = rust_source(root, 'src/main.rs')
for marker_0223 in ['TlsCommand::Deploy', '/api/certificates/deploy', '/api/certificates/reload', 'read_external_pem']:
assert marker_0223 in main_0223, marker_0223
tls_0223 = rust_source(root, 'src/tls.rs')
for marker_0223 in ['pub fn stage_external_pair', 'pub fn reconcile_external_pair', 'ExternalPairDeployment::Unchanged', 'external-', 'remove_external_pair']:
assert marker_0223 in tls_0223, marker_0223
for marker_0223 in ['"/api/certificates/reload"', '"CertificateReloadResult"', '"/api/certificates/deploy"', '"CertificateDeploy"', '"CertificateDeployResult"']:
assert marker_0223 in openapi, marker_0223
assert 'api("/api/certificates/reload"' in app_js
assert 'certificateAdminRestartRequired' in app_js
# 0.24.0 H2 lifecycle contracts retained by 0.24.1.
server_0240 = rust_source(root, "src/server.rs")
settings_0240 = rust_source(root, "src/settings.rs")
config_0240 = rust_source(root, "src/config.rs")
for marker_0240 in [
"H2ConnectionState", "H2StreamLease", "H2TrackedBody",
"wait_for_h2_idle", "graceful_shutdown()", "H2ShutdownCause::Lifetime",
"h2_idle_connection_sends_goaway_before_closing",
"h2_lifetime_goaway_is_bounded_by_drain_timeout",
"h2_lifetime_allows_active_stream_to_finish_during_drain",
]:
assert marker_0240 in server_0240, marker_0240
for marker_0240 in ["Http2Connections", "idle_timeout_seconds", "max_connection_lifetime_seconds", "drain_timeout_seconds"]:
assert marker_0240 in settings_0240, marker_0240
assert "pub http2: crate::settings::Http2Connections" in config_0240
assert "pub http2_settings: Option<crate::settings::Http2Connections>" in rust_source(root, "src/vhost.rs")
assert "serve_frontend_with_http2" in main_source and "binding.http2_settings.unwrap_or_default()" in main_source
assert 'renderHttp2Settings' in integrations_js and 'collectHttp2Listeners' in integrations_js
assert '"Http2ConnectionSettings"' in openapi and '"max_connection_lifetime_seconds"' in openapi
# 0.24.1 shared statistics/runtime-info/settings-navigation contracts.
system_stats_0241 = rust_source(root, "src/system_stats/mod.rs")
linux_stats_0241 = rust_source(root, "src/system_stats/linux.rs")
main_0241 = rust_source(root, "src/main.rs")
admin_0241 = rust_source(root, "src/admin/mod.rs")
settings_js_0241 = (root / "src/admin/web/settings.js").read_text()
assert not (root / "src/system_stats/bsd.rs").exists(), "per-BSD parser backend must not return"
assert manifest["target"]['cfg(any(target_os = "linux", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly", target_os = "macos", target_os = "windows"))']["dependencies"]["systemstat"] == "=0.2.7"
metrics_dep = manifest["dependencies"]["metrics-process"]
assert metrics_dep["version"] == "=2.4.3" and metrics_dep["default-features"] is False
assert metrics_dep["features"] == ["dummy"]
sysinfo_dep = manifest["dependencies"]["sysinfo"]
assert sysinfo_dep["version"] == "0.39" and sysinfo_dep["default-features"] is False
assert set(sysinfo_dep["features"]) == {"network", "system"}
for marker_0241 in [
"systemstat::{Platform, System}", "metrics_process::collector::collect",
"sysinfo::Networks::new_with_refreshed_list", "collect_network_systemstat", "merge_network_interfaces",
"system_swap_total_bytes", "system_uptime_seconds", "process_virtual_memory_bytes",
"process_start_time_seconds", "max_fds", "FreeBSD", "OpenBSD", "NetBSD", "DragonFly BSD",
]:
assert marker_0241 in system_stats_0241, marker_0241
for marker_0241 in ["/proc/stat", "/proc/meminfo", "RssAnon", "VmData", "VmSwap", "pub(crate) fn augment"]:
assert marker_0241 in linux_stats_0241, marker_0241
for marker_0266_lxc in [
"LinuxEnvironment::Lxc", "process_start_ticks", "CLOCK_BOOTTIME", "/proc/1/stat",
"/proc/loadavg", "lxc_load_average", "view.environment = Some(environment.label())",
"if environment == LinuxEnvironment::Lxc",
]:
assert marker_0266_lxc in linux_stats_0241, marker_0266_lxc
assert 'const processPlatform = [d.platform, d.environment].filter(Boolean).join(" / ");' in app_js
for forbidden in ["sysctl", "netstat", "Command::new"]:
assert forbidden not in system_stats_0241, f"shared statistics adapter must not shell/parse per platform: {forbidden}"
for marker_0241 in ["installed_data_dir_candidates", '"/var/lib/rustproxy"', '"/var/db/rustproxy"', "resolve_installed_data_dir"]:
assert marker_0241 in main_0241, marker_0241
for marker_0241 in ['"runtime"', '"platform"', '"statistics_source"', '"data_directory"', '"database_path"']:
assert marker_0241 in admin_0241 or marker_0241 in openapi, marker_0241
assert 'id="process-platform"' in html and 'd.platform' in app_js
assert 'id="panel-logging"' not in html
assert 'id="settings-tab-logging"' in html and 'id="settings-page-logging"' in html and 'id="logging-form"' in html and 'id="error-log-form"' in html
assert 'data-i18n="errorLogHelp"' not in html
assert 'bindSettingsForm("error-log-form"' in app_js and '}, "logging", selectLoggingSection);' in app_js
assert 'const selectLoggingSection = next => ({ logging: next.logging, error_log: next.error_log });' in app_js
assert '"error_log" => {' not in admin_0241 and 'request("/api/config/error_log")' in admin_0241
assert '"error_log"' in openapi and 'logging, error_log, forwarding' not in openapi
assert 'logging_section_persists_error_log_settings_atomically' in admin_0241 and 'error_log_is_not_a_standalone_configuration_section' in admin_0241
assert 'location.pathname === "/logging"' in settings_js_0241
assert '"RuntimeInformation"' in openapi and '"version": "0.32.7"' in openapi
# 0.24.1 compiler and hostname-cardinality regressions.
tls_0241 = rust_source(root, "src/tls.rs")
vhost_0241 = rust_source(root, "src/vhost.rs")
redirect_0241 = rust_source(root, "src/redirect.rs")
not_found_0241 = rust_source(root, "src/not_found.rs")
docker_0241 = rust_source(root, "src/docker.rs")
integrations_0241 = (root / "src/admin/web/integrations.js").read_text()
docker_js_0241 = (root / "src/admin/web/docker.js").read_text()
assert "future::Future" not in server_0240
assert "uptime.as_secs()" in system_stats_0241 and "whole_seconds()" not in system_stats_0241
for forbidden_0241 in [
"cert.hosts.len() <= 32", "settings.certificates.len() <= 64",
"hosts.len() <= 32", "domains.len() <= 16",
]:
assert forbidden_0241 not in tls_0241, forbidden_0241
for source_0241 in [vhost_0241, redirect_0241, not_found_0241]:
assert "hosts.len() <= 16" not in source_0241
assert "allowed_hosts.len() <= 32" not in settings_0240
assert "MAX_ALIASES" not in docker_0241 and "aliases.len() <= 32" not in docker_0241
assert "const add = (raw, changed = true) => { const value = normalize(raw); if (!value || values.includes(value)) return; values.push(value);" in integrations_0241
assert "values.length >= 32" not in docker_js_0241
for marker_0241 in [
"certificate_hostname_bindings_are_not_artificially_capped",
"acme_validation_has_no_rustproxy_domain_count_ceiling",
]:
assert marker_0241 in tls_0241, marker_0241
assert "vhost_hostname_count_is_not_artificially_capped" in vhost_0241
assert "administration_hostname_count_is_not_artificially_capped" in settings_0240
assert "docker_alias_count_is_not_artificially_capped" in docker_0241
openapi_0241 = json.loads(openapi)
for schema_name, property_path in [
("CertificateUpload", ("hosts",)),
("AcmeIssue", ("domains",)),
("DockerAssignment", ("aliases",)),
]:
node = openapi_0241["components"]["schemas"][schema_name]["properties"]
for part in property_path:
node = node[part]
assert "maxItems" not in node, (schema_name, property_path)
for schema_name in ["RedirectHost", "NotFoundHost"]:
node = openapi_0241["components"]["schemas"][schema_name]["properties"]["frontend"]["properties"]["hosts"]
assert "maxItems" not in node, schema_name
# 0.27.3 maintenance regressions: restore ownership, production paths, GeoIP,
# explicit startup binds, strict WebSocket 101 framing and fail-soft update checks.
bootstrap_0273 = rust_source(root, "src/main/bootstrap.rs")
settings_0273 = rust_source(root, "src/settings.rs")
websocket_0273 = rust_source(root, "src/proxy/websocket/handshake.rs")
websocket_tests_0273 = (root / "src/proxy/websocket/tests.rs").read_text()
backup_validation_0273 = (root / "src/backup/validation.rs").read_text()
backup_owner_0273 = (root / "src/backup/ownership.rs").read_text()
geoip_update_0273 = (root / "src/geoip/update.rs").read_text()
geoip_http_0273 = (root / "src/geoip/update_http.rs").read_text()
update_check_0273 = rust_source(root, "src/update_check.rs")
admin_runtime_0273 = rust_source(root, "src/main/admin_runtime.rs")
dev_0273 = (root / "dev.sh").read_text()
style_0273 = (root / "src/admin/web/style.css").read_text()
settings_web_0273 = (root / "src/admin/web/settings.js").read_text()
assert 'default_value = "/var/lib/rustproxy"' in bootstrap_0273
assert 'RUST_PROXY_DATA_DIR="${RUST_PROXY_DATA_DIR:-$ROOT/data}"' in dev_0273
assert 'let restore_owner = if data_dir.exists()' in backup_validation_0273
assert 'set_tree_owner(&stage, owner)?;' in backup_validation_0273
assert 'libc::lchown' in backup_owner_0273 and 'restore_owner_is_applied_recursively' in (root / "src/backup/tests.rs").read_text()
assert 'explicit_startup_bind_replaces_canonical_saved_binding' in settings_0273
assert 'endpoint.id == canonical_id' in settings_0273
assert 'strict_upstream_101_body_framing_matrix' in websocket_tests_0273
assert '!headers.contains_key("transfer-encoding")' in websocket_0273
assert 'value.trim() == "0"' in websocket_0273
for marker_0273 in [
'DEFAULT_IPV4_URL', 'DEFAULT_IPV6_URL', 'DEFAULT_MMDB_URL', 'DEFAULT_MAX_BYTES',
'DEFAULT_INTERVAL_SECONDS', '.geoip-update.lock', 'pub async fn poll_loop',
'GeoIP update failed; proxy traffic is unaffected',
]:
assert marker_0273 in geoip_update_0273, marker_0273
for marker_0273 in ['pub(super) async fn download', 'expected_digest: Option<&str>', 'written <= max_bytes', 'Sha256::new()']:
assert marker_0273 in geoip_http_0273, marker_0273
assert 'state.start_geoip_updates();' in admin_runtime_0273
assert admin_runtime_0273.index('let admin_listener = TcpListener::bind(admin_addr)') < admin_runtime_0273.index('state.start_update_check(update_check);')
assert 'tracing::warn!(' in update_check_0273 and 'update check failed; retrying on the next interval' in update_check_0273
assert 'calc(100vh / var(--ui-scale, 1))' in style_0273
for marker_0273 in ['geoip-form', 'geoip_updates', '268435456', '86400']:
assert marker_0273 in settings_web_0273 or marker_0273 in html, marker_0273
assert '"geoip"' in openapi and 'GeoIpUpdateSettings' in openapi
# 0.28.0 retained operator controls and cache-policy regressions.
geoip_tests_0280 = (root / "src/geoip/update_tests.rs").read_text()
cache_settings_0280 = (root / "src/cache/model/settings.rs").read_text()
cache_entry_0280 = (root / "src/cache/model/entry.rs").read_text()
runtime_types_0280 = (root / "src/runtime/types.rs").read_text()
runtime_tests_0280 = (root / "src/runtime/tests.rs").read_text()
vhost_core_0280 = (root / "src/admin/web/vhosts/core.js").read_text()
runtime_web_0280 = (root / "src/admin/web/app/runtime.js").read_text()
cache_web_0280 = (root / "src/admin/web/app/settings.js").read_text()
for marker_0280 in [
'pub async fn update_now', 'publish_database(&app.geoip, database)',
'UpdateOutcome::Updated', 'UpdateOutcome::Current', 'UpdateOutcome::Busy',
]:
assert marker_0280 in geoip_update_0273, marker_0280
assert 'publishing_a_downloaded_database_hot_swaps_future_geoip_lookups' in geoip_tests_0280
assert 'state.geoip.load().country(context.client_ip)' in rust_source(root, "src/proxy/forward_entry.rs")
assert '.route("/api/geoip/update", post(geoip_update))' in admin_0241
assert 'id="geoip-update-now"' in html and 'api("/api/geoip/update", { method: "POST" })' in settings_web_0273
assert 'GeoIpUpdateResult' in openapi and '"/api/geoip/update"' in openapi
for marker_0280 in [
'DatabaseFormat::CsvPair', 'DatabaseFormat::Mmdb', 'ipv4_checksum_url: Option<String>',
'mmdb_checksum_url: Option<String>', 'validate_directory_format',
]:
assert marker_0280 in geoip_update_0273 or marker_0280 in (root / 'src/geoip.rs').read_text(), marker_0280
assert 'country.iso_code' in (root / 'langs/en_US.json').read_text()
assert 'user-country.mmdb' in settings_web_0273 and 'geoip-mmdb-url' in html
assert 'publisher checksums are intentionally not required' in (root / 'scripts/deploy/deploy_core.py').read_text().lower()
assert 'pub via_header: Option<String>' in cache_settings_0280 and 'via_header: Some("RustProxy".into())' in cache_settings_0280
assert 'http::header::VIA' in cache_entry_0280 and 'headers.append(' in cache_entry_0280
for marker_0280 in ['cache.bypass_query = false', 'cache.bypass_prefixes.clear()', 'cache.via_header = None']:
assert marker_0280 in runtime_types_0280, marker_0280
assert 'cache_invalidation(&base, &wire_only)' in runtime_tests_0280 and 'CacheInvalidation::None' in runtime_tests_0280
assert 'listener-active-item' in runtime_web_0280 and 'listener-active-feature' in runtime_web_0280
assert 'cache-via-enabled' in cache_web_0280 and 'via_header:' in cache_web_0280
assert 'location-header-direction location-header-editor' in vhost_core_0280
# 0.29.3 internal-error/multipart/PATH_INFO contracts.
vhost_model_0291 = rust_source(root, "src/vhost.rs")
vhost_validation_0291 = rust_source(root, "src/vhost/validation.rs")
config_snapshot_0291 = rust_source(root, "src/config/internal_routing.rs")
proxy_types_0291 = rust_source(root, "src/proxy/error_fallback.rs")
proxy_response_0291 = rust_source(root, "src/proxy/forward/response.rs")
web_headers_0291 = rust_source(root, "src/web_server/response/headers.rs")
web_file_0291 = rust_source(root, "src/web_server/response/file.rs")
php_protocol_0291 = rust_source(root, "src/web_server/fastcgi/protocol.rs")
php_model_0291 = rust_source(root, "src/web_server/config/model.rs")
prometheus_0291 = rust_source(root, "src/prometheus/core.rs")
for marker_0291 in ['pub struct ErrorFallback', 'ERROR_FALLBACK_STATUSES', 'pub internal: bool', 'pub error_fallback: Option<ErrorFallback>']:
assert marker_0291 in vhost_model_0291, marker_0291
assert 'recursive error fallback loop detected' in vhost_validation_0291
assert 'select_internal_on' in config_snapshot_0291
for marker_0291 in ['MAX_ERROR_FALLBACK_DEPTH', 'MAX_ERROR_FALLBACK_REPLAY_BODY_BYTES', 'execute_error_fallback']:
assert marker_0291 in proxy_types_0291, marker_0291
assert 'execute_error_fallback' in proxy_response_0291
assert 'MAX_BYTE_RANGES: usize = 16' in web_headers_0291 and 'parse_ranges' in web_headers_0291
assert 'multipart/byteranges' in web_file_0291
assert 'pub path_info: bool' in php_model_0291 and 'PATH_INFO' in php_protocol_0291
for marker_0291 in ['rust_proxy_vhost_error_fallback_triggered_total', 'rust_proxy_vhost_error_fallback_successful_total', 'rust_proxy_vhost_error_fallback_failed_total']:
assert marker_0291 not in prometheus_0291, marker_0291
assert 'unavailable: host.transient_unavailable && host.source.is_reverse_proxy()' in rust_source(root, "src/config/routing.rs")
assert 'filter(|_| needs_proxy_pool)' in rust_source(root, "src/config/routing.rs")
assert (root / 'docs/CUSTOM_LOCATIONS.md').is_file()
assert '"ErrorFallback"' in openapi and '"path_info"' in openapi and '"internal"' in openapi
# Retained 0.29.0 redirect/health/cache/gzip-log contracts.
vhost_model_0290 = rust_source(root, "src/vhost/model.rs")
vhost_validation_0290 = rust_source(root, "src/vhost/validation.rs")
config_model_0290 = rust_source(root, "src/config/model.rs")
config_routing_0290 = rust_source(root, "src/config/routing.rs")
proxy_redirect_0290 = rust_source(root, "src/proxy/redirect_helpers.rs")
route_cache_0290 = rust_source(root, "src/proxy/forward/route_cache.rs")
cache_entry_0290 = rust_source(root, "src/cache/model/entry.rs")
cache_request_0290 = rust_source(root, "src/cache/policy/request.rs")
file_logs_0290 = rust_source(root, "src/admin/file_logs.rs")
file_logs_io_0290 = rust_source(root, "src/admin/file_logs_io.rs")
for marker_0290 in ['www_redirect', 'redirect: Option<LocationRedirect>']:
assert marker_0290 in vhost_model_0290, marker_0290
for marker_0290 in ['routing_hosts', 'www_redirect_pair']:
assert marker_0290 in vhost_validation_0290, marker_0290
assert 'www_redirect: Option<(String, String)>' in config_model_0290
assert 'health_check.host.is_none()' in config_routing_0290 and 'HealthMode::Http' in rust_source(root, "src/config/routing.rs")
assert 'canonical_host_redirect' in proxy_redirect_0290 and 'PERMANENT_REDIRECT' in proxy_redirect_0290
assert 'redirect_location' in rust_source(root, "src/config/snapshot.rs") and 'local_redirect' in route_cache_0290
assert 'pub struct UnsafeForce' in cache_entry_0290 and 'unsafe_force: UnsafeForce' in cache_entry_0290
assert 'forced_request_policy' in cache_request_0290 and 'cache_miss_forced' in rust_source(root, "src/proxy/mod.rs")
assert 'compressed: bool' in file_logs_0290 and 'GzDecoder' in file_logs_io_0290
for path_0290 in ['src/vhost/redirect.rs']:
assert (root / path_0290).is_file(), path_0290
assert 'static_vhost_page_can_serve_html_with_503_status' in rust_source(root, "src/pages.rs")
assert 'upstream_uri_preserves_nested_url_query_without_rejecting_valid_separators' in rust_source(root, "src/proxy/mod.rs")
assert '"www_redirect"' in openapi and '"unsafe_force"' in openapi
assert '"redirect"' in openapi and 'Backend-less client redirect for this location.' in openapi
# 0.28.2 external-certificate ACL/path hardening and least-privilege Certificate API.
tls_types_0282 = (root / "src/tls/types.rs").read_text()
tls_external_0282 = (root / "src/tls/external_paths.rs").read_text()
tls_server_0282 = (root / "src/tls/server_config.rs").read_text()
tls_tests_0282 = (root / "src/tls/tests.rs").read_text() + (root / "src/tls/tests/external_paths.rs").read_text()
backup_snapshot_0282 = (root / "src/backup/snapshot.rs").read_text()
certificate_admin_0282 = (root / "src/admin/certificates.rs").read_text()
certificate_api_db_0282 = (root / "src/db/certificate_api.rs").read_text()
certificate_session_0282 = (root / "src/admin/session.rs").read_text()
deploy_core_0282 = (root / "scripts/deploy/deploy_core.py").read_text()
for marker_0282 in [
'pub fn certificate_files_are_external',
'cert_external == key_external',
]:
assert marker_0282 in tls_external_0282, marker_0282
for marker_0282 in [
'validate_external_parent_chain',
'fs::canonicalize(configured)',
'libc::O_NOFOLLOW',
'mode & 0o022 == 0',
'mode & 0o004 == 0',
'POSIX ACL masks are reflected',
]:
assert marker_0282 in tls_external_0282, marker_0282
assert 'certificate_files_are_external(cert, key)?;' in tls_server_0282
for marker_0282 in [
'external_absolute_paths_follow_certbot_style_symlinks_on_each_reload',
'external_key_permissions_accept_acl_style_group_mask_but_reject_unsafe_write_or_world_read',
'external_paths_reject_writable_non_sticky_parent_directories',
]:
assert marker_0282 in tls_tests_0282, marker_0282
assert 'certificate_files_are_external(' in backup_snapshot_0282 and 'External certificate material is intentionally outside' in backup_snapshot_0282
assert 'uses external file paths; renew those files in place and call the certificate reload endpoint instead of deploy' in certificate_admin_0282
for marker_0282 in [
'certificate_api_grants',
'allow_deploy',
'certificate_ids',
'value != "*"',
]:
assert marker_0282 in certificate_api_db_0282, marker_0282
for marker_0282 in [
'certificate_api.target_required',
'certificate_api.certificate_forbidden',
'certificate_api.deploy_forbidden',
]:
assert marker_0282 in certificate_session_0282, marker_0282
assert 'ReadOnlyPaths=-/etc/letsencrypt -/etc/ssl' in deploy_core_0282
for marker_0282 in [
'id="certificate-file-source"',
'certificateSourceManaged',
'certificateSourceExternal',
'/etc/letsencrypt/live/example.com/fullchain.pem',
'certificate-external-acl-example',
'certificate-api-certificate-ids',
'certificate-api-allow-deploy',
]:
assert marker_0282 in html or marker_0282 in runtime_web_0280 or marker_0282 in (root / 'langs/en_US.json').read_text(), marker_0282
assert 'Zewnętrzne ścieżki plików' in (root / 'langs/pl_pl.json').read_text()
assert 'setfacl -m u:rustproxy:--x /etc/ssl/' in (root / 'docs/INSTALL.md').read_text()
print("PASS: 0.31.9 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, external-packaging/Grafana/Prometheus/404-host/custom-location/path/cache/dashboard/Nagios UI/source contracts, stopped legacy-renewal removal, session/admin/transport contracts, deterministic package source and embedded SQLite schema-v9 migrations.")
print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")