* Fixes the 404 errors for Fetch Guardian and Fetch Public Keys
* Log stack traces on error
* Remove the memory repository, it didn't work
* Notify client if there are duplicate guardians
* typo
* Show stack trace if errors occur retrieving guardians
* Debugging should default to local storage for simplicity
* Debug windows documentation
* Fix linting
* Minor cleanup to postman
This commit is contained in:
Lee Richardson 2021-12-21 14:02:48 -05:00 ΠΊΠΎΠΌΠΌΠΈΡ‚ ΠΏΡ€ΠΎΠΈΠ·Π²Ρ‘Π» GitHub
Π ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒ ff32ddfc18
ΠšΠΎΠΌΠΌΠΈΡ‚ cbc7cc57b4
НС Π½Π°ΠΉΠ΄Π΅Π½ ΠΊΠ»ΡŽΡ‡, ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ Π΄Π°Π½Π½ΠΎΠΉ подписи
Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ ΠΊΠ»ΡŽΡ‡Π° GPG: 4AEE18F83AFDEB23
8 ΠΈΠ·ΠΌΠ΅Π½Ρ‘Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ²: 34 Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠΉ ΠΈ 55 ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΉ

4
.vscode/launch.json поставляСмый
ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -15,7 +15,7 @@
"PYTHONPATH": "${workspaceRoot}",
"API_MODE": "guardian",
"QUEUE_MODE": "remote",
"STORAGE_MODE": "mongo"
"STORAGE_MODE": "local_storage"
}
},
{
@ -32,7 +32,7 @@
"PYTHONPATH": "${workspaceRoot}",
"API_MODE": "mediator",
"QUEUE_MODE": "remote",
"STORAGE_MODE": "mongo"
"STORAGE_MODE": "local_storage"
}
}
]

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -86,7 +86,7 @@ Developing with Python provides the fastest developer inner loop (speed from cod
### βœ… 3.1. Windows Prerequisites
On Windows you can use an IDE of your choice in Windows, and run the make and Python commands in WSL which will expose API's in Windows. However, developing with Python on Windows involves additional setup that is not required for Linux or Mac.
On Windows you can use an IDE of your choice in Windows, and run the make and Python commands in WSL which will expose API's in Windows. Developing with Python on Windows involves the following additional setup that is not required for Linux or Mac.
1. Install [WSL 2](https://docs.microsoft.com/en-us/windows/wsl/install)
2. Install [Ubuntu](https://www.microsoft.com/en-us/p/ubuntu/9nblggh4msv6?ocid=9nblggh4msv6_ORSEARCH_Bing&rtc=1&activetab=pivot:overviewtab) (other Linux distributions should also work with minor modifications to the instructions below)
@ -149,12 +149,21 @@ OR as guardian
make start API_MODE=guardian
```
### Debugging
### Debugging Mac/Linux
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.
If the code fails to run, [make sure your Python interpreter is set](https://code.visualstudio.com/docs/python/environments) to use your poetry environment.
### Debugging Windows
With Visual Studio Code:
1. Install the [Remote WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) extension
2. In the bottom left click the Green Icon and "New WSL Window using Distro", select Ubuntu
3. F5
4. Choose either `Guardian Web API` or `Mediator Web API`
## πŸ§ͺ Testing
End-to-end integration tests can be found in the [`/tests/integration`](/tests/integration) folder. To see them in action, run:

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,3 +1,4 @@
import traceback
import sys
from typing import Dict, List
from fastapi import APIRouter, Body, status, HTTPException, Request
@ -120,8 +121,10 @@ def create_guardian(
status_code=status.HTTP_409_CONFLICT,
detail=f"Already exists {data.guardian_id}",
)
except HTTPException:
raise
except Exception as error:
print(sys.exc_info())
traceback.print_exc()
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
detail="Submit guardian failed",

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,3 +1,4 @@
import traceback
from typing import List
import sys
from fastapi import APIRouter, Body, HTTPException, Request, status
@ -37,7 +38,7 @@ def create_key_ceremony_guardian(
"""
Create a Key Ceremony Guardian.
In order for a guardian to participate they must be assiciated with the key ceremony first.
In order for a guardian to participate they must be associated with the key ceremony first.
"""
try:
with get_repository(
@ -54,6 +55,7 @@ def create_key_ceremony_guardian(
detail=f"Already exists {data.guardian_id}",
)
except Exception as error:
traceback.print_exc()
print(sys.exc_info())
raise HTTPException(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,3 +1,4 @@
import traceback
from typing import Any
import sys
from fastapi import HTTPException, status
@ -22,6 +23,7 @@ __all__ = [
def guardian_from_query(query_result: Any) -> Guardian:
return Guardian(
guardian_id=query_result["guardian_id"],
name=query_result["name"],
sequence_order=query_result["sequence_order"],
number_of_guardians=query_result["number_of_guardians"],
quorum=query_result["quorum"],
@ -49,6 +51,7 @@ def get_guardian(guardian_id: str, settings: Settings = Settings()) -> Guardian:
guardian = guardian_from_query(query_result)
return guardian
except Exception as error:
traceback.print_exc()
print(sys.exc_info())
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,4 +1,4 @@
from typing import Dict, Any, List, Union
from typing import Any, List, Union
from collections.abc import MutableMapping
from abc import ABC, abstractmethod
@ -17,7 +17,6 @@ from .settings import Settings, StorageMode
__all__ = [
"IRepository",
"LocalRepository",
"MemoryRepository",
"MongoRepository",
"get_repository",
]
@ -145,42 +144,6 @@ class LocalRepository(IRepository):
pass
class MemoryRepository(IRepository):
def __init__(
self,
container: str,
collection: str,
):
super().__init__()
self._id = 0
self._container = container
self._collection = collection
self.storage: Dict[int, Any] = {}
def __enter__(self) -> Any:
return self
def __exit__(self, exc_type: Any, exc_value: Any, exc_traceback: Any) -> None:
pass
def find(self, filter: MutableMapping, skip: int = 0, limit: int = 0) -> Any:
pass
def get(self, filter: MutableMapping) -> Any:
for item in self.storage.items():
if item[filter[0]] == filter[1]:
return item
return None
def set(self, value: DOCUMENT_VALUE_TYPE) -> Any:
self._id += 1
self.storage[self._id] = value
return str(self._id)
def update(self, filter: MutableMapping, value: DOCUMENT_VALUE_TYPE) -> Any:
pass
class MongoRepository(IRepository):
def __init__(
self,
@ -234,4 +197,4 @@ def get_repository(
if settings.STORAGE_MODE == StorageMode.LOCAL_STORAGE:
return LocalRepository(container, collection)
return MemoryRepository(container, collection)
raise ValueError("Unsupported storage mode: " + settings.STORAGE_MODE)

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -23,7 +23,6 @@ class QueueMode(str, Enum):
class StorageMode(str, Enum):
LOCAL_STORAGE = "local_storage"
MEMORY = "memory"
MONGO = "mongo"
@ -31,7 +30,7 @@ class StorageMode(str, Enum):
class Settings(BaseSettings):
API_MODE: ApiMode = ApiMode.MEDIATOR
QUEUE_MODE: QueueMode = QueueMode.LOCAL
STORAGE_MODE: StorageMode = StorageMode.MEMORY
STORAGE_MODE: StorageMode = StorageMode.LOCAL_STORAGE
API_V1_STR: str = "/api/v1"
BACKEND_CORS_ORIGINS: List[AnyHttpUrl] = Field(

ΠŸΡ€ΠΎΡΠΌΠΎΡ‚Ρ€Π΅Ρ‚ΡŒ Ρ„Π°ΠΉΠ»

@ -1,6 +1,6 @@
{
"info": {
"_postman_id": "977c776c-3ab8-40d2-a0ab-7c56f6f510d8",
"_postman_id": "afbe5e1b-166d-404d-8b1f-76d33fc07ecb",
"name": "ElectionGuard Web Api",
"description": "A collection of API calls for ElectionGuard Web Api",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
@ -136,7 +136,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"filter\": {\n \"state\": \"OPEN\"\n }\n}",
"raw": "{\n \"filter\": {\n \"state\": \"CREATED\"\n }\n}",
"options": {
"raw": {
"language": "json"
@ -257,7 +257,7 @@
"method": "POST",
"header": [],
"url": {
"raw": "{{mediator-url}}/api/{{version}}/election/close?election_id=some-election-id-1",
"raw": "{{mediator-url}}/api/{{version}}/election/close?election_id=hamilton-general-election-1",
"host": [
"{{mediator-url}}"
],
@ -270,7 +270,7 @@
"query": [
{
"key": "election_id",
"value": "some-election-id-1"
"value": "hamilton-general-election-1"
}
]
}
@ -283,7 +283,7 @@
"method": "POST",
"header": [],
"url": {
"raw": "{{mediator-url}}/api/{{version}}/election/publish?election_id=some-election-id-1",
"raw": "{{mediator-url}}/api/{{version}}/election/publish?election_id=hamilton-general-election-1",
"host": [
"{{mediator-url}}"
],
@ -296,7 +296,7 @@
"query": [
{
"key": "election_id",
"value": "some-election-id-1"
"value": "hamilton-general-election-1"
}
]
}
@ -1707,7 +1707,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"guardian_id\": \"guardian_1\",\n \"sequence_order\": 1,\n \"number_of_guardians\": 3,\n \"quorum\": 2\n}",
"raw": "{\n \"guardian_id\": \"guardian_1\",\n \"name\": \"Bob Smith 1\",\n \"sequence_order\": 1,\n \"number_of_guardians\": 3,\n \"quorum\": 2\n}",
"options": {
"raw": {
"language": "json"
@ -1884,7 +1884,7 @@
"header": [],
"body": {
"mode": "raw",
"raw": "{\n \"owner_id\":\"hamilton-county-canvass-board-member-0\",\n \"sequence_order\": 0\n \"quorum\": 3\n}",
"raw": "{\n \"owner_id\":\"hamilton-county-canvass-board-member-0\",\n \"sequence_order\": 0,\n \"quorum\": 3\n}",
"options": {
"raw": {
"language": "json"