added secret verification to webhook endpoint w/ burnettk
This commit is contained in:
parent
d7221690f0
commit
6122fb0ae5
|
@ -61,8 +61,9 @@ SPIFFWORKFLOW_BACKEND_LOG_LEVEL = environ.get(
|
|||
|
||||
# When a user clicks on the `Publish` button, this is the default branch this server merges into.
|
||||
# I.e., dev server could have `staging` here. Staging server might have `production` here.
|
||||
GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO", default="staging")
|
||||
GIT_CLONE_URL_FOR_PUBLISHING = environ.get("GIT_CLONE_URL", default=None)
|
||||
GIT_BRANCH_TO_PUBLISH_TO = environ.get("GIT_BRANCH_TO_PUBLISH_TO")
|
||||
GIT_BRANCH = environ.get("GIT_BRANCH")
|
||||
GIT_CLONE_URL_FOR_PUBLISHING = environ.get("GIT_CLONE_URL")
|
||||
GIT_COMMIT_ON_SAVE = environ.get("GIT_COMMIT_ON_SAVE", default="false") == "true"
|
||||
|
||||
# Datbase Configuration
|
||||
|
|
|
@ -17,3 +17,5 @@ GIT_CLONE_URL_FOR_PUBLISHING = environ.get(
|
|||
)
|
||||
GIT_USERNAME = "sartography-automated-committer"
|
||||
GIT_USER_EMAIL = f"{GIT_USERNAME}@users.noreply.github.com"
|
||||
GIT_BRANCH_TO_PUBLISH_TO = "main"
|
||||
GIT_BRANCH = "main"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
"""staging."""
|
||||
GIT_BRANCH = "staging"
|
||||
GIT_BRANCH_TO_PUBLISH_TO = "main"
|
||||
GIT_COMMIT_ON_SAVE = False
|
|
@ -1826,8 +1826,12 @@ def get_spiff_task_from_process_instance(
|
|||
# where 7000 is the port the app is running on locally
|
||||
def github_webhook_receive(body: Dict) -> Response:
|
||||
"""Github_webhook_receive."""
|
||||
GitService.handle_web_hook(body)
|
||||
return Response(json.dumps({"ok": True}), status=200, mimetype="application/json")
|
||||
auth_header = request.headers.get("X-Hub-Signature-256")
|
||||
AuthorizationService.verify_sha256_token(auth_header)
|
||||
result = GitService.handle_web_hook(body)
|
||||
return Response(
|
||||
json.dumps({"git_pull": result}), status=200, mimetype="application/json"
|
||||
)
|
||||
|
||||
|
||||
#
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
"""Authorization_service."""
|
||||
import inspect
|
||||
import re
|
||||
from hashlib import sha256
|
||||
from hmac import compare_digest
|
||||
from hmac import HMAC
|
||||
from typing import Optional
|
||||
from typing import Union
|
||||
|
||||
|
@ -45,6 +48,27 @@ class UserDoesNotHaveAccessToTaskError(Exception):
|
|||
class AuthorizationService:
|
||||
"""Determine whether a user has permission to perform their request."""
|
||||
|
||||
# https://stackoverflow.com/a/71320673/6090676
|
||||
@classmethod
|
||||
def verify_sha256_token(cls, auth_header: Optional[str]) -> None:
|
||||
"""Verify_sha256_token."""
|
||||
if auth_header is None:
|
||||
raise ApiError(
|
||||
error_code="unauthorized",
|
||||
message="",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
received_sign = auth_header.split("sha256=")[-1].strip()
|
||||
secret = current_app.config["GITHUB_WEBHOOK_SECRET"].encode()
|
||||
expected_sign = HMAC(key=secret, msg=request.data, digestmod=sha256).hexdigest()
|
||||
if not compare_digest(received_sign, expected_sign):
|
||||
raise ApiError(
|
||||
error_code="unauthorized",
|
||||
message="",
|
||||
status_code=403,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def has_permission(
|
||||
cls, principals: list[PrincipalModel], permission: str, target_uri: str
|
||||
|
|
|
@ -140,7 +140,7 @@ class GitService:
|
|||
|
||||
# only supports github right now
|
||||
@classmethod
|
||||
def handle_web_hook(cls, webhook: dict) -> None:
|
||||
def handle_web_hook(cls, webhook: dict) -> bool:
|
||||
"""Handle_web_hook."""
|
||||
cls.check_for_configs()
|
||||
|
||||
|
@ -155,8 +155,25 @@ class GitService:
|
|||
f"Configured clone url does not match clone url from webhook: {clone_url}"
|
||||
)
|
||||
|
||||
if "ref" not in webhook:
|
||||
raise InvalidGitWebhookBodyError(
|
||||
f"Could not find the 'ref' arg in the webhook boy: {webhook}"
|
||||
)
|
||||
|
||||
if current_app.config["GIT_BRANCH"] is None:
|
||||
raise MissingGitConfigsError(
|
||||
"Missing config for GIT_BRANCH. "
|
||||
"This is required for updating the repository as a result of the webhook"
|
||||
)
|
||||
|
||||
ref = webhook["ref"]
|
||||
git_branch = current_app.config["GIT_BRANCH"]
|
||||
if ref != f"refs/heads/{git_branch}":
|
||||
return False
|
||||
|
||||
with FileSystemService.cd(current_app.config["BPMN_SPEC_ABSOLUTE_DIR"]):
|
||||
cls.run_shell_command(["git", "pull"])
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def publish(cls, process_model_id: str, branch_to_update: str) -> str:
|
||||
|
|
|
@ -9,7 +9,6 @@ import pytest
|
|||
from flask.app import Flask
|
||||
from flask.testing import FlaskClient
|
||||
from flask_bpmn.models.db import db
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
from tests.spiffworkflow_backend.helpers.base_test import BaseTest
|
||||
from tests.spiffworkflow_backend.helpers.test_data import load_test_spec
|
||||
|
||||
|
@ -33,6 +32,7 @@ from spiffworkflow_backend.models.spec_reference import SpecReferenceCache
|
|||
from spiffworkflow_backend.models.user import UserModel
|
||||
from spiffworkflow_backend.services.authorization_service import AuthorizationService
|
||||
from spiffworkflow_backend.services.file_system_service import FileSystemService
|
||||
from spiffworkflow_backend.services.git_service import GitService
|
||||
from spiffworkflow_backend.services.process_instance_processor import (
|
||||
ProcessInstanceProcessor,
|
||||
)
|
||||
|
@ -2573,7 +2573,8 @@ class TestProcessApi(BaseTest):
|
|||
assert "On branch main" in output
|
||||
assert "No commits yet" in output
|
||||
assert (
|
||||
'nothing to commit (create/copy files and use "git add" to track)' in output
|
||||
'nothing to commit (create/copy files and use "git add" to track)'
|
||||
in output
|
||||
)
|
||||
|
||||
process_group_id = "test_group"
|
||||
|
@ -2593,7 +2594,9 @@ class TestProcessApi(BaseTest):
|
|||
bpmn_file_name=bpmn_file_name,
|
||||
bpmn_file_location=bpmn_file_location,
|
||||
)
|
||||
process_model_absolute_dir = os.path.join(bpmn_root, process_model_identifier)
|
||||
process_model_absolute_dir = os.path.join(
|
||||
bpmn_root, process_model_identifier
|
||||
)
|
||||
|
||||
output = GitService.run_shell_command_to_get_stdout(["git", "status"])
|
||||
test_string = 'Untracked files:\n (use "git add <file>..." to include in what will be committed)\n\ttest_group'
|
||||
|
|
Loading…
Reference in New Issue