hecks 3.0.1 → 3.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d36051842e6b18aa1f52af8b4c4a3b8e4d36cf69b66b62cf4d9119a8a160f68
4
- data.tar.gz: ad1ed152aafd1c09c7aadd890ce80aa2690fda9e51fdbb9a231fdd7c97dfcb55
3
+ metadata.gz: 46f6f36759cf946f2fd26b0b11b0ec64b02b7b84e1213fcf239a08aa314d0168
4
+ data.tar.gz: 295310e1f10f391cfdc53900f7eda2ee6b96db34ced1e93fbd73e50978b6fa07
5
5
  SHA512:
6
- metadata.gz: f711d13656e8af3eb9a3023436979beff389ba3e07804b49031631e114d1063ac983657757a3fce5f67c55f91d12bac1c2e99b7c8e4e239e25bf37f5f5e506b4
7
- data.tar.gz: bf9daee0b3e0b4b8e1660bd2143fdbac674a8b59a65cf2f2ca6b0958c4e9c1bf5c6b7a1f55aac9d5bcdde09154c7937aa445fb9036c9e10c7ced434e864434f7
6
+ metadata.gz: 9d7a89486e004a7e786177ee9debfb4fcdc1e331611da9293a29cc2e16e0b4f2b388d718d3062e7b236e27b2655f16282e6e1b1065bb151fcdd8bb67c839a34f
7
+ data.tar.gz: 9713d8af8eb4eebdf7885e0ec9821e304f0d6be393e22968c32b971e83d920e6f4ecfa52ce3ee46a19336de8a4e50d5c70d20c443784042aeac5607046ceb9ce
@@ -7,6 +7,10 @@ module Hecks
7
7
  autoload :Vendor, File.join(__dir__, "embryonaut_bluebook/vendor")
8
8
  autoload :VendorCli, File.join(__dir__, "embryonaut_bluebook/vendor_cli")
9
9
 
10
+ # The shape `hecks vendor` accepts for a package directory name. The name is joined into a
11
+ # path that `load!` evaluates as Ruby, so `../x` or an absolute path must never reach it.
12
+ PACKAGE_NAME = /\A[a-z][a-z0-9_]*\z/
13
+
10
14
  # Loads a vendored embryonaut bluebook package's `.bluebook` files, once
11
15
  # per registry.
12
16
  #
@@ -23,6 +27,12 @@ module Hecks
23
27
  "uses_embryonaut_bluebook(#{name.inspect}) needs a registry with a root to vendor from"
24
28
  end
25
29
 
30
+ unless name.to_s.match?(PACKAGE_NAME)
31
+ raise Runtime::WiringError,
32
+ "uses_embryonaut_bluebook(#{name.inspect}) is not a package name — it must match " \
33
+ "[a-z][a-z0-9_]* (the name `hecks vendor` accepts)"
34
+ end
35
+
26
36
  return if registry.bluebook(Naming.pascal(name.to_s))
27
37
 
28
38
  dir = File.join(registry.root, "vendor", "embryonaut_bluebooks", name.to_s, "bluebook")
@@ -53,9 +53,30 @@ module Hecks
53
53
  raise
54
54
  end
55
55
 
56
+ # Where the language's own bluebooks live: this checkout's, unless a block is running under
57
+ # `with_language_dir`.
58
+ #
59
+ # @return [String] the directory holding the syntax tables
60
+ def language_dir = @language_dir || File.expand_path("../language", __dir__)
61
+
62
+ # Runs the block with every table read and edit aimed at `dir`, so a caller can try real
63
+ # edits on a copy. The language's own files are what other processes load, so an edit that
64
+ # lands on them, even one put back afterwards, can be loaded half-made.
65
+ #
66
+ # @param dir [String] a directory laid out like `lib/hecks/language`
67
+ # @yield the work to run against `dir`
68
+ # @return [Object] what the block returns
69
+ def with_language_dir(dir)
70
+ previous = @language_dir
71
+ @language_dir = dir
72
+ yield
73
+ ensure
74
+ @language_dir = previous
75
+ end
76
+
56
77
  # Every syntax-table file declaring a KeywordSeed or ArgumentSeed value object.
57
78
  def syntax_paths
58
- Dir.glob(File.expand_path("../language/**/*.bluebook", __dir__)).select do |path|
79
+ Dir.glob(File.join(language_dir, "**/*.bluebook")).select do |path|
59
80
  source = read_source(path)
60
81
  source.include?('value_object "KeywordSeed"') || source.include?('value_object "ArgumentSeed"')
61
82
  end
data/lib/hecks/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Hecks
2
2
  # Read directly by the gemspec, so this file must never require the
3
3
  # rest of the gem (its dependencies aren't resolved yet at that point).
4
- VERSION = "3.0.1".freeze
4
+ VERSION = "3.0.3".freeze
5
5
  end
@@ -94,7 +94,20 @@ fn resolve_json(parser_bin: &Path, chapter_name: &str, hecksagon_path: &Path, ke
94
94
  Ok(names.iter().filter_map(Json::as_str).map(str::to_string).collect())
95
95
  }
96
96
 
97
+ /// `/\A[a-z][a-z0-9_]*\z/` — the shape `hecks vendor` accepts for a package directory name.
98
+ /// The name is joined into a path and, through its chapter, into a directory the build deletes,
99
+ /// so `../x` or an absolute path must never reach either.
100
+ pub fn valid_package_name(name: &str) -> bool {
101
+ let mut chars = name.chars();
102
+ matches!(chars.next(), Some(c) if c.is_ascii_lowercase()) && chars.all(|c| c.is_ascii_lowercase() || c.is_ascii_digit() || c == '_')
103
+ }
104
+
97
105
  pub fn vendored_bluebook_files(domain: &Path, pkg_name: &str) -> Result<Vec<PathBuf>, String> {
106
+ if !valid_package_name(pkg_name) {
107
+ return Err(format!(
108
+ "uses_embryonaut_bluebook {pkg_name:?} is not a package name — it must match [a-z][a-z0-9_]* (the name `hecks vendor` accepts)"
109
+ ));
110
+ }
98
111
  let dir = domain.join("vendor").join("embryonaut_bluebooks").join(pkg_name).join("bluebook");
99
112
  if !dir.is_dir() {
100
113
  return Err(format!(
@@ -109,6 +122,18 @@ pub fn vendored_bluebook_files(domain: &Path, pkg_name: &str) -> Result<Vec<Path
109
122
  mod tests {
110
123
  use super::*;
111
124
 
125
+ #[test]
126
+ fn a_package_name_that_is_a_path_is_refused_before_any_directory_is_touched() {
127
+ for name in ["../x", "a/b", "/etc", "", "X", "1st", "a-b", "a b", ".."] {
128
+ assert!(!valid_package_name(name), "{name:?}");
129
+ let refusal = vendored_bluebook_files(Path::new("/nonexistent"), name).unwrap_err();
130
+ assert!(refusal.contains("is not a package name"), "{refusal}");
131
+ }
132
+ for name in ["payments", "console_settings", "a1"] {
133
+ assert!(valid_package_name(name), "{name:?}");
134
+ }
135
+ }
136
+
112
137
  #[test]
113
138
  fn pascal_cases_snake_case_stems() {
114
139
  assert_eq!(pascal("governance"), "Governance");
@@ -121,6 +121,9 @@ fn write_domain(
121
121
  if let Some(refusal) = naming::reserved_name_refusal(source_label, mod_name, &aggregate_names) {
122
122
  return Err(refusal);
123
123
  }
124
+ if let Some(refusal) = naming::unsafe_name_refusal(source_label, ir) {
125
+ return Err(refusal);
126
+ }
124
127
 
125
128
  std::fs::create_dir_all(out_dir).map_err(|e| format!("creating {out_dir}: {e}"))?;
126
129
 
@@ -1,5 +1,7 @@
1
1
  //! Port of `rust/project/naming.rb`, mirrored function for function.
2
2
 
3
+ use crate::json::Json;
4
+
3
5
  pub fn scalar_rust_type(type_name: &str) -> Option<&'static str> {
4
6
  match type_name {
5
7
  "String" => Some("String"),
@@ -115,6 +117,55 @@ pub fn reserved_name_refusal(source_label: &str, mod_name: &str, aggregate_names
115
117
  ))
116
118
  }
117
119
 
120
+ /// `/\A[A-Za-z_][A-Za-z0-9_]*\z/` — a declared name that is safe to write into generated Rust.
121
+ fn plain_identifier(name: &str) -> bool {
122
+ let mut chars = name.chars();
123
+ matches!(chars.next(), Some(c) if c == '_' || c.is_ascii_alphabetic())
124
+ && chars.all(|c| c == '_' || c.is_ascii_alphanumeric())
125
+ }
126
+
127
+ /// Every declared `name` in the IR, in document order. The `fields` maps under `mutations` are
128
+ /// skipped: their keys are attribute names and their values are source text, not declarations.
129
+ fn declared_names<'a>(ir: &'a Json, out: &mut Vec<&'a str>) {
130
+ match ir {
131
+ Json::Object(pairs) => {
132
+ for (key, value) in pairs {
133
+ match (key.as_str(), value) {
134
+ ("fields", _) => {}
135
+ ("name", Json::String(name)) => out.push(name),
136
+ _ => declared_names(value, out),
137
+ }
138
+ }
139
+ }
140
+ Json::Array(items) => items.iter().for_each(|item| declared_names(item, out)),
141
+ _ => {}
142
+ }
143
+ }
144
+
145
+ /// `None` when every declared name is a plain identifier, else the refusal text the Ruby generator
146
+ /// raises, byte for byte. Attribute, command, event, query and port names are written into the
147
+ /// generated crate as field, struct and function names, so a name like `"a: String, pub evil: u8"`
148
+ /// would otherwise inject code into it.
149
+ pub fn unsafe_name_refusal(source_label: &str, ir: &Json) -> Option<String> {
150
+ let mut names = Vec::new();
151
+ declared_names(ir, &mut names);
152
+ let mut refused: Vec<&str> = Vec::new();
153
+ for name in names.into_iter().filter(|name| !plain_identifier(name)) {
154
+ if !refused.contains(&name) {
155
+ refused.push(name);
156
+ }
157
+ }
158
+ if refused.is_empty() {
159
+ return None;
160
+ }
161
+ let list = refused.iter().map(|name| ruby_inspect_string(name)).collect::<Vec<_>>().join(", ");
162
+ Some(format!(
163
+ "{source_label}: declared name(s) {list} can't be used as-is — each is written into the generated Rust as \
164
+ an identifier, and at least one is not a plain identifier (letters, digits and underscores, not starting \
165
+ with a digit). Rename it in the bluebook."
166
+ ))
167
+ }
168
+
118
169
  pub fn rust_field(name: &str) -> String {
119
170
  name.to_string()
120
171
  }
@@ -265,6 +316,25 @@ mod tests {
265
316
  assert!(refusal.contains("Rust keyword"), "{refusal}");
266
317
  }
267
318
 
319
+ #[test]
320
+ fn refuses_a_declared_name_that_would_inject_code_into_the_generated_crate() {
321
+ let ir = Json::parse(
322
+ r#"{"name":"Shop","aggregates":[{"name":"Pizza","attributes":[{"name":"size"},{"name":"a: String, pub evil: u8"}]}]}"#,
323
+ )
324
+ .unwrap();
325
+ let refusal = unsafe_name_refusal("shop", &ir).expect("refused");
326
+ assert!(refusal.starts_with("shop: declared name(s) \"a: String, pub evil: u8\" can't be used as-is"), "{refusal}");
327
+ }
328
+
329
+ #[test]
330
+ fn accepts_plain_identifiers_and_ignores_mutation_field_maps() {
331
+ let ir = Json::parse(
332
+ r#"{"name":"Shop","aggregates":[{"name":"Pizza","commands":[{"name":"AddTopping","mutations":[{"fields":{"name":":topping"}}]}]}]}"#,
333
+ )
334
+ .unwrap();
335
+ assert_eq!(unsafe_name_refusal("shop", &ir), None);
336
+ }
337
+
268
338
  #[test]
269
339
  fn refuses_an_aggregate_name_that_is_not_a_plain_identifier() {
270
340
  assert!(reserved_name_refusal("shop", "shop", &["My-App"]).is_some());
data/rust/host/Cargo.lock CHANGED
@@ -609,23 +609,11 @@ dependencies = [
609
609
  "either",
610
610
  ]
611
611
 
612
- [[package]]
613
- name = "cap-fs-ext"
614
- version = "4.0.2"
615
- source = "registry+https://github.com/rust-lang/crates.io-index"
616
- checksum = "d78e5a3368ae89b7cb68186411452b4b9fac8b41be9c19bf3f47c2d2c8e36e6b"
617
- dependencies = [
618
- "cap-primitives",
619
- "cap-std",
620
- "io-lifetimes 3.0.1",
621
- "windows-sys 0.61.2",
622
- ]
623
-
624
612
  [[package]]
625
613
  name = "cap-primitives"
626
- version = "4.0.2"
614
+ version = "4.0.3"
627
615
  source = "registry+https://github.com/rust-lang/crates.io-index"
628
- checksum = "cdadbd7c002d3a484b35243669abdae85a0ebaded5a61117169dc3400f9a7ff0"
616
+ checksum = "8b5f74729fd2f44701d1a8eb47e906cdb3ccd9ec0f02baad85a744b791940b18"
629
617
  dependencies = [
630
618
  "ambient-authority",
631
619
  "fs-set-times",
@@ -639,18 +627,6 @@ dependencies = [
639
627
  "winx",
640
628
  ]
641
629
 
642
- [[package]]
643
- name = "cap-std"
644
- version = "4.0.2"
645
- source = "registry+https://github.com/rust-lang/crates.io-index"
646
- checksum = "7281235d6e96d3544ca18bba9049be92f4190f8d923e3caef1b5f66cfa752608"
647
- dependencies = [
648
- "cap-primitives",
649
- "io-extras",
650
- "io-lifetimes 3.0.1",
651
- "rustix",
652
- ]
653
-
654
630
  [[package]]
655
631
  name = "cc"
656
632
  version = "1.4.2"
@@ -758,27 +734,27 @@ dependencies = [
758
734
 
759
735
  [[package]]
760
736
  name = "cranelift-assembler-x64"
761
- version = "0.134.3"
737
+ version = "0.136.1"
762
738
  source = "registry+https://github.com/rust-lang/crates.io-index"
763
- checksum = "d552bd33b7a56dc70aeb1e1c960e51a218fa0db50f23873b500a310379450b2d"
739
+ checksum = "c8a495ae3e4d638712a0c0378719e526e448d04d7ebbbe1745712e12c5feb4c3"
764
740
  dependencies = [
765
741
  "cranelift-assembler-x64-meta",
766
742
  ]
767
743
 
768
744
  [[package]]
769
745
  name = "cranelift-assembler-x64-meta"
770
- version = "0.134.3"
746
+ version = "0.136.1"
771
747
  source = "registry+https://github.com/rust-lang/crates.io-index"
772
- checksum = "078e80e4c222279e3330f6aa1a256ca77ddf156d4453166a9f09defedc4594dd"
748
+ checksum = "4eb2e299e844a27d799f43988e4415a37696fdb738cb463312ef5d06cae15b2a"
773
749
  dependencies = [
774
750
  "cranelift-srcgen",
775
751
  ]
776
752
 
777
753
  [[package]]
778
754
  name = "cranelift-bforest"
779
- version = "0.134.3"
755
+ version = "0.136.1"
780
756
  source = "registry+https://github.com/rust-lang/crates.io-index"
781
- checksum = "820ce15d4ad3562d613c31a67b6d0434d403e7091a68d1349903842f7d31737e"
757
+ checksum = "f4710c34489bc844e45c1c0005d3e44d3d2b29cee77187507ba8d0bb400c621f"
782
758
  dependencies = [
783
759
  "cranelift-entity",
784
760
  "wasmtime-internal-core",
@@ -786,9 +762,9 @@ dependencies = [
786
762
 
787
763
  [[package]]
788
764
  name = "cranelift-bitset"
789
- version = "0.134.3"
765
+ version = "0.136.1"
790
766
  source = "registry+https://github.com/rust-lang/crates.io-index"
791
- checksum = "61bca563d4b86d285928d9e27f97f27039bb33a0fc524fa130d7d0c106bf8ab3"
767
+ checksum = "76b63a4b0cfea80610150fffda11b1a9c3dc5a835403d9f381bf7d1a2874b4d7"
792
768
  dependencies = [
793
769
  "serde",
794
770
  "serde_derive",
@@ -797,9 +773,9 @@ dependencies = [
797
773
 
798
774
  [[package]]
799
775
  name = "cranelift-codegen"
800
- version = "0.134.3"
776
+ version = "0.136.1"
801
777
  source = "registry+https://github.com/rust-lang/crates.io-index"
802
- checksum = "709f4b7c0fb57d952658d5b5c07fbdc4149acd7b7f0de9678ae754b9c981949a"
778
+ checksum = "e1af881f3b3392433e6f4f9b172b8d99270c538db4effea62b28bc48f02f0833"
803
779
  dependencies = [
804
780
  "bumpalo",
805
781
  "cranelift-assembler-x64",
@@ -828,9 +804,9 @@ dependencies = [
828
804
 
829
805
  [[package]]
830
806
  name = "cranelift-codegen-meta"
831
- version = "0.134.3"
807
+ version = "0.136.1"
832
808
  source = "registry+https://github.com/rust-lang/crates.io-index"
833
- checksum = "903dc8915af62aad1d9d0f39a5968d33fa80b9aa899ed6f56e47f40ca4512e1e"
809
+ checksum = "24ce99c30dc7a692294613241119eea0de3c3cb4cf10ac2570ed72adf9a8c2eb"
834
810
  dependencies = [
835
811
  "cranelift-assembler-x64-meta",
836
812
  "cranelift-codegen-shared",
@@ -841,24 +817,24 @@ dependencies = [
841
817
 
842
818
  [[package]]
843
819
  name = "cranelift-codegen-shared"
844
- version = "0.134.3"
820
+ version = "0.136.1"
845
821
  source = "registry+https://github.com/rust-lang/crates.io-index"
846
- checksum = "0522d74c227e49f3fd49ab055311486ae4f09083262b66705bed676952491469"
822
+ checksum = "34c2a529b638d95c347c2337403dacec86197ad6503cedc63caf53466ae5c4de"
847
823
 
848
824
  [[package]]
849
825
  name = "cranelift-control"
850
- version = "0.134.3"
826
+ version = "0.136.1"
851
827
  source = "registry+https://github.com/rust-lang/crates.io-index"
852
- checksum = "66560ea1c5cef72e170b18e46d263dba2d3169c9d39e8cafdab2173c6362cc1a"
828
+ checksum = "570eb4e02cca190896beb3c8a0a67583dca8b6965517a9f3e04cc89e17c9a986"
853
829
  dependencies = [
854
830
  "arbitrary",
855
831
  ]
856
832
 
857
833
  [[package]]
858
834
  name = "cranelift-entity"
859
- version = "0.134.3"
835
+ version = "0.136.1"
860
836
  source = "registry+https://github.com/rust-lang/crates.io-index"
861
- checksum = "b62ef5b17cc814d27e96b66a5b46da0e4ce2b8ac55a6d478048bb99d04b05526"
837
+ checksum = "e73c65538d460b1062cb9a97428ee6bb4b616f5cb17be3b3ac0a3e4f1f789166"
862
838
  dependencies = [
863
839
  "cranelift-bitset",
864
840
  "serde",
@@ -868,9 +844,9 @@ dependencies = [
868
844
 
869
845
  [[package]]
870
846
  name = "cranelift-frontend"
871
- version = "0.134.3"
847
+ version = "0.136.1"
872
848
  source = "registry+https://github.com/rust-lang/crates.io-index"
873
- checksum = "a87e0aaa39dbf70693b348a221e45904111704ee8f9fef140498471005f9842d"
849
+ checksum = "5ed70ab5849184973c42b57366f57611dc81c3e355d5b612c68a2900bea92242"
874
850
  dependencies = [
875
851
  "cranelift-codegen",
876
852
  "hashbrown 0.17.1",
@@ -881,15 +857,15 @@ dependencies = [
881
857
 
882
858
  [[package]]
883
859
  name = "cranelift-isle"
884
- version = "0.134.3"
860
+ version = "0.136.1"
885
861
  source = "registry+https://github.com/rust-lang/crates.io-index"
886
- checksum = "cf79003ebfa1eed5e87f3b84446ad5236f540268289960e14f387dc9b28e40b7"
862
+ checksum = "379f10a451c9b1bf4f59e4ce38061c53ca2454783041a3c1fafa6deef3c37108"
887
863
 
888
864
  [[package]]
889
865
  name = "cranelift-native"
890
- version = "0.134.3"
866
+ version = "0.136.1"
891
867
  source = "registry+https://github.com/rust-lang/crates.io-index"
892
- checksum = "05bf4f235743c81e67ee4db617c5a4a0b65d58d3f0cfc575ee0f1a4e0cd58273"
868
+ checksum = "4f496865b1a14bc85bcc9fb51a9539ca93b1d1f44fb92bd6a091fba02d6ab4a7"
893
869
  dependencies = [
894
870
  "cranelift-codegen",
895
871
  "libc",
@@ -898,9 +874,9 @@ dependencies = [
898
874
 
899
875
  [[package]]
900
876
  name = "cranelift-srcgen"
901
- version = "0.134.3"
877
+ version = "0.136.1"
902
878
  source = "registry+https://github.com/rust-lang/crates.io-index"
903
- checksum = "f6977c2a71ab1e0d1e62f966b411a498aa04c4dce47d93d52f8a360a06058922"
879
+ checksum = "89643801d9192df80c294f174d5fe0416395e7edb0bb3024784ba10fc933e76f"
904
880
 
905
881
  [[package]]
906
882
  name = "crc32fast"
@@ -1315,9 +1291,9 @@ dependencies = [
1315
1291
 
1316
1292
  [[package]]
1317
1293
  name = "h2"
1318
- version = "0.4.15"
1294
+ version = "0.4.19"
1319
1295
  source = "registry+https://github.com/rust-lang/crates.io-index"
1320
- checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155"
1296
+ checksum = "ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16"
1321
1297
  dependencies = [
1322
1298
  "atomic-waker",
1323
1299
  "bytes",
@@ -1991,9 +1967,9 @@ dependencies = [
1991
1967
 
1992
1968
  [[package]]
1993
1969
  name = "object"
1994
- version = "0.39.1"
1970
+ version = "0.40.0"
1995
1971
  source = "registry+https://github.com/rust-lang/crates.io-index"
1996
- checksum = "2e5a6c098c7a3b6547378093f5cc30bc54fd361ce711e05293a5cc589562739b"
1972
+ checksum = "dd229a0361b9d0d4396176e02d65897f487eebeab7caa6d443855ee152ca0b9c"
1997
1973
  dependencies = [
1998
1974
  "crc32fast",
1999
1975
  "hashbrown 0.17.1",
@@ -2194,9 +2170,9 @@ dependencies = [
2194
2170
 
2195
2171
  [[package]]
2196
2172
  name = "pulley-interpreter"
2197
- version = "47.0.3"
2173
+ version = "49.0.1"
2198
2174
  source = "registry+https://github.com/rust-lang/crates.io-index"
2199
- checksum = "bc5c8c21ea032e4efbdf2d067dc45171779dbe0c8ecf20ef4a57efa7474f2b0a"
2175
+ checksum = "0091857bc410bd7117eb6ac042ced7714c69f994a8b9c2ae30add2f73e3a25ac"
2200
2176
  dependencies = [
2201
2177
  "cranelift-bitset",
2202
2178
  "log",
@@ -2206,9 +2182,9 @@ dependencies = [
2206
2182
 
2207
2183
  [[package]]
2208
2184
  name = "pulley-macros"
2209
- version = "47.0.3"
2185
+ version = "49.0.1"
2210
2186
  source = "registry+https://github.com/rust-lang/crates.io-index"
2211
- checksum = "9f10925455d5dde962e3604eade797ba5488644c8ee14a44191e2f2b58980574"
2187
+ checksum = "8798ebc6bf0ef227e204fa3fad05b04970599a85f456fd28365450fd679b2600"
2212
2188
  dependencies = [
2213
2189
  "proc-macro2",
2214
2190
  "quote",
@@ -2528,9 +2504,9 @@ dependencies = [
2528
2504
 
2529
2505
  [[package]]
2530
2506
  name = "rustls"
2531
- version = "0.23.43"
2507
+ version = "0.23.45"
2532
2508
  source = "registry+https://github.com/rust-lang/crates.io-index"
2533
- checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06"
2509
+ checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634"
2534
2510
  dependencies = [
2535
2511
  "once_cell",
2536
2512
  "ring",
@@ -2573,9 +2549,9 @@ dependencies = [
2573
2549
 
2574
2550
  [[package]]
2575
2551
  name = "rustls-webpki"
2576
- version = "0.103.13"
2552
+ version = "0.103.15"
2577
2553
  source = "registry+https://github.com/rust-lang/crates.io-index"
2578
- checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e"
2554
+ checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
2579
2555
  dependencies = [
2580
2556
  "ring",
2581
2557
  "rustls-pki-types",
@@ -3140,9 +3116,9 @@ dependencies = [
3140
3116
 
3141
3117
  [[package]]
3142
3118
  name = "toml"
3143
- version = "0.9.12+spec-1.1.0"
3119
+ version = "1.1.6+spec-1.1.0"
3144
3120
  source = "registry+https://github.com/rust-lang/crates.io-index"
3145
- checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
3121
+ checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a"
3146
3122
  dependencies = [
3147
3123
  "indexmap",
3148
3124
  "serde_core",
@@ -3150,14 +3126,14 @@ dependencies = [
3150
3126
  "toml_datetime",
3151
3127
  "toml_parser",
3152
3128
  "toml_writer",
3153
- "winnow 0.7.15",
3129
+ "winnow",
3154
3130
  ]
3155
3131
 
3156
3132
  [[package]]
3157
3133
  name = "toml_datetime"
3158
- version = "0.7.5+spec-1.1.0"
3134
+ version = "1.1.1+spec-1.1.0"
3159
3135
  source = "registry+https://github.com/rust-lang/crates.io-index"
3160
- checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
3136
+ checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7"
3161
3137
  dependencies = [
3162
3138
  "serde_core",
3163
3139
  ]
@@ -3168,7 +3144,7 @@ version = "1.1.3+spec-1.1.0"
3168
3144
  source = "registry+https://github.com/rust-lang/crates.io-index"
3169
3145
  checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56"
3170
3146
  dependencies = [
3171
- "winnow 1.0.4",
3147
+ "winnow",
3172
3148
  ]
3173
3149
 
3174
3150
  [[package]]
@@ -3501,9 +3477,9 @@ dependencies = [
3501
3477
 
3502
3478
  [[package]]
3503
3479
  name = "wasm-compose"
3504
- version = "0.252.0"
3480
+ version = "0.258.0"
3505
3481
  source = "registry+https://github.com/rust-lang/crates.io-index"
3506
- checksum = "d59b710751a35d54732a63851cdfacbfb2266b7160ce174faf269d3f4e84e31b"
3482
+ checksum = "7dd08e5283f98238f2f16f5f978188a33af9901b81186bb549faad306a7b5388"
3507
3483
  dependencies = [
3508
3484
  "anyhow",
3509
3485
  "heck",
@@ -3511,36 +3487,48 @@ dependencies = [
3511
3487
  "log",
3512
3488
  "petgraph",
3513
3489
  "smallvec",
3514
- "wasm-encoder 0.252.0",
3515
- "wasmparser 0.252.0",
3490
+ "wasm-encoder 0.258.0",
3491
+ "wasmparser 0.258.0",
3516
3492
  "wat",
3517
3493
  ]
3518
3494
 
3519
3495
  [[package]]
3520
3496
  name = "wasm-encoder"
3521
- version = "0.252.0"
3497
+ version = "0.258.0"
3522
3498
  source = "registry+https://github.com/rust-lang/crates.io-index"
3523
- checksum = "8185ae345fa5687c054626ff9a50e7089797a343d9904d1dc9820eb4c4d3196f"
3499
+ checksum = "e974fe6821a8cf64575d51ea2194e2c8f77e7b66e9afe7419ce8a97f9ee0d251"
3524
3500
  dependencies = [
3525
3501
  "leb128fmt",
3526
- "wasmparser 0.252.0",
3502
+ "wasmparser 0.258.0",
3527
3503
  ]
3528
3504
 
3529
3505
  [[package]]
3530
3506
  name = "wasm-encoder"
3531
- version = "0.255.0"
3507
+ version = "0.260.0"
3532
3508
  source = "registry+https://github.com/rust-lang/crates.io-index"
3533
- checksum = "9b524283fb5df62eec102ed0574838961bdd7ba5ac9c50d38e2756c51c971a42"
3509
+ checksum = "e1e9692da9ef627c5ee12b45378f68ac2689ce306f88078f5cf849b7c3444ed8"
3534
3510
  dependencies = [
3535
3511
  "leb128fmt",
3536
- "wasmparser 0.255.0",
3512
+ "wasmparser 0.260.0",
3513
+ ]
3514
+
3515
+ [[package]]
3516
+ name = "wasm-metadata"
3517
+ version = "0.258.0"
3518
+ source = "registry+https://github.com/rust-lang/crates.io-index"
3519
+ checksum = "18a11585adb92fe9b55ad1d760e8d8fb5d87e0d2e303cb8eed57f078d54293a2"
3520
+ dependencies = [
3521
+ "anyhow",
3522
+ "indexmap",
3523
+ "wasm-encoder 0.258.0",
3524
+ "wasmparser 0.258.0",
3537
3525
  ]
3538
3526
 
3539
3527
  [[package]]
3540
3528
  name = "wasmparser"
3541
- version = "0.252.0"
3529
+ version = "0.258.0"
3542
3530
  source = "registry+https://github.com/rust-lang/crates.io-index"
3543
- checksum = "d3eb099dcadcde5be9eef55e3a337128efd4e44b4c93122487e4d2e4e1c6627c"
3531
+ checksum = "d9a61719f93a87b16d325921e251800c4833f8fab50fa21c7de73aed50086313"
3544
3532
  dependencies = [
3545
3533
  "bitflags",
3546
3534
  "hashbrown 0.17.1",
@@ -3551,9 +3539,9 @@ dependencies = [
3551
3539
 
3552
3540
  [[package]]
3553
3541
  name = "wasmparser"
3554
- version = "0.255.0"
3542
+ version = "0.260.0"
3555
3543
  source = "registry+https://github.com/rust-lang/crates.io-index"
3556
- checksum = "e8e329ef4b5d46e73b91d3ac6924417cad55a8cbbf869c199283383427c3320b"
3544
+ checksum = "4c94519d78304dc4a4bb5925eda6ff153bf06167467cff9233dc9593bae28fdd"
3557
3545
  dependencies = [
3558
3546
  "bitflags",
3559
3547
  "indexmap",
@@ -3562,27 +3550,27 @@ dependencies = [
3562
3550
 
3563
3551
  [[package]]
3564
3552
  name = "wasmprinter"
3565
- version = "0.252.0"
3553
+ version = "0.258.0"
3566
3554
  source = "registry+https://github.com/rust-lang/crates.io-index"
3567
- checksum = "7142797de29b35ab8dbf15c00f55fda75d409da4c423a8ab8bd6b667a785824b"
3555
+ checksum = "3a65e30fb2cd3cc5cb7761a6064787b2abf017e6566d8d0dedf2bb7f55ad5383"
3568
3556
  dependencies = [
3569
3557
  "anyhow",
3570
3558
  "termcolor",
3571
- "wasmparser 0.252.0",
3559
+ "wasmparser 0.258.0",
3572
3560
  ]
3573
3561
 
3574
3562
  [[package]]
3575
3563
  name = "wasmtime"
3576
- version = "47.0.3"
3564
+ version = "49.0.1"
3577
3565
  source = "registry+https://github.com/rust-lang/crates.io-index"
3578
- checksum = "c80ca6098e0d4d06886d91d7f2cc3cb6623eb583c4c0ab3c89cbfb6098c8586c"
3566
+ checksum = "942ddd2fc5800ec01d4b11c28ad62ab00517dcd416aff728f7d73fddf75872c1"
3579
3567
  dependencies = [
3580
3568
  "addr2line",
3581
3569
  "async-trait",
3582
3570
  "bitflags",
3583
3571
  "bumpalo",
3572
+ "bytes",
3584
3573
  "cc",
3585
- "cfg-if",
3586
3574
  "encoding_rs",
3587
3575
  "futures",
3588
3576
  "fxprof-processed-profile",
@@ -3606,8 +3594,8 @@ dependencies = [
3606
3594
  "target-lexicon",
3607
3595
  "tempfile",
3608
3596
  "wasm-compose",
3609
- "wasm-encoder 0.252.0",
3610
- "wasmparser 0.252.0",
3597
+ "wasm-encoder 0.258.0",
3598
+ "wasmparser 0.258.0",
3611
3599
  "wasmtime-environ",
3612
3600
  "wasmtime-internal-cache",
3613
3601
  "wasmtime-internal-component-macro",
@@ -3626,9 +3614,9 @@ dependencies = [
3626
3614
 
3627
3615
  [[package]]
3628
3616
  name = "wasmtime-environ"
3629
- version = "47.0.3"
3617
+ version = "49.0.1"
3630
3618
  source = "registry+https://github.com/rust-lang/crates.io-index"
3631
- checksum = "134f9d136d29c76f6c1b4c9b468e97a2efc38c7d49fd188e39b64870b2fea701"
3619
+ checksum = "98f2ca21b23a51c1b1944297e9671a628c368e92aa6250e4c38f48e2dc251f0c"
3632
3620
  dependencies = [
3633
3621
  "anyhow",
3634
3622
  "cpp_demangle",
@@ -3648,8 +3636,8 @@ dependencies = [
3648
3636
  "sha2 0.10.9",
3649
3637
  "smallvec",
3650
3638
  "target-lexicon",
3651
- "wasm-encoder 0.252.0",
3652
- "wasmparser 0.252.0",
3639
+ "wasm-encoder 0.258.0",
3640
+ "wasmparser 0.258.0",
3653
3641
  "wasmprinter",
3654
3642
  "wasmtime-internal-component-util",
3655
3643
  "wasmtime-internal-core",
@@ -3657,9 +3645,9 @@ dependencies = [
3657
3645
 
3658
3646
  [[package]]
3659
3647
  name = "wasmtime-internal-cache"
3660
- version = "47.0.3"
3648
+ version = "49.0.1"
3661
3649
  source = "registry+https://github.com/rust-lang/crates.io-index"
3662
- checksum = "65db2eb1bfc5371a3b4107dbf539d0b93d05016fc29625b1648146b47db02071"
3650
+ checksum = "76c83428ffb93757881522619aef1f6571a235c25ea5e9e6b67aa6a2324da72a"
3663
3651
  dependencies = [
3664
3652
  "base64",
3665
3653
  "directories-next",
@@ -3677,9 +3665,9 @@ dependencies = [
3677
3665
 
3678
3666
  [[package]]
3679
3667
  name = "wasmtime-internal-component-macro"
3680
- version = "47.0.3"
3668
+ version = "49.0.1"
3681
3669
  source = "registry+https://github.com/rust-lang/crates.io-index"
3682
- checksum = "2bf7b91fed3fc34781d57f9c6654ea2513bf0a99f7b0b0523c00de1e6efebe1c"
3670
+ checksum = "92c42f95d879875994319bd6689b17570e68aebd1a17e0dc54430928ed0699b5"
3683
3671
  dependencies = [
3684
3672
  "anyhow",
3685
3673
  "proc-macro2",
@@ -3692,15 +3680,15 @@ dependencies = [
3692
3680
 
3693
3681
  [[package]]
3694
3682
  name = "wasmtime-internal-component-util"
3695
- version = "47.0.3"
3683
+ version = "49.0.1"
3696
3684
  source = "registry+https://github.com/rust-lang/crates.io-index"
3697
- checksum = "fc8a678149885cae00289f806fbe74c7863084cf74cace0b8dc73602279400e1"
3685
+ checksum = "294c7f12f062ceb148cd26c77170ff739552db76d1f203f6127f249684988a70"
3698
3686
 
3699
3687
  [[package]]
3700
3688
  name = "wasmtime-internal-core"
3701
- version = "47.0.3"
3689
+ version = "49.0.1"
3702
3690
  source = "registry+https://github.com/rust-lang/crates.io-index"
3703
- checksum = "8a0092c4b9d070ac5e278b6d0db10f5e71214190f0347ca57502b4692f796321"
3691
+ checksum = "64b67114739063bb72bb8ed2b4994b8b22809d354432db68553ad529850f9536"
3704
3692
  dependencies = [
3705
3693
  "anyhow",
3706
3694
  "hashbrown 0.17.1",
@@ -3710,11 +3698,10 @@ dependencies = [
3710
3698
 
3711
3699
  [[package]]
3712
3700
  name = "wasmtime-internal-cranelift"
3713
- version = "47.0.3"
3701
+ version = "49.0.1"
3714
3702
  source = "registry+https://github.com/rust-lang/crates.io-index"
3715
- checksum = "6851ebc9e03cab23d9821d2b2505d380bdfe38f35ccec945247b05274d85c98b"
3703
+ checksum = "b7d19868a30cc20df6f6648c9a4b3f700fcd1ddd0a63af9a98cb75f2b58dc874"
3716
3704
  dependencies = [
3717
- "cfg-if",
3718
3705
  "cranelift-codegen",
3719
3706
  "cranelift-control",
3720
3707
  "cranelift-entity",
@@ -3728,7 +3715,7 @@ dependencies = [
3728
3715
  "smallvec",
3729
3716
  "target-lexicon",
3730
3717
  "thiserror 2.0.20",
3731
- "wasmparser 0.252.0",
3718
+ "wasmparser 0.258.0",
3732
3719
  "wasmtime-environ",
3733
3720
  "wasmtime-internal-core",
3734
3721
  "wasmtime-internal-unwinder",
@@ -3737,12 +3724,11 @@ dependencies = [
3737
3724
 
3738
3725
  [[package]]
3739
3726
  name = "wasmtime-internal-fiber"
3740
- version = "47.0.3"
3727
+ version = "49.0.1"
3741
3728
  source = "registry+https://github.com/rust-lang/crates.io-index"
3742
- checksum = "9b26da6d5f60d4c438da70bba3553fe810a840533a64156be287dca2081c6991"
3729
+ checksum = "4f1999aee268c3f625666b12ba0ded55a6ac2c800b60b426af7d164d63411908"
3743
3730
  dependencies = [
3744
3731
  "cc",
3745
- "cfg-if",
3746
3732
  "libc",
3747
3733
  "rustix",
3748
3734
  "wasmtime-environ",
@@ -3752,9 +3738,9 @@ dependencies = [
3752
3738
 
3753
3739
  [[package]]
3754
3740
  name = "wasmtime-internal-jit-debug"
3755
- version = "47.0.3"
3741
+ version = "49.0.1"
3756
3742
  source = "registry+https://github.com/rust-lang/crates.io-index"
3757
- checksum = "ed621ba25d7bf78b7edd7b4749abbb27c2e5cdba836c9504a424ee74b6c23149"
3743
+ checksum = "33ca2499301c6f11cc9eb42c2beafc8efae396ae4cb91077e3ac080dc5d765e4"
3758
3744
  dependencies = [
3759
3745
  "cc",
3760
3746
  "object",
@@ -3764,11 +3750,10 @@ dependencies = [
3764
3750
 
3765
3751
  [[package]]
3766
3752
  name = "wasmtime-internal-jit-icache-coherence"
3767
- version = "47.0.3"
3753
+ version = "49.0.1"
3768
3754
  source = "registry+https://github.com/rust-lang/crates.io-index"
3769
- checksum = "5684ba160951baad06a725696f3c590e2fb0e8067c2aebee27bf7f9259058e85"
3755
+ checksum = "7162d829c56265e183d23b17d67afc5c6876433daaed54c137388a8078a1bb6b"
3770
3756
  dependencies = [
3771
- "cfg-if",
3772
3757
  "libc",
3773
3758
  "wasmtime-internal-core",
3774
3759
  "windows-sys 0.61.2",
@@ -3776,11 +3761,10 @@ dependencies = [
3776
3761
 
3777
3762
  [[package]]
3778
3763
  name = "wasmtime-internal-unwinder"
3779
- version = "47.0.3"
3764
+ version = "49.0.1"
3780
3765
  source = "registry+https://github.com/rust-lang/crates.io-index"
3781
- checksum = "112eead527bffa8ff0646a11fb4339a9d52ddd1da2b9a6fce4aff84c815dd94f"
3766
+ checksum = "4e167cf144f3cee40838f7663e3a589f93bba65151efa084a2d58b2bd47469f1"
3782
3767
  dependencies = [
3783
- "cfg-if",
3784
3768
  "cranelift-codegen",
3785
3769
  "log",
3786
3770
  "object",
@@ -3789,9 +3773,9 @@ dependencies = [
3789
3773
 
3790
3774
  [[package]]
3791
3775
  name = "wasmtime-internal-versioned-export-macros"
3792
- version = "47.0.3"
3776
+ version = "49.0.1"
3793
3777
  source = "registry+https://github.com/rust-lang/crates.io-index"
3794
- checksum = "153592e0bed824fc13c6696203fa1bd7bd20eb355316475e39a55f081ef80eca"
3778
+ checksum = "8d09e038ad69c741dae29da4606ccfc0df66f156e62cb7f0664c8d7d1272a36d"
3795
3779
  dependencies = [
3796
3780
  "proc-macro2",
3797
3781
  "quote",
@@ -3800,33 +3784,32 @@ dependencies = [
3800
3784
 
3801
3785
  [[package]]
3802
3786
  name = "wasmtime-internal-wit-bindgen"
3803
- version = "47.0.3"
3787
+ version = "49.0.1"
3804
3788
  source = "registry+https://github.com/rust-lang/crates.io-index"
3805
- checksum = "c456ad6e81e0f46abfeca43687d18ea15e289c395b262ea6e0023e2682e088be"
3789
+ checksum = "c63d97a742fc9b415dad7ed2ac33ddb8fe6c5413fcd0c7ee58907f2ab6f9a430"
3806
3790
  dependencies = [
3807
3791
  "anyhow",
3808
3792
  "bitflags",
3809
3793
  "heck",
3810
3794
  "indexmap",
3795
+ "wit-component",
3811
3796
  "wit-parser",
3812
3797
  ]
3813
3798
 
3814
3799
  [[package]]
3815
3800
  name = "wasmtime-wasi"
3816
- version = "47.0.3"
3801
+ version = "49.0.1"
3817
3802
  source = "registry+https://github.com/rust-lang/crates.io-index"
3818
- checksum = "4c1cf60cd6a565213af7074b4aad7bb5e110e3c6c6aae54425aa0500a0e15e86"
3803
+ checksum = "ce11727cb331abeaace3681a4b072e4fe04818d7b99786d183b318671f9e4e0e"
3819
3804
  dependencies = [
3820
3805
  "async-trait",
3821
3806
  "bitflags",
3822
3807
  "bytes",
3823
- "cap-fs-ext",
3824
- "cap-std",
3825
- "cfg-if",
3808
+ "cap-primitives",
3826
3809
  "futures",
3827
- "io-lifetimes 3.0.1",
3828
3810
  "rand",
3829
3811
  "rustix",
3812
+ "rustix-linux-procfs",
3830
3813
  "thiserror 2.0.20",
3831
3814
  "tokio",
3832
3815
  "tracing",
@@ -3835,13 +3818,14 @@ dependencies = [
3835
3818
  "wasmtime-wasi-io",
3836
3819
  "wiggle",
3837
3820
  "windows-sys 0.61.2",
3821
+ "winx",
3838
3822
  ]
3839
3823
 
3840
3824
  [[package]]
3841
3825
  name = "wasmtime-wasi-io"
3842
- version = "47.0.3"
3826
+ version = "49.0.1"
3843
3827
  source = "registry+https://github.com/rust-lang/crates.io-index"
3844
- checksum = "7fb08e1d7755aaa467ce14080b7b01e33c914a920f6000696f1e42e40ea6387e"
3828
+ checksum = "35f5ed8d710d8daf71cb4742c6b90c1fd121acb62b6848556eb4e0661cbd28bd"
3845
3829
  dependencies = [
3846
3830
  "async-trait",
3847
3831
  "bytes",
@@ -3861,24 +3845,24 @@ dependencies = [
3861
3845
 
3862
3846
  [[package]]
3863
3847
  name = "wast"
3864
- version = "255.0.0"
3848
+ version = "260.0.0"
3865
3849
  source = "registry+https://github.com/rust-lang/crates.io-index"
3866
- checksum = "55ffec530f199bd3d553ac442c13dd108353cad533cad8514bc41e1f1f0fe686"
3850
+ checksum = "17573754cde137d26852892330414efb6d1d33480adcd10e8825d092b2132229"
3867
3851
  dependencies = [
3868
3852
  "bumpalo",
3869
3853
  "leb128fmt",
3870
3854
  "memchr",
3871
3855
  "unicode-width",
3872
- "wasm-encoder 0.255.0",
3856
+ "wasm-encoder 0.260.0",
3873
3857
  ]
3874
3858
 
3875
3859
  [[package]]
3876
3860
  name = "wat"
3877
- version = "1.255.0"
3861
+ version = "1.260.0"
3878
3862
  source = "registry+https://github.com/rust-lang/crates.io-index"
3879
- checksum = "dda82c82e1486c7eed42a0465e544d80fff37abc3b39482e0d34dbaabe2fe5b1"
3863
+ checksum = "5f56de9341c410d04121da51dd16c11d095cb6a914bd2b2850cd3c60558c0c15"
3880
3864
  dependencies = [
3881
- "wast 255.0.0",
3865
+ "wast 260.0.0",
3882
3866
  ]
3883
3867
 
3884
3868
  [[package]]
@@ -3925,9 +3909,9 @@ dependencies = [
3925
3909
 
3926
3910
  [[package]]
3927
3911
  name = "wiggle"
3928
- version = "47.0.3"
3912
+ version = "49.0.1"
3929
3913
  source = "registry+https://github.com/rust-lang/crates.io-index"
3930
- checksum = "89091642df051b84a7e00bdff75e985e507f2298384e477cc9310b0ddd79f004"
3914
+ checksum = "3dfb96da9ecf96621fee71a01916ca99038cc8f212cd19a8923fb32c36060477"
3931
3915
  dependencies = [
3932
3916
  "bitflags",
3933
3917
  "thiserror 2.0.20",
@@ -3939,9 +3923,9 @@ dependencies = [
3939
3923
 
3940
3924
  [[package]]
3941
3925
  name = "wiggle-generate"
3942
- version = "47.0.3"
3926
+ version = "49.0.1"
3943
3927
  source = "registry+https://github.com/rust-lang/crates.io-index"
3944
- checksum = "12247f46f31bb5e7593947f9bba07317d0c1978e0d02250b979dd08f56f46e9f"
3928
+ checksum = "ba7cbdab1c5fa79f98a96c3b0b02b81f83585a4cdc3ce1d2744e6cfa2aef333b"
3945
3929
  dependencies = [
3946
3930
  "heck",
3947
3931
  "proc-macro2",
@@ -3953,9 +3937,9 @@ dependencies = [
3953
3937
 
3954
3938
  [[package]]
3955
3939
  name = "wiggle-macro"
3956
- version = "47.0.3"
3940
+ version = "49.0.1"
3957
3941
  source = "registry+https://github.com/rust-lang/crates.io-index"
3958
- checksum = "e556a0880c9506fdcc662b1e226c7ced692f4977fed5b1ed40a3f3f0a48356f2"
3942
+ checksum = "daa97f5b7ad6ace3254b6bec1f82ef53f7c49c4cf5f117fad4171acc15fd6ff0"
3959
3943
  dependencies = [
3960
3944
  "proc-macro2",
3961
3945
  "quote",
@@ -4082,12 +4066,6 @@ version = "0.52.6"
4082
4066
  source = "registry+https://github.com/rust-lang/crates.io-index"
4083
4067
  checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
4084
4068
 
4085
- [[package]]
4086
- name = "winnow"
4087
- version = "0.7.15"
4088
- source = "registry+https://github.com/rust-lang/crates.io-index"
4089
- checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
4090
-
4091
4069
  [[package]]
4092
4070
  name = "winnow"
4093
4071
  version = "1.0.4"
@@ -4110,11 +4088,30 @@ version = "0.57.1"
4110
4088
  source = "registry+https://github.com/rust-lang/crates.io-index"
4111
4089
  checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
4112
4090
 
4091
+ [[package]]
4092
+ name = "wit-component"
4093
+ version = "0.258.0"
4094
+ source = "registry+https://github.com/rust-lang/crates.io-index"
4095
+ checksum = "481b5c47b2ecce0389b5e08a05557d6a190c9cd761773b8880a8017ee04dc7ef"
4096
+ dependencies = [
4097
+ "anyhow",
4098
+ "bitflags",
4099
+ "indexmap",
4100
+ "log",
4101
+ "serde",
4102
+ "serde_derive",
4103
+ "serde_json",
4104
+ "wasm-encoder 0.258.0",
4105
+ "wasm-metadata",
4106
+ "wasmparser 0.258.0",
4107
+ "wit-parser",
4108
+ ]
4109
+
4113
4110
  [[package]]
4114
4111
  name = "wit-parser"
4115
- version = "0.252.0"
4112
+ version = "0.258.0"
4116
4113
  source = "registry+https://github.com/rust-lang/crates.io-index"
4117
- checksum = "4266bea110371c620ccf3201c5023676046bc4556e5c7cfb5d500bda5ebc162d"
4114
+ checksum = "ff4daaa3cd97ae49ecd0a99dc009d453f93e0f083dd3be38c0f24a83a93e37ac"
4118
4115
  dependencies = [
4119
4116
  "anyhow",
4120
4117
  "hashbrown 0.17.1",
@@ -4126,7 +4123,7 @@ dependencies = [
4126
4123
  "serde_derive",
4127
4124
  "serde_json",
4128
4125
  "unicode-ident",
4129
- "wasmparser 0.252.0",
4126
+ "wasmparser 0.258.0",
4130
4127
  ]
4131
4128
 
4132
4129
  [[package]]
data/rust/host/Cargo.toml CHANGED
@@ -13,8 +13,8 @@ path = "src/main.rs"
13
13
  # No path dependency on `rust`: the compiled `.wasm` is loaded through wasmtime as an untrusted
14
14
  # module, so dispatch runs sandboxed with no access to this crate's Postgres connection.
15
15
  [dependencies]
16
- wasmtime = "47.0.3"
17
- wasmtime-wasi = "47.0.3"
16
+ wasmtime = "49.0.1"
17
+ wasmtime-wasi = "49.0.1"
18
18
  lambda_runtime = "0.13"
19
19
  tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "sync"] }
20
20
  # Used by server.rs (HECKS_SERVE_MODE=1) to answer the ALB's HTTP on Fargate. HTTP/1.1 only;
@@ -1 +1 @@
1
- 3.0.1
1
+ 3.0.3
@@ -89,15 +89,20 @@ fn require_signing_secret(secret: &str) -> Result<(), Value> {
89
89
  Ok(())
90
90
  }
91
91
 
92
- // Refuses (before anything is marked sent) when the caller isn't an
93
- // Admin/Owner, mail isn't configured, or there's no signing secret.
94
- async fn authorize(domain_ir: &Value, cookies: &HashMap<String, String>, secret: &str, client: &Mutex<Client>) -> Result<Mailer, Value> {
92
+ // An active account cookie whose person holds Admin or Owner.
93
+ pub(super) async fn require_admin(domain_ir: &Value, cookies: &HashMap<String, String>, secret: &str, client: &Mutex<Client>) -> Result<(), Value> {
95
94
  let email = active_session_email(domain_ir, cookies, secret, client).await?;
96
95
  match auth::caller_is_admin(client, domain_ir, &email).await {
97
- Ok(true) => {}
98
- Ok(false) => return Err(json_error(403, "only an Admin or Owner can send the newsletter")),
99
- Err(e) => return Err(json_error(500, &format!("members lookup failed: {e}"))),
96
+ Ok(true) => Ok(()),
97
+ Ok(false) => Err(json_error(403, "only an Admin or Owner can do this")),
98
+ Err(e) => Err(json_error(500, &format!("members lookup failed: {e}"))),
100
99
  }
100
+ }
101
+
102
+ // Refuses (before anything is marked sent) when the caller isn't an
103
+ // Admin/Owner, mail isn't configured, or there's no signing secret.
104
+ async fn authorize(domain_ir: &Value, cookies: &HashMap<String, String>, secret: &str, client: &Mutex<Client>) -> Result<Mailer, Value> {
105
+ require_admin(domain_ir, cookies, secret, client).await?;
101
106
  require_signing_secret(secret)?;
102
107
  match Mailer::from_env() {
103
108
  Ok(Some(mailer)) => Ok(mailer),
data/rust/host/src/web.rs CHANGED
@@ -61,6 +61,16 @@ pub async fn render(
61
61
  // Newsletter subscribe shares this gate (same hecksagon as the
62
62
  // registration aggregates) and is checked first since it needs none
63
63
  // of the Payments::Payment/Event context checkout requires.
64
+ // The subscriber list is PII (email, names, status): only an Admin or
65
+ // Owner holding the account cookie may read it, like sending does.
66
+ if method == "GET" && path == "/newsletter/subscribers" && ir().and_then(crate::ir::newsletter_provider).is_some() {
67
+ let Some(domain_ir) = ir() else {
68
+ return Some(respond(500, "text/plain", "HECKS_IR_PATH not set or unreadable — this domain has no web layer configured"));
69
+ };
70
+ if let Err(response) = newsletter_send::require_admin(domain_ir, &extract_cookies(body), &session_secret(), client).await {
71
+ return Some(response);
72
+ }
73
+ }
64
74
  if let Some(response) = newsletter::newsletter_route(method, path, &query, &raw_body, client, wasm_path, config, invoker).await {
65
75
  return Some(response);
66
76
  }
@@ -363,10 +373,11 @@ async fn accounts_me_route(domain_ir: &Value, cookies: &HashMap<String, String>,
363
373
  }
364
374
  }
365
375
 
366
- // GET /members: admitted people as JSON, for a caller holding the
367
- // account cookie but not the Governance session /admin/members needs.
376
+ // GET /members: admitted people as JSON, for an Admin or Owner holding the
377
+ // account cookie but not the Governance session /admin/members needs. The list
378
+ // is every person's name, email and role, so a plain member does not get it.
368
379
  async fn members_route(domain_ir: &Value, cookies: &HashMap<String, String>, secret: &str, client: &Mutex<Client>) -> Value {
369
- if let Err(response) = active_session_email(domain_ir, cookies, secret, client).await {
380
+ if let Err(response) = newsletter_send::require_admin(domain_ir, cookies, secret, client).await {
370
381
  return response;
371
382
  }
372
383
  match auth::all_people(client, domain_ir).await {
@@ -2292,6 +2303,32 @@ mod tests {
2292
2303
  }
2293
2304
  }
2294
2305
 
2306
+ #[tokio::test]
2307
+ async fn members_route_refuses_a_plain_member_with_a_403_and_no_people() {
2308
+ let secret = "s3cret";
2309
+ let (client, domain_ir) = scratch_members_db("hecks_host_web_test_members_route_403").await;
2310
+ client
2311
+ .lock()
2312
+ .await
2313
+ .execute(
2314
+ "INSERT INTO acme_member_head_snapshot_1 (id, ordinal, state) VALUES ($1, 0, $2::jsonb)",
2315
+ &[
2316
+ &"max@example.com",
2317
+ &json!({"name": {"value": "Max"}, "email": {"value": "max@example.com"},
2318
+ "role": {"value": "Member"}, "identity_id": {"value": "id-2"}}),
2319
+ ],
2320
+ )
2321
+ .await
2322
+ .unwrap();
2323
+
2324
+ let response = members_route(&domain_ir, &session_cookies(secret, "max@example.com"), secret, &client).await;
2325
+ assert_eq!(response["statusCode"], 403, "{response:?}");
2326
+ let body = response["body"].as_str().unwrap();
2327
+ for leaked in ["zed@example.com", "amy@example.com", "Zed"] {
2328
+ assert!(!body.contains(leaked), "{leaked:?} leaked to a plain member: {body}");
2329
+ }
2330
+ }
2331
+
2295
2332
  fn session_cookies(secret: &str, email: &str) -> HashMap<String, String> {
2296
2333
  let mut cookies = HashMap::new();
2297
2334
  cookies.insert(auth::account_cookie_name(), auth::account_token(secret, email, 60));
@@ -2798,9 +2835,15 @@ mod tests {
2798
2835
  } else {
2799
2836
  assert_eq!((add, registrations, disable, enable), (403, 403, 403, 403), "{caller} is refused everywhere");
2800
2837
  }
2801
- // Listing needs access, not admin: a Member may list, a stranger may not.
2838
+ // Listing is an admin gate too: it carries every person's email and role, so an
2839
+ // Admin or Owner lists, a Member is refused, and a stranger has no session at all.
2802
2840
  let listing = status_of(members_route(&domain_ir, &cookies, secret, &client).await).await;
2803
- assert_eq!(listing, if caller == "stranger@example.com" { 401 } else { 200 }, "{caller} listing");
2841
+ let expected = match caller {
2842
+ "stranger@example.com" => 401,
2843
+ _ if admits => 200,
2844
+ _ => 403,
2845
+ };
2846
+ assert_eq!(listing, expected, "{caller} listing");
2804
2847
  }
2805
2848
 
2806
2849
  // Anonymous: 401 on every route, before any role is looked at.
@@ -239,6 +239,9 @@ module RustProjection
239
239
  refusal = Projector.reserved_name_refusal(source_label, mod_name, ir[:aggregates].map { |a| a[:name] })
240
240
  raise refusal if refusal
241
241
 
242
+ unsafe = Projector.unsafe_name_refusal(source_label, ir)
243
+ raise unsafe if unsafe
244
+
242
245
  FileUtils.mkdir_p(mod_dir)
243
246
  domain_name = ir[:name]
244
247
  generated_aggregates = []
@@ -98,6 +98,42 @@ module RustProjection
98
98
  "Rust keyword (RustReservedWord), or is a reserved Cargo.toml key (CargoReservedName). Rename the domain."
99
99
  end
100
100
 
101
+ # Every declared `name` in the IR, in document order. The `fields` maps under
102
+ # `mutations` are skipped: their keys are attribute names and their values
103
+ # are source text, not declarations.
104
+ def declared_names(node, out = [])
105
+ case node
106
+ when Hash
107
+ node.each do |key, value|
108
+ if key.to_s == "fields"
109
+ next
110
+ elsif key.to_s == "name" && value.is_a?(String)
111
+ out << value
112
+ else
113
+ declared_names(value, out)
114
+ end
115
+ end
116
+ when Array
117
+ node.each { |item| declared_names(item, out) }
118
+ end
119
+ out
120
+ end
121
+
122
+ # Returns nil when every declared name is a plain identifier, else the
123
+ # message `DomainGenerator.call` raises. Attribute, command, event, query
124
+ # and port names are written into the generated crate as field, struct and
125
+ # function names, so a name like "a: String, pub evil: u8" would otherwise
126
+ # inject code into it. Must return the identical string as hecks-codegen's
127
+ # `naming::unsafe_name_refusal` (rust/codegen/src/naming.rs).
128
+ def unsafe_name_refusal(source_label, ir)
129
+ refused = declared_names(ir).uniq.reject { |name| name.match?(/\A[A-Za-z_][A-Za-z0-9_]*\z/) }
130
+ return nil if refused.empty?
131
+
132
+ "#{source_label}: declared name(s) #{refused.map(&:inspect).join(', ')} can't be used as-is — each is " \
133
+ "written into the generated Rust as an identifier, and at least one is not a plain identifier (letters, " \
134
+ "digits and underscores, not starting with a digit). Rename it in the bluebook."
135
+ end
136
+
101
137
  # `r#crate`/`r#self`/`r#super`/`r#Self` are not valid raw-identifier
102
138
  # syntax in Rust at all, so these four can't be escaped the way
103
139
  # `rust_ident_field` escapes every other `RUST_KEYWORDS` entry.
@@ -70,6 +70,10 @@ module RustProjectPipeline
70
70
  # vendor/embryonaut_bluebooks/<name>/bluebook/, sorted. A vendored
71
71
  # package has no .hecksagon of its own either, just its .bluebook(s).
72
72
  chapters += uses_embryonaut_bluebook_names.map do |pkg_name|
73
+ unless pkg_name.to_s.match?(Hecks::EmbryonautBluebook::PACKAGE_NAME)
74
+ abort "hecks project_rust (Rust path): uses_embryonaut_bluebook #{pkg_name.inspect} is not a package " \
75
+ "name — it must match [a-z][a-z0-9_]* (the name `hecks vendor` accepts)"
76
+ end
73
77
  pkg_dir = File.join(domain, "vendor", "embryonaut_bluebooks", pkg_name.to_s, "bluebook")
74
78
  pkg_files = Dir.glob(File.join(pkg_dir, "*.bluebook")).sort
75
79
  if pkg_files.empty?
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hecks
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.1
4
+ version: 3.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Young
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-09-30 00:00:00.000000000 Z
11
+ date: 2026-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism