From c1e6996e998da6fe13524d6b2d001a1a9bbcee07 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 2 Jun 2022 14:24:29 +0200 Subject: [PATCH 1/4] Inline Expectation Tests: Allow `tag[foo bar]` This is partly motivated by the MaD tests which looks much better now in my opinion. I also wanted this for testing argument passing. In Python we're adopting the same argument positions as Ruby has [here](https://github.com/github/codeql/blob/4f3751dfea06c84b97685301739f5303b9678a18/ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowDispatch.qll#L508-L540) So it would be nice if `arg[keyword foo]=...` was allowed, without having to transform the `toString()` result of an argument position into something without a space. --- .../TestUtilities/InlineExpectationsTest.qll | 14 ++++-- python/ql/test/experimental/meta/MaDTest.qll | 6 ++- .../library-tests/frameworks/asyncpg/test.py | 50 +++++++++---------- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/python/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/python/ql/test/experimental/meta/MaDTest.qll b/python/ql/test/experimental/meta/MaDTest.qll index 345fc973284..3d75ba0d2e7 100644 --- a/python/ql/test/experimental/meta/MaDTest.qll +++ b/python/ql/test/experimental/meta/MaDTest.qll @@ -11,7 +11,9 @@ class MadSinkTest extends InlineExpectationsTest { MadSinkTest() { this = "MadSinkTest" } override string getARelevantTag() { - exists(string kind | exists(ModelOutput::getASinkNode(kind)) | result = "mad-sink__" + kind) + exists(string kind | exists(ModelOutput::getASinkNode(kind)) | + result = "mad-sink[" + kind + "]" + ) } override predicate hasActualResult(Location location, string element, string tag, string value) { @@ -21,7 +23,7 @@ class MadSinkTest extends InlineExpectationsTest { location = sink.getLocation() and element = sink.toString() and value = prettyNodeForInlineTest(sink) and - tag = "mad-sink__" + kind + tag = "mad-sink[" + kind + "]" ) } } diff --git a/python/ql/test/library-tests/frameworks/asyncpg/test.py b/python/ql/test/library-tests/frameworks/asyncpg/test.py index e2e5e1c5826..ad99751ba3d 100644 --- a/python/ql/test/library-tests/frameworks/asyncpg/test.py +++ b/python/ql/test/library-tests/frameworks/asyncpg/test.py @@ -7,17 +7,17 @@ async def test_connection(): try: # The file-like object is passed in as a keyword-only argument. # See https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.connection.Connection.copy_from_query - await conn.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" - await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" + await conn.copy_from_query("sql", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath" + await conn.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath" - await conn.copy_from_table("table", output="filepath") # $ mad-sink__path-injection="filepath" - await conn.copy_to_table("table", source="filepath") # $ mad-sink__path-injection="filepath" + await conn.copy_from_table("table", output="filepath") # $ mad-sink[path-injection]="filepath" + await conn.copy_to_table("table", source="filepath") # $ mad-sink[path-injection]="filepath" - await conn.execute("sql") # $ mad-sink__sql-injection="sql" - await conn.executemany("sql") # $ mad-sink__sql-injection="sql" - await conn.fetch("sql") # $ mad-sink__sql-injection="sql" - await conn.fetchrow("sql") # $ mad-sink__sql-injection="sql" - await conn.fetchval("sql") # $ mad-sink__sql-injection="sql" + await conn.execute("sql") # $ mad-sink[sql-injection]="sql" + await conn.executemany("sql") # $ mad-sink[sql-injection]="sql" + await conn.fetch("sql") # $ mad-sink[sql-injection]="sql" + await conn.fetchrow("sql") # $ mad-sink[sql-injection]="sql" + await conn.fetchval("sql") # $ mad-sink[sql-injection]="sql" finally: await conn.close() @@ -27,7 +27,7 @@ async def test_prepared_statement(): conn = await asyncpg.connect() try: - pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql" + pstmt = await conn.prepare("psql") # $ mad-sink[sql-injection]="psql" pstmt.executemany() pstmt.fetch() pstmt.fetchrow() @@ -46,7 +46,7 @@ async def test_cursor(): cursor = await conn.cursor("sql") # $ getSql="sql" constructedSql="sql" await cursor.fetch() - pstmt = await conn.prepare("psql") # $ mad-sink__sql-injection="psql" + pstmt = await conn.prepare("psql") # $ mad-sink[sql-injection]="psql" pcursor = await pstmt.cursor() # $ getSql="psql" await pcursor.fetch() @@ -69,23 +69,23 @@ async def test_connection_pool(): pool = await asyncpg.create_pool() try: - await pool.copy_from_query("sql", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" - await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink__sql-injection="sql" mad-sink__path-injection="filepath" - await pool.copy_from_table("table", output="filepath") # $ mad-sink__path-injection="filepath" - await pool.copy_to_table("table", source="filepath") # $ mad-sink__path-injection="filepath" + await pool.copy_from_query("sql", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath" + await pool.copy_from_query("sql", "arg1", "arg2", output="filepath") # $ mad-sink[sql-injection]="sql" mad-sink[path-injection]="filepath" + await pool.copy_from_table("table", output="filepath") # $ mad-sink[path-injection]="filepath" + await pool.copy_to_table("table", source="filepath") # $ mad-sink[path-injection]="filepath" - await pool.execute("sql") # $ mad-sink__sql-injection="sql" - await pool.executemany("sql") # $ mad-sink__sql-injection="sql" - await pool.fetch("sql") # $ mad-sink__sql-injection="sql" - await pool.fetchrow("sql") # $ mad-sink__sql-injection="sql" - await pool.fetchval("sql") # $ mad-sink__sql-injection="sql" + await pool.execute("sql") # $ mad-sink[sql-injection]="sql" + await pool.executemany("sql") # $ mad-sink[sql-injection]="sql" + await pool.fetch("sql") # $ mad-sink[sql-injection]="sql" + await pool.fetchrow("sql") # $ mad-sink[sql-injection]="sql" + await pool.fetchval("sql") # $ mad-sink[sql-injection]="sql" async with pool.acquire() as conn: - await conn.execute("sql") # $ mad-sink__sql-injection="sql" + await conn.execute("sql") # $ mad-sink[sql-injection]="sql" conn = await pool.acquire() try: - await conn.fetch("sql") # $ mad-sink__sql-injection="sql" + await conn.fetch("sql") # $ mad-sink[sql-injection]="sql" finally: await pool.release(conn) @@ -93,13 +93,13 @@ async def test_connection_pool(): await pool.close() async with asyncpg.create_pool() as pool: - await pool.execute("sql") # $ mad-sink__sql-injection="sql" + await pool.execute("sql") # $ mad-sink[sql-injection]="sql" async with pool.acquire() as conn: - await conn.execute("sql") # $ mad-sink__sql-injection="sql" + await conn.execute("sql") # $ mad-sink[sql-injection]="sql" conn = await pool.acquire() try: - await conn.fetch("sql") # $ mad-sink__sql-injection="sql" + await conn.fetch("sql") # $ mad-sink[sql-injection]="sql" finally: await pool.release(conn) From 50196d099b13dad1b2c0100663281c9ae52997aa Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 2 Jun 2022 15:14:54 +0200 Subject: [PATCH 2/4] Inline Expectation Tests: sync --- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- .../test/TestUtilities/InlineExpectationsTest.qll | 14 +++++++++++--- 6 files changed, 66 insertions(+), 18 deletions(-) diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/go/ql/test/TestUtilities/InlineExpectationsTest.qll b/go/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/go/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/go/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/java/ql/test/TestUtilities/InlineExpectationsTest.qll b/java/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/java/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/java/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll index 3891fcf13a1..c0b5fea632c 100644 --- a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -239,12 +239,20 @@ private string getColumnString(TColumn column) { /** * RegEx pattern to match a single expected result, not including the leading `$`. It consists of one or - * more comma-separated tags containing only letters, digits, `-` and `_` (note that the first character - * must not be a digit), optionally followed by `=` and the expected value. + * more comma-separated tags optionally followed by `=` and the expected value. + * + * Tags must be only letters, digits, `-` and `_` (note that the first character + * must not be a digit), but can contain anything enclosed in a square brackets. + * + * Examples: + * - `tag` + * - `tag=value` + * - `tag,tag2=value` + * - `tag[foo bar]=value` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_][A-Za-z-_0-9]*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. From 5fb41e4894a58db3fcb3d1d5af8f2db50209afa5 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 17 Jun 2022 17:36:04 +0200 Subject: [PATCH 3/4] Inline Expectation Tests: Disallow `tag[[[foo bar]` --- python/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/python/ql/test/TestUtilities/InlineExpectationsTest.qll b/python/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/python/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/python/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. From b65a10d1ef447adbe8994646daa72512a1b52394 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 17 Jun 2022 17:38:19 +0200 Subject: [PATCH 4/4] Inline Expectation Tests: sync --- cpp/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- csharp/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- go/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- java/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- ql/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- ruby/ql/test/TestUtilities/InlineExpectationsTest.qll | 8 ++++++-- 6 files changed, 36 insertions(+), 12 deletions(-) diff --git a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/cpp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/csharp/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/go/ql/test/TestUtilities/InlineExpectationsTest.qll b/go/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/go/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/go/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/java/ql/test/TestUtilities/InlineExpectationsTest.qll b/java/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/java/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/java/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/ql/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ql/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`. diff --git a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll index c0b5fea632c..4b4a31d6950 100644 --- a/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll +++ b/ruby/ql/test/TestUtilities/InlineExpectationsTest.qll @@ -242,17 +242,21 @@ private string getColumnString(TColumn column) { * more comma-separated tags optionally followed by `=` and the expected value. * * Tags must be only letters, digits, `-` and `_` (note that the first character - * must not be a digit), but can contain anything enclosed in a square brackets. + * must not be a digit), but can contain anything enclosed in a single set of + * square brackets. * * Examples: * - `tag` * - `tag=value` * - `tag,tag2=value` * - `tag[foo bar]=value` + * + * Not allowed: + * - `tag[[[foo bar]` */ private string expectationPattern() { exists(string tag, string tags, string value | - tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]]*\\])*" and + tag = "[A-Za-z-_](?:[A-Za-z-_0-9]|\\[[^\\]\\]]*\\])*" and tags = "((?:" + tag + ")(?:\\s*,\\s*" + tag + ")*)" and // In Python, we allow both `"` and `'` for strings, as well as the prefixes `bru`. // For example, `b"foo"`.