Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ jobs:
vm:
- fedora-coreos
- fcarm
- rhel
- rhel-arm64
- rhcos

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -80,11 +83,25 @@ jobs:
quay:
username: ${{ secrets.QUAY_RHACS_ENG_RO_USERNAME }}
password: ${{ secrets.QUAY_RHACS_ENG_RO_PASSWORD }}
excluded_vms:
# RHEL 8 doesn't handle file creation properly,
# need more investigation
- rhel-8
- rhcos-412-86-202402272018-0-gcp-x86-64
- rhcos-414-92-202407091253-0-gcp-x86-64
# BPF trampolines are only implemented starting with RHEL 10
- rhel-9-arm64
EOF

- name: Create Test VMs
env:
ANSIBLE_CONFIG: "${{ github.workspace }}/collector/ansible/ansible.cfg"
run: |
make -C "./collector/ansible" create-ci-vms
ansible-playbook \
-i "${GITHUB_WORKSPACE}/collector/ansible/ci" \
-e @vars.yml \
--tags setup,provision \
"${GITHUB_WORKSPACE}/collector/ansible/integration-tests.yml"

- name: Run the tests
env:
Expand All @@ -104,10 +121,10 @@ jobs:
if: always()
run: |
cd "${GITHUB_WORKSPACE}/fact/tests"
if [[ -f "logs.tar.gz" ]]; then
tar xzf "logs.tar.gz"
rm -f "logs.tar.gz"
fi
for file in logs/*.tar.gz; do
tar xzf "$file"
rm -f "$file"
done

- name: Test summary
uses: test-summary/action@v2
Expand Down
1 change: 1 addition & 0 deletions ansible/group_vars/all.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
---
runtime_command: docker
runtime_host: 'unix:///var/run/docker.sock'
1 change: 1 addition & 0 deletions ansible/group_vars/platform_rhcos.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
---
ansible_user: core
runtime_host: "unix:///run/podman/podman.sock"
1 change: 1 addition & 0 deletions ansible/group_vars/platform_rhcos_arm64.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
---
ansible_user: core
runtime_host: "unix:///run/podman/podman.sock"
2 changes: 2 additions & 0 deletions ansible/group_vars/platform_rhel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
runtime_host: "unix:///run/podman/podman.sock"
2 changes: 2 additions & 0 deletions ansible/group_vars/platform_rhel_arm64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
runtime_host: "unix:///run/podman/podman.sock"
93 changes: 62 additions & 31 deletions ansible/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,88 @@
FACT_IMAGE_NAME: "{{ fact.image | default(None) }}"

tasks:
- name: Install dependencies
become: true
community.general.rpm_ostree_pkg:
apply_live: true
name:
- make
- python3-packaging
- python3-requests
state: present

- name: Login to quay.io
community.docker.docker_login:
registry_url: quay.io
username: "{{ quay.username }}"
password: "{{ quay.password }}"

- name: Clone the repo
ansible.builtin.git:
repo: https://github.com/stackrox/fact
dest: ./fact
dest: /tmp/fact
version: "{{ fact.version }}"
update: false

- name: Install python packages
ansible.builtin.pip:
requirements: ./fact/tests/requirements.txt
chdir: "{{ ansible_env.HOME }}"
virtualenv: ./fact/.venv
virtualenv_command: python3 -m venv
- name: Log into quay.io
become: "{{ runtime_command == 'podman' }}"
shell:
cmd: "{{ runtime_command }} login -u {{ quay.username }} --password-stdin quay.io"
stdin: "{{ quay.password }}"

- name: Copy podman auth
become: true
shell:
cmd: |
mkdir -p ~/.docker/
if [[ -f "${XDG_RUNTIME_DIR:-}/containers/auth.json" ]]; then
AUTH_FILE="${XDG_RUNTIME_DIR:-}/containers/auth.json"
elif [[ -f "/run/containers/0/auth.json" ]]; then
AUTH_FILE="/run/containers/0/auth.json"
else
echo &>2 "No valid auth.json file found"
exit 1
fi
cp "${AUTH_FILE}" ~/.docker/config.json
creates: ~/.docker/config.json
when: runtime_command == "podman"

- block:
# There are some ansible modules that we could use to modularize
# this next task, however they required some Python modules to be
# installed on the managed VM that may not be available (like
# python3-packaging), so we stick to a shell as ugly as it is.
- name: Run tests
become: true
environment:
DOCKER_HOST: "{{ runtime_host }}"
ansible.builtin.shell:
cmd: |
cd "${HOME}/fact"
source ".venv/bin/activate"
make integration-tests
set -euo pipefail
cd "/tmp/fact/tests"

# Setup the virtual environment
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

# Generate gRPC files
python3 -m grpc_tools.protoc \
-I../third_party/stackrox/proto \
--python_out=. \
--pyi_out=. \
--grpc_python_out=. \
../third_party/stackrox/proto/internalapi/sensor/collector.proto \
../third_party/stackrox/proto/internalapi/sensor/sfa.proto \
../third_party/stackrox/proto/internalapi/sensor/sfa_iservice.proto

# Run the tests
pytest --image="${FACT_IMAGE_NAME}" --junit-xml=results.xml

always:
- name: Make logs directories
file:
state: directory
path: "../tests/logs"
delegate_to: localhost

- name: Retrieve results
ansible.builtin.fetch:
src: "{{ ansible_env.HOME }}/fact/tests/results.xml"
src: "/tmp/fact/tests/results.xml"
dest: ../tests/
flat: true

- name: Compress log files
community.general.archive:
path: "{{ ansible_env.HOME }}/fact/tests/logs"
dest: "{{ ansible_env.HOME }}/fact/tests/logs.tar.gz"
path: "/tmp/fact/tests/logs"
dest: "/tmp/fact/tests/{{ vm_config }}.tar.gz"

- name: Fetch log files
ansible.builtin.fetch:
src: "{{ ansible_env.HOME }}/fact/tests/logs.tar.gz"
dest: ../tests/logs.tar.gz
src: "/tmp/fact/tests/logs.tar.gz"
dest: ../tests/logs
flat: true
12 changes: 11 additions & 1 deletion tests/event.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
from __future__ import annotations

import os
import string
from enum import Enum
from re import Pattern
from typing import Any, override
from typing import Any

try:
from typing import override # type: ignore[reportAssignmentType]
except ImportError:

def override(func): # type: ignore[reportMissingParameterType]
return func


import utils
from internalapi.sensor.collector_pb2 import ProcessSignal
Expand Down
5 changes: 3 additions & 2 deletions tests/test_config_hotreload.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations

import os
from concurrent.futures import TimeoutError as FuturesTimeoutError
from time import sleep

import docker.models.containers
Expand Down Expand Up @@ -219,7 +220,7 @@ def test_no_paths_then_add(

e = Event(process=p, event_type=EventType.OPEN, file=fut, host_path=fut)

with pytest.raises(TimeoutError):
with pytest.raises((TimeoutError, FuturesTimeoutError)):
server.wait_events([e])

# Add paths back
Expand Down Expand Up @@ -264,7 +265,7 @@ def test_paths_then_remove(
f.write('This should be ignored')
sleep(1)

with pytest.raises(TimeoutError):
with pytest.raises((TimeoutError, FuturesTimeoutError)):
server.wait_events([e])


Expand Down
56 changes: 39 additions & 17 deletions tests/test_path_rename.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,28 +451,39 @@ def test_cross_mountpoints(
container_id=test_container.id[:12],
)

server.wait_events(
[
Event(
process=touch,
event_type=EventType.OPEN,
file=mounted_file,
host_path=host_path,
),
Event(
process=first_rename,
event_type=EventType.CREATION,
file=ovfs_file,
host_path='',
),
events = [
Event(
process=touch,
event_type=EventType.OPEN,
file=mounted_file,
host_path=host_path,
),
Event(
process=first_rename,
event_type=EventType.CREATION,
file=ovfs_file,
host_path='',
),
]

# If the id for the current process and the process in the container (root)
# match, the ownership events are skipped
curr_id = (os.getuid(), os.getgid())
root_id = (0, 0)
if curr_id != root_id:
events.append(
Event(
process=first_rename,
event_type=EventType.OWNERSHIP,
file=ovfs_file,
host_path='',
owner_uid=owner_uid,
owner_gid=owner_gid,
),
)
)

events.extend(
[
Event(
process=first_rename,
event_type=EventType.PERMISSION,
Expand All @@ -492,14 +503,23 @@ def test_cross_mountpoints(
file=mounted_file,
host_path=host_path,
),
]
)

if curr_id != root_id:
events.append(
Event(
process=second_rename,
event_type=EventType.OWNERSHIP,
file=mounted_file,
host_path=host_path,
owner_uid=owner_uid,
owner_gid=owner_gid,
),
)
)

events.extend(
[
Event(
process=second_rename,
event_type=EventType.PERMISSION,
Expand All @@ -513,5 +533,7 @@ def test_cross_mountpoints(
file=ovfs_file,
host_path='',
),
],
]
)

server.wait_events(events)
5 changes: 5 additions & 0 deletions tests/test_path_rmdir.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import shutil
import sys

import pytest

Expand Down Expand Up @@ -154,6 +155,10 @@ def test_rmdir_empty(
)


@pytest.mark.skipif(
sys.version_info < (3, 10),
reason='shutil.rmtree behavior changes between interpreter versions',
)
def test_rmdir_recursive(
monitored_dir: str,
server: FileActivityService,
Expand Down
Loading