extract: opt-in mail tree (IMPORT_INCLUDE_MAIL=true) + mail_included marker
WHP's cPanel mailbox import needs cpmove-*/homedir/mail, which extract.sh always excluded: in sanitization-container mode every mailbox was queued with no Maildir and "verified" empty (B5, whp02 canary 2026-10-20). - IMPORT_INCLUDE_MAIL=true (exactly "true"; default off) keeps the mail tree in the extract. Default behaviour is unchanged. The DANGEROUS symlink strips still apply inside the mail tree (scan-symlinks.php lists every archive entry). - scan-files.php --skip-mail (passed by entrypoint.sh with the opt-in): clamscan --exclude-dir for the mail tree, the file count skips it, and a hit inside it is never quarantined. Logged with the reason: mail is copied verbatim into the customer's own mailbox and verified against the source, and multi-GB maildirs would dominate the run. - report.json gains "mail_included" (true only with the opt-in) so the panel can tell this image from an older one, which never writes the key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
08b995a29c
commit
8217397154
5 files changed
+111
-22
No files matched your search
+25
-2
@@ -8,6 +8,11 @@
|
||||
# IMPORT_BACKUP_FILE absolute path inside the container, typically
|
||||
# /host/backup/cpmove-<user>.tar.gz
|
||||
# CLAMAV_REFRESH "true" to run freshclam at start (default: true)
|
||||
# IMPORT_INCLUDE_MAIL "true" to extract cpmove-*/homedir/mail for WHP's
|
||||
# mailbox import (default: false = mail tree skipped).
|
||||
# The mail tree is never ClamAV-scanned. report.json
|
||||
# records "mail_included" so the panel can tell this
|
||||
# image (which honours the opt-in) from an older one.
|
||||
#
|
||||
# Flow (spec §0):
|
||||
# 1. validate env
|
||||
@@ -71,8 +76,15 @@ log "cpanel-importer starting (container UID=$(id -u) GID=$(id -g))"
|
||||
: "${IMPORT_USERNAME:?IMPORT_USERNAME env var is required}"
|
||||
: "${IMPORT_BACKUP_FILE:?IMPORT_BACKUP_FILE env var is required}"
|
||||
CLAMAV_REFRESH="${CLAMAV_REFRESH:-true}"
|
||||
# Exactly "true" opts in; anything else is the default (no mail tree).
|
||||
if [[ "${IMPORT_INCLUDE_MAIL:-false}" == "true" ]]; then
|
||||
IMPORT_INCLUDE_MAIL=true
|
||||
else
|
||||
IMPORT_INCLUDE_MAIL=false
|
||||
fi
|
||||
export IMPORT_INCLUDE_MAIL
|
||||
|
||||
log "import_id=$IMPORT_ID username=$IMPORT_USERNAME backup=$IMPORT_BACKUP_FILE"
|
||||
log "import_id=$IMPORT_ID username=$IMPORT_USERNAME backup=$IMPORT_BACKUP_FILE include_mail=$IMPORT_INCLUDE_MAIL"
|
||||
|
||||
if [[ ! -f "$IMPORT_BACKUP_FILE" ]]; then
|
||||
die "backup file does not exist or is not a regular file: $IMPORT_BACKUP_FILE"
|
||||
@@ -140,11 +152,17 @@ fi
|
||||
|
||||
STAGE="scan_files"
|
||||
log "stage: scan_files"
|
||||
SCAN_FILES_EXTRA=()
|
||||
if [[ "$IMPORT_INCLUDE_MAIL" == "true" ]]; then
|
||||
# The extracted mail tree is not scanned (see scan-files.php --skip-mail).
|
||||
SCAN_FILES_EXTRA+=(--skip-mail)
|
||||
fi
|
||||
php /scripts/scan-files.php \
|
||||
--extract "$EXTRACT_DIR" \
|
||||
--quarantine "$QUARANTINE_DIR" \
|
||||
--report /tmp/scan-files-report.json \
|
||||
--import-id "$IMPORT_ID" \
|
||||
"${SCAN_FILES_EXTRA[@]}" \
|
||||
|| die "scan-files.php failed; see stderr above"
|
||||
|
||||
# --- DB engine swap + WP content scan -------------------------------------
|
||||
@@ -192,6 +210,7 @@ $filesPath = $argv[3];
|
||||
$dbsPath = $argv[4];
|
||||
$strippedPath = $argv[5];
|
||||
$outPath = $argv[6];
|
||||
$mailIncluded = $argv[7] === "true";
|
||||
|
||||
$files = is_file($filesPath) ? json_decode(file_get_contents($filesPath), true) : null;
|
||||
$dbs = is_file($dbsPath) ? json_decode(file_get_contents($dbsPath), true) : null;
|
||||
@@ -252,6 +271,10 @@ $report = [
|
||||
"files_clean" => $filesClean,
|
||||
"files_cleaned" => $filesCleaned,
|
||||
"files_quarantined" => $filesQuarantined,
|
||||
// true only when IMPORT_INCLUDE_MAIL=true AND this image extracted the
|
||||
// mail tree. Older images never write the key; the panel treats a
|
||||
// missing/false value as "mail was not extracted".
|
||||
"mail_included" => $mailIncluded,
|
||||
"actions" => $actions,
|
||||
"databases" => $databases,
|
||||
"summary_for_panel" => [
|
||||
@@ -263,7 +286,7 @@ $report = [
|
||||
|
||||
file_put_contents($outPath, json_encode($report, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n");
|
||||
fprintf(STDERR, "report written: %s\n", $outPath);
|
||||
' "$IMPORT_ID" "$DURATION" /tmp/scan-files-report.json /tmp/scan-dbs-report.json "$STRIPPED_SYMLINKS_FILE" "$SANITIZED_DIR/report.json" \
|
||||
' "$IMPORT_ID" "$DURATION" /tmp/scan-files-report.json /tmp/scan-dbs-report.json "$STRIPPED_SYMLINKS_FILE" "$SANITIZED_DIR/report.json" "$IMPORT_INCLUDE_MAIL" \
|
||||
|| die "report merge failed"
|
||||
|
||||
log "done — exited cleanly after ${DURATION}s"
|
||||
|
||||
Reference in new issue
Block a user