#!/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.1" 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.1"' 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.1", "CHANGELOG.md": "## 0.32.1", "ROADMAP.md": "## 0.32.1", "AGENTS.md": "Current source version: 0.32.1.", "docs/TEST_REPORT.md": "# Verification report - RustProxy 0.32.1", }.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(¤t, 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*\{", 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', 'target_ip: Option', 'tls_fingerprint_sha256', 'certificate_id: Option', '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.1"', '"/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::().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,' in model_source assert 'struct TransientLease(Arc);' 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' 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 '
' in html and '
' 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>', '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>::as_ref() is ambiguous for Engine::encode" assert "&mut *ciphertext" in secret_store_source, "ring seal must receive the underlying Vec, not an ambiguous AsMut target" assert "&mut *encrypted" in backup_source, "ring seal must receive the underlying Vec, 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', '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' in runtime_source assert 'pub fn start_update_check(self: &Arc, 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', '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' 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' 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>", "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", "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 '
' 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", "light"])' 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 'matches!(preferences.theme.as_str(), "dark" | "light")' in 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'(? 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::()' 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 '' not in html, "duplicate top-right version label returned" assert '
INDEPENDENT BY DESIGN ' not in html, "release version returned beside the dashboard brand" assert '
INDEPENDENT BY DESIGN
' 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 html.count('class="stats-grid"') >= 1 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", "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" 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.1"' 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', 'mmdb_checksum_url: Option', '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' 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']: 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']: 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.")