dbt-labs / hologram

A library for automatically generating Draft 7 JSON Schemas from Python dataclasses
MIT License
9 stars 13 forks source link

Credential leaking from class validation #59

Open leehuwuj opened 1 year ago

leehuwuj commented 1 year ago

The hologram package is using jsonschema as validator tool to check class data fields. In the context of Dbt Profile class where password or api key is a field then if there is any wrong input the jsonschema will show all the instance value in plain text.

Example: In the context of Dbt Redshift profile. If user forget to set the port parameter then the log will show up the password.

Traceback (most recent call last):
  File "/home/airflow/.local/lib/python3.10/site-packages/dbt/config/profile.py", line 183, in _credentials_from_profile
    cls.validate(data)
  File "/home/airflow/.local/lib/python3.10/site-packages/hologram/__init__.py", line 989, in validate
    raise ValidationError.create_from(error) from error
hologram.ValidationError: 'port' is a required property

Failed validating 'required' in schema:
    {'$schema': 'http://json-schema.org/draft-07/schema#',
     'additionalProperties': True,
     'definitions': {},
     'description': 'RedshiftCredentials(database: str, schema: str, host: '
                    'str, user: str, port: dbt.helper_types.Port, '
                    'password: Optional[str] = None, connect_timeout: int '
                    '= 10, role: Optional[str] = None, search_path: '
                    'Optional[str] = None, keepalives_idle: int = 4, '
                    'sslmode: Optional[str] = None, sslcert: Optional[str] '
                    '= None, sslkey: Optional[str] = None, sslrootcert: '
                    'Optional[str] = None, application_name: Optional[str] '
                    "= 'dbt', retries: int = 1, method: str = "
                    "<RedshiftConnectionMethod.DATABASE: 'database'>, "
                    'cluster_id: Optional[str] = None, iam_profile: '
                    'Optional[str] = None, iam_duration_seconds: int = '
                    '900, autocreate: bool = False, db_groups: List[str] = '
                    '<factory>, ra3_node: Optional[bool] = False)',
     'properties': {'application_name': {'default': 'dbt',
                                         'oneOf': [{'type': 'string'},
                                                   {'type': 'null'}]},
                    'autocreate': {'default': False, 'type': 'boolean'},
                    'cluster_id': {'description': 'If using IAM auth, the '
                                                  'name of the cluster',
                                   'oneOf': [{'type': 'string'},
                                             {'type': 'null'}]},
                    'connect_timeout': {'default': 10, 'type': 'integer'},
                    'database': {'type': 'string'},
                    'db_groups': {'default': [],
                                  'items': {'type': 'string'},
                                  'type': 'array'},
                    'host': {'type': 'string'},
                    'iam_duration_seconds': {'default': 900,
                                             'type': 'integer'},
                    'iam_profile': {'oneOf': [{'type': 'string'},
                                              {'type': 'null'}]},
                    'keepalives_idle': {'default': 4, 'type': 'integer'},
                    'method': {'default': <RedshiftConnectionMethod.DATABASE: 'database'>,
                               'type': 'string'},
                    'password': {'oneOf': [{'type': 'string'},
                                           {'type': 'null'}]},
                    'port': {'maximum': 65535,
                             'minimum': 0,
                             'type': 'integer'},
                    'ra3_node': {'default': False,
                                 'oneOf': [{'type': 'boolean'},
                                           {'type': 'null'}]},
                    'retries': {'default': 1, 'type': 'integer'},
                    'role': {'oneOf': [{'type': 'string'},
                                       {'type': 'null'}]},
                    'schema': {'type': 'string'},
                    'search_path': {'oneOf': [{'type': 'string'},
                                              {'type': 'null'}]},
                    'sslcert': {'oneOf': [{'type': 'string'},
                                          {'type': 'null'}]},
                    'sslkey': {'oneOf': [{'type': 'string'},
                                         {'type': 'null'}]},
                    'sslmode': {'oneOf': [{'type': 'string'},
                                          {'type': 'null'}]},
                    'sslrootcert': {'oneOf': [{'type': 'string'},
                                              {'type': 'null'}]},
                    'user': {'type': 'string'}},
     'required': ['database', 'schema', 'host', 'user', 'port'],
     'type': 'object'}

On instance:
    {'database': 'xxx',
     'host': 'xxx',
     'password': 'PASS_WORD_LEAKED',
     'schema': 'xxx',
     'user': 'xxx'}