diff --git a/rules/python/security/hashids-with-flask-secret-python.yml b/rules/python/security/hashids-with-flask-secret-python.yml new file mode 100644 index 00000000..5ac0b18e --- /dev/null +++ b/rules/python/security/hashids-with-flask-secret-python.yml @@ -0,0 +1,201 @@ +id: hashids-with-flask-secret-python +severity: warning +language: python +message: >- + The Flask secret key is used as salt in HashIDs. The HashID mechanism + is not secure. By observing sufficient HashIDs, the salt used to construct + them can be recovered. This means the Flask secret key can be obtained by + attackers, through the HashIDs). +note: >- + [CWE-327] Use of a Broken or Risky Cryptographic Algorithm. + [REFERENCES] + - https://flask.palletsprojects.com/en/2.2.x/config/#SECRET_KEY + - http://carnage.github.io/2015/08/cryptanalysis-of-hashids +utils: + hashids.Hashids(..., salt=flask.current_app.config['SECRET_KEY'], ...): + # hashids.Hashids(..., salt=flask.current_app.config['SECRET_KEY'], ...) + kind: call + all: + - has: + stopBy: neighbor + kind: attribute + regex: ^hashids.Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^salt$ + - has: + stopBy: neighbor + kind: subscript + pattern: flask.current_app.config['SECRET_KEY'] + hashids.Hashids(flask.current_app.config['SECRET_KEY'], ...): + # hashids.Hashids(flask.current_app.config['SECRET_KEY'], ...) + kind: call + all: + - has: + stopBy: neighbor + kind: attribute + regex: ^hashids.Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: neighbor + kind: subscript + pattern: flask.current_app.config['SECRET_KEY'] + hashids.Hashids($APP.config['SECRET_KEY'], ...): + # hashids.Hashids($APP.config['SECRET_KEY'], ...) + kind: call + all: + - has: + stopBy: neighbor + kind: attribute + regex: ^hashids.Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: neighbor + kind: subscript + pattern: $APP.config['SECRET_KEY'] + - inside: + stopBy: end + kind: module + has: + stopBy: end + kind: expression_statement + has: + stopBy: neighbor + kind: assignment + pattern: $APP = flask.Flask($$$) + hashids.Hashids(..., salt=$APP.config['SECRET_KEY'], ...): + # hashids.Hashids(..., salt=$APP.config['SECRET_KEY'], ...) + kind: call + all: + - has: + stopBy: neighbor + kind: attribute + regex: ^hashids.Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^salt$ + - has: + stopBy: neighbor + kind: subscript + pattern: $APP.config['SECRET_KEY'] + - inside: + stopBy: end + kind: module + has: + stopBy: end + kind: expression_statement + has: + stopBy: neighbor + kind: assignment + pattern: $APP = flask.Flask($$$) + Hashids(salt=app.config['SECRET_KEY']): +# from hashids import Hashids +# from flask import current_app as app +# hash_id = Hashids(salt=app.config['SECRET_KEY']) + kind: call + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^salt$ + - has: + stopBy: neighbor + kind: subscript + pattern: $APP.config['SECRET_KEY'] + - inside: + stopBy: end + kind: module + all: + - has: + stopBy: end + kind: import_from_statement + pattern: from hashids import Hashids + - any: + - has: + stopBy: end + kind: import_from_statement + pattern: from flask import current_app as $APP + - has: + stopBy: end + kind: expression_statement + has: + stopBy: end + kind: assignment + pattern: $APP = Flask($$$) + Hashids(salt=current_app.config['SECRET_KEY']): + # from hashids import Hashids + # from flask import current_app + # hashids = Hashids(min_length=5, salt=current_app.config['SECRET_KEY']) + kind: call + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^Hashids$ + - has: + stopBy: neighbor + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + stopBy: neighbor + kind: identifier + regex: ^salt$ + - has: + stopBy: neighbor + kind: subscript + pattern: current_app.config['SECRET_KEY'] + - inside: + stopBy: end + kind: module + all: + - has: + stopBy: end + kind: import_from_statement + pattern: from hashids import Hashids + - has: + stopBy: end + kind: import_from_statement + pattern: from flask import current_app +rule: + kind: call + any: + - matches: hashids.Hashids(..., salt=flask.current_app.config['SECRET_KEY'], ...) + - matches: hashids.Hashids(flask.current_app.config['SECRET_KEY'], ...) + - matches: hashids.Hashids($APP.config['SECRET_KEY'], ...) + - matches: hashids.Hashids(..., salt=$APP.config['SECRET_KEY'], ...) + - matches: Hashids(salt=app.config['SECRET_KEY']) + - matches: Hashids(salt=current_app.config['SECRET_KEY']) \ No newline at end of file diff --git a/rules/python/security/python-cassandra-empty-password-python.yml b/rules/python/security/python-cassandra-empty-password-python.yml new file mode 100644 index 00000000..53e259e4 --- /dev/null +++ b/rules/python/security/python-cassandra-empty-password-python.yml @@ -0,0 +1,225 @@ +id: python-cassandra-empty-password-python +language: python +severity: warning +message: >- + The application creates a database connection with an empty password. This can lead to unauthorized access by either an internal or external malicious actor. To prevent this vulnerability, enforce authentication when connecting to a database by using environment variables to securely provide credentials or retrieving them from a secure vault or HSM (Hardware Security Module). +note: >- + [CWE-287]: Improper Authentication + [REFERENCES] + - https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html + +rule: + any: + - kind: call + any: + - kind: call + has: + kind: identifier + regex: ^PlainTextAuthProvider$ + precedes: + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + nthChild: 1 + kind: identifier + regex: ^password$ + - has: + nthChild: 2 + kind: string + all: + - has: + kind: string_start + nthChild: 1 + - has: + kind: string_end + nthChild: 2 + - kind: call + has: + kind: identifier + regex: ^PlainTextAuthProvider$ + precedes: + kind: argument_list + has: + stopBy: end + kind: string + all: + - has: + nthChild: 1 + kind: string_start + - has: + nthChild: 2 + kind: string_end + inside: + stopBy: end + follows: + stopBy: end + kind: import_from_statement + all: + - has: + nthChild: 1 + kind: dotted_name + field: module_name + regex: ^cassandra.auth$ + - has: + stopBy: end + kind: dotted_name + regex: ^PlainTextAuthProvider$ + - kind: call + any: + - kind: call + has: + kind: identifier + regex: ^SaslAuthProvider$ + precedes: + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + nthChild: 1 + kind: identifier + regex: ^password$ + - has: + nthChild: 2 + kind: string + all: + - has: + kind: string_start + nthChild: 1 + - has: + kind: string_end + nthChild: 2 + inside: + stopBy: end + follows: + stopBy: end + kind: import_from_statement + all: + - has: + nthChild: 1 + kind: dotted_name + field: module_name + regex: ^cassandra.auth$ + - has: + stopBy: end + kind: dotted_name + regex: ^SaslAuthProvider$ + - kind: call + any: + - kind: call + has: + kind: identifier + pattern: $PLAIN_ALIAS + precedes: + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + nthChild: 1 + kind: identifier + regex: ^password$ + - has: + nthChild: 2 + kind: string + all: + - has: + kind: string_start + nthChild: 1 + - has: + kind: string_end + nthChild: 2 + - kind: call + has: + kind: identifier + regex: ^PlainTextAuthProvider$ + precedes: + kind: argument_list + has: + stopBy: end + kind: string + all: + - has: + nthChild: 1 + kind: string_start + - has: + nthChild: 2 + kind: string_end + inside: + stopBy: end + follows: + stopBy: end + kind: import_from_statement + all: + - has: + nthChild: 1 + kind: dotted_name + field: module_name + regex: ^cassandra.auth$ + - has: + stopBy: end + kind: aliased_import + all: + - has: + kind: dotted_name + nthChild: 1 + regex: ^PlainTextAuthProvider$ + - has: + kind: identifier + nthChild: 2 + pattern: $PLAIN_ALIAS + - kind: call + any: + - kind: call + has: + kind: identifier + pattern: $SASL_ALIAS + precedes: + kind: argument_list + has: + stopBy: end + kind: keyword_argument + all: + - has: + nthChild: 1 + kind: identifier + regex: ^password$ + - has: + nthChild: 2 + kind: string + all: + - has: + kind: string_start + nthChild: 1 + - has: + kind: string_end + nthChild: 2 + inside: + stopBy: end + follows: + stopBy: end + kind: import_from_statement + all: + - has: + nthChild: 1 + kind: dotted_name + field: module_name + regex: ^cassandra.auth$ + - has: + stopBy: end + kind: aliased_import + all: + - has: + kind: dotted_name + nthChild: 1 + regex: ^SaslAuthProvider$ + - has: + kind: identifier + field: alias + nthChild: 2 + pattern: $SASL_ALIAS diff --git a/rules/python/security/python-couchbase-empty-password-python.yml b/rules/python/security/python-couchbase-empty-password-python.yml new file mode 100644 index 00000000..1d8bf737 --- /dev/null +++ b/rules/python/security/python-couchbase-empty-password-python.yml @@ -0,0 +1,77 @@ +id: python-couchbase-empty-password-python +language: python +severity: warning +message: >- + The application creates a database connection with an empty password. + This can lead to unauthorized access by either an internal or external + malicious actor. To prevent this vulnerability, enforce authentication + when connecting to a database by using environment variables to securely + provide credentials or retrieving them from a secure vault or HSM + (Hardware Security Module). +note: >- + [CWE-287]: Improper Authentication + [OWASP A07:2021]: Identification and Authentication Failures + [REFERENCES] + https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html +utils: + match_passwordauthenticator: + kind: call + all: + - has: + kind: identifier + pattern: $R + - has: + stopBy: neighbor + kind: argument_list + all: + - any: + - has: + stopBy: end + kind: attribute + has: + stopBy: neighbor + kind: identifier + - has: + stopBy: neighbor + kind: string + - has: + stopBy: neighbor + kind: string + not: + has: + stopBy: neighbor + kind: string_content + + - inside: + stopBy: end + kind: module + has: + stopBy: end + kind: import_from_statement + all: + - has: + stopBy: end + kind: dotted_name + field: module_name + all: + - has: + stopBy: end + kind: identifier + regex: couchbase_core + - has: + stopBy: end + kind: identifier + regex: cluster + - has: + stopBy: end + kind: dotted_name + field: name + has: + stopBy: end + kind: identifier + pattern: $R + regex: PasswordAuthenticator +rule: + all: + - matches: match_passwordauthenticator + diff --git a/tests/__snapshots__/hashids-with-flask-secret-python-snapshot.yml b/tests/__snapshots__/hashids-with-flask-secret-python-snapshot.yml new file mode 100644 index 00000000..2154f4ee --- /dev/null +++ b/tests/__snapshots__/hashids-with-flask-secret-python-snapshot.yml @@ -0,0 +1,230 @@ +id: hashids-with-flask-secret-python +snapshots: + ? |- + from hashids import Hashids + app = Flask(__name__.split('.')[0]) + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) + : labels: + - source: Hashids(min_length=4, salt=app.config['SECRET_KEY']) + style: primary + start: 74 + end: 126 + - source: Hashids + style: secondary + start: 74 + end: 81 + - source: salt + style: secondary + start: 96 + end: 100 + - source: app.config['SECRET_KEY'] + style: secondary + start: 101 + end: 125 + - source: salt=app.config['SECRET_KEY'] + style: secondary + start: 96 + end: 125 + - source: (min_length=4, salt=app.config['SECRET_KEY']) + style: secondary + start: 81 + end: 126 + - source: from hashids import Hashids + style: secondary + start: 0 + end: 27 + - source: app = Flask(__name__.split('.')[0]) + style: secondary + start: 28 + end: 63 + - source: app = Flask(__name__.split('.')[0]) + style: secondary + start: 28 + end: 63 + - source: |- + from hashids import Hashids + app = Flask(__name__.split('.')[0]) + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) + style: secondary + start: 0 + end: 126 + ? | + from hashids import Hashids + foo = Flask() + hashids = Hashids(min_length=4, salt=foo.config['SECRET_KEY']) + : labels: + - source: Hashids(min_length=4, salt=foo.config['SECRET_KEY']) + style: primary + start: 52 + end: 104 + - source: Hashids + style: secondary + start: 52 + end: 59 + - source: salt + style: secondary + start: 74 + end: 78 + - source: foo.config['SECRET_KEY'] + style: secondary + start: 79 + end: 103 + - source: salt=foo.config['SECRET_KEY'] + style: secondary + start: 74 + end: 103 + - source: (min_length=4, salt=foo.config['SECRET_KEY']) + style: secondary + start: 59 + end: 104 + - source: from hashids import Hashids + style: secondary + start: 0 + end: 27 + - source: foo = Flask() + style: secondary + start: 28 + end: 41 + - source: foo = Flask() + style: secondary + start: 28 + end: 41 + - source: | + from hashids import Hashids + foo = Flask() + hashids = Hashids(min_length=4, salt=foo.config['SECRET_KEY']) + style: secondary + start: 0 + end: 105 + ? | + from hashids import Hashids + from flask import current_app + hashids = Hashids(min_length=5, salt=current_app.config['SECRET_KEY']) + : labels: + - source: Hashids(min_length=5, salt=current_app.config['SECRET_KEY']) + style: primary + start: 68 + end: 128 + - source: Hashids + style: secondary + start: 68 + end: 75 + - source: salt + style: secondary + start: 90 + end: 94 + - source: current_app.config['SECRET_KEY'] + style: secondary + start: 95 + end: 127 + - source: salt=current_app.config['SECRET_KEY'] + style: secondary + start: 90 + end: 127 + - source: (min_length=5, salt=current_app.config['SECRET_KEY']) + style: secondary + start: 75 + end: 128 + - source: from hashids import Hashids + style: secondary + start: 0 + end: 27 + - source: from flask import current_app + style: secondary + start: 28 + end: 57 + - source: | + from hashids import Hashids + from flask import current_app + hashids = Hashids(min_length=5, salt=current_app.config['SECRET_KEY']) + style: secondary + start: 0 + end: 129 + ? | + from hashids import Hashids + from flask import current_app as app + hash_id = Hashids(salt=app.config['SECRET_KEY'], min_length=34) + : labels: + - source: Hashids(salt=app.config['SECRET_KEY'], min_length=34) + style: primary + start: 75 + end: 128 + - source: Hashids + style: secondary + start: 75 + end: 82 + - source: salt + style: secondary + start: 83 + end: 87 + - source: app.config['SECRET_KEY'] + style: secondary + start: 88 + end: 112 + - source: salt=app.config['SECRET_KEY'] + style: secondary + start: 83 + end: 112 + - source: (salt=app.config['SECRET_KEY'], min_length=34) + style: secondary + start: 82 + end: 128 + - source: from hashids import Hashids + style: secondary + start: 0 + end: 27 + - source: from flask import current_app as app + style: secondary + start: 28 + end: 64 + - source: | + from hashids import Hashids + from flask import current_app as app + hash_id = Hashids(salt=app.config['SECRET_KEY'], min_length=34) + style: secondary + start: 0 + end: 129 + ? | + from hashids import Hashids + from flask import current_app as app + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) + : labels: + - source: Hashids(min_length=4, salt=app.config['SECRET_KEY']) + style: primary + start: 75 + end: 127 + - source: Hashids + style: secondary + start: 75 + end: 82 + - source: salt + style: secondary + start: 97 + end: 101 + - source: app.config['SECRET_KEY'] + style: secondary + start: 102 + end: 126 + - source: salt=app.config['SECRET_KEY'] + style: secondary + start: 97 + end: 126 + - source: (min_length=4, salt=app.config['SECRET_KEY']) + style: secondary + start: 82 + end: 127 + - source: from hashids import Hashids + style: secondary + start: 0 + end: 27 + - source: from flask import current_app as app + style: secondary + start: 28 + end: 64 + - source: | + from hashids import Hashids + from flask import current_app as app + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) + style: secondary + start: 0 + end: 128 diff --git a/tests/__snapshots__/python-cassandra-empty-password-python-snapshot.yml b/tests/__snapshots__/python-cassandra-empty-password-python-snapshot.yml new file mode 100644 index 00000000..0f86b2f2 --- /dev/null +++ b/tests/__snapshots__/python-cassandra-empty-password-python-snapshot.yml @@ -0,0 +1,98 @@ +id: python-cassandra-empty-password-python +snapshots: + ? | + from cassandra.auth import PlainTextAuthProvider + auth_provider = PlainTextAuthProvider('user', '') + : labels: + - source: PlainTextAuthProvider('user', '') + style: primary + start: 65 + end: 98 + - source: '''' + style: secondary + start: 95 + end: 96 + - source: '''' + style: secondary + start: 96 + end: 97 + - source: '''''' + style: secondary + start: 95 + end: 97 + - source: ('user', '') + style: secondary + start: 86 + end: 98 + - source: PlainTextAuthProvider + style: secondary + start: 65 + end: 86 + - source: cassandra.auth + style: secondary + start: 5 + end: 19 + - source: PlainTextAuthProvider + style: secondary + start: 27 + end: 48 + - source: from cassandra.auth import PlainTextAuthProvider + style: secondary + start: 0 + end: 48 + - source: from cassandra.auth import PlainTextAuthProvider + style: secondary + start: 0 + end: 48 + ? | + from cassandra.auth import PlainTextAuthProvider + auth_provider = PlainTextAuthProvider(username='user', password='') + : labels: + - source: PlainTextAuthProvider(username='user', password='') + style: primary + start: 65 + end: 116 + - source: password + style: secondary + start: 104 + end: 112 + - source: '''' + style: secondary + start: 113 + end: 114 + - source: '''' + style: secondary + start: 114 + end: 115 + - source: '''''' + style: secondary + start: 113 + end: 115 + - source: password='' + style: secondary + start: 104 + end: 115 + - source: (username='user', password='') + style: secondary + start: 86 + end: 116 + - source: PlainTextAuthProvider + style: secondary + start: 65 + end: 86 + - source: cassandra.auth + style: secondary + start: 5 + end: 19 + - source: PlainTextAuthProvider + style: secondary + start: 27 + end: 48 + - source: from cassandra.auth import PlainTextAuthProvider + style: secondary + start: 0 + end: 48 + - source: from cassandra.auth import PlainTextAuthProvider + style: secondary + start: 0 + end: 48 diff --git a/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml b/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml new file mode 100644 index 00000000..fdd4f71e --- /dev/null +++ b/tests/__snapshots__/python-couchbase-empty-password-python-snapshot.yml @@ -0,0 +1,118 @@ +id: python-couchbase-empty-password-python +snapshots: + ? | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', '') + : labels: + - source: PasswordAuthenticator('username', '') + style: primary + start: 121 + end: 158 + - source: PasswordAuthenticator + style: secondary + start: 121 + end: 142 + - source: '''username''' + style: secondary + start: 143 + end: 153 + - source: '''''' + style: secondary + start: 155 + end: 157 + - source: ('username', '') + style: secondary + start: 142 + end: 158 + - source: couchbase_core + style: secondary + start: 69 + end: 83 + - source: cluster + style: secondary + start: 84 + end: 91 + - source: couchbase_core.cluster + style: secondary + start: 69 + end: 91 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: from couchbase_core.cluster import PasswordAuthenticator + style: secondary + start: 64 + end: 120 + - source: | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', '') + style: secondary + start: 0 + end: 159 + ? | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + : labels: + - source: PasswordAuthenticator('username', '') + style: primary + start: 179 + end: 216 + - source: PasswordAuthenticator + style: secondary + start: 179 + end: 200 + - source: '''username''' + style: secondary + start: 201 + end: 211 + - source: '''''' + style: secondary + start: 213 + end: 215 + - source: ('username', '') + style: secondary + start: 200 + end: 216 + - source: couchbase_core + style: secondary + start: 69 + end: 83 + - source: cluster + style: secondary + start: 84 + end: 91 + - source: couchbase_core.cluster + style: secondary + start: 69 + end: 91 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: PasswordAuthenticator + style: secondary + start: 99 + end: 120 + - source: from couchbase_core.cluster import PasswordAuthenticator + style: secondary + start: 64 + end: 120 + - source: | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + style: secondary + start: 0 + end: 219 diff --git a/tests/python/hashids-with-flask-secret-python-test.yml b/tests/python/hashids-with-flask-secret-python-test.yml new file mode 100644 index 00000000..88897471 --- /dev/null +++ b/tests/python/hashids-with-flask-secret-python-test.yml @@ -0,0 +1,25 @@ +id: hashids-with-flask-secret-python +valid: + - | + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) +invalid: + - | + from hashids import Hashids + from flask import current_app as app + hash_id = Hashids(salt=app.config['SECRET_KEY'], min_length=34) + - | + from hashids import Hashids + from flask import current_app as app + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) + - | + from hashids import Hashids + from flask import current_app + hashids = Hashids(min_length=5, salt=current_app.config['SECRET_KEY']) + - | + from hashids import Hashids + foo = Flask() + hashids = Hashids(min_length=4, salt=foo.config['SECRET_KEY']) + - | + from hashids import Hashids + app = Flask(__name__.split('.')[0]) + hashids = Hashids(min_length=4, salt=app.config['SECRET_KEY']) \ No newline at end of file diff --git a/tests/python/python-cassandra-empty-password-python-test.yml b/tests/python/python-cassandra-empty-password-python-test.yml new file mode 100644 index 00000000..885b0dac --- /dev/null +++ b/tests/python/python-cassandra-empty-password-python-test.yml @@ -0,0 +1,12 @@ +id: python-cassandra-empty-password-python +valid: + - | + from cassandra.auth import PlainTextAuthProvider + auth_provider = PlainTextAuthProvider('user', 'pass') +invalid: + - | + from cassandra.auth import PlainTextAuthProvider + auth_provider = PlainTextAuthProvider('user', '') + - | + from cassandra.auth import PlainTextAuthProvider + auth_provider = PlainTextAuthProvider(username='user', password='') diff --git a/tests/python/python-couchbase-empty-password-python-test.yml b/tests/python/python-couchbase-empty-password-python-test.yml new file mode 100644 index 00000000..288034f0 --- /dev/null +++ b/tests/python/python-couchbase-empty-password-python-test.yml @@ -0,0 +1,23 @@ +id: python-couchbase-empty-password-python +valid: + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', os.env['pass']) + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', os.getenv('')) +invalid: + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + cluster = Cluster('couchbase://localhost', ClusterOptions(PasswordAuthenticator('username', ''))) + - | + import os + from couchbase.cluster import Cluster, ClusterOptions + from couchbase_core.cluster import PasswordAuthenticator + PasswordAuthenticator('username', '')