Skip to content

Commit d03c0d5

Browse files
rkorsakkeithrfung
authored andcommitted
👯 Split API into Guardian and Mediator modes (#74)
Guardian mode endpoints: - /guardian/* - /key - /auxiliary/generate - /election/generate - /tally - /decrypt-share - /ping Mediator mode endtpoints: - /ballot/* - /election/* - /key/election/combine - /tally - / - /append - /decrypt - /ping The mode is determined on startup by the `API_MODE` environment variable, which can be set to either `guardian` or `mediator` (default). The docker image accepts this environment variable if provided, and a docker-compose file has been added for easy local execution of the image in both guardian and mediator modes.
1 parent 6b1b96c commit d03c0d5

27 files changed

+912
-595
lines changed

.vscode/launch.json

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,33 @@
22
"version": "0.2.0",
33
"configurations": [
44
{
5-
"name": "Web API",
5+
"name": "Guardian Web API",
66
"type": "python",
77
"request": "launch",
88
"program": "${workspaceRoot}/app/main.py",
99
"console": "integratedTerminal",
10+
"args": [
11+
"--port",
12+
"8001"
13+
],
1014
"env": {
11-
"PYTHONPATH": "${workspaceRoot}"
15+
"PYTHONPATH": "${workspaceRoot}",
16+
"API_MODE": "guardian"
17+
}
18+
},
19+
{
20+
"name": "Mediator Web API",
21+
"type": "python",
22+
"request": "launch",
23+
"program": "${workspaceRoot}/app/main.py",
24+
"console": "integratedTerminal",
25+
"args": [
26+
"--port",
27+
"8000"
28+
],
29+
"env": {
30+
"PYTHONPATH": "${workspaceRoot}",
31+
"API_MODE": "mediator"
1232
}
1333
}
1434
]

Dockerfile

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,21 @@
1-
FROM python:3.8
1+
FROM python:3.8 AS base
22
ENV host 0.0.0.0
3-
3+
ENV port 8000
44
RUN apt update && apt-get install -y \
55
libgmp-dev \
66
libmpfr-dev \
77
libmpc-dev
88
RUN pip install pipenv
9-
109
COPY ./Pipfile* /tmp/
1110
RUN cd /tmp && pipenv lock --requirements > requirements.txt
1211
RUN pip install -r /tmp/requirements.txt
1312

14-
COPY ./app /app
13+
FROM base AS dev
14+
VOLUME [ "/app" ]
15+
EXPOSE $port
16+
CMD uvicorn app.main:app --reload --host "$host" --port "$port"
1517

16-
EXPOSE 8000
17-
CMD uvicorn app.main:app --host "$host" --port 8000
18+
FROM base AS prod
19+
COPY ./app /app
20+
EXPOSE $port
21+
CMD uvicorn app.main:app --host "$host" --port "$port"

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ CONTAINER_NAME = electionguard_web_api
66
CONTAINER_ADDRESS ?= 0.0.0.0
77
CONTAINER_PORT ?= 8000
88
IMAGE_NAME = electionguard_web_api
9+
# Supports either "guardian" or "mediator" modes
10+
API_MODE = mediator
911

1012
all: environment lint start
1113

@@ -51,10 +53,13 @@ start:
5153

5254
# Docker
5355
docker-build:
54-
docker build -t $(IMAGE_NAME) .
56+
DOCKER_BUILDKIT=1 docker build -t $(IMAGE_NAME) .
5557

5658
docker-run:
57-
docker run -d --name $(CONTAINER_NAME) -p $(CONTAINER_PORT):8000 -e host=$(CONTAINER_ADDRESS) $(IMAGE_NAME)
59+
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose up --build
60+
61+
docker-dev:
62+
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f docker-compose.dev.yml up --build
5863

5964
# Linting
6065
lint:

README.md

Lines changed: 52 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,75 @@
11
![Microsoft Defending Democracy Program: ElectionGuard](images/electionguard-banner.svg)
22

3-
# 🗳️ ElectionGuard Web API
3+
# 🗳️ ElectionGuard Web API
44

55
![docker version](https://img.shields.io/docker/v/electionguard/electionguard-web-api) ![docker pulls](https://img.shields.io/docker/pulls/electionguard/electionguard-web-api) [![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/microsoft/electionguard-web-api.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/microsoft/electionguard-web-api/context:python) [![Total alerts](https://img.shields.io/lgtm/alerts/g/microsoft/electionguard-web-api.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/microsoft/electionguard-web-api/alerts/) [![Documentation Status](https://readthedocs.org/projects/electionguard-web-api/badge/?version=latest)](https://electionguard-web-api.readthedocs.io) [![license](https://img.shields.io/github/license/microsoft/electionguard-web-api)](LICENSE)
66

7+
This is a python API that utilizes [`electionguard-python`](https://github.com/microsoft/electionguard-python) to perform ballot encryption, casting, spoiling, and tallying. This API is implemented using [FastAPI](https://fastapi.tiangolo.com/#interactive-api-docs).
78

8-
This is a python API that utilizes [`electionguard-python`](https://github.com/microsoft/electionguard-python) to perform ballot encryption, casting, spoiling, and tallying. This API is implemented using [FastAPI](https://fastapi.tiangolo.com/#interactive-api-docs
9-
).
9+
## 👯‍♀️ Two APIs in One
1010

11+
The application can run in one of two modes:
1112

12-
## 💻 Requirements
13+
- `guardian` mode runs features used by Guardians (key ceremony actions, partial tally decryption, etc.)
14+
- `mediator` mode runs features used by Mediators (ballot encryption, casting, spoiling, etc.)
15+
16+
In practice, you will likely need to run at least one instance of each mode. We provide a single codebase and Docker image, but the mode can be set at runtime.
17+
18+
## 🐳 Running with Docker
19+
20+
If you run Docker and want to get started quickly, we provide a Dockerfile and docker-compose.yml.
21+
22+
Run both APIs at the same time:
23+
24+
```bash
25+
make docker-run
26+
```
27+
28+
Or run both APIs in development mode, with automatic reloading on file change:
29+
30+
```bash
31+
make docker-dev
32+
```
33+
34+
After either command, you will find the `mediator` API running at http://127.0.0.1:8000 and the `guardian` API at http://127.0.0.1:8001
35+
36+
## 🐍 Running with Python
37+
38+
### Requirements
1339

1440
_These requirements line up with [electionguard-python](https://github.com/microsoft/electionguard-python/blob/main/README.md#-requirements)._
1541

1642
- [Python 3.8](https://www.python.org/downloads/) is <ins>**required**</ins> to develop this API. If developer uses multiple versions of python, [pyenv](https://github.com/pyenv/pyenv) is suggested to assist version management.
1743
- [GNU Make](https://www.gnu.org/software/make/manual/make.html) is used to simplify the commands and GitHub Actions. This approach is recommended to simplify the command line experience. This is built in for MacOS and Linux. For Windows, setup is simpler with [Chocolatey](https://chocolatey.org/install) and installing the provided [make package](https://chocolatey.org/packages/make). The other Windows option is [manually installing make](http://gnuwin32.sourceforge.net/packages/make.htm).
18-
- [Gmpy2](https://gmpy2.readthedocs.io/en/latest/) is used for [Arbitrary-precision arithmetic](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) which
19-
has its own [installation requirements (native C libraries)](https://gmpy2.readthedocs.io/en/latest/intro.html#installation) on Linux and MacOS. **⚠️ Note:** _This is not required for Windows but the python package must be installed with the precompiled libraries._
2044
- [pipenv](https://github.com/pypa/pipenv) is used to configure the python environment. Installation instructions can be found [here](https://github.com/pypa/pipenv#installation).
2145

22-
## 🚀 Quick Start
46+
### Quick Start
2347

2448
Using [**make**](https://www.gnu.org/software/make/manual/make.html), installation and startup can be run with one command:
2549

26-
```
27-
make
28-
```
50+
To set up the environment:
2951

30-
To start the api:
31-
```
32-
make start
52+
```bash
53+
make environment
3354
```
3455

35-
## 🛠 Debugging
56+
To start the api:
3657

37-
For local debugging with Visual Studio Code, choose the `Web API` option from the dropdown in the Run menu. Once the server is up, you can easily hit your breakpoints.
58+
```bash
59+
make start API_MODE=mediator
60+
```
3861

39-
If the code fails to run, [make sure your Python interpreter is set](https://code.visualstudio.com/docs/python/environments) to use your pipenv environment.
62+
OR
4063

41-
## 🐳 Docker
42-
A DockerFile is available to quickly create and run a docker container.
64+
```bash
65+
make start API_MODE=guardian
66+
```
4367

68+
### Debugging
4469

45-
Build docker container:
46-
```
47-
make docker-build
48-
```
70+
For local debugging with Visual Studio Code, choose the `Guardian Web API` or `Mediator Web API` options from the dropdown in the Run menu. Once the server is up, you can easily hit your breakpoints.
4971

50-
Run docker container:
51-
```
52-
make docker-run
53-
```
72+
If the code fails to run, [make sure your Python interpreter is set](https://code.visualstudio.com/docs/python/environments) to use your pipenv environment.
5473

5574
## 🧪 Testing
5675

@@ -60,33 +79,35 @@ A Postman collection is available to test the API located in the `/tests` folder
6079

6180
**FastApi** defaultly has API documentation built in. The following is available after running:
6281

63-
- **[SwaggerUI](https://github.com/swagger-api/swagger-ui)** at [`http://127.0.0.1:8000/docs`](http://127.0.0.1:8000/docs)
82+
- **[SwaggerUI](https://github.com/swagger-api/swagger-ui)** at [`http://127.0.0.1:8000/docs`](http://127.0.0.1:8000/docs) or [`http://127.0.0.1:8001/docs`](http://127.0.0.1:8001/docs), depending on the API mode
6483

65-
- **[ReDoc](https://github.com/Redocly/redoc)** at [`http://127.0.0.1:8000/redoc`](http://127.0.0.1:8000/redoc)
84+
- **[ReDoc](https://github.com/Redocly/redoc)** at [`http://127.0.0.1:8000/redoc`](http://127.0.0.1:8000/redoc) or [`http://127.0.0.1:8001/redoc`](http://127.0.0.1:8001/redoc)
6685

6786
Overviews of the API itself are available on:
6887

6988
- [GitHub Pages](https://microsoft.github.io/electionguard-web-api/)
7089
- [Read the Docs](https://electionguard-web-api.readthedocs.io/)
7190

7291
## 🗄 Archived
92+
7393
As of 06/15/2020, the previous C wrapped implementation was transitioned to the python version. ElectionGuard development has transitioned to the [ElectionGuard-Python](https://github.com/microsoft/electionguard-python) Repo. The old version is available using the `dotnet-api` tag.
7494

7595
## 🤝 Contributing
7696

77-
This project encourages community contributions for development, testing, documentation, code review, and performance analysis, etc. For more information on how to contribute, see [the contribution guidelines][Contributing]
97+
This project encourages community contributions for development, testing, documentation, code review, and performance analysis, etc. For more information on how to contribute, see [the contribution guidelines][contributing]
7898

7999
### Code of Conduct
80100

81101
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [[email protected]](mailto:[email protected]) with any additional questions or comments.
82102

83103
### Reporting Issues
84104

85-
Please report any bugs, feature requests, or enhancements using the [GitHub Issue Tracker](https://github.com/microsoft/electionguard-web-api/issues). Please do not report any security vulnerabilities using the Issue Tracker. Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). See the [Security Documentation][Security] for more information.
105+
Please report any bugs, feature requests, or enhancements using the [GitHub Issue Tracker](https://github.com/microsoft/electionguard-web-api/issues). Please do not report any security vulnerabilities using the Issue Tracker. Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). See the [Security Documentation][security] for more information.
86106

87107
### Have Questions?
88108

89109
Electionguard would love for you to ask questions out in the open using GitHub Issues. If you really want to email the ElectionGuard team, reach out at [email protected].
90110

91111
## License
92-
This repository is licensed under the [MIT License]
112+
113+
This repository is licensed under the [MIT License]

app/api/v1/api.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,19 @@
11
from fastapi import APIRouter
2-
3-
from app.api.v1.endpoints import ballot, election, guardian, key, ping, tally
2+
from app.core.config import settings, ApiMode
3+
from . import common
44

55
api_router = APIRouter()
6-
api_router.include_router(ballot.router, prefix="/ballot", tags=["ballot"])
7-
api_router.include_router(election.router, prefix="/election", tags=["election"])
8-
api_router.include_router(guardian.router, prefix="/guardian", tags=["guardian"])
9-
api_router.include_router(key.router, prefix="/key", tags=["key"])
10-
api_router.include_router(ping.router, prefix="/ping", tags=["ping"])
11-
api_router.include_router(tally.router, prefix="/tally", tags=["tally"])
6+
7+
if settings.API_MODE == ApiMode.guardian:
8+
from . import guardian
9+
10+
api_router.include_router(guardian.router)
11+
elif settings.API_MODE == ApiMode.mediator:
12+
from . import mediator
13+
14+
api_router.include_router(mediator.router)
15+
else:
16+
raise ValueError(f"Unknown API mode: {settings.API_MODE}")
17+
18+
19+
api_router.include_router(common.router)

app/api/v1/common/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .routes import router
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
from fastapi import APIRouter
44

5+
from ..tags import UTILITY
6+
57
router = APIRouter()
68

79

8-
@router.get("", response_model=str)
10+
@router.get("", response_model=str, tags=[UTILITY])
911
def ping() -> Any:
1012
"""
1113
Ensure API can be pinged

app/api/v1/common/routes.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from fastapi import APIRouter
2+
from . import ping
3+
4+
router = APIRouter()
5+
6+
router.include_router(ping.router, prefix="/ping")

app/api/v1/endpoints/__init__.py

Whitespace-only changes.

app/api/v1/guardian/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from .routes import router

0 commit comments

Comments
 (0)