#!/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 root = Path(__file__).resolve().parents[1] def read_cache_source() -> str: return "\n".join(path.read_text() for path in sorted((root / "src/cache").glob("*.rs"))) preflight(root) manifest = tomllib.loads((root / "Cargo.toml").read_text()) assert manifest["package"]["version"] == "0.24.5" assert manifest["dependencies"]["quinn"]["version"] == "0.11.12" h3dep = manifest["dependencies"]["h3"] assert h3dep["package"] == "hpx-h3" and h3dep["version"] == "=2.5.19" 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.24.5"' 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.24.5", "CHANGELOG.md": "## 0.24.5", "ROADMAP.md": "## 0.24.5", "AGENTS.md": "Current source version: 0.24.5.", "docs/TEST_REPORT.md": "# Verification report - RustProxy 0.24.5", }.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 = (root / "src/update_check.rs").read_text() 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 name in ["README.md", "ROADMAP.md", "AGENTS.md", "CHANGELOG.md", "UPDATE_CHECK.toml", "Dockerfile", ".dockerignore", "docs/TEST_REPORT.md", "docs/V0.24.5_AUDIT.md", "docs/V0.24.1_AUDIT.md", "docs/V0.24.0_AUDIT.md", "docs/V0.23.2_AUDIT.md", "docs/V0.23.1_AUDIT.md", "docs/V0.22.3_AUDIT.md", "docs/LIVE_LOGS.md", "docs/README.md", "docs/API.md", "docs/ARCHITECTURE.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/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", "debian/control", "debian/rules", "debian/rustproxy.service", "debian/rustproxy.logrotate", "debian/build-package.sh", "debian/build-repository.sh", "grafana/rustproxy-overview.json", "grafana/README.md"]: assert (root / name).is_file(), name 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").glob("*.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}" for path in [root / "make_zip.py", *(root / "scripts").glob("*.py")]: 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", "debian/build-package.sh", "debian/build-repository.sh", "debian/rustproxy.postinst", "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-certbot-dns-rfc2136', 'python3-certbot-dns-cloudflare', ]: 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 "Environment=MALLOC_ARENA_MAX=2" in unit assert "Environment=MALLOC_ARENA_MAX=2" in (root / "debian/rustproxy.service").read_text() assert "Environment=MALLOC_ARENA_MAX=2" in (root / "scripts/deploy.py").read_text() 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 / "scripts/langs_check.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 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 ".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 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 '/assets/docker.js' in html 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.js']: assert 'x-rust-proxy-revision' not in (root / path).read_text().lower(), f'legacy revision-header logic remains in {path}' assert './dev.sh admin reset-password' not in html and 'rust-proxy admin reset-password locally' in 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 = (root / "src/balance.rs").read_text() assert 'mode: HealthMode::Tcp' 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 '/assets/streams.js' in html and '/assets/redirects.js' in html and '/assets/host404.js' in html vhosts_js = (root / "src/admin/web/vhosts.js").read_text() 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 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', 'setInterval']: assert marker in docker_js, marker docker_source = (root / "src/docker.rs").read_text() 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 = (root / "docker-agent/main.go").read_text() 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 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.24.5"', '"/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']: 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"']: assert marker in html, marker management = (root / "src/admin/web/management.js").read_text() assert 'collectRuleRows' in management and 'parseRules(rules.value, rules)' in management 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 = (root / "src/cache/mod.rs").read_text() 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 (root / "src/cache" / fragment).read_text().lstrip().startswith("impl Cache {"), fragment assert 'disabled_cache_strips_diagnostics_without_exposing_bypass_headers' in cache_source assert 'if !self.enabled' in cache_source proxy_source = (root / "src/proxy/mod.rs").read_text() 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 = (root / "src/transform/mod.rs").read_text() 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', 'drop(decoded);', 'drop(raw);', 'rustproxy-', ]: assert marker in transform_source, marker 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 (root / 'src/lib.rs').read_text() for marker in ['cache-cold-gc-interval', 'cache-cold-gc-max-delete', 'settings-tab-transform', 'transform-form', '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 assert 'envelope?.config.cache?.enabled === true && cacheToggle.value !== "off"' in vhosts_js for marker in ['transform: { enabled: false }', 'vhTransform', 'collectTransform']: 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 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 = (root / 'src/admin/mod.rs').read_text() 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 = (root / "src/redirect.rs").read_text() for marker in ["pub struct Host", "pub struct Rule", "strip_prefix", "cache_seconds", "unconditional self-redirect"]: assert marker in redirect_source, marker proxy_source = (root / "src/proxy/mod.rs").read_text() 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 = (root / "src/config.rs").read_text() 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 = (root / "src/vhost.rs").read_text() 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 = (root / "src/headers.rs").read_text() assert '"x-rust-proxy-backend"' in generic_headers_source and '"x-rustproxy-backend-time"' in generic_headers_source headers_source = (root / "src/proxy/headers.rs").read_text() 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 = (root / "src/settings.rs").read_text() 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 = (root / "src/auth/mod.rs").read_text() auth_store = (root / "src/auth/store.rs").read_text() 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 = (root / "src/upstream.rs").read_text() 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 = (root / "src/runtime.rs").read_text() 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 = (root / "src/admin/mod.rs").read_text() 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 admin 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 = (root / "src/admin/web/app.js").read_text() for marker in ['const PANEL_PATHS', 'history.pushState', 'window.addEventListener("popstate"', 'async function saveSection', 'async function revalidateSession', 'Object.values(PANEL_PATHS), "/configuration"', 'certificateCovers', 'covered_hosts', 'refreshCertificateInventory', 'certificateDetails', 'certificate-domain-pills', 'certificateIssuerName', 'certificateDaysRemaining', 'certificateRenewalStatus']: 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 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() 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" }', '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' 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 html, marker db_source = (root / "src/db.rs").read_text() acme_source = (root / "src/acme.rs").read_text() main_source = (root / "src/main.rs").read_text() logging_source = (root / "src/logging.rs").read_text() 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 (root / 'src/auth/store.rs').read_text(), 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 = 6' 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 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 '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 = (root / "src/runtime.rs").read_text() 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 = (root / 'src/settings.rs').read_text() assert 'pub struct StartupLocks' in settings_rust and 'fixed by systemd/startup' in settings_rust logging_rust = (root / 'src/logging.rs').read_text() assert 'pub per_vhost: bool' in logging_rust and 'default_vhost_log_directory' in logging_rust and '_unmatched' in logging_rust pages_rust = (root / 'src/pages.rs').read_text() 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/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 = (root / "src/tls.rs").read_text() 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 = (root / 'src/vhost.rs').read_text() 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 = (root / 'src/docker.rs').read_text() 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 = (root / 'src/acl.rs').read_text() assert '/Ubuntu%2014.04%20LTS/' in acl_source and 'repeated_slashes_are_normalized_for_routing' in acl_source and 'merge_slashes' in acl_source 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 = (root / "src/http3.rs").read_text() 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 (root / 'src/proxy/websocket.rs').read_text(), 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 = (root / 'src/admin/mod.rs').read_text() 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 = (root / 'src/proxy/websocket.rs').read_text() 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 (root / 'src/logging.rs').read_text(), marker diagnostics_source = (root / 'src/diagnostics.rs').read_text() + (root / 'src/system_stats/mod.rs').read_text() + (root / 'src/system_stats/linux.rs').read_text() 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 = (root / 'src/prometheus.rs').read_text() for marker in ['allow_trusted_network_without_token', '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']: 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_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', 'process-rss-total', '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 (root / 'src/vhost.rs').read_text(), 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', 'cacheHitSamples', 'processCpuSamples', 'processRssSamples', 'networkRxSamples', 'responseLatencySamples', 'client_ip']: assert marker in app_js, marker logging_source = (root / 'src/logging.rs').read_text() assert 'pub client_ip: Option' in logging_source and '"client_ip" => entry.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 = (root / "src/stream.rs").read_text() 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 = (root / 'src/not_found.rs').read_text() for marker in ['pub struct Host', 'pub struct CompiledHost', 'default_status', 'crate::pages::Page']: assert marker in not_found_source, marker pages_source = (root / 'src/pages.rs').read_text() 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'" in make_zip and "'grafana'" in make_zip and "'docker-agent'" in make_zip assert "'UPDATE_CHECK.toml'" in make_zip # Debian package contracts. debian_service = (root / 'debian/rustproxy.service').read_text() for marker in ['User=rustproxy', 'AmbientCapabilities=CAP_NET_BIND_SERVICE', 'StateDirectory=rustproxy', 'LogsDirectory=rustproxy', 'ProtectSystem=strict', 'RUST_PROXY_ADMIN_LISTEN']: if marker.startswith('RUST_PROXY_'): assert marker in (root / 'debian/rustproxy.environment').read_text(), marker else: assert marker in debian_service, marker logrotate = (root / 'debian/rustproxy.logrotate').read_text() for marker in ['daily', 'rotate 3', 'maxage 3', 'compresscmd /usr/bin/gzip', 'compressoptions -9', 'copytruncate', 'su rustproxy rustproxy']: assert marker in logrotate, marker repo_script = (root / 'debian/build-repository.sh').read_text() for marker in ['dpkg-scanpackages', 'apt-ftparchive', 'Packages.gz', 'RUSTPROXY_REPO_GPG_KEY', 'rustproxy.linuxiarz.pl']: assert marker in repo_script, marker 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']: assert marker in expressions, marker # 0.19.0 compression/protocol/dashboard UX regressions. compression_source = (root / "src/compression.rs").read_text() metrics_source = (root / "src/metrics.rs").read_text() admin_source = (root / "src/admin/mod.rs").read_text() 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 assert "quality_weights_can_select_each_enabled_codec" in compression_source diagnostics_source = (root / "src/diagnostics.rs").read_text() + (root / "src/system_stats/mod.rs").read_text() + (root / "src/system_stats/linux.rs").read_text() 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 = (root / "src/docker.rs").read_text() 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-agent-acl-profile"]: assert marker in docker_ui, marker for marker in ['"force_ssl": assignment.force_ssl.unwrap_or(false)', '"websockets": assignment.websockets', '"cache": {"enabled": assignment.cache_enabled}', 'assignment.acl_profile_id.clone().or_else(|| agent.acl_profile_id.clone())']: assert marker in docker_source, 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 = (root / "src/vhost.rs").read_text() 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 '
' in html and 'class="mini-live-chart-head"' in html and 'data-i18n="responseLatencyHistory"' 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 assert 'const transformed = s.transform_metrics || {}' in app_js and 'transformSamples.push(rates.transform)' in app_js 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 '/assets/transform-panel.js' in html 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 'stroke: var(--transform-chart)' 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 (root / "src/headers.rs").read_text() # 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 = (root / "src/logging.rs").read_text() 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() 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 = (root / 'src/balance.rs').read_text() 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 '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 = (root / "scripts/deploy.py").read_text() 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 "'shell_path_action':'install' if args.mode == 'install' else 'check-only'" 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::().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 = (root / "src/upstream.rs").read_text(encoding="utf-8") assert "BackendCertificateVerificationDisabled { 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 = (root / "src/server.rs").read_text() websocket_source = (root / "src/proxy/websocket.rs").read_text() vhost_source = (root / "src/vhost.rs").read_text() 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")', '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 = (root / 'src/cache/fill.rs').read_text() assert 'let body_allocation = self.data.capacity().max(self.data.len());' 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 assert (root / "docs/V0.24.1_AUDIT.md").is_file() and (root / "docs/V0.24.0_AUDIT.md").is_file() and (root / "docs/V0.23.2_AUDIT.md").is_file() and (root / "docs/V0.23.1_AUDIT.md").is_file() and (root / "docs/V0.23.0_AUDIT.md").is_file() and (root / "docs/V0.22.3_AUDIT.md").is_file() # 0.22.3 replay-safe retry and ordinary H2 upstream contracts. balance_0222 = (root / "src/balance.rs").read_text() 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 = (root / "src/upstream.rs").read_text() assert "explicit_h2c_backend_uses_http2_prior_knowledge" in upstream_0222 vhosts_0222 = (root / "src/admin/web/vhosts.js").read_text() 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"]: assert marker_0222 in vhosts_0222 or marker_0222 in html, marker_0222 for marker_0222 in ["CertificateMetadata", "certificate_public_metadata", "x509_time_parser_handles_utc_and_generalized_time_with_offsets"]: assert marker_0222 in (root / "src/tls.rs").read_text(), 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.execute("PRAGMA user_version = 6") 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] == 6 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 = (root / 'src/runtime.rs').read_text() for marker_0223 in ['pub async fn reload_certificates', 'configured certificates reloaded from disk']: assert marker_0223 in runtime_0223, marker_0223 main_0223 = (root / 'src/main.rs').read_text() 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 = (root / 'src/tls.rs').read_text() 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 = (root / "src/server.rs").read_text() settings_0240 = (root / "src/settings.rs").read_text() config_0240 = (root / "src/config.rs").read_text() 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 (root / "src/vhost.rs").read_text() 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 = (root / "src/system_stats/mod.rs").read_text() linux_stats_0241 = (root / "src/system_stats/linux.rs").read_text() main_0241 = (root / "src/main.rs").read_text() admin_0241 = (root / "src/admin/mod.rs").read_text() 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.38.4" and sysinfo_dep["default-features"] is False assert sysinfo_dep["features"] == ["network"] 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 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 assert 'location.pathname === "/logging"' in settings_js_0241 assert '"RuntimeInformation"' in openapi and '"version": "0.24.5"' in openapi # 0.24.1 compiler and hostname-cardinality regressions. tls_0241 = (root / "src/tls.rs").read_text() vhost_0241 = (root / "src/vhost.rs").read_text() redirect_0241 = (root / "src/redirect.rs").read_text() not_found_0241 = (root / "src/not_found.rs").read_text() docker_0241 = (root / "src/docker.rs").read_text() 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 print("PASS: 0.24.5 manifest/package, shared system-statistics/runtime metadata, Settings logging, retained H2, Debian/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-v6 migrations.") print("NOT VERIFIED: Rust parsing, types, compilation, linking or runtime behavior. Run ./dev.sh test.")