Files
cpanel-importer/tests/build-fixtures.sh

114 lines
4.0 KiB
Bash
Raw Permalink Normal View History

Initial bootstrap: cpanel-importer sanitization sandbox Skeleton for the cpanel-importer Docker container — a one-shot sandbox the WHP panel invokes BEFORE extracting a customer cpmove tarball. See cpanel-import-container-spec.md (in /workspace/) for the full design. What this ships in v1.0: - Dockerfile: almalinux:10-minimal + PHP 8.4 (Remi) + ClamAV 1.4 + SaneSecurity Foxhole.PHP rules + tar/mariadb-client/rsync. Runs as UID 999 (whp-import) via the panel-side --user 999:999 flag. - scripts/entrypoint.sh: validates env, runs (optional) freshclam, drives extract -> scan-files -> scan-dbs -> rsync -> report.json. - scripts/extract.sh + scripts/lib/scan-symlinks.php: pre-extract symlink scan ported standalone from web-files/libs/CpanelBackupImporter.php (the existing 2026-05-29 whp02 destruction-vector fix). Aborts with exit 3 before tar runs if any DANGEROUS symlink is found. - scripts/scan-files.php: ClamAV walk + classify-and-action. v1.0 ships with an empty cleaner registry — every hit is QUARANTINE_ONLY. Cleaner hooks are stubbed for v1.1. - scripts/scan-dbs.php: regex MyISAM -> InnoDB rewrite (always applied), WordPress identification, and ONE WP content scan check (siteurl_external_domain). v1.1 will grow the check set. - scripts/lib/safety-net.php: container-narrow open_basedir allow-list, much tighter than the panel-side one. - .gitea/workflows/build-push.yaml: builds + smoke-tests + PHP-syntax-checks + bash-syntax-checks before pushing to repo.anhonesthost.net/cloud-hosting-platform/cpanel-importer. - tests/build-fixtures.sh: builds cpmove-clean.tar.gz (benign WP dump) and cpmove-alfa.tar.gz (the ALFA-shell symlink-to-/etc vector) for local end-to-end testing. - README.md / CONTRIBUTING.md: docker-run invocation, bind-mount catalog, report.json schema, how to add a cleaner pattern or a WP scan signature. Local acceptance test results: - clean fixture -> status=completed, 3 MyISAM->InnoDB, no flags, 0 - ALFA fixture -> exit 1, status=failed, failed_stage=extract, "tarball contains dangerous symlinks; aborting" on stderr - compromised-siteurl fixture -> imported_into_new_server=false, .flagged file written, summary_for_panel.show_alert=true Image size: 197 MB compressed (gzipped docker save), ~397 MB unique layers extracted. Well under the spec's 600 MB compressed / 1.2 GB extracted budget. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-30 19:56:57 -07:00
#!/usr/bin/env bash
#
# build-fixtures.sh — generate synthetic cpmove tarballs for testing.
#
# Two fixtures are built:
#
# cpmove-clean.tar.gz — a minimal cpmove with a benign homedir, one
# wp-style SQL dump with ENGINE=MyISAM tables
# and a clean siteurl, and a user-internal
# relative symlink (must not trigger).
#
# cpmove-alfa.tar.gz — same shape PLUS an ALFA-style symlink:
# `cpmove-testuser/homedir/.../alfasymlink -> /etc`
# — the pre-extract scan MUST refuse this.
#
# Run: bash tests/build-fixtures.sh
# Output: tests/fixtures/cpmove-clean.tar.gz, tests/fixtures/cpmove-alfa.tar.gz
set -euo pipefail
FIXTURES_DIR="$(cd "$(dirname "$0")" && pwd)/fixtures"
mkdir -p "$FIXTURES_DIR"
USER=testuser
DOMAIN=example.com
build_common_tree() {
local root="$1"
mkdir -p "$root/cpmove-$USER"/{homedir/public_html,mysql,userdata,addons,sds,ssl}
# main userdata
cat > "$root/cpmove-$USER/userdata/main" <<EOF
main_domain: $DOMAIN
user: $USER
EOF
# per-domain userdata file
cat > "$root/cpmove-$USER/userdata/$DOMAIN" <<EOF
servername: $DOMAIN
documentroot: /home/$USER/public_html
user: $USER
EOF
# benign content
echo "<?php phpinfo();" > "$root/cpmove-$USER/homedir/public_html/index.php"
echo "Hello world." > "$root/cpmove-$USER/homedir/public_html/about.txt"
# benign user-internal relative symlink — must NOT trigger the scan
ln -sf "../public_html/about.txt" "$root/cpmove-$USER/homedir/about-shortcut"
# one synthetic WordPress mysql dump with ENGINE=MyISAM + a clean siteurl
cat > "$root/cpmove-$USER/mysql/${USER}_wp.sql" <<EOF
-- Synthetic WP dump for cpanel-importer fixtures.
CREATE TABLE \`wp_options\` (
option_id bigint(20) NOT NULL,
option_name varchar(191) NOT NULL,
option_value longtext NOT NULL,
autoload varchar(20) NOT NULL DEFAULT 'yes'
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
CREATE TABLE \`wp_posts\` (
ID bigint(20) NOT NULL,
post_content longtext NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
CREATE TABLE \`wp_users\` (
ID bigint(20) NOT NULL,
user_login varchar(60) NOT NULL,
user_pass varchar(255) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
INSERT INTO \`wp_options\` (option_id, option_name, option_value, autoload) VALUES
(1, 'siteurl', 'https://$DOMAIN', 'yes'),
(2, 'home', 'https://$DOMAIN', 'yes'),
(3, 'blogname', 'Hello', 'yes'),
(4, 'template', 'twentytwentyfour', 'yes'),
(5, 'stylesheet', 'twentytwentyfour', 'yes');
INSERT INTO \`wp_users\` VALUES (1, 'admin', 'doesnotmatter');
EOF
}
# ---- cpmove-clean.tar.gz --------------------------------------------------
CLEAN_TMP="$(mktemp -d)"
trap 'rm -rf "$CLEAN_TMP" "$ALFA_TMP" 2>/dev/null || true' EXIT
build_common_tree "$CLEAN_TMP"
tar -C "$CLEAN_TMP" -czf "$FIXTURES_DIR/cpmove-clean.tar.gz" "cpmove-$USER"
echo "wrote $FIXTURES_DIR/cpmove-clean.tar.gz ($(stat -c%s "$FIXTURES_DIR/cpmove-clean.tar.gz") bytes)"
# ---- cpmove-alfa.tar.gz ---------------------------------------------------
#
# Build the SAME tree, then add an ALFA-shell-style symlink pointing at
# /etc. This is the exact vector that wiped whp02 — the importer's
# recursive walker followed the symlink and unlink()'d every file in
# /etc. Our pre-extract scan MUST refuse to extract this tarball.
ALFA_TMP="$(mktemp -d)"
build_common_tree "$ALFA_TMP"
mkdir -p "$ALFA_TMP/cpmove-$USER/homedir/public_html/$DOMAIN/ALFA_DATA"
echo "<?php /* ALFA shell stub */ ?>" \
> "$ALFA_TMP/cpmove-$USER/homedir/public_html/$DOMAIN/ALFA_DATA/index.php"
# THE attack: absolute-target symlink to /etc.
ln -sf "/etc" "$ALFA_TMP/cpmove-$USER/homedir/public_html/$DOMAIN/ALFA_DATA/root"
tar -C "$ALFA_TMP" -czf "$FIXTURES_DIR/cpmove-alfa.tar.gz" "cpmove-$USER"
echo "wrote $FIXTURES_DIR/cpmove-alfa.tar.gz ($(stat -c%s "$FIXTURES_DIR/cpmove-alfa.tar.gz") bytes)"
echo ""
echo "fixtures built:"
ls -la "$FIXTURES_DIR"