Skip to content
Draft
35 changes: 27 additions & 8 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,27 @@ 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
# RHEL 10 is not being ablit to connect, need more investigation
- rhel-10
- 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,16 +123,16 @@ 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
if: always()
with:
paths: ${{ github.workspace }}/fact/tests/results.xml
paths: ${{ github.workspace }}/fact/tests/*-results.xml

- name: Store artifacts
if: always()
Expand All @@ -125,6 +144,6 @@ jobs:
with:
name: ${{ matrix.vm }}-test-logs
path: |
${{ github.workspace }}/fact/tests/logs
${{ github.workspace }}/fact/tests/results.xml
/tmp/fact/tests/logs
/tmp/fact/tests/*-results.xml
if-no-files-found: ignore
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"
102 changes: 70 additions & 32 deletions ansible/run-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,57 +5,95 @@
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: true
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
ansible.builtin.file:
state: directory
path: /tmp/fact/tests/logs
recurse: true
delegate_to: localhost

- name: Retrieve results
ansible.builtin.fetch:
src: "{{ ansible_env.HOME }}/fact/tests/results.xml"
dest: ../tests/
src: /tmp/fact/tests/results.xml
dest: "/tmp/fact/tests/{{ vm_config }}-results.xml"
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/{{ vm_config }}.tar.gz"
dest: /tmp/fact/tests/logs/
validate_checksum: false
flat: true

- name: Debug
ansible.builtin.command:
cmd: ls -la /tmp/fact/tests/**
delegate_to: localhost
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