@@ -389,11 +389,77 @@ def validate(self, value: typing.Any | None) -> File:
389389 raise ParameterValueError (str (e ))
390390
391391
392+ class Secret (str ):
393+ """Marker type for secret/password pipeline parameters.
394+
395+ Use as the ``type`` argument of the ``@parameter`` decorator to indicate that the parameter value is sensitive
396+ and should be hidden in the OpenHEXA web interface. The pipeline function will receive the value as a plain
397+ ``str`` at runtime.
398+
399+ Example::
400+
401+ @parameter("iaso_token", type=Secret, name="IASO token", required=True)
402+ @pipeline("my-pipeline")
403+ def my_pipeline(iaso_token: str):
404+ ...
405+ """
406+
407+ pass
408+
409+
410+ class SecretType (ParameterType ):
411+ """Type class for secret/password string parameters. Values are treated as plain strings at runtime."""
412+
413+ @property
414+ def spec_type (self ) -> str :
415+ """Return a type string for the specs that are sent to the backend."""
416+ return "secret"
417+
418+ @property
419+ def expected_type (self ) -> type :
420+ """Returns the python type expected for values."""
421+ return Secret
422+
423+ @property
424+ def accepts_choices (self ) -> bool :
425+ """Secrets don't support choices."""
426+ return False
427+
428+ @property
429+ def accepts_multiple (self ) -> bool :
430+ """Secrets don't support multiple values."""
431+ return False
432+
433+ @staticmethod
434+ def normalize (value : typing .Any ) -> Secret | None :
435+ """Strip whitespace, convert empty strings to None, and wrap as Secret."""
436+ if isinstance (value , str ):
437+ normalized_value = value .strip ()
438+ else :
439+ normalized_value = value
440+
441+ if normalized_value == "" :
442+ return None
443+
444+ if isinstance (normalized_value , str ):
445+ return Secret (normalized_value )
446+
447+ return normalized_value
448+
449+ def validate_default (self , value : typing .Any | None ):
450+ """Validate the default value configured for this type."""
451+ if value == "" :
452+ raise ParameterValueError ("Empty values are not accepted." )
453+
454+ super ().validate_default (value )
455+
456+
392457TYPES_BY_PYTHON_TYPE = {
393458 "str" : StringType ,
394459 "bool" : Boolean ,
395460 "int" : Integer ,
396461 "float" : Float ,
462+ "Secret" : SecretType ,
397463 "DHIS2Connection" : DHIS2ConnectionType ,
398464 "PostgreSQLConnection" : PostgreSQLConnectionType ,
399465 "IASOConnection" : IASOConnectionType ,
@@ -438,6 +504,7 @@ def __init__(
438504 | int
439505 | bool
440506 | float
507+ | Secret
441508 | DHIS2Connection
442509 | IASOConnection
443510 | PostgreSQLConnection
@@ -622,6 +689,7 @@ def parameter(
622689 | int
623690 | bool
624691 | float
692+ | Secret
625693 | DHIS2Connection
626694 | IASOConnection
627695 | PostgreSQLConnection
0 commit comments