Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add job access checks for model invocations #5392

Merged
merged 19 commits into from
Dec 5, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ non-ascii paths while adding files from "Connected file share" (issue #4428)
- Fixed FBRS serverless function runtime error on images with alpha channel (<https://github.com/opencv/cvat/pull/5384>)
- Attaching manifest with custom name (<https://github.com/opencv/cvat/pull/5377>)
- Uploading non-zip annotaion files (<https://github.com/opencv/cvat/pull/5386>)
- A permission problem with interactive model launches for workers in orgs (<https://github.com/opencv/cvat/issues/4996>)

### Security
- TDB
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,8 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
try {
// run server request
this.setState({ fetching: true });
const response = await core.lambda.call(jobInstance.taskId, interactor, data);
const response = await core.lambda.call(jobInstance.taskId, interactor,
{ ...data, job: jobInstance.id });

// approximation with cv.approxPolyDP
const approximated = await this.approximateResponsePoints(response.points);
Expand Down Expand Up @@ -740,6 +741,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
const response = await core.lambda.call(jobInstance.taskId, tracker, {
frame: frame - 1,
shapes: trackableObjects.shapes,
job: jobInstance.id,
});

const { states: serverlessStates } = response;
Expand Down Expand Up @@ -787,6 +789,7 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
frame,
shapes: trackableObjects.shapes,
states: trackableObjects.states,
job: jobInstance.id,
});

response.shapes = response.shapes.map(trackedRectangleMapper);
Expand Down Expand Up @@ -1161,7 +1164,9 @@ export class ToolsControlComponent extends React.PureComponent<Props, State> {
runInference={async (model: Model, body: DetectorRequestBody) => {
try {
this.setState({ mode: 'detection', fetching: true });
const result = await core.lambda.call(jobInstance.taskId, model, { ...body, frame });
const result = await core.lambda.call(jobInstance.taskId, model, {
...body, frame, job: jobInstance.id,
});
const states = result.map(
(data: any): any => {
const jobLabel = (jobInstance.labels as Label[])
Expand Down
8 changes: 8 additions & 0 deletions cvat/apps/engine/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,9 @@ class Segment(models.Model):
start_frame = models.IntegerField()
stop_frame = models.IntegerField()

def contains_frame(self, idx: int) -> bool:
return self.start_frame <= idx and idx <= self.stop_frame

class Meta:
default_permissions = ()

Expand All @@ -472,6 +475,11 @@ def get_project_id(self):
project = self.segment.task.project
return project.id if project else None

@extend_schema_field(OpenApiTypes.INT)
def get_task_id(self):
task = self.segment.task
return task.id if task else None

def get_organization_id(self):
return self.segment.task.organization

Expand Down
22 changes: 18 additions & 4 deletions cvat/apps/iam/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,14 +365,20 @@ class LambdaPermission(OpenPolicyAgentPermission):
def create(cls, request, view, obj):
permissions = []
if view.basename == 'function' or view.basename == 'request':
for scope in cls.get_scopes(request, view, obj):
scopes = cls.get_scopes(request, view, obj)
for scope in scopes:
self = cls.create_base_perm(request, view, scope, obj)
permissions.append(self)

task_id = request.data.get('task')
if task_id:
perm = TaskPermission.create_scope_view_data(request, task_id)
job_id = request.data.get('job')
if job_id:
perm = JobPermission.create_scope_view_data(request, job_id)
permissions.append(perm)
else:
task_id = request.data.get('task')
if task_id:
perm = TaskPermission.create_scope_view_data(request, task_id)
permissions.append(perm)
SpecLad marked this conversation as resolved.
Show resolved Hide resolved

return permissions

Expand Down Expand Up @@ -879,6 +885,14 @@ def create(cls, request, view, obj):

return permissions

@classmethod
def create_scope_view_data(cls, request, job_id):
try:
obj = Job.objects.get(id=job_id)
except Job.DoesNotExist as ex:
raise ValidationError(str(ex))

Check warning

Code scanning / CodeQL

Information exposure through an exception

[Stack trace information](1) flows to this location and may be exposed to an external user.
return cls(**cls.unpack_context(request), obj=obj, scope='view:data')

def __init__(self, **kwargs):
super().__init__(**kwargs)
self.url = settings.IAM_OPA_DATA_URL + '/jobs/allow'
Expand Down
Loading