ConfigurableParameter: do not magically overwrite the 'name' attribute
The ClassVarMeta metaclass used to derive each ConfigurableParameter's 'name' attribute automatically from the Python class name (via camel_to_snake()). Stop doing this, for three reasons:
1) Python class names follow constraints that do not fit the naming commonly used in CSV files. For example, a name like "5GS-SUCI-CalcInfo" starts with a digit and contains dashes, neither of which is permissible in a class name.
2) Python class names live in their own namespace, distinct from the one used to present eSIM parameters to end users. Deriving the UI name from the class name couples these two namespaces together.
Taken together, (1) and (2) mean that automatic naming both imposes class-name constraints on the user-visible names and merges the internal Python namespace with the publicly shown one - a layer violation from the perspective of UI design.
3) Overriding 'name' from __new__() makes manual naming impossible: a subclass that sets 'name = "bar"' as a class attribute would still end up with the value computed by the metaclass, which is surprising and hard to track down:
class MySuper(metaclass=...): # __new__ sets name = 'foo' ... class MySub(MySuper): name = 'bar' print(MySub().name) # 'foo', not 'bar' as one would expect
Add ConfigurableParameterTest, which applies each parameter to a real UPP DER template and reads it back, comparing results against a stored expected-output snapshot (xo/test_configurable_parameters).
Add TestValidateVal covering validate_val() for Iccid, Imsi, Pin1, Puk1 and K, testing both valid inputs and invalid ones expected to raise ValueError.
Add TestEnumParam covering the EnumParam methods (validate_val, map_name_to_val, map_val_to_name, name_normalize, clean_name_str) using AlgorithmID as the concrete subclass, including fuzzy name matching.
Also add get_value_from_pes() to ConfigurableParameter as a convenience wrapper around get_values_from_pes() that asserts all returned values are identical and returns the single result.
param_source: use random.SystemRandom as random nr source
Python's random module uses a PRNG (Mersenne Twister) which is utterly insecure for key generation - it was so far only used for testing. Replace it with random.SystemRandom(), which draws from /dev/urandom and is suitable for generating cryptographic key material.
validate_val() calls len() to check the value against allow_len, min_len and max_len. len() requires the object to have a __len__() method, which integers do not — calling len() on an int raises TypeError.
Fix this by checking for __len__ first: if present, use len(val) as usual; otherwise fall back to len(str(val)), which gives the number of decimal digits for integer values.
SmspTpScAddr: fix SMSP record length and alpha_id padding
apply_val() was re-encoding the SMSP with the minimum total_len of 28, which produces a 28-byte body with no alpha_id field. After a DER round-trip, the profile machinery re-pads the body to the original record length using the template's fill pattern, which may not be 0xFF. Those non-0xFF fill bytes end up in the alpha_id area, and GSM 7-bit decoding then fails with a KeyError when the modified profile is read back.
Fix by: - setting alpha_id = '' so the field is present but empty - setting f_smsp.rec_len = 42 (28 fixed bytes + 14 bytes of alpha_id padding) so the re-encoded body carries 0xFF-padded alpha_id space and the efFileSize in the fileDescriptor stays consistent - passing total_len=f_smsp.rec_len to encode_record_bin() so the alpha_id area is actually padded to that length
saip: add numeric_base indicator to ConfigurableParameter
By default, numeric_base = None, to indicate that there are no explicit limitations on the number space.
For parameters that are definitely decimal, set numeric_base = 10. For definitely hexadecimal, set numeric_base = 16.
Do the same for ConfigurableParameter as well as ParamSource, so callers can match them up: if a parameter is numeric_base = 10, then omit sources that are numeric_base = 16, and vice versa.