use super::{line::find_line_number, ExtractedPair};
pub fn parse_k8s_secret(text: &str) -> Vec<ExtractedPair> {
let mut pairs = Vec::new();
let value: serde_yaml::Value = match serde_yaml::from_str(text) {
Ok(v) => v,
Err(error) => {
tracing::debug!(target: "keyhog::structured", %error, "k8s secret YAML parse failed");
return pairs;
}
};
if let Some(serde_yaml::Value::Mapping(map)) = value.get("data") {
for (k, v) in map {
let key = k.as_str().unwrap_or_default();
let encoded = v.as_str().unwrap_or_default();
if key.is_empty() || encoded.is_empty() {
continue;
}
let decoded = match keyhog_core::encoding::decode_standard_base64(encoded) {
Ok(bytes) => String::from_utf8_lossy(&bytes).into_owned(),
Err(_) => continue,
};
let line = find_line_number(text, &format!("{}:", key))
.or_else(|| find_line_number(text, encoded))
.unwrap_or(1);
pairs.push(ExtractedPair {
context: key.to_string(),
value: decoded,
line,
});
}
}
if let Some(serde_yaml::Value::Mapping(map)) = value.get("stringData") {
for (k, v) in map {
let key = k.as_str().unwrap_or_default();
let secret_value = v.as_str().unwrap_or_default().to_string();
if key.is_empty() {
continue;
}
let line = find_line_number(text, key).unwrap_or(1);
pairs.push(ExtractedPair {
context: key.to_string(),
value: secret_value,
line,
});
}
}
pairs
}
pub fn parse_docker_compose(text: &str) -> Vec<ExtractedPair> {
let mut pairs = Vec::new();
let value: serde_yaml::Value = match serde_yaml::from_str(text) {
Ok(v) => v,
Err(error) => {
tracing::debug!(target: "keyhog::structured", %error, "docker-compose YAML parse failed");
return pairs;
}
};
find_environment_pairs(&value, text, &mut pairs, 0);
pairs
}
const MAX_COMPOSE_DEPTH: usize = 256;
fn find_environment_pairs(
value: &serde_yaml::Value,
text: &str,
pairs: &mut Vec<ExtractedPair>,
depth: usize,
) {
if depth >= MAX_COMPOSE_DEPTH {
return;
}
match value {
serde_yaml::Value::Mapping(map) => {
for (k, v) in map {
if k.as_str() == Some("environment") {
extract_environment_block(v, text, pairs);
} else {
find_environment_pairs(v, text, pairs, depth + 1);
}
}
}
serde_yaml::Value::Sequence(seq) => {
for v in seq {
find_environment_pairs(v, text, pairs, depth + 1);
}
}
_ => {}
}
}
fn extract_environment_block(
value: &serde_yaml::Value,
text: &str,
pairs: &mut Vec<ExtractedPair>,
) {
match value {
serde_yaml::Value::Mapping(map) => {
for (k, v) in map {
let key = k.as_str().unwrap_or_default();
let val = v.as_str().unwrap_or_default().to_string();
if key.is_empty() {
continue;
}
let line = find_line_number(text, key).unwrap_or(1);
pairs.push(ExtractedPair {
context: key.to_string(),
value: val,
line,
});
}
}
serde_yaml::Value::Sequence(seq) => {
for item in seq {
if let Some(s) = item.as_str() {
if let Some((key, val)) = s.split_once('=') {
if key.is_empty() {
continue;
}
let line = find_line_number(text, s).unwrap_or(1);
pairs.push(ExtractedPair {
context: key.to_string(),
value: val.to_string(),
line,
});
}
}
}
}
_ => {}
}
}