83 lines
2.3 KiB
Markdown
83 lines
2.3 KiB
Markdown
# 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`
|