summaryrefslogtreecommitdiffstats
path: root/testing
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2014-05-06 13:23:55 +0300
committerTimo Teräs <timo.teras@iki.fi>2014-05-06 16:56:23 +0300
commit4898593dd7fdb5dec3f0ccdbec5e7347b2146c48 (patch)
treefd4025d3918c2c761adc387648778ad588e64275 /testing
parent3e62492bb468dbae22138a6238262696bce754c9 (diff)
downloadaports-4898593dd7fdb5dec3f0ccdbec5e7347b2146c48.tar.bz2
aports-4898593dd7fdb5dec3f0ccdbec5e7347b2146c48.tar.xz
testing/aaudit: new aport
Alpine Auditor - utility to track remote apkovls in a git tree and email about changes
Diffstat (limited to 'testing')
-rw-r--r--testing/aaudit/APKBUILD44
-rwxr-xr-xtesting/aaudit/aaudit-create20
-rwxr-xr-xtesting/aaudit/aaudit-emaildiff61
-rwxr-xr-xtesting/aaudit/aaudit-import-tar173
-rwxr-xr-xtesting/aaudit/aaudit-refresh15
-rw-r--r--testing/aaudit/aaudit.conf25
6 files changed, 338 insertions, 0 deletions
diff --git a/testing/aaudit/APKBUILD b/testing/aaudit/APKBUILD
new file mode 100644
index 000000000..d253c9f15
--- /dev/null
+++ b/testing/aaudit/APKBUILD
@@ -0,0 +1,44 @@
+# Contributor: Timo Teräs <timo.teras@iki.fi>
+# Maintainer: Timo Teräs <timo.teras@iki.fi>
+pkgname=aaudit
+pkgver=0.1
+pkgrel=0
+pkgdesc="Alpine Auditor"
+url="http://alpinelinux.org"
+arch="noarch"
+license="GPL"
+depends="lua5.2 lua-posix git"
+makedepends=""
+install=""
+subpackages=""
+replaces=""
+source_libexec="aaudit-emaildiff aaudit-import-tar"
+source_bin="aaudit-create aaudit-refresh"
+source="$source_libexec $source_bin aaudit.conf"
+
+build() {
+ return 0
+}
+
+package() {
+ mkdir -p "$pkgdir"/etc/aaudit "$pkgdir"/usr/bin "$pkgdir"/usr/libexec/aaudit
+ cp aaudit.conf "$pkgdir"/etc/aaudit
+ cp $source_bin "$pkgdir"/usr/bin
+ cp $source_libexec "$pkgdir"/usr/libexec/aaudit
+}
+
+md5sums="6ab0ebec3419a4c495a1935a07d4825c aaudit-emaildiff
+d71863d014f844656b2fd1926f63826e aaudit-import-tar
+5dafe6078c114ac0a445dcf0633371cd aaudit-create
+9bcfb058c2b28b36d593203f838b90fa aaudit-refresh
+43ca8205fec84b7fe8ead005d0cbd8f3 aaudit.conf"
+sha256sums="56ec6e2c13a5e857ae604264a424fd8c6dc04bf37122d88197ddbbb92e42b560 aaudit-emaildiff
+4ea264c0a0fd7e1a0ff52a42db9b098358cce545b3eec1066ecc977cfe06565e aaudit-import-tar
+6643a7c1353253a417a319b0ac8558a348248cb97dcca2c724940350edef47b2 aaudit-create
+6f3fb2d53141be5b58dfbda4977243628ed56de6ad3949ac349ad01013f43f75 aaudit-refresh
+c23f1dd4fe68b5cbde0bb5c8cc9996c9569b1cb4a249523c995381c8b3eee8ee aaudit.conf"
+sha512sums="114d931491faf8f2df71a050a87d2d895a73f48b3948da424f3c1def9da9ec9dec2db96b2a1fefafd25477dc285a010ea95ce0372174b139d081899e09be01d3 aaudit-emaildiff
+a1db9c83165ca42bcddf37c13b23206b5d1e0d7c00f8d5f1ce942a8ee8d94d21f6ebd85d1e4be53111b7f7468968df18dc00b073c710f25a4ff1a726f11eee83 aaudit-import-tar
+85911c1b5e548cfaf417b310abff0d42d0a5a77a49f40584275d55feef30a2c68413c1db70d946709a3bf794dc31ec70bc61c3e50f2a8e1d91e57e13dc6470b1 aaudit-create
+6286214d25322f835156c2891cc509503df22fb979514c3a60a2bb3b520f0fe09e73bae80ed73ff0117e571956fa9cce17f1094e1d3f7698c19d14e80c36c5bd aaudit-refresh
+da7bd0febcf45ee4db8fb32d54fe014830895aafb131b93ad5e1ee8e95bd0a67d12b7931362135ccd7661bbf54909d09be6308c68506970dfbdb7d6f8de70ad3 aaudit.conf"
diff --git a/testing/aaudit/aaudit-create b/testing/aaudit/aaudit-create
new file mode 100755
index 000000000..450dec9e6
--- /dev/null
+++ b/testing/aaudit/aaudit-create
@@ -0,0 +1,20 @@
+#!/bin/sh -e
+
+IP="$1"
+DESC="$2"
+
+if [ -z "$IP" -o -z "$DESC" ]; then
+ echo "usage: $0 <IP> <Description>"
+ exit 1
+fi
+
+git init --quiet --bare
+echo "$IP" > aaudit-hostname
+echo "$DESC ($IP)" > description
+
+if ! ssh root@$IP 'lbu package -' | gunzip | /usr/libexec/aaudit/aaudit-import-tar --initial-commit; then
+ git branch --quiet -D import
+ exit 1
+fi
+git branch --quiet --force master import
+git branch --quiet -D import
diff --git a/testing/aaudit/aaudit-emaildiff b/testing/aaudit/aaudit-emaildiff
new file mode 100755
index 000000000..56d754103
--- /dev/null
+++ b/testing/aaudit/aaudit-emaildiff
@@ -0,0 +1,61 @@
+#!/usr/bin/lua5.2
+
+local posix = require 'posix'
+local config_file = "/etc/aaudit/aaudit.conf"
+
+local function load_config(filename)
+ local F = io.open(filename, "r")
+ local cfg = "return {" .. F:read("*all").. "}"
+ F:close()
+ return loadstring(cfg, "config:"..filename)()
+end
+
+local function match_file(fn, match_list)
+ if not match_list then return false end
+ local i, m
+ for i, pattern in ipairs(match_list) do
+ if posix.fnmatch(pattern, fn) then return true end
+ end
+ return false
+end
+
+local CONF = load_config(config_file)
+if CONF.notify_email == nil or CONF.smtp_server == nil then return end
+
+local visible, has_data = false, false
+local diff = {}
+for l in io.lines() do
+ local fn = l:match("^diff [^ \t]* a/([^ \t]*)")
+ if fn then
+ visible = not match_file(fn, CONF.no_notify_files)
+ if visible then
+ has_data = true
+ visible = not match_file(fn, CONF.private_files)
+ if not visible then
+ table.insert(diff, "Private file "..fn.." changed")
+ end
+ end
+ end
+ if visible then table.insert(diff, l) end
+end
+
+if has_data then
+ local EMAIL = io.popen(string.format("sendmail -t -S %s", CONF.smtp_server), "w")
+ EMAIL:write(string.format([[
+From: %s <%s>
+To: %s
+Subject: Configuration change on %s
+Date: %s
+
+This is automatically generated e-mail about the following configuration change:
+
+%s
+]],
+ CONF.author_name or "Alpine Auditor", CONF.author_email or "auditor@alpine.local",
+ table.concat(CONF.notify_email, ", "),
+ arg[1],
+ os.date("%a, %d %b %Y %H:%M:%S"),
+ table.concat(diff, '\n')
+ ))
+ EMAIL:close()
+end
diff --git a/testing/aaudit/aaudit-import-tar b/testing/aaudit/aaudit-import-tar
new file mode 100755
index 000000000..effe93756
--- /dev/null
+++ b/testing/aaudit/aaudit-import-tar
@@ -0,0 +1,173 @@
+#!/usr/bin/lua5.2
+
+local posix = require 'posix'
+local branch_ref = "refs/heads/import"
+local from_ref = "refs/heads/master"
+local config_file = "/etc/aaudit/aaudit.conf"
+
+local function load_config(filename)
+ local F = io.open(filename, "r")
+ local cfg = "return {" .. F:read("*all").. "}"
+ F:close()
+ return loadstring(cfg, "config:"..filename)()
+end
+
+local function match_file(fn, match_list)
+ if not match_list then return false end
+ local i, m
+ for i, pattern in ipairs(match_list) do
+ if posix.fnmatch(pattern, fn) then return true end
+ end
+ return false
+end
+
+local function checksum_header(block)
+ local sum = 256
+ for i = 1,148 do sum = sum + block:byte(i) end
+ for i = 157,500 do sum = sum + block:byte(i) end
+ return sum
+end
+
+local function nullterm(s) return s:match("^[^%z]*") end
+local function octal_to_number(str) return tonumber(nullterm(str), 8) end
+
+local function read_header_block(block)
+ local header = {
+ name = nullterm(block:sub(1,100)),
+ mode = octal_to_number(block:sub(101,108)),
+ uid = octal_to_number(block:sub(109,116)),
+ gid = octal_to_number(block:sub(117,124)),
+ size = octal_to_number(block:sub(125,136)),
+ mtime = octal_to_number(block:sub(137,148)),
+ chksum = octal_to_number(block:sub(149,156)),
+ typeflag = block:sub(157,157),
+ linkname = nullterm(block:sub(158,257)),
+ magic = block:sub(258,263),
+ version = block:sub(264,265),
+ uname = nullterm(block:sub(266,297)),
+ gname = nullterm(block:sub(298,329)),
+ devmajor = octal_to_number(block:sub(330,337)),
+ devminor = octal_to_number(block:sub(338,345)),
+ prefix = nullterm(block:sub(346,500)),
+ }
+ if header.magic ~= "ustar " and header.magic ~= "ustar\0" then
+ return false, "Invalid header magic "..header.magic
+ end
+ if header.version ~= "00" and header.version ~= " \0" then
+ return false, "Unknown version "..header.version
+ end
+ if not checksum_header(block) == header.chksum then
+ return false, "Failed header checksum"
+ end
+ return header
+end
+
+function import_tar(CONF, TAR, GIT, initial_commit)
+ local blocksize = 512
+ local zeroblock = string.rep("\0", blocksize)
+ local nextmark = 1
+ local author_time = 0
+ local all_files = {}
+ local long_name, long_link_name
+ local symlinkmode = tonumber('0120000', 8)
+ local rwmode = tonumber('0755', 8)
+ local romode = tonumber('0644', 8)
+ local wandmode = tonumber('0111', 8)
+
+ local author_name = CONF.author_name or "Alpine Auditor"
+ local author_email = CONF.author_email or "auditor@alpine.local"
+
+ while true do
+ local block = TAR:read(blocksize)
+ if not block then
+ return false, "Premature end of archive"
+ end
+ if block == zeroblock then break end
+
+ local header, err = read_header_block(block)
+ if not header then return false, err end
+
+ local file_data = TAR:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size)
+ if header.typeflag == "L" then
+ long_name = nullterm(file_data)
+ elseif header.typeflag == "K" then
+ long_link_name = nullterm(file_data)
+ else
+ if long_name then
+ header.name = long_name
+ long_name = nil
+ end
+ if long_link_name then
+ header.linkname = long_link_name
+ long_link_name = nil
+ end
+ end
+
+ if header.typeflag:match("^[0-46]$") and
+ not match_file(header.name, CONF.no_track_files) then
+ GIT:write('blob\nmark :'..nextmark..'\n')
+ if header.typeflag == "2" then
+ GIT:write('data '..#header.linkname..'\n'..header.linkname)
+ header.mode = symlinkmode
+ else
+ GIT:write('data '..header.size..'\n')
+ GIT:write(file_data)
+ end
+ GIT:write('\n')
+
+ local fn = header.prefix..header.name
+ all_files[fn] = { mark=nextmark, mode=header.mode }
+ nextmark = nextmark + 1
+ if header.mtime > author_time then author_time = header.mtime end
+ end
+ end
+
+ GIT:write(string.format([[
+commit %s
+author %s <%s> %d +0000
+committer %s <%s> %d +0000
+data <<END_OF_COMMIT_MESSAGE
+%s
+END_OF_COMMIT_MESSAGE
+
+]],
+ branch_ref,
+ author_name, author_email, author_time,
+ author_name, author_email, os.time(),
+ CONF.commit_message or "Changes"
+ ))
+
+ if not initial_commit then GIT:write(string.format("from %s^0\n", from_ref)) end
+ GIT:write("deleteall\n")
+ local path, v
+ for path, v in pairs(all_files) do
+ local mode = v.mode
+ if mode ~= symlinkmode then
+ if bit32.band(mode, wandmode) then
+ mode = rwmode
+ else
+ mode = romode
+ end
+ end
+ GIT:write(string.format("M %o :%i %s\n", mode, v.mark, path))
+ end
+ GIT:write("\n")
+
+ return true
+end
+
+local initial_commit = false
+local a
+for _, a in ipairs(arg) do
+ if a == '--initial-commit' then
+ initial_commit = true
+ else
+ os.exit(1)
+ end
+end
+
+local GI = io.popen("git fast-import --quiet", "w")
+local rc = import_tar(load_config(config_file), io.stdin, GI, initial_commit)
+GI:close()
+
+if not rc then os.exit(1) end
diff --git a/testing/aaudit/aaudit-refresh b/testing/aaudit/aaudit-refresh
new file mode 100755
index 000000000..6e400c5d8
--- /dev/null
+++ b/testing/aaudit/aaudit-refresh
@@ -0,0 +1,15 @@
+#!/bin/sh
+if [ ! -f aaudit-hostname -o ! -f config -o ! -f description -o ! -d objects ]; then
+ echo "run in the created git repository"
+ exit 1
+fi
+IP="$(cat aaudit-hostname)"
+if ! ssh root@"$IP" 'lbu package -' | gunzip | /usr/libexec/aaudit/aaudit-import-tar; then
+ git branch --quiet -D import
+ exit 1
+fi
+if ! git diff --quiet --exit-code master..import; then
+ git diff --patch-with-stat master..import | /usr/libexec/aaudit/aaudit-emaildiff "$(cat description)"
+ git branch --quiet --force master import
+fi
+git branch --quiet -D import
diff --git a/testing/aaudit/aaudit.conf b/testing/aaudit/aaudit.conf
new file mode 100644
index 000000000..cfecde6e3
--- /dev/null
+++ b/testing/aaudit/aaudit.conf
@@ -0,0 +1,25 @@
+author_name = "Alpine Auditor";
+author_email = "audit@alpine.local";
+notify_email = { "engineers@alpine.local" };
+-- smtp_server = "<server>";
+commit_message = "Changes";
+
+no_track_files = {
+ "*/.git/*",
+ "*.apk-new",
+ "*~",
+ "etc/unbound/root.hints",
+ "etc/chrony/chrony.drift",
+ "etc/ld.so.cache",
+};
+
+no_notify_files = {
+ "etc/acf/password",
+};
+
+private_files = {
+ "etc/shadow*",
+ "*.crt",
+ "*.pem",
+ "*.pfx",
+};