Skip to content

Commit

Permalink
Created numeric cve ids
Browse files Browse the repository at this point in the history
  • Loading branch information
samhotep committed Jul 23, 2024
1 parent 5486ac1 commit a9887bd
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 81 deletions.
46 changes: 46 additions & 0 deletions migrations/versions/5df43dc932dd_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
"""empty message
Revision ID: 5df43dc932dd
Revises: c27fec1bfee2
Create Date: 2024-07-23 14:49:17.928909
"""

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = "5df43dc932dd"
down_revision = "c27fec1bfee2"
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.add_column(
"cve", sa.Column("numerical_id", sa.Numeric(), nullable=True)
)
op.create_index(
op.f("ix_cve_numerical_id"), "cve", ["numerical_id"], unique=False
)
op.drop_index("notices_published_desc_idx", table_name="notice")
op.drop_index("notices_published_idx", table_name="notice")
# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_index(
"notices_published_idx", "notice", ["published"], unique=False
)
op.create_index(
"notices_published_desc_idx",
"notice",
[sa.text("published DESC")],
unique=False,
)
op.drop_index(op.f("ix_cve_numerical_id"), table_name="cve")
op.drop_column("cve", "numerical_id")
# ### end Alembic commands ###
83 changes: 83 additions & 0 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Standard library
from contextlib import redirect_stderr
import io
import os
import unittest
import warnings

# Packages
from sqlalchemy_utils import database_exists, create_database
import flask_migrate


# Local
from tests.fixtures.models import make_models

"""
Monkey-patching before importing the main application
===
Get the database connection string from the TEST_DATABASE_URL environment
variable. This variabel is required, as it's important not to accidentally
wipe out a real database.
Replace the authorization_required view decorator with a transparent function
to disable authorization checks for testing privileged views.
This is not ideal, as it means we're not testing the actual authorization
functionality, but I don't know of a good way to do that right now.
"""

from webapp import auth
from tests.helpers import transparent_decorator

auth.authorization_required = transparent_decorator
os.environ["DATABASE_URL"] = os.environ["TEST_DATABASE_URL"]

from webapp.app import app, db # noqa: E402


# Create database if it doesn't exist
with app.app_context():
if not database_exists(db.engine.url):
create_database(db.engine.url)


# Suppress annoying ResourceWarnings
warnings.filterwarnings(action="ignore", category=ResourceWarning)


class BaseTestCase(unittest.TestCase):
def setUp(self):
app.testing = True

# Set up app context
self.context = app.app_context()
self.context.push()

# Clear DB
db.drop_all()
with redirect_stderr(io.StringIO()):
flask_migrate.stamp(revision="base")

# Prepare DB
with redirect_stderr(io.StringIO()):
flask_migrate.upgrade()

# Import data
self.models = make_models()
db.session.add(self.models["cve"])
db.session.add(self.models["notice"])
db.session.add(self.models["release"])
db.session.add(self.models["package"])
db.session.add(self.models["status"])
db.session.commit()

self.client = app.test_client()
return super().setUp()

def tearDown(self):
db.session.close()

self.context.pop()

return super().tearDown()
27 changes: 27 additions & 0 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from click.testing import CliRunner
import unittest

from tests import BaseTestCase, db
from webapp.commands import insert_numerical_cve_ids
from webapp.models import CVE


class TestCommands(BaseTestCase):
runner = CliRunner()

def test_upsert_numerical_cve_ids(self):
"""
Numerical CVE ids should be inserted correctly
"""
result = self.runner.invoke(insert_numerical_cve_ids)
assert result.exit_code == 0

# Check that the numerical cve id was inserted
new_cve = (
db.session.query(CVE).filter(CVE.id == "CVE-1111-0001").first()
)
assert new_cve.numerical_id == int("11110001")


if __name__ == "__main__":
unittest.main()
83 changes: 2 additions & 81 deletions tests/test_routes.py
Original file line number Diff line number Diff line change
@@ -1,88 +1,9 @@
# Standard library
from contextlib import redirect_stderr
import io
import os
import unittest
import warnings

# Packages
from sqlalchemy_utils import database_exists, create_database
import flask_migrate


# Local
from tests.fixtures.models import make_models
from tests import BaseTestCase
from tests.fixtures import payloads

"""
Monkey-patching before importing the main application
===
Get the database connection string from the TEST_DATABASE_URL environment
variable. This variabel is required, as it's important not to accidentally
wipe out a real database.
Replace the authorization_required view decorator with a transparent function
to disable authorization checks for testing privileged views.
This is not ideal, as it means we're not testing the actual authorization
functionality, but I don't know of a good way to do that right now.
"""

from webapp import auth
from tests.helpers import transparent_decorator

auth.authorization_required = transparent_decorator
os.environ["DATABASE_URL"] = os.environ["TEST_DATABASE_URL"]

from webapp.app import app, db # noqa: E402


# Create database if it doesn't exist
with app.app_context():
if not database_exists(db.engine.url):
create_database(db.engine.url)


# Suppress annoying ResourceWarnings
warnings.filterwarnings(action="ignore", category=ResourceWarning)


class TestRoutes(unittest.TestCase):
def setUp(self):
app.testing = True

# Set up app context
self.context = app.app_context()
self.context.push()

# Clear DB
db.drop_all()
with redirect_stderr(io.StringIO()):
flask_migrate.stamp(revision="base")

# Prepare DB
with redirect_stderr(io.StringIO()):
flask_migrate.upgrade()

# Import data
self.models = make_models()
db.session.add(self.models["cve"])
db.session.add(self.models["notice"])
db.session.add(self.models["release"])
db.session.add(self.models["package"])
db.session.add(self.models["status"])
db.session.commit()

self.client = app.test_client()
return super().setUp()

def tearDown(self):
db.session.close()

self.context.pop()

return super().tearDown()

class TestRoutes(BaseTestCase):
def test_spec(self):
response = self.client.get("/security/api/spec.json")

Expand Down
12 changes: 12 additions & 0 deletions webapp/commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import click
from webapp.app import app
from webapp.models import (
upsert_numerical_cve_ids,
)


@app.cli.command("insert-numerical-cve-ids")
def insert_numerical_cve_ids():
"""Management script for the Wiki application."""
upsert_numerical_cve_ids()
click.echo("Numerical CVE ids inserted successfully.")
26 changes: 26 additions & 0 deletions webapp/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from collections import defaultdict
from datetime import datetime
import re

from sqlalchemy import (
Boolean,
Expand All @@ -9,6 +10,7 @@
Float,
ForeignKey,
JSON,
Numeric,
String,
Table,
func,
Expand Down Expand Up @@ -51,6 +53,7 @@ class CVE(db.Model):
__tablename__ = "cve"

id = Column(String, primary_key=True)
numerical_id = Column(Numeric, index=True)
published = Column(DateTime)
description = Column(String)
ubuntu_description = Column(String)
Expand Down Expand Up @@ -143,6 +146,29 @@ def notices_ids(self):
return [notice.id for notice in self.notices]


def convert_cve_id_to_numerical_id(cve_id):
"""
Convert a CVE id to a numerical id.
"""
id_match = re.match(r"^[A-Z]{1,3}-(\d*)-(\d*)", cve_id)
# Upsert numerical_id
return int(id_match.group(1) + id_match.group(2))


def upsert_numerical_cve_ids():
"""
Insert or update the numerical_id column using the CVE id.
e.g 'CVE-2025-12345' -> 202512345
"""
all_cves = db.session.query(CVE).all()
updated_cves = []
for cve in all_cves:
cve.numerical_id = convert_cve_id_to_numerical_id(cve.id)
updated_cves.append(cve)
db.session.add_all(updated_cves)
db.session.commit()


class Notice(db.Model):
__tablename__ = "notice"

Expand Down

0 comments on commit a9887bd

Please sign in to comment.