[Git][security-tracker-team/security-tracker][master] 3 commits: security_db.py: support opening the database read-only
Emilio Pozuelo Monfort (@pochu)
pochu at debian.org
Tue Aug 18 10:39:43 BST 2026
Emilio Pozuelo Monfort pushed to branch master at Debian Security Tracker / security-tracker
Commits:
85e765c4 by Helmut Grohne at 2026-08-12T18:22:22+02:00
security_db.py: support opening the database read-only
Most applications using the database know in advance whether they intend
to modify it. As a defensive mechanism, we can convey this intention and
make stuff fail when the intention is not met.
- - - - -
1a274edc by Helmut Grohne at 2026-08-12T18:23:26+02:00
tracker_service.py: open the security database read-only
The web service never modifies the database. All updates are performed
via other scripts. Convey this to the database class to defend against
unintended modification.
As a side effect, this slightly reduces the cost of creating the
connection, which may become relevant if we more frequently open
connections for scaling load. It also removes a possible race condition
if (read-only) connections were created concurrently.
Suggested-by: Enrico Zini <enrico at enricozini.org>
- - - - -
49e5fcb3 by Emilio Pozuelo Monfort at 2026-08-18T09:39:40+00:00
Merge branch 'helmutg/web-readonly' into 'master'
web service: open database connection read-only
See merge request security-tracker-team/security-tracker!320
- - - - -
2 changed files:
- bin/tracker_service.py
- lib/python/security_db.py
Changes:
=====================================
bin/tracker_service.py
=====================================
@@ -110,7 +110,7 @@ class TrackerService(WebServiceBase):
def __init__(self, db_name):
WebServiceBase.__init__(self)
- self.db = security_db.DB(db_name)
+ self.db = security_db.DB(db_name, readonly=True)
self.stable_releases = config.get_supported_releases()
self.stable_releases.remove(config.get_release_codename('testing'))
=====================================
lib/python/security_db.py
=====================================
@@ -268,9 +268,12 @@ class DB:
misnomer because these objects are quite versatile.
"""
- def __init__(self, name, verbose=False):
+ def __init__(self, name, *, verbose=False, readonly=False):
self.name = name
- self.db = apsw.Connection(name)
+ flags = apsw.SQLITE_OPEN_READWRITE | apsw.SQLITE_OPEN_CREATE
+ if readonly:
+ flags = apsw.SQLITE_OPEN_READONLY
+ self.db = apsw.Connection(name, flags=flags)
self.verbose = verbose
c = self.cursor()
@@ -279,18 +282,26 @@ class DB:
c.execute("PRAGMA page_size = 4096")
- # Enable WAL. This means that updates will not block readers.
- c.execute("PRAGMA journal_mode = WAL")
+ if not readonly:
+ # Enable WAL. This means that updates will not block readers.
+ c.execute("PRAGMA journal_mode = WAL")
self.schema_version = 24
self._initFunctions()
- for (v,) in c.execute("PRAGMA user_version"):
- if v == 0:
+ try:
+ user_version, = next(c.execute("PRAGMA user_version"))
+ except StopIteration:
+ raise RuntimeError("no user_version returned from sqlite")
+ if user_version != self.schema_version:
+ if readonly:
+ raise RuntimeError("DB: readonly open failed. expected schema version %d mismatches database schema version %d"
+ % (self.schema_version, user_version))
+ elif user_version == 0:
self.initSchema(c)
- elif v == 20:
+ elif user_version == 20:
self._initSchema20(c)
- elif v == 21:
+ elif user_version == 21:
# Remove legacy views.
for view in ('testing_status', 'stable_status',
'oldstable_status'):
@@ -299,18 +310,16 @@ class DB:
except apsw.SQLError:
pass
c.execute("PRAGMA user_version = 22")
- elif v == 22:
+ elif user_version == 22:
self._initSchema22(c)
- elif v == 23:
+ elif user_version == 23:
self._initSchema23(c)
- elif v != self.schema_version:
+ else:
if self.verbose:
print("DB: schema version mismatch: expected %d, got %d"
- % (self.schema_version, v))
- raise SchemaMismatch(repr(v))
- self._initViews(c)
- return
- assert False
+ % (self.schema_version, user_version))
+ raise SchemaMismatch(repr(user_version))
+ self._initViews(c)
def __del__(self):
self.db.close()
@@ -487,7 +496,6 @@ class DB:
def _initSchema20(self, cursor):
cursor.execute("PRAGMA user_version = 1")
self._initNoDSA(cursor)
- self._initViews(cursor)
cursor.execute("DELETE FROM inodeprints WHERE file ='data/CVE/list'")
cursor.execute("PRAGMA user_version = %d" % self.schema_version)
View it on GitLab: https://salsa.debian.org/security-tracker-team/security-tracker/-/compare/0f4fefb8bdf3bc880fcbb84fcbff129d58e2cec5...49e5fcb3d02a581e2f3df5948d7af1372f631f34
--
View it on GitLab: https://salsa.debian.org/security-tracker-team/security-tracker/-/compare/0f4fefb8bdf3bc880fcbb84fcbff129d58e2cec5...49e5fcb3d02a581e2f3df5948d7af1372f631f34
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-security-tracker-commits/attachments/20260818/77da613c/attachment-0001.htm>
More information about the debian-security-tracker-commits
mailing list