Skip to content
Closed
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
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
# Auto detect text files and perform LF normalization
* text=auto

# Enforce LF line endings for files that run inside Linux containers or are
# parsed by tools that are sensitive to CRLF (Docker, bash, etc.).
*.sh text eol=lf
Dockerfile* text eol=lf
*.yml text eol=lf
138 changes: 138 additions & 0 deletions .github/workflows/install-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: SimpleRisk Install/Uninstall Tests

on:
push:
branches: [main, "feature/**"]
pull_request:
branches: [main]
workflow_dispatch:

jobs:
test:
name: "Test: ${{ matrix.os-slug }}"
runs-on: ubuntu-latest

strategy:
# Run all matrix jobs even if one fails so we get a full picture
fail-fast: false
matrix:
os-slug:
- ubuntu-22.04
- ubuntu-24.04
- debian-12
- debian-13
- centos-stream-9
- centos-stream-10

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

# ── Build ───────────────────────────────────────────────────────────────
- name: Build test image
run: |
docker build \
-f tests/dockerfiles/Dockerfile.${{ matrix.os-slug }} \
-t simplerisk-test:${{ matrix.os-slug }} \
tests/dockerfiles/

# ── Start container ─────────────────────────────────────────────────────
# All OSes use --init (tini as PID 1) so that child processes (Apache
# workers, mysqld) are properly reaped and multiple rapid service
# start/stop/restart calls during apt/dnf post-install triggers work
# correctly. CentOS/RHEL uses the /usr/local/bin/systemctl shim baked
# into the image; no real systemd is needed.
# --privileged is required for ufw/iptables inside Debian/Ubuntu and
# is harmless for CentOS.
- name: Start container
run: |
docker run -d \
--name simplerisk-test-${{ matrix.os-slug }} \
--privileged \
--init \
simplerisk-test:${{ matrix.os-slug }} \
/bin/bash -c "tail -f /dev/null"
sleep 2

# ── Pre-start services (Ubuntu only) ────────────────────────────────────
# Ubuntu images pre-install lamp-server^ during the Docker build (with
# policy-rc.d blocking auto-start). Start MySQL and Apache now so that
# the setup script finds them in the expected running state — mirroring
# what would happen on a freshly provisioned real server where the
# package post-install scripts start the services.
- name: Start pre-installed services (Ubuntu only)
if: ${{ startsWith(matrix.os-slug, 'ubuntu') }}
run: |
docker exec simplerisk-test-${{ matrix.os-slug }} service mysql start 2>/dev/null || true
docker exec simplerisk-test-${{ matrix.os-slug }} service apache2 start 2>/dev/null || true
sleep 2

# ── Copy files ──────────────────────────────────────────────────────────
- name: Copy scripts into container
run: |
CONTAINER="simplerisk-test-${{ matrix.os-slug }}"
docker cp simplerisk-setup.sh "$CONTAINER:/root/simplerisk-setup.sh"
docker cp tests/verify-install.sh "$CONTAINER:/root/verify-install.sh"
docker cp tests/verify-uninstall.sh "$CONTAINER:/root/verify-uninstall.sh"
docker exec "$CONTAINER" chmod +x \
/root/simplerisk-setup.sh \
/root/verify-install.sh \
/root/verify-uninstall.sh

# ── Install ─────────────────────────────────────────────────────────────
- name: Run install
run: |
docker exec simplerisk-test-${{ matrix.os-slug }} \
bash /root/simplerisk-setup.sh --yes --debug

# ── Verify install ──────────────────────────────────────────────────────
- name: Verify installation
run: |
docker exec simplerisk-test-${{ matrix.os-slug }} \
bash /root/verify-install.sh

# ── Uninstall ───────────────────────────────────────────────────────────
- name: Run uninstall
run: |
docker exec simplerisk-test-${{ matrix.os-slug }} \
bash /root/simplerisk-setup.sh --uninstall --yes --debug

# ── Verify uninstall ────────────────────────────────────────────────────
- name: Verify uninstallation
run: |
docker exec simplerisk-test-${{ matrix.os-slug }} \
bash /root/verify-uninstall.sh

# ── Diagnostics on failure ──────────────────────────────────────────────
- name: Collect diagnostics on failure
if: failure()
run: |
CONTAINER="simplerisk-test-${{ matrix.os-slug }}"
echo "=== /etc/my.cnf ===" && \
docker exec "$CONTAINER" cat /etc/my.cnf 2>/dev/null || true
echo "=== /etc/my.cnf.d/ ===" && \
docker exec "$CONTAINER" ls -la /etc/my.cnf.d/ 2>/dev/null || true
echo "=== /etc/my.cnf.d/* contents ===" && \
docker exec "$CONTAINER" sh -c 'for f in /etc/my.cnf.d/*.cnf; do echo "--- $f ---"; cat "$f"; done' 2>/dev/null || true
echo "=== MySQL sql_mode ===" && \
docker exec "$CONTAINER" sh -c \
'PW=$(grep "MYSQL ROOT PASSWORD:" /root/passwords.txt 2>/dev/null | cut -d" " -f4); mysql -uroot -p"$PW" -e "SELECT @@sql_mode;" 2>/dev/null' || true
echo "=== journalctl (last 50 lines) ===" && \
docker exec "$CONTAINER" journalctl -n 50 2>/dev/null || true
echo "=== Apache error log ===" && \
docker exec "$CONTAINER" cat /var/log/apache2/error.log 2>/dev/null || \
docker exec "$CONTAINER" cat /var/log/httpd/error_log 2>/dev/null || true
echo "=== MySQL error log (last 30 lines) ===" && \
docker exec "$CONTAINER" tail -30 /var/log/mysql/error.log 2>/dev/null || \
docker exec "$CONTAINER" tail -30 /var/log/mysqld.log 2>/dev/null || true
echo "=== /root/passwords.txt ===" && \
docker exec "$CONTAINER" cat /root/passwords.txt 2>/dev/null || true

# ── Teardown ────────────────────────────────────────────────────────────
- name: Teardown container
if: always()
run: |
docker rm -f simplerisk-test-${{ matrix.os-slug }} 2>/dev/null || true
95 changes: 95 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What this repository is

A single Bash script (`simplerisk-setup.sh`) that installs or uninstalls [SimpleRisk](https://www.simplerisk.com/) (an open-source risk management application) on supported Linux servers. It sets up a full LAMP stack (Apache, MySQL 8.4 LTS, PHP 8.5) with SSL, firewall rules, sendmail/postfix, and a backup cron job.

## Supported operating systems

| OS | Versions |
|---|---|
| Ubuntu | 22.04 LTS, 24.x, 25.x |
| Debian | 12, 13 |
| CentOS Stream | 9, 10 |
| RHEL / RHEL Server | 9.x, 10.x |
| SLES | 15.7+ (requires PHP module activated via `suseconnect`) |

## Automated testing

Docker-based tests live in `tests/`. They cover install and uninstall for every supported OS except RHEL (requires paid subscription) and SLES (requires subscription + `suseconnect`).

```bash
# Run all OSes
bash tests/run-tests.sh

# Run a single OS
bash tests/run-tests.sh ubuntu-22.04
bash tests/run-tests.sh debian-12
bash tests/run-tests.sh centos-stream-9
```

Available slugs: `ubuntu-22.04`, `ubuntu-24.04`, `debian-12`, `debian-13`, `centos-stream-9`, `centos-stream-10`.

Each test run: builds the image → starts the container → installs SimpleRisk (`--yes --debug`) → runs `tests/verify-install.sh` inside the container → uninstalls (`--uninstall --yes --debug`) → runs `tests/verify-uninstall.sh`. Logs land in `tests/logs/<os-slug>/`.

**CentOS/RHEL containers require `--privileged` and systemd as PID 1.** The Dockerfiles handle this. Debian/Ubuntu containers use `--privileged` only for UFW; no systemd is needed because the script calls `service` on those distros.

CI runs automatically via `.github/workflows/install-test.yml` on push/PR to `main` using a matrix across all six OSes (`fail-fast: false`).

## Validating the script

The only "test" available is the OS validation dry-run — no build system or test suite exists:

```bash
sudo bash simplerisk-setup.sh --validate-os-only
```

This validates that the detected OS/version is supported without requiring root and without making any changes.

## Running the script

```bash
# Interactive install
sudo bash simplerisk-setup.sh

# Headless install (auto-yes)
sudo bash simplerisk-setup.sh --yes

# Debug mode (shows all command output)
sudo bash simplerisk-setup.sh --debug

# Install the current testing release
sudo bash simplerisk-setup.sh --testing

# Uninstall SimpleRisk and all associated components
sudo bash simplerisk-setup.sh --uninstall
```

## Architecture

The script is structured as a single file with clearly delimited sections:

- **Main flow** (`setup`, `validate_args`, `check_root`, `ask_user`, `load_os_variables`, `validate_os_and_version`) — orchestrates the overall run. `setup()` is the entry point called at the bottom of the file.
- **Installation dispatcher** (`perform_installation`) — calls the appropriate OS-specific setup function.
- **Uninstallation dispatcher** (`perform_uninstallation`) — calls the appropriate OS-specific uninstall function.
- **Auxiliary/shared functions** — `set_up_database`, `set_up_simplerisk`, `set_php_settings`, `set_up_backup_cronjob`, `generate_passwords`, `drop_simplerisk_database`, `remove_backup_cronjob`, etc. These are called by the OS-specific functions.
- **OS setup functions** — `setup_ubuntu_debian`, `setup_centos_rhel`, `setup_suse`. Each handles its package manager, repos, service management, and config file paths.
- **OS uninstall functions** — `uninstall_ubuntu_debian`, `uninstall_centos_rhel`, `uninstall_suse`. Mirror the setup functions in reverse.

## Keeping README.md in sync

After any change to `simplerisk-setup.sh`, check whether `README.md` needs updating. The areas most likely to drift:

- **Supported OS/version table** — if a new distro or version is added/removed, update the list in the README.
- **`--help` flags block** — the README contains a verbatim copy of the help output. If flags are added, removed, or their descriptions change, mirror those changes in the README's ` ```--help``` ` section and its synopsis line.
- **SLES minimum SP** — the `SLES_15_SUPPORTED_SP` constant drives the version check; the README must reflect the same value.

## Key conventions

- `exec_cmd` wraps a command and calls `bail` on failure. Use this for steps that must succeed.
- `exec_cmd_nobail` runs a command but does not abort on failure. Use this for cleanup/uninstall steps where partial state is acceptable.
- OS detection populates `$OS` and `$VER`; `validate_os_and_version` sets `$SETUP_TYPE` to `debian`, `rhel`, or `suse`. All OS-specific branching elsewhere uses `$SETUP_TYPE` or `$OS`/`$VER` directly.
- MySQL root password is stored in `/root/passwords.txt` (mode 600) after install. The uninstall path reads it back via `get_mysql_root_password` to drop the database.
- SLES requires the PHP8 module to be activated in the subscription before running the script.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
- Debian 12, 13
- CentOS Stream 9, 10
- Red Hat Enterprise Linux (RHEL) 9, 10
- SUSE Linux Enterprise Server (SLES) higher than 15.5
- SUSE Linux Enterprise Server (SLES) 15.7 or higher

## Instructions

Expand All @@ -20,14 +20,16 @@ Run as root or insert `sudo -E` before `bash`:
## `--help`

```
Script to set up SimpleRisk on a server.
Script to set up or uninstall SimpleRisk on a server.

./simplerisk-setup [-d|--debug] [-n|--no-assistance] [-h|--help] [--validate-os-only]
./simplerisk-setup [-d|--debug] [--yes] [-h|--help] [--validate-os-only] [--uninstall]

Flags:
-d|--debug: Shows the output of the commands being run by this script
-n|--no-assistance: Runs the script in headless mode (will assume yes on anything)
-t|--testing: Picks the current testing version
--validate-os-only: Only validates if the current host (OS and version) are supported by the script. This option does not require running the script as superuser.
--uninstall: Removes SimpleRisk and all associated packages, services, and data
WARNING: This action is irreversible and will destroy all SimpleRisk data.
--yes: Will answer yes on every question (Use it carefully)
-h|--help: Shows instructions on how to use this script
```
Loading
Loading