Skip to content

Format and add linting rules/github action #88

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jan 16, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/workflows/pr-linting.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Ruff Code Formatter and Linting Check

on:
pull_request:
branches: [ main ]

jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Ruff Format and Lint Check
uses: astral-sh/ruff-action@v3
with:
src: "./server"
version: "0.9.1"
args: "format --check"
4 changes: 3 additions & 1 deletion server/app/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fastapi import FastAPI, APIRouter
from fastapi import APIRouter, FastAPI
from fastapi.responses import JSONResponse

from app.routers import identifiers
from config import settings

Expand All @@ -10,6 +11,7 @@

@api_router.get("/server/status", tags=["Server"], include_in_schema=False)
async def server_status():
"""Server status endpoint."""
return JSONResponse(status_code=200, content={"status": "ok"})


Expand Down
8 changes: 6 additions & 2 deletions server/app/dependencies.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
"""This module contains dependencies used by the FastAPI application."""

from fastapi import HTTPException
from config import settings

from app.plugins import AskarStorage


async def identifier_available(did: str):
"""Check if a DID identifier is available."""
if await AskarStorage().fetch("didDocument", did):
raise HTTPException(status_code=409, detail="Identifier unavailable.")


async def did_document_exists(did: str):
"""Check if a DID document exists."""
if not await AskarStorage().fetch("didDocument", did):
raise HTTPException(status_code=404, detail="Ressource not found.")
raise HTTPException(status_code=404, detail="Resource not found.")
14 changes: 13 additions & 1 deletion server/app/models/di_proof.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
from typing import Dict, Any
"""This module defines the DataIntegrityProof model used for data integrity proofs."""

from typing import Any, Dict

from pydantic import BaseModel, Field, field_validator


class BaseModel(BaseModel):
"""Base model for all models in the application."""

def model_dump(self, **kwargs) -> Dict[str, Any]:
"""Dump the model to a dictionary."""
return super().model_dump(by_alias=True, exclude_none=True, **kwargs)


class DataIntegrityProof(BaseModel):
"""DataIntegrityProof model."""

type: str = Field("DataIntegrityProof")
cryptosuite: str = Field("eddsa-jcs-2022")
proofValue: str = Field()
Expand Down Expand Up @@ -35,22 +43,26 @@ class DataIntegrityProof(BaseModel):
@field_validator("type")
@classmethod
def validate_type(cls, value):
"""Validate the type field."""
assert value == "DataIntegrityProof"
return value

@field_validator("cryptosuite")
@classmethod
def validate_cryptosuite(cls, value):
"""Validate the cryptosuite field."""
assert value in ["eddsa-jcs-2022"]
return value

@field_validator("proofPurpose")
@classmethod
def validate_proof_purpose(cls, value):
"""Validate the proofPurpose field."""
assert value in ["assertionMethod", "authentication"]
return value

@field_validator("expires")
@classmethod
def validate_expires(cls, value):
"""Validate the expires field."""
return value
48 changes: 36 additions & 12 deletions server/app/models/did_document.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,45 @@
from typing import Union, List, Dict, Any
from pydantic import BaseModel, Field, field_validator
from .di_proof import DataIntegrityProof
from multiformats import multibase
from config import settings
"""DID Document model."""

import re
from typing import Any, Dict, List, Union

import validators
from multiformats import multibase
from pydantic import BaseModel, Field, field_validator

from .di_proof import DataIntegrityProof

DID_WEB_REGEX = re.compile("did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)")

DID_WEB_ID_REGEX = re.compile(
"did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)#([a-z0-9._%-]+)"
)
DID_WEB_ID_REGEX = re.compile("did:web:((?:[a-zA-Z0-9._%-]*:)*[a-zA-Z0-9._%-]+)#([a-z0-9._%-]+)")


class BaseModel(BaseModel):
"""Base model for all models in the application."""

def model_dump(self, **kwargs) -> Dict[str, Any]:
"""Dump the model to a dictionary."""
return super().model_dump(by_alias=True, exclude_none=True, **kwargs)


class VerificationMethod(BaseModel):
"""VerificationMethod model."""

id: str = Field()
type: Union[str, List[str]] = Field()
controller: str = Field()

@field_validator("id")
@classmethod
def verification_method_id_validator(cls, value):
"""Validate the id field."""
assert value.startswith("did:")
return value

@field_validator("type")
@classmethod
def verification_method_type_validator(cls, value):
"""Validate the type field."""
assert value in [
"Multikey",
"JsonWebKey",
Expand All @@ -42,58 +49,73 @@ def verification_method_type_validator(cls, value):
@field_validator("controller")
@classmethod
def verification_method_controller_validator(cls, value):
"""Validate the controller field."""
assert value.startswith("did:")
return value


class JsonWebKey(BaseModel):
"""JsonWebKey model."""

kty: str = Field("OKP")
crv: str = Field("Ed25519")
x: str = Field()


class VerificationMethodJwk(VerificationMethod):
"""VerificationMethodJwk model."""

publicKeyJwk: JsonWebKey = Field()

@field_validator("publicKeyJwk")
@classmethod
def verification_method_public_key_validator(cls, value):
"""Validate the public key field."""
# TODO decode b64
return value


class VerificationMethodMultikey(VerificationMethod):
"""VerificationMethodMultikey model."""

publicKeyMultibase: str = Field()

@field_validator("publicKeyMultibase")
@classmethod
def verification_method_public_key_validator(cls, value):
"""Validate the public key field."""
try:
multibase.decode(value)
except:
except Exception:
assert False, f"Unable to decode public key multibase value {value}"
return value


class Service(BaseModel):
"""Service model."""

id: str = Field()
type: Union[str, List[str]] = Field()
serviceEndpoint: str = Field()

@field_validator("id")
@classmethod
def service_id_validator(cls, value):
"""Validate the id field."""
assert value.startswith("did:")
return value

@field_validator("serviceEndpoint")
@classmethod
def service_endpoint_validator(cls, value):
"""Validate the service endpoint field."""
assert validators.url(value), f"Invalid service endpoint {value}."
return value


class DidDocument(BaseModel):
"""DID Document model."""

context: Union[str, List[str]] = Field(
["https://www.w3.org/ns/did/v1"],
alias="@context",
Expand All @@ -103,9 +125,7 @@ class DidDocument(BaseModel):
description: str = Field(None)
controller: str = Field(None)
alsoKnownAs: List[str] = Field(None)
verificationMethod: List[
Union[VerificationMethodMultikey, VerificationMethodJwk]
] = Field(None)
verificationMethod: List[Union[VerificationMethodMultikey, VerificationMethodJwk]] = Field(None)
authentication: List[Union[str, VerificationMethod]] = Field(None)
assertionMethod: List[Union[str, VerificationMethod]] = Field(None)
keyAgreement: List[Union[str, VerificationMethod]] = Field(None)
Expand All @@ -127,15 +147,19 @@ class DidDocument(BaseModel):
@field_validator("context")
@classmethod
def context_validator(cls, value):
"""Validate the context field."""
assert value[0] == "https://www.w3.org/ns/did/v1", "Invalid context."
return value

@field_validator("id")
@classmethod
def id_validator(cls, value):
"""Validate the id field."""
assert value.startswith("did:")
return value


class SecuredDidDocument(DidDocument):
"""Secured DID Document model."""

proof: Union[DataIntegrityProof, List[DataIntegrityProof]] = Field()
28 changes: 25 additions & 3 deletions server/app/models/did_log.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,48 @@
from typing import Union, List, Dict, Any
"""DID Log models."""

from typing import Any, Dict, List, Union

from pydantic import BaseModel, Field
from .did_document import DidDocument
from .di_proof import DataIntegrityProof

from config import settings

from .di_proof import DataIntegrityProof
from .did_document import DidDocument


class BaseModel(BaseModel):
"""Base model for all models in the application."""

def model_dump(self, **kwargs) -> Dict[str, Any]:
"""Dump the model to a dictionary."""
return super().model_dump(by_alias=True, exclude_none=True, **kwargs)


class Witness(BaseModel):
"""Witness model."""

id: str = Field(None)
weight: int = Field(None)


class WitnessParam(BaseModel):
"""WitnessParam model."""

threshold: int = Field(None)
selfWeight: int = Field(None)
witnesses: List[Witness] = Field(None)


class WitnessSignature(BaseModel):
"""WitnessSignature model."""

versionId: str = Field(None)
proof: List[DataIntegrityProof] = Field()


class InitialLogParameters(BaseModel):
"""InitialLogParameters model."""

method: str = Field(f"did:webvh:{settings.WEBVH_VERSION}")
scid: str = Field()
updateKeys: List[str] = Field()
Expand All @@ -37,6 +53,8 @@ class InitialLogParameters(BaseModel):


class LogParameters(BaseModel):
"""LogParameters model."""

prerotation: bool = Field(None)
portable: bool = Field(None)
updateKeys: List[str] = Field(None)
Expand Down Expand Up @@ -64,6 +82,8 @@ class LogParameters(BaseModel):


class InitialLogEntry(BaseModel):
"""InitialLogEntry model."""

versionId: str = Field()
versionTime: str = Field()
parameters: LogParameters = Field()
Expand All @@ -72,6 +92,8 @@ class InitialLogEntry(BaseModel):


class LogEntry(BaseModel):
"""LogEntry model."""

versionId: str = Field()
versionTime: str = Field()
parameters: LogParameters = Field()
Expand Down
19 changes: 16 additions & 3 deletions server/app/models/web_schemas.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
from typing import Dict, Any, List
"""Pydantic models for the web schemas."""

from typing import Any, Dict, List

from pydantic import BaseModel, Field
from .did_document import SecuredDidDocument
from .did_log import InitialLogEntry, LogEntry, WitnessSignature

from .di_proof import DataIntegrityProof
from .did_document import SecuredDidDocument
from .did_log import InitialLogEntry, LogEntry


class BaseModel(BaseModel):
"""Base model for all models in the application."""

def model_dump(self, **kwargs) -> Dict[str, Any]:
"""Dump the model to a dictionary."""
return super().model_dump(by_alias=True, exclude_none=True, **kwargs)


class RegisterDID(BaseModel):
"""RegisterDID model."""

didDocument: SecuredDidDocument = Field()


class RegisterInitialLogEntry(BaseModel):
"""RegisterInitialLogEntry model."""

logEntry: InitialLogEntry = Field()


class UpdateLogEntry(BaseModel):
"""UpdateLogEntry model."""

logEntry: LogEntry = Field()
witnessProof: List[DataIntegrityProof] = Field(None)

Expand Down
Loading
Loading