Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

worklog.py: Add CVE links and a security-updates command. #2151

Merged
merged 2 commits into from
Apr 17, 2024
Merged
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
52 changes: 46 additions & 6 deletions common/Scripts/worklog.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import html
import json
import os.path
import re
import subprocess
import sys
import tempfile
Expand Down Expand Up @@ -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')
Expand Down Expand Up @@ -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'<a href="{html.escape(build.tag_url, quote=True)}">@{html.escape(build.commit().author)}</a>'
for build in self._successful_builds]
cves = [f'<a href="https://nvd.nist.gov/vuln/detail/{cve}">{cve}</a>'
for cve in self.cves]
line = (f'<strong>{html.escape(self.package)}</strong> was updated to <strong>{html.escape(self.v)}</strong> '
f'({", ".join(authors)}).')

return (f'<strong>{html.escape(self.package)}</strong> was updated to <strong>{html.escape(self.v)}</strong> '
f'({", ".join(authors)})')
if len(cves) > 0:
line += f' Includes security fixes for {", ".join(cves)}.'

return line


class Builds:
Expand All @@ -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):
Expand All @@ -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]:
Expand Down Expand Up @@ -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 _:
Expand Down Expand Up @@ -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. '
Expand Down
Loading