Skip to content
This repository has been archived by the owner on Oct 2, 2024. It is now read-only.

add debian lts security advisories #234

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions ircbot/plugin/debian_lts_security.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import operator
import re
from collections import namedtuple
from datetime import datetime
from typing import List
from xml.etree import ElementTree

import requests


DLA = namedtuple('DLA', ('number', 'package', 'link', 'description', 'date'))
last_seen = None


def dla_list():
req = requests.get('https://www.debian.org/lts/security/dla-long')
req.raise_for_status()

root = ElementTree.fromstring(req.content)
for item in root.iter('{http://purl.org/rss/1.0/}item'):
# title is of the form "DLA-3804 linux - security update"
title = item.find('{http://purl.org/rss/1.0/}title')
assert title is not None
assert title.text is not None
# group 1: dla number, group 2: optional package name
# line ends with the type of notice, see DSA-4204, DSA-4205 for examples
m = re.match(r'DLA-(\d+) ?(.+)? - ', title.text)
assert m, title.text
dla_num = int(m.group(1))
package = m.group(2)
link_elt = item.find('{http://purl.org/rss/1.0/}link')
assert link_elt is not None
link = link_elt.text

# description has random html tags and whitespace
description_elt = item.find('{http://purl.org/rss/1.0/}description')
assert description_elt is not None
assert description_elt.text is not None
description = description_elt.text.strip()
description = description.replace('\n', ' ')
description = re.sub('<[^<]+>', '', description) # not secure! but good enough
date_elt = item.find('{http://purl.org/dc/elements/1.1/}date')
assert date_elt is not None
assert date_elt.text is not None
date = datetime.strptime(date_elt.text, '%Y-%m-%d')

yield DLA(
number=dla_num,
package=package,
link=link,
description=description,
date=date,
)


def summarize(description, limit=256):
words = description.split()
line = ''
for word in words:
new_line = line + ' ' + word
if len(new_line) > limit:
return line.strip() + ' [...]'
else:
line = new_line
return line.strip()


def get_new_dlas():
"""Return new DLA summary lines."""
global last_seen
lines: List[str] = []
# exceptions (including HTTP error codes) are handled in timer.py
dlas = list(dla_list())

if last_seen is not None:
for dla in sorted(dlas, key=operator.attrgetter('number')):
if last_seen < dla.number:
lines.append('\x02\x0304[DLA {dla.number}] {dla.package} - {dla.link}'.format(dla=dla))
lines.append('\x0304' + summarize(dla.description))

last_seen = max(dla.number for dla in dlas)
return lines
36 changes: 36 additions & 0 deletions ircbot/plugin/timer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from textwrap import dedent
from traceback import format_exc

from ircbot.plugin import debian_lts_security
from ircbot.plugin import debian_security

# Check for Debian security announcements every 5 minutes
Expand All @@ -20,9 +21,13 @@ def register(bot):

def timer(bot):
dsa_freq = DSA_FREQ_DEFAULT
dla_freq = DSA_FREQ_DEFAULT

last_date = None
last_date_dla = None

last_dsa_check = None
last_dla_check = None

while not (hasattr(bot, 'connection') and bot.connection.connected):
time.sleep(2)
Expand All @@ -41,6 +46,7 @@ def timer(bot):

# After a successful fetch, we reset timer to 5m
dsa_freq = DSA_FREQ_DEFAULT

except Exception as ex:
error_msg = f'ircbot exception in timer: {ex}'
bot.say('#rebuild', error_msg)
Expand All @@ -58,4 +64,34 @@ def timer(bot):
)
dsa_freq = min(dsa_freq + DSA_FREQ_BACKOFF, DSA_FREQ_MAX)

try:
last_date_dla, old_dla = date.today(), last_date_dla
if old_dla and last_date_dla != old_dla:
bot.bump_topic()

if last_dla_check is None or time.time() - last_dla_check > 60 * dla_freq:
last_dla_check = time.time()

for line in debian_lts_security.get_new_dlas():
bot.say('#rebuild', line)

dla_freq = DSA_FREQ_DEFAULT

except Exception as ex:
error_msg = f'ircbot exception in timer: {ex}'
bot.say('#rebuild', error_msg)
bot.handle_error(
dedent(
"""
{error}

{traceback}
""",
).format(
error=error_msg,
traceback=format_exc(),
),
)
dla_freq = min(dla_freq + DSA_FREQ_BACKOFF, DSA_FREQ_MAX)

time.sleep(1)