diff --git a/README.md b/README.md index 48be970..044638a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Dev-Sec-Ops Demo/Assignment -[![codecov](https://codecov.io/gh/PGCSEDS-IIITH/devsecops-iris/branch/master/graph/badge.svg?token=EILEH8L7R5)](https://codecov.io/gh/PGCSEDS-IIITH/devsecops-iris) +[![codecov](https://codecov.io/gh/vineeth964/devsecops-iris/branch/master/graph/badge.svg?token=EILEH8L7R5)](https://codecov.io/gh/vineeth964/devsecops-iris) This repository contains code which demonstrates Dev-Sec-Ops using a `FastAPI` application which predicts the flower class using the IRIS dataset (https://scikit-learn.org/stable/auto_examples/datasets/plot_iris_dataset.html) diff --git a/results.sariff b/results.sariff new file mode 100644 index 0000000..3fa5331 --- /dev/null +++ b/results.sariff @@ -0,0 +1,89 @@ +{ + "runs": [ + { + "tool": { + "driver": { + "name": "Bandit", + "rules": [ + { + "id": "B104", + "name": "hardcoded_bind_all_interfaces", + "helpUri": "https://bandit.readthedocs.io/en/latest/plugins/b104_hardcoded_bind_all_interfaces.html" + } + ] + } + }, + "invocations": [ + { + "executionSuccessful": true, + "endTimeUtc": "2021-09-25T13:05:38Z" + } + ], + "properties": { + "metrics": { + "_totals": { + "loc": 33, + "nosec": 0, + "SEVERITY.UNDEFINED": 0.0, + "CONFIDENCE.UNDEFINED": 0.0, + "SEVERITY.LOW": 0.0, + "CONFIDENCE.LOW": 0.0, + "SEVERITY.MEDIUM": 1.0, + "CONFIDENCE.MEDIUM": 1.0, + "SEVERITY.HIGH": 0.0, + "CONFIDENCE.HIGH": 0.0 + }, + "./main.py": { + "loc": 33, + "nosec": 0, + "SEVERITY.UNDEFINED": 0.0, + "SEVERITY.LOW": 0.0, + "SEVERITY.MEDIUM": 1.0, + "SEVERITY.HIGH": 0.0, + "CONFIDENCE.UNDEFINED": 0.0, + "CONFIDENCE.LOW": 0.0, + "CONFIDENCE.MEDIUM": 1.0, + "CONFIDENCE.HIGH": 0.0 + } + } + }, + "results": [ + { + "message": { + "text": "Possible binding to all interfaces." + }, + "locations": [ + { + "physicalLocation": { + "region": { + "snippet": { + "text": " uvicorn.run(\"main:app\", host=\"0.0.0.0\", port=8888, reload=True)\n" + }, + "startLine": 64 + }, + "artifactLocation": { + "uri": "main.py" + }, + "contextRegion": { + "snippet": { + "text": " # Uvicorn is used to run the server and listen for incoming API requests on 0.0.0.0:8888\n uvicorn.run(\"main:app\", host=\"0.0.0.0\", port=8888, reload=True)\n" + }, + "endLine": 64, + "startLine": 63 + } + } + } + ], + "properties": { + "issue_confidence": "MEDIUM", + "issue_severity": "MEDIUM" + }, + "ruleId": "B104", + "ruleIndex": 0 + } + ] + } + ], + "version": "2.1.0", + "$schema": "https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.4.json" +} \ No newline at end of file diff --git a/test_app.py b/test_app.py index b65fc90..4c733d0 100644 --- a/test_app.py +++ b/test_app.py @@ -24,3 +24,111 @@ def test_pred_virginica(): # asserting the correct response is received assert response.status_code == 200 assert response.json() == {"flower_class": "Iris Virginica"} + + +# test to check if Iris Virginica is classified correctly +def test_pred_virginica_diff(): + # defining a sample payload for the testcase + payload = { + "sepal_length": 3.1, + "sepal_width": 5.7, + "petal_length": 6, + "petal_width": 6, + } + with TestClient(app) as client: + response = client.post("/predict_flower", json=payload) + # asserting the correct response is received + assert response.status_code == 200 + assert response.json() == {"flower_class": "Iris Virginica"} + + +# test to check if invalid param in payload is passed +def test_pred_invalid_payload(): + # defining a sample payload for the testcase + payload = { + "sepal_length": 2, + "sepal_wid": 3.5, + "petal_length": 1.4, + "petal_width": 0.2, + } + with TestClient(app) as client: + response = client.post("/predict_flower", json=payload) + # asserting the correct response is received + assert response.status_code == 422 + assert response.json() == {'detail': [{'loc': ['body', 'sepal_width'], 'msg': 'field required', 'type': 'value_error.missing'}]} + + +# test to check if invalid param in payload is passed +def test_pred_empty_payload(): + # defining a sample payload for the testcase + payload = { + + } + with TestClient(app) as client: + response = client.post("/predict_flower", json=payload) + # asserting the correct response is received + assert response.status_code == 422 + assert response.json() == {'detail': [{'loc': ['body', 'sepal_length'], 'msg': 'field required', 'type': 'value_error.missing'}, {'loc': ['body', 'sepal_width'], 'msg': 'field required', 'type': 'value_error.missing'}, {'loc': ['body', 'petal_length'], 'msg': 'field required', 'type': 'value_error.missing'}, {'loc': ['body', 'petal_width'], 'msg': 'field required', 'type': 'value_error.missing'}]} + + +# test to check if Iris Setosa is classified correctly +def test_pred_setosa(): + # defining a sample payload for the testcase + payload = { + "sepal_length": 5.1, + "sepal_width": 3.5, + "petal_length": 1.4, + "petal_width": 0.2, + } + with TestClient(app) as client: + response = client.post("/predict_flower", json=payload) + # asserting the correct response is received + assert response.status_code == 200 + assert response.json()["flower_class"] == "Iris Setosa" + +# test to check if Iris Virginica is classified correctly with different payload +def test_pred_virginica_diff_payload(): + # defining a sample payload for the testcase + payload = { + "sepal_length": 5.2, + "sepal_width": 5.4, + "petal_length": 10.4, + "petal_width": 6.2, + } + with TestClient(app) as client: + response = client.post("/predict_flower", json=payload) + # asserting the correct response is received + assert response.status_code == 200 + assert response.json()["flower_class"] == "Iris Virginica" + +#test to check feedback_loop method for Iris Virginica +def test_feedback_loop_virginica(): +# defining a sample payload for the testcase + payload = [{ + "sepal_length": 3, + "sepal_width": 5, + "petal_length": 3.2, + "petal_width": 4.4, + "flower_class":"Iris Virginica" + }] + with TestClient(app) as client: + response = client.post("/feedback_loop", json=payload) + # asserting the correct response is received + assert response.status_code == 200 + assert response.json() == {"detail": "Feedback loop successful"} + +#test to check feedback_loop method +def test_feedback_loop(): +# defining a sample payload for the testcase + payload = [{ + "sepal_length": 3.8, + "sepal_width": 8, + "petal_length": 5.2, + "petal_width": 4.4, + "flower_class":"Iris Setosa" + }] + with TestClient(app) as client: + response = client.post("/feedback_loop", json=payload) + # asserting the correct response is received + assert response.status_code == 200 + assert response.json() == {"detail": "Feedback loop successful"} \ No newline at end of file