--- /dev/null
+#!/bin/bash
+
+set -euo pipefail
+
+#####################################################################
+# Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#####################################################################
+
+function display_help_and_exit {
+ echo "Usage: $0 <COMMAND> [ARGS]"
+ echo ""
+ echo "Commands:"
+ echo " r, required Run tests that are required to pass."
+ echo " o, others Run only tests that are not required to pass."
+ echo " s, specified <TEST_NAME>..."
+ echo " Run the specified tests."
+ echo ""
+ echo "Examples:"
+ echo ""
+ echo " Check if all tests that should pass indeed pass:"
+ echo " $ $0 r"
+ echo ""
+ echo " Check if something not required to pass started to pass:"
+ echo " $ $0 o"
+ echo ""
+ echo " Check specified tests (notice that regexes are supported):"
+ echo " $ $0 s security_manager_01c_app_uninstall_wrong_pkg_id '_25.*'"
+ exit 1
+}
+
+if [[ $# == 0 ]]; then
+ display_help_and_exit
+fi
+
+# Tests that are required to pass on no-smack image
+required=(
+ security_manager_01a_app_double_install_double_uninstall
+ security_manager_01b_app_double_install_wrong_pkg_id
+ security_manager_01c_app_uninstall_wrong_pkg_id
+ security_manager_01d_app_install_complicated_dir_tree
+ security_manager_02_app_install_uninstall_full
+ security_manager_02a_set_process_groups
+ security_manager_04b_app_install_by_root_for_app_user
+ security_manager_05_drop_process_capabilities
+ security_manager_06_install_app_offline
+ security_manager_07a_user_add_app_install
+ security_manager_07b_user_add_offline
+ security_manager_08_user_double_add_double_remove
+ security_manager_09a_install_many_apps_in_single_request
+ security_manager_09c_update_many_apps_in_single_request_hybrid_package
+ security_manager_09d_uninstall_app_from_hybrid_package
+ security_manager_09e_update_app_nonhybrid_package
+ security_manager_09f_update_app_hybrid_package
+ security_manager_10_app_has_privilege
+ security_manager_11a_set_identity_system
+ security_manager_11b_set_identity_privileged
+ security_manager_11c_set_identity_app_no_author
+ app_defined_10_check_system_privileges
+ security_manager_22_security_manager_cmd_install
+ security_manager_23_security_manager_cmd_users
+ security_manager_51b_get_id_by_socket_bad_fd
+ security_manager_51e_get_id_by_socket_nulls
+ security_manager_52e_get_id_by_pid_nulls
+ security_manager_53b_get_id_by_cynara_client_wrong_client
+ security_manager_53e_get_id_by_cynara_client_nulls
+ security_manager_24_groups_get
+ security_manager_25a_global_user_set_install_type_global
+ security_manager_25c_global_user_set_install_type_preloaded
+ security_manager_25d_local_user_set_install_type_invalid
+ security_manager_25e_unprivileged_install_type_global
+ security_manager_25f_unprivileged_install_type_preloaded
+ security_manager_25h_local_path_global_install
+ security_manager_25i_local_path_preloaded_install
+ security_manager_25j_global_path_local_install
+ security_manager_26_hybrid_pkg_uninstall_artifacts_check
+ security_manager_26_1_security_manager_get_app_owner_uid
+ security_manager_26_2_security_manager_self_is_app
+ security_manager_26_3_security_manager_is_app_from_pid
+ nss_01_normal_user_without_inter_daemon_groups
+ nss_02_guest_user_without_inter_daemon_groups
+ nss_03_guest_user_without_inter_daemon_groups_unaffected_by_cynara
+ security_manager_101_paths_global_extended
+ security_manager_102_paths_local_extended
+ security_manager_103_paths_global_skel
+ security_manager_104_paths_local_skel
+ security_manager_121a_repair_permissible_file_daemon_global
+ security_manager_121b_repair_permissible_file_daemon_local
+ security_manager_20_user_cynara_policy
+ security_manager_100_synchronize_credentials_test
+ security_manager_100_synchronize_credentials_no_author_test
+ security_manager_101_create_namespace_test_n
+ security_manager_101_create_namespace_test_p
+ security_manager_102_check_propagation_test
+ security_manager_103_policy_change_test
+ security_manager_104_policy_change_kill_app_test
+ security_manager_190_prepare_app_threads_malloc
+ security_manager_200_prepare_app_perf
+ security_manager_300_prepare_app_recursive_threads
+ security_manager_400_prepare_app_with_concurrent_install
+ security_manager_400_prepare_app_series_with_concurrent_install_stress
+ security_manager_16_policy_levels_get
+ security_manager_17a_privacy_manager_delete_policy_for_self
+ security_manager_19a_privacy_manager_privacy_related_privileges_policy_hybrid
+ security_manager_19b_privacy_manager_privacy_related_privileges_policy_no_hybrid
+ security_manager_20_privacy_manager_privacy_related_privileges_policy_admin_check
+ security_manager_21_fetch_app_manifest_invalid_params
+ security_manager_22_fetch_app_manifest_no_app
+ security_manager_24_fetch_app_manifest_global_app
+ security_manager_54_path_req_no_pkg
+ security_manager_55_path_req_empty_pkg
+ security_manager_56_path_req_wrong_type
+ security_manager_57_path_req_wrong_uid
+ security_manager_58_path_req_empty_paths
+ security_manager_59_path_req_as_root_positive
+ security_manager_59a_path_req_as_root_positive_realpath_check
+ security_manager_60_path_req_as_user_positive
+ security_manager_60a_path_req_as_user_positive_realpath_check
+ security_manager_61_path_req_different_user
+ security_manager_62_path_req_path_outside
+ security_manager_63a_path_req_as_user
+ security_manager_63b_path_req_preloaded_as_user
+ security_manager_64a_path_req_as_local_as_root
+ security_manager_64b_path_req_as_local_as_global_user
+ security_manager_66_path_req_check_labels
+ security_manager_67_path_req_shared_ro_3_0
+ security_manager_68_path_req_shared_ro_2_X
+ security_manager_70_path_req_trusted_rw_positive
+ security_manager_82_add_invalid_path_to_app_and_check_all
+ smack_privileges_10_no_privileges
+ smack_privileges_20_internet_privilege
+ smack_privileges_30_one_after_another
+ smack_privileges_40_different_users_one_after_another
+ smack_privileges_50_same_user_simultaneously
+ smack_privileges_60_same_user_interchangeably
+ smack_privileges_70_different_users_simultaneously
+ smack_privileges_80_uninstall_local_while_running
+ smack_privileges_90_user_removal
+ smack_privileges_100_hybrid_app
+ smack_privileges_110_hybridity_change
+ smack_privileges_120_policy_change_while_running
+ smack_privileges_130_different_users_and_policies
+ smack_privileges_140_two_users_sequence
+ smack_privileges_150_independent_apps
+ smack_privileges_160_nonhybrid_package
+ smack_privileges_170_hybrid_package
+ smack_privileges_180_hybrid_package_both_apps_privileged
+ smack_privileges_200_empty_policy
+ smack_privileges_300_multi_policy_no_privs
+ smack_privileges_310_multi_policy_single_priv
+ smack_privileges_320_multi_policy_all_privs
+ smack_privileges_400_malformed
+ security_manager_40_set_wrong_author_id
+ security_manager_41_set_author_id_multiple_times
+)
+
+function run_tests_and_exit {
+ list_passing_tests=false
+ if [[ $1 == '--list-passing-tests' ]]; then
+ shift
+ list_passing_tests=true
+ fi
+
+ tmp_file="$(mktemp)"
+ trap "rm -rf '${tmp_file}'" EXIT
+ passing_tests=()
+ failing_tests=()
+ ignored=0
+ tests_num=${#@}
+ for test in "$@"; do
+ run_tests_num=$((${#passing_tests[@]} + ${#failing_tests[@]} + ignored))
+ printf '[%3i%%] \x1b[1mRunning \x1b[36m%s\x1b[m...\n' "$((run_tests_num * 100 / tests_num))" "${test}"
+ /usr/bin/security-manager-tests --test="${test}" | tee "${tmp_file}" || true
+ if grep --quiet --fixed-strings $'[\x1b[1;32m OK \x1b[m]' "${tmp_file}"; then
+ passing_tests+=("${test}")
+ elif grep --quiet --fixed-strings $'[\x1b[0;36mIgnored \x1b[m]' "${tmp_file}"; then
+ ignored=$((ignored + 1))
+ else
+ failing_tests+=("${test}")
+ fi
+
+ done
+ printf "[100%%] \x1b[1mSummary:\x1b[m\n"
+ printf "\x1b[1;32mOK\x1b[m: ${#passing_tests[@]}\n"
+ printf "\x1b[1;31mFailed\x1b[m: ${#failing_tests[@]}\n"
+ printf "\x1b[1;36mIgnored\x1b[m: ${ignored}\n"
+ if [[ ${#passing_tests[@]} != 0 ]] && [[ "$list_passing_tests" == true ]]; then
+ echo 'Passing tests:'
+ printf '\x2d \x1b[1;32m%s\x1b[m\n' "${passing_tests[@]}"
+ fi
+ if [[ ${#failing_tests[@]} != 0 ]]; then
+ echo 'Failing tests:'
+ printf '\x2d \x1b[1;31m%s\x1b[m\n' "${failing_tests[@]}"
+ exit 1
+ else
+ exit 0
+ fi
+}
+
+function cmd_required {
+ if [[ $# != 1 ]]; then
+ display_help_and_exit
+ fi
+ run_tests_and_exit "${required[@]}"
+}
+
+function cmd_others {
+ if [[ $# != 1 ]]; then
+ display_help_and_exit
+ fi
+ run_tests_and_exit --list-passing-tests $(security-manager-tests --list |
+ cut -d ':' -f 3 |
+ grep --invert-match --file=<(printf '%s\n' "${required[@]}"))
+}
+
+function cmd_specified {
+ shift
+ all_tests="$(security-manager-tests --list | cut -d ':' -f 3)"
+ run_tests_and_exit --list-passing-tests $(for regex in "$@"; do
+ grep --perl-regex "${regex}" <<< "${all_tests}"
+ done | sort | uniq)
+}
+
+if [[ "$1" == "r" ]] || [[ "$1" == "required" ]]; then
+ cmd_required "$@"
+elif [[ "$1" == "o" ]] || [[ "$1" == "others" ]]; then
+ cmd_others "$@"
+elif [[ "$1" == "s" ]] || [[ "$1" == "specified" ]]; then
+ cmd_specified "$@"
+else
+ echo "error: unrecognized command $1"
+ exit 1
+fi