sysreport 1.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ ## 1.1.3
4
+
5
+ - Fixed npm global installs by resolving symlinked CLI launchers before locating runtime files.
6
+ - Prepared npm metadata and GitHub release packaging for RPM/Debian artifacts.
7
+ - Ensured RPM/Debian packages own runtime directories so package removal is clean.
8
+
9
+ ## 1.1.2
10
+
11
+ - Improved WHM/cPanel output formatting for PHP-FPM units.
12
+ - Added CSF, LFD, Imunify360, firewalld, and ufw service status checks.
13
+ - Kept `--no-color` output clean by suppressing fastfetch's colored block.
14
+
15
+ ## 1.1.1
16
+
17
+ - Fixed installed CLI version detection by installing `VERSION` with the runtime files.
18
+ - Included `VERSION` in nFPM and RPM package layouts.
19
+
20
+ ## 1.1.0
21
+
22
+ - Rebuilt SysReport as a modular CLI with a small launcher and reusable report modules.
23
+ - Added CI smoke tests and GitHub release archive automation.
24
+ - Added public project docs: README, contributing guide, security policy, license, and packaging metadata.
25
+ - Added safer runtime behavior for public use: report-only execution, section filtering, and graceful skips for missing tools.
26
+
27
+ ## 1.0.2
28
+
29
+ - Refactored the CLI into a modular runtime under `src/sysreport/`.
30
+ - Added section filtering with `--section` and discovery with `--list-sections`.
31
+ - Removed automatic dependency installation during report execution.
32
+ - Updated package metadata and install paths for public distribution.
33
+
34
+ ## 1.0.0
35
+
36
+ - Initial release.
37
+ - Hardware audit.
38
+ - Network audit.
39
+ - PHP audit.
40
+ - MySQL audit.
41
+ - Security audit.
42
+ - SEO audit.
@@ -0,0 +1,33 @@
1
+ # Contributing
2
+
3
+ Thanks for helping improve SysReport.
4
+
5
+ ## Local Checks
6
+
7
+ ```bash
8
+ make check
9
+ bash bin/sysreport --list-sections
10
+ bash bin/sysreport --section system --no-color
11
+ ```
12
+
13
+ ## Adding a Report Section
14
+
15
+ Create a new file under `src/sysreport/modules/` and register it:
16
+
17
+ ```bash
18
+ report_example() {
19
+ sysreport_section "Example"
20
+ sysreport_item "Status" "ok"
21
+ }
22
+
23
+ sysreport_register_section "example" "Example report" "report_example"
24
+ ```
25
+
26
+ Keep modules read-only by default. A report command should never install packages, restart services, edit configuration, or delete files.
27
+
28
+ ## Style
29
+
30
+ - Prefer portable Bash and common Linux utilities.
31
+ - Check for optional commands with `sysreport_have`.
32
+ - If a command is missing or access is denied, print a skipped or unknown result instead of failing the whole report.
33
+ - Keep output useful for humans first.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amir Hossein Khateri
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # SysReport
2
+
3
+ SysReport is a lightweight Linux server audit CLI for sysadmins, DevOps engineers, and hosting operators. Run one command and get a practical summary of the server's health, identity, network, web stack, databases, security posture, and optimization signals.
4
+
5
+ ```bash
6
+ sysreport
7
+ ```
8
+
9
+ ## Highlights
10
+
11
+ - Modular Bash architecture: each report area lives in `src/sysreport/modules/`.
12
+ - Safe by default: it does not install dependencies or change server configuration while reporting.
13
+ - Works on generic Linux servers and adds extra context when cPanel/WHM, PHP, MySQL, Redis, Memcached, or common firewalls are detected.
14
+ - Supports targeted checks with `--section`.
15
+ - Friendly to package managers: npm, deb/rpm layouts, and manual install scripts are included.
16
+
17
+ ## Installation
18
+
19
+ ### Manual
20
+
21
+ ```bash
22
+ git clone https://github.com/amirkhateri/sysreport.git
23
+ cd sysreport
24
+ bash scripts/install/install.sh
25
+ sysreport
26
+ ```
27
+
28
+ ### npm
29
+
30
+ ```bash
31
+ npm install -g sysreport
32
+ sysreport
33
+ ```
34
+
35
+ ### Debian / Ubuntu and RPM
36
+
37
+ Download packages from the GitHub release page, or install the RPM directly with `dnf`:
38
+
39
+ ```bash
40
+ VERSION=1.1.3
41
+ sudo dnf install -y "https://github.com/amirkhateri/sysreport/releases/download/v${VERSION}/sysreport-${VERSION}-1.noarch.rpm"
42
+ ```
43
+
44
+ Debian/Ubuntu users can install the `.deb` package from the same release:
45
+
46
+ ```bash
47
+ VERSION=1.1.3
48
+ curl -LO "https://github.com/amirkhateri/sysreport/releases/download/v${VERSION}/sysreport_${VERSION}_all.deb"
49
+ sudo apt install ./sysreport_${VERSION}_all.deb
50
+ ```
51
+
52
+ Package templates are available under `templates/`, and release automation publishes `.deb` and `.rpm` artifacts.
53
+
54
+ For GitHub releases, download the `sysreport-<version>.tar.gz` archive, extract it, and run the installer:
55
+
56
+ ```bash
57
+ tar -xzf sysreport-<version>.tar.gz
58
+ cd sysreport-<version>
59
+ bash scripts/install/install.sh
60
+ ```
61
+
62
+ ## Usage
63
+
64
+ ```bash
65
+ sysreport # run the full report
66
+ sysreport --list-sections # show available sections
67
+ sysreport --section system --section security
68
+ sysreport --no-color
69
+ sysreport --version
70
+ ```
71
+
72
+ Current sections:
73
+
74
+ - `system`
75
+ - `identity`
76
+ - `network`
77
+ - `services`
78
+ - `webstack`
79
+ - `database`
80
+ - `security`
81
+ - `optimization`
82
+
83
+ You can customize network ping targets:
84
+
85
+ ```bash
86
+ SYSREPORT_PING_TARGETS="1.1.1.1 github.com example.com" sysreport --section network
87
+ ```
88
+
89
+ ## Optional Dependencies
90
+
91
+ SysReport runs without these tools, but it reports more detail when they exist:
92
+
93
+ - `curl` for public IP detection
94
+ - `jq` for IP geolocation parsing
95
+ - `fastfetch` for an optional system profile block
96
+ - `systemctl`, `ss`, `ip`, `ping`, `free`, `df`, `awk`, `sed`, `grep`
97
+ - `mysql`, `psql`, `php`, `nginx`, `httpd` or `apache2` for stack-specific checks
98
+
99
+ ## Development
100
+
101
+ Run locally:
102
+
103
+ ```bash
104
+ make run
105
+ make sections
106
+ ```
107
+
108
+ Syntax check:
109
+
110
+ ```bash
111
+ make check
112
+ ```
113
+
114
+ Add a new report module by creating a file in `src/sysreport/modules/`:
115
+
116
+ ```bash
117
+ report_example() {
118
+ sysreport_section "Example"
119
+ sysreport_item "Status" "ok"
120
+ }
121
+
122
+ sysreport_register_section "example" "Example report" "report_example"
123
+ ```
124
+
125
+ ## Philosophy
126
+
127
+ SysReport should be useful on the first run, readable by humans, conservative on production servers, and easy to extend. It reports what it can see and skips what is unavailable instead of failing the whole run.
128
+
129
+ ## License
130
+
131
+ MIT
package/SECURITY.md ADDED
@@ -0,0 +1,15 @@
1
+ # Security Policy
2
+
3
+ SysReport is a read-only audit tool. Report modules should not change server state, install packages, restart services, or expose secrets.
4
+
5
+ ## Reporting a Vulnerability
6
+
7
+ Please open a private security advisory or contact the maintainer from the repository profile if you find a vulnerability.
8
+
9
+ When reporting, include:
10
+
11
+ - affected version or commit
12
+ - command used
13
+ - operating system
14
+ - impact
15
+ - suggested fix, if known
package/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.1.3
package/bin/sysreport ADDED
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -o pipefail
4
+
5
+ resolve_lib_dir() {
6
+ local source bin_dir candidate
7
+ source="${BASH_SOURCE[0]}"
8
+
9
+ while [[ -L "$source" ]]; do
10
+ bin_dir="$(cd -- "$(dirname -- "$source")" >/dev/null 2>&1 && pwd -P)"
11
+ source="$(readlink "$source")"
12
+ [[ "$source" != /* ]] && source="$bin_dir/$source"
13
+ done
14
+
15
+ bin_dir="$(cd -- "$(dirname -- "$source")" >/dev/null 2>&1 && pwd -P)"
16
+
17
+ if [[ -n "${SYSREPORT_LIB_DIR:-}" && -f "$SYSREPORT_LIB_DIR/core.sh" ]]; then
18
+ printf '%s\n' "$SYSREPORT_LIB_DIR"
19
+ return 0
20
+ fi
21
+
22
+ for candidate in \
23
+ "$bin_dir/../src/sysreport" \
24
+ "$bin_dir/../lib/sysreport" \
25
+ "/usr/local/lib/sysreport" \
26
+ "/usr/lib/sysreport"; do
27
+ if [[ -f "$candidate/core.sh" ]]; then
28
+ printf '%s\n' "$candidate"
29
+ return 0
30
+ fi
31
+ done
32
+
33
+ return 1
34
+ }
35
+
36
+ SYSREPORT_LIB_DIR="$(resolve_lib_dir)" || {
37
+ echo "sysreport: unable to find runtime files. Set SYSREPORT_LIB_DIR to the sysreport library path." >&2
38
+ exit 1
39
+ }
40
+
41
+ # shellcheck source=/dev/null
42
+ source "$SYSREPORT_LIB_DIR/core.sh"
43
+
44
+ shopt -s nullglob
45
+ for module in "$SYSREPORT_LIB_DIR"/modules/*.sh; do
46
+ # shellcheck source=/dev/null
47
+ source "$module"
48
+ done
49
+ shopt -u nullglob
50
+
51
+ sysreport_main "$@"
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "sysreport",
3
+ "version": "1.1.3",
4
+ "description": "Linux server audit and operations summary CLI",
5
+ "license": "MIT",
6
+ "os": [
7
+ "linux"
8
+ ],
9
+ "author": "Amir Hossein Khateri",
10
+ "homepage": "https://github.com/amirkhateri/sysreport",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "git+https://github.com/amirkhateri/sysreport.git"
14
+ },
15
+ "bin": {
16
+ "sysreport": "bin/sysreport"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public",
20
+ "registry": "https://registry.npmjs.org/"
21
+ },
22
+ "files": [
23
+ "bin/",
24
+ "src/",
25
+ "README.md",
26
+ "CHANGELOG.md",
27
+ "CONTRIBUTING.md",
28
+ "SECURITY.md",
29
+ "LICENSE",
30
+ "VERSION"
31
+ ],
32
+ "keywords": [
33
+ "linux",
34
+ "server",
35
+ "audit",
36
+ "sysadmin",
37
+ "devops",
38
+ "monitoring"
39
+ ]
40
+ }
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SYSREPORT_NAME="sysreport"
4
+ SYSREPORT_DESCRIPTION="Linux server audit and operations summary"
5
+ SYSREPORT_VERSION="${SYSREPORT_VERSION:-dev}"
6
+
7
+ if [[ -z "${SYSREPORT_ROOT:-}" ]]; then
8
+ SYSREPORT_ROOT="$(cd -- "${SYSREPORT_LIB_DIR:-$(pwd)}/../.." >/dev/null 2>&1 && pwd -P)"
9
+ fi
10
+
11
+ if [[ -n "${SYSREPORT_LIB_DIR:-}" && -f "$SYSREPORT_LIB_DIR/VERSION" ]]; then
12
+ SYSREPORT_VERSION="$(tr -d '[:space:]' < "$SYSREPORT_LIB_DIR/VERSION")"
13
+ elif [[ -f "$SYSREPORT_ROOT/VERSION" ]]; then
14
+ SYSREPORT_VERSION="$(tr -d '[:space:]' < "$SYSREPORT_ROOT/VERSION")"
15
+ fi
16
+
17
+ SYSREPORT_SECTION_IDS=()
18
+ SYSREPORT_SECTION_TITLES=()
19
+ SYSREPORT_SECTION_FUNCS=()
20
+ SYSREPORT_SELECTED_SECTIONS=()
21
+ SYSREPORT_COLOR=1
22
+
23
+ if [[ ! -t 1 || -n "${NO_COLOR:-}" || "${TERM:-}" == "dumb" ]]; then
24
+ SYSREPORT_COLOR=0
25
+ fi
26
+
27
+ sysreport_use_color() {
28
+ [[ "$SYSREPORT_COLOR" -eq 1 ]]
29
+ }
30
+
31
+ sysreport_color() {
32
+ local code="$1"
33
+ if sysreport_use_color; then
34
+ printf '\033[%sm' "$code"
35
+ fi
36
+ }
37
+
38
+ sysreport_refresh_colors() {
39
+ SR_RESET="$(sysreport_color 0)"
40
+ SR_BOLD="$(sysreport_color 1)"
41
+ SR_BLUE="$(sysreport_color '0;34')"
42
+ SR_CYAN="$(sysreport_color '0;36')"
43
+ SR_GREEN="$(sysreport_color '0;32')"
44
+ SR_YELLOW="$(sysreport_color '1;33')"
45
+ SR_RED="$(sysreport_color '0;31')"
46
+ }
47
+
48
+ sysreport_refresh_colors
49
+
50
+ sysreport_have() {
51
+ command -v "$1" >/dev/null 2>&1
52
+ }
53
+
54
+ sysreport_read_os_release() {
55
+ if [[ -r /etc/os-release ]]; then
56
+ (
57
+ # shellcheck disable=SC1091
58
+ source /etc/os-release
59
+ printf '%s\n' "${PRETTY_NAME:-${NAME:-Linux}}"
60
+ )
61
+ else
62
+ uname -s
63
+ fi
64
+ }
65
+
66
+ sysreport_register_section() {
67
+ local id="$1" title="$2" fn="$3"
68
+ SYSREPORT_SECTION_IDS+=("$id")
69
+ SYSREPORT_SECTION_TITLES+=("$title")
70
+ SYSREPORT_SECTION_FUNCS+=("$fn")
71
+ }
72
+
73
+ sysreport_is_selected() {
74
+ local id="$1" selected
75
+ if [[ "${#SYSREPORT_SELECTED_SECTIONS[@]}" -eq 0 ]]; then
76
+ return 0
77
+ fi
78
+
79
+ for selected in "${SYSREPORT_SELECTED_SECTIONS[@]}"; do
80
+ [[ "$selected" == "$id" ]] && return 0
81
+ done
82
+
83
+ return 1
84
+ }
85
+
86
+ sysreport_header() {
87
+ printf '%s\n' "${SR_BLUE}${SR_BOLD}============================================================${SR_RESET}"
88
+ printf '%s\n' "${SR_CYAN}${SR_BOLD} SysReport ${SYSREPORT_VERSION} - ${SYSREPORT_DESCRIPTION}${SR_RESET}"
89
+ printf '%s\n' "${SR_BLUE}${SR_BOLD}============================================================${SR_RESET}"
90
+ }
91
+
92
+ sysreport_section() {
93
+ printf '\n%s\n' "${SR_BLUE}${SR_BOLD}-- $1 --${SR_RESET}"
94
+ }
95
+
96
+ sysreport_item() {
97
+ printf '%b%s:%b %s\n' "${SR_GREEN}" "$1" "${SR_RESET}" "${2:-}"
98
+ }
99
+
100
+ sysreport_ok() {
101
+ printf ' [%bOK%b] %s\n' "$SR_GREEN" "$SR_RESET" "$1"
102
+ }
103
+
104
+ sysreport_warn() {
105
+ printf ' [%bWARN%b] %s\n' "$SR_YELLOW" "$SR_RESET" "$1"
106
+ }
107
+
108
+ sysreport_fail() {
109
+ printf ' [%bFAIL%b] %s\n' "$SR_RED" "$SR_RESET" "$1"
110
+ }
111
+
112
+ sysreport_unknown() {
113
+ printf ' [%bSKIP%b] %s\n' "$SR_YELLOW" "$SR_RESET" "$1"
114
+ }
115
+
116
+ sysreport_usage() {
117
+ cat <<EOF
118
+ SysReport - Linux server audit and operations summary
119
+
120
+ Usage:
121
+ sysreport [options]
122
+
123
+ Options:
124
+ -h, --help Show this help message
125
+ -v, --version Show version
126
+ --no-color Disable colored output
127
+ --list-sections List available report sections
128
+ --section <id> Run one section; repeat to run multiple sections
129
+
130
+ Examples:
131
+ sysreport
132
+ sysreport --section system --section security
133
+ NO_COLOR=1 sysreport
134
+ EOF
135
+ }
136
+
137
+ sysreport_list_sections() {
138
+ local i
139
+ for i in "${!SYSREPORT_SECTION_IDS[@]}"; do
140
+ printf '%-14s %s\n' "${SYSREPORT_SECTION_IDS[$i]}" "${SYSREPORT_SECTION_TITLES[$i]}"
141
+ done
142
+ }
143
+
144
+ sysreport_parse_args() {
145
+ while [[ "$#" -gt 0 ]]; do
146
+ case "$1" in
147
+ -h|--help)
148
+ sysreport_usage
149
+ exit 0
150
+ ;;
151
+ -v|--version)
152
+ printf '%s\n' "$SYSREPORT_VERSION"
153
+ exit 0
154
+ ;;
155
+ --no-color)
156
+ SYSREPORT_COLOR=0
157
+ ;;
158
+ --list-sections)
159
+ sysreport_list_sections
160
+ exit 0
161
+ ;;
162
+ --section)
163
+ if [[ -z "${2:-}" ]]; then
164
+ echo "sysreport: --section requires a section id" >&2
165
+ exit 2
166
+ fi
167
+ SYSREPORT_SELECTED_SECTIONS+=("$2")
168
+ shift
169
+ ;;
170
+ *)
171
+ echo "sysreport: unknown option: $1" >&2
172
+ echo "Try 'sysreport --help'." >&2
173
+ exit 2
174
+ ;;
175
+ esac
176
+ shift
177
+ done
178
+ }
179
+
180
+ sysreport_main() {
181
+ local i fn matched=0
182
+ sysreport_parse_args "$@"
183
+ sysreport_refresh_colors
184
+ sysreport_header
185
+
186
+ for i in "${!SYSREPORT_SECTION_IDS[@]}"; do
187
+ if sysreport_is_selected "${SYSREPORT_SECTION_IDS[$i]}"; then
188
+ matched=1
189
+ fn="${SYSREPORT_SECTION_FUNCS[$i]}"
190
+ "$fn"
191
+ fi
192
+ done
193
+
194
+ if [[ "$matched" -eq 0 ]]; then
195
+ echo "sysreport: no matching sections selected" >&2
196
+ exit 2
197
+ fi
198
+
199
+ printf '\n%s\n' "${SR_BLUE}${SR_BOLD}============================================================${SR_RESET}"
200
+ printf '%s\n' "${SR_GREEN}${SR_BOLD}Report complete.${SR_RESET}"
201
+ }
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_system() {
4
+ local os kernel uptime_text load_avg cpu_cores memory_line swap_line root_usage
5
+
6
+ sysreport_section "System Summary"
7
+
8
+ os="$(sysreport_read_os_release)"
9
+ kernel="$(uname -r 2>/dev/null || echo unknown)"
10
+ uptime_text="$(uptime -p 2>/dev/null || uptime 2>/dev/null || echo unknown)"
11
+ load_avg="$(uptime 2>/dev/null | awk -F'load average: ' '{print $2}' || true)"
12
+ cpu_cores="$(nproc 2>/dev/null || getconf _NPROCESSORS_ONLN 2>/dev/null || echo unknown)"
13
+ memory_line="$(free -h 2>/dev/null | awk '/^Mem:/ {print $3 " used / " $2 " total"}')"
14
+ swap_line="$(free -h 2>/dev/null | awk '/^Swap:/ {print $3 " used / " $2 " total"}')"
15
+ root_usage="$(df -h / 2>/dev/null | awk 'NR==2 {print $5 " used on " $1 " (" $4 " free)"}')"
16
+
17
+ sysreport_item "OS" "$os"
18
+ sysreport_item "Kernel" "$kernel"
19
+ sysreport_item "Uptime" "$uptime_text"
20
+ sysreport_item "CPU cores" "$cpu_cores"
21
+ sysreport_item "Load average" "${load_avg:-unknown}"
22
+ sysreport_item "Memory" "${memory_line:-unknown}"
23
+ sysreport_item "Swap" "${swap_line:-unknown}"
24
+ sysreport_item "Root filesystem" "${root_usage:-unknown}"
25
+
26
+ if sysreport_have fastfetch && sysreport_use_color; then
27
+ printf '\n'
28
+ fastfetch --pipe false 2>/dev/null || true
29
+ fi
30
+ }
31
+
32
+ sysreport_register_section "system" "System summary" "report_system"
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_identity() {
4
+ local hostname_value private_ipv4 public_ipv4 public_ipv6 location ip_info country city
5
+
6
+ sysreport_section "Identity and Location"
7
+
8
+ hostname_value="$(hostname -f 2>/dev/null || hostname 2>/dev/null || echo unknown)"
9
+ private_ipv4="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for (i=1;i<=NF;i++) if ($i=="src") {print $(i+1); exit}}')"
10
+
11
+ if sysreport_have curl; then
12
+ public_ipv4="$(curl -fsS --max-time 3 -4 https://icanhazip.com 2>/dev/null | head -n1 || true)"
13
+ public_ipv6="$(curl -fsS --max-time 3 -6 https://icanhazip.com 2>/dev/null | head -n1 || true)"
14
+ fi
15
+
16
+ sysreport_item "Hostname" "$hostname_value"
17
+ sysreport_item "Primary IPv4" "${private_ipv4:-unknown}"
18
+ sysreport_item "Public IPv4" "${public_ipv4:-unknown}"
19
+ sysreport_item "Public IPv6" "${public_ipv6:-not detected}"
20
+
21
+ if [[ -n "${public_ipv4:-}" ]] && sysreport_have curl && sysreport_have jq; then
22
+ ip_info="$(curl -fsS --max-time 4 "http://ip-api.com/json/${public_ipv4}" 2>/dev/null || true)"
23
+ country="$(printf '%s' "$ip_info" | jq -r '.country // empty' 2>/dev/null || true)"
24
+ city="$(printf '%s' "$ip_info" | jq -r '.city // empty' 2>/dev/null || true)"
25
+ location="$(printf '%s, %s' "${city:-unknown}" "${country:-unknown}")"
26
+ sysreport_item "Geolocation" "$location"
27
+ else
28
+ sysreport_item "Geolocation" "skipped (requires curl, jq, and public IPv4)"
29
+ fi
30
+ }
31
+
32
+ sysreport_register_section "identity" "Host identity and public IP" "report_identity"
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_network_ping() {
4
+ local target="$1" ms
5
+ if ! sysreport_have ping; then
6
+ sysreport_unknown "ping command not available"
7
+ return 0
8
+ fi
9
+
10
+ ms="$(ping -c 1 -W 2 "$target" 2>/dev/null | awk -F'time=' '/time=/{print $2}' | awk '{print $1; exit}')"
11
+ if [[ -n "$ms" ]]; then
12
+ sysreport_ok "$target reachable (${ms} ms)"
13
+ else
14
+ sysreport_warn "$target timeout or unreachable"
15
+ fi
16
+ }
17
+
18
+ report_network() {
19
+ local targets target
20
+
21
+ sysreport_section "Network"
22
+
23
+ targets="${SYSREPORT_PING_TARGETS:-1.1.1.1 google.com github.com}"
24
+ sysreport_item "Ping targets" "$targets"
25
+ for target in $targets; do
26
+ report_network_ping "$target"
27
+ done
28
+
29
+ printf '\n'
30
+ sysreport_item "DNS resolvers" ""
31
+ if [[ -r /etc/resolv.conf ]]; then
32
+ awk '/^nameserver/ {print " " $2}' /etc/resolv.conf
33
+ else
34
+ sysreport_unknown "/etc/resolv.conf is not readable"
35
+ fi
36
+
37
+ printf '\n'
38
+ sysreport_item "Listening TCP ports" ""
39
+ if sysreport_have ss; then
40
+ ss -H -tln 2>/dev/null | awk '{print " " $4}' | sed 's/.*://' | sort -n | uniq | head -n 30
41
+ else
42
+ sysreport_unknown "ss command not available"
43
+ fi
44
+ }
45
+
46
+ sysreport_register_section "network" "Network diagnostics" "report_network"
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_service_status() {
4
+ local label="$1" unit="$2"
5
+
6
+ if ! sysreport_have systemctl; then
7
+ sysreport_unknown "systemctl not available for $label"
8
+ return 0
9
+ fi
10
+
11
+ if systemctl list-unit-files --no-legend "$unit" 2>/dev/null | grep -q . || \
12
+ systemctl list-units --no-legend "$unit" 2>/dev/null | grep -q .; then
13
+ if systemctl is-active --quiet "$unit" 2>/dev/null; then
14
+ sysreport_ok "$label active ($unit)"
15
+ else
16
+ sysreport_warn "$label installed but not active ($unit)"
17
+ fi
18
+ else
19
+ sysreport_unknown "$label not detected ($unit)"
20
+ fi
21
+ }
22
+
23
+ report_services() {
24
+ sysreport_section "Core Services"
25
+
26
+ report_service_status "OpenSSH" "sshd.service"
27
+ report_service_status "Nginx" "nginx.service"
28
+ report_service_status "Apache httpd" "httpd.service"
29
+ report_service_status "Apache apache2" "apache2.service"
30
+ report_service_status "MariaDB" "mariadb.service"
31
+ report_service_status "MySQL" "mysql.service"
32
+ report_service_status "PostgreSQL" "postgresql.service"
33
+ report_service_status "Redis" "redis.service"
34
+ report_service_status "Memcached" "memcached.service"
35
+ report_service_status "Docker" "docker.service"
36
+ }
37
+
38
+ sysreport_register_section "services" "Core service status" "report_services"
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_webstack() {
4
+ local apache_version nginx_version php_version cpanel_version accounts suspended fpm_services disabled_functions
5
+
6
+ sysreport_section "Web Stack"
7
+
8
+ if sysreport_have httpd; then
9
+ apache_version="$(httpd -v 2>/dev/null | awk 'NR==1 {print $3}')"
10
+ sysreport_item "Apache" "${apache_version:-detected}"
11
+ elif sysreport_have apache2; then
12
+ apache_version="$(apache2 -v 2>/dev/null | awk 'NR==1 {print $3}')"
13
+ sysreport_item "Apache" "${apache_version:-detected}"
14
+ else
15
+ sysreport_item "Apache" "not detected"
16
+ fi
17
+
18
+ if sysreport_have nginx; then
19
+ nginx_version="$(nginx -v 2>&1 | sed 's/^nginx version: //')"
20
+ sysreport_item "Nginx" "${nginx_version:-detected}"
21
+ else
22
+ sysreport_item "Nginx" "not detected"
23
+ fi
24
+
25
+ if pgrep -af 'litespeed|lshttpd' >/dev/null 2>&1; then
26
+ sysreport_item "LiteSpeed" "running"
27
+ else
28
+ sysreport_item "LiteSpeed" "not detected"
29
+ fi
30
+
31
+ if sysreport_have php; then
32
+ php_version="$(php -v 2>/dev/null | awk 'NR==1 {print $1 " " $2}')"
33
+ disabled_functions="$(php -r 'echo ini_get("disable_functions");' 2>/dev/null || true)"
34
+ sysreport_item "PHP CLI" "${php_version:-detected}"
35
+ sysreport_item "PHP OPcache" "$(php -v 2>/dev/null | grep -iq opcache && echo enabled || echo not detected)"
36
+ sysreport_item "PHP disable_functions" "${disabled_functions:-empty}"
37
+ else
38
+ sysreport_item "PHP CLI" "not detected"
39
+ fi
40
+
41
+ if sysreport_have systemctl; then
42
+ fpm_services="$(systemctl list-units --type=service --no-legend 2>/dev/null | awk '/php.*fpm|ea-php.*fpm/ {print $1 " " $4}' | head -n 20)"
43
+ sysreport_item "PHP-FPM units" ""
44
+ if [[ -n "$fpm_services" ]]; then
45
+ printf '%s\n' "$fpm_services" | awk '{print " " $1 ": " $2}'
46
+ else
47
+ sysreport_unknown "none detected"
48
+ fi
49
+ fi
50
+
51
+ if [[ -x /usr/local/cpanel/cpanel ]]; then
52
+ cpanel_version="$(/usr/local/cpanel/cpanel -V 2>/dev/null || true)"
53
+ accounts="$(find /var/cpanel/users -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')"
54
+ suspended="$(find /var/cpanel/suspended -maxdepth 1 -type f 2>/dev/null | wc -l | tr -d ' ')"
55
+ sysreport_item "cPanel/WHM" "version ${cpanel_version:-unknown}; accounts ${accounts:-0}; suspended ${suspended:-0}"
56
+ else
57
+ sysreport_item "cPanel/WHM" "not detected"
58
+ fi
59
+ }
60
+
61
+ sysreport_register_section "webstack" "Web, PHP, and cPanel profile" "report_webstack"
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_database() {
4
+ local mysql_version slow_log buffer_pool pg_version
5
+
6
+ sysreport_section "Database"
7
+
8
+ if sysreport_have mysql; then
9
+ mysql_version="$(mysql -V 2>/dev/null)"
10
+ sysreport_item "MySQL client" "${mysql_version:-detected}"
11
+
12
+ slow_log="$(mysql --batch --skip-column-names -e "SHOW VARIABLES LIKE 'slow_query_log';" 2>/dev/null | awk '{print $2}' || true)"
13
+ sysreport_item "MySQL slow query log" "${slow_log:-unknown or access denied}"
14
+
15
+ buffer_pool="$(mysql --batch --skip-column-names -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';" 2>/dev/null | awk '{printf "%.2f GB", $2/1024/1024/1024}' || true)"
16
+ sysreport_item "InnoDB buffer pool" "${buffer_pool:-unknown or access denied}"
17
+ else
18
+ sysreport_item "MySQL client" "not detected"
19
+ fi
20
+
21
+ if sysreport_have psql; then
22
+ pg_version="$(psql --version 2>/dev/null)"
23
+ sysreport_item "PostgreSQL client" "${pg_version:-detected}"
24
+ else
25
+ sysreport_item "PostgreSQL client" "not detected"
26
+ fi
27
+ }
28
+
29
+ sysreport_register_section "database" "Database summary" "report_database"
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_security_port() {
4
+ local port="$1" service
5
+ if sysreport_have ss && ss -H -tln 2>/dev/null | awk '{print $4}' | grep -Eq "[:.]${port}$"; then
6
+ service="$(ss -H -tlnp 2>/dev/null | awk -v port="$port" '$4 ~ ":" port "$" {print $0; exit}' | sed 's/.*users:(("//; s/".*//')"
7
+ sysreport_ok "port $port open${service:+ ($service)}"
8
+ else
9
+ sysreport_warn "port $port closed or not visible"
10
+ fi
11
+ }
12
+
13
+ report_security_unit() {
14
+ local label="$1" unit="$2" status
15
+
16
+ if ! sysreport_have systemctl; then
17
+ return 1
18
+ fi
19
+
20
+ if ! systemctl list-unit-files --no-legend "$unit" 2>/dev/null | grep -q . && \
21
+ ! systemctl list-units --no-legend "$unit" 2>/dev/null | grep -q .; then
22
+ return 1
23
+ fi
24
+
25
+ status="$(systemctl is-active "$unit" 2>/dev/null || true)"
26
+ case "$status" in
27
+ active)
28
+ sysreport_ok "$label active ($unit)"
29
+ ;;
30
+ failed)
31
+ sysreport_fail "$label installed but failed ($unit)"
32
+ ;;
33
+ inactive|deactivating|activating)
34
+ sysreport_warn "$label installed but $status ($unit)"
35
+ ;;
36
+ *)
37
+ sysreport_warn "$label installed but status is ${status:-unknown} ($unit)"
38
+ ;;
39
+ esac
40
+
41
+ return 0
42
+ }
43
+
44
+ report_security() {
45
+ local ssh_config ssh_port root_login password_auth found_security_unit
46
+
47
+ sysreport_section "Security"
48
+
49
+ ssh_config="/etc/ssh/sshd_config"
50
+ if [[ -r "$ssh_config" ]]; then
51
+ ssh_port="$(awk 'tolower($1)=="port" {print $2; exit}' "$ssh_config")"
52
+ root_login="$(awk 'tolower($1)=="permitrootlogin" {print $2; exit}' "$ssh_config")"
53
+ password_auth="$(awk 'tolower($1)=="passwordauthentication" {print $2; exit}' "$ssh_config")"
54
+ fi
55
+
56
+ sysreport_item "SSH port" "${ssh_port:-22}"
57
+ [[ "${ssh_port:-22}" == "22" ]] && sysreport_warn "SSH is using the default port 22" || sysreport_ok "SSH port is customized"
58
+ sysreport_item "SSH root login" "${root_login:-default}"
59
+ [[ "${root_login:-}" == "yes" ]] && sysreport_warn "PermitRootLogin is enabled" || sysreport_ok "PermitRootLogin is not explicitly enabled"
60
+ sysreport_item "SSH password auth" "${password_auth:-default}"
61
+
62
+ printf '\n'
63
+ sysreport_item "Firewall and hardening services" ""
64
+ found_security_unit=0
65
+ report_security_unit "CSF firewall" "csf.service" && found_security_unit=1
66
+ report_security_unit "LFD login failure daemon" "lfd.service" && found_security_unit=1
67
+ report_security_unit "Imunify360" "imunify360.service" && found_security_unit=1
68
+ report_security_unit "firewalld" "firewalld.service" && found_security_unit=1
69
+ report_security_unit "ufw" "ufw.service" && found_security_unit=1
70
+ [[ "$found_security_unit" -eq 0 ]] && sysreport_unknown "no common firewall or hardening service detected"
71
+
72
+ if sysreport_have fail2ban-client; then
73
+ sysreport_item "Fail2ban" "$(fail2ban-client ping 2>/dev/null | tr '\n' ' ' || echo detected)"
74
+ else
75
+ sysreport_item "Fail2ban" "not detected"
76
+ fi
77
+
78
+ printf '\n'
79
+ sysreport_item "Common exposed ports" ""
80
+ for port in 22 80 443 3306 5432 6379 8080 2083 2087; do
81
+ report_security_port "$port"
82
+ done
83
+ }
84
+
85
+ sysreport_register_section "security" "Security posture" "report_security"
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env bash
2
+
3
+ report_optimization() {
4
+ local disk_usage load_one cpu_cores swap_used disabled_funcs
5
+
6
+ sysreport_section "Optimization Checks"
7
+
8
+ disk_usage="$(df / 2>/dev/null | awk 'NR==2 {gsub("%","",$5); print $5}')"
9
+ if [[ -n "$disk_usage" && "$disk_usage" -ge 85 ]]; then
10
+ sysreport_fail "root disk usage is high (${disk_usage}%)"
11
+ elif [[ -n "$disk_usage" ]]; then
12
+ sysreport_ok "root disk usage is healthy (${disk_usage}%)"
13
+ else
14
+ sysreport_unknown "root disk usage unavailable"
15
+ fi
16
+
17
+ load_one="$(uptime 2>/dev/null | awk -F'load average: ' '{print $2}' | cut -d, -f1 | tr -d ' ')"
18
+ cpu_cores="$(nproc 2>/dev/null || echo 1)"
19
+ if [[ -n "${load_one:-}" ]] && awk "BEGIN {exit !($load_one > $cpu_cores)}" 2>/dev/null; then
20
+ sysreport_warn "1-minute load (${load_one}) is above CPU cores (${cpu_cores})"
21
+ else
22
+ sysreport_ok "1-minute load (${load_one:-unknown}) is within CPU capacity (${cpu_cores})"
23
+ fi
24
+
25
+ swap_used="$(free -m 2>/dev/null | awk '/^Swap:/ {print $3}')"
26
+ if [[ -n "$swap_used" && "$swap_used" -gt 500 ]]; then
27
+ sysreport_warn "swap usage is above 500 MB (${swap_used} MB)"
28
+ elif [[ -n "$swap_used" ]]; then
29
+ sysreport_ok "swap usage is low (${swap_used} MB)"
30
+ else
31
+ sysreport_unknown "swap usage unavailable"
32
+ fi
33
+
34
+ if pgrep -af 'redis-server|memcached' >/dev/null 2>&1; then
35
+ sysreport_ok "object cache service detected"
36
+ else
37
+ sysreport_warn "no Redis or Memcached process detected"
38
+ fi
39
+
40
+ if sysreport_have php; then
41
+ disabled_funcs="$(php -r 'echo ini_get("disable_functions");' 2>/dev/null || true)"
42
+ if [[ -z "$disabled_funcs" ]]; then
43
+ sysreport_warn "PHP disable_functions is empty"
44
+ else
45
+ sysreport_ok "PHP disable_functions is configured"
46
+ fi
47
+ else
48
+ sysreport_unknown "PHP CLI not available for PHP hardening check"
49
+ fi
50
+ }
51
+
52
+ sysreport_register_section "optimization" "Operational optimization checks" "report_optimization"