#!/bin/bash # SPDX-Version: 3.0 # SPDX-CreationInfo: 2026-06-11; WEIDNER, Marc S.; # SPDX-ExternalRef: GIT https://git.coresecret.dev/msw/CISS.debian.live.builder.git # SPDX-FileContributor: WEIDNER, Marc S.; Centurion Intelligence Consulting Agency # SPDX-FileCopyrightText: 2024-2026; WEIDNER, Marc S.; # SPDX-FileType: SOURCE # SPDX-License-Identifier: LicenseRef-CNCL-1.1 OR LicenseRef-CCLA-1.1 # SPDX-LicenseComment: This file is part of the CISS.debian.installer.secure framework. # SPDX-PackageName: CISS.debian.live.builder # SPDX-Security-Contact: security@coresecret.eu # shellcheck disable=SC2154 # Function behavior: # debug_sanitize_escape_glob(): Escape Bash glob metacharacters so exact values can be used safely in parameter-substitution matches. # debug_sanitize_read_file(): Read a text file into a named variable while preserving trailing newline bytes. # debug_sanitize_add_secret(): Add one non-empty exact secret value to the in-memory redaction list, avoiding duplicates. # debug_sanitize_add_secret_file(): Add the exact content of a regular, non-symlink secret file to the redaction list. # debug_sanitize_collect_secrets(): Add controlled secret variables and secret-file contents to the redaction list. # collect_debug_secret_values(): Collect exact secret values while xtrace is temporarily disabled. # finalize_debug_xtrace_logging(): Permanently disable xtrace and close the xtrace log FD before rewriting logs. # debug_sanitize_log_file(): Redact collected exact secret values from one log file and restrict its permissions. # sanitize_debug_logs(): Run the final exact-value sanitization pass across closed debug, variable, and error logs. guard_sourcing || return "${ERR_GUARD_SRCE}" declare -ga _ARY_DEBUG_SECRET_VALUES=() declare -g _VAR_DEBUG_XTRACE_FINALIZED="false" ####################################### # Escape Bash glob metacharacters for exact parameter-substitution matching. # Globals: # None # Arguments: # 1: Raw value. # Returns: # 0: on success ####################################### debug_sanitize_escape_glob() { declare value="${1}" value="${value//\\/\\\\}" value="${value//\*/\\*}" value="${value//\?/\\?}" value="${value//\[/\\[}" value="${value//\]/\\]}" printf '%s' "${value}" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_escape_glob ####################################### # Read a text file into a variable, preserving trailing newlines. # Globals: # None # Arguments: # 1: File path. # 2: Output variable name. # Returns: # 0: on success ####################################### debug_sanitize_read_file() { declare file_path="${1}" output_var="${2}" content="" IFS= read -r -d '' content < "${file_path}" || true printf -v "${output_var}" '%s' "${content}" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_read_file ####################################### # Add one exact secret value to the redaction list. # Globals: # _ARY_DEBUG_SECRET_VALUES # Arguments: # 1: Secret value. # Returns: # 0: on success ####################################### debug_sanitize_add_secret() { declare secret_value="${1}" known_value="" [[ -n "${secret_value}" ]] || return 0 for known_value in "${_ARY_DEBUG_SECRET_VALUES[@]:-}"; do [[ "${known_value}" == "${secret_value}" ]] && return 0 done _ARY_DEBUG_SECRET_VALUES+=("${secret_value}") return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_add_secret ####################################### # Add a secret file's exact content to the redaction list. # Globals: # _ARY_DEBUG_SECRET_VALUES # Arguments: # 1: File path. # Returns: # 0: on success ####################################### debug_sanitize_add_secret_file() { declare file_path="${1}" secret_value="" [[ -n "${file_path}" && -f "${file_path}" && ! -L "${file_path}" ]] || return 0 [[ -s "${file_path}" ]] || return 0 debug_sanitize_read_file "${file_path}" secret_value debug_sanitize_add_secret "${secret_value}" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_add_secret_file ####################################### # Gather exact values from controlled secret variables and files. # Globals: # _ARY_DEBUG_SECRET_VALUES # VAR_HASHED_PWD # VAR_SIGNING_KEY_PASSFILE # VAR_TMP_SECRET # Arguments: # None # Returns: # 0: on success ####################################### debug_sanitize_collect_secrets() { declare secret_file="" if [[ -n "${VAR_HASHED_PWD:-}" ]]; then debug_sanitize_add_secret "${VAR_HASHED_PWD}" fi if [[ -n "${VAR_SIGNING_KEY_PASSFILE:-}" ]]; then debug_sanitize_add_secret_file "${VAR_SIGNING_KEY_PASSFILE}" fi if [[ -n "${VAR_TMP_SECRET:-}" && -d "${VAR_TMP_SECRET}" && ! -L "${VAR_TMP_SECRET}" ]]; then while IFS= read -r -d '' secret_file; do debug_sanitize_add_secret_file "${secret_file}" done < <(find "${VAR_TMP_SECRET}" -xdev -type f -print0 2>/dev/null || true) fi return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_collect_secrets ####################################### # Collect exact secret values without tracing secret-bearing operations. # Globals: # _VAR_DEBUG_XTRACE_FINALIZED # Arguments: # None # Returns: # 0: on success ####################################### collect_debug_secret_values() { declare tracing_was_enabled="false" case "$-" in *x*) tracing_was_enabled="true" set +x ;; *) ;; esac debug_sanitize_collect_secrets || true if [[ "${tracing_was_enabled}" == "true" && "${_VAR_DEBUG_XTRACE_FINALIZED}" != "true" ]]; then set -x fi return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f collect_debug_secret_values ####################################### # Permanently stop xtrace logging before the final log rewrite. # Globals: # BASH_XTRACEFD # _VAR_DEBUG_XTRACE_FINALIZED # Arguments: # None # Returns: # 0: on success ####################################### finalize_debug_xtrace_logging() { declare xtrace_fd="" set +x if [[ "${BASH_XTRACEFD:-}" =~ ^[0-9]+$ ]]; then xtrace_fd="${BASH_XTRACEFD}" unset BASH_XTRACEFD if (( xtrace_fd > 2 )); then exec {xtrace_fd}>&- 2>/dev/null || true fi fi _VAR_DEBUG_XTRACE_FINALIZED="true" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f finalize_debug_xtrace_logging ####################################### # Redact exact secret values from one log file. # Globals: # _ARY_DEBUG_SECRET_VALUES # Arguments: # 1: Log file path. # Returns: # 0: on success ####################################### debug_sanitize_log_file() { declare log_file="${1}" log_content="" secret_value="" secret_pattern="" redaction="" declare -i secret_len=0 [[ -n "${log_file}" && -f "${log_file}" && ! -L "${log_file}" ]] || return 0 debug_sanitize_read_file "${log_file}" log_content for secret_value in "${_ARY_DEBUG_SECRET_VALUES[@]:-}"; do [[ -n "${secret_value}" ]] || continue secret_pattern="$(debug_sanitize_escape_glob "${secret_value}")" secret_len="${#secret_value}" printf -v redaction '%*s' "${secret_len}" '' redaction="${redaction// /*}" log_content="${log_content//${secret_pattern}/${redaction}}" done printf '%s' "${log_content}" >| "${log_file}" chmod 0600 "${log_file}" 2>/dev/null || true return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f debug_sanitize_log_file ####################################### # Final exact-value debug log sanitization pass. # Globals: # LOG_DEBUG # LOG_ERROR # LOG_VAR # Arguments: # None # Returns: # 0: on success ####################################### sanitize_debug_logs() { declare old_lc_all="${LC_ALL:-}" log_file="" finalize_debug_xtrace_logging || true LC_ALL=C debug_sanitize_collect_secrets || true for log_file in "${LOG_DEBUG:-}" "${LOG_VAR:-}" "${LOG_ERROR:-}"; do debug_sanitize_log_file "${log_file}" || true done LC_ALL="${old_lc_all}" return 0 } ### Prevents accidental 'unset -f'. # shellcheck disable=SC2034 readonly -f sanitize_debug_logs # vim: number et ts=2 sw=2 sts=2 ai tw=128 ft=sh