From 895a05602192991c7fdfa1afc8dc9a1a32e5dd67 Mon Sep 17 00:00:00 2001 From: Kegan Maher Date: Wed, 18 Dec 2024 23:54:39 +0000 Subject: [PATCH 1/3] feat(metadata): define and load model --- eligibility_server/db/models.py | 10 ++++++++++ eligibility_server/db/setup.py | 22 +++++++++++++++++++--- tests/db/test_setup.py | 11 ++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/eligibility_server/db/models.py b/eligibility_server/db/models.py index bd5caab4..13976f47 100644 --- a/eligibility_server/db/models.py +++ b/eligibility_server/db/models.py @@ -1,6 +1,16 @@ from eligibility_server.db import db +class Metadata(db.Model): + id = db.Column(db.Integer, primary_key=True) + timestamp = db.Column(db.String, unique=True, nullable=False) + users = db.Column(db.Integer, nullable=False) + eligibility = db.Column(db.PickleType, nullable=False) + + def __repr__(self): + return f" 1 else ''}>" # noqa: E501 + + user_eligibility = db.Table( "user_eligibility", db.Column("user_id", db.Integer, db.ForeignKey("user.id"), primary_key=True), diff --git a/eligibility_server/db/setup.py b/eligibility_server/db/setup.py index 18c0aa68..a585ce3e 100644 --- a/eligibility_server/db/setup.py +++ b/eligibility_server/db/setup.py @@ -1,13 +1,14 @@ import csv +from datetime import datetime, timezone from tempfile import NamedTemporaryFile import click from flask import current_app -from sqlalchemy import inspect +from sqlalchemy import column, inspect import requests from eligibility_server.db import db -from eligibility_server.db.models import User, Eligibility +from eligibility_server.db.models import User, Eligibility, Metadata from eligibility_server.settings import Configuration @@ -29,9 +30,10 @@ def init_db_command(): click.echo("Creating table...") db.create_all() click.echo("Table created.") - import_users() + update_metadata() + def import_users(): """ @@ -135,3 +137,17 @@ def drop_db_command(): click.echo("Database dropped.") else: click.echo("Database does not exist.") + + +def update_metadata(): + Metadata.query.delete() + + ts = datetime.now(tz=timezone.utc).isoformat(timespec="seconds") + users = User.query.count() + eligibility = [e.name for e in Eligibility.query.add_column(column("name"))] + + metadata = Metadata(timestamp=ts, users=users, eligibility=eligibility) + db.session.add(metadata) + db.session.commit() + + click.echo("Database metadata updated.") diff --git a/tests/db/test_setup.py b/tests/db/test_setup.py index 87337a38..eb7a85b0 100644 --- a/tests/db/test_setup.py +++ b/tests/db/test_setup.py @@ -1,8 +1,10 @@ +from datetime import datetime, timedelta, timezone + import pytest from sqlalchemy import inspect from eligibility_server.db import db -from eligibility_server.db.models import Eligibility, User +from eligibility_server.db.models import Eligibility, Metadata, User @pytest.mark.usefixtures("flask") @@ -10,12 +12,19 @@ def test_init_db_command(runner): """Assumes that IMPORT_FILE_PATH is data/server.csv.""" runner.invoke(args="drop-db") + start_time = datetime.now(tz=timezone.utc) result = runner.invoke(args="init-db") assert result.exit_code == 0 assert User.query.count() == 26 assert Eligibility.query.count() == 1 + assert Metadata.query.count() == 1 + + metadata = Metadata.query.first() + assert metadata.users == User.query.count() + assert datetime.fromisoformat(metadata.timestamp) - start_time < timedelta(seconds=1) + assert metadata.eligibility == ["agency_card"] user_with_one_eligibility = User.query.filter_by(sub="32587", name="Gonzales").first() agency_card_type = Eligibility.query.filter_by(name="agency_card").first() From 6ee16285ca2f0b11b964969caad873923318febf Mon Sep 17 00:00:00 2001 From: Kegan Maher Date: Thu, 19 Dec 2024 00:09:09 +0000 Subject: [PATCH 2/3] feat(metadata): endpoint returns info as JSON --- eligibility_server/app.py | 12 ++++++++++++ tests/test_app.py | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/eligibility_server/app.py b/eligibility_server/app.py index 3b017c14..022a4464 100644 --- a/eligibility_server/app.py +++ b/eligibility_server/app.py @@ -9,6 +9,7 @@ from flask_restful import Api from eligibility_server import __version__, db, sentry +from eligibility_server.db.models import Metadata from eligibility_server.keypair import get_server_public_key from eligibility_server.settings import Configuration from eligibility_server.verify import Verify @@ -53,6 +54,17 @@ def healthcheck(): return TextResponse("Healthy") +@app.route("/metadata") +def metadata(): + app.logger.info("Request metadata") + + md = Metadata.query.first() + return { + "app": {"version": __version__}, + "db": {"timestamp": md.timestamp, "users": md.users, "eligibility": md.eligibility}, + } + + @app.route("/publickey") def publickey(): app.logger.info("Request public key") diff --git a/tests/test_app.py b/tests/test_app.py index 105d6190..ae21665a 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -4,6 +4,7 @@ import re +from eligibility_server import __version__ from eligibility_server.settings import APP_NAME from eligibility_server.keypair import get_server_public_key @@ -20,6 +21,23 @@ def test_healthcheck(client): assert "Strict-Transport-Security" in response.headers +def test_metadata(client): + response = client.get("metadata") + assert response.status_code == 200 + assert response.mimetype == "application/json" + assert "Strict-Transport-Security" in response.headers + + data = response.json + + assert "app" in data + assert data["app"]["version"] == __version__ + assert "db" in data + assert isinstance(data["db"]["timestamp"], str) + assert isinstance(data["db"]["users"], int) + assert isinstance(data["db"]["eligibility"], list) + assert len(data["db"]["eligibility"]) > 0 + + def test_404(client): response = client.get("/random") From dcfafae3349bc7bc1c7aae546e369d9f39b65a32 Mon Sep 17 00:00:00 2001 From: Kegan Maher Date: Thu, 19 Dec 2024 00:16:28 +0000 Subject: [PATCH 3/3] feat(terraform): allow public access to /metadata endpoint --- terraform/front_door.tf | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/terraform/front_door.tf b/terraform/front_door.tf index f3cdc1b2..9742a310 100644 --- a/terraform/front_door.tf +++ b/terraform/front_door.tf @@ -83,7 +83,11 @@ resource "azurerm_cdn_frontdoor_firewall_policy" "main" { match_condition { match_variable = "RequestUri" operator = "BeginsWith" - match_values = ["https://${azurerm_cdn_frontdoor_endpoint.main.host_name}:443/healthcheck", "https://${azurerm_cdn_frontdoor_endpoint.main.host_name}:443/static/"] + match_values = [ + "https://${azurerm_cdn_frontdoor_endpoint.main.host_name}:443/healthcheck", + "https://${azurerm_cdn_frontdoor_endpoint.main.host_name}:443/metadata", + "https://${azurerm_cdn_frontdoor_endpoint.main.host_name}:443/static/" + ] } }