sentry-options 0.0.4__tar.gz → 0.0.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,6 +31,15 @@ version = "0.2.21"
31
31
  source = "registry+https://github.com/rust-lang/crates.io-index"
32
32
  checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
33
33
 
34
+ [[package]]
35
+ name = "android_system_properties"
36
+ version = "0.1.5"
37
+ source = "registry+https://github.com/rust-lang/crates.io-index"
38
+ checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
39
+ dependencies = [
40
+ "libc",
41
+ ]
42
+
34
43
  [[package]]
35
44
  name = "anstream"
36
45
  version = "0.6.21"
@@ -150,12 +159,33 @@ version = "1.11.0"
150
159
  source = "registry+https://github.com/rust-lang/crates.io-index"
151
160
  checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3"
152
161
 
162
+ [[package]]
163
+ name = "cc"
164
+ version = "1.2.52"
165
+ source = "registry+https://github.com/rust-lang/crates.io-index"
166
+ checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
167
+ dependencies = [
168
+ "find-msvc-tools",
169
+ "shlex",
170
+ ]
171
+
153
172
  [[package]]
154
173
  name = "cfg-if"
155
174
  version = "1.0.4"
156
175
  source = "registry+https://github.com/rust-lang/crates.io-index"
157
176
  checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
158
177
 
178
+ [[package]]
179
+ name = "chrono"
180
+ version = "0.4.43"
181
+ source = "registry+https://github.com/rust-lang/crates.io-index"
182
+ checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118"
183
+ dependencies = [
184
+ "iana-time-zone",
185
+ "num-traits",
186
+ "windows-link",
187
+ ]
188
+
159
189
  [[package]]
160
190
  name = "clap"
161
191
  version = "4.5.53"
@@ -202,6 +232,12 @@ version = "1.0.4"
202
232
  source = "registry+https://github.com/rust-lang/crates.io-index"
203
233
  checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75"
204
234
 
235
+ [[package]]
236
+ name = "core-foundation-sys"
237
+ version = "0.8.7"
238
+ source = "registry+https://github.com/rust-lang/crates.io-index"
239
+ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
240
+
205
241
  [[package]]
206
242
  name = "displaydoc"
207
243
  version = "0.2.5"
@@ -240,7 +276,7 @@ dependencies = [
240
276
 
241
277
  [[package]]
242
278
  name = "example"
243
- version = "0.0.4"
279
+ version = "0.0.6"
244
280
  dependencies = [
245
281
  "anyhow",
246
282
  "sentry-options",
@@ -264,6 +300,12 @@ version = "2.3.0"
264
300
  source = "registry+https://github.com/rust-lang/crates.io-index"
265
301
  checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
266
302
 
303
+ [[package]]
304
+ name = "find-msvc-tools"
305
+ version = "0.1.7"
306
+ source = "registry+https://github.com/rust-lang/crates.io-index"
307
+ checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
308
+
267
309
  [[package]]
268
310
  name = "fluent-uri"
269
311
  version = "0.4.1"
@@ -472,6 +514,30 @@ dependencies = [
472
514
  "tracing",
473
515
  ]
474
516
 
517
+ [[package]]
518
+ name = "iana-time-zone"
519
+ version = "0.1.64"
520
+ source = "registry+https://github.com/rust-lang/crates.io-index"
521
+ checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
522
+ dependencies = [
523
+ "android_system_properties",
524
+ "core-foundation-sys",
525
+ "iana-time-zone-haiku",
526
+ "js-sys",
527
+ "log",
528
+ "wasm-bindgen",
529
+ "windows-core",
530
+ ]
531
+
532
+ [[package]]
533
+ name = "iana-time-zone-haiku"
534
+ version = "0.1.2"
535
+ source = "registry+https://github.com/rust-lang/crates.io-index"
536
+ checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
537
+ dependencies = [
538
+ "cc",
539
+ ]
540
+
475
541
  [[package]]
476
542
  name = "icu_collections"
477
543
  version = "2.1.1"
@@ -1111,7 +1177,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
1111
1177
 
1112
1178
  [[package]]
1113
1179
  name = "sentry-options"
1114
- version = "0.0.4"
1180
+ version = "0.0.6"
1115
1181
  dependencies = [
1116
1182
  "sentry-options-validation",
1117
1183
  "serde_json",
@@ -1121,8 +1187,9 @@ dependencies = [
1121
1187
 
1122
1188
  [[package]]
1123
1189
  name = "sentry-options-cli"
1124
- version = "0.0.4"
1190
+ version = "0.0.6"
1125
1191
  dependencies = [
1192
+ "chrono",
1126
1193
  "clap",
1127
1194
  "sentry-options-validation",
1128
1195
  "serde",
@@ -1135,7 +1202,7 @@ dependencies = [
1135
1202
 
1136
1203
  [[package]]
1137
1204
  name = "sentry-options-python"
1138
- version = "0.0.4"
1205
+ version = "0.0.6"
1139
1206
  dependencies = [
1140
1207
  "pyo3",
1141
1208
  "sentry-options",
@@ -1144,7 +1211,7 @@ dependencies = [
1144
1211
 
1145
1212
  [[package]]
1146
1213
  name = "sentry-options-validation"
1147
- version = "0.0.4"
1214
+ version = "0.0.6"
1148
1215
  dependencies = [
1149
1216
  "anyhow",
1150
1217
  "jsonschema",
@@ -1222,6 +1289,12 @@ dependencies = [
1222
1289
  "unsafe-libyaml",
1223
1290
  ]
1224
1291
 
1292
+ [[package]]
1293
+ name = "shlex"
1294
+ version = "1.3.0"
1295
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1296
+ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
1297
+
1225
1298
  [[package]]
1226
1299
  name = "slab"
1227
1300
  version = "0.4.11"
@@ -1600,12 +1673,65 @@ dependencies = [
1600
1673
  "windows-sys 0.61.2",
1601
1674
  ]
1602
1675
 
1676
+ [[package]]
1677
+ name = "windows-core"
1678
+ version = "0.62.2"
1679
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1680
+ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
1681
+ dependencies = [
1682
+ "windows-implement",
1683
+ "windows-interface",
1684
+ "windows-link",
1685
+ "windows-result",
1686
+ "windows-strings",
1687
+ ]
1688
+
1689
+ [[package]]
1690
+ name = "windows-implement"
1691
+ version = "0.60.2"
1692
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1693
+ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
1694
+ dependencies = [
1695
+ "proc-macro2",
1696
+ "quote",
1697
+ "syn",
1698
+ ]
1699
+
1700
+ [[package]]
1701
+ name = "windows-interface"
1702
+ version = "0.59.3"
1703
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1704
+ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
1705
+ dependencies = [
1706
+ "proc-macro2",
1707
+ "quote",
1708
+ "syn",
1709
+ ]
1710
+
1603
1711
  [[package]]
1604
1712
  name = "windows-link"
1605
1713
  version = "0.2.1"
1606
1714
  source = "registry+https://github.com/rust-lang/crates.io-index"
1607
1715
  checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
1608
1716
 
1717
+ [[package]]
1718
+ name = "windows-result"
1719
+ version = "0.4.1"
1720
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1721
+ checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
1722
+ dependencies = [
1723
+ "windows-link",
1724
+ ]
1725
+
1726
+ [[package]]
1727
+ name = "windows-strings"
1728
+ version = "0.5.1"
1729
+ source = "registry+https://github.com/rust-lang/crates.io-index"
1730
+ checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
1731
+ dependencies = [
1732
+ "windows-link",
1733
+ ]
1734
+
1609
1735
  [[package]]
1610
1736
  name = "windows-sys"
1611
1737
  version = "0.60.2"
@@ -11,13 +11,13 @@ default-members = [
11
11
  ]
12
12
 
13
13
  [workspace.package]
14
- version = "0.0.4"
14
+ version = "0.0.6"
15
15
  edition = "2024"
16
16
  repository = "https://github.com/getsentry/sentry-options"
17
17
  license = "Apache-2.0"
18
18
 
19
19
  [workspace.dependencies]
20
- sentry-options-validation = { path = "sentry-options-validation", version = "0.0.4" }
20
+ sentry-options-validation = { path = "sentry-options-validation", version = "0.0.6" }
21
21
  serde = { version = "1.0", features = ["derive"] }
22
22
  serde_json = "1.0.145"
23
23
  anyhow = "1.0.100"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sentry_options
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Classifier: Programming Language :: Python :: 3
5
5
  Classifier: Programming Language :: Python :: 3 :: Only
6
6
  Classifier: Programming Language :: Python :: Implementation :: CPython
@@ -79,7 +79,8 @@ fn options_err(err: RustOptionsError) -> PyErr {
79
79
  }
80
80
  }
81
81
 
82
- /// Initialize global options from default path or SENTRY_OPTIONS_DIR env var.
82
+ /// Initialize global options using fallback chain: SENTRY_OPTIONS_DIR env var,
83
+ /// then /etc/sentry-options if it exists, otherwise sentry-options/.
83
84
  #[pyfunction]
84
85
  fn init() -> PyResult<()> {
85
86
  let opts = RustOptions::new().map_err(options_err)?;
@@ -1,16 +1,15 @@
1
1
  //! Options client for reading validated configuration values.
2
2
 
3
3
  use std::collections::HashMap;
4
- use std::path::{Path, PathBuf};
4
+ use std::path::Path;
5
5
  use std::sync::{Arc, OnceLock, RwLock};
6
6
 
7
- use sentry_options_validation::{SchemaRegistry, ValidationError, ValuesWatcher};
7
+ use sentry_options_validation::{
8
+ SchemaRegistry, ValidationError, ValuesWatcher, resolve_options_dir,
9
+ };
8
10
  use serde_json::Value;
9
11
  use thiserror::Error;
10
12
 
11
- const DEFAULT_OPTIONS_DIR: &str = "/etc/sentry-options";
12
- const OPTIONS_DIR_ENV: &str = "SENTRY_OPTIONS_DIR";
13
-
14
13
  static GLOBAL_OPTIONS: OnceLock<Options> = OnceLock::new();
15
14
 
16
15
  #[derive(Debug, Error)]
@@ -38,14 +37,11 @@ pub struct Options {
38
37
  }
39
38
 
40
39
  impl Options {
41
- /// Load options from default path (`/etc/sentry-options`) or `SENTRY_OPTIONS_DIR` env var.
40
+ /// Load options using fallback chain: `SENTRY_OPTIONS_DIR` env var, then `/etc/sentry-options`
41
+ /// if it exists, otherwise `sentry-options/`.
42
42
  /// Expects `{dir}/schemas/` and `{dir}/values/` subdirectories.
43
43
  pub fn new() -> Result<Self> {
44
- let base_dir = std::env::var(OPTIONS_DIR_ENV)
45
- .map(PathBuf::from)
46
- .unwrap_or_else(|_| PathBuf::from(DEFAULT_OPTIONS_DIR));
47
-
48
- Self::from_directory(&base_dir)
44
+ Self::from_directory(&resolve_options_dir())
49
45
  }
50
46
 
51
47
  /// Load options from a specific directory (useful for testing).
@@ -98,7 +94,8 @@ impl Options {
98
94
  }
99
95
  }
100
96
 
101
- /// Initialize global options from default path or `SENTRY_OPTIONS_DIR` env var.
97
+ /// Initialize global options using fallback chain: `SENTRY_OPTIONS_DIR` env var,
98
+ /// then `/etc/sentry-options` if it exists, otherwise `sentry-options/`.
102
99
  pub fn init() -> Result<()> {
103
100
  let opts = Options::new()?;
104
101
  GLOBAL_OPTIONS
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "sentry_options"
7
- version = "0.0.4"
7
+ version = "0.0.6"
8
8
  description = "Python client for sentry-options using Rust validation"
9
9
  license = "Apache-2.0"
10
10
  requires-python = ">=3.11"
@@ -26,6 +26,32 @@ const VALUES_FILE_NAME: &str = "values.json";
26
26
  /// Time between file polls in seconds
27
27
  const POLLING_DELAY: u64 = 5;
28
28
 
29
+ /// Production path where options are deployed via config map
30
+ pub const PRODUCTION_OPTIONS_DIR: &str = "/etc/sentry-options";
31
+
32
+ /// Local fallback path for development
33
+ pub const LOCAL_OPTIONS_DIR: &str = "sentry-options";
34
+
35
+ /// Environment variable to override options directory
36
+ pub const OPTIONS_DIR_ENV: &str = "SENTRY_OPTIONS_DIR";
37
+
38
+ /// Resolve options directory using fallback chain:
39
+ /// 1. `SENTRY_OPTIONS_DIR` env var (if set)
40
+ /// 2. `/etc/sentry-options` (if exists)
41
+ /// 3. `sentry-options/` (local fallback)
42
+ pub fn resolve_options_dir() -> PathBuf {
43
+ if let Ok(dir) = std::env::var(OPTIONS_DIR_ENV) {
44
+ return PathBuf::from(dir);
45
+ }
46
+
47
+ let prod_path = PathBuf::from(PRODUCTION_OPTIONS_DIR);
48
+ if prod_path.exists() {
49
+ return prod_path;
50
+ }
51
+
52
+ PathBuf::from(LOCAL_OPTIONS_DIR)
53
+ }
54
+
29
55
  /// Result type for validation operations
30
56
  pub type ValidationResult<T> = Result<T, ValidationError>;
31
57
 
@@ -52,12 +78,56 @@ pub enum ValidationError {
52
78
 
53
79
  #[error("Failed to parse JSON: {0}")]
54
80
  JSONParse(#[from] serde_json::Error),
81
+
82
+ #[error("{} validation error(s)", .0.len())]
83
+ ValidationErrors(Vec<ValidationError>),
84
+
85
+ #[error("Invalid {label} '{name}': {reason}")]
86
+ InvalidName {
87
+ label: String,
88
+ name: String,
89
+ reason: String,
90
+ },
91
+ }
92
+
93
+ /// Validate a name component is valid for K8s (lowercase alphanumeric, '-', '.')
94
+ pub fn validate_k8s_name_component(name: &str, label: &str) -> ValidationResult<()> {
95
+ if let Some(c) = name
96
+ .chars()
97
+ .find(|&c| !matches!(c, 'a'..='z' | '0'..='9' | '-' | '.'))
98
+ {
99
+ return Err(ValidationError::InvalidName {
100
+ label: label.to_string(),
101
+ name: name.to_string(),
102
+ reason: format!(
103
+ "character '{}' not allowed. Use lowercase alphanumeric, '-', or '.'",
104
+ c
105
+ ),
106
+ });
107
+ }
108
+ if !name.starts_with(|c: char| c.is_ascii_alphanumeric())
109
+ || !name.ends_with(|c: char| c.is_ascii_alphanumeric())
110
+ {
111
+ return Err(ValidationError::InvalidName {
112
+ label: label.to_string(),
113
+ name: name.to_string(),
114
+ reason: "must start and end with alphanumeric".to_string(),
115
+ });
116
+ }
117
+ Ok(())
55
118
  }
56
119
 
57
- /// Schema for a namespace, containing validator and defaults
120
+ /// Metadata for a single option in a namespace schema
121
+ #[derive(Debug, Clone)]
122
+ pub struct OptionMetadata {
123
+ pub option_type: String,
124
+ pub default: Value,
125
+ }
126
+
127
+ /// Schema for a namespace, containing validator and option metadata
58
128
  pub struct NamespaceSchema {
59
129
  pub namespace: String,
60
- defaults: HashMap<String, Value>,
130
+ pub options: HashMap<String, OptionMetadata>,
61
131
  validator: jsonschema::Validator,
62
132
  }
63
133
 
@@ -85,7 +155,7 @@ impl NamespaceSchema {
85
155
  /// Get the default value for an option key.
86
156
  /// Returns None if the key doesn't exist in the schema.
87
157
  pub fn get_default(&self, key: &str) -> Option<&Value> {
88
- self.defaults.get(key)
158
+ self.options.get(key).map(|meta| &meta.default)
89
159
  }
90
160
  }
91
161
 
@@ -166,6 +236,8 @@ impl SchemaRegistry {
166
236
  message: "Directory name contains invalid UTF-8".to_string(),
167
237
  })?;
168
238
 
239
+ validate_k8s_name_component(&namespace, "namespace name")?;
240
+
169
241
  let schema_file = entry.path().join(SCHEMA_FILE_NAME);
170
242
  let schema = Self::load_schema(&schema_file, &namespace, &namespace_validator)?;
171
243
  schemas.insert(namespace, schema);
@@ -254,8 +326,8 @@ impl SchemaRegistry {
254
326
  message: format!("Failed to compile validator: {}", e),
255
327
  })?;
256
328
 
257
- // Extract defaults and validate types
258
- let mut defaults = HashMap::new();
329
+ // Extract option metadata and validate types
330
+ let mut options = HashMap::new();
259
331
  if let Some(properties) = schema.get("properties").and_then(|p| p.as_object()) {
260
332
  for (prop_name, prop_value) in properties {
261
333
  if let (Some(prop_type), Some(default_value)) = (
@@ -263,14 +335,20 @@ impl SchemaRegistry {
263
335
  prop_value.get("default"),
264
336
  ) {
265
337
  Self::validate_default_type(prop_name, prop_type, default_value, path)?;
266
- defaults.insert(prop_name.clone(), default_value.clone());
338
+ options.insert(
339
+ prop_name.clone(),
340
+ OptionMetadata {
341
+ option_type: prop_type.to_string(),
342
+ default: default_value.clone(),
343
+ },
344
+ );
267
345
  }
268
346
  }
269
347
  }
270
348
 
271
349
  Ok(Arc::new(NamespaceSchema {
272
350
  namespace: namespace.to_string(),
273
- defaults,
351
+ options,
274
352
  validator,
275
353
  }))
276
354
  }
@@ -280,6 +358,11 @@ impl SchemaRegistry {
280
358
  self.schemas.get(namespace)
281
359
  }
282
360
 
361
+ /// Get all loaded schemas (for schema evolution validation)
362
+ pub fn schemas(&self) -> &HashMap<String, Arc<NamespaceSchema>> {
363
+ &self.schemas
364
+ }
365
+
283
366
  /// Load and validate JSON values from a directory.
284
367
  /// Expects structure: `{values_dir}/{namespace}/values.json`
285
368
  /// Skips namespaces without a values.json file.
@@ -488,6 +571,52 @@ mod tests {
488
571
  schema_file
489
572
  }
490
573
 
574
+ #[test]
575
+ fn test_validate_k8s_name_component_valid() {
576
+ assert!(validate_k8s_name_component("relay", "namespace").is_ok());
577
+ assert!(validate_k8s_name_component("my-service", "namespace").is_ok());
578
+ assert!(validate_k8s_name_component("my.service", "namespace").is_ok());
579
+ assert!(validate_k8s_name_component("a1-b2.c3", "namespace").is_ok());
580
+ }
581
+
582
+ #[test]
583
+ fn test_validate_k8s_name_component_rejects_uppercase() {
584
+ let result = validate_k8s_name_component("MyService", "namespace");
585
+ assert!(matches!(result, Err(ValidationError::InvalidName { .. })));
586
+ assert!(result.unwrap_err().to_string().contains("'M' not allowed"));
587
+ }
588
+
589
+ #[test]
590
+ fn test_validate_k8s_name_component_rejects_underscore() {
591
+ let result = validate_k8s_name_component("my_service", "target");
592
+ assert!(matches!(result, Err(ValidationError::InvalidName { .. })));
593
+ assert!(result.unwrap_err().to_string().contains("'_' not allowed"));
594
+ }
595
+
596
+ #[test]
597
+ fn test_validate_k8s_name_component_rejects_leading_hyphen() {
598
+ let result = validate_k8s_name_component("-service", "namespace");
599
+ assert!(matches!(result, Err(ValidationError::InvalidName { .. })));
600
+ assert!(
601
+ result
602
+ .unwrap_err()
603
+ .to_string()
604
+ .contains("start and end with alphanumeric")
605
+ );
606
+ }
607
+
608
+ #[test]
609
+ fn test_validate_k8s_name_component_rejects_trailing_dot() {
610
+ let result = validate_k8s_name_component("service.", "namespace");
611
+ assert!(matches!(result, Err(ValidationError::InvalidName { .. })));
612
+ assert!(
613
+ result
614
+ .unwrap_err()
615
+ .to_string()
616
+ .contains("start and end with alphanumeric")
617
+ );
618
+ }
619
+
491
620
  #[test]
492
621
  fn test_load_schema_valid() {
493
622
  let temp_dir = TempDir::new().unwrap();
@@ -677,7 +806,7 @@ Error: \"version\" is a required property"
677
806
  fn test_invalid_directory_structure() {
678
807
  let temp_dir = TempDir::new().unwrap();
679
808
  // Create a namespace directory without schema.json file
680
- let schema_dir = temp_dir.path().join("missing_schema");
809
+ let schema_dir = temp_dir.path().join("missing-schema");
681
810
  fs::create_dir_all(&schema_dir).unwrap();
682
811
 
683
812
  let result = SchemaRegistry::from_directory(temp_dir.path());
@@ -893,7 +1022,7 @@ Error: \"version\" is a required property"
893
1022
  let values_dir = temp_dir.path().join("values");
894
1023
 
895
1024
  // Create two schemas
896
- let schema_dir1 = schemas_dir.join("with_values");
1025
+ let schema_dir1 = schemas_dir.join("with-values");
897
1026
  fs::create_dir_all(&schema_dir1).unwrap();
898
1027
  fs::write(
899
1028
  schema_dir1.join("schema.json"),
@@ -907,7 +1036,7 @@ Error: \"version\" is a required property"
907
1036
  )
908
1037
  .unwrap();
909
1038
 
910
- let schema_dir2 = schemas_dir.join("without_values");
1039
+ let schema_dir2 = schemas_dir.join("without-values");
911
1040
  fs::create_dir_all(&schema_dir2).unwrap();
912
1041
  fs::write(
913
1042
  schema_dir2.join("schema.json"),
@@ -922,7 +1051,7 @@ Error: \"version\" is a required property"
922
1051
  .unwrap();
923
1052
 
924
1053
  // Only create values for one namespace
925
- let with_values_dir = values_dir.join("with_values");
1054
+ let with_values_dir = values_dir.join("with-values");
926
1055
  fs::create_dir_all(&with_values_dir).unwrap();
927
1056
  fs::write(with_values_dir.join("values.json"), r#"{"opt": "y"}"#).unwrap();
928
1057
 
@@ -930,8 +1059,8 @@ Error: \"version\" is a required property"
930
1059
  let values = registry.load_values_json(&values_dir).unwrap();
931
1060
 
932
1061
  assert_eq!(values.len(), 1);
933
- assert!(values.contains_key("with_values"));
934
- assert!(!values.contains_key("without_values"));
1062
+ assert!(values.contains_key("with-values"));
1063
+ assert!(!values.contains_key("without-values"));
935
1064
  }
936
1065
 
937
1066
  #[test]