nix_compat/derivation/
validate.rs1use crate::derivation::{Derivation, DerivationError};
2use crate::store_path;
3
4pub fn validate_output_name(output_name: &str) -> Result<(), DerivationError> {
13 if output_name.is_empty()
14 || output_name == "drv"
15 || store_path::validate_name(output_name.as_bytes()).is_err()
16 {
17 return Err(DerivationError::InvalidOutputName(output_name.to_string()));
18 }
19 Ok(())
20}
21
22impl Derivation {
23 pub fn validate(&self, validate_output_paths: bool) -> Result<(), DerivationError> {
32 if self.outputs.is_empty() {
34 return Err(DerivationError::NoOutputs());
35 }
36
37 for (output_name, output) in &self.outputs {
39 validate_output_name(output_name)?;
40
41 if output.is_fixed() {
42 if self.outputs.len() != 1 {
43 return Err(DerivationError::MoreThanOneOutputButFixed());
44 }
45 if output_name != "out" {
46 return Err(DerivationError::InvalidOutputNameForFixed(
47 output_name.to_string(),
48 ));
49 }
50 }
51
52 if let Err(e) = output.validate(validate_output_paths) {
53 return Err(DerivationError::InvalidOutput(output_name.to_string(), e));
54 }
55 }
56
57 for (input_derivation_path, output_names) in &self.input_derivations {
59 if !input_derivation_path.name().ends_with(".drv") {
61 return Err(DerivationError::InvalidInputDerivationPrefix(
62 input_derivation_path.to_string(),
63 ));
64 }
65
66 if output_names.is_empty() {
67 return Err(DerivationError::EmptyInputDerivationOutputNames(
68 input_derivation_path.to_string(),
69 ));
70 }
71
72 for output_name in output_names.iter() {
73 if let Err(DerivationError::InvalidOutputName(_)) =
76 validate_output_name(output_name)
77 {
78 return Err(DerivationError::InvalidInputDerivationOutputName(
79 input_derivation_path.to_string(),
80 output_name.to_string(),
81 ));
82 }
83 }
84 }
85
86 if self.system.is_empty() {
88 return Err(DerivationError::InvalidPlatform(self.system.to_string()));
89 }
90
91 if self.builder.is_empty() {
93 return Err(DerivationError::InvalidBuilder(self.builder.to_string()));
94 }
95
96 for k in self.environment.keys() {
99 if k.is_empty() {
100 return Err(DerivationError::InvalidEnvironmentKey(k.to_string()));
101 }
102 }
103
104 Ok(())
105 }
106}
107
108#[cfg(test)]
109mod test {
110 use std::collections::BTreeMap;
111
112 use super::validate_output_name;
113 use crate::derivation::{CAHash, Derivation, DerivationError, Output};
114
115 #[test]
117 fn test_validate_output_name_valid() {
118 assert!(validate_output_name("out").is_ok());
120 assert!(validate_output_name("dev").is_ok());
121 assert!(validate_output_name("lib").is_ok());
122 assert!(validate_output_name("bin").is_ok());
123 assert!(validate_output_name("debug").is_ok());
124 }
125
126 #[test]
128 fn test_validate_output_name_invalid() {
129 assert!(matches!(
131 validate_output_name(""),
132 Err(DerivationError::InvalidOutputName(_))
133 ));
134
135 assert!(matches!(
137 validate_output_name("drv"),
138 Err(DerivationError::InvalidOutputName(_))
139 ));
140
141 assert!(matches!(
143 validate_output_name("invalid/name"),
144 Err(DerivationError::InvalidOutputName(_))
145 ));
146
147 assert!(matches!(
148 validate_output_name("invalid name"),
149 Err(DerivationError::InvalidOutputName(_))
150 ));
151 }
152
153 #[test]
156 fn output_validate() {
157 let mut outputs = BTreeMap::new();
158 outputs.insert(
159 "out".to_string(),
160 Output {
161 path: None,
162 ca_hash: Some(CAHash::Text([0; 32])), },
164 );
165
166 let drv = Derivation {
167 arguments: vec![],
168 builder: "/bin/sh".to_string(),
169 outputs,
170 system: "x86_64-linux".to_string(),
171 ..Default::default()
172 };
173
174 drv.validate(false).expect_err("must fail");
175 }
176}