Skip to content

Conversation

@sshmulev
Copy link
Collaborator

@sshmulev sshmulev commented Oct 16, 2025

Fixed according to bug requierments: CLOUDX-1266
Updated docstring with detailed steps

Summary by Sourcery

Enhance the check_avc_denials test helper to enforce SELinux and auditd preconditions, perform a synchronous AVC search, and filter out known benign denials or permissive AVCs before asserting failures.

Enhancements:

  • Enforce that SELinux is in permissive mode and auditd is active before scanning AVC logs
  • Use a synchronous ausearch since boot and filter out benign AVC sources and permissive entries
  • Allow targeted AVC checks when relevant_keywords are specified

Documentation:

  • Add detailed docstring outlining preconditions, ignored services, and keyword-driven checks

Tests:

  • Refine the test helper logic for AVC denial verification in the test suite

Fixed according to bug requierments: CLOUDX-1266
Updated docstring with detailed steps
@sourcery-ai
Copy link

sourcery-ai bot commented Oct 16, 2025

Reviewer's Guide

This PR overhauls the check_avc_denials helper by introducing detailed documentation, enforcing precondition checks (SELinux in permissive, auditd running), executing a synchronous ausearch under sudo, filtering out known benign AVCs and permissive denials, and consolidating assertion logic to report only relevant AVC issues.

File-Level Changes

Change Details Files
Add comprehensive docstring to explain preconditions, ignored contexts, and usage
  • Document SELinux and auditd preconditions
  • List services and contexts to ignore
  • Clarify relevant_keywords behavior
test_suite/generic/helpers.py
Refactor AVC denial detection with structured host.run calls and filtering
  • Execute commands under sudo and assert SELinux/auditd status
  • Perform ausearch since boot and capture output
  • Filter out ignored services/contexts and permissive AVCs
  • Assert failures only for relevant or unexpected AVCs
test_suite/generic/helpers.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes and they look great!

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `test_suite/generic/helpers.py:30` </location>
<code_context>
+    If relevant_keywords is provided(cloudx services), only AVCs matching those keywords cause failure.
+    """
+
+    with host.sudo():
+        # Check SELinux mode
+        selinux_mode = host.run("getenforce").stdout.strip().lower()
</code_context>

<issue_to_address>
**suggestion (testing):** No direct test coverage for the updated helper function.

Please add or update tests to cover the new logic, including SELinux mode checks, auditd status, ignored AVCs, keyword-based failures, and unexpected AVC denials.

Suggested implementation:

```python
import pytest
from unittest.mock import MagicMock

from test_suite.generic import helpers

@pytest.fixture
def mock_host():
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = host
    return host

def test_selinux_mode_enforcing(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Enforcing"),  # getenforce
        MagicMock(stdout="active"),     # systemctl is-active auditd
        MagicMock(stdout="")            # ausearch
    ]
    with pytest.raises(AssertionError, match="SELinux is not in permissive mode"):
        helpers.your_helper_function(mock_host)

def test_auditd_not_running(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"), # getenforce
        MagicMock(stdout="inactive"),   # systemctl is-active auditd
        MagicMock(stdout="")            # ausearch
    ]
    with pytest.raises(AssertionError, match="auditd is not running"):
        helpers.your_helper_function(mock_host)

def test_ignore_known_avcs(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { read } for pid=123 comm=\"irqbalance\"")
    ]
    # Should not raise, known AVC is ignored
    helpers.your_helper_function(mock_host)

def test_keyword_based_failure(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { read } for pid=123 comm=\"cloudx\"")
    ]
    relevant_keywords = ["cloudx"]
    with pytest.raises(AssertionError, match="AVC denial found for relevant keyword"):
        helpers.your_helper_function(mock_host, relevant_keywords=relevant_keywords)

def test_unexpected_avc_denial(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { write } for pid=123 comm=\"unexpected\"")
    ]
    with pytest.raises(AssertionError, match="Unexpected AVC denial found"):
        helpers.your_helper_function(mock_host)

```

- Replace `your_helper_function` with the actual name of the helper function being tested.
- If the helper function signature differs (e.g., does not accept `relevant_keywords`), adjust the test calls accordingly.
- If the helper function is in a different module or location, update the import statement.
- If you already have a test file, add these tests to it instead of creating a new one.
- You may need to adjust the assertion error messages to match the actual ones raised in your code.
</issue_to_address>

### Comment 2
<location> `test_suite/generic/helpers.py:32-33` </location>
<code_context>
+
+    with host.sudo():
+        # Check SELinux mode
+        selinux_mode = host.run("getenforce").stdout.strip().lower()
+        assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"
+
+        # Check auditd status
</code_context>

<issue_to_address>
**suggestion (testing):** Edge case: SELinux mode assertion could benefit from a dedicated test.

Add a test that verifies the assertion fails when SELinux is set to enforcing or disabled mode.

Suggested implementation:

```python
    with host.sudo():
        # Check SELinux mode
        selinux_mode = host.run("getenforce").stdout.strip().lower()
        assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

        # Check auditd status
        auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()

```

```python
        if "no matches" in output or not output.strip():
            return

# --- TESTS ---

import pytest
from unittest.mock import MagicMock

def test_selinux_mode_assertion_permissive():
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = None
    host.run.side_effect = lambda cmd: MagicMock(stdout="permissive\n")
    # Should not raise
    try:
        with host.sudo():
            selinux_mode = host.run("getenforce").stdout.strip().lower()
            assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"
    except AssertionError:
        pytest.fail("AssertionError raised unexpectedly for permissive mode")

@pytest.mark.parametrize("mode", ["enforcing", "disabled"])
def test_selinux_mode_assertion_non_permissive(mode):
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = None
    host.run.side_effect = lambda cmd: MagicMock(stdout=f"{mode}\n")
    with pytest.raises(AssertionError, match=f"SELinux is not in permissive mode: {mode}"):
        with host.sudo():
            selinux_mode = host.run("getenforce").stdout.strip().lower()
            assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

```
</issue_to_address>

### Comment 3
<location> `test_suite/generic/helpers.py:36-37` </location>
<code_context>
+        assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"
+
+        # Check auditd status
+        auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()
+        assert auditd_status == "active", "auditd is not running; cannot check AVC denials"
+
+        # Run ausearch synchronously to get AVCs since boot
</code_context>

<issue_to_address>
**suggestion (testing):** Missing test for auditd not running scenario.

Add a test that verifies the assertion and error message when auditd is not running.
</issue_to_address>

### Comment 4
<location> `test_suite/generic/helpers.py:48-54` </location>
<code_context>
+            return
+
+        # Filter out lines containing ignored services/contexts and permissive AVCs
+        ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
+        filtered_lines = [
+            line for line in output.splitlines()
+            if "permissive=1" not in line
</code_context>

<issue_to_address>
**suggestion (testing):** No test for ignored AVCs filtering logic.

Add a test to confirm that AVCs with these keywords are correctly ignored and do not affect test outcomes.

```suggestion
        ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
        filtered_lines = [
            line for line in output.splitlines()
            if "permissive=1" not in line
               and all(ignored not in line for ignored in ignored_avcs)
        ]
        filtered_output = "\n".join(filtered_lines).strip()


def _test_avc_filtering():
    """
    Test that AVCs with ignored keywords or permissive=1 are filtered out.
    """
    ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
    sample_output = (
        "type=AVC msg=audit(123): avc:  denied  { read } for  pid=1 comm=\"irqbalance\"\n"
        "type=AVC msg=audit(124): avc:  denied  { write } for  pid=2 comm=\"myservice\"\n"
        "type=AVC msg=audit(125): avc:  denied  { read } for  pid=3 comm=\"insights_client_t\"\n"
        "type=AVC msg=audit(126): avc:  denied  { write } for  pid=4 comm=\"subscription-ma\"\n"
        "type=AVC msg=audit(127): avc:  denied  { write } for  pid=5 comm=\"myservice\" permissive=1\n"
        "type=AVC msg=audit(128): avc:  denied  { write } for  pid=6 comm=\"myservice\"\n"
    )
    expected_lines = [
        "type=AVC msg=audit(124): avc:  denied  { write } for  pid=2 comm=\"myservice\"",
        "type=AVC msg=audit(128): avc:  denied  { write } for  pid=6 comm=\"myservice\"",
    ]
    filtered_lines = [
        line for line in sample_output.splitlines()
        if "permissive=1" not in line
           and all(ignored not in line for ignored in ignored_avcs)
    ]
    assert filtered_lines == expected_lines, f"Filtered lines did not match expected: {filtered_lines}"

```
</issue_to_address>

### Comment 5
<location> `test_suite/generic/helpers.py:29-38` </location>
<code_context>
+        filtered_output = "\n".join(filtered_lines).strip()
+
+        # If relevant keywords are provided, check for them
+        if relevant_keywords:
+            for kw in relevant_keywords:
+                if kw.lower() in filtered_output:
+                    assert False, f"AVC denial related to '{kw}' found:\n{filtered_output}"
+
</code_context>

<issue_to_address>
**suggestion (testing):** Relevant keywords logic should be covered by tests.

Add tests that supply different relevant_keywords and confirm that assertion failures occur only for matching AVC denials, not for unrelated ones.

Suggested implementation:

```python
import pytest

def check_avc_denials(host, relevant_keywords=None):

```

```python
def check_avc_denials(host, relevant_keywords=None):
    # ... existing implementation ...

# ------------------ TESTS FOR RELEVANT KEYWORDS LOGIC ------------------

@pytest.mark.parametrize(
    "filtered_lines,relevant_keywords,should_raise,expected_keyword",
    [
        # No relevant keywords, should not raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], None, False, None),
        # Relevant keyword present, should raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], ["cat"], True, "cat"),
        # Relevant keyword absent, should not raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], ["dog"], False, None),
        # Multiple keywords, one matches
        (["AVC: denied { write } for pid=5678 comm=\"echo\""], ["echo", "cat"], True, "echo"),
        # Multiple keywords, none match
        (["AVC: denied { write } for pid=5678 comm=\"echo\""], ["cat", "dog"], False, None),
        # Keyword matches case-insensitively
        (["AVC: denied { write } for pid=5678 comm=\"Echo\""], ["echo"], True, "echo"),
    ]
)
def test_check_avc_denials_relevant_keywords(monkeypatch, filtered_lines, relevant_keywords, should_raise, expected_keyword):
    # Patch the part of check_avc_denials that gets filtered_lines
    def fake_check_avc_denials(host, relevant_keywords=None):
        filtered_output = "\n".join(filtered_lines).strip()
        if relevant_keywords:
            for kw in relevant_keywords:
                if kw.lower() in filtered_output.lower():
                    assert False, f"AVC denial related to '{kw}' found:\n{filtered_output}"

    if should_raise:
        with pytest.raises(AssertionError) as excinfo:
            fake_check_avc_denials("dummy_host", relevant_keywords)
        assert expected_keyword in str(excinfo.value)
    else:
        # Should not raise
        fake_check_avc_denials("dummy_host", relevant_keywords)

```
</issue_to_address>

### Comment 6
<location> `test_suite/generic/helpers.py:62-65` </location>
<code_context>
def check_avc_denials(host, relevant_keywords=None):
    """
    Check for SELinux AVC denials.

    Preconditions:
      - SELinux must be in permissive mode
      - auditd must be running

    Known AVCs from irqbalance, insights-client, and subscription-manager are ignored.
    AVCs in permissive mode are ignored.

    If relevant_keywords is provided(cloudx services), only AVCs matching those keywords cause failure.
    """

    with host.sudo():
        # Check SELinux mode
        selinux_mode = host.run("getenforce").stdout.strip().lower()
        assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

        # Check auditd status
        auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()
        assert auditd_status == "active", "auditd is not running; cannot check AVC denials"

        # Run ausearch synchronously to get AVCs since boot
        result = host.run("ausearch -m avc -ts boot 2>&1")
        output = result.stdout.lower()

        # If no AVCs are found, nothing to do (test passes)
        if "no matches" in output or not output.strip():
            return

        # Filter out lines containing ignored services/contexts and permissive AVCs
        ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
        filtered_lines = [
            line for line in output.splitlines()
            if "permissive=1" not in line
               and all(ignored not in line for ignored in ignored_avcs)
        ]
        filtered_output = "\n".join(filtered_lines).strip()

        # If relevant keywords are provided, check for them
        if relevant_keywords:
            for kw in relevant_keywords:
                if kw.lower() in filtered_output:
                    assert False, f"AVC denial related to '{kw}' found:\n{filtered_output}"

        else:
            # If any AVCs remain after filtering, fail
            if filtered_output:
                assert False, f"Unexpected AVC denials found:\n{filtered_output}"

</code_context>

<issue_to_address>
**suggestion (code-quality):** Merge else clause's nested if statement into elif ([`merge-else-if-into-elif`](https://docs.sourcery.ai/Reference/Default-Rules/refactorings/merge-else-if-into-elif/))

```suggestion
        elif filtered_output:
            assert False, f"Unexpected AVC denials found:\n{filtered_output}"
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

If relevant_keywords is provided(cloudx services), only AVCs matching those keywords cause failure.
"""

with host.sudo():
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): No direct test coverage for the updated helper function.

Please add or update tests to cover the new logic, including SELinux mode checks, auditd status, ignored AVCs, keyword-based failures, and unexpected AVC denials.

Suggested implementation:

import pytest
from unittest.mock import MagicMock

from test_suite.generic import helpers

@pytest.fixture
def mock_host():
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = host
    return host

def test_selinux_mode_enforcing(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Enforcing"),  # getenforce
        MagicMock(stdout="active"),     # systemctl is-active auditd
        MagicMock(stdout="")            # ausearch
    ]
    with pytest.raises(AssertionError, match="SELinux is not in permissive mode"):
        helpers.your_helper_function(mock_host)

def test_auditd_not_running(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"), # getenforce
        MagicMock(stdout="inactive"),   # systemctl is-active auditd
        MagicMock(stdout="")            # ausearch
    ]
    with pytest.raises(AssertionError, match="auditd is not running"):
        helpers.your_helper_function(mock_host)

def test_ignore_known_avcs(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { read } for pid=123 comm=\"irqbalance\"")
    ]
    # Should not raise, known AVC is ignored
    helpers.your_helper_function(mock_host)

def test_keyword_based_failure(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { read } for pid=123 comm=\"cloudx\"")
    ]
    relevant_keywords = ["cloudx"]
    with pytest.raises(AssertionError, match="AVC denial found for relevant keyword"):
        helpers.your_helper_function(mock_host, relevant_keywords=relevant_keywords)

def test_unexpected_avc_denial(mock_host):
    mock_host.run.side_effect = [
        MagicMock(stdout="Permissive"),
        MagicMock(stdout="active"),
        MagicMock(stdout="type=AVC msg=audit(123): avc: denied { write } for pid=123 comm=\"unexpected\"")
    ]
    with pytest.raises(AssertionError, match="Unexpected AVC denial found"):
        helpers.your_helper_function(mock_host)
  • Replace your_helper_function with the actual name of the helper function being tested.
  • If the helper function signature differs (e.g., does not accept relevant_keywords), adjust the test calls accordingly.
  • If the helper function is in a different module or location, update the import statement.
  • If you already have a test file, add these tests to it instead of creating a new one.
  • You may need to adjust the assertion error messages to match the actual ones raised in your code.

Comment on lines +32 to +33
selinux_mode = host.run("getenforce").stdout.strip().lower()
assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Edge case: SELinux mode assertion could benefit from a dedicated test.

Add a test that verifies the assertion fails when SELinux is set to enforcing or disabled mode.

Suggested implementation:

    with host.sudo():
        # Check SELinux mode
        selinux_mode = host.run("getenforce").stdout.strip().lower()
        assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

        # Check auditd status
        auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()
        if "no matches" in output or not output.strip():
            return

# --- TESTS ---

import pytest
from unittest.mock import MagicMock

def test_selinux_mode_assertion_permissive():
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = None
    host.run.side_effect = lambda cmd: MagicMock(stdout="permissive\n")
    # Should not raise
    try:
        with host.sudo():
            selinux_mode = host.run("getenforce").stdout.strip().lower()
            assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"
    except AssertionError:
        pytest.fail("AssertionError raised unexpectedly for permissive mode")

@pytest.mark.parametrize("mode", ["enforcing", "disabled"])
def test_selinux_mode_assertion_non_permissive(mode):
    host = MagicMock()
    host.sudo.return_value.__enter__.return_value = None
    host.run.side_effect = lambda cmd: MagicMock(stdout=f"{mode}\n")
    with pytest.raises(AssertionError, match=f"SELinux is not in permissive mode: {mode}"):
        with host.sudo():
            selinux_mode = host.run("getenforce").stdout.strip().lower()
            assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

Comment on lines +36 to +37
auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()
assert auditd_status == "active", "auditd is not running; cannot check AVC denials"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Missing test for auditd not running scenario.

Add a test that verifies the assertion and error message when auditd is not running.

Comment on lines +48 to +54
ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
filtered_lines = [
line for line in output.splitlines()
if "permissive=1" not in line
and all(ignored not in line for ignored in ignored_avcs)
]
filtered_output = "\n".join(filtered_lines).strip()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): No test for ignored AVCs filtering logic.

Add a test to confirm that AVCs with these keywords are correctly ignored and do not affect test outcomes.

Suggested change
ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
filtered_lines = [
line for line in output.splitlines()
if "permissive=1" not in line
and all(ignored not in line for ignored in ignored_avcs)
]
filtered_output = "\n".join(filtered_lines).strip()
ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
filtered_lines = [
line for line in output.splitlines()
if "permissive=1" not in line
and all(ignored not in line for ignored in ignored_avcs)
]
filtered_output = "\n".join(filtered_lines).strip()
def _test_avc_filtering():
"""
Test that AVCs with ignored keywords or permissive=1 are filtered out.
"""
ignored_avcs = ["irqbalance", "insights_client_t", "subscription-ma"]
sample_output = (
"type=AVC msg=audit(123): avc: denied { read } for pid=1 comm=\"irqbalance\"\n"
"type=AVC msg=audit(124): avc: denied { write } for pid=2 comm=\"myservice\"\n"
"type=AVC msg=audit(125): avc: denied { read } for pid=3 comm=\"insights_client_t\"\n"
"type=AVC msg=audit(126): avc: denied { write } for pid=4 comm=\"subscription-ma\"\n"
"type=AVC msg=audit(127): avc: denied { write } for pid=5 comm=\"myservice\" permissive=1\n"
"type=AVC msg=audit(128): avc: denied { write } for pid=6 comm=\"myservice\"\n"
)
expected_lines = [
"type=AVC msg=audit(124): avc: denied { write } for pid=2 comm=\"myservice\"",
"type=AVC msg=audit(128): avc: denied { write } for pid=6 comm=\"myservice\"",
]
filtered_lines = [
line for line in sample_output.splitlines()
if "permissive=1" not in line
and all(ignored not in line for ignored in ignored_avcs)
]
assert filtered_lines == expected_lines, f"Filtered lines did not match expected: {filtered_lines}"

Comment on lines +29 to +38

with host.sudo():
# Check SELinux mode
selinux_mode = host.run("getenforce").stdout.strip().lower()
assert selinux_mode == "permissive", f"SELinux is not in permissive mode: {selinux_mode}"

# Check auditd status
auditd_status = host.run("systemctl is-active auditd").stdout.strip().lower()
assert auditd_status == "active", "auditd is not running; cannot check AVC denials"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Relevant keywords logic should be covered by tests.

Add tests that supply different relevant_keywords and confirm that assertion failures occur only for matching AVC denials, not for unrelated ones.

Suggested implementation:

import pytest

def check_avc_denials(host, relevant_keywords=None):
def check_avc_denials(host, relevant_keywords=None):
    # ... existing implementation ...

# ------------------ TESTS FOR RELEVANT KEYWORDS LOGIC ------------------

@pytest.mark.parametrize(
    "filtered_lines,relevant_keywords,should_raise,expected_keyword",
    [
        # No relevant keywords, should not raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], None, False, None),
        # Relevant keyword present, should raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], ["cat"], True, "cat"),
        # Relevant keyword absent, should not raise
        (["AVC: denied { read } for pid=1234 comm=\"cat\""], ["dog"], False, None),
        # Multiple keywords, one matches
        (["AVC: denied { write } for pid=5678 comm=\"echo\""], ["echo", "cat"], True, "echo"),
        # Multiple keywords, none match
        (["AVC: denied { write } for pid=5678 comm=\"echo\""], ["cat", "dog"], False, None),
        # Keyword matches case-insensitively
        (["AVC: denied { write } for pid=5678 comm=\"Echo\""], ["echo"], True, "echo"),
    ]
)
def test_check_avc_denials_relevant_keywords(monkeypatch, filtered_lines, relevant_keywords, should_raise, expected_keyword):
    # Patch the part of check_avc_denials that gets filtered_lines
    def fake_check_avc_denials(host, relevant_keywords=None):
        filtered_output = "\n".join(filtered_lines).strip()
        if relevant_keywords:
            for kw in relevant_keywords:
                if kw.lower() in filtered_output.lower():
                    assert False, f"AVC denial related to '{kw}' found:\n{filtered_output}"

    if should_raise:
        with pytest.raises(AssertionError) as excinfo:
            fake_check_avc_denials("dummy_host", relevant_keywords)
        assert expected_keyword in str(excinfo.value)
    else:
        # Should not raise
        fake_check_avc_denials("dummy_host", relevant_keywords)

Comment on lines +62 to +65
else:
# If any AVCs remain after filtering, fail
if filtered_output:
assert False, f"Unexpected AVC denials found:\n{filtered_output}"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Merge else clause's nested if statement into elif (merge-else-if-into-elif)

Suggested change
else:
# If any AVCs remain after filtering, fail
if filtered_output:
assert False, f"Unexpected AVC denials found:\n{filtered_output}"
elif filtered_output:
assert False, f"Unexpected AVC denials found:\n{filtered_output}"

@sshmulev sshmulev requested a review from alexxa October 16, 2025 09:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant