0.34.6_repo_cleanup

This commit is contained in:
Mateusz Gruszczyński committed 2026-10-22 09:31:15 +02:00
1 parent ce1a90397c
commit 133d2f0f91
273 files changed
+5969 -6926

No files matched your search

-9
View File
@@ -159,7 +159,6 @@ impl Manager {
"acme.not_due"
}
.into();
// A dry run must not postpone a due production renewal.
if !dry_run {
entry.failures = 0;
entry.next_check = now + 43200 + (rand::random::<u16>() as i64 % 1800);
@@ -231,8 +230,6 @@ async fn deploy_renewal(
.await
.map_err(|_| "acme.validation_worker_failed".to_owned())?
.map_err(|_| "acme.certificate_validation_failed".to_owned())?;
// CAS retries preserve edits to other parts of the document. A simultaneous
// change of this certificate wins over the worker; never silently overwrite it.
for _ in 0..3 {
let snapshot = state.config.load_full();
let Some(current) = snapshot
@@ -280,16 +277,10 @@ async fn deploy_renewal(
}
Err("acme.configuration_changed".into())
}
/// One scheduler per process, sharing the issuance semaphore. It does not run
/// its own shell hooks or stop listeners; validated snapshots rotate TCP and QUIC TLS.
pub async fn renewal_loop(
weak: std::sync::Weak<App>,
shutdown: tokio_util::sync::CancellationToken,
) {
// Observations are restored from SQLite before listeners are exposed. If an
// older installation has no SQLite observations, the normal scheduler will
// safely reconstruct them on its first check; certificate/key state is not
// derived from historical observation sidecars.
let delay = 300 + (rand::random::<u16>() as u64 % 300);
tokio::select! { _ = shutdown.cancelled() => return, _ = tokio::time::sleep(Duration::from_secs(delay)) => {} }
loop {
-1
View File
@@ -394,7 +394,6 @@ impl Manager {
finished.message = message;
}
}
// Never write provider stderr, request JSON or TSIG material to audit.
let _ = state
.store
.audit(
@@ -35,8 +35,6 @@ async fn execute(
.map_err(|_| "acme.validation_worker_failed".to_owned())?
}
/// A reserved validation path: only an active HTTP-01 job and its exact DNS
/// names can read bounded tokens. No origin, cache, auth or custom pages here.
pub async fn challenge(
axum::extract::State(state): axum::extract::State<Arc<App>>,
request: axum::extract::Request,
@@ -140,10 +138,8 @@ pub async fn challenge(
}
#[cfg(test)]
include!("providers/tests.rs");
include!("tests.rs");
/// Public diagnostics contain no account/credential material. Desired renewal
/// permission lives with the certificate; observations never overwrite it.
#[derive(Clone, Default, Serialize, Deserialize)]
#[serde(default)]
pub struct RenewalState {
+7 -18
View File
@@ -13,7 +13,6 @@ async fn create_virtual_environment(
return false;
}
let _ = tokio::fs::remove_dir_all(staging).await;
// Fall back to an application-local virtualenv bootstrap.
let bootstrap = staging.with_extension("virtualenv-bootstrap");
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
let install_bootstrap = |break_system_packages: bool| {
@@ -30,30 +29,20 @@ async fn create_virtual_environment(
"--timeout",
"30",
]);
// Some distro pip builds enforce PEP 668 even for --target. Retrying with
// --break-system-packages is safe here because the destination is the
// private bootstrap directory; distribution site-packages are untouched.
if break_system_packages {
install.arg("--break-system-packages");
}
install.arg("--target").arg(&bootstrap).arg("virtualenv>=20,<21");
install
.arg("--target")
.arg(&bootstrap)
.arg("virtualenv>=20,<21");
install
};
let installed = command_success(
install_bootstrap(false),
Duration::from_secs(300),
shutdown,
)
.await;
let installed =
command_success(install_bootstrap(false), Duration::from_secs(300), shutdown).await;
if !installed {
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
if !command_success(
install_bootstrap(true),
Duration::from_secs(300),
shutdown,
)
.await
{
if !command_success(install_bootstrap(true), Duration::from_secs(300), shutdown).await {
let _ = tokio::fs::remove_dir_all(&bootstrap).await;
return false;
}
+11 -8
View File
@@ -24,7 +24,6 @@ pub struct RuntimeStatus {
pub python: bool,
pub pip: bool,
pub certbot: bool,
/// Versions of the executables actually selected for ACME, never a guessed system default.
pub python_version: Option<String>,
pub pip_version: Option<String>,
pub certbot_version: Option<String>,
@@ -75,13 +74,14 @@ fn find_on_path(name: &str) -> Option<PathBuf> {
if candidate.components().count() > 1 {
return candidate.is_file().then(|| candidate.to_owned());
}
for directory in env::var_os("PATH").into_iter().flat_map(|paths| env::split_paths(&paths).collect::<Vec<_>>()) {
for directory in env::var_os("PATH")
.into_iter()
.flat_map(|paths| env::split_paths(&paths).collect::<Vec<_>>())
{
let path = directory.join(name);
if path.is_file() {
return Some(path);
}
// Windows PATH lookup uses PATHEXT; Path::is_file alone does not.
// Python and Certbot are installed as .exe launchers on Windows.
#[cfg(windows)]
if path.extension().is_none() {
let executable = path.with_extension("exe");
@@ -230,7 +230,8 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
let managed = data_dir.join("acme-python");
let managed_directory = Some(managed.to_string_lossy().into_owned());
if managed_environment_valid(&managed, &state.shutdown).await {
let versions = runtime_versions(&venv_python(&managed), true, Some(&venv_certbot(&managed)));
let versions =
runtime_versions(&venv_python(&managed), true, Some(&venv_certbot(&managed)));
state.acme.set_runtime(RuntimeStatus {
status: "ready",
mode: "managed",
@@ -274,7 +275,9 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
let system_versions = runtime_versions(
&python,
system_pip,
distro_certbot.as_deref().filter(|_| distro_certbot_available),
distro_certbot
.as_deref()
.filter(|_| distro_certbot_available),
);
state.acme.set_runtime(RuntimeStatus {
status: "initializing",
@@ -291,7 +294,8 @@ async fn ensure_runtime(state: &App) -> Result<RuntimeLaunch, String> {
let build = build_managed_environment(&python, &managed, system_pip, &state.shutdown).await;
if build.is_ok() {
tracing::info!(path = %managed.display(), "managed ACME runtime ready");
let versions = runtime_versions(&venv_python(&managed), true, Some(&venv_certbot(&managed)));
let versions =
runtime_versions(&venv_python(&managed), true, Some(&venv_certbot(&managed)));
state.acme.set_runtime(RuntimeStatus {
status: "ready",
mode: "managed",
@@ -383,7 +387,6 @@ impl Drop for ProcessGroup {
fn drop(&mut self) {
#[cfg(unix)]
if let Some(id) = self.0 {
// SAFETY: this process group belongs only to the managed child.
unsafe {
libc::kill(-(id as i32), libc::SIGKILL);
}
+44 -25
View File
@@ -1,7 +1,3 @@
// Version information is diagnostic, not a health check. Read package metadata
// for the *selected* runtime without launching Python, pip, Certbot or a shell.
// A missing/ambiguous version stays None; do not guess an interpreter patch
// version from an executable name or report a hard-coded Certbot pin.
use std::io::Read;
const MAX_VERSION_METADATA_BYTES: u64 = 16 * 1024;
@@ -21,7 +17,10 @@ fn metadata_text(path: &Path) -> Option<String> {
fn safe_version(raw: &str) -> Option<String> {
let version = raw.trim();
(version.len() <= 48
&& version.bytes().next().is_some_and(|byte| byte.is_ascii_digit())
&& version
.bytes()
.next()
.is_some_and(|byte| byte.is_ascii_digit())
&& version
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || b".+-_".contains(&byte)))
@@ -41,8 +40,6 @@ fn python_environment_root(executable: &Path) -> Option<std::path::PathBuf> {
fn interpreter_version(root: &Path) -> Option<String> {
let content = metadata_text(&root.join("pyvenv.cfg"))?;
// CPython venv writes `version = X.Y.Z`. `version_info` from virtualenv
// is a fallback when its standard `version` field is not present.
for key in ["version", "version_info"] {
for line in content.lines() {
if let Some((name, value)) = line.split_once('=') {
@@ -61,20 +58,20 @@ fn python_minor(version: &str) -> Option<String> {
let mut parts = version.split('.');
let major = parts.next()?;
let minor = parts.next()?;
(major.bytes().all(|b| b.is_ascii_digit())
&& minor.bytes().all(|b| b.is_ascii_digit()))
.then(|| format!("python{major}.{minor}"))
(major.bytes().all(|b| b.is_ascii_digit()) && minor.bytes().all(|b| b.is_ascii_digit()))
.then(|| format!("python{major}.{minor}"))
}
fn package_sites(root: &Path, python_version: Option<&str>) -> Vec<std::path::PathBuf> {
let mut sites = vec![root.join("Lib/site-packages"), root.join("lib/python3/dist-packages")];
let mut sites = vec![
root.join("Lib/site-packages"),
root.join("lib/python3/dist-packages"),
];
for base in [root.join("lib"), root.join("lib64")] {
if let Some(minor) = python_version.and_then(python_minor) {
sites.push(base.join(&minor).join("site-packages"));
sites.push(base.join(&minor).join("dist-packages"));
} else if let Ok(entries) = std::fs::read_dir(&base) {
// Python installations with no pyvenv.cfg may contain multiple
// interpreter versions. Never choose between conflicting results.
for entry in entries.take(MAX_SITE_DIRECTORIES).flatten() {
let path = entry.path();
if entry.file_name().to_string_lossy().starts_with("python3.") && path.is_dir() {
@@ -91,14 +88,26 @@ fn package_version(root: &Path, package: &str, python_version: Option<&str>) ->
let prefix = format!("{package}-");
let mut result: Option<String> = None;
for site in package_sites(root, python_version) {
let Ok(entries) = std::fs::read_dir(site) else { continue };
let Ok(entries) = std::fs::read_dir(site) else {
continue;
};
for entry in entries.take(MAX_PACKAGES_PER_SITE).flatten() {
let name = entry.file_name();
let Some(dir_name) = name.to_str() else { continue };
let Some(suffix) = dir_name.strip_prefix(prefix.as_str())
.and_then(|name| name.strip_suffix(".dist-info")) else { continue };
let Some(directory_version) = safe_version(suffix) else { continue };
let Some(content) = metadata_text(&entry.path().join("METADATA")) else { continue };
let Some(dir_name) = name.to_str() else {
continue;
};
let Some(suffix) = dir_name
.strip_prefix(prefix.as_str())
.and_then(|name| name.strip_suffix(".dist-info"))
else {
continue;
};
let Some(directory_version) = safe_version(suffix) else {
continue;
};
let Some(content) = metadata_text(&entry.path().join("METADATA")) else {
continue;
};
let mut reported_name = None;
let mut reported_version = None;
for line in content.lines() {
@@ -107,13 +116,19 @@ fn package_version(root: &Path, package: &str, python_version: Option<&str>) ->
} else if let Some(value) = line.strip_prefix("Version: ") {
reported_version = safe_version(value);
}
if reported_name.is_some() && reported_version.is_some() { break; }
if reported_name.is_some() && reported_version.is_some() {
break;
}
}
if !reported_name.is_some_and(|name| name.eq_ignore_ascii_case(package))
|| reported_version.as_deref() != Some(directory_version.as_str()) {
|| reported_version.as_deref() != Some(directory_version.as_str())
{
continue;
}
if result.as_ref().is_some_and(|previous| previous != &directory_version) {
if result
.as_ref()
.is_some_and(|previous| previous != &directory_version)
{
return None;
}
result = Some(directory_version);
@@ -133,7 +148,8 @@ fn runtime_versions(python: &Path, has_pip: bool, certbot: Option<&Path>) -> Run
let root = python_environment_root(python);
let python_version = root.as_deref().and_then(interpreter_version);
let pip_version = if has_pip {
root.as_deref().and_then(|root| package_version(root, "pip", python_version.as_deref()))
root.as_deref()
.and_then(|root| package_version(root, "pip", python_version.as_deref()))
} else {
None
};
@@ -146,6 +162,9 @@ fn runtime_versions(python: &Path, has_pip: bool, certbot: Option<&Path>) -> Run
};
package_version(&certbot_root, "certbot", certbot_python_version)
});
RuntimeVersions { python: python_version, pip: pip_version, certbot: certbot_version }
RuntimeVersions {
python: python_version,
pip: pip_version,
certbot: certbot_version,
}
}
+23 -7
View File
@@ -111,7 +111,6 @@ mod renewal_regressions {
"acme.configuration_changed"
);
assert_eq!(app.config.load().envelope.revision, 0);
// Explicit Check now remains allowed when scheduled checks are disabled.
deploy_renewal(&app, &original, &output, false)
.await
.unwrap();
@@ -147,7 +146,6 @@ mod renewal_regressions {
}
}
mod runtime_metadata_tests {
use super::*;
@@ -166,13 +164,22 @@ mod runtime_metadata_tests {
std::fs::create_dir_all(venv_bin(root)).unwrap();
std::fs::write(&python, "").unwrap();
std::fs::write(&certbot, "").unwrap();
std::fs::write(root.join("pyvenv.cfg"), "home = /usr/bin\nversion = 3.13.5\n").unwrap();
std::fs::write(
root.join("pyvenv.cfg"),
"home = /usr/bin\nversion = 3.13.5\n",
)
.unwrap();
let site = if cfg!(windows) {
root.join("Lib/site-packages")
} else {
root.join("lib/python3.13/site-packages")
};
write_package(&site, "pip", "25.2", "Metadata-Version: 2.3\nName: pip\nVersion: 25.2\n");
write_package(
&site,
"pip",
"25.2",
"Metadata-Version: 2.3\nName: pip\nVersion: 25.2\n",
);
write_package(&site, "certbot", "5.8.0", "Name: certbot\nVersion: 5.8.0\n");
let versions = runtime_versions(&python, true, Some(&certbot));
assert_eq!(versions.python.as_deref(), Some("3.13.5"));
@@ -202,9 +209,18 @@ mod runtime_metadata_tests {
let executable = root.join("bin/python3");
std::fs::create_dir_all(root.join("bin")).unwrap();
std::fs::write(&executable, "").unwrap();
write_package(&root.join("lib/python3/dist-packages"), "pip", "23.0", "Name: pip\nVersion: 23.0\n");
write_package(&root.join("lib/python3.13/site-packages"), "pip", "25.0", "Name: pip\nVersion: 25.0\n");
write_package(
&root.join("lib/python3/dist-packages"),
"pip",
"23.0",
"Name: pip\nVersion: 23.0\n",
);
write_package(
&root.join("lib/python3.13/site-packages"),
"pip",
"25.0",
"Name: pip\nVersion: 25.0\n",
);
assert!(runtime_versions(&executable, true, None).pip.is_none());
}
}