# jss-devsecops-challenge DevSecOps assessment - device registration and statistics API built with Python (Flask) and MariaDB. ## What it does A single API server that tracks device type registrations per user. It exposes three endpoints: - `POST /log/auth` - logs a user login event by storing the device type - `GET /log/auth/statistics?deviceType=iOS` - returns count of registrations for a given device type - `POST /device/register` - directly registers a device type for a user Accepted device types: iOS, Android, Watch, TV, Tablet, Desktop, IoT. In contrast to API endpoints asked in pdf file, I used smaller case here. ## Project structure ``` app/server.py - Flask application with all endpoints tests/test_app.py - unit tests (mocked DB) init.sql - MariaDB schema initialization Dockerfile - container image for the API docker-compose.yml - full stack (MariaDB + API) requirements.txt - Python dependencies ``` ## Docker Hub The API image is published to Docker Hub: ``` docker.io/harshavmb/jss-devsecops-api:latest ``` To pull it directly: ```bash docker pull harshavmb/jss-devsecops-api:latest ``` MariaDB is used from the official registry (`docker.io/library/mariadb:12`) and does not need a custom image. The schema is applied at startup via the init SQL script mounted in docker-compose. ## Running locally with Docker Compose ```bash docker compose up --build -d ``` This starts MariaDB, runs the init SQL script, and launches the API on port 5000. To stop: ```bash docker compose down -v ``` ## Running tests ```bash pip install -r requirements.txt pytest tests/ -v ``` ## Security controls - Input validation on userKey (regex whitelist) and deviceType (enum whitelist) - Parameterized SQL queries to prevent injection - Rate limiting (30 req/min per endpoint, 60 req/min global) - Non-root container user - No secrets hardcoded (configurable via DATABASE_URL env var) - No docker/podman container is run as root user (that depends on how docker/podman are configured on host) - Authentication of endpoints is left out for brevity ## Configuration The API reads `DATABASE_URL` from the environment. Format: ``` mysql://user:password@host:port/database ``` Default: `mysql://root:my-secret-pw@localhost:3306/devsecops_db`