diff --git a/tests/test_api_v10.py b/tests/test_api_v10.py
index f08db8b9..99c0008b 100644
--- a/tests/test_api_v10.py
+++ b/tests/test_api_v10.py
@@ -886,7 +886,7 @@ def test_permissions_endpoint(client):
"maintainers": ["alice@example.com"],
"_testcase_regex_pattern": "^kernel-qe",
"groups": ["devel", "qa"],
- "users": ["alice@example.com"],
+ "users": ["alice"],
},
{
"name": "Greenwave Tests",
@@ -928,6 +928,33 @@ def test_permissions_endpoint(client):
assert f"
{config['PERMISSIONS'][1]['name']} | " in r.text
+def test_permissions_endpoint_include_following(client):
+ config = {
+ 'PERMISSIONS': [
+ {
+ "name": "Security",
+ "testcases": ["security.*"],
+ "groups": ["security"],
+ },
+ {
+ "name": "Development",
+ "testcases": ["*"],
+ "groups": ["devel"],
+ "testcases_ignore": ["security.*"],
+ }
+ ]
+ }
+
+ with patch.dict(client.application.config, config):
+ r = client.get('/api/v1.0/permissions?testcase=security.test1')
+ assert r.status_code == 200, r.text
+ assert r.json == config['PERMISSIONS'][0:1]
+
+ r = client.get('/api/v1.0/permissions?testcase=security-not.test1')
+ assert r.status_code == 200, r.text
+ assert r.json == config['PERMISSIONS'][1:]
+
+
def test_config_endpoint_superusers(client):
config = {
'SUPERUSERS': ['alice', 'bob']
diff --git a/waiverdb/api_v1.py b/waiverdb/api_v1.py
index e4880984..f1b2ef5f 100644
--- a/waiverdb/api_v1.py
+++ b/waiverdb/api_v1.py
@@ -681,6 +681,18 @@ def get(self):
"""
Returns the waiver permissions.
+ Each entry has "testcases" (list of glob patterns for matching test
+ case name) and "users" or "groups".
+
+ Optional "testcases_ignore" (similar to "testcases") allows to ignore a
+ permission entry on a matching test case name.
+
+ The full list of users and groups permitted to waive given test case is
+ constructed by iterating the permissions in order and adding "users"
+ and "groups" from each permission entry which has at least one pattern
+ in "testcases" matching the test case name and no matching pattern in
+ "testcases_ignore".
+
**Sample response**:
.. sourcecode:: none
@@ -696,8 +708,9 @@ def get(self):
"name": "kernel-qe",
"maintainers": ["alice@example.com"],
"testcases": ["kernel-qe.*"],
+ "testcases_ignore": ["kernel-qe.unwaivable.*"],
"groups": ["devel", "qa"],
- "users": ["alice@example.com"]
+ "users": ["alice@example.com"],
},
{
"name": "Greenwave Tests",
diff --git a/waiverdb/authorization.py b/waiverdb/authorization.py
index 3b58595b..061c9b09 100644
--- a/waiverdb/authorization.py
+++ b/waiverdb/authorization.py
@@ -32,13 +32,17 @@ def get_group_membership(ldap, user, con, ldap_search):
raise Unauthorized('Some error occurred initializing the LDAP connection.')
+def match_testcase(testcase: str, patterns: dict[str, Any]):
+ return any(fnmatch(testcase, pattern) for pattern in patterns)
+
+
def match_testcase_permissions(testcase: str, permissions: list[dict[str, Any]]):
for permission in permissions:
+ if match_testcase(testcase, permission.get("testcases_ignore", [])):
+ continue
+
if "testcases" in permission:
- testcase_match = any(
- fnmatch(testcase, testcase_pattern)
- for testcase_pattern in permission["testcases"]
- )
+ testcase_match = match_testcase(testcase, permission["testcases"])
elif "_testcase_regex_pattern" in permission:
testcase_match = re.search(
permission["_testcase_regex_pattern"], testcase)
diff --git a/waiverdb/templates/layout.html b/waiverdb/templates/layout.html
index f7f3485b..8a5f7039 100644
--- a/waiverdb/templates/layout.html
+++ b/waiverdb/templates/layout.html
@@ -19,6 +19,10 @@
{% block scripts %}
{% endblock %}
+
+
diff --git a/waiverdb/templates/permissions.html b/waiverdb/templates/permissions.html
index 07e99607..62ddcab1 100644
--- a/waiverdb/templates/permissions.html
+++ b/waiverdb/templates/permissions.html
@@ -21,19 +21,23 @@
{% for p in permissions -%}
{{ p["name"] }} |
- {{ p["maintainers"] | map("urlize") | join(" ") | safe }} |
- {{ p["testcases"] | join(" ") | replace('-', '‑') | safe }} |
+
+ {%- for maintainer in p["maintainers"] %}- {{ maintainer | urlize }}
{% endfor -%}
+ |
+
+ {%- if p["_testcase_regex_pattern"] -%}/{{ p["_testcase_regex_pattern"] }}/ {%- endif -%}
+ {%- for testcase in p["testcases_ignore"] %}- NOT
{{ testcase }} {% endfor -%}
+ {%- for testcase in p["testcases"] %}{{ testcase }} {% endfor -%}
+ |
{% if p["groups"] | length > 0 -%}
- Groups:
- {{ p["groups"] | join(" ") | replace('-', '‑') | safe }}
- {% if p["users"] | length > 0 -%}
-
- {%- endif %}
+ Groups:
+ {%- for group in p["groups"] %}- {{ group }}
{% endfor -%}
{%- endif %}
+
{% if p["users"] | length > 0 -%}
- Users:
- {{ p["users"] | join(" ") | replace('-', '‑') | safe }}
+ Users:
+ {%- for user in p["users"] %}- {{ user }}
{% endfor -%}
{%- endif %}
|