feat(security): harden gateway boundaries and usage policies

Consolidate subscription usage policy enforcement, privacy-safe persistence, and gateway security hardening into one reviewable change.

Includes bounded HTTP and execution envelopes, header and protocol guards, DNS and relay validation, authentication and secret projection hardening, secure backup/install paths, and regression coverage.
This commit is contained in:
elky
2026-09-04 03:45:52 +08:00
parent ddcbeb3ae9
commit 579f2c7cc1
1019 changed files with 190437 additions and 26080 deletions
+59
View File
@@ -0,0 +1,59 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
PROJECT_DIR="${TEST_ROOT}/project"
FAKE_BIN="${TEST_ROOT}/fake-bin"
mkdir -p "${PROJECT_DIR}" "${FAKE_BIN}"
cp "${REPO_ROOT}/deploy.sh" "${PROJECT_DIR}/deploy.sh"
chmod 0755 "${PROJECT_DIR}/deploy.sh"
printf 'FROM scratch\n' >"${PROJECT_DIR}/Dockerfile.app.local"
printf 'services: {}\n' >"${PROJECT_DIR}/docker-compose.yml"
printf 'services: {}\n' >"${PROJECT_DIR}/docker-compose.local.yml"
cat >"${FAKE_BIN}/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
if [[ "${1:-}" == "image" && "${2:-}" == "inspect" ]]; then
exit 1
fi
if [[ " $* " == *" ps -q "* ]]; then
printf 'fixture-container\n'
fi
exit 0
EOF
chmod 0755 "${FAKE_BIN}/docker"
cp "${FAKE_BIN}/docker" "${FAKE_BIN}/docker-compose"
VICTIM="${TEST_ROOT}/victim"
printf 'known-good\n' >"${VICTIM}"
ln -s -- "${VICTIM}" "${PROJECT_DIR}/.code-hash"
if (cd -- "${PROJECT_DIR}" && PATH="${FAKE_BIN}:${PATH}" bash ./deploy.sh) >/dev/null 2>&1; then
fail_test "deploy accepted a symbolic-link build-state file"
fi
[[ "$(cat -- "${VICTIM}")" == "known-good" ]] \
|| fail_test "deploy overwrote the symbolic-link target"
[[ -L "${PROJECT_DIR}/.code-hash" ]] \
|| fail_test "deploy unexpectedly replaced the rejected symbolic link"
rm -f -- "${PROJECT_DIR}/.code-hash"
(cd -- "${PROJECT_DIR}" && PATH="${FAKE_BIN}:${PATH}" bash ./deploy.sh) >/dev/null
[[ -f "${PROJECT_DIR}/.code-hash" && ! -L "${PROJECT_DIR}/.code-hash" ]] \
|| fail_test "deploy did not atomically create a regular build-state file"
mode="$(stat -c '%a' "${PROJECT_DIR}/.code-hash" 2>/dev/null || stat -f '%Lp' "${PROJECT_DIR}/.code-hash")"
[[ "${mode}" == "600" ]] || fail_test "deploy build-state mode is ${mode}, expected 600"
if find "${PROJECT_DIR}" -maxdepth 1 -name '.code-hash.tmp.*' -print -quit | grep -q .; then
fail_test "deploy left a temporary build-state file"
fi
echo "PASS: deploy build-state symlink and atomic-write fixtures"
+49
View File
@@ -0,0 +1,49 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_archive_rejected() {
local archive="$1"
if (validate_release_archive "${archive}" >/dev/null 2>&1); then
fail_test "unsafe archive was accepted: ${archive}"
fi
}
mkdir -p "${TEST_ROOT}/bundle/bin" "${TEST_ROOT}/bundle/frontend"
printf '#!/bin/sh\nexit 0\n' >"${TEST_ROOT}/bundle/bin/aether-gateway"
printf '<!doctype html>\n' >"${TEST_ROOT}/bundle/frontend/index.html"
chmod 0755 "${TEST_ROOT}/bundle/bin/aether-gateway"
tar -czf "${TEST_ROOT}/valid.tar.gz" -C "${TEST_ROOT}" bundle
TMP_ROOT="${TEST_ROOT}/validation"
mkdir -p "${TMP_ROOT}"
[[ "$(validate_release_archive "${TEST_ROOT}/valid.tar.gz" bundle)" == "bundle" ]] \
|| fail_test "valid release archive was rejected"
original_entry_limit="${MAX_RELEASE_ARCHIVE_ENTRIES}"
MAX_RELEASE_ARCHIVE_ENTRIES=2
assert_archive_rejected "${TEST_ROOT}/valid.tar.gz"
MAX_RELEASE_ARCHIVE_ENTRIES="${original_entry_limit}"
original_size_limit="${MAX_RELEASE_UNPACKED_BYTES}"
MAX_RELEASE_UNPACKED_BYTES=1
assert_archive_rejected "${TEST_ROOT}/valid.tar.gz"
MAX_RELEASE_UNPACKED_BYTES="${original_size_limit}"
mkdir -p "${TEST_ROOT}/linked-bundle"
ln -s /etc/passwd "${TEST_ROOT}/linked-bundle/aether-gateway"
tar -czf "${TEST_ROOT}/link.tar.gz" -C "${TEST_ROOT}" linked-bundle
assert_archive_rejected "${TEST_ROOT}/link.tar.gz"
echo "PASS: installer archive validation fixtures"
+203
View File
@@ -0,0 +1,203 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_generated_key_output() {
local label="$1"
local output="$2"
local key value
local -a values=()
for key in \
JWT_SECRET_KEY ENCRYPTION_KEY DB_PASSWORD REDIS_PASSWORD \
MYSQL_PASSWORD MYSQL_ROOT_PASSWORD; do
value="$(printf '%s\n' "${output}" | awk -F= -v key="${key}" '
$1 == key { print substr($0, length(key) + 2); exit }
')"
[[ "${value}" =~ ^[A-Za-z0-9_-]{40,}$ ]] \
|| fail_test "${label} did not generate a strong URL-safe ${key}"
values+=("${value}")
done
[[ "$(printf '%s\n' "${values[@]}" | sort -u | wc -l | tr -d '[:space:]')" == "6" ]] \
|| fail_test "${label} reused a generated secret"
}
assert_line() {
local file="$1"
local expected="$2"
grep -Fqx -- "${expected}" "${file}" \
|| fail_test "missing expected line in ${file}: ${expected}"
}
APP_DOCKERFILE="${REPO_ROOT}/Dockerfile.app"
COMPOSE_FILES=(
"${REPO_ROOT}/docker-compose.yml"
"${REPO_ROOT}/docker-compose.single-node.yml"
)
assert_line "${APP_DOCKERFILE}" "USER 65532:65532"
assert_line "${APP_DOCKERFILE}" " HOME=/tmp/aether-home \\"
if grep -Eq '^USER[[:space:]]+(root|0)(:0)?[[:space:]]*$' "${APP_DOCKERFILE}"; then
fail_test "production image still selects a root runtime identity"
fi
for compose_file in "${COMPOSE_FILES[@]}"; do
assert_line "${compose_file}" \
' user: "${AETHER_CONTAINER_UID:-65532}:${AETHER_CONTAINER_GID:-65532}"'
assert_line "${compose_file}" " read_only: true"
assert_line "${compose_file}" " cap_drop:"
assert_line "${compose_file}" " - ALL"
assert_line "${compose_file}" " security_opt:"
assert_line "${compose_file}" " - no-new-privileges:true"
assert_line "${compose_file}" " tmpfs:"
assert_line "${compose_file}" " - /tmp:rw,nosuid,nodev,noexec,mode=1777"
if grep -Eq '^[[:space:]]+user:[[:space:]]+"?(root|0)(:0)?"?[[:space:]]*$' "${compose_file}"; then
fail_test "production Compose file still selects a root runtime identity: ${compose_file}"
fi
done
standard_install_body="$(declare -f install_compose_mode)"
single_node_install_body="$(declare -f install_compose_single_node_mode)"
if grep -Fq "prepare_compose_single_node_data_directory" <<<"${standard_install_body}"; then
fail_test "standard Postgres Compose install unexpectedly prepares a SQLite data directory"
fi
grep -Fq "prepare_compose_single_node_data_directory" <<<"${single_node_install_body}" \
|| fail_test "single-node Compose install does not prepare its SQLite data directory"
assert_line "${REPO_ROOT}/.env.example" "DB_PASSWORD="
assert_line "${REPO_ROOT}/.env.example" "REDIS_PASSWORD="
assert_line "${REPO_ROOT}/.env.example" "MYSQL_PASSWORD="
assert_line "${REPO_ROOT}/.env.example" "MYSQL_ROOT_PASSWORD="
assert_line "${REPO_ROOT}/README.md" "chmod 600 .env"
assert_line "${REPO_ROOT}/README.md" \
"docker compose -f docker-compose.single-node.yml stop app"
assert_line "${REPO_ROOT}/README.md" \
"sudo chown -R -P 65532:65532 ./data"
grep -Fq '${DB_PASSWORD:?set DB_PASSWORD in .env}' "${REPO_ROOT}/docker-compose.yml" \
|| fail_test "Postgres password is not required by Compose"
grep -Fq '${REDIS_PASSWORD:?set REDIS_PASSWORD in .env}' "${REPO_ROOT}/docker-compose.yml" \
|| fail_test "Redis password is not required by Compose"
grep -Fq '${MYSQL_PASSWORD:?set MYSQL_PASSWORD in .env}' "${REPO_ROOT}/docker-compose.yml" \
|| fail_test "MySQL application password is not required by Compose"
grep -Fq '${MYSQL_ROOT_PASSWORD:?set MYSQL_ROOT_PASSWORD in .env}' "${REPO_ROOT}/docker-compose.yml" \
|| fail_test "MySQL root password is not required by Compose"
if grep -Eq '(DB_PASSWORD|REDIS_PASSWORD|MYSQL_PASSWORD|MYSQL_ROOT_PASSWORD):?-?=?aether(_root)?([}"[:space:]]|$)' \
"${REPO_ROOT}/docker-compose.yml" "${REPO_ROOT}/.env.example"; then
fail_test "production Compose configuration contains a weak infrastructure password default"
fi
TEST_ROOT="$(mktemp -d)"
trap 'chmod -R u+rwX "${TEST_ROOT}" 2>/dev/null || true; rm -rf "${TEST_ROOT}"' EXIT
COMPOSE_DIR="${TEST_ROOT}/compose"
mkdir -p "${COMPOSE_DIR}/data"
fake_bin="${TEST_ROOT}/fake-bin"
mkdir -p "${fake_bin}"
printf '#!/usr/bin/env bash\nprintf "false\\n"\n' >"${fake_bin}/docker"
chmod 0755 "${fake_bin}/docker"
PATH="${fake_bin}:${PATH}"
fixture_uid="$(id -u)"
fixture_gid="$(id -g)"
[[ "${fixture_uid}" != "0" ]] || fixture_uid="65532"
[[ "${fixture_gid}" != "0" ]] || fixture_gid="65532"
printf 'AETHER_CONTAINER_UID=%s\nAETHER_CONTAINER_GID=%s\n' \
"${fixture_uid}" "${fixture_gid}" >"${COMPOSE_DIR}/.env"
printf 'sqlite fixture\n' >"${COMPOSE_DIR}/data/aether.db"
chmod 0755 "${COMPOSE_DIR}/data/aether.db"
chmod 4755 "${COMPOSE_DIR}/data/aether.db" 2>/dev/null || true
prepare_compose_single_node_data_directory
[[ "$(stat_file_mode "${COMPOSE_DIR}/data")" == "700" ]] \
|| fail_test "single-node data directory was not restricted to mode 0700"
[[ "$(stat_file_mode "${COMPOSE_DIR}/data/aether.db")" == "600" ]] \
|| fail_test "single-node SQLite file was not restricted to mode 0600"
printf 'AETHER_CONTAINER_UID=0\nAETHER_CONTAINER_GID=%s\n' \
"${fixture_gid}" >"${COMPOSE_DIR}/.env"
if (prepare_compose_single_node_data_directory) >/dev/null 2>&1; then
fail_test "root container uid was accepted"
fi
printf 'AETHER_CONTAINER_UID=%s\nAETHER_CONTAINER_GID=%s\n' \
"${fixture_uid}" "${fixture_gid}" >"${COMPOSE_DIR}/.env"
ln -s "${TEST_ROOT}" "${COMPOSE_DIR}/data/unsafe-link"
if (prepare_compose_single_node_data_directory) >/dev/null 2>&1; then
fail_test "symbolic link inside the managed SQLite directory was accepted"
fi
rm -f "${COMPOSE_DIR}/data/unsafe-link"
mkfifo "${COMPOSE_DIR}/data/unsafe-fifo"
if (prepare_compose_single_node_data_directory) >/dev/null 2>&1; then
fail_test "FIFO inside the managed SQLite directory was accepted"
fi
rm -f "${COMPOSE_DIR}/data/unsafe-fifo"
printf '#!/usr/bin/env bash\nprintf "true\\n"\n' >"${fake_bin}/docker"
chmod 0755 "${fake_bin}/docker"
if (prepare_compose_single_node_data_directory) >/dev/null 2>&1; then
fail_test "running app container did not block SQLite permission migration"
fi
printf '#!/usr/bin/env bash\nprintf "false\\n"\n' >"${fake_bin}/docker"
chmod 0755 "${fake_bin}/docker"
ln "${COMPOSE_DIR}/data/aether.db" "${COMPOSE_DIR}/data/unsafe-hardlink"
if (prepare_compose_single_node_data_directory) >/dev/null 2>&1; then
fail_test "hard link inside the managed SQLite directory was accepted"
fi
rm -f "${COMPOSE_DIR}/data/unsafe-hardlink"
cp "${REPO_ROOT}/.env.example" "${COMPOSE_DIR}/.env.example"
ADMIN_PASSWORD="test-admin-password"
APP_IMAGE="example.invalid/aether:test"
AETHER_CONTAINER_UID="${fixture_uid}"
AETHER_CONTAINER_GID="${fixture_gid}"
JWT_SECRET_KEY=""
ENCRYPTION_KEY=""
generated_env="${TEST_ROOT}/generated.env"
generate_compose_env "${generated_env}"
generated_secrets=()
for key in \
JWT_SECRET_KEY ENCRYPTION_KEY DB_PASSWORD REDIS_PASSWORD \
MYSQL_PASSWORD MYSQL_ROOT_PASSWORD; do
value="$(env_file_value "${generated_env}" "${key}")"
[[ "${value}" =~ ^[A-Za-z0-9_-]{40,}$ ]] \
|| fail_test "installer did not generate a strong URL-safe ${key}"
generated_secrets+=("${value}")
done
[[ "$(printf '%s\n' "${generated_secrets[@]}" | sort -u | wc -l | tr -d '[:space:]')" == "6" ]] \
|| fail_test "installer reused a generated secret"
assert_generated_key_output \
"repository generate_keys.sh" "$("${REPO_ROOT}/generate_keys.sh")"
generated_key_script="${TEST_ROOT}/generated-keys.sh"
write_generate_keys_script "${generated_key_script}"
assert_generated_key_output \
"installer-generated key script" "$("${generated_key_script}")"
injection_env="${TEST_ROOT}/injection.env"
printf 'SAFE=value\n' >"${injection_env}"
if (replace_or_append_env "${injection_env}" "SAFE" $'value\nINJECTED=true') >/dev/null 2>&1; then
fail_test "dotenv CR/LF injection was accepted"
fi
grep -Fqx "SAFE=value" "${injection_env}" \
|| fail_test "rejected dotenv injection still modified the target"
if grep -Fq "INJECTED" "${injection_env}"; then
fail_test "rejected dotenv injection added another variable"
fi
literal_backslash_value='literal\nINJECTED=true'
replace_or_append_env "${injection_env}" "SAFE" "${literal_backslash_value}"
grep -Fqx "SAFE=${literal_backslash_value}" "${injection_env}" \
|| fail_test "dotenv replacement interpreted a literal backslash escape"
[[ "$(wc -l <"${injection_env}" | tr -d '[:space:]')" == "1" ]] \
|| fail_test "literal backslash escape injected another dotenv line"
echo "PASS: production container runtime hardening fixtures"
+193
View File
@@ -0,0 +1,193 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
TEST_ROOT="$(mktemp -d)/aether installer fixtures"
mkdir -p "${TEST_ROOT}"
cleanup_test_root() {
rm -rf -- "$(dirname -- "${TEST_ROOT}")"
}
trap cleanup_test_root EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_link_target() {
local link="$1"
local expected="$2"
[[ -L "${link}" ]] || fail_test "${link} is not a symbolic link"
[[ "$(readlink "${link}")" == "${expected}" ]] \
|| fail_test "${link} does not point to ${expected}"
}
assert_switch_rejected() {
local release_dir="$1"
local current_link="$2"
if (switch_current_release_link "${release_dir}" "${current_link}"); then
fail_test "unsafe current-link fixture was accepted: ${current_link}"
fi
}
test_initial_switch() {
local fixture="${TEST_ROOT}/initial"
local release_dir="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${release_dir}"
switch_current_release_link "${release_dir}" "${current_link}"
assert_link_target "${current_link}" "${release_dir}"
[[ ! -e "${current_link}.new" && ! -L "${current_link}.new" ]] \
|| fail_test "temporary link remained after initial switch"
}
test_existing_link_switch() {
local fixture="${TEST_ROOT}/existing link"
local old_release="${fixture}/release old"
local new_release="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${old_release}" "${new_release}"
ln -s -- "${old_release}" "${current_link}"
switch_current_release_link "${new_release}" "${current_link}"
assert_link_target "${current_link}" "${new_release}"
[[ ! -e "${old_release}/current.new" && ! -L "${old_release}/current.new" ]] \
|| fail_test "temporary link was moved into the previous release directory"
}
test_dangling_links_are_replaced() {
local fixture="${TEST_ROOT}/dangling links"
local release_dir="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${release_dir}"
ln -s -- "${fixture}/missing current target" "${current_link}"
ln -s -- "${fixture}/missing temporary target" "${current_link}.new"
switch_current_release_link "${release_dir}" "${current_link}"
assert_link_target "${current_link}" "${release_dir}"
[[ ! -e "${current_link}.new" && ! -L "${current_link}.new" ]] \
|| fail_test "temporary dangling link remained after switch"
}
test_current_file_is_rejected() {
local fixture="${TEST_ROOT}/current file"
local release_dir="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${release_dir}"
printf '%s\n' "keep-current-file" >"${current_link}"
assert_switch_rejected "${release_dir}" "${current_link}"
[[ "$(cat "${current_link}")" == "keep-current-file" ]] \
|| fail_test "current file was modified"
[[ ! -e "${current_link}.new" && ! -L "${current_link}.new" ]] \
|| fail_test "temporary link was created for an unsafe current file"
}
test_current_directory_is_rejected() {
local fixture="${TEST_ROOT}/current directory"
local release_dir="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${release_dir}" "${current_link}"
assert_switch_rejected "${release_dir}" "${current_link}"
[[ -d "${current_link}" && ! -L "${current_link}" ]] \
|| fail_test "current directory was modified"
[[ ! -e "${current_link}/current.new" && ! -L "${current_link}/current.new" ]] \
|| fail_test "temporary link was moved into an unsafe current directory"
}
test_temporary_file_is_rejected() {
local fixture="${TEST_ROOT}/temporary file"
local old_release="${fixture}/release old"
local new_release="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${old_release}" "${new_release}"
ln -s -- "${old_release}" "${current_link}"
printf '%s\n' "keep-temporary-file" >"${current_link}.new"
assert_switch_rejected "${new_release}" "${current_link}"
assert_link_target "${current_link}" "${old_release}"
[[ "$(cat "${current_link}.new")" == "keep-temporary-file" ]] \
|| fail_test "temporary file was modified"
}
test_temporary_directory_is_rejected() {
local fixture="${TEST_ROOT}/temporary directory"
local old_release="${fixture}/release old"
local new_release="${fixture}/release new"
local current_link="${fixture}/current"
mkdir -p "${old_release}" "${new_release}" "${current_link}.new"
ln -s -- "${old_release}" "${current_link}"
assert_switch_rejected "${new_release}" "${current_link}"
assert_link_target "${current_link}" "${old_release}"
[[ -d "${current_link}.new" && ! -L "${current_link}.new" ]] \
|| fail_test "temporary directory was modified"
}
test_managed_directory_link_is_rejected() {
local fixture="${TEST_ROOT}/managed directory link"
local target="${fixture}/target"
local link="${fixture}/managed"
mkdir -p "${target}"
ln -s -- "${target}" "${link}"
if (ensure_directory "${link}"); then
fail_test "managed directory symbolic link was accepted"
fi
}
test_existing_release_is_never_rewritten_in_place() {
local fixture="${TEST_ROOT}/immutable release"
local requested="${fixture}/releases/v1.2.3"
local selected
mkdir -p "${requested}"
printf '%s\n' "old-release" >"${requested}/marker"
selected="$(select_release_install_directory "${requested}")"
[[ "${selected}" != "${requested}" ]] \
|| fail_test "an existing release directory was selected for in-place rewriting"
[[ -d "${selected}" && ! -L "${selected}" ]] \
|| fail_test "replacement release directory was not allocated safely"
[[ "$(cat "${requested}/marker")" == "old-release" ]] \
|| fail_test "the existing release was modified while allocating its replacement"
}
test_new_release_keeps_the_requested_version_path() {
local fixture="${TEST_ROOT}/new release"
local requested="${fixture}/releases/v1.2.3"
local selected
mkdir -p "$(dirname -- "${requested}")"
selected="$(select_release_install_directory "${requested}")"
[[ "${selected}" == "${requested}" ]] \
|| fail_test "a new release unexpectedly received a suffixed directory"
[[ ! -e "${requested}" && ! -L "${requested}" ]] \
|| fail_test "release selection created the requested path before installation"
}
test_initial_switch
test_existing_link_switch
test_dangling_links_are_replaced
test_current_file_is_rejected
test_current_directory_is_rejected
test_temporary_file_is_rejected
test_temporary_directory_is_rejected
test_managed_directory_link_is_rejected
test_existing_release_is_never_rewritten_in_place
test_new_release_keeps_the_requested_version_path
echo "PASS: current release link safety fixtures"
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
make_bundle() {
local bundle="$1"
mkdir -p "${bundle}/bin" "${bundle}/frontend/assets"
printf '#!/bin/sh\nexit 0\n' >"${bundle}/bin/aether-gateway"
printf '<!doctype html>\n' >"${bundle}/frontend/index.html"
printf 'asset\n' >"${bundle}/frontend/assets/app.js"
chmod 0755 "${bundle}/bin/aether-gateway"
}
assert_rejected() {
local bundle="$1"
local description="$2"
if (validate_local_bundle_tree "${bundle}"); then
fail_test "unsafe local bundle was accepted: ${description}"
fi
}
valid="${TEST_ROOT}/valid"
make_bundle "${valid}"
validate_local_bundle_tree "${valid}"
victim="${TEST_ROOT}/victim"
printf 'do-not-touch\n' >"${victim}"
frontend_link="${TEST_ROOT}/frontend-link"
make_bundle "${frontend_link}"
rm -rf -- "${frontend_link}/frontend"
ln -s -- "${TEST_ROOT}" "${frontend_link}/frontend"
assert_rejected "${frontend_link}" "frontend symbolic link"
[[ "$(cat "${victim}")" == "do-not-touch" ]] \
|| fail_test "frontend symbolic-link validation modified its target"
binary_link="${TEST_ROOT}/binary-link"
make_bundle "${binary_link}"
rm -f -- "${binary_link}/bin/aether-gateway"
ln -s -- "${valid}/bin/aether-gateway" "${binary_link}/bin/aether-gateway"
assert_rejected "${binary_link}" "binary symbolic link"
hardlink="${TEST_ROOT}/hardlink"
make_bundle "${hardlink}"
ln "${hardlink}/frontend/index.html" "${hardlink}/frontend/index-copy.html"
assert_rejected "${hardlink}" "multiply-linked frontend file"
fifo="${TEST_ROOT}/fifo"
make_bundle "${fifo}"
mkfifo "${fifo}/frontend/events.pipe"
assert_rejected "${fifo}" "FIFO frontend entry"
bundle_link="${TEST_ROOT}/bundle-link"
ln -s -- "${valid}" "${bundle_link}"
assert_rejected "${bundle_link}" "bundle symbolic link"
echo "PASS: local release bundle type and link safety fixtures"
+180
View File
@@ -0,0 +1,180 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_rejected() {
if ("$@") >/dev/null 2>&1; then
fail_test "unsafe managed-file fixture was accepted: $*"
fi
}
assert_victim_unchanged() {
local victim="$1"
local expected="$2"
[[ "$(cat "${victim}")" == "${expected}" ]] \
|| fail_test "managed-file guard modified ${victim}"
}
mkdir -p "${TEST_ROOT}/managed" "${TEST_ROOT}/config"
source_file="${TEST_ROOT}/source"
victim="${TEST_ROOT}/victim"
target="${TEST_ROOT}/managed/target"
printf '%s\n' "replacement" >"${source_file}"
printf '%s\n' "keep-victim" >"${victim}"
ln -s "${victim}" "${target}"
assert_rejected atomic_install_managed_file "${source_file}" "${target}" 0600
assert_victim_unchanged "${victim}" "keep-victim"
rm -f "${target}"
ln "${victim}" "${target}"
atomic_install_managed_file "${source_file}" "${target}" 0600
assert_victim_unchanged "${victim}" "keep-victim"
[[ "$(cat "${target}")" == "replacement" ]] \
|| fail_test "atomic managed-file replacement did not update the target"
[[ "$(stat_file_link_count "${target}")" == "1" ]] \
|| fail_test "atomic managed-file replacement retained an attacker-controlled hard link"
keys_victim="${TEST_ROOT}/keys-victim"
keys_target="${TEST_ROOT}/managed/generate_keys.sh"
printf '%s\n' "keep-keys-victim" >"${keys_victim}"
ln -s "${keys_victim}" "${keys_target}"
CONFIG_DIR="${TEST_ROOT}/config"
assert_rejected write_generate_keys_script "${keys_target}"
assert_victim_unchanged "${keys_victim}" "keep-keys-victim"
env_victim="${TEST_ROOT}/env-victim"
env_target="${TEST_ROOT}/config/aether-gateway.env"
printf '%s\n' "keep-env-victim" >"${env_victim}"
ln -s "${env_victim}" "${env_target}"
assert_rejected replace_or_append_env "${env_target}" "AETHER_UPDATE_STRATEGY" "manual"
assert_victim_unchanged "${env_victim}" "keep-env-victim"
ENV_TARGET="${env_target}"
SERVICE_GROUP="$(id -gn)"
assert_rejected install_env_target_from "${source_file}"
assert_victim_unchanged "${env_victim}" "keep-env-victim"
rm -f "${env_target}"
printf '%s\n' "AETHER_UPDATE_STRATEGY=self" >"${env_target}"
chmod 0640 "${env_target}"
replace_or_append_env "${env_target}" "AETHER_UPDATE_STRATEGY" "manual"
grep -Fxq "AETHER_UPDATE_STRATEGY=manual" "${env_target}" \
|| fail_test "env update did not replace the managed value"
[[ "$(stat_file_mode "${env_target}")" == "640" ]] \
|| fail_test "env update did not preserve the managed file mode"
# Exercise the real writers without requiring root ownership changes in the
# temporary fixture tree. The original atomic replacement implementation is
# retained; only ownership application and privileged-directory creation are
# adapted for an unprivileged test process.
eval "$(declare -f atomic_install_managed_file | \
sed '1s/atomic_install_managed_file/original_atomic_install_managed_file/')"
atomic_install_managed_file() {
original_atomic_install_managed_file "$1" "$2" "$3"
}
ensure_privileged_directory() {
ensure_directory "$1" "$2"
}
systemctl() {
return 0
}
systemd_dir="${TEST_ROOT}/systemd"
SYSTEMD_UNIT_PATH="${systemd_dir}/aether-gateway.service"
mkdir -p "${systemd_dir}"
unit_victim="${TEST_ROOT}/unit-victim"
printf '%s\n' "keep-unit-victim" >"${unit_victim}"
ln -s "${unit_victim}" "${SYSTEMD_UNIT_PATH}"
assert_rejected install_systemd_unit
assert_victim_unchanged "${unit_victim}" "keep-unit-victim"
rm -f "${SYSTEMD_UNIT_PATH}"
install_systemd_unit
[[ -f "${SYSTEMD_UNIT_PATH}" && ! -L "${SYSTEMD_UNIT_PATH}" ]] \
|| fail_test "systemd unit was not installed as a regular file"
INSTALL_ROOT="${TEST_ROOT}/install path/\$(touch wrapper-injected)"
CONFIG_DIR="${TEST_ROOT}/config"
ENV_TARGET="${TEST_ROOT}/config path/\$(touch env-injected)"
mkdir -p "$(dirname "${ENV_TARGET}")"
wrapper="$(launchd_wrapper_path)"
mkdir -p "$(dirname "${wrapper}")"
wrapper_victim="${TEST_ROOT}/wrapper-victim"
printf '%s\n' "keep-wrapper-victim" >"${wrapper_victim}"
ln -s "${wrapper_victim}" "${wrapper}"
assert_rejected write_launchd_wrapper
assert_victim_unchanged "${wrapper_victim}" "keep-wrapper-victim"
rm -f "${wrapper}"
write_launchd_wrapper
bash -n "${wrapper}"
if (cd "${TEST_ROOT}" && "${wrapper}") >/dev/null 2>&1; then
fail_test "launchd wrapper unexpectedly ran without its env file"
fi
[[ ! -e "${TEST_ROOT}/wrapper-injected" && ! -e "${TEST_ROOT}/env-injected" ]] \
|| fail_test "launchd wrapper executed a generated-path shell injection"
LAUNCHD_LOG_DIR="${TEST_ROOT}/launchd-logs"
mkdir -p "${LAUNCHD_LOG_DIR}"
log_victim="${TEST_ROOT}/log-victim"
printf '%s\n' "keep-log-victim" >"${log_victim}"
ln -s "${log_victim}" "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
assert_rejected install_launchd_log_files
assert_victim_unchanged "${log_victim}" "keep-log-victim"
rm -f "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
ln "${log_victim}" "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
assert_rejected install_launchd_log_files
assert_victim_unchanged "${log_victim}" "keep-log-victim"
rm -f "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
printf '%s\n' "keep-existing-log" >"${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
chmod 0600 "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log"
ln -s "${log_victim}" "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.err.log"
assert_rejected install_launchd_log_files
[[ "$(cat "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log")" == "keep-existing-log" ]] \
|| fail_test "launchd log preflight changed an earlier valid log"
[[ "$(stat_file_mode "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.out.log")" == "600" ]] \
|| fail_test "launchd log preflight changed permissions before rejecting a later target"
rm -f "${LAUNCHD_LOG_DIR}/${SERVICE_NAME}.err.log"
plist_dir="${TEST_ROOT}/launchd"
LAUNCHD_PLIST_PATH="${plist_dir}/aether-gateway.plist"
mkdir -p "${plist_dir}"
plist_victim="${TEST_ROOT}/plist-victim"
printf '%s\n' "keep-plist-victim" >"${plist_victim}"
ln -s "${plist_victim}" "${LAUNCHD_PLIST_PATH}"
assert_rejected install_launchd_unit
assert_victim_unchanged "${plist_victim}" "keep-plist-victim"
LAUNCHD_LABEL="aether&amp-test"
SERVICE_USER="user&amp-test"
SERVICE_GROUP="group&lt-test"
rendered_plist="${TEST_ROOT}/rendered.plist"
render_launchd_plist >"${rendered_plist}"
grep -Fq '<string>aether&amp;amp-test</string>' "${rendered_plist}" \
|| fail_test "launchd label was not XML escaped"
grep -Fq '<string>user&amp;amp-test</string>' "${rendered_plist}" \
|| fail_test "launchd account was not XML escaped"
SERVICE_USER="aether"
SERVICE_GROUP="aether"
LAUNCHD_LABEL="../outside"
assert_rejected validate_launchd_label "${LAUNCHD_LABEL}"
assert_rejected validate_managed_absolute_path "install root" "/opt/aether/../outside"
assert_rejected validate_managed_absolute_path "install root" "/opt/aether path"
ancestor_target="${TEST_ROOT}/ancestor-target"
ancestor_link="${TEST_ROOT}/ancestor-link"
mkdir -p "${ancestor_target}"
ln -s "${ancestor_target}" "${ancestor_link}"
assert_rejected validate_privileged_path_ancestor "${ancestor_link}/managed"
echo "PASS: privileged installer managed-file safety fixtures"
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
mkdir -p "${TEST_ROOT}/bin" "${TEST_ROOT}/frontend"
printf '#!/bin/sh\nexit 0\n' >"${TEST_ROOT}/bin/aether-gateway"
chmod +x "${TEST_ROOT}/bin/aether-gateway"
definitions="$({
awk '/^current_script_dir\(\)/ { emit=1 } emit { print } emit && /^}/ { emit=0 }' "${REPO_ROOT}/install.sh"
awk '/^local_bundle_dir\(\)/ { emit=1 } emit { print } emit && /^}/ { emit=0 }' "${REPO_ROOT}/install.sh"
})"
if printf '%s\ncd -- %q\nif local_bundle_dir; then exit 9; fi\n' \
"${definitions}" "${TEST_ROOT}" | bash; then
:
else
status=$?
[[ "${status}" -ne 9 ]] || fail_test "stdin execution trusted a bundle from the current directory"
fail_test "stdin trust regression fixture failed unexpectedly with status ${status}"
fi
# shellcheck source=../install.sh
source "${REPO_ROOT}/install.sh"
[[ "$(current_script_dir)" == "${REPO_ROOT}" ]] \
|| fail_test "a real installer file no longer resolves its adjacent bundle directory"
echo "PASS: installer source-directory trust boundary"
+68
View File
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
COMPOSE_FILE="${REPO_ROOT}/docker-compose.yml"
RELEASE_WORKFLOW="${REPO_ROOT}/.github/workflows/release.yml"
TUNNEL_RELEASE_WORKFLOW="${REPO_ROOT}/.github/workflows/build-tunnel.yml"
APP_DOCKERFILE="${REPO_ROOT}/Dockerfile.app"
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_line() {
local file="$1"
local expected="$2"
grep -Fqx -- "${expected}" "${file}" \
|| fail_test "missing expected line in ${file}: ${expected}"
}
assert_line "${COMPOSE_FILE}" \
" image: postgres:15.19@sha256:5f72c7b5bd616308ccfd2e74d6be16fb06364e5eecbb815fe9dc6ab9761d2111"
assert_line "${COMPOSE_FILE}" \
" image: redis:7.4.11-alpine@sha256:ff02b58f971e7d7d156a1267e283fcbbeee91773b6aa36c49dac28ecfe28eadf"
assert_line "${COMPOSE_FILE}" \
" image: mysql:8.0.46@sha256:7dcddc01f13bab2f15cde676d44d01f61fc9f99fe7785e86196dfc07d358ae2b"
if grep -Eq '^[[:space:]]+image:[[:space:]]+(postgres|redis|mysql):[^@[:space:]]+[[:space:]]*$' "${COMPOSE_FILE}"; then
fail_test "compose contains a mutable third-party image tag"
fi
assert_line "${APP_DOCKERFILE}" \
"FROM busybox:1.37.0-musl@sha256:fc6dddc4c44b1bfe37f41cae8e67d1693828e8f42a91862816d7953e2c9d3f23 AS layout"
assert_line "${APP_DOCKERFILE}" \
"FROM gcr.io/distroless/static-debian12@sha256:6447365a6337c3732f412d1b74357b30a633831955b2bc45552b0086be907687"
if grep -Eq '^FROM[[:space:]]+[^[:space:]@]+(:[^[:space:]@]+)?([[:space:]]+AS[[:space:]]+[^[:space:]]+)?$' "${APP_DOCKERFILE}"; then
fail_test "production Dockerfile contains an unpinned base image"
fi
assert_line "${RELEASE_WORKFLOW}" " attestations: write"
assert_line "${RELEASE_WORKFLOW}" " id-token: write"
assert_line "${RELEASE_WORKFLOW}" \
" uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2"
assert_line "${RELEASE_WORKFLOW}" ' subject-digest: ${{ steps.push.outputs.digest }}'
assert_line "${RELEASE_WORKFLOW}" " push-to-registry: true"
assert_line "${RELEASE_WORKFLOW}" " subject-path: |"
assert_line "${RELEASE_WORKFLOW}" " release-assets/install.sh"
assert_line "${RELEASE_WORKFLOW}" " release-assets/SHA256SUMS"
assert_line "${RELEASE_WORKFLOW}" " release-assets/AETHER_RELEASE_PROVENANCE.sigstore.json"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" " attestations: write"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" " id-token: write"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" \
" uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" " artifacts/SHA256SUMS.txt"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" \
" artifacts/AETHER_TUNNEL_RELEASE_PROVENANCE.sigstore.json"
assert_line "${TUNNEL_RELEASE_WORKFLOW}" \
" tar czf ../../../aether-tunnel-\${{ matrix.name }}.tar.gz aether-tunnel.exe"
if grep -ERq '^[[:space:]]*(-[[:space:]]+)?uses:[[:space:]]+[^[:space:]#]+@[^0-9a-f[:space:]][^[:space:]]*([[:space:]#]|$)' \
"${REPO_ROOT}/.github/workflows"; then
fail_test "workflow contains a mutable third-party action reference"
fi
echo "PASS: release supply-chain pins and provenance workflow"
+221
View File
@@ -0,0 +1,221 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
INSTALLER="${REPO_ROOT}/apps/aether-tunnel/install.sh"
POWERSHELL_INSTALLER="${REPO_ROOT}/apps/aether-tunnel/install.ps1"
TEST_ROOT="${REPO_ROOT}/.tmp-tunnel-installer-test.$$"
cleanup_test_root() {
chmod -R u+rwX "${TEST_ROOT}" 2>/dev/null || true
rm -rf -- "${TEST_ROOT}"
}
trap cleanup_test_root EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
assert_rejected() {
if ("$@") >/dev/null 2>&1; then
fail_test "unsafe installer fixture was accepted: $*"
fi
}
file_mode() {
stat -c '%a' "$1" 2>/dev/null || stat -f '%Lp' "$1"
}
mkdir -m 700 "${TEST_ROOT}"
LIB="${TEST_ROOT}/installer-lib.sh"
sed '/^main()/,$d' "${INSTALLER}" >"${LIB}"
# shellcheck source=/dev/null
source "${LIB}"
trap cleanup_test_root EXIT
validate_release_repo "fawney19/Aether"
validate_tunnel_release_tag "tunnel-v0.3.16-rc.1"
validate_tunnel_release_tag "tunnel-v1.2.3+build.7"
validate_release_asset_name "aether-tunnel-linux-amd64.tar.gz"
validate_node_name "Tokyo edge 01"
validate_node_name "东京节点"
assert_rejected validate_release_repo "owner/repo/extra"
assert_rejected validate_release_repo 'owner/repo;touch injected'
assert_rejected validate_tunnel_release_tag "../tunnel-v0.3.16"
assert_rejected validate_tunnel_release_tag "gateway-v0.3.16"
assert_rejected validate_tunnel_release_tag "tunnel-v1.2"
assert_rejected validate_tunnel_release_tag "tunnel-v01.2.3"
assert_rejected validate_tunnel_release_tag "tunnel-v1.2.3-01"
assert_rejected validate_release_asset_name "../aether-tunnel-linux-amd64.tar.gz"
assert_rejected validate_node_name " trailing "
assert_rejected validate_node_name $'node\tname'
assert_rejected validate_node_name $'node\nname'
assert_rejected validate_node_name "$(printf 'n%.0s' {1..256})"
assert_rejected validate_https_download_url "http://example.test/release.tar.gz"
assert_rejected validate_https_download_url "https://user:pass@example.test/release.tar.gz"
assert_rejected validate_https_download_url "https://example.test/release.tar.gz#fragment"
validate_trusted_github_download_url "https://github.com/fawney19/Aether/releases/download/tunnel-v1.2.3/aether-tunnel-linux-amd64.tar.gz"
validate_trusted_github_download_url "https://release-assets.githubusercontent.com/example/object"
assert_rejected validate_trusted_github_download_url "https://github.com.evil.example/release.tar.gz"
assert_rejected validate_trusted_github_download_url "https://github.com:444/release.tar.gz"
CURL_ARGS="${TEST_ROOT}/curl-args"
curl() {
printf '%s\n' "$@" >"${CURL_ARGS}"
local headers='' output='' url=''
while (($#)); do
case "$1" in
--dump-header) headers="$2"; shift 2 ;;
--output) output="$2"; shift 2 ;;
--write-out) shift 2 ;;
-*) shift ;;
*) url="$1"; shift ;;
esac
done
: >"${headers}"
printf '%s\n' "verified download from ${url}" >"${output}"
printf '200'
}
download "https://github.com/fawney19/Aether/release.tar.gz" "${TEST_ROOT}/downloaded"
grep -Fxq -- '--proto' "${CURL_ARGS}" || fail_test "curl HTTPS protocol restriction is missing"
grep -Fxq -- '=https' "${CURL_ARGS}" || fail_test "curl HTTPS protocol value is missing"
grep -Fxq -- '--max-redirs' "${CURL_ARGS}" || fail_test "curl automatic redirects were not disabled"
unset -f curl
checksum_asset="aether-tunnel-linux-amd64.tar.gz"
checksum_archive="${TEST_ROOT}/${checksum_asset}"
checksum_manifest="${TEST_ROOT}/SHA256SUMS.txt"
printf '%s\n' "verified release payload" >"${checksum_archive}"
if command -v sha256sum >/dev/null 2>&1; then
checksum="$(sha256sum "${checksum_archive}" | awk '{print $1}')"
else
checksum="$(shasum -a 256 "${checksum_archive}" | awk '{print $1}')"
fi
printf '%s %s\n' "${checksum}" "${checksum_asset}" >"${checksum_manifest}"
verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%064d %s\n' 0 "${checksum_asset}" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%063d %s\n' 0 "${checksum_asset}" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%s %s\n' "${checksum}" "other-asset.tar.gz" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%s %s trailing-field\n' "${checksum}" "${checksum_asset}" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%s extra-field %s\n' "${checksum}" "${checksum_asset}" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
printf '%s %s\n%s *%s\n' \
"${checksum}" "${checksum_asset}" "${checksum}" "${checksum_asset}" >"${checksum_manifest}"
assert_rejected verify_checksum "${checksum_archive}" "${checksum_manifest}" "${checksum_asset}"
CONFIG_PATH="${TEST_ROOT}/normal/aether-tunnel.toml"
append_server_config "https://aether.example" "secret-token" "node-one" "off" ""
[[ "$(file_mode "${CONFIG_PATH}")" == "600" ]] || fail_test "config mode is not 0600"
grep -Fq 'management_token = "secret-token"' "${CONFIG_PATH}" || fail_test "config block was not written"
source_binary="${TEST_ROOT}/source-aether-tunnel"
printf '#!/bin/sh\nexit 0\n' >"${source_binary}"
chmod 755 "${source_binary}"
INSTALL_DIR="${TEST_ROOT}/install-bin"
install_tunnel_binary_file "${source_binary}"
[[ -x "${INSTALL_DIR}/aether-tunnel" ]] || fail_test "tunnel binary was not installed"
binary_victim="${TEST_ROOT}/binary-victim"
printf '%s\n' "keep-binary-victim" >"${binary_victim}"
rm -f "${INSTALL_DIR}/aether-tunnel"
ln -s "${binary_victim}" "${INSTALL_DIR}/aether-tunnel"
if (install_tunnel_binary_file "${source_binary}") 2>/dev/null; then
fail_test "symbolic-link binary target was accepted"
fi
[[ "$(cat "${binary_victim}")" == "keep-binary-victim" ]] \
|| fail_test "symbolic-link binary target was modified"
rm -f "${INSTALL_DIR}/aether-tunnel"
binary_hardlink_victim="${TEST_ROOT}/binary-hardlink-victim"
printf '%s\n' "keep-hardlink-victim" >"${binary_hardlink_victim}"
ln "${binary_hardlink_victim}" "${INSTALL_DIR}/aether-tunnel"
if (install_tunnel_binary_file "${source_binary}") 2>/dev/null; then
fail_test "hard-linked binary target was accepted"
fi
[[ "$(cat "${binary_hardlink_victim}")" == "keep-hardlink-victim" ]] \
|| fail_test "hard-linked binary victim was modified"
linked_install_target="${TEST_ROOT}/linked-install-target"
mkdir -m 700 "${linked_install_target}"
INSTALL_DIR="${TEST_ROOT}/linked-install-dir"
ln -s "${linked_install_target}" "${INSTALL_DIR}"
if (install_tunnel_binary_file "${source_binary}") 2>/dev/null; then
fail_test "symbolic-link install directory was accepted"
fi
[[ ! -e "${linked_install_target}/aether-tunnel" ]] \
|| fail_test "symbolic-link install directory target was modified"
ancestor_target="${TEST_ROOT}/ancestor-target"
mkdir -m 700 "${ancestor_target}"
ancestor_link="${TEST_ROOT}/ancestor-link"
ln -s "${ancestor_target}" "${ancestor_link}"
INSTALL_DIR="${ancestor_link}/nested/bin"
if (install_tunnel_binary_file "${source_binary}") 2>/dev/null; then
fail_test "symbolic-link install ancestor was accepted"
fi
[[ ! -e "${ancestor_target}/nested/bin/aether-tunnel" ]] \
|| fail_test "symbolic-link install ancestor target was modified"
chmod 644 "${CONFIG_PATH}"
append_server_config "https://aether.example" "second-token" "node-two" "off" ""
[[ "$(file_mode "${CONFIG_PATH}")" == "600" ]] || fail_test "existing config was not protected before update"
backup="$(find "$(dirname "${CONFIG_PATH}")" -maxdepth 1 -type f -name 'aether-tunnel.toml.bak.*' | head -n1)"
[[ -n "${backup}" && "$(file_mode "${backup}")" == "600" ]] || fail_test "backup mode is not 0600"
victim="${TEST_ROOT}/victim.txt"
printf '%s\n' "keep-me" >"${victim}"
CONFIG_PATH="${TEST_ROOT}/linked.toml"
ln -s "${victim}" "${CONFIG_PATH}"
if (append_server_config "https://aether.example" "stolen-token" "node-link" "off" "") 2>/dev/null; then
fail_test "symbolic-link config was accepted"
fi
[[ "$(cat "${victim}")" == "keep-me" ]] || fail_test "symbolic-link target was modified"
hardlink_victim="${TEST_ROOT}/hardlink-victim.toml"
printf '%s\n' 'victim = true' >"${hardlink_victim}"
CONFIG_PATH="${TEST_ROOT}/hardlinked.toml"
ln "${hardlink_victim}" "${CONFIG_PATH}"
if (append_server_config "https://aether.example" "stolen-token" "node-hardlink" "off" "") 2>/dev/null; then
fail_test "hard-linked config was accepted"
fi
[[ "$(cat "${hardlink_victim}")" == 'victim = true' ]] || fail_test "hard-linked config victim was modified"
grep -Fq 'Get-Content -LiteralPath' "${POWERSHELL_INSTALLER}" || fail_test "PowerShell reads are not literal-path safe"
grep -Fq '[IO.File]::Replace' "${POWERSHELL_INSTALLER}" || fail_test "PowerShell config replacement is not atomic"
grep -Fq 'FileAttributes]::ReparsePoint' "${POWERSHELL_INSTALLER}" || fail_test "PowerShell reparse-point guard is missing"
grep -Fq 'Assert-NoReparsePointAncestors' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell ancestor reparse-point guard is missing"
grep -Fq "LinkType -eq 'HardLink'" "${POWERSHELL_INSTALLER}" || fail_test "PowerShell hard-link guard is missing"
grep -Fq 'AllowAutoRedirect = $false' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell automatic redirects are still enabled"
grep -Fq 'Assert-TrustedGithubUri $CurrentUri' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell trusted redirect validation is missing"
if grep -Eq 'Invoke-(WebRequest|RestMethod)' "${POWERSHELL_INSTALLER}"; then
fail_test "PowerShell installer still uses an automatically redirecting download command"
fi
grep -Fq '[IO.File]::Replace($TempBinary, $TargetBinary' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell binary replacement is not atomic"
grep -Fq '$ExpectedLines.Count -ne 1' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell checksum matching does not reject duplicates"
grep -Fq 'if (-not $ExpectedMatch.Success)' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell checksum matching does not reject malformed target entries"
if grep -Fq 'Select-Object -First 1' "${POWERSHELL_INSTALLER}"; then
fail_test "PowerShell checksum matching still silently accepts duplicate entries"
fi
grep -Fq 'Assert-SafeReleaseRepo $Repo' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell release repository validation is missing"
grep -Fq 'Assert-SafeTunnelReleaseTag $Tag' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell release tag validation is missing"
grep -Fq 'Assert-SafeNodeName $NodeName' "${POWERSHELL_INSTALLER}" \
|| fail_test "PowerShell node-name validation is missing"
if grep -Eq 'Add-Content[[:space:]]+-Path' "${POWERSHELL_INSTALLER}"; then
fail_test "PowerShell config still uses wildcard-aware Add-Content -Path"
fi
echo "PASS: tunnel installer config safety fixtures"
+134
View File
@@ -0,0 +1,134 @@
#!/usr/bin/env bash
set -euo pipefail
REPO_ROOT="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd -P)"
TEST_ROOT="$(mktemp -d)"
trap 'rm -rf -- "${TEST_ROOT}"' EXIT
fail_test() {
echo "FAIL: $*" >&2
exit 1
}
make_fixture() {
local fixture="$1"
mkdir -p "${fixture}/bin" "${fixture}/compose"
: >"${fixture}/compose/docker-compose.yml"
: >"${fixture}/calls"
cp "${REPO_ROOT}/update.sh" "${fixture}/compose/update.sh"
chmod 0755 "${fixture}/compose/update.sh"
}
test_wait_failure_is_not_ignored() {
local fixture="${TEST_ROOT}/wait-failure"
make_fixture "${fixture}"
cat >"${fixture}/bin/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"${AETHER_TEST_CALLS}"
case "$*" in
"compose version"|"info") exit 0 ;;
*"config --services") printf 'app\n' ;;
*"up --help") printf '%s\n' ' --wait Wait for services' ;;
*"up -d --wait --wait-timeout 120 app") exit 42 ;;
*"pull app") exit 0 ;;
esac
exit 0
EOF
chmod 0755 "${fixture}/bin/docker"
if PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" \
>"${fixture}/stdout" 2>"${fixture}/stderr"; then
fail_test "update succeeded after compose --wait reported an unhealthy app"
fi
[[ "$(grep -Fc 'up -d' "${fixture}/calls")" -eq 1 ]] \
|| fail_test "failed update retried an unverified simple recreate"
! grep -Fq '>>> Done.' "${fixture}/stdout" \
|| fail_test "failed update was reported as successful"
}
test_legacy_compose_uses_health_polling() {
local fixture="${TEST_ROOT}/legacy-wait"
make_fixture "${fixture}"
cat >"${fixture}/bin/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"${AETHER_TEST_CALLS}"
case "$*" in
"compose version"|"info") exit 0 ;;
*"config --services") printf 'app\n' ;;
*"up --help") printf '%s\n' 'Usage: docker compose up' ;;
*"pull app"|*"up -d app"|*" ps") exit 0 ;;
*"ps -q app") printf 'container-id\n' ;;
"inspect --format={{.State.Health.Status}} container-id") printf 'healthy\n' ;;
esac
exit 0
EOF
chmod 0755 "${fixture}/bin/docker"
PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" \
>"${fixture}/stdout" 2>"${fixture}/stderr"
grep -Fq 'up -d app' "${fixture}/calls" \
|| fail_test "legacy Compose path did not recreate the app"
grep -Fq '>>> Container is healthy.' "${fixture}/stdout" \
|| fail_test "legacy Compose path did not require a healthy container"
}
test_legacy_compose_health_failure_is_not_ignored() {
local fixture="${TEST_ROOT}/legacy-unhealthy"
make_fixture "${fixture}"
cat >"${fixture}/bin/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
printf '%s\n' "$*" >>"${AETHER_TEST_CALLS}"
case "$*" in
"compose version"|"info") exit 0 ;;
*"config --services") printf 'app\n' ;;
*"up --help") printf '%s\n' 'Usage: docker compose up' ;;
*"pull app"|*"up -d app") exit 0 ;;
*"ps -q app") printf 'container-id\n' ;;
"inspect --format={{.State.Health.Status}} container-id") printf 'unhealthy\n' ;;
esac
exit 0
EOF
cat >"${fixture}/bin/sleep" <<'EOF'
#!/usr/bin/env bash
exit 0
EOF
chmod 0755 "${fixture}/bin/docker" "${fixture}/bin/sleep"
if PATH="${fixture}/bin:${PATH}" AETHER_TEST_CALLS="${fixture}/calls" \
"${fixture}/compose/update.sh" --compose-dir "${fixture}/compose" \
>"${fixture}/stdout" 2>"${fixture}/stderr"; then
fail_test "legacy Compose update succeeded with an unhealthy app"
fi
grep -Fq 'health check timed out' "${fixture}/stdout" \
|| fail_test "legacy unhealthy app did not reach the health failure path"
! grep -Fq '>>> Done.' "${fixture}/stdout" \
|| fail_test "legacy unhealthy update was reported as successful"
}
test_option_like_service_name_is_rejected() {
local fixture="${TEST_ROOT}/unsafe-service"
make_fixture "${fixture}"
if PATH="${fixture}/bin:${PATH}" "${fixture}/compose/update.sh" \
--compose-dir "${fixture}/compose" --service --ansi \
>"${fixture}/stdout" 2>"${fixture}/stderr"; then
fail_test "option-like service name was accepted"
fi
grep -Fq 'service name contains unsafe characters' "${fixture}/stderr" \
|| fail_test "unsafe service name was not rejected by the identifier guard"
}
test_wait_failure_is_not_ignored
test_legacy_compose_uses_health_polling
test_legacy_compose_health_failure_is_not_ignored
test_option_like_service_name_is_rejected
echo "PASS: compose updater failure and argument safety fixtures"