Description
ImageOptimizerSettings::normalize and ImageOptimizerProfileSet::normalize in crates/trusted-server-core/src/settings.rs trim map keys by draining a HashMap and collecting into a new one. Two distinct source keys can then become one key. For example, medium and " medium" both normalize to medium, and the later iteration silently overwrites the earlier value. HashMap iteration order is randomized, so either value can survive on a new settings parse. The same collision exists for profile-set names.
Fastly parses Settings on each request. One configuration can therefore select different image optimization parameters across requests; template_fingerprint and the resulting template cache key can also vary. This is related to #1197, but arises from a separate normalization collision.
Steps to reproduce
[image_optimizer.profile_sets.default_images]
default_profile = "medium"
[image_optimizer.profile_sets.default_images.profiles]
medium = "width=100"
" medium" = "width=200"
At a4e01eb55, parsing this configuration 64 times with Settings::from_toml returned both width=100 and width=200 for profiles["medium"].
Expected behavior
Settings loading rejects profile keys and profile-set keys that collide after trimming, with a configuration error identifying the profile set and the colliding source keys. A deterministic winner would still discard one configured value without telling the operator.
Root cause
Both normalization functions use drain().map(…).filter(…).collect() into a HashMap, with no collision check. The profile-key path also trims values. The resulting map cannot show that two source keys mapped to the same normalized name.
Done when
Affected area
Core settings / image optimizer / template cache fingerprint
Version
Reproduced at a4e01eb55 (main at the time of the report).
Description
ImageOptimizerSettings::normalizeandImageOptimizerProfileSet::normalizeincrates/trusted-server-core/src/settings.rstrim map keys by draining aHashMapand collecting into a new one. Two distinct source keys can then become one key. For example,mediumand" medium"both normalize tomedium, and the later iteration silently overwrites the earlier value.HashMapiteration order is randomized, so either value can survive on a new settings parse. The same collision exists for profile-set names.Fastly parses
Settingson each request. One configuration can therefore select different image optimization parameters across requests;template_fingerprintand the resulting template cache key can also vary. This is related to #1197, but arises from a separate normalization collision.Steps to reproduce
At
a4e01eb55, parsing this configuration 64 times withSettings::from_tomlreturned bothwidth=100andwidth=200forprofiles["medium"].Expected behavior
Settings loading rejects profile keys and profile-set keys that collide after trimming, with a configuration error identifying the profile set and the colliding source keys. A deterministic winner would still discard one configured value without telling the operator.
Root cause
Both normalization functions use
drain().map(…).filter(…).collect()into aHashMap, with no collision check. The profile-key path also trims values. The resulting map cannot show that two source keys mapped to the same normalized name.Done when
Affected area
Core settings / image optimizer / template cache fingerprint
Version
Reproduced at
a4e01eb55(mainat the time of the report).