Skip to content

Commit

Permalink
Return list of ValidationError in all cases from REST API upon HTTP 422
Browse files Browse the repository at this point in the history
  • Loading branch information
CBonnell committed Nov 21, 2023
1 parent 61b2a08 commit 6fd8dd1
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project from version 0.9.3 onwards are documented in this file.

## 0.9.8 - 2023-11-21

### Fixes

- HTTP 422 errors from REST API do not return a list of ValidationErrors in some cases (#54)

## 0.9.7 - 2023-11-03

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion VERSION.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.9.7
0.9.8
6 changes: 5 additions & 1 deletion pkilint/rest/cabf_serverauth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fastapi import HTTPException
from pyasn1.error import PyAsn1Error
from starlette import status

from pkilint.cabf import serverauth
from pkilint.cabf.serverauth import serverauth_constants
Expand All @@ -17,7 +18,10 @@ def determine_linter(self, doc):
except (ValueError, PyAsn1Error) as e:
message = f'Parsing error occurred: {e}'

raise HTTPException(status_code=422, detail=message)
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=model.create_unprocessable_entity_error_detail(message)
)

# this doesn't fail, so we don't need to guard against not being able to determine the certificate type
return next((l for l in self.linters if l.name.casefold() == cert_type.to_option_str.casefold()))
Expand Down
11 changes: 9 additions & 2 deletions pkilint/rest/cabf_smime.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from fastapi import HTTPException
from pyasn1.error import PyAsn1Error
from starlette import status

from pkilint.cabf import smime
from pkilint.cabf.smime import smime_constants
Expand All @@ -17,10 +18,16 @@ def determine_linter(self, doc):
except (ValueError, PyAsn1Error) as e:
message = f'Parsing error occurred: {e}'

raise HTTPException(status_code=422, detail=message)
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=model.create_unprocessable_entity_error_detail(message)
)

if v_g is None:
raise HTTPException(status_code=422, detail='Could not determine certificate type')
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail=model.create_unprocessable_entity_error_detail('Could not determine certificate type')
)

v, g = v_g

Expand Down
10 changes: 10 additions & 0 deletions pkilint/rest/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,13 @@ def validate(self) -> 'CertificateModel':
@property
def parsed_document(self):
return self._parsed_document


def create_unprocessable_entity_error_detail(message: str, error_type: str = 'value_error'):
return [
{
'loc': ['body'],
'type': error_type,
'message': message,
}
]
20 changes: 20 additions & 0 deletions tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@ def test_version(client):
'''


def _assert_validationerror_list_present(resp):
j = resp.json()

detail_list = j['detail']
assert len(detail_list) == 1

detail_0 = detail_list[0]
assert detail_0['loc'] == ['body']
assert detail_0['type'] == 'value_error'
assert 'message' in detail_0


def test_groups(client):
resp = client.get('/certificate')
assert resp.status_code == HTTPStatus.OK
Expand Down Expand Up @@ -199,11 +211,15 @@ def test_smime_detect_bad_extension_der(client):
resp = client.post('/certificate/cabf-smime', json={'pem': _BAD_CERT_POLICIES_DER_PEM})
assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY

_assert_validationerror_list_present(resp)


def test_smime_detect_not_smime(client):
resp = client.post('/certificate/cabf-smime', json={'pem': _OV_FINAL_CLEAN_PEM})
assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY

_assert_validationerror_list_present(resp)


def test_lint_smime_unknown_linter(client):
resp = client.post('/certificate/cabf-smime/lint/FOOMASTER-BAR', json={'pem': _SMBR_SPONSORED_STRICT_PEM})
Expand Down Expand Up @@ -251,6 +267,8 @@ def test_detect_and_lint_smime_with_tls(client):
resp = client.post('/certificate/cabf-smime', json={'pem': _OV_FINAL_CLEAN_PEM})
assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY

_assert_validationerror_list_present(resp)


def test_serverauth_no_cert(client):
resp = client.post('/certificate/cabf-serverauth', json={})
Expand Down Expand Up @@ -288,6 +306,8 @@ def test_serverauth_detect_bad_extension_der(client):
resp = client.post('/certificate/cabf-serverauth', json={'pem': _BAD_CERT_POLICIES_DER_PEM})
assert resp.status_code == HTTPStatus.UNPROCESSABLE_ENTITY

_assert_validationerror_list_present(resp)


def test_lint_serverauth_unknown_linter(client):
resp = client.post('/certificate/cabf-serverauth/FOOMASTER-BAR', json={'pem': _OV_FINAL_CLEAN_PEM})
Expand Down

0 comments on commit 6fd8dd1

Please sign in to comment.