Skip to content

Commit dbd45ed

Browse files
author
Ben Elam
committed
Fix bug and linting issues
1 parent 3bbe13b commit dbd45ed

File tree

6 files changed

+49
-34
lines changed

6 files changed

+49
-34
lines changed

orchestrator/api/api_v1/endpoints/processes.py

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,27 +101,27 @@ def get_auth_callbacks(pstat: ProcessStat) -> tuple[Authorizer | None, Authorize
101101
# Default to workflow start callbacks
102102
auth_resume = pstat.workflow.authorize_callback
103103
# Retry defaults to the workflow start callback if not otherwise specified
104-
auth_retry = pstat.workflow.retry_auth_callback if pstat.workflow.retry_auth_callback else auth_resume
104+
auth_retry = pstat.workflow.retry_auth_callback if pstat.workflow.retry_auth_callback is not None else auth_resume
105105
# Iterate over previous steps to look for policy changes
106106
remaining_steps = pstat.log
107-
past_steps = pstat.workflow.steps[:-len(remaining_steps)]
107+
past_steps = pstat.workflow.steps[: -len(remaining_steps)]
108108
# Review last steps and current step
109109
for step in past_steps + [pstat.log[0]]:
110110
if step.resume_auth_callback and step.retry_auth_callback is None:
111111
# Set both to authorize_callback
112112
auth_resume = step.resume_auth_callback
113113
auth_retry = step.resume_auth_callback
114114
continue
115-
elif step.resume_auth_callback and step.retry_auth_callback:
115+
if step.resume_auth_callback and step.retry_auth_callback:
116116
auth_resume = step.resume_auth_callback
117117
auth_retry = step.retry_auth_callback
118118
continue
119-
elif step.resume_auth_callback is None and step.retry_auth_callback:
119+
if step.resume_auth_callback is None and step.retry_auth_callback:
120120
# Only update retry
121121
auth_retry = step.retry_auth_callback
122122
continue
123-
else: # Both None
124-
continue
123+
# Both None
124+
continue
125125
return auth_resume, auth_retry
126126

127127

@@ -209,13 +209,12 @@ def resume_process_endpoint(
209209
pstat = load_process(process)
210210
auth_resume, auth_retry = get_auth_callbacks(pstat)
211211
if process.last_status == ProcessStatus.SUSPENDED:
212-
if not auth_resume(user_model):
212+
if auth_resume is not None and not auth_resume(user_model):
213213
raise_status(HTTPStatus.FORBIDDEN, "User is not authorized to resume step")
214214
elif process.last_status == ProcessStatus.FAILED:
215-
if not auth_retry(user_model):
215+
if auth_retry is not None and not auth_retry(user_model):
216216
raise_status(HTTPStatus.FORBIDDEN, "User is not authorized to retry step")
217217

218-
219218
broadcast_invalidate_status_counts()
220219
broadcast_func = api_broadcast_process_data(request)
221220

orchestrator/services/celery.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
import structlog
1919
from celery.result import AsyncResult
2020
from kombu.exceptions import ConnectionError, OperationalError
21-
from oauth2_lib.fastapi import OIDCUserModel
2221

22+
from oauth2_lib.fastapi import OIDCUserModel
2323
from orchestrator import app_settings
2424
from orchestrator.api.error_handling import raise_status
2525
from orchestrator.db import ProcessTable, db
@@ -47,7 +47,7 @@ def _celery_start_process(
4747
user_inputs: list[State] | None,
4848
user: str = SYSTEM_USER,
4949
user_model: OIDCUserModel | None = None,
50-
**kwargs: Any
50+
**kwargs: Any,
5151
) -> UUID:
5252
"""Client side call of Celery."""
5353
from orchestrator.services.tasks import NEW_TASK, NEW_WORKFLOW, get_celery_task

orchestrator/services/processes.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
from orchestrator.workflow import (
4343
CALLBACK_TOKEN_KEY,
4444
DEFAULT_CALLBACK_PROGRESS_KEY,
45-
Authorizer,
4645
Failed,
4746
ProcessStat,
4847
ProcessStatus,
@@ -575,7 +574,7 @@ def resume_process(
575574
raise
576575

577576
resume_func = get_execution_context()["resume"]
578-
return resume_func(process, user_inputs=user_inputs, user=user, user_model=user_model, broadcast_func=broadcast_func)
577+
return resume_func(process, user_inputs=user_inputs, user=user, broadcast_func=broadcast_func)
579578

580579

581580
def ensure_correct_callback_token(pstat: ProcessStat, *, token: str) -> None:

orchestrator/workflow.py

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,19 @@
1313

1414

1515
from __future__ import annotations
16+
1617
import contextvars
1718
import functools
1819
import inspect
1920
import secrets
2021
from collections.abc import Callable
2122
from dataclasses import asdict, dataclass
22-
from functools import update_wrapper
23-
from http import HTTPStatus
2423
from itertools import dropwhile
2524
from typing import (
2625
Any,
2726
Generic,
2827
NoReturn,
2928
Protocol,
30-
TypeAlias,
3129
TypeVar,
3230
cast,
3331
overload,
@@ -42,7 +40,6 @@
4240

4341
from nwastdlib import const, identity
4442
from oauth2_lib.fastapi import OIDCUserModel
45-
from orchestrator.api.error_handling import raise_status
4643
from orchestrator.config.assignee import Assignee
4744
from orchestrator.db import db, transactional
4845
from orchestrator.services.settings import get_engine_settings
@@ -181,7 +178,7 @@ def __repr__(self) -> str:
181178

182179

183180
def _handle_simple_input_form_generator(f: StateInputStepFunc) -> StateInputFormGenerator:
184-
"""Processes f into a form generator and injects a pre-hook for user authorization"""
181+
"""Processes f into a form generator and injects a pre-hook for user authorization."""
185182
if inspect.isgeneratorfunction(f):
186183
return cast(StateInputFormGenerator, f)
187184
if inspect.isgenerator(f):
@@ -219,7 +216,9 @@ def wrapping_function() -> NoReturn:
219216
wrapping_function.description = description
220217
wrapping_function.authorize_callback = allow if authorize_callback is None else authorize_callback
221218
# If no retry auth policy is given, defer to policy for process creation.
222-
wrapping_function.retry_auth_callback = wrapping_function.authorize_callback if retry_auth_callback is None else retry_auth_callback
219+
wrapping_function.retry_auth_callback = (
220+
wrapping_function.authorize_callback if retry_auth_callback is None else retry_auth_callback
221+
)
223222

224223
if initial_input_form is None:
225224
# We always need a form to prevent starting a workflow when no input is needed.
@@ -288,9 +287,16 @@ def wrapper(state: State) -> Process:
288287
return decorator
289288

290289

291-
def inputstep(name: str, assignee: Assignee, resume_auth_callback: Authorizer | None = None, retry_auth_callback: Authorizer | None = None) -> Callable[[InputStepFunc], Step]:
290+
def inputstep(
291+
name: str,
292+
assignee: Assignee,
293+
resume_auth_callback: Authorizer | None = None,
294+
retry_auth_callback: Authorizer | None = None,
295+
) -> Callable[[InputStepFunc], Step]:
292296
"""Add user input step to workflow.
293297
298+
Any authorization callbacks will be attached to the resulting Step.
299+
294300
IMPORTANT: In contrast to other workflow steps, the `@inputstep` wrapped function will not run in the
295301
workflow engine! This means that it must be free of side effects!
296302
@@ -317,7 +323,14 @@ def wrapper(state: State) -> FormGenerator:
317323
def suspend(state: State) -> Process:
318324
return Suspend(state)
319325

320-
return make_step_function(suspend, name, wrapper, assignee, resume_auth_callback=resume_auth_callback, retry_auth_callback=retry_auth_callback)
326+
return make_step_function(
327+
suspend,
328+
name,
329+
wrapper,
330+
assignee,
331+
resume_auth_callback=resume_auth_callback,
332+
retry_auth_callback=retry_auth_callback,
333+
)
321334

322335
return decorator
323336

@@ -497,8 +510,8 @@ def workflow(
497510
description: str,
498511
initial_input_form: InputStepFunc | None = None,
499512
target: Target = Target.SYSTEM,
500-
authorize_callback: Authorizer| None = None,
501-
retry_auth_callback: Authorizer| None = None,
513+
authorize_callback: Authorizer | None = None,
514+
retry_auth_callback: Authorizer | None = None,
502515
) -> Callable[[Callable[[], StepList]], Workflow]:
503516
"""Transform an initial_input_form and a step list into a workflow.
504517
@@ -519,7 +532,13 @@ def create_service_port():
519532

520533
def _workflow(f: Callable[[], StepList]) -> Workflow:
521534
return make_workflow(
522-
f, description, initial_input_form_in_form_inject_args, target, f(), authorize_callback=authorize_callback, retry_auth_callback=retry_auth_callback
535+
f,
536+
description,
537+
initial_input_form_in_form_inject_args,
538+
target,
539+
f(),
540+
authorize_callback=authorize_callback,
541+
retry_auth_callback=retry_auth_callback,
523542
)
524543

525544
return _workflow

orchestrator/workflows/utils.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
from pydantic import field_validator, model_validator
2121
from sqlalchemy import select
2222

23-
from oauth2_lib.fastapi import OIDCUserModel
2423
from orchestrator.db import ProductTable, SubscriptionTable, db
2524
from orchestrator.forms.validators import ProductId
2625
from orchestrator.services import subscriptions
@@ -242,7 +241,7 @@ def _create_workflow(f: Callable[[], StepList]) -> Workflow:
242241
Target.CREATE,
243242
steplist,
244243
authorize_callback=authorize_callback,
245-
retry_auth_callback=retry_auth_callback
244+
retry_auth_callback=retry_auth_callback,
246245
)
247246

248247
return _create_workflow

test/unit_tests/api/test_processes.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
from uuid import uuid4
77

88
import pytest
9-
from pydantic_forms.core import FormPage
10-
from pydantic_forms.types import State
119
from sqlalchemy import select
1210

1311
from oauth2_lib.fastapi import OIDCUserModel
@@ -25,6 +23,7 @@
2523
from orchestrator.settings import app_settings
2624
from orchestrator.targets import Target
2725
from orchestrator.workflow import ProcessStatus, done, init, inputstep, step, workflow
26+
from pydantic_forms.core import FormPage
2827
from test.unit_tests.helpers import URL_STR_TYPE
2928
from test.unit_tests.workflows import WorkflowInstanceForTests
3029

@@ -600,25 +599,25 @@ def unauthorized_workflow():
600599
def test_inputstep_authorization(test_client):
601600
def disallow(_: OIDCUserModel | None = None) -> bool:
602601
return False
603-
602+
604603
def allow(_: OIDCUserModel | None = None) -> bool:
605604
return True
606605

607606
class ConfirmForm(FormPage):
608607
confirm: bool
609608

610609
@inputstep("unauthorized_resume", assignee=Assignee.SYSTEM, resume_auth_callback=disallow)
611-
def unauthorized_resume(state: State) -> State:
610+
def unauthorized_resume(state):
612611
user_input = yield ConfirmForm
613612
return user_input.model_dump()
614613

615614
@inputstep("authorized_resume", assignee=Assignee.SYSTEM, resume_auth_callback=allow)
616-
def authorized_resume(state: State) -> State:
615+
def authorized_resume(state):
617616
user_input = yield ConfirmForm
618617
return user_input.model_dump()
619618

620619
@inputstep("noauth_resume", assignee=Assignee.SYSTEM)
621-
def noauth_resume(state: State) -> State:
620+
def noauth_resume(state):
622621
user_input = yield ConfirmForm
623622
return user_input.model_dump()
624623

@@ -640,5 +639,5 @@ def test_auth_workflow():
640639
response = test_client.put(f"/api/processes/{process_id}/resume", json=[{"confirm": True}])
641640
assert HTTPStatus.FORBIDDEN == response.status_code
642641

643-
#TODO test how this interacts with passing a different callback to @authorize_workflow
644-
# These should be as functionally independent as possible.
642+
# TODO test how this interacts with passing a different callback to @authorize_workflow
643+
# These should be as functionally independent as possible.

0 commit comments

Comments
 (0)