feat(tvix/glue): emit a warning in case of bad SRI hashes

And include a test to ensure we show the warning.

Change-Id: Ib6a436dbba2592b398b54e44f15a48d1aa345099
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10470
Tested-by: BuildkiteCI
Reviewed-by: raitobezarius <tvl@lahfa.xyz>
This commit is contained in:
Florian Klink 2023-12-30 03:01:59 +01:00 committed by tazjin
parent d5aa75bbcf
commit 6b136dfd23
6 changed files with 50 additions and 3 deletions

View file

@ -106,12 +106,14 @@ fn populate_inputs<I: IntoIterator<Item = PathName>>(
/// (lowercase) hex encoding of the digest.
///
/// These values are only rewritten for the outputs, not what's passed to env.
///
/// The return value may optionally contain a warning.
fn handle_fixed_output(
drv: &mut Derivation,
hash_str: Option<String>, // in nix: outputHash
hash_algo_str: Option<String>, // in nix: outputHashAlgo
hash_mode_str: Option<String>, // in nix: outputHashmode
) -> Result<(), ErrorKind> {
) -> Result<Option<WarningKind>, ErrorKind> {
// If outputHash is provided, ensure hash_algo_str is compatible.
// If outputHash is not provided, do nothing.
if let Some(hash_str) = hash_str {
@ -125,6 +127,7 @@ fn handle_fixed_output(
// construct a NixHash.
let nixhash = nixhash::from_str(&hash_str, hash_algo_str.as_deref())
.map_err(DerivationError::InvalidOutputHash)?;
let algo = nixhash.algo();
// construct the fixed output.
drv.outputs.insert(
@ -140,8 +143,18 @@ fn handle_fixed_output(
},
},
);
// Peek at hash_str once more.
// If it was a SRI hash, but is not using the correct length, this means
// the padding was wrong. Emit a warning in that case.
let sri_prefix = format!("{}-", algo);
if let Some(rest) = hash_str.strip_prefix(&sri_prefix) {
if data_encoding::BASE64.encode_len(algo.digest_length()) != rest.len() {
return Ok(Some(WarningKind::SRIHashWrongPadding));
}
}
}
Ok(())
Ok(None)
}
/// Handles derivation parameters which are not just forwarded to
@ -349,7 +362,12 @@ pub(crate) mod derivation_builtins {
Err(cek) => return Ok(Value::Catchable(cek)),
Ok(s) => s,
};
handle_fixed_output(&mut drv, output_hash, output_hash_algo, output_hash_mode)?;
if let Some(warning) =
handle_fixed_output(&mut drv, output_hash, output_hash_algo, output_hash_mode)?
{
emit_warning_kind(&co, warning).await;
}
}
// Scan references in relevant attributes to detect any build-references.

View file

@ -154,4 +154,24 @@ mod tests {
"/171rf4jhx57xqz3p7swniwkig249cif71pa08p80mgaf0mqz5bmr"
);
}
/// constructs calls to builtins.derivation that should succeed, but produce warnings
#[test_case(r#"(builtins.derivation { name = "foo"; builder = "/bin/sh"; system = "x86_64-linux"; outputHashMode = "recursive"; outputHashAlgo = "sha256"; outputHash = "sha256-fgIr3TyFGDAXP5+qoAaiMKDg/a1MlT6Fv/S/DaA24S8===="; }).outPath"#, "/nix/store/xm1l9dx4zgycv9qdhcqqvji1z88z534b-foo"; "r:sha256 wrong padding")]
fn builtins_derivation_hash_wrong_padding_warn(code: &str, expected_path: &str) {
let eval_result = eval(code);
let value = eval_result.value.expect("must succeed");
match value {
tvix_eval::Value::String(s) => {
assert_eq!(expected_path, s.as_str());
}
_ => panic!("unexpected value type: {:?}", value),
}
assert!(
!eval_result.warnings.is_empty(),
"warnings should not be empty"
);
}
}