mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-07 00:01:49 +00:00
fix: smarter secret masking based on secret length (#8629)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
3876902a7b
commit
bfc2aefdb8
@@ -215,8 +215,8 @@ export async function main() {
|
||||
"scenario 1: secret value leaked in logs\nLogs:\n{logs1}"
|
||||
);
|
||||
assert!(
|
||||
logs1.contains("The secret value is: alp*****"),
|
||||
"scenario 1: expected masked output with first 3 chars\nLogs:\n{logs1}"
|
||||
logs1.contains("The secret value is: alp*****k2m"),
|
||||
"scenario 1: expected masked output with first 3 + last 3 chars\nLogs:\n{logs1}"
|
||||
);
|
||||
assert!(
|
||||
logs1.contains("[windmill] secret value was masked for security reasons, use string transformations to display full value"),
|
||||
@@ -277,11 +277,11 @@ export async function main() {
|
||||
"scenario 3: secret2 leaked\nLogs:\n{logs3}"
|
||||
);
|
||||
assert!(
|
||||
logs3.contains("secret1=alp*****"),
|
||||
logs3.contains("secret1=alp*****k2m"),
|
||||
"scenario 3: secret1 not masked\nLogs:\n{logs3}"
|
||||
);
|
||||
assert!(
|
||||
logs3.contains("secret2=bet*****"),
|
||||
logs3.contains("secret2=bet*****n3p"),
|
||||
"scenario 3: secret2 not masked\nLogs:\n{logs3}"
|
||||
);
|
||||
|
||||
@@ -309,7 +309,7 @@ export async function main() {
|
||||
"scenario 4: secret leaked mid-string\nLogs:\n{logs4}"
|
||||
);
|
||||
assert!(
|
||||
logs4.contains("token=alp*****&user=bob&format=json"),
|
||||
logs4.contains("token=alp*****k2m&user=bob&format=json"),
|
||||
"scenario 4: mid-string masking failed\nLogs:\n{logs4}"
|
||||
);
|
||||
|
||||
@@ -338,7 +338,7 @@ export async function main() {
|
||||
!logs5.contains(secret2),
|
||||
"scenario 5: secret leaked\nLogs:\n{logs5}"
|
||||
);
|
||||
let mask_count = logs5.matches("bet*****").count();
|
||||
let mask_count = logs5.matches("bet*****n3p").count();
|
||||
assert!(
|
||||
mask_count >= 3,
|
||||
"scenario 5: expected >= 3 masked occurrences, found {mask_count}\nLogs:\n{logs5}"
|
||||
@@ -374,7 +374,7 @@ export async function main() {
|
||||
"scenario 6: encrypted password leaked\nLogs:\n{logs6}"
|
||||
);
|
||||
assert!(
|
||||
logs6.contains("password is: enc*****"),
|
||||
logs6.contains("password is: enc*****q5r"),
|
||||
"scenario 6: encrypted password not masked\nLogs:\n{logs6}"
|
||||
);
|
||||
|
||||
@@ -403,7 +403,7 @@ export async function main() {
|
||||
"scenario 7: resource secret leaked\nLogs:\n{logs7}"
|
||||
);
|
||||
assert!(
|
||||
logs7.contains("db password: res*****"),
|
||||
logs7.contains("db password: res*****7t2"),
|
||||
"scenario 7: resource secret not masked\nLogs:\n{logs7}"
|
||||
);
|
||||
// Non-secret field should remain visible
|
||||
|
||||
@@ -88,8 +88,16 @@ pub fn snapshot(job_id: &Uuid) -> Option<MaskSnapshot> {
|
||||
let replacements: Vec<String> = sorted
|
||||
.iter()
|
||||
.map(|s| {
|
||||
let prefix: String = s.chars().take(3).collect();
|
||||
format!("{}*****", prefix)
|
||||
let char_count = s.chars().count();
|
||||
if char_count > 20 {
|
||||
let prefix: String = s.chars().take(3).collect();
|
||||
let suffix: String = s.chars().skip(char_count - 3).collect();
|
||||
format!("{}*****{}", prefix, suffix)
|
||||
} else {
|
||||
let first: String = s.chars().take(1).collect();
|
||||
let last: String = s.chars().skip(char_count - 1).collect();
|
||||
format!("{}*****{}", first, last)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user