CloudyScripts 1.6.1 → 1.7.27
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -1
- data/lib/audit/checks/APACHE2.group +6 -0
- data/lib/audit/checks/APACHE2_CONFIG_01.check +36 -0
- data/lib/audit/checks/APACHE2_CONFIG_02.check +34 -0
- data/lib/audit/checks/APACHE2_CONFIG_03.check +60 -0
- data/lib/audit/checks/APACHE2_CONFIG_04.check +23 -0
- data/lib/audit/checks/APACHE2_CONFIG_05.check +23 -0
- data/lib/audit/checks/APACHE2_CONFIG_06.check +30 -0
- data/lib/audit/checks/APACHE2_INIT_1.check +14 -0
- data/lib/audit/checks/APACHE2_INIT_2.check +66 -0
- data/lib/audit/checks/APACHE2_INIT_3.check +13 -0
- data/lib/audit/checks/APACHE2_USER_7.check +17 -0
- data/lib/audit/checks/BACKUP_HOME_DOTFILES.check +26 -0
- data/lib/audit/checks/BACKUP_LOG.check +24 -0
- data/lib/audit/checks/BACKUP_MAIL.check +19 -0
- data/lib/audit/checks/BACKUP_WEB.check +12 -0
- data/lib/audit/checks/CONFIGURATION_BACKUP.check +14 -0
- data/lib/audit/checks/DIRECTORY_LISTING.check +14 -0
- data/lib/audit/checks/DISTRIBUTION_FACTS.check +60 -0
- data/lib/audit/checks/DMESG_OUTPUT.check +14 -0
- data/lib/audit/checks/FIND_GROUP_FILE.check +6 -0
- data/lib/audit/checks/FIND_PASSWD_FILE.check +8 -0
- data/lib/audit/checks/FIND_SHADOW_FILE.check +5 -0
- data/lib/audit/checks/FIND_SUDOERS_FILE.check +6 -0
- data/lib/audit/checks/FREE_SPACE.check +26 -0
- data/lib/audit/checks/HAS_AWK.check +30 -0
- data/lib/audit/checks/HAS_BASE.check +21 -0
- data/lib/audit/checks/HAS_CAT.check +18 -0
- data/lib/audit/checks/HAS_COMPRESSOR.check +30 -0
- data/lib/audit/checks/HAS_CUT.check +18 -0
- data/lib/audit/checks/HAS_DF.check +19 -0
- data/lib/audit/checks/HAS_DPKG.check +18 -0
- data/lib/audit/checks/HAS_FILE_DOWNLOADER.check +32 -0
- data/lib/audit/checks/HAS_FIND.check +18 -0
- data/lib/audit/checks/HAS_GREP.check +19 -0
- data/lib/audit/checks/HAS_GROUPCHECK.check +23 -0
- data/lib/audit/checks/HAS_GROUPS.check +19 -0
- data/lib/audit/checks/HAS_HOSTNAME.check +7 -0
- data/lib/audit/checks/HAS_ID.check +7 -0
- data/lib/audit/checks/HAS_LSB_RELEASE.check +16 -0
- data/lib/audit/checks/HAS_MOUNT.check +19 -0
- data/lib/audit/checks/HAS_NETSTAT.check +20 -0
- data/lib/audit/checks/HAS_PASSWD_CHECK.check +17 -0
- data/lib/audit/checks/HAS_PS.check +19 -0
- data/lib/audit/checks/HAS_ROUTE.check +19 -0
- data/lib/audit/checks/HAS_SH.check +19 -0
- data/lib/audit/checks/HAS_SORT.check +17 -0
- data/lib/audit/checks/HAS_STAT.check +17 -0
- data/lib/audit/checks/HAS_SUPERUSER.check +11 -0
- data/lib/audit/checks/HAS_TAIL.check +16 -0
- data/lib/audit/checks/HAS_TAR.check +7 -0
- data/lib/audit/checks/HAS_TR.check +22 -0
- data/lib/audit/checks/HAS_UNAME.check +7 -0
- data/lib/audit/checks/HAS_UNIQ.check +17 -0
- data/lib/audit/checks/HAS_WC.check +16 -0
- data/lib/audit/checks/HAS_WHO.check +18 -0
- data/lib/audit/checks/HAS_YUM.check +18 -0
- data/lib/audit/checks/LASTLOG.check +28 -0
- data/lib/audit/checks/LIST_ROUTES.check +33 -0
- data/lib/audit/checks/LIST_USER_ACCOUNTS.check +25 -0
- data/lib/audit/checks/LOADED_MODULES.check +22 -0
- data/lib/audit/checks/LOCAL_NMAP.check +97 -0
- data/lib/audit/checks/LOGGED_USERS.check +28 -0
- data/lib/audit/checks/LYNIS_AUTH.group +9 -0
- data/lib/audit/checks/LYNIS_AUTH_9204.check +43 -0
- data/lib/audit/checks/LYNIS_AUTH_9208.check +35 -0
- data/lib/audit/checks/LYNIS_AUTH_9216.check +24 -0
- data/lib/audit/checks/LYNIS_AUTH_9222.check +25 -0
- data/lib/audit/checks/LYNIS_AUTH_9226.check +24 -0
- data/lib/audit/checks/LYNIS_AUTH_9228.check +24 -0
- data/lib/audit/checks/LYNIS_AUTH_9252.check +19 -0
- data/lib/audit/checks/MAYBE_HAS_BZIP2.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_CURL.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_DU.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_HOSTNAME.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_ID.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_LSB_RELEASE.check +15 -0
- data/lib/audit/checks/MAYBE_HAS_SUPERUSER.check +36 -0
- data/lib/audit/checks/MAYBE_HAS_TAR.check +19 -0
- data/lib/audit/checks/MAYBE_HAS_UNAME.check +17 -0
- data/lib/audit/checks/MAYBE_HAS_WGET.check +17 -0
- data/lib/audit/checks/MOUNTED_DEVICES.check +22 -0
- data/lib/audit/checks/MYSQL_HISTORY_1.check +29 -0
- data/lib/audit/checks/MYSQL_INIT_1.check +9 -0
- data/lib/audit/checks/MYSQL_INIT_2.check +12 -0
- data/lib/audit/checks/MYSQL_INIT_3.check +7 -0
- data/lib/audit/checks/PACKAGES_INSTALLED_DPKG.check +38 -0
- data/lib/audit/checks/PACKAGES_INSTALLED_YUM.check +36 -0
- data/lib/audit/checks/PASSWORD_INFORMATION.check +33 -0
- data/lib/audit/checks/PLATFORM_FACTS.check +35 -0
- data/lib/audit/checks/PORTS_OPEN_NETSTAT.check +121 -0
- data/lib/audit/checks/PROCESS_LIST.check +87 -0
- data/lib/audit/checks/SLOW.group +7 -0
- data/lib/audit/checks/SLOW_1.check +4 -0
- data/lib/audit/checks/SLOW_2.check +4 -0
- data/lib/audit/checks/SLOW_3.check +4 -0
- data/lib/audit/checks/SSH.group +14 -0
- data/lib/audit/checks/SSH_CONFIG_01.check +12 -0
- data/lib/audit/checks/SSH_CONFIG_02.check +15 -0
- data/lib/audit/checks/SSH_CONFIG_03.check +13 -0
- data/lib/audit/checks/SSH_CONFIG_04.check +11 -0
- data/lib/audit/checks/SSH_CONFIG_05.check +12 -0
- data/lib/audit/checks/SSH_CONFIG_06.check +12 -0
- data/lib/audit/checks/SSH_CONFIG_07.check +11 -0
- data/lib/audit/checks/SSH_CONFIG_08.check +12 -0
- data/lib/audit/checks/SSH_CONFIG_09.check +12 -0
- data/lib/audit/checks/SSH_CONFIG_10.check +15 -0
- data/lib/audit/checks/SSH_CONFIG_11.check +14 -0
- data/lib/audit/checks/SSH_INIT_1.check +9 -0
- data/lib/audit/checks/SSH_INIT_2.check +12 -0
- data/lib/audit/checks/SSH_KEYS_1.check +32 -0
- data/lib/audit/checks/USERS_INIT_1.check +9 -0
- data/lib/audit/checks/USERS_INIT_2.check +5 -0
- data/lib/audit/checks/USERS_INIT_3.check +5 -0
- data/lib/audit/checks/USERS_INIT_4.check +9 -0
- data/lib/audit/checks/USERS_INIT_5.check +10 -0
- data/lib/audit/checks/USER_INFORMATION.check +29 -0
- data/lib/audit/checks/VARIOUS.group +19 -0
- data/lib/audit/checks/VAR_LIST_HOME_DIRECTORIES.check +5 -0
- data/lib/audit/checks/benchmark.group +6 -0
- data/lib/audit/checks/footer.template +12 -0
- data/lib/audit/checks/header.template +10 -0
- data/lib/audit/checks/helpers/head.sh +59 -0
- data/lib/audit/checks/script_header.template +69 -0
- data/lib/audit/create_benchmark.sh +93 -0
- data/lib/audit/lib/audit.rb +136 -0
- data/lib/audit/lib/audit_facade.rb +5 -0
- data/lib/audit/lib/benchmark/audit_benchmark.rb +165 -0
- data/lib/audit/lib/benchmark/automatic_dependencies.rb +13 -0
- data/lib/audit/lib/benchmark/benchmark_factory.rb +23 -0
- data/lib/audit/lib/benchmark/benchmark_result.rb +25 -0
- data/lib/audit/lib/benchmark/check.rb +34 -0
- data/lib/audit/lib/benchmark/group.rb +30 -0
- data/lib/audit/lib/benchmark/item_exception.rb +13 -0
- data/lib/audit/lib/benchmark/result_code.rb +11 -0
- data/lib/audit/lib/benchmark/rule_result.rb +42 -0
- data/lib/audit/lib/benchmark/rule_role.rb +5 -0
- data/lib/audit/lib/benchmark/rule_severity.rb +13 -0
- data/lib/audit/lib/benchmark/yaml_benchmark.rb +133 -0
- data/lib/audit/lib/connection/ami_connection.rb +4 -0
- data/lib/audit/lib/connection/connection_factory.rb +27 -0
- data/lib/audit/lib/connection/ssh_connection.rb +243 -0
- data/lib/audit/lib/ec2_utils.rb +245 -0
- data/lib/audit/lib/http_fingerprint.rb +116 -0
- data/lib/audit/lib/lazy.rb +37 -0
- data/lib/audit/lib/linear_script_generator.rb +31 -0
- data/lib/audit/lib/main.rb +13 -0
- data/lib/audit/lib/my_option_parser.rb +106 -0
- data/lib/audit/lib/nessus_new.rb +290 -0
- data/lib/audit/lib/nessus_utils.rb +102 -0
- data/lib/audit/lib/parser/command/abstract_command.rb +32 -0
- data/lib/audit/lib/parser/command/abstract_command_result.rb +30 -0
- data/lib/audit/lib/parser/command/attach_file_command.rb +63 -0
- data/lib/audit/lib/parser/command/check_finished_command.rb +45 -0
- data/lib/audit/lib/parser/command/cpe_name_command.rb +37 -0
- data/lib/audit/lib/parser/command/data_command.rb +43 -0
- data/lib/audit/lib/parser/command/listening_port_command.rb +46 -0
- data/lib/audit/lib/parser/command/message_command.rb +21 -0
- data/lib/audit/lib/parser/command/program_name_command.rb +42 -0
- data/lib/audit/lib/parser/parse_exception.rb +2 -0
- data/lib/audit/lib/parser/result_type.rb +13 -0
- data/lib/audit/lib/parser/script_output_parser.rb +201 -0
- data/lib/audit/lib/parser/stdout_line_buffer.rb +43 -0
- data/lib/audit/lib/ssh_fingerprint.rb +220 -0
- data/lib/audit/lib/ssh_fingerprint2.rb +170 -0
- data/lib/audit/lib/ssh_utils.rb +292 -0
- data/lib/audit/lib/transformers/web_view_transformer.rb +171 -0
- data/lib/audit/lib/transformers/yaml_transformer.rb +50 -0
- data/lib/audit/lib/util/random_string.rb +22 -0
- data/lib/audit/lib/version.rb +7 -0
- data/lib/help/ec2_helper.rb +65 -2
- data/lib/help/remote_command_handler.rb +17 -0
- data/lib/help/state_transition_helper.rb +8 -0
- data/lib/scripts/ec2/open_port_checker.rb +112 -0
- data/lib/scripts/ec2/port_range_detector.rb +0 -1
- metadata +175 -16
@@ -0,0 +1,5 @@
|
|
1
|
+
ID: VAR_LIST_HOME_DIRECTORIES
|
2
|
+
Depends: [USERS_INIT_1, HAS_CAT, HAS_TR, HAS_CUT, HAS_SED]
|
3
|
+
Description: Export colon-separated home directory list from /etc/passwd.
|
4
|
+
Type: [export]
|
5
|
+
Script: "export HOME_DIRS_LIST=$(${CAT} /etc/passwd | ${CUT} -d: -f6 | ${TR} '\n' ':' | ${SED} -e 's/:$//')"
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
if [ "${1##--}" = "version" ]
|
4
|
+
then
|
5
|
+
echo "internal helper"
|
6
|
+
exit 0
|
7
|
+
fi
|
8
|
+
|
9
|
+
|
10
|
+
NB_LINES=${1##-}
|
11
|
+
|
12
|
+
#test if number of lines parameter is really numerical
|
13
|
+
NB_LINES_FILTERED=${NB_LINES##[0-9]}
|
14
|
+
NB_LINES_FILTERED=${NB_LINES_FILTERED##[0-9]}
|
15
|
+
NB_LINES_FILTERED=${NB_LINES_FILTERED##[0-9]}
|
16
|
+
if [ -z "${NB_LINES_FILTERED}" ]
|
17
|
+
then
|
18
|
+
shift
|
19
|
+
else
|
20
|
+
NB_LINES=10
|
21
|
+
fi
|
22
|
+
|
23
|
+
#if 0 lines of head, simply return
|
24
|
+
if [ "${NB_LINES}" -le 0 ]
|
25
|
+
then
|
26
|
+
return 0
|
27
|
+
fi
|
28
|
+
|
29
|
+
# test if second parameter is given
|
30
|
+
if [ -z "$1" ]
|
31
|
+
then
|
32
|
+
INPUT_FILE=/dev/stdin
|
33
|
+
else
|
34
|
+
TEMPFILE=/tmp/$$
|
35
|
+
mkfifo ${TEMPFILE}
|
36
|
+
cat "$1" > ${TEMPFILE} &
|
37
|
+
INPUT_FILE=${TEMPFILE}
|
38
|
+
fi
|
39
|
+
|
40
|
+
#read each line and count down the line counter
|
41
|
+
while read LINE < ${INPUT_FILE}
|
42
|
+
do
|
43
|
+
echo ${LINE}
|
44
|
+
NB_LINES=$((${NB_LINES}-1))
|
45
|
+
#if line counter reaches zero, it's finished
|
46
|
+
if [ "${NB_LINES}" -le 0 ]
|
47
|
+
then
|
48
|
+
if [ ! -z "${TEMPFILE}" ]
|
49
|
+
then
|
50
|
+
rm ${TEMPFILE}
|
51
|
+
fi
|
52
|
+
return 0
|
53
|
+
fi
|
54
|
+
done
|
55
|
+
|
56
|
+
if [ ! -z "${TEMPFILE}" ]
|
57
|
+
then
|
58
|
+
rm ${TEMPFILE}
|
59
|
+
fi
|
@@ -0,0 +1,69 @@
|
|
1
|
+
|
2
|
+
###################################################
|
3
|
+
# Auditor scanning script #########################
|
4
|
+
###################################################
|
5
|
+
# (C) 2010 SecludIT, Jonas Zaddach ################
|
6
|
+
###################################################
|
7
|
+
|
8
|
+
script_raw_message() {
|
9
|
+
msg="%% ${MY_SCRIPT_ID}"
|
10
|
+
for val in "$@"
|
11
|
+
do
|
12
|
+
if [ ! val = "" ]
|
13
|
+
then
|
14
|
+
msg="${msg} %% ${val}"
|
15
|
+
fi
|
16
|
+
done
|
17
|
+
echo "${msg}"
|
18
|
+
}
|
19
|
+
|
20
|
+
script_message() {
|
21
|
+
script_raw_message "$1" "MESSAGE" "$2"
|
22
|
+
}
|
23
|
+
|
24
|
+
script_info_message() {
|
25
|
+
script_message "INFO" "$1"
|
26
|
+
}
|
27
|
+
|
28
|
+
script_warn_message() {
|
29
|
+
script_message "WARN" "$1"
|
30
|
+
}
|
31
|
+
|
32
|
+
script_error_message() {
|
33
|
+
script_message "ERROR" "$1"
|
34
|
+
}
|
35
|
+
|
36
|
+
script_return() {
|
37
|
+
script_raw_message "INFO" "CHECK_FINISHED" "$1"
|
38
|
+
}
|
39
|
+
|
40
|
+
script_program_name() {
|
41
|
+
script_raw_message "INFO" "PROGRAM_NAME" "$1" "$2"
|
42
|
+
}
|
43
|
+
|
44
|
+
script_not_found() {
|
45
|
+
script_raw_message "ERROR" "NOT_FOUND" "$1"
|
46
|
+
}
|
47
|
+
|
48
|
+
script_data() {
|
49
|
+
script_raw_message "INFO" "DATA" "$1" "$2"
|
50
|
+
}
|
51
|
+
|
52
|
+
script_debug() {
|
53
|
+
echo "$1" 1>&2
|
54
|
+
}
|
55
|
+
|
56
|
+
script_attach_file() {
|
57
|
+
script_raw_message "INFO" "ATTACH_FILE" "$1" "$2"
|
58
|
+
}
|
59
|
+
|
60
|
+
|
61
|
+
script_set_exit_code() {
|
62
|
+
/bin/sh -c "exit $1"
|
63
|
+
}
|
64
|
+
|
65
|
+
# create directory that can be used to store audit files
|
66
|
+
AUDIT_DIRECTORY="/tmp/audit"
|
67
|
+
rm -Rf ${AUDIT_DIRECTORY}
|
68
|
+
mkdir -p ${AUDIT_DIRECTORY}
|
69
|
+
|
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
BENCHMARK_FILE=$1
|
4
|
+
ZIP_FILE=$2
|
5
|
+
MISC_FILES="script_header.template header.template footer.template"
|
6
|
+
REPOSIT="checks"
|
7
|
+
|
8
|
+
if [ "${BENCHMARK_FILE}" = "" ] || [ "${ZIP_FILE}" = "" ]
|
9
|
+
then
|
10
|
+
echo "USAGE: "$0" <benchmark group file> <target zip file>"
|
11
|
+
exit 1
|
12
|
+
fi
|
13
|
+
|
14
|
+
#check that identifiers are unique
|
15
|
+
DUPLICATE_IDENTIFIERS=$( cd $REPOSIT && ls -1 *.check *.group | sed -e 's/\.[^.]*$//' | sort | uniq -d )
|
16
|
+
|
17
|
+
if [ ! "${DUPLICATE_IDENTIFIERS}" = "" ]
|
18
|
+
then
|
19
|
+
for f in $( echo ${DUPLICATE_IDENTIFIERS} )
|
20
|
+
do
|
21
|
+
echo "WARNING: There exist several files with the same identifier: $f"
|
22
|
+
done
|
23
|
+
fi
|
24
|
+
|
25
|
+
#check for identifiers that do not correspond to file names
|
26
|
+
WRONG_IDENTIFIERS=""
|
27
|
+
|
28
|
+
cd $REPOSIT
|
29
|
+
for f in *.check *.group
|
30
|
+
do
|
31
|
+
FILENAME_ID=$( echo $f | sed -e 's/.[^.]*$//' )
|
32
|
+
INTERNAL_ID=$( grep "ID:" $f | sed -e 's/^ID:\s*//' )
|
33
|
+
|
34
|
+
if [ ! "${FILENAME_ID}" = "${INTERNAL_ID}" ]
|
35
|
+
then
|
36
|
+
echo "WARNING: ID in file $f is different from file name"
|
37
|
+
fi
|
38
|
+
done
|
39
|
+
|
40
|
+
#if zip file exists already, delete it
|
41
|
+
rm -f ../${ZIP_FILE}
|
42
|
+
|
43
|
+
#build list of tests required by benchmark
|
44
|
+
CHECKS_FIFO="${BENCHMARK_FILE%.group}"
|
45
|
+
DONE_CHECKS=""
|
46
|
+
|
47
|
+
while [ ! "${CHECKS_FIFO}" = "" ]
|
48
|
+
do
|
49
|
+
CURRENT_CHECK=$( echo ${CHECKS_FIFO} | cut -d" " -f1 )
|
50
|
+
CHECKS_FIFO=$( echo ${CHECKS_FIFO} | sed -e "s/${CURRENT_CHECK}//" )
|
51
|
+
DONE_CHECKS="${DONE_CHECKS} ${CURRENT_CHECK}"
|
52
|
+
|
53
|
+
echo "adding check: ${CURRENT_CHECK}"
|
54
|
+
|
55
|
+
if [ -f "${CURRENT_CHECK}.group" ]
|
56
|
+
then
|
57
|
+
CHILDREN=$( ruby -r "yaml" -e "File.open('${CURRENT_CHECK}.group') {|f| x = YAML::load(f)['Children']; print x ? x.join(' ') : '' }" )
|
58
|
+
#add child if it is not already in benchmark
|
59
|
+
for f in $( echo ${CHILDREN} )
|
60
|
+
do
|
61
|
+
if ( ! echo ${CHECKS_FIFO} | grep $f 2>/dev/null 1>/dev/null ) && ( ! echo ${DONE_CHECKS} | grep $f 2>/dev/null 1>/dev/null )
|
62
|
+
then
|
63
|
+
CHECKS_FIFO="${CHECKS_FIFO} $f"
|
64
|
+
fi
|
65
|
+
done
|
66
|
+
|
67
|
+
zip -9 ../${ZIP_FILE} "${CURRENT_CHECK}.group" 2>/dev/null 1>/dev/null
|
68
|
+
elif [ -f "${CURRENT_CHECK}.check" ]
|
69
|
+
then
|
70
|
+
# get list of dependencies
|
71
|
+
DEPENDENCIES=$( ruby -r "yaml" -e "File.open('${CURRENT_CHECK}.check') {|f| x = YAML::load(f)['Depends']; print x ? x.join(' ') : '' }" )
|
72
|
+
|
73
|
+
for f in $( echo ${DEPENDENCIES} )
|
74
|
+
do
|
75
|
+
if ( ! echo ${CHECKS_FIFO} | grep $f 2>/dev/null 1>/dev/null ) && ( ! echo ${DONE_CHECKS} | grep $f 2>/dev/null 1>/dev/null )
|
76
|
+
then
|
77
|
+
CHECKS_FIFO="${CHECKS_FIFO} $f"
|
78
|
+
fi
|
79
|
+
done
|
80
|
+
|
81
|
+
zip -9 ../${ZIP_FILE} "${CURRENT_CHECK}.check" 2>/dev/null 1>/dev/null
|
82
|
+
else
|
83
|
+
echo "WARNING: Unsatisfied dependency: ${CURRENT_CHECK}"
|
84
|
+
fi
|
85
|
+
done
|
86
|
+
|
87
|
+
for f in $( echo ${MISC_FILES} )
|
88
|
+
do
|
89
|
+
echo "adding file: $f"
|
90
|
+
zip -9 ../${ZIP_FILE} $f 2>/dev/null 1>/dev/null
|
91
|
+
done
|
92
|
+
|
93
|
+
cd -
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
require 'connection/connection_factory'
|
4
|
+
require 'benchmark/benchmark_factory'
|
5
|
+
require 'linear_script_generator'
|
6
|
+
require 'parser/script_output_parser'
|
7
|
+
require 'util/random_string'
|
8
|
+
require 'benchmark/benchmark_result'
|
9
|
+
require 'lazy'
|
10
|
+
|
11
|
+
class Audit
|
12
|
+
attr_reader :benchmark
|
13
|
+
attr_reader :connection
|
14
|
+
attr_reader :start_time
|
15
|
+
attr_reader :end_time
|
16
|
+
attr_reader :results
|
17
|
+
attr_reader :exceptions
|
18
|
+
|
19
|
+
# Create a new audit.
|
20
|
+
# The audit will be initialized, but not started.
|
21
|
+
# * <em>benchmark</em> is a path string that points to the benchmark file
|
22
|
+
# that should be used for the audit.
|
23
|
+
# * <em>attachment_dir</em> is a path string that points to the directory where incoming
|
24
|
+
# files will be saved (that directory needs to be writable). If a null value
|
25
|
+
# is passed, ATTACH_FILE requests will be ignored and no files will be saved.
|
26
|
+
# * <em>connection_type</em> is a symbol for the connection type that will be used.
|
27
|
+
# Anything that can be given to the ConnectionFactory (connection/ConnectionFactory::create)
|
28
|
+
# is valid (:ssh, ...)
|
29
|
+
# * <em>connection_params</em> is a dictionary of connection parameters that are
|
30
|
+
# specific to the connection type chosen with <em>connection_type</em>. See the
|
31
|
+
# ConnectionFactory class for more datails.
|
32
|
+
# * <em>logger</em> is an optional logger that the debug output is logged to
|
33
|
+
def initialize(options)
|
34
|
+
raise "Option :benchmark is required" unless options[:benchmark]
|
35
|
+
# raise "Option :attachment_dir is required" unless options[:attachment_dir]
|
36
|
+
raise "Option :connection_type is required" unless options[:connection_type]
|
37
|
+
raise "Option :connection_params is required" unless options[:connection_params]
|
38
|
+
|
39
|
+
if options[:logger] then
|
40
|
+
@logger = options[:logger]
|
41
|
+
else
|
42
|
+
@logger = Logger.new(STDOUT)
|
43
|
+
end
|
44
|
+
|
45
|
+
@benchmark = BenchmarkFactory.new(:logger => @logger).load(:benchmark => options[:benchmark])
|
46
|
+
@connection = ConnectionFactory.new(:logger => @logger).create(:connection_type => options[:connection_type],
|
47
|
+
:connection_params => options[:connection_params])
|
48
|
+
@results = {}
|
49
|
+
@exceptions = []
|
50
|
+
@attachment_dir = options[:attachment_dir]
|
51
|
+
end
|
52
|
+
|
53
|
+
def start(parallel = true)
|
54
|
+
@start_time = Time.now.utc
|
55
|
+
|
56
|
+
launch_audit = Proc.new do
|
57
|
+
remote_script_path = "/tmp/" + RandomString::generate() + ".sh"
|
58
|
+
script = LinearScriptGenerator.generate(@benchmark)
|
59
|
+
|
60
|
+
@connection.open() do|conn|
|
61
|
+
conn.write_to_remote_file(script, remote_script_path)
|
62
|
+
@response_parser = ScriptOutputParser.new(:benchmark => @benchmark,
|
63
|
+
:connection => conn,
|
64
|
+
:attachment_dir => @attachment_dir,
|
65
|
+
:logger => @logger)
|
66
|
+
@response_parser.on_check_completed() do|rule_result|
|
67
|
+
@results[rule_result.rule_idref] = rule_result
|
68
|
+
@check_completed_handler.call(rule_result) unless @check_completed_handler.nil?
|
69
|
+
end
|
70
|
+
@response_parser.on_finished() do|benchmark, rule_results|
|
71
|
+
@end_time = Time.now.utc
|
72
|
+
@finished_handler.call(benchmark, rule_results) unless @finished_handler.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
conn.exec("/bin/sh " + remote_script_path)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
if (parallel) then
|
80
|
+
begin
|
81
|
+
Thread.new {launch_audit.call}
|
82
|
+
rescue Exception => ex
|
83
|
+
exceptions << ex
|
84
|
+
@logger.error {"Exception type: #{ex.class.name}"}
|
85
|
+
@logger.error {"=== stack trace of exception #{ex.message}"}
|
86
|
+
ex.backtrace.each do|line|
|
87
|
+
@logger.error {line}
|
88
|
+
end
|
89
|
+
@logger.error {"=== end stack trace"}
|
90
|
+
end
|
91
|
+
else
|
92
|
+
launch_audit.call
|
93
|
+
end
|
94
|
+
return self
|
95
|
+
end
|
96
|
+
|
97
|
+
def on_check_completed(&block)
|
98
|
+
@check_completed_handler = block
|
99
|
+
end
|
100
|
+
|
101
|
+
def on_finished(&block)
|
102
|
+
@finished_handler = block
|
103
|
+
end
|
104
|
+
|
105
|
+
def progress()
|
106
|
+
return ((@response_parser.progress() unless @response_parser.nil?) or 0.0)
|
107
|
+
end
|
108
|
+
|
109
|
+
def abort()
|
110
|
+
@connection.abort() if @connection
|
111
|
+
end
|
112
|
+
|
113
|
+
def finished?()
|
114
|
+
return !end_time.nil?
|
115
|
+
end
|
116
|
+
|
117
|
+
def name()
|
118
|
+
return (@benchmark.name || @benchmark.id) + "#" + @connection.to_s() + (@start_time ? "#" + @start_time.to_s() : "")
|
119
|
+
end
|
120
|
+
|
121
|
+
def remaining_time()
|
122
|
+
return @benchmark.duration() if @response_parser.nil?
|
123
|
+
return @response_parser.remaining_time()
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_hash()
|
127
|
+
return {
|
128
|
+
:type => :AUDIT,
|
129
|
+
:start_time => @start_time,
|
130
|
+
:end_time => @end_time,
|
131
|
+
:connection => @connection.to_hash(),
|
132
|
+
:benchmark => @benchmark.to_hash(),
|
133
|
+
:results => Lazy.new(@results.values(), :map) {|x| Lazy.new(x, :to_hash)}
|
134
|
+
}
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'benchmark/check'
|
2
|
+
require 'benchmark/item_exception'
|
3
|
+
require 'lazy'
|
4
|
+
|
5
|
+
class AuditBenchmark
|
6
|
+
attr_reader :item_repository
|
7
|
+
|
8
|
+
def execution_order()
|
9
|
+
# resolve dependencies between checks based on the depends-tag of the checks.
|
10
|
+
# In a first pass, all dependencies are discovered iteratively popping checks
|
11
|
+
# from a queue of checks with unresolved dependencies, pushing them onto a resolved
|
12
|
+
# queue and pushing the check's dependencies onto the unresolved queue if they
|
13
|
+
# are not yet in the resolved or unresolved queue. Also, the reversed dependencies
|
14
|
+
# (which check is needed by which) are stored for the second pass.
|
15
|
+
#
|
16
|
+
# In a second pass, starting from checks which do not depend on any other checks,
|
17
|
+
# all checks are labelled with the dependency level they're in. Checks without dependencies
|
18
|
+
# have dependency level 0, checks which rely on checks from level 0 have level 1,
|
19
|
+
# and so on. This is not the optimal solution for the problem ... but I have forgot why,
|
20
|
+
# so figure this out yourself.
|
21
|
+
#
|
22
|
+
# You might wonder why I don't do dependency tracking with the Imports and Exports
|
23
|
+
# declarations: If there are two scripts which provide a variable (alternatives),
|
24
|
+
# it is very easy to write a mediating script, which chooses one of the provider scripts,
|
25
|
+
# and then can be depended on, but it is very hard to do the resolution based on
|
26
|
+
# imports and exports. So imagine this like the linker, which uses library/object
|
27
|
+
# names to include dependencies, but still checks that all symbols are resolved
|
28
|
+
# correctly (TODO: Add a check that all Imports are satisfied by Exports)
|
29
|
+
|
30
|
+
#find all dependencies
|
31
|
+
items = @children.dup
|
32
|
+
|
33
|
+
unresolved = []
|
34
|
+
while not items.empty?
|
35
|
+
item = items.shift
|
36
|
+
if item.class == Group
|
37
|
+
item.children.each do|x|
|
38
|
+
items << x unless items.include? x or unresolved.include? x
|
39
|
+
end
|
40
|
+
elsif item.class == Check
|
41
|
+
unresolved << item
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
resolved = []
|
46
|
+
dependency_root = []
|
47
|
+
reversed_dependencies = {}
|
48
|
+
iterations = 0
|
49
|
+
|
50
|
+
while !unresolved.empty? and iterations < @item_repository.length
|
51
|
+
cur = unresolved.shift
|
52
|
+
|
53
|
+
dependency_root.push(cur) if cur.dependencies.empty? and not dependency_root.include? cur
|
54
|
+
|
55
|
+
cur.dependencies.each do|dep|
|
56
|
+
unresolved.push dep unless unresolved.include? dep or resolved.include? dep
|
57
|
+
reversed_dependencies[dep] = [] if reversed_dependencies[dep].nil?
|
58
|
+
reversed_dependencies[dep] << cur
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
untagged = []
|
63
|
+
tagged = []
|
64
|
+
|
65
|
+
dependency_root.each {|x| untagged.push(x)}
|
66
|
+
untagged.push(:NEXT_LEVEL)
|
67
|
+
|
68
|
+
level = 0
|
69
|
+
while untagged.length > 1
|
70
|
+
cur = untagged.shift
|
71
|
+
|
72
|
+
if cur == :NEXT_LEVEL then
|
73
|
+
level = level + 1
|
74
|
+
untagged.push(:NEXT_LEVEL)
|
75
|
+
next
|
76
|
+
end
|
77
|
+
|
78
|
+
tag = tagged.select {|x| x[:check] == cur}
|
79
|
+
if tag.empty? then
|
80
|
+
tagged << {:level => level, :check => cur}
|
81
|
+
else
|
82
|
+
raise "multiple tags for check #{cur.id} found" if tag.length != 1
|
83
|
+
|
84
|
+
tag[0][:level] = level
|
85
|
+
end
|
86
|
+
|
87
|
+
unless reversed_dependencies[cur].nil? then
|
88
|
+
reversed_dependencies[cur].each {|x| untagged.push(x)}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
retval = []
|
93
|
+
(0 .. level).each {|i| retval.push(tagged.select {|x| x[:level] == i}.map {|x| x[:check]})}
|
94
|
+
|
95
|
+
return retval
|
96
|
+
end
|
97
|
+
|
98
|
+
def element(name)
|
99
|
+
@elements = {} unless @elements
|
100
|
+
@elements[name] = element_impl(name) unless @elements[name]
|
101
|
+
|
102
|
+
return @elements[name]
|
103
|
+
end
|
104
|
+
|
105
|
+
def rules()
|
106
|
+
untraversed = @children.dup
|
107
|
+
rules = []
|
108
|
+
|
109
|
+
while untraversed.length > 0
|
110
|
+
item = untraversed.shift
|
111
|
+
|
112
|
+
if item.kind_of? Group then
|
113
|
+
untraversed = untraversed + item.children
|
114
|
+
elsif item.kind_of? Check then
|
115
|
+
rules << item
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
return rules.uniq
|
120
|
+
end
|
121
|
+
|
122
|
+
def dependencies()
|
123
|
+
return (rules().map {|x| x.dependencies }.flatten()).uniq
|
124
|
+
end
|
125
|
+
|
126
|
+
def automatic_dependencies()
|
127
|
+
return dependencies() - rules()
|
128
|
+
end
|
129
|
+
|
130
|
+
# def checks()
|
131
|
+
# checks = []
|
132
|
+
# not_traversed = @children.dup
|
133
|
+
#
|
134
|
+
# while !not_traversed.empty? do
|
135
|
+
# item = not_traversed.shift
|
136
|
+
#
|
137
|
+
# if (item.class == Group) then
|
138
|
+
# item.children.each do |child|
|
139
|
+
# not_traversed << child unless not_traversed.include? child
|
140
|
+
# end
|
141
|
+
# elsif item.class == Check then
|
142
|
+
# checks << item
|
143
|
+
# item.dependencies.each do |dep|
|
144
|
+
# not_traversed << dep unless not_traversed.include? dep
|
145
|
+
# end
|
146
|
+
# end
|
147
|
+
# end
|
148
|
+
#
|
149
|
+
# return checks
|
150
|
+
# end
|
151
|
+
|
152
|
+
def duration()
|
153
|
+
execution_order().flatten().each().inject(0) {|result, element| result + element.duration}
|
154
|
+
end
|
155
|
+
|
156
|
+
def to_hash()
|
157
|
+
return {
|
158
|
+
:type => :BENCHMARK,
|
159
|
+
:id => @id,
|
160
|
+
:name => @name,
|
161
|
+
:description => @description,
|
162
|
+
:children => Lazy.new(Lazy.new(@children, :reject) {|x| !x.in_report?}, :map) {|child| Lazy.new(child, :to_hash)}
|
163
|
+
}
|
164
|
+
end
|
165
|
+
end
|