Private
Public Access
1
0

Compare commits

..

3 Commits

Author SHA1 Message Date
04a16ab862 chore: bump version to 1.3.1
Some checks failed
CI/CD Pipeline / Code Format (push) Successful in 1s
CI/CD Pipeline / Clippy Lints (push) Successful in 43s
CI/CD Pipeline / All Unit Tests (push) Successful in 1m50s
CI/CD Pipeline / Security Audit (push) Successful in 7s
CI/CD Pipeline / Enrollment Tests (push) Successful in 1m22s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Failing after 4s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 1m1s
CI/CD Pipeline / Build Debian Package (push) Failing after 3s
CI/CD Pipeline / Build Arch Package (push) Successful in 2m16s
CI/CD Pipeline / Build RPM Package (push) Successful in 2m9s
CI/CD Pipeline / Build Alpine Package (push) Failing after 3m0s
Co-authored-by: git-echo <git-echo@moon-dragon.us>
2026-06-06 00:45:58 -05:00
624f9017b3 fix: add ca_chain and crl_pem to enrollment response and persist CRL to disk
Co-authored-by: git-echo <git-echo@moon-dragon.us>
2026-06-06 00:38:43 -05:00
70f2666c2e chore: bump version to 1.3.0
Some checks failed
CI/CD Pipeline / Code Format (push) Successful in 4s
CI/CD Pipeline / Clippy Lints (push) Successful in 43s
CI/CD Pipeline / All Unit Tests (push) Successful in 1m17s
CI/CD Pipeline / Security Audit (push) Successful in 6s
CI/CD Pipeline / Enrollment Tests (push) Successful in 1m22s
CI/CD Pipeline / Build Debian Package (Ubuntu 22.04) (push) Failing after 5s
CI/CD Pipeline / Verify Enrollment CLI Flag (push) Successful in 1m0s
CI/CD Pipeline / Build Debian Package (push) Failing after 4s
CI/CD Pipeline / Build Arch Package (push) Successful in 2m19s
CI/CD Pipeline / Build RPM Package (push) Successful in 2m13s
CI/CD Pipeline / Build Alpine Package (push) Failing after 3m2s
Co-authored-by: git-echo <git-echo@moon-dragon.us>
2026-06-05 17:41:04 -05:00
6 changed files with 42 additions and 3 deletions

2
Cargo.lock generated
View File

@ -1931,7 +1931,7 @@ dependencies = [
[[package]]
name = "linux-patch-api"
version = "1.2.0"
version = "1.3.0"
dependencies = [
"actix",
"actix-rt",

View File

@ -1,6 +1,6 @@
[package]
name = "linux-patch-api"
version = "1.3.0"
version = "1.3.1"
edition = "2021"
authors = ["Echo <echo@moon-dragon.us>"]
description = "Secure remote package management API for Linux systems"

View File

@ -38,8 +38,12 @@ pub enum EnrollmentStatusResponse {
Pending,
Approved {
ca_crt: String,
#[serde(default)]
ca_chain: String,
server_crt: String,
server_key: String,
#[serde(default)]
crl_pem: String,
},
Denied,
NotFound,
@ -49,8 +53,10 @@ pub enum EnrollmentStatusResponse {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PkiBundle {
pub ca_crt: String,
pub ca_chain: String,
pub server_crt: String,
pub server_key: String,
pub crl_pem: String,
}
impl From<EnrollmentStatusResponse> for Option<PkiBundle> {
@ -58,12 +64,16 @@ impl From<EnrollmentStatusResponse> for Option<PkiBundle> {
match response {
EnrollmentStatusResponse::Approved {
ca_crt,
ca_chain,
server_crt,
server_key,
crl_pem,
} => Some(PkiBundle {
ca_crt,
ca_chain,
server_crt,
server_key,
crl_pem,
}),
_ => None,
}
@ -451,8 +461,10 @@ impl EnrollmentClient {
}
EnrollmentStatusResponse::Approved {
ca_crt,
ca_chain,
server_crt,
server_key,
crl_pem,
} => {
tracing::info!(
elapsed_seconds = start.elapsed().as_secs(),
@ -461,8 +473,10 @@ impl EnrollmentClient {
);
return Ok(PkiBundle {
ca_crt,
ca_chain,
server_crt,
server_key,
crl_pem,
});
}
EnrollmentStatusResponse::Denied => {
@ -566,8 +580,10 @@ mod tests {
fn approved_to_pki_bundle() {
let status = EnrollmentStatusResponse::Approved {
ca_crt: "ca".into(),
ca_chain: String::new(),
server_crt: "crt".into(),
server_key: "key".into(),
crl_pem: String::new(),
};
let bundle: Option<PkiBundle> = status.into();
assert!(bundle.is_some());

View File

@ -160,8 +160,10 @@ pub async fn run_enrollment(
// Write certificates to configured paths (or defaults)
provision::provision_pki_bundle(
&pki_bundle.ca_crt,
&pki_bundle.ca_chain,
&pki_bundle.server_crt,
&pki_bundle.server_key,
&pki_bundle.crl_pem,
config.tls_config(),
)
.await?;

View File

@ -16,6 +16,8 @@ const DEFAULT_CA_CERT: &str = "/etc/linux_patch_api/certs/ca.pem";
const DEFAULT_SERVER_CERT: &str = "/etc/linux_patch_api/certs/server.pem";
/// Default server key path.
const DEFAULT_SERVER_KEY: &str = "/etc/linux_patch_api/certs/server.key.pem";
/// Default CRL path.
const DEFAULT_CRL_PATH: &str = "/etc/linux_patch_api/certs/crl.pem";
/// Validate that a PEM string has proper format (BEGIN/END markers present).
///
@ -128,12 +130,14 @@ pub fn write_pem_file(path: &str, pem_data: &str, is_key: bool) -> Result<()> {
/// Provision the full PKI bundle from an approved enrollment response.
///
/// Writes CA cert, server cert, and server key to configured paths.
/// Writes CA cert, CA chain, server cert, server key, and CRL to configured paths.
/// Paths are read from TLS config if available, otherwise defaults are used.
pub async fn provision_pki_bundle(
ca_crt: &str,
_ca_chain: &str,
server_crt: &str,
server_key: &str,
crl_pem: &str,
tls_config: Option<&super::super::config::loader::TlsConfig>,
) -> Result<()> {
// Determine target paths from config or defaults
@ -173,6 +177,19 @@ pub async fn provision_pki_bundle(
write_pem_file(&key_path, server_key, true).context("Failed to write server key")?;
// Write CRL if provided (non-empty)
let crl_path = if let Some(tls) = tls_config {
tls.crl_path.clone()
} else {
DEFAULT_CRL_PATH.to_string()
};
if !crl_pem.trim().is_empty() {
write_pem_file(&crl_path, crl_pem, false).context("Failed to write CRL")?;
tracing::info!(path = %crl_path, "CRL written from enrollment bundle");
} else {
tracing::info!("No CRL in enrollment bundle — agent will fetch on refresh cycle");
}
// 3. Log successful provisioning with structured fields
tracing::info!(
ca_cert = %ca_path,

View File

@ -178,8 +178,10 @@ async fn test_full_enrollment_flow_happy_path() {
let tls_config = build_tls_config(cert_dir.path());
provision::provision_pki_bundle(
&bundle.ca_crt,
&bundle.ca_chain,
&bundle.server_crt,
&bundle.server_key,
&bundle.crl_pem,
Some(&tls_config),
)
.await
@ -445,8 +447,10 @@ async fn test_certificate_permission_verification() {
let tls_config = build_tls_config(cert_dir.path());
provision::provision_pki_bundle(
&bundle.ca_crt,
&bundle.ca_chain,
&bundle.server_crt,
&bundle.server_key,
&bundle.crl_pem,
Some(&tls_config),
)
.await