diff --git a/agentctl b/agentctl index b1647d7..46035a4 100755 --- a/agentctl +++ b/agentctl @@ -98,15 +98,40 @@ verify_release_asset() { fi } +read_env_value() { + local file="$1" + local key="$2" + local line value="" found="0" + + while IFS= read -r line || [[ -n "${line}" ]]; do + if [[ "${line}" == "${key}="* ]]; then + if [[ "${found}" == "1" ]]; then + echo "Error: ${key} is defined more than once in ${file}." >&2 + return 1 + fi + value="${line#*=}" + found="1" + fi + done < "${file}" + + printf '%s' "${value}" +} + render_compose_file() { local template="$1" local destination="$2" local agent_id agent_suffix container_name - agent_id=$(sed -n 's/^AGENT_ID=//p' .env | head -1) + if ! agent_id=$(read_env_value .env AGENT_ID); then + return 1 + fi if [[ -z "${agent_id}" ]]; then echo "Error: AGENT_ID is missing from .env." >&2 return 1 fi + if [[ ! "${agent_id}" =~ __ISE__[A-Za-z0-9-]+$ ]]; then + echo "Error: AGENT_ID in .env has an invalid format." >&2 + return 1 + fi agent_suffix="${agent_id##*__}" agent_suffix="${agent_suffix:0:8}" container_name="ise-agent-${agent_suffix}" @@ -173,11 +198,9 @@ load_network_mode() { local network_mode="${ISE_AGENT_NETWORK_MODE:-}" if [[ -z "${network_mode}" ]] && [[ -r ".env" ]]; then - network_mode=$( - # shellcheck disable=SC1091 - source .env - printf '%s' "${ISE_AGENT_NETWORK_MODE:-}" - ) + if ! network_mode=$(read_env_value .env ISE_AGENT_NETWORK_MODE); then + return 1 + fi fi ISE_AGENT_NETWORK_MODE="${network_mode:-bridge}" @@ -186,7 +209,7 @@ load_network_mode() { ;; *) echo "Error: ISE_AGENT_NETWORK_MODE must be bridge or host." >&2 - exit 1 + return 1 ;; esac diff --git a/tests/test-host-tools.sh b/tests/test-host-tools.sh index a54dd08..cb74f0f 100755 --- a/tests/test-host-tools.sh +++ b/tests/test-host-tools.sh @@ -17,6 +17,8 @@ PODMAN_PACKAGE_DIR="${TEST_ROOT}/podman-package" ROOTLESS_INSTALL_DIR="${TEST_ROOT}/rootless-install" ROOTFUL_INSTALL_DIR="${TEST_ROOT}/rootful-install" ROLLBACK_DIR="${TEST_ROOT}/rollback" +UNTRUSTED_ENV_DIR="${TEST_ROOT}/untrusted-env" +INVALID_AGENT_DIR="${TEST_ROOT}/invalid-agent" BIN_DIR="${TEST_ROOT}/bin" PODMAN_BIN_DIR="${TEST_ROOT}/podman-bin" PODMAN_INSTALL_BIN_DIR="${TEST_ROOT}/podman-install-bin" @@ -32,6 +34,8 @@ mkdir -p \ "${ROOTLESS_INSTALL_DIR}" \ "${ROOTFUL_INSTALL_DIR}" \ "${ROLLBACK_DIR}/.launcher" \ + "${UNTRUSTED_ENV_DIR}/.launcher" \ + "${INVALID_AGENT_DIR}/.launcher" \ "${BIN_DIR}" \ "${PODMAN_BIN_DIR}" \ "${PODMAN_INSTALL_BIN_DIR}" @@ -163,6 +167,50 @@ grep -q 'compose .*config --quiet' "${COMMAND_LOG}" grep -q 'compose down' "${COMMAND_LOG}" grep -q 'compose up -d' "${COMMAND_LOG}" +for test_directory in "${UNTRUSTED_ENV_DIR}" "${INVALID_AGENT_DIR}"; do + cp "${REPOSITORY_ROOT}/start.sh" "${test_directory}/start.sh" + cp "${REPOSITORY_ROOT}/agentctl" "${test_directory}/.launcher/agentctl" + cp "${REPOSITORY_ROOT}/docker-compose.yml" "${test_directory}/docker-compose.yml" + chmod +x "${test_directory}/start.sh" "${test_directory}/.launcher/agentctl" +done + +INJECTION_MARKER="${TEST_ROOT}/env-command-executed" +printf '%s\n' \ + 'AGENT_ID=test-tenant__ISE__12345678-abcd' \ + "ISE_AGENT_NETWORK_MODE=\$(touch \"${INJECTION_MARKER}\")" \ + > "${UNTRUSTED_ENV_DIR}/.env" +if PATH="${BIN_DIR}:${PATH}" \ + ISE_AGENT_TEST_COMMAND_LOG="${COMMAND_LOG}" \ + "${UNTRUSTED_ENV_DIR}/start.sh" --stop; then + echo "Expected an executable network-mode value to be rejected." >&2 + exit 1 +fi +test ! -e "${INJECTION_MARKER}" + +cat > "${UNTRUSTED_ENV_DIR}/.env" <<'EOF' +AGENT_ID=test-tenant__ISE__12345678-abcd +ISE_AGENT_NETWORK_MODE=bridge +ISE_AGENT_NETWORK_MODE=host +EOF +if PATH="${BIN_DIR}:${PATH}" \ + ISE_AGENT_TEST_COMMAND_LOG="${COMMAND_LOG}" \ + "${UNTRUSTED_ENV_DIR}/start.sh" --stop; then + echo "Expected duplicate network-mode values to be rejected." >&2 + exit 1 +fi + +cat > "${INVALID_AGENT_DIR}/.env" <<'EOF' +AGENT_ID=test-tenant__ISE__invalid|sed +EOF +if PATH="${BIN_DIR}:${PATH}" \ + ISE_AGENT_TEST_COMMAND_LOG="${COMMAND_LOG}" \ + ISE_AGENT_RELEASE_ASSET_BASE="file://${RELEASE_DIR}" \ + "${INVALID_AGENT_DIR}/start.sh" --update; then + echo "Expected an unsafe agent ID to be rejected before compose rendering." >&2 + exit 1 +fi +test ! -f "${INVALID_AGENT_DIR}/.launcher/previous/start.sh" + cp "${REPOSITORY_ROOT}/start.sh" "${BOOTSTRAP_DIR}/start.sh" chmod +x "${BOOTSTRAP_DIR}/start.sh" PATH="${BIN_DIR}:${PATH}" \