Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9f08e61
Update __init__.py
grumo35 Jan 31, 2022
bc964ca
Merge branch 'master' into patch-1
furlongm Feb 15, 2022
57b33e1
Merge branch 'master' into patch-1
furlongm Feb 16, 2022
8072e34
Merge branch 'master' into patch-1
furlongm Mar 20, 2025
fecca1c
Merge branch 'main' into patch-1
furlongm Mar 22, 2025
ae7d58e
Merge branch 'main' into patch-1
furlongm Mar 22, 2025
cd577bf
Update __init__.py
furlongm Mar 22, 2025
80a2d60
Update __init__.py
furlongm Mar 22, 2025
12b2d79
Merge branch 'main' into patch-1
furlongm Mar 22, 2025
5685ef3
Merge branch 'main' into patch-1
furlongm Apr 30, 2025
b616296
Package types are in the Package class
willfurnell Sep 12, 2025
3f8756c
Merge pull request #701 from willfurnell/package-fix
furlongm Sep 15, 2025
3676e78
Bump django from 4.2.24 to 4.2.25
dependabot[bot] Oct 1, 2025
1328e52
Merge pull request #704 from furlongm/dependabot/pip/django-4.2.25
furlongm Oct 3, 2025
1c26001
bump redis
furlongm Oct 3, 2025
0f54454
Update license in common.py
furlongm Oct 3, 2025
ce9f4f0
fix licenses
furlongm Oct 3, 2025
c651c3f
use GPL-3.0-only for debian copyright
furlongm Oct 3, 2025
964c2c6
Merge branch 'docker' into patchman-email
RicardoJeronimo Oct 14, 2025
dbcaa3a
Added patchman-email installation to Dockerfile
RicardoJeronimo Oct 14, 2025
aca5279
Added patchman-email dependency
RicardoJeronimo Oct 14, 2025
b656738
Added dependency to Dockerfile
RicardoJeronimo Oct 20, 2025
807e5de
Merge pull request #377 from grumo35/patch-1
furlongm Oct 21, 2025
eee5675
fix some flake8-bugbear bugs
furlongm Oct 22, 2025
ad28bfe
Merge pull request #711 from furlongm/bugbear
furlongm Oct 22, 2025
99c5b30
fix tag handling
furlongm Oct 21, 2025
4881407
Fixed DB credentials lookup
RicardoJeronimo Oct 24, 2025
0a7f400
Added dependencies to Dockerfile
RicardoJeronimo Oct 24, 2025
d6d8fcf
Modified dependencies in Dockerfile
RicardoJeronimo Oct 24, 2025
5ed809e
Modified entrypoint script to configure sendmail to forward to anothe…
RicardoJeronimo Oct 24, 2025
0ffaa1a
Report design improvements
RicardoJeronimo Oct 24, 2025
3eaca7a
Minor code refactor
RicardoJeronimo Oct 24, 2025
91067be
Merge remote-tracking branch 'upstream/main' into patchman-email
RicardoJeronimo Oct 27, 2025
5cbda58
Merge branch 'main' into patchman-email
RicardoJeronimo Oct 27, 2025
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
2 changes: 1 addition & 1 deletion debian/copyright
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Source: https://github.com/furlongm/patchman
Files: *
Copyright: 2011-2012 VPAC http://www.vpac.org
2013-2021 Marcus Furlong <furlongm@gmail.com>
License: GPL-3.0
License: GPL-3.0-only
This package is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 3 only.
Expand Down
6 changes: 5 additions & 1 deletion docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM debian:bookworm-slim

RUN apt -y update && apt -y upgrade
RUN apt install -y apache2 git libapache2-mod-wsgi-py3 mariadb-client python-celery-common python3-celery python3-debian python3-defusedxml python3-lxml python3-mysqldb python3-pip python3-progressbar python3-psycopg2 python3-redis python3-rpm
RUN apt install -y apache2 git libapache2-mod-wsgi-py3 mariadb-client python-celery-common python3-celery python3-debian python3-defusedxml python3-lxml python3-mysqldb python3-pip python3-progressbar python3-psycopg2 python3-redis python3-rpm sendmail sharutils uuid-runtime vim weasyprint

WORKDIR /srv/patchman

Expand All @@ -10,6 +10,10 @@ COPY ./etc/patchman/apache.conf.example /etc/apache2/sites-available/patchman.co

RUN /srv/patchman/setup.py install

COPY ./email/patchman-email /usr/bin/patchman-email
COPY ./etc/patchman/patchman-email.conf /etc/patchman/patchman-email.conf
RUN chmod u+x /usr/bin/patchman-email

RUN a2enmod wsgi
RUN a2ensite patchman

Expand Down
6 changes: 6 additions & 0 deletions docker/docker-entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ if "${USE_CACHE}"; then
fi
fi

# Set sendmail destination
if [ -n "${MTA_HOST}" ]; then
echo "define(\`SMART_HOST', \`[$MTA_HOST]')dnl" >> /etc/mail/submit.mc
m4 /etc/mail/submit.mc > /etc/mail/submit.cf
fi

# Sync database on container first start
if [ ! -f /var/lib/patchman/.firstrun ]; then
patchman-manage makemigrations
Expand Down
13 changes: 7 additions & 6 deletions email/patchman-email
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ report() {
cat <<-EOF > "$FILE.html"
<html><style>
body { font-family: "Calibri" }
#details table { border-collapse: collapse; width: 20em; white-space: nowrap;}
#details table { border-collapse: collapse; width: 20em; white-space: nowrap; }
#details table tr:nth-child(1) { font-size: 1.5em; text-decoration: underline; }
#updates table { border-collapse: collapse; width: 100%; }
#details th, #details tr, #details td { text-align: left; }
#updates th, #updates td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }
Expand Down Expand Up @@ -187,11 +188,11 @@ if [ $# -gt 0 ] && [[ $1 == -* ]]; then
custom_html="/etc/patchman/patchman-email.html"

# Database credentials configured in /etc/patchman/local_settings.py
mysql_db=$(grep -E "'NAME'" /etc/patchman/local_settings.py | grep -v "#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_user=$(grep -E "'USER'" /etc/patchman/local_settings.py | grep -v "#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_pass=$(grep -E "'PASSWORD'" /etc/patchman/local_settings.py | grep -v "#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_host=$(grep -E "'HOST'" /etc/patchman/local_settings.py | grep -v "#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_port=$(grep -E "'PORT'" /etc/patchman/local_settings.py | grep -v "#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_db=$(grep -E "'NAME'" /etc/patchman/local_settings.py | grep -v "^#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_user=$(grep -E "'USER'" /etc/patchman/local_settings.py | grep -v "^#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_pass=$(grep -E "'PASSWORD'" /etc/patchman/local_settings.py | grep -v "^#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_host=$(grep -E "'HOST'" /etc/patchman/local_settings.py | grep -v "^#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')
mysql_port=$(grep -E "'PORT'" /etc/patchman/local_settings.py | grep -v "^#" | sed -e "s/'\|,//g" | awk -F " " '{print $2}')

while getopts 'aH:T:h' arg; do
case $arg in
Expand Down
2 changes: 1 addition & 1 deletion hosts/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def show(self):
text += f'Packages : {self.get_num_packages()}\n'
text += f'Repos : {self.get_num_repos()}\n'
text += f'Updates : {self.get_num_updates()}\n'
text += f'Tags : {self.tags}\n'
text += f'Tags : {" ".join(self.tags.slugs())}\n'
text += f'Needs reboot : {self.reboot_required}\n'
text += f'Updated at : {self.updated_at}\n'
text += f'Host repos : {self.host_repos_only}\n'
Expand Down
7 changes: 3 additions & 4 deletions hosts/templatetags/report_alert.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
# Copyright 2016-2021 Marcus Furlong <furlongm@gmail.com>
# Copyright 2016-2025 Marcus Furlong <furlongm@gmail.com>
#
# This file is part of Patchman.
#
# Patchman is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# the Free Software Foundation, version 3 only.
#
# Patchman is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Patchman If not, see <http://www.gnu.org/licenses/>.
# along with Patchman. If not, see <http://www.gnu.org/licenses/>

from datetime import timedelta

Expand Down
19 changes: 17 additions & 2 deletions hosts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
from socket import gethostbyaddr, gaierror, herror

from django.db import transaction, IntegrityError
from taggit.models import Tag

from patchman.signals import error_message
from patchman.signals import error_message, info_message


def update_rdns(host):
Expand Down Expand Up @@ -62,7 +63,7 @@ def get_or_create_host(report, arch, osvariant, domain):
host.osvariant = osvariant
host.domain = domain
host.lastreport = report.created
host.tags = report.tags
host.tags.set(report.tags.split(','), clear=True)
if report.reboot == 'True':
host.reboot_required = True
else:
Expand All @@ -73,3 +74,17 @@ def get_or_create_host(report, arch, osvariant, domain):
if host:
host.check_rdns()
return host


def clean_tags():
""" Delete Tags that have no Host
"""
tags = Tag.objects.filter(
host__isnull=True,
)
tlen = tags.count()
if tlen == 0:
info_message.send(sender=None, text='No orphaned Tags found.')
else:
info_message.send(sender=None, text=f'{tlen} orphaned Tags found.')
tags.delete()
6 changes: 3 additions & 3 deletions packages/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,11 @@ def __str__(self):
rel = f'-{self.release}'
else:
rel = ''
if self.packagetype == self.GENTOO:
if self.packagetype == Package.GENTOO:
return f'{self.category}/{self.name}-{epo}{self.version}{rel}-{self.arch}.{self.get_packagetype_display()}'
elif self.packagetype in [self.DEB, self.ARCH]:
elif self.packagetype in [Package.DEB, Package.ARCH]:
return f'{self.name}_{epo}{self.version}{rel}_{self.arch}.{self.get_packagetype_display()}'
elif self.packagetype == self.RPM:
elif self.packagetype == Package.RPM:
return f'{self.name}-{epo}{self.version}{rel}-{self.arch}.{self.get_packagetype_display()}'
else:
return f'{self.name}-{epo}{self.version}{rel}-{self.arch}.{self.get_packagetype_display()}'
Expand Down
2 changes: 1 addition & 1 deletion patchman/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
router.register(r'package', package_views.PackageViewSet)
router.register(r'package-update', package_views.PackageUpdateViewSet)
router.register(r'cve', security_views.CVEViewSet)
router.register(r'reference', security_views.ReferenceViewSet),
router.register(r'reference', security_views.ReferenceViewSet)
router.register(r'erratum', errata_views.ErratumViewSet)
router.register(r'repo', repo_views.RepositoryViewSet)
router.register(r'mirror', repo_views.MirrorViewSet)
Expand Down
2 changes: 1 addition & 1 deletion repos/repo_types/gentoo.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def extract_gentoo_overlay_ebuilds(t):
""" Extract ebuilds from a Gentoo overlay tarball
"""
extracted_ebuilds = {}
for root, dirs, files in os.walk(t):
for root, _, files in os.walk(t):
for name in files:
if fnmatch(name, '*.ebuild'):
package_name = root.replace(t + '/', '')
Expand Down
2 changes: 1 addition & 1 deletion repos/repo_types/rpm.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def refresh_rpm_repo_mirrors(repo, errata_only=False):
]
ts = get_datetime_now()
enabled_mirrors = repo.mirror_set.filter(mirrorlist=False, refresh=True, enabled=True)
for i, mirror in enumerate(enabled_mirrors):
for mirror in enabled_mirrors:
res = find_mirror_url(mirror.url, formats)
if not res:
mirror.fail()
Expand Down
4 changes: 2 additions & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Django==4.2.24
Django==4.2.25
django-taggit==4.0.0
django-extensions==3.2.3
django-bootstrap3==23.1
Expand All @@ -15,7 +15,7 @@ python-magic==0.4.27
gitpython==3.1.44
tenacity==8.2.3
celery==5.4.0
redis==5.2.1
redis==6.4.0
django-celery-beat==2.7.0
tqdm==4.67.1
cvss==3.4
2 changes: 2 additions & 0 deletions sbin/patchman
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ from errata.utils import mark_errata_security_updates, enrich_errata, \
scan_package_updates_for_affected_packages
from errata.tasks import update_errata
from hosts.models import Host
from hosts.utils import clean_tags
from modules.utils import clean_modules
from packages.utils import clean_packages, clean_packageupdates, clean_packagenames
from repos.models import Repository
Expand Down Expand Up @@ -362,6 +363,7 @@ def dbcheck(remove_duplicates=False):
clean_repos()
clean_modules()
clean_packageupdates()
clean_tags()


def collect_args():
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
# Copyright 2013-2021 Marcus Furlong <furlongm@gmail.com>
# Copyright 2013-2025 Marcus Furlong <furlongm@gmail.com>
#
# This file is part of Patchman.
#
Expand Down
19 changes: 15 additions & 4 deletions util/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import magic
import zlib
import lzma
import os
from datetime import datetime, timezone
from enum import Enum
from hashlib import md5, sha1, sha256, sha512
Expand All @@ -28,17 +29,23 @@
from time import time
from tqdm import tqdm

from patchman.signals import error_message, info_message, debug_message

from django.utils.timezone import make_aware
from django.utils.dateparse import parse_datetime
from django.conf import settings

from patchman.signals import error_message, info_message, debug_message

pbar = None
verbose = None
Checksum = Enum('Checksum', 'md5 sha sha1 sha256 sha512')

http_proxy = os.getenv('http_proxy')
https_proxy = os.getenv('https_proxy')
proxies = {
'http': http_proxy,
'https': https_proxy,
}


def get_verbosity():
""" Get the global verbosity level
Expand Down Expand Up @@ -107,13 +114,17 @@ def fetch_content(response, text='', ljust=35):
wait=wait_exponential(multiplier=1, min=1, max=10),
reraise=False,
)
def get_url(url, headers={}, params={}):
def get_url(url, headers=None, params=None):
""" Perform a http GET on a URL. Return None on error.
"""
response = None
if not headers:
headers = {}
if not params:
params = {}
try:
debug_message.send(sender=None, text=f'Trying {url} headers:{headers} params:{params}')
response = requests.get(url, headers=headers, params=params, stream=True, timeout=30)
response = requests.get(url, headers=headers, params=params, stream=True, proxies=proxies, timeout=30)
debug_message.send(sender=None, text=f'{response.status_code}: {response.headers}')
if response.status_code in [403, 404]:
return response
Expand Down
7 changes: 3 additions & 4 deletions util/filterspecs.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
# Copyright 2010 VPAC
# Copyright 2014-2021 Marcus Furlong <furlongm@gmail.com>
# Copyright 2014-2025 Marcus Furlong <furlongm@gmail.com>
#
# This file is part of Patchman.
#
# Patchman is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# the Free Software Foundation, version 3 only.
#
# Patchman is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Patchman If not, see <http://www.gnu.org/licenses/>.
# along with Patchman. If not, see <http://www.gnu.org/licenses/>

from django.utils.safestring import mark_safe
from django.db.models.query import QuerySet
Expand Down
8 changes: 3 additions & 5 deletions util/templatetags/common.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
# Copyright 2010 VPAC
# Copyright 2013-2021 Marcus Furlong <furlongm@gmail.com>
# Copyright 2013-2025 Marcus Furlong <furlongm@gmail.com>
#
# This file is part of Patchman.
#
# Patchman is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# the Free Software Foundation, version 3 only.
#
# Patchman is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Patchman If not, see <http://www.gnu.org/licenses/>.
# along with Patchman. If not, see <http://www.gnu.org/licenses/>

import re

Expand Down