Skip to content

Instantly share code, notes, and snippets.

@dmiller-nmap
Forked from bonsaiviking/pre-commit
Last active April 11, 2024 16:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dmiller-nmap/04d166bdd7872993fedb50db7fe90ac5 to your computer and use it in GitHub Desktop.
Save dmiller-nmap/04d166bdd7872993fedb50db7fe90ac5 to your computer and use it in GitHub Desktop.
Pre-commit git hook for Nmap (WIP)
#!/bin/bash
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments. The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
if git rev-parse --verify HEAD >/dev/null 2>&1
then
against=HEAD
else
# Initial commit: diff against an empty tree object
against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# If you want to allow non-ascii filenames set this variable to true.
allownonascii=$(git config hooks.allownonascii)
# Redirect output to stderr.
exec 1>&2
# Cross platform projects tend to avoid non-ascii filenames; prevent
# them from being added to the repository. We exploit the fact that the
# printable range starts at the space character and ends with tilde.
if [ "$allownonascii" != "true" ] &&
# Note that the use of brackets around a tr range is ok here, (it's
# even required, for portability to Solaris 10's /usr/bin/tr), since
# the square bracket bytes happen to fall in the designated range.
test $(git diff --cached --name-only --diff-filter=A -z $against |
LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
then
echo "Error: Attempt to add a non-ascii file name."
echo
echo "This can cause problems if you want to work"
echo "with people on other platforms."
echo
echo "To be portable it is advisable to rename the file ..."
echo
echo "If you know what you are doing you can disable this"
echo "check using:"
echo
echo " git config hooks.allownonascii true"
echo
exit 1
fi
if [ -z "$GIT_NOWS" ]; then
echo "whitespace check..."
# If there are whitespace errors, print the offending file names and fail.
git diff-index --check --cached $against -- || exit 1
fi
if [ -z "$GIT_NOPEP8" ]; then
echo "PEP 8 check..."
PEP8=$(which pep8)
PEP8IGNORE=${PEP8IGNORE:-E123,E124,E126,E127,E128,E402}
if [ -z $PEP8 ]; then
echo "No pep8 in your path. Skipping Python checks"
else
FILES=$(git diff --cached --name-status | grep -v ^D | awk '$1 $2 { print $2}' | grep -e '\.py$')
if [ -n "$FILES" ]; then
for file in $FILES; do
OUTPUT=$(mktemp)
INPUT=$(mktemp)
git show ":$file" > "$INPUT"
"$PEP8" "${PEP8IGNORE:+--ignore=$PEP8IGNORE}" -r "$INPUT" > "$OUTPUT"
if [ -s "$OUTPUT" ]; then
sed "s|$INPUT|$file|" < "$OUTPUT" > /dev/stderr
rm -f "$OUTPUT" "$INPUT"
exit 1
fi
rm -f "$OUTPUT" "$INPUT"
done
fi
fi
fi
echo "Lua checks..."
if [ -z "$GIT_NONSEDOC" ]; then
FILES=$(git diff --cached --name-status | grep -v ^D | awk '$1 $2 { print $2}' | grep -E '\.(nse|lua(doc)?)$')
if [ -n "$FILES" ]; then
perl -lne 'if(/^---/){close ARGV;next}if(/^-- *@/){print "$ARGV:$.:$_";close ARGV;next}' $FILES | grep .
if [ $? -eq 0 ]; then
exit 1
fi
fi
fi
TOPDIR=$(git rev-parse --show-toplevel)
if [ -x "$TOPDIR/lua" ]; then
LUA=${LUA:-$TOPDIR/lua}
elif [ -x "$TOPDIR/liblua/lua" ]; then
LUA=${LUA:-$TOPDIR/liblua/lua}
fi
if [ -x "$TOPDIR/luac" ]; then
LUAC=${LUAC:-$TOPDIR/luac}
elif [ -x "$TOPDIR/liblua/luac" ]; then
LUAC=${LUAC:-$TOPDIR/liblua/luac}
fi
# Lua checks stolen from/based on nse_check_globals by Patrick Donnelly
LUA=${LUA:-$(which lua5.4 || which lua54 || which lua)}
if [ -n "$LUA" ]; then
if ! "$LUA" -v 2>&1 | grep 5.4 > /dev/null; then
echo Lua 5.4 required. Skipping Lua checks.
unset LUA
unset LUAC
fi
else
echo Lua 5.4 required. Skipping Lua checks.
fi
LUAC=${LUAC:-$(which luac5.4 || which luac54 || which luac)}
if [ -n "$LUAC" ]; then
if ! "$LUAC" -v 2>&1 | grep 5.4 > /dev/null; then
echo Luac 5.4 required. Skipping Lua checks.
unset LUA
unset LUAC
fi
else
echo Luac 5.4 required. Skipping Lua checks.
fi
export LUA
export LUAC
if [ -n "$LUA" -a -n "$LUAC" ]; then
FILES=$(git diff --cached --name-status | grep -v ^D | awk '$1 $2 { print $2}' | grep -E '\.(nse|lua)$')
if [ -n "$FILES" ]; then
for file in $FILES; do
OUTPUT=$(mktemp)
INPUT=$(mktemp)
git show ":$file" > "$INPUT"
"$LUAC" -l -p "$INPUT" > /dev/null 2> "$OUTPUT"
if [ -s "$OUTPUT" ]; then
sed "s|$LUAC: $INPUT|$file|" < "$OUTPUT" > /dev/stderr
rm -f "$OUTPUT"
exit 1
fi
rm -f "$OUTPUT"
NSE_LIBRARIES=""
for lib in "$TOPDIR"/nselib/*.luadoc; do
NSE_LIBRARIES="$NSE_LIBRARIES$(basename "$lib" .luadoc)"$'\n'
done
for lib in "$TOPDIR"/nselib/*.lua; do
NSE_LIBRARIES="$NSE_LIBRARIES$(basename "$lib" .lua)"$'\n'
done
export NSE_LIBRARIES
"$LUA" - "$INPUT" <<EOF
local NSE_LIBRARIES = "\\n"..os.getenv("NSE_LIBRARIES").."\\n"; -- add delimiters
local LUA_LIBRARIES = {
string = true,
debug = true,
package = true,
_G = true,
io = true,
os = true,
table = true,
math = true,
coroutine = true,
utf8 = true,
};
IGNORE = {
_M = true,
_NAME = true,
_PACKAGE = true,
};
local file = arg[1];
arg = nil; -- clear from global namespace
if not file or not io.open(file, "r") then
io.stdout:write("no file argument specified.\\n");
os.exit(1);
end
local command = os.getenv "LUAC" .. " -l -p " .. file .. "\\n";
local required = {};
local get_globals = {};
local set_globals = {};
local main_set = {};
if ("$file"):match ".nse\$" then
main_set.SCRIPT_NAME = true;
main_set.SCRIPT_PATH = true;
main_set.SCRIPT_TYPE = true;
end
local main = true;
local first_loc = 1;
local registers = {};
local required_fields = {description = false; author = false; license = false; categories = false};
local exit_status = 0;
for line in assert(io.popen(command)):lines() do
if main and line:find "^function" then
main = false;
registers = {}
end
-- sometimes we see this:
-- 428 [4680] LOADK 12 -258 ; "get_pad"
-- 429 [4683] CLOSURE 13 67 ; 0xcf41e0
-- 430 [4680] SETTABUP 0 12 13 ; _ENV
-- We must sadly save what constants are loaded into registers (simply)
-- to determine what the key is for SETTABUP. There is no need to clear
-- the registers.
local r, constant = line:match("^%s%d+%s%[%d+%]%sLOADK%s+(%d+).-; \\"([%w_]+)\\"");
if constant then
registers[r] = constant;
goto next_line
end
-- We also have to watch for local _ENV
r = line:match("^%s%d+%s%[%d+%]%sGETUPVAL%s+(%d+).-; _ENV");
if r then
registers[r] = main_set;
goto next_line
end
local get_n, get_global = line:match("^%s%d+%s%[(%d+)%]%sGETTABUP.-; _ENV \\"([%w_]+)\\"");
if not get_n then
local r;
get_n, r = line:match("^%s%d+%s%[(%d+)%]%sGETTABUP%s+%d+%s+%d+%s+(%d+).-; _ENV");
if r then
get_global = registers[r];
if not get_global then get_n = nil end
end
end
local set_n, set_global = line:match("^%s%d+%s%[(%d+)%]%sSETTABUP.-; _ENV \\"([%w_]+)\\"");
if not set_n then
local r;
set_n, r = line:match("^%s%d+%s%[(%d+)%]%sSETTABUP%s+%d+%s+(%d+).-; _ENV");
if r then
set_global = registers[r];
if not set_global then set_n = nil end
end
end
if not set_n then
local rkey
set_n, r, rkey = line:match("^%s%d+%s%[(%d+)%]%sSETTABLE%s+(%d+)%s+(%d+)");
if set_n and registers[r] == main_set then
set_global = registers[rkey];
end
if not set_global then set_n = nil end
end
if get_n then
if IGNORE[get_global] then
-- ignore it
elseif NSE_LIBRARIES:find("\\n"..get_global.."\\n", 1, true) or LUA_LIBRARIES[get_global] then
-- found global library, needs to be required
--io.stdout:write("found global library ", get_global);
if not required[get_global] then
required[get_global] = get_n;
required[#required+1] = get_global;
end
elseif _G[get_global] then
-- found global Lua function, this is okay
--io.stdout:write("found global ", get_global);
else
-- found global which may be "set", so we wait to report it
if not get_globals[get_global] then
get_globals[get_global] = get_n;
end
--io.stdout:write("found other global ", get_global);
end
elseif set_n then
if main then
-- Setting globals in main is okay.
main_set[set_global] = true;
--io.stdout:write("found main set global ", set_global);
else
-- Add to list of globals set which may be errors.
if not set_globals[set_global] then
set_globals[set_global] = set_n;
end
--io.stdout:write("found set global ", set_global);
end
end
::next_line::
end
-- go through list of libraries that need required, emit a patch
if next(required) then
exit_status = 1
table.sort(required);
for i, global in ipairs(required) do
local line = required[global];
io.stdout:write("$file:", line, ": Found unrequired NSE library \\"", global, "\\".\\n");
end
end
-- go through list of get_globals, if not in main_set, then error
for global, line in pairs(get_globals) do
if main_set[global] then
-- user is getting a global variable which we consider okay
-- since this global was set previously in the main function
else
exit_status = 1
io.stdout:write("$file:", line, ": Found bad indexed global \\"", global, "\\".\\n");
end
end
-- go through list of set_globals, if not in main_set, then error
for global, line in pairs(set_globals) do
if main_set[global] then
-- user is setting a global variable which we consider okay
-- since this global was set previously in the main function
else
exit_status = 1
io.stdout:write("$file:", line, ": Found bad set global \\"", global, "\\".\\n");
end
end
os.exit(exit_status)
EOF
if [ $? -ne 0 ]; then
rm -f "$INPUT"
exit 1
fi
rm -f "$INPUT"
done
else
true
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment