Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
4 changes: 4 additions & 0 deletions src/roles/iop_core/tasks/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
ansible.builtin.include_role:
name: iop_cvemap_downloader

- name: Deploy IOP VEX Downloader
ansible.builtin.include_role:
name: iop_vex_downloader

- name: Deploy IOP VMAAS service
ansible.builtin.include_role:
name: iop_vmaas
Expand Down
4 changes: 4 additions & 0 deletions src/roles/iop_vex_downloader/defaults/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
iop_vex_downloader_base_url: "https://security.access.redhat.com/data/csaf/v2/vex/"
iop_vex_downloader_output_dir: "/var/www/html/pub/iop/data/csaf/v2/vex/"
iop_vex_downloader_timer_interval: "7d"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

If the script would implement the archive change checking, we could increase this default value to 1 day. 7 days might not be ideal for either scenarios, online and offline.

9 changes: 9 additions & 0 deletions src/roles/iop_vex_downloader/files/iop-vex-download.path
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Unit]
Description=Path unit for vex-latest.tar.zst manual file watcher

[Path]
PathChanged=/var/lib/foreman/vex-latest.tar.zst
PathModified=/var/lib/foreman/vex-latest.tar.zst

[Install]
WantedBy=multi-user.target
10 changes: 10 additions & 0 deletions src/roles/iop_vex_downloader/handlers/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
- name: Restart vex download timer
ansible.builtin.systemd:
name: iop-vex-download.timer
state: restarted

- name: Restart vex download path
ansible.builtin.systemd:
name: iop-vex-download.path
state: restarted
59 changes: 59 additions & 0 deletions src/roles/iop_vex_downloader/tasks/main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
- name: Install vex download script
ansible.builtin.template:
src: iop-vex-downloader.sh.j2
dest: /usr/local/bin/iop-vex-downloader.sh
owner: root
group: root
mode: '0755'

- name: Create vex download service unit
ansible.builtin.copy:
dest: /etc/systemd/system/iop-vex-download.service
content: |
[Unit]
Description=Manages vex-latest.tar.zst for IoP Vulnerability
After=network-online.target iop-core-gateway.service
Wants=network-online.target iop-core-gateway.service

[Service]
Type=oneshot
ExecStart=/usr/local/bin/iop-vex-downloader.sh \
'{{ iop_vex_downloader_base_url }}' \
'{{ iop_vex_downloader_output_dir }}'
User=root
Group=root
mode: '0644'

- name: Create vex download timer unit
ansible.builtin.template:
src: iop-vex-download.timer.j2
dest: /etc/systemd/system/iop-vex-download.timer
mode: '0644'
notify: Restart vex download timer

- name: Create vex download path unit
ansible.builtin.copy:
src: iop-vex-download.path
dest: /etc/systemd/system/iop-vex-download.path
mode: '0644'
notify: Restart vex download path

- name: Reload systemd daemon
ansible.builtin.systemd:
daemon_reload: true

- name: Flush handlers
ansible.builtin.meta: flush_handlers

- name: Enable and start vex download timer
ansible.builtin.systemd:
name: iop-vex-download.timer
enabled: true
state: started

- name: Enable and start vex download path watcher
ansible.builtin.systemd:
name: iop-vex-download.path
enabled: true
state: started
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[Unit]
Description=Timer for vex-latest.tar.zst download

[Timer]
OnActiveSec=0
OnUnitActiveSec={{ iop_vex_downloader_timer_interval }}

[Install]
WantedBy=timers.target
74 changes: 74 additions & 0 deletions src/roles/iop_vex_downloader/templates/iop-vex-downloader.sh.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash

set -euo pipefail

FILENAME_LATEST="archive_latest.txt"
OUTPUT_FILENAME="vex-latest.tar.zst"

URL="${1:-}"
Comment thread
pfreyburg marked this conversation as resolved.
OUTPUT_DIR="${2:-}"


if [[ -z "${URL}" || -z "${OUTPUT_DIR}" ]]; then
echo "Usage: ${0} URL OUTPUT_DIR" >&2
echo "Example: ${0} https://security.access.redhat.com/data/csaf/v2/vex/ /root/download/" >&2
exit 1
fi

URL="${URL%/}/"
OUTPUT_DIR="${OUTPUT_DIR%/}/"

mkdir -p "${OUTPUT_DIR}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

mkdir should not be part of the script. Existence of the dir is expected when running the script. Existence is ensured by Ansible role.


MANUAL_FILE="/var/lib/foreman/vex-latest.tar.zst"
MANUAL_FILE="/Users/pfreybur/work/workbench/vex/vex-latest.tar.zst"
Comment thread
pfreyburg marked this conversation as resolved.
Outdated
CHECKSUM_FILE="${OUTPUT_FILENAME}.checksum"
Comment thread
pfreyburg marked this conversation as resolved.
Outdated

if [[ -f "$MANUAL_FILE" ]]; then
echo "Offline mode: Using manual file from $MANUAL_FILE"

CURRENT_CHECKSUM=$(sha256sum "$MANUAL_FILE" | cut -d' ' -f1)
STORED_CHECKSUM=""

if [[ -f "$CHECKSUM_FILE" ]]; then
STORED_CHECKSUM=$(cat "$CHECKSUM_FILENAME")
fi

if [[ "$CURRENT_CHECKSUM" != "$STORED_CHECKSUM" ]]; then
echo "Copying updated manual file"
cp -Z "$MANUAL_FILE" "${OUTPUT_DIR}${OUTPUT_FILENAME}" && echo "$CURRENT_CHECKSUM" > "$CHECKSUM_FILE"
chmod 644 "${OUTPUT_DIR}${OUTPUT_FILENAME}"
FILE_UPDATED=true
else
echo "Manual file unchanged, skipping"
fi
else
echo "Online mode: Checking for updates from $URL"
ARCHIVE_DOWNLOAD_NAME_CONTENT=$(curl -sf "${URL}${FILENAME_LATEST}")

if [ "${?}" -ne 0 ]; then
echo "Error: The tarball's name wasn't downloaded" >&2
exit 1
fi

curl -sf "${URL}${ARCHIVE_DOWNLOAD_NAME_CONTENT}" -o "/tmp/${OUTPUT_FILENAME}"
Comment thread
pfreyburg marked this conversation as resolved.
Outdated

RET=${?}

if [ "${RET}" -ne 0 ]; then
echo "Error: Downloading of tarball failed. Curl failed with code ${RET}" >&2
exit 2
fi

curl -sf "${URL}${ARCHIVE_DOWNLOAD_NAME_CONTENT}.asc" -o "/tmp/${OUTPUT_FILENAME}.asc"
Comment thread
pfreyburg marked this conversation as resolved.
Outdated

RET=${?}

if [ "${RET}" -ne 0 ]; then
echo "Error: Downloading of tarball's signature failed. Curl failed with code ${RET}" >&2
exit 3
fi

mv "/tmp/${OUTPUT_FILENAME}" "${OUTPUT_DIR}${OUTPUT_FILENAME}"
mv "/tmp/${OUTPUT_FILENAME}.asc" "${OUTPUT_DIR}${OUTPUT_FILENAME}.asc"
fi
55 changes: 55 additions & 0 deletions tests/iop/test_vex_downloader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import pytest

pytestmark = pytest.mark.feature("iop")


def test_vex_download_script(server):
script = server.file("/usr/local/bin/iop-vex-download.sh")
assert script.exists
assert script.is_file
assert script.mode == 0o755


def test_vex_download_service_unit(server):
unit = server.file("/etc/systemd/system/iop-vex-download.service")
assert unit.exists
assert unit.is_file

content = unit.content_string
assert "Type=oneshot" in content
assert "iop-vex-download.sh" in content
assert "iop-core-gateway.service" in content


def test_vex_download_timer_unit(server):
unit = server.file("/etc/systemd/system/iop-vex-download.timer")
assert unit.exists
assert unit.is_file

content = unit.content_string
assert "OnActiveSec=0" in content
assert "OnUnitActiveSec=7d" in content
assert "WantedBy=timers.target" in content


def test_vex_download_timer_enabled(server):
timer = server.service("iop-vex-download.timer")
assert timer.is_enabled
assert timer.is_running


def test_vex_download_path_unit(server):
unit = server.file("/etc/systemd/system/iop-vex-download.path")
assert unit.exists
assert unit.is_file

content = unit.content_string
assert "PathChanged=/var/lib/foreman/vex.xml" in content
assert "PathModified=/var/lib/foreman/vex.xml" in content
assert "WantedBy=multi-user.target" in content


def test_vex_download_path_enabled(server):
path = server.service("iop-vex-download.path")
assert path.is_enabled
assert path.is_running
Loading