V9.14.022.2026.06.11: document and test audit safeguards
This commit is contained in:
@@ -60,12 +60,15 @@ and spoofing surfaces.
|
|||||||
|
|
||||||
Internally, the builder employs a dedicated secret-handling pipeline backed by a tmpfs-only secrets directory
|
Internally, the builder employs a dedicated secret-handling pipeline backed by a tmpfs-only secrets directory
|
||||||
(`/dev/shm/cdlb_secrets`). Sensitive material such as root passwords, SSH keys, and signing keys never appears on the command
|
(`/dev/shm/cdlb_secrets`). Sensitive material such as root passwords, SSH keys, and signing keys never appears on the command
|
||||||
line, is guarded by strict `0400 root:root` permissions, and any symlink inside the secret path is treated as a hard failure
|
line, is guarded by a `0700 root:root` secret root and single-link regular `0400` or `0600` root-owned files, and any symlink
|
||||||
that aborts the run. Critical code paths temporarily disable Bash xtrace so that credentials never leak into debug logs, and
|
inside the secret path is treated as a hard failure that aborts the run. Filename-only secret arguments reject slashes and
|
||||||
transient secret files are shredded (`shred -fzu`) as soon as they are no longer needed. GNUPG homes used for signing are
|
traversal.
|
||||||
wiped, unencrypted chroot artifacts and includes are removed after `lb build`, and the final artifact is reduced to the
|
Critical code paths temporarily disable Bash xtrace, and a final exact-value debug-log sanitisation pass provides additional
|
||||||
encrypted SquashFS inside the LUKS2 container. At runtime, LUKS passphrases in the live ISO and installer are transported via
|
defence in depth. Transient secret files are shredded (`shred -fzu`) as soon as they are no longer needed, but this is only a
|
||||||
named pipes inside the initramfs instead of process arguments, further minimizing exposure in process listings.
|
best-effort cleanup on SSD, NVMe, copy-on-write, journaled, and virtualised storage. Use tmpfs for secrets and encrypted storage
|
||||||
|
for build workspaces. Destructive build cleanup is restricted to the exact canonical directory carrying the
|
||||||
|
`.ciss-live-builder-owned` marker. This private operator workflow still requires strict local path validation; it does not
|
||||||
|
define public ISO release policy.
|
||||||
|
|
||||||
Check out more leading world-class services powered by Centurion Intelligence Consulting Agency:
|
Check out more leading world-class services powered by Centurion Intelligence Consulting Agency:
|
||||||
* [CenturionDNS Resolver](https://eddns.eu/)
|
* [CenturionDNS Resolver](https://eddns.eu/)
|
||||||
@@ -493,10 +496,14 @@ To use **``CISS.debian.live.builder``** as intended, the following baseline is e
|
|||||||
|
|
||||||
2. Preparation:
|
2. Preparation:
|
||||||
1. Ensure you are root.
|
1. Ensure you are root.
|
||||||
2. Create the build directory `mkdir /opt/cdlb` and the tmpfs secrets directory `mkdir /dev/shm/cdlb_secrets`.
|
2. Create the empty build directory with `install -d -m 0700 -o root -g root /opt/cdlb`.
|
||||||
3. Place your desired SSH public key in the `authorized_keys` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
3. Create the tmpfs secret root with `install -d -m 0700 -o root -g root /dev/shm/cdlb_secrets`.
|
||||||
4. Place your desired Password in the `password.txt` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
4. Place required secret files in the secret root as single-link regular, non-symlink, root-owned files with mode `0400`
|
||||||
5. Make any other changes you need to.
|
or `0600`.
|
||||||
|
5. Place your desired SSH public key in `/dev/shm/cdlb_secrets/authorized_keys`.
|
||||||
|
6. Place your desired root password in `/dev/shm/cdlb_secrets/password.txt`.
|
||||||
|
7. Use filename-only values without slashes, `.` or `..` for `--key_age`, `--key_luks`, and signing-file arguments.
|
||||||
|
8. Make any other changes you need to.
|
||||||
|
|
||||||
3. Run the config builder script `./ciss_live_builder.sh` and the integrated `lb build` command (example):
|
3. Run the config builder script `./ciss_live_builder.sh` and the integrated `lb build` command (example):
|
||||||
|
|
||||||
@@ -538,6 +545,10 @@ To use **``CISS.debian.live.builder``** as intended, the following baseline is e
|
|||||||
both the newer Sigstore bundle asset, and the legacy-split certificate/signature assets before checking the downloaded
|
both the newer Sigstore bundle asset, and the legacy-split certificate/signature assets before checking the downloaded
|
||||||
SOPS binary with `sha256sum -c --ignore-missing`.
|
SOPS binary with `sha256sum -c --ignore-missing`.
|
||||||
|
|
||||||
|
On the first run, the builder creates `.ciss-live-builder-owned` in a new or empty build directory whose canonical parent
|
||||||
|
already exists. A populated directory without that marker is rejected and is never adopted automatically. Cleanup remains
|
||||||
|
intentionally destructive inside the exact validated marker-owned directory.
|
||||||
|
|
||||||
4. Locate your ISO in the `--build-directory`.
|
4. Locate your ISO in the `--build-directory`.
|
||||||
5. Boot from the ISO and login to the live image via the console, or the multi-layer secured **coresecret** SSH tunnel.
|
5. Boot from the ISO and login to the live image via the console, or the multi-layer secured **coresecret** SSH tunnel.
|
||||||
6. Type `sysp` for the final kernel hardening features.
|
6. Type `sysp` for the final kernel hardening features.
|
||||||
@@ -559,7 +570,8 @@ preview it or run it.
|
|||||||
|
|
||||||
2. Preparation:
|
2. Preparation:
|
||||||
1. Ensure you are root.
|
1. Ensure you are root.
|
||||||
2. Create the build directory `mkdir /opt/cdlb` and the tmpfs secrets directory `mkdir /dev/shm/cdlb_secrets`.
|
2. Create the empty build directory and tmpfs secret root with restrictive ownership and permissions:
|
||||||
|
`install -d -m 0700 -o root -g root /opt/cdlb /dev/shm/cdlb_secrets`.
|
||||||
3. Place your desired SSH public key in the `authorized_keys` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
3. Place your desired SSH public key in the `authorized_keys` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
||||||
4. Place your desired Password in the `password.txt` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
4. Place your desired Password in the `password.txt` file, for example, in the `/dev/shm/cdlb_secrets` directory.
|
||||||
5. Copy and edit the sample and set your options (no spaces around commas in lists):
|
5. Copy and edit the sample and set your options (no spaces around commas in lists):
|
||||||
@@ -656,10 +668,10 @@ The private directory is ignored by Git. The hooks fail if the CISS EFI image si
|
|||||||
#...
|
#...
|
||||||
- name: Preparing the build environment.
|
- name: Preparing the build environment.
|
||||||
run: |
|
run: |
|
||||||
mkdir -p /opt/config
|
install -d -m 0700 -o root -g root /opt/livebuild /dev/shm/cdlb_secrets
|
||||||
mkdir -p /opt/livebuild
|
umask 0077
|
||||||
echo "${{ secrets.CHANGE_ME }}" >| /opt/config/password.txt
|
printf '%s\n' "${{ secrets.CHANGE_ME }}" >| /dev/shm/cdlb_secrets/password.txt
|
||||||
echo "${{ secrets.CHANGE_ME }}" >| /opt/config/authorized_keys
|
printf '%s\n' "${{ secrets.CHANGE_ME }}" >| /dev/shm/cdlb_secrets/authorized_keys
|
||||||
#...
|
#...
|
||||||
- name: Starting CISS.debian.live.builder. This may take a while ...
|
- name: Starting CISS.debian.live.builder. This may take a while ...
|
||||||
run: |
|
run: |
|
||||||
@@ -672,9 +684,9 @@ The private directory is ignored by Git. The hooks fail if the CISS EFI image si
|
|||||||
--build-directory /opt/livebuild \
|
--build-directory /opt/livebuild \
|
||||||
--control "${timestamp}" \
|
--control "${timestamp}" \
|
||||||
--jump-host "${{ secrets.CHANGE_ME }}" \
|
--jump-host "${{ secrets.CHANGE_ME }}" \
|
||||||
--root-password-file /opt/config/password.txt \
|
--root-password-file /dev/shm/cdlb_secrets/password.txt \
|
||||||
--ssh-port CHANGE_ME \
|
--ssh-port CHANGE_ME \
|
||||||
--ssh-pubkey /opt/config
|
--ssh-pubkey /dev/shm/cdlb_secrets
|
||||||
#...
|
#...
|
||||||
### SKIP OR CHANGE ALL REMAINING STEPS
|
### SKIP OR CHANGE ALL REMAINING STEPS
|
||||||
```
|
```
|
||||||
|
|||||||
+13
-2
@@ -37,6 +37,10 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
|
|
||||||
--build-directory </path/to/build_directory>
|
--build-directory </path/to/build_directory>
|
||||||
Where the Debian Live Build Image should be generated. RECOMMENDED path: </opt/cdlb>
|
Where the Debian Live Build Image should be generated. RECOMMENDED path: </opt/cdlb>
|
||||||
|
The path MUST be canonical and dedicated to the builder; a new directory's canonical parent MUST already exist.
|
||||||
|
New or empty directories receive the
|
||||||
|
'.ciss-live-builder-owned' marker; populated unmarked directories are rejected. Cleanup is intentionally destructive
|
||||||
|
only inside the exact validated marker-owned directory.
|
||||||
MUST be provided.
|
MUST be provided.
|
||||||
|
|
||||||
--change-splash <STRING> one of <club | hexagon>
|
--change-splash <STRING> one of <club | hexagon>
|
||||||
@@ -57,6 +61,7 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
--debug, -d
|
--debug, -d
|
||||||
Enables debug logging for the main program routine. Detailed logging information are written to:
|
Enables debug logging for the main program routine. Detailed logging information are written to:
|
||||||
</tmp/ciss_live_builder_1801049.log>
|
</tmp/ciss_live_builder_1801049.log>
|
||||||
|
A final exact-value sanitisation pass is defence in depth and does not replace careful tracing discipline.
|
||||||
|
|
||||||
--dhcp-centurion
|
--dhcp-centurion
|
||||||
If a DHCP lease is provided, the provider's name server will be overridden and the hardened, privacy-focused
|
If a DHCP lease is provided, the provider's name server will be overridden and the hardened, privacy-focused
|
||||||
@@ -86,11 +91,13 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
|
|
||||||
--key_age=*
|
--key_age=*
|
||||||
The SOPS AGE private keyring for decryption operations. Change '*' to your desired SOPS AGE key file.
|
The SOPS AGE private keyring for decryption operations. Change '*' to your desired SOPS AGE key file.
|
||||||
|
'*' MUST be a filename only without slashes, '.' or '..' traversal.
|
||||||
File MUST be placed in:
|
File MUST be placed in:
|
||||||
</dev/shm/cdlb_secrets>
|
</dev/shm/cdlb_secrets>
|
||||||
|
|
||||||
--key_luks=*
|
--key_luks=*
|
||||||
The LUKS encryption / decryption passphrase for '/'-fs-encryption. Change '*' to your desired passphrase file.
|
The LUKS encryption / decryption passphrase for '/'-fs-encryption. Change '*' to your desired passphrase file.
|
||||||
|
'*' MUST be a filename only without slashes, '.' or '..' traversal.
|
||||||
File MUST be placed in:
|
File MUST be placed in:
|
||||||
</dev/shm/cdlb_secrets>
|
</dev/shm/cdlb_secrets>
|
||||||
|
|
||||||
@@ -140,7 +147,7 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
--root-password-file </dev/shm/cdlb_secrets/password.txt>>
|
--root-password-file </dev/shm/cdlb_secrets/password.txt>>
|
||||||
Password file for 'root', if given, MUST be a string of 42 to 64 characters.
|
Password file for 'root', if given, MUST be a string of 42 to 64 characters.
|
||||||
If the argument is omitted, no further login authentication is required for the local console.
|
If the argument is omitted, no further login authentication is required for the local console.
|
||||||
MUST be placed in:
|
Safe absolute paths remain supported and are validated separately. RECOMMENDED path:
|
||||||
</dev/shm/cdlb_secrets/password.txt>
|
</dev/shm/cdlb_secrets/password.txt>
|
||||||
|
|
||||||
--secure-boot-profile <STRING> one of <debian-shim | ciss-uki>
|
--secure-boot-profile <STRING> one of <debian-shim | ciss-uki>
|
||||||
@@ -156,7 +163,8 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
specified via '--signing_key=*'. If the keyring is protected, then provide the passphrase in its own file.
|
specified via '--signing_key=*'. If the keyring is protected, then provide the passphrase in its own file.
|
||||||
Specify the fingerprint of the key to use via '--signing_key_fpr=*'.
|
Specify the fingerprint of the key to use via '--signing_key_fpr=*'.
|
||||||
Optionally import an offline GPG CA signing public key via: '--signing_ca=*'.
|
Optionally import an offline GPG CA signing public key via: '--signing_ca=*'.
|
||||||
Change '*' to your desired files / fingerprint. Files MUST be placed in:
|
Change '*' to your desired filename-only files / fingerprint. Filename-only values MUST NOT contain slashes or traversal.
|
||||||
|
Files MUST be placed in:
|
||||||
</dev/shm/cdlb_secrets>
|
</dev/shm/cdlb_secrets>
|
||||||
|
|
||||||
--sshfp
|
--sshfp
|
||||||
@@ -182,6 +190,9 @@ A lightweight Shell Wrapper for building a hardened Debian Live ISO Image.
|
|||||||
|
|
||||||
💡 Notes:
|
💡 Notes:
|
||||||
🔵 You MUST be 'root' to run this script.
|
🔵 You MUST be 'root' to run this script.
|
||||||
|
🔵 Private operator control does not remove the requirement for strict local secret path validation.
|
||||||
|
🔵 '/dev/shm/cdlb_secrets' MUST be tmpfs-backed, root-owned, mode 0700, and contain only single-link regular non-symlink files
|
||||||
|
with mode 0400 or 0600. Secure deletion with shred is best-effort only on modern storage.
|
||||||
|
|
||||||
💷 Please consider donating to my work at:
|
💷 Please consider donating to my work at:
|
||||||
🌐 https://coresecret.eu/spenden/
|
🌐 https://coresecret.eu/spenden/
|
||||||
|
|||||||
+13
-2
@@ -67,6 +67,10 @@ usage() {
|
|||||||
echo
|
echo
|
||||||
echo -e "\e[97m --build-directory </path/to/build_directory> \e[0m"
|
echo -e "\e[97m --build-directory </path/to/build_directory> \e[0m"
|
||||||
echo " Where the Debian Live Build Image should be generated. RECOMMENDED path: </opt/cdlb>"
|
echo " Where the Debian Live Build Image should be generated. RECOMMENDED path: </opt/cdlb>"
|
||||||
|
echo " The path MUST be canonical and dedicated to the builder; a new directory's canonical parent MUST already exist."
|
||||||
|
echo " New or empty directories receive the"
|
||||||
|
echo " '.ciss-live-builder-owned' marker; populated unmarked directories are rejected. Cleanup is intentionally"
|
||||||
|
echo " destructive only inside the exact validated marker-owned directory."
|
||||||
echo " MUST be provided."
|
echo " MUST be provided."
|
||||||
echo
|
echo
|
||||||
echo -e "\e[97m --change-splash <STRING> one of <club | hexagon> \e[0m"
|
echo -e "\e[97m --change-splash <STRING> one of <club | hexagon> \e[0m"
|
||||||
@@ -87,6 +91,7 @@ usage() {
|
|||||||
echo -e "\e[97m --debug, -d \e[0m"
|
echo -e "\e[97m --debug, -d \e[0m"
|
||||||
echo " Enables debug logging for the main program routine. Detailed logging information are written to:"
|
echo " Enables debug logging for the main program routine. Detailed logging information are written to:"
|
||||||
echo " </tmp/ciss_live_builder_$$.log>"
|
echo " </tmp/ciss_live_builder_$$.log>"
|
||||||
|
echo " A final exact-value sanitisation pass is defence in depth and does not replace careful tracing discipline."
|
||||||
echo
|
echo
|
||||||
echo -e "\e[97m --dhcp-centurion \e[0m"
|
echo -e "\e[97m --dhcp-centurion \e[0m"
|
||||||
echo " If a DHCP lease is provided, the provider's name server will be overridden and the hardened, privacy-focused "
|
echo " If a DHCP lease is provided, the provider's name server will be overridden and the hardened, privacy-focused "
|
||||||
@@ -108,11 +113,13 @@ usage() {
|
|||||||
echo
|
echo
|
||||||
echo -e "\e[97m --key_age=* \e[0m"
|
echo -e "\e[97m --key_age=* \e[0m"
|
||||||
echo " The SOPS AGE private keyring for decryption operations. Change '*' to your desired SOPS AGE key file."
|
echo " The SOPS AGE private keyring for decryption operations. Change '*' to your desired SOPS AGE key file."
|
||||||
|
echo " '*' MUST be a filename only without slashes, '.' or '..' traversal."
|
||||||
echo " File MUST be placed in:"
|
echo " File MUST be placed in:"
|
||||||
echo " </dev/shm/cdlb_secrets>"
|
echo " </dev/shm/cdlb_secrets>"
|
||||||
echo
|
echo
|
||||||
echo -e "\e[97m --key_luks=* \e[0m"
|
echo -e "\e[97m --key_luks=* \e[0m"
|
||||||
echo " The LUKS encryption / decryption passphrase for '/'-fs-encryption. Change '*' to your desired passphrase file."
|
echo " The LUKS encryption / decryption passphrase for '/'-fs-encryption. Change '*' to your desired passphrase file."
|
||||||
|
echo " '*' MUST be a filename only without slashes, '.' or '..' traversal."
|
||||||
echo " File MUST be placed in:"
|
echo " File MUST be placed in:"
|
||||||
echo " </dev/shm/cdlb_secrets>"
|
echo " </dev/shm/cdlb_secrets>"
|
||||||
echo
|
echo
|
||||||
@@ -162,7 +169,7 @@ usage() {
|
|||||||
echo -e "\e[97m --root-password-file </dev/shm/cdlb_secrets/password.txt>> \e[0m"
|
echo -e "\e[97m --root-password-file </dev/shm/cdlb_secrets/password.txt>> \e[0m"
|
||||||
echo " Password file for 'root', if given, MUST be a string of 42 to 64 characters."
|
echo " Password file for 'root', if given, MUST be a string of 42 to 64 characters."
|
||||||
echo " If the argument is omitted, no further login authentication is required for the local console."
|
echo " If the argument is omitted, no further login authentication is required for the local console."
|
||||||
echo " MUST be placed in:"
|
echo " Safe absolute paths remain supported and are validated separately. RECOMMENDED path:"
|
||||||
echo " </dev/shm/cdlb_secrets/password.txt>"
|
echo " </dev/shm/cdlb_secrets/password.txt>"
|
||||||
echo
|
echo
|
||||||
echo -e "\e[97m --secure-boot-profile <STRING> one of <debian-shim | ciss-uki> \e[0m"
|
echo -e "\e[97m --secure-boot-profile <STRING> one of <debian-shim | ciss-uki> \e[0m"
|
||||||
@@ -178,7 +185,8 @@ usage() {
|
|||||||
echo " specified via '--signing_key=*'. If the keyring is protected, then provide the passphrase in its own file."
|
echo " specified via '--signing_key=*'. If the keyring is protected, then provide the passphrase in its own file."
|
||||||
echo " Specify the fingerprint of the key to use via '--signing_key_fpr=*'."
|
echo " Specify the fingerprint of the key to use via '--signing_key_fpr=*'."
|
||||||
echo " Optionally import an offline GPG CA signing public key via: '--signing_ca=*'."
|
echo " Optionally import an offline GPG CA signing public key via: '--signing_ca=*'."
|
||||||
echo " Change '*' to your desired files / fingerprint. Files MUST be placed in:"
|
echo " Change '*' to your desired filename-only files / fingerprint. Filename-only values MUST NOT contain slashes"
|
||||||
|
echo " or traversal. Files MUST be placed in:"
|
||||||
echo " </dev/shm/cdlb_secrets>"
|
echo " </dev/shm/cdlb_secrets>"
|
||||||
echo
|
echo
|
||||||
echo -e "\e[97m --sops-version <STRING> \e[0m"
|
echo -e "\e[97m --sops-version <STRING> \e[0m"
|
||||||
@@ -212,6 +220,9 @@ usage() {
|
|||||||
echo
|
echo
|
||||||
echo -e "\e[93m💡 Notes: \e[0m"
|
echo -e "\e[93m💡 Notes: \e[0m"
|
||||||
echo -e "\e[93m🔵 You MUST be 'root' to run this script. \e[0m"
|
echo -e "\e[93m🔵 You MUST be 'root' to run this script. \e[0m"
|
||||||
|
echo -e "\e[93m🔵 Private operator control does not remove the requirement for strict local secret path validation. \e[0m"
|
||||||
|
echo -e "\e[93m🔵 '/dev/shm/cdlb_secrets' MUST be tmpfs-backed, root-owned, mode 0700, and contain only \e[0m"
|
||||||
|
echo -e "\e[93m single-link regular secret files with mode 0400 or 0600. Secure deletion with shred is best-effort only. \e[0m"
|
||||||
echo
|
echo
|
||||||
echo -e "\e[95m💷 Please consider donating to my work at: \e[0m"
|
echo -e "\e[95m💷 Please consider donating to my work at: \e[0m"
|
||||||
echo -e "\e[95m🌐 https://coresecret.eu/spenden/ \e[0m"
|
echo -e "\e[95m🌐 https://coresecret.eu/spenden/ \e[0m"
|
||||||
|
|||||||
Executable
+191
@@ -0,0 +1,191 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# SPDX-Version: 3.0
|
||||||
|
# SPDX-CreationInfo: 2026-06-11; WEIDNER, Marc S.; <msw@coresecret.dev>
|
||||||
|
# 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.; <msw@coresecret.dev>
|
||||||
|
# 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
|
||||||
|
set -Ceuo pipefail
|
||||||
|
# shellcheck disable=SC1091,SC2034
|
||||||
|
|
||||||
|
declare TEST_ROOT=""
|
||||||
|
declare TEST_TMP=""
|
||||||
|
TEST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
TEST_TMP="$(realpath "$(mktemp -d)")"
|
||||||
|
readonly TEST_ROOT TEST_TMP
|
||||||
|
declare -r ERR_BUILD_PATH=217
|
||||||
|
declare -r ERR_GUARD_SRCE=131
|
||||||
|
declare -r ERR_SANITIZING=133
|
||||||
|
declare -r ERR_SECRET_PATH=216
|
||||||
|
declare -r VAR_WORKDIR="${TEST_ROOT}"
|
||||||
|
declare VAR_TMP_SECRET="${TEST_TMP}/secret-root"
|
||||||
|
declare LOG_DEBUG=""
|
||||||
|
declare LOG_ERROR=""
|
||||||
|
declare LOG_VAR=""
|
||||||
|
declare VAR_EARLY_DEBUG="false"
|
||||||
|
declare ERRTRAP="true"
|
||||||
|
|
||||||
|
cleanup_test() {
|
||||||
|
chmod -R u+rwX "${TEST_TMP}" 2>/dev/null || true
|
||||||
|
rm -rf "${TEST_TMP}"
|
||||||
|
}
|
||||||
|
trap cleanup_test EXIT
|
||||||
|
|
||||||
|
guard_sourcing() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
# shellcheck source=../lib/lib_secret_validation.sh
|
||||||
|
. "${TEST_ROOT}/lib/lib_secret_validation.sh"
|
||||||
|
# shellcheck source=../lib/lib_build_directory.sh
|
||||||
|
. "${TEST_ROOT}/lib/lib_build_directory.sh"
|
||||||
|
# shellcheck source=../lib/lib_debug_sanitizer.sh
|
||||||
|
. "${TEST_ROOT}/lib/lib_debug_sanitizer.sh"
|
||||||
|
# shellcheck source=../lib/lib_trap_on_exit.sh
|
||||||
|
. "${TEST_ROOT}/lib/lib_trap_on_exit.sh"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf 'FAIL: %s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
expect_failure() {
|
||||||
|
declare description="$1"
|
||||||
|
shift
|
||||||
|
if "$@" >/dev/null 2>&1; then
|
||||||
|
fail "${description}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -m 0700 "${VAR_TMP_SECRET}"
|
||||||
|
printf 'safe-private-value\n' > "${VAR_TMP_SECRET}/safe.txt"
|
||||||
|
chmod 0400 "${VAR_TMP_SECRET}/safe.txt"
|
||||||
|
|
||||||
|
validate_secret_directory "${VAR_TMP_SECRET}" "test secret root" "false" || fail "safe secret root rejected"
|
||||||
|
validate_secret_filename "safe.txt" "test secret filename" || fail "safe secret filename rejected"
|
||||||
|
validate_secret_file "${VAR_TMP_SECRET}/safe.txt" "test secret file" || fail "safe secret file rejected"
|
||||||
|
validate_secret_absolute_file "${VAR_TMP_SECRET}/safe.txt" "test absolute secret file" \
|
||||||
|
|| fail "safe absolute secret file rejected"
|
||||||
|
expect_failure "relative external secret path accepted" \
|
||||||
|
validate_secret_absolute_file "secret-root/safe.txt" "test absolute secret file"
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/external-secret-dir"
|
||||||
|
printf 'external-private-value\n' > "${TEST_TMP}/external-secret-dir/external.txt"
|
||||||
|
chmod 0400 "${TEST_TMP}/external-secret-dir/external.txt"
|
||||||
|
ln -s "${TEST_TMP}/external-secret-dir" "${TEST_TMP}/external-secret-dir-link"
|
||||||
|
expect_failure "external secret file through a symlinked parent accepted" \
|
||||||
|
validate_secret_absolute_file "${TEST_TMP}/external-secret-dir-link/external.txt" "test absolute secret file"
|
||||||
|
expect_failure "external secret directory through a symlinked parent accepted" \
|
||||||
|
validate_secret_absolute_directory "${TEST_TMP}/external-secret-dir-link" "test absolute secret directory"
|
||||||
|
declare secret_root_fs=""
|
||||||
|
secret_root_fs="$(secure_stat -f -c '%T' "${VAR_TMP_SECRET}")"
|
||||||
|
if [[ "${secret_root_fs}" != "tmpfs" && "${secret_root_fs}" != "ramfs" ]]; then
|
||||||
|
expect_failure "persistent secret staging area accepted" validate_secret_staging_area
|
||||||
|
fi
|
||||||
|
expect_failure "secret filename traversal accepted" validate_secret_filename "../safe.txt" "test secret filename"
|
||||||
|
expect_failure "absolute filename-only secret accepted" validate_secret_filename "/tmp/safe.txt" "test secret filename"
|
||||||
|
expect_failure "slash in filename-only secret accepted" validate_secret_filename "subdir/safe.txt" "test secret filename"
|
||||||
|
|
||||||
|
ln -s "${VAR_TMP_SECRET}" "${TEST_TMP}/secret-root-link"
|
||||||
|
expect_failure "secret-root symlink accepted" \
|
||||||
|
validate_secret_directory "${TEST_TMP}/secret-root-link" "test secret root" "false"
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/unsafe-secret-root-mode"
|
||||||
|
chmod 0755 "${TEST_TMP}/unsafe-secret-root-mode"
|
||||||
|
expect_failure "broad secret-root permissions accepted" \
|
||||||
|
validate_secret_directory "${TEST_TMP}/unsafe-secret-root-mode" "test secret root" "false"
|
||||||
|
ln -s "${VAR_TMP_SECRET}/safe.txt" "${VAR_TMP_SECRET}/unsafe-link"
|
||||||
|
expect_failure "secret-file symlink accepted" validate_secret_file "${VAR_TMP_SECRET}/unsafe-link" "test secret file"
|
||||||
|
rm "${VAR_TMP_SECRET}/unsafe-link"
|
||||||
|
ln "${VAR_TMP_SECRET}/safe.txt" "${VAR_TMP_SECRET}/unsafe-hardlink"
|
||||||
|
expect_failure "hardlinked secret file accepted" validate_secret_file "${VAR_TMP_SECRET}/safe.txt" "test secret file"
|
||||||
|
rm "${VAR_TMP_SECRET}/unsafe-hardlink"
|
||||||
|
|
||||||
|
declare fake_secret='CISS-CANARY-[exact]-value'
|
||||||
|
declare expected_redaction=""
|
||||||
|
declare sanitisation_status=0
|
||||||
|
printf -v expected_redaction '%*s' "${#fake_secret}" ''
|
||||||
|
expected_redaction="${expected_redaction// /*}"
|
||||||
|
register_secret_value "${fake_secret}"
|
||||||
|
|
||||||
|
LOG_DEBUG="${TEST_TMP}/debug.log"
|
||||||
|
LOG_VAR="${TEST_TMP}/var.log"
|
||||||
|
LOG_ERROR="${TEST_TMP}/error.log"
|
||||||
|
printf 'before %s after\nunrelated line\n' "${fake_secret}" > "${LOG_DEBUG}"
|
||||||
|
printf 'unrelated vars\n' > "${LOG_VAR}"
|
||||||
|
printf 'unrelated error\n' > "${LOG_ERROR}"
|
||||||
|
chmod 0600 "${LOG_DEBUG}" "${LOG_VAR}" "${LOG_ERROR}"
|
||||||
|
|
||||||
|
sanitize_debug_logs || fail "debug-log sanitisation failed"
|
||||||
|
grep -Fq "${fake_secret}" "${LOG_DEBUG}" && fail "debug-log canary remained"
|
||||||
|
grep -Fq "${expected_redaction}" "${LOG_DEBUG}" || fail "expected exact-value redaction missing"
|
||||||
|
grep -Fq 'unrelated line' "${LOG_DEBUG}" || fail "unrelated debug content changed"
|
||||||
|
|
||||||
|
ln -s "${LOG_DEBUG}" "${TEST_TMP}/unsafe-debug-link"
|
||||||
|
(
|
||||||
|
LOG_DEBUG="${TEST_TMP}/unsafe-debug-link"
|
||||||
|
trap_on_exit 73 "test" 1 "test" "false"
|
||||||
|
) 2>/dev/null || sanitisation_status=$?
|
||||||
|
[[ ${sanitisation_status} -eq 73 ]] || fail "sanitisation failure masked the original exit status"
|
||||||
|
|
||||||
|
expect_failure "empty build-directory path accepted" validate_build_directory_path ""
|
||||||
|
expect_failure "root build-directory path accepted" validate_build_directory_path "/"
|
||||||
|
expect_failure "broad parent build-directory path accepted" validate_build_directory_path "/tmp"
|
||||||
|
expect_failure "secret root accepted as build directory" validate_build_directory_path "${VAR_TMP_SECRET}"
|
||||||
|
mkdir -m 0700 "${VAR_TMP_SECRET}/unsafe-build-child"
|
||||||
|
expect_failure "secret-root descendant accepted as build directory" \
|
||||||
|
validate_build_directory_path "${VAR_TMP_SECRET}/unsafe-build-child"
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/unmarked"
|
||||||
|
expect_failure "build directory without marker accepted" validate_build_directory_marker "${TEST_TMP}/unmarked"
|
||||||
|
printf 'do-not-adopt\n' > "${TEST_TMP}/unmarked/content"
|
||||||
|
expect_failure "non-empty unmarked build directory adopted" initialize_build_directory "${TEST_TMP}/unmarked" unsafe_result
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/unsafe-build-mode"
|
||||||
|
chmod 0777 "${TEST_TMP}/unsafe-build-mode"
|
||||||
|
expect_failure "unsafe build-directory permissions accepted" \
|
||||||
|
initialize_build_directory "${TEST_TMP}/unsafe-build-mode" unsafe_result
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/marker-link-dir"
|
||||||
|
printf '%s\n' "${TEST_TMP}/marker-link-dir" > "${TEST_TMP}/marker-target"
|
||||||
|
chmod 0400 "${TEST_TMP}/marker-target"
|
||||||
|
ln -s "${TEST_TMP}/marker-target" "${TEST_TMP}/marker-link-dir/.ciss-live-builder-owned"
|
||||||
|
expect_failure "symlinked builder-owned marker accepted" validate_build_directory_marker "${TEST_TMP}/marker-link-dir"
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/marker-hardlink-dir"
|
||||||
|
printf '%s\n' "${TEST_TMP}/marker-hardlink-dir" > "${TEST_TMP}/marker-hardlink-target"
|
||||||
|
chmod 0400 "${TEST_TMP}/marker-hardlink-target"
|
||||||
|
ln "${TEST_TMP}/marker-hardlink-target" "${TEST_TMP}/marker-hardlink-dir/.ciss-live-builder-owned"
|
||||||
|
expect_failure "hardlinked builder-owned marker accepted" validate_build_directory_marker "${TEST_TMP}/marker-hardlink-dir"
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/marker-extra-content-dir"
|
||||||
|
printf '%s\nunexpected\n' "${TEST_TMP}/marker-extra-content-dir" \
|
||||||
|
> "${TEST_TMP}/marker-extra-content-dir/.ciss-live-builder-owned"
|
||||||
|
chmod 0400 "${TEST_TMP}/marker-extra-content-dir/.ciss-live-builder-owned"
|
||||||
|
expect_failure "builder-owned marker with extra content accepted" \
|
||||||
|
validate_build_directory_marker "${TEST_TMP}/marker-extra-content-dir"
|
||||||
|
|
||||||
|
ln -s "${TEST_TMP}/unmarked" "${TEST_TMP}/build-link"
|
||||||
|
expect_failure "build-directory symlink accepted" validate_build_directory_path "${TEST_TMP}/build-link"
|
||||||
|
|
||||||
|
declare validated_build_dir=""
|
||||||
|
initialize_build_directory "${TEST_TMP}/owned-build" validated_build_dir || fail "safe builder-owned directory rejected"
|
||||||
|
validate_build_directory_marker "${validated_build_dir}" || fail "builder marker rejected"
|
||||||
|
mkdir "${validated_build_dir}/subdir"
|
||||||
|
printf 'remove me\n' > "${validated_build_dir}/artifact"
|
||||||
|
printf 'remove me too\n' > "${validated_build_dir}/.hidden-artifact"
|
||||||
|
printf 'nested\n' > "${validated_build_dir}/subdir/nested"
|
||||||
|
clean_build_directory_contents "${validated_build_dir}" || fail "safe builder-owned cleanup failed"
|
||||||
|
validate_build_directory_marker "${validated_build_dir}" || fail "builder marker removed by cleanup"
|
||||||
|
[[ -z "$(find "${validated_build_dir}" -mindepth 1 ! -name '.ciss-live-builder-owned' -print -quit)" ]] \
|
||||||
|
|| fail "builder-owned cleanup left unexpected content"
|
||||||
|
|
||||||
|
mkdir -m 0700 "${TEST_TMP}/outside-build"
|
||||||
|
mkdir "${TEST_TMP}/outside-build/includes.chroot"
|
||||||
|
ln -s "${TEST_TMP}/outside-build" "${validated_build_dir}/config"
|
||||||
|
expect_failure "cleanup subpath through a symlinked parent accepted" \
|
||||||
|
validate_build_directory_subpath "${validated_build_dir}" "config/includes.chroot" unsafe_subpath
|
||||||
|
|
||||||
|
printf 'PASS: secret validation, debug sanitisation, and build cleanup guards\n'
|
||||||
Reference in New Issue
Block a user