Merge remote-tracking branch 'origin/main' into feature/script-unit-tests

This commit is contained in:
jasquat 2022-09-28 17:45:38 -04:00
commit f4539d2715
6 changed files with 87 additions and 25 deletions

View File

@ -1103,6 +1103,19 @@ paths:
$ref: "#/components/schemas/ProcessInstanceLog"
/secrets:
parameters:
- name: page
in: query
required: false
description: The page number to return. Defaults to page 1.
schema:
type: integer
- name: per_page
in: query
required: false
description: The number of items to show per page. Defaults to page 10.
schema:
type: integer
post:
operationId: spiffworkflow_backend.routes.process_api_blueprint.add_secret
summary: Create a secret for a key and value
@ -1120,6 +1133,18 @@ paths:
application/json:
schema:
type: number
get:
operationId: spiffworkflow_backend.routes.process_api_blueprint.secret_list
summary: Return list of all secrets
tags:
- Secrets
responses:
"200":
description: list of secrets
content:
application/json:
schema:
$ref: "#/components/schemas/Secret"
/secrets/{key}:
parameters:
@ -1140,7 +1165,7 @@ paths:
content:
application/json:
schema:
type: string
$ref: "#/components/schemas/Secret"
delete:
operationId: spiffworkflow_backend.routes.process_api_blueprint.delete_secret
summary: Delete an existing secret

View File

@ -1,13 +1,17 @@
"""Secret_model."""
from dataclasses import dataclass
from flask_bpmn.models.db import db
from flask_bpmn.models.db import SpiffworkflowBaseDBModel
from marshmallow import Schema
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.orm import RelationshipProperty
from spiffworkflow_backend.models.user import UserModel
@dataclass()
class SecretModel(SpiffworkflowBaseDBModel):
"""SecretModel."""
@ -17,19 +21,12 @@ class SecretModel(SpiffworkflowBaseDBModel):
value: str = db.Column(db.String(255), nullable=False)
creator_user_id: int = db.Column(ForeignKey(UserModel.id), nullable=False)
allowed_processes = relationship("SecretAllowedProcessPathModel", cascade="delete")
class SecretModelSchema(Schema):
"""SecretModelSchema."""
class Meta:
"""Meta."""
model = SecretModel
fields = ["key", "value", "creator_user_id"]
allowed_processes: RelationshipProperty = relationship(
"SecretAllowedProcessPathModel", cascade="delete"
)
@dataclass()
class SecretAllowedProcessPathModel(SpiffworkflowBaseDBModel):
"""Allowed processes can be Process Groups or Process Models.
@ -48,6 +45,16 @@ class SecretAllowedProcessPathModel(SpiffworkflowBaseDBModel):
allowed_relative_path: str = db.Column(db.String(500), nullable=False)
class SecretModelSchema(Schema):
"""SecretModelSchema."""
class Meta:
"""Meta."""
model = SecretModel
fields = ["key", "value", "creator_user_id", "allowed_processes"]
class SecretAllowedProcessSchema(Schema):
"""SecretAllowedProcessSchema."""

View File

@ -48,6 +48,7 @@ from spiffworkflow_backend.models.process_instance_report import (
from spiffworkflow_backend.models.process_model import ProcessModelInfo
from spiffworkflow_backend.models.process_model import ProcessModelInfoSchema
from spiffworkflow_backend.models.secret_model import SecretAllowedProcessSchema
from spiffworkflow_backend.models.secret_model import SecretModel
from spiffworkflow_backend.models.secret_model import SecretModelSchema
from spiffworkflow_backend.models.spiff_logging import SpiffLoggingModel
from spiffworkflow_backend.models.user import UserModel
@ -1246,11 +1247,33 @@ def get_secret(key: str) -> Optional[str]:
return SecretService.get_secret(key)
def secret_list(
page: int = 1,
per_page: int = 100,
) -> Response:
"""Secret_list."""
secrets = (
SecretModel.query.order_by(SecretModel.key)
.join(UserModel)
.add_columns(
UserModel.username,
)
.paginate(page, per_page, False)
)
response_json = {
"results": secrets.items,
"pagination": {
"count": len(secrets.items),
"total": secrets.total,
"pages": secrets.pages,
},
}
return make_response(jsonify(response_json), 200)
def add_secret(body: Dict) -> Response:
"""Add secret."""
secret_model = SecretService().add_secret(
body["key"], body["value"], body["creator_user_id"]
)
secret_model = SecretService().add_secret(body["key"], body["value"], g.user.id)
assert secret_model # noqa: S101
return Response(
json.dumps(SecretModelSchema().dump(secret_model)),

View File

@ -54,13 +54,13 @@ class SecretService:
return secret_model
@staticmethod
def get_secret(key: str) -> Optional[str]:
def get_secret(key: str) -> Optional[SecretModel]:
"""Get_secret."""
secret: SecretModel = (
db.session.query(SecretModel).filter(SecretModel.key == key).first()
)
if secret is not None:
return secret.value
return secret
@staticmethod
def update_secret(

View File

@ -23,7 +23,9 @@ class ServiceTaskDelegate:
secret_prefix = "secret:" # noqa: S105
if value.startswith(secret_prefix):
key = value.removeprefix(secret_prefix)
value = SecretService().get_secret(key)
secret = SecretService().get_secret(key)
assert secret # noqa: S101
value = secret.value
return value
@staticmethod

View File

@ -1,5 +1,6 @@
"""Test_secret_service."""
import json
from typing import Optional
import pytest
from flask.app import Flask
@ -103,7 +104,7 @@ class TestSecretService(SecretServiceTestHelpers):
secret = SecretService().get_secret(self.test_key)
assert secret is not None
assert secret == self.test_value
assert secret.value == self.test_value
def test_get_secret_bad_key_fails(
self, app: Flask, with_db_and_bpmn_file_cleanup: None
@ -122,10 +123,12 @@ class TestSecretService(SecretServiceTestHelpers):
user = self.find_or_create_user()
self.add_test_secret(user)
secret = SecretService.get_secret(self.test_key)
assert secret == self.test_value
assert secret
assert secret.value == self.test_value
SecretService.update_secret(self.test_key, "new_secret_value", user.id)
new_secret = SecretService.get_secret(self.test_key)
assert new_secret == "new_secret_value" # noqa: S105
assert new_secret
assert new_secret.value == "new_secret_value" # noqa: S105
def test_update_secret_bad_user_fails(
self, app: Flask, client: FlaskClient, with_db_and_bpmn_file_cleanup: None
@ -370,7 +373,8 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
)
assert secret_response
assert secret_response.status_code == 200
assert secret_response.json == self.test_value
assert secret_response.json
assert secret_response.json["value"] == self.test_value
def test_update_secret(
self, app: Flask, client: FlaskClient, with_db_and_bpmn_file_cleanup: None
@ -378,8 +382,9 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
"""Test_update_secret."""
user = self.find_or_create_user()
self.add_test_secret(user)
secret = SecretService.get_secret(self.test_key)
assert secret == self.test_value
secret: Optional[SecretModel] = SecretService.get_secret(self.test_key)
assert secret
assert secret.value == self.test_value
secret_model = SecretModel(
key=self.test_key, value="new_secret_value", creator_user_id=user.id
)
@ -404,7 +409,7 @@ class TestSecretServiceApi(SecretServiceTestHelpers):
self.add_test_secret(user)
secret = SecretService.get_secret(self.test_key)
assert secret
assert secret == self.test_value
assert secret.value == self.test_value
secret_response = client.delete(
f"/v1.0/secrets/{self.test_key}",
headers=self.logged_in_headers(user),