diff --git a/common/Scripts/worklog.py b/common/Scripts/worklog.py index 4530b3dbfb0..a1ac03fd623 100755 --- a/common/Scripts/worklog.py +++ b/common/Scripts/worklog.py @@ -3,6 +3,7 @@ import html import json import os.path +import re import subprocess import sys import tempfile @@ -108,6 +109,14 @@ def author(self) -> str: return str(self._data['commit']['author']['name']) + @property + def message(self) -> str: + return str(self._data['commit']['message']) + + @property + def cves(self) -> List[str]: + return re.findall(r'CVE-\d{4}-\d{4,7}', self.message) + @staticmethod def __tempfile(ref: str) -> str: dir = os.path.join(tempfile.gettempdir(), '_solus_worklog') @@ -283,25 +292,49 @@ def v(self) -> str: def _successful_builds(self) -> Iterable[Build]: return [build for build in self.builds if build.status == "OK"] + @property + def cves(self) -> List[str]: + return [cve for build in self._successful_builds + for cve in build.commit().cves] + def to_tty(self) -> str: authors = [TTY.url(f'@{build.commit().author}', build.tag_url) for build in self._successful_builds] + cves = [TTY.url(cve, f'https://nvd.nist.gov/vuln/detail/{cve}') + for cve in self.cves] - return (f'{TTY.Green}{self.package}{TTY.Reset} {self.v} ' + + line = (f'{TTY.Green}{self.package}{TTY.Reset} {self.v} ' + f'{TTY.Blue}[{", ".join(authors)}]{TTY.Reset}') + if len(cves) > 0: + line += f' {TTY.Red}[{", ".join(cves)}]{TTY.Reset}' + + return line + def to_md(self) -> str: authors = [f'[@{build.commit().author}]({build.tag_url})' for build in self._successful_builds] + cves = [f'[{cve}](https://nvd.nist.gov/vuln/detail/{cve})' + for cve in self.cves] + line = f'**{self.package}** was updated to **{self.v}** ({", ".join(authors)}).' + + if len(cves) > 0: + line += f' Includes security fixes for {", ".join(cves)}.' - return f'**{self.package}** was updated to **{self.v}** ({", ".join(authors)})' + return line def to_html(self) -> str: authors = [f'@{html.escape(build.commit().author)}' for build in self._successful_builds] + cves = [f'{cve}' + for cve in self.cves] + line = (f'{html.escape(self.package)} was updated to {html.escape(self.v)} ' + f'({", ".join(authors)}).') - return (f'{html.escape(self.package)} was updated to {html.escape(self.v)} ' - f'({", ".join(authors)})') + if len(cves) > 0: + line += f' Includes security fixes for {", ".join(cves)}.' + + return line class Builds: @@ -317,7 +350,7 @@ def all(self) -> List[Build]: def packages(self) -> List[Build]: return list({b.pkg: b for b in self.all}.values()) - def updates(self, start: datetime, end: datetime) -> List[Update]: + def updates(self, start: datetime, end: datetime, security: bool = False) -> List[Update]: updates: Dict[str, Update] = {} for build in self._filter(self.all, start, end): @@ -326,6 +359,10 @@ def updates(self, start: datetime, end: datetime) -> List[Update]: else: updates[build.package] = Update(build) + if security: + updates = {pkg: update for pkg, update in updates.items() + if len(update.cves) > 0} + return list(updates.values()) def during(self, start: datetime, end: datetime) -> List[Build]: @@ -454,6 +491,8 @@ def _items(self, kind: str) -> Sequence[Listable]: return self.builds.during(self.start, self.end) case 'updates': return self.builds.updates(self.start, self.end) + case 'security-updates': + return self.builds.updates(self.start, self.end, security=True) case 'commits': return self.git.commits(self.start, self.end) case _: @@ -502,10 +541,11 @@ def _print_item(item: Listable, fmt: str) -> None: ./worklog.py commits '1 days ago' ''' )) - parser.add_argument('command', type=str, choices=['builds', 'updates', 'commits'], + parser.add_argument('command', type=str, choices=['builds', 'updates', 'security-updates', 'commits'], help='Type of output to show. ' '`builds` shows the builds as produced by the build server, ' '`updates` shows per-package updates based on the build server log and GitHub metadata, ' + '`security-updates` shows updates with security fixes, ' '`commits` shows the commits from your local copy of the `packages` repository.') parser.add_argument('after', type=str, help='Show builds after this date. '