diff --git a/CHANGELOG.md b/CHANGELOG.md index 522c992..1bbb183 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 0.24.9 +- Fix the secret-redaction KV regex literal so 0.24.9 compiles correctly; the redaction behavior itself is unchanged. - Harden the built-in release checker for FreeBSD/OPNsense and other Unix platforms: supplement bundled Mozilla roots with common system CA bundles/`SSL_CERT_FILE`/`CURL_CA_BUNDLE`, follow bounded non-downgrading HTTP(S) redirects, and report failed checks as normal application `ERROR` events without changing dashboard behavior. - Add a central AES-256-GCM encrypted Secret Store with private local master-key storage and migration of existing ACME DNS-provider credentials. - Add encrypted full backup/restore with Argon2id, authenticated encryption, explicit manifests/checksums, staging validation and rollback-safe activation. diff --git a/SHA256SUMS b/SHA256SUMS index 798c419..3b6e615 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -2,7 +2,7 @@ 4140a2956264b44f259e6a37fc00ba02097bbe68b09296e04d3d243c1287129b .env.example 9e6356475bf587091bab72246ec9e325b498f7e48a6220e9a18baa50d0a385a6 .gitignore 60d7b6e6599269c73bb901383fc979be2403d41dbea221ff3100def26161baa3 AGENTS.md -6b70a0382728f3cbdaf69f17d2681fa233252cf9be93e744d992531c4cdbbbb5 CHANGELOG.md +b159e8d97a7de7bfc64256d13885b6f0c700433d265ecdbcee6d2312e7c91cc2 CHANGELOG.md 31147611b139a69c531fbdafcbe53e3331c7afbcfcab1167ebbca8b24b5bc4cb Cargo.lock 5928784bf7f69a9b21f2420d63a82986ae03a08998ceca6bae1900fda16804a2 Cargo.toml d6d22ba63f4bc3d16a13012ecaabff8a156be57c824d2f20f66976502fb27d1f Dockerfile @@ -63,7 +63,7 @@ c6fa646500c0acac18bff6349cbb1d821680a849c8648b4eaa64f2a4305f9b9d docs/SECURITY. 620b69e566d27af04f0604f4ca3f88cf95cdfea7fbc6ae9dd92446d2b2b5d9be docs/SECURITY_AUDIT.md fce52cc908fb86cab16072c0297b6cdaf4857e84185783bc96240d9a6bc321fd docs/SETTINGS.md 3611defd206cde107e75cac006159856d12cd8f15df7ae2eb9ec3592ed2b4abd docs/STREAMS.md -2aab477150cea7e66de021676016a0872d244f7c7dca6e211fe3a25ac98ff539 docs/TEST_REPORT.md +4396f0ee6b5c124aef2869eab802ecb221f3cdc4efc1cb1536484b392a8d0e32 docs/TEST_REPORT.md 8ee6187a5460ca45643b7fd789e27bffd264449e3a92ff70e9359edee011bbbb docs/TRANSFORM.md b02957b708174c9def830ced3c70c943a47af7a33467ef858255d04ab92c4af0 docs/TRANSPORT.md 96a6816915d526f00e261846131ee3f942ef332af996cf0f73c79ec1ba9f9c7a docs/V0.21.0_AUDIT.md @@ -121,7 +121,7 @@ edb6ee1445b01cd6f3a74a3a607f39fb107d411b49df028d2e0f4679e093de31 scripts/acme_p e69813fb1d3a4cdcfb7243964cc323fc21a603087bf2e84188fa42b9d3cee4b5 scripts/acme_rfc2136.py ea2c670aa1fc2c145fb3666711642d526c2adb01537fc3b6398664e33136f0e4 scripts/admin_audit.py 20e83f8b6347b819d1d1ea3de5c691c36f0816954a4210b0d3f39557fefe1931 scripts/backup.py -b99f7bb40c05530b74948bd02fe9552b0c3c34767ac1c061fa4fb28c032a19d7 scripts/check_source.py +551ccaf255b59a9219b4605c93c7c459f20639b253387d30d46f1a7d5f001b87 scripts/check_source.py e19eba9a8b8a0a8eb26b1e70a78fdfea2661be3a32b3f769fe8129dc81b7aaf5 scripts/deploy.py 6facb2d65bfab234f09855097d12da8f72669a38ebceb4b1cbd03ab42b8d2469 scripts/langs_check.py 9f89ccdcd31da0f203113051a109ada8e51b44f91382ee2c5c75228d1e456540 scripts/memory_contracts.py @@ -206,7 +206,7 @@ eff4484fd9630009471f824c57c5c74f3d3c5378f9e46a3bdda03ede37daec82 src/geoip.rs 185a7874d2ba45e6705fb69703fb99c96eef2a8134f43343e2b20f105f1a1be3 src/headers.rs 2f6dd8c74fe1d22a8fa4ec5a21d0d334a667ede1b11629541f4802252765b21b src/http3.rs 95bd6977db93be728b2597e942d9200e47474d6e0c7c78584df8c8bae6a1f9c7 src/lib.rs -681732a2ae47e99f3e86b2c627f22eaf3d54c3223e7e8477f426f085c4caf3ca src/logging.rs +993cda76f3bfc029c02700f09dc25580e2a3d8e22b8be0cba4ba335f8c65b6e6 src/logging.rs 26b704f3de0020488c09c8ece38aeec62a7d4c561ae8c63f0eb2347570cf6d6b src/main.rs 7022ec2e991e9906e30b06f5bca58f96b9d7e09cc92a27202b5196d54e341b75 src/metrics.rs 64494e5746912cfcb10612ea4e0b336004b1f738bd7999be7e58fc96abadb6e1 src/not_found.rs diff --git a/docs/TEST_REPORT.md b/docs/TEST_REPORT.md index 75e093c..d6656f1 100644 --- a/docs/TEST_REPORT.md +++ b/docs/TEST_REPORT.md @@ -14,6 +14,7 @@ The release also retains the 0.24.8 overview cache diagnostics, 0.24.7 transform - `rust-proxy backup restore` requires an interactive password, decrypts into private staging, validates manifest/checksums/schema/configuration/Secret Store decryptability before activation, then switches the data directory by rename with rollback on activation failure. - `error_log` is independent from normal access logging, defaults disabled, accepts only `ERROR`, supports JSON/RAW, uses a bounded queue and a single asynchronous writer, handles filesystem failures without terminating RustProxy, and relies on system `logrotate` rather than application rollover. - The stderr/journald path, access-log sinks and the optional error-file sink share secret-redaction helpers for authorization/provider/password/private-key material. +- The KV secret-redaction expression uses a hash-delimited Rust raw string, avoiding the `E0762` unterminated-character-literal parser failure while preserving the same redaction character class. - The release checker preserves the existing dashboard contract while using bundled roots plus common system CA bundles (`SSL_CERT_FILE`, `CURL_CA_BUNDLE`, FreeBSD/OPNsense and Linux paths), follows at most five credential-free HTTP(S) redirects without HTTPS-to-HTTP downgrade, and reports network/TLS/HTTP/parser failures at `ERROR` level so the optional error-file sink receives them. - The overview Cache RAM block keeps separate histories for HOT allocated bytes, transient RAM, fill bytes, COLD queue bytes, COLD I/O bytes and COLD disk bytes; the disk series is never included in process RAM accounting. - HOT and transient histories are rendered against their runtime limits, while COLD storage is rendered against the configured COLD byte budget. diff --git a/scripts/check_source.py b/scripts/check_source.py index 2aff46d..e0a4e5e 100755 --- a/scripts/check_source.py +++ b/scripts/check_source.py @@ -517,6 +517,8 @@ for feature_marker in [ "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 "finally:" in acme_worker_source and "credential_file.unlink" in acme_worker_source diff --git a/src/logging.rs b/src/logging.rs index 75045fe..49f9d44 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -434,7 +434,7 @@ fn redact_regex(pattern: &'static str) -> &'static regex::Regex { "auth" => AUTH.get_or_init(|| regex::Regex::new(r"(?i)(authorization\s*[:=]\s*)(?:bearer\s+)?[^\s,;]+" ).expect("redaction regex")), "query" => QUERY.get_or_init(|| regex::Regex::new(r"(?i)([?&](?:token|access_token|api_token|password|backup_password|secret|credential|credentials|key_secret|application_secret|consumer_key)=)[^&\s]+" ).expect("redaction regex")), "json" => JSON.get_or_init(|| regex::Regex::new(r#"(?i)(\"(?:authorization|proxy_authorization|api_token|access_token|application_secret|consumer_key|key_secret|backup_password|password|credential|credentials|secret|token|private_key|master_key)\"\s*:\s*\")[^\"]*(\")"#).expect("redaction regex")), - "kv" => KV.get_or_init(|| regex::Regex::new(r"(?i)((?:authorization|proxy[_-]?authorization|api[_-]?token|access[_-]?token|application[_-]?secret|consumer[_-]?key|key[_-]?secret|backup[_-]?password|password|credential|credentials|secret|token|private[_-]?key|master[_-]?key)\s*[=:]\s*)[^\s,;\"']+" ).expect("redaction regex")), + "kv" => KV.get_or_init(|| regex::Regex::new(r#"(?i)((?:authorization|proxy[_-]?authorization|api[_-]?token|access[_-]?token|application[_-]?secret|consumer[_-]?key|key[_-]?secret|backup[_-]?password|password|credential|credentials|secret|token|private[_-]?key|master[_-]?key)\s*[=:]\s*)[^\s,;"']+"#).expect("redaction regex")), "pem" => PEM.get_or_init(|| regex::Regex::new(r"(?s)-----BEGIN [^-\r\n]*PRIVATE KEY-----.*?-----END [^-\r\n]*PRIVATE KEY-----" ).expect("redaction regex")), _ => unreachable!(), }