Skip to content

Commit

Permalink
fixing django lint
Browse files Browse the repository at this point in the history
  • Loading branch information
ansibleguy committed Feb 12, 2024
1 parent 1f943ee commit 7eb0182
Show file tree
Hide file tree
Showing 33 changed files with 194 additions and 158 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ jobs:
- name: Running PyLint
run: |
pylint --version
pylint --recursive=y .
pylint --recursive=y --load-plugins pylint_django --django-settings-module=aw.settings .
- name: Running YamlLint
run: |
Expand Down
2 changes: 2 additions & 0 deletions docs/source/usage/2_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
.. |cnf_admin| image:: ../_static/img/config_admin.png
:class: wiki-img

.. |cnf_jobs| image:: ../_static/img/config_jobs.png
:class: wiki-img

==========
2 - Config
Expand Down
2 changes: 1 addition & 1 deletion docs/source/usage/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ API

This project has a API first development approach!

To use the API you have to create an API key: `ui/settings/api_keys <http://localhost:8000/ui/settings/api_keys>`_
To use the API you have to create an API key. You can use the UI at :code:`Settings - API Keys` to do so.


Examples
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
.. |perm_overview| image:: ../_static/img/permission_overview.svg
:class: wiki-img

===========
Permissions
===========
==========
Privileges
==========

You can set job-permissions to limit user actions.

Expand All @@ -24,20 +24,20 @@ Users & Groups

The :code:`System - Admin - Users/Groups` admin-page allows you to create new users and manage group memberships.

To allow a user to create jobs and permissions you need to activate the :code:`Staff status`.
To allow a user to create jobs, permissions and global-credentials you need to activate the :code:`Staff status`.

|perm_users_groups|

----

Job permissions
***************
Permissions
***********

The UI at :code:`Settings - Permissions` allows you to create job permissions and link them to users and groups.
The UI at :code:`Settings - Permissions` allows you to create job & credential permissions and link them to users and groups.

|perm_ui|

Each job can have multiple permissions linked to it.
Each job & credential can have multiple permissions linked to it.

**Permission types:**

Expand Down
1 change: 1 addition & 0 deletions requirements_lint.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pylint
pylint-django
yamllint
2 changes: 1 addition & 1 deletion scripts/lint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ echo ''
echo 'LINTING Python'
echo ''

pylint --recursive=y .
pylint --recursive=y --load-plugins pylint_django --django-settings-module=aw.settings .

echo ''
echo 'LINTING YAML'
Expand Down
8 changes: 4 additions & 4 deletions src/ansible-webui/aw/api_endpoints/base.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from rest_framework.permissions import IsAuthenticated
from rest_framework_api_key.permissions import BaseHasAPIKey

from aw.model.api import AwAPIKey
from aw.base import USERS, GROUPS


class HasAwAPIKey(BaseHasAPIKey):
Expand All @@ -17,7 +17,7 @@ class HasAwAPIKey(BaseHasAPIKey):


# see: rest_framework_api_key.permissions.BaseHasAPIKey:get_from_header
def get_api_user(request) -> settings.AUTH_USER_MODEL:
def get_api_user(request) -> USERS:
if isinstance(request.user, AnonymousUser):
try:
return AwAPIKey.objects.get_from_key(
Expand Down Expand Up @@ -45,9 +45,9 @@ class GenericResponse(BaseResponse):

class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
model = GROUPS


class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
model = USERS
7 changes: 2 additions & 5 deletions src/ansible-webui/aw/api_endpoints/credentials.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.db.utils import IntegrityError
from rest_framework.views import APIView
Expand All @@ -11,6 +10,7 @@
from aw.api_endpoints.base import API_PERMISSION, get_api_user, GenericResponse, BaseResponse
from aw.utils.permission import has_credentials_permission
from aw.utils.util import is_null
from aw.base import USERS


class JobGlobalCredentialsReadResponse(serializers.ModelSerializer):
Expand Down Expand Up @@ -61,9 +61,8 @@ def are_global_credentials(request) -> bool:


def _find_credentials(
credentials_id: int, are_global: bool, user: settings.AUTH_USER_MODEL
credentials_id: int, are_global: bool, user: USERS
) -> (BaseJobCredentials, None):
# pylint: disable=E1101
try:
if are_global:
return JobGlobalCredentials.objects.get(id=credentials_id)
Expand Down Expand Up @@ -108,7 +107,6 @@ class APIJobCredentials(APIView):
operation_id='credentials_list',
)
def get(self, request):
# pylint: disable=E1101
user = get_api_user(request)
credentials_global = []
credentials_global_raw = JobGlobalCredentials.objects.all()
Expand Down Expand Up @@ -333,7 +331,6 @@ def put(self, request, credentials_id: int):
status=400,
)

# pylint: disable=E1101
try:
# not working with password properties: 'Job.objects.filter(id=job_id).update(**serializer.data)'
for field, value in serializer.data.items():
Expand Down
55 changes: 35 additions & 20 deletions src/ansible-webui/aw/api_endpoints/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,24 @@
from aw.model.job import Job, JobExecution
from aw.model.job_permission import CHOICE_PERMISSION_READ, CHOICE_PERMISSION_EXECUTE, \
CHOICE_PERMISSION_WRITE, CHOICE_PERMISSION_FULL
from aw.model.job_credential import JobGlobalCredentials
from aw.api_endpoints.base import API_PERMISSION, get_api_user, BaseResponse, GenericResponse
from aw.api_endpoints.job_util import get_viewable_jobs_serialized, JobReadResponse, get_job_executions_serialized, \
JobExecutionReadResponse, get_viewable_jobs, get_job_execution_serialized
from aw.utils.permission import has_job_permission
from aw.utils.permission import has_job_permission, has_credentials_permission
from aw.execute.queue import queue_add
from aw.execute.util import update_execution_status, is_execution_status
from aw.utils.util import is_set
from aw.base import USERS


class JobWriteRequest(serializers.ModelSerializer):
class Meta:
model = Job
fields = Job.api_fields_write

# vault_pass = serializers.CharField(max_length=100, required=False, default=None)
# become_pass = serializers.CharField(max_length=100, required=False, default=None)
# connect_pass = serializers.CharField(max_length=100, required=False, default=None)


def _find_job(job_id: int) -> (Job, None):
# pylint: disable=E1101
try:
return Job.objects.get(id=job_id)

Expand All @@ -38,7 +36,6 @@ def _find_job(job_id: int) -> (Job, None):


def _find_job_and_execution(job_id: int, exec_id: int) -> tuple[Job, (JobExecution, None)]:
# pylint: disable=E1101
job = _find_job(job_id)
try:
return job, JobExecution.objects.get(id=exec_id, job=job)
Expand Down Expand Up @@ -68,6 +65,21 @@ def _want_job_executions(request) -> tuple:
return False, max_count


def _has_credentials_permission(user: USERS, data: dict) -> bool:
if 'credentials_default' in data and is_set(data['credentials_default']):
try:
return has_credentials_permission(
user=user,
credentials=JobGlobalCredentials.objects.get(id=data['credentials_default']),
permission_needed=CHOICE_PERMISSION_READ,
)

except ObjectDoesNotExist:
pass

return True


class APIJob(APIView):
http_method_names = ['post', 'get']
serializer_class = JobReadResponse
Expand Down Expand Up @@ -118,7 +130,8 @@ def get(request):
operation_id='job_create'
)
def post(self, request):
if not get_api_user(request).is_staff:
user = get_api_user(request)
if not user.is_staff:
return Response(data={'msg': 'Not privileged to create jobs'}, status=403)

serializer = JobWriteRequest(data=request.data)
Expand All @@ -129,6 +142,12 @@ def post(self, request):
status=400,
)

if not _has_credentials_permission(user=user, data=serializer.validated_data):
return Response(
data={'msg': "Not privileged to use provided credentials"},
status=403,
)

try:
serializer.save()

Expand Down Expand Up @@ -240,17 +259,14 @@ def put(self, request, job_id: int):
status=400,
)

# pylint: disable=E1101
try:
# not working with password properties: 'Job.objects.filter(id=job_id).update(**serializer.data)'
for field, value in serializer.data.items():
# if field in BaseJobCredentials.SECRET_ATTRS and \
# (is_null(value) or value == BaseJobCredentials.SECRET_HIDDEN):
# value = getattr(job, field)

setattr(job, field, value)
if not _has_credentials_permission(user=user, data=serializer.validated_data):
return Response(
data={'msg': "Not privileged to use provided credentials"},
status=403,
)

job.save()
try:
Job.objects.filter(id=job_id).update(**serializer.data)

except IntegrityError as err:
return Response(
Expand Down Expand Up @@ -451,14 +467,13 @@ class APIJobExecution(APIView):
],
)
def get(self, request):
# pylint: disable=E1101
jobs = get_viewable_jobs(get_api_user(request))
exec_count = _job_execution_count(request)
if exec_count is None:
exec_count = JOB_EXECUTION_LIMIT

serialized = []
for execution in JobExecution.objects.filter(job__in=jobs).order_by('updated')[:exec_count]:
for execution in JobExecution.objects.filter(job__in=jobs).order_by('-updated')[:exec_count]:
serialized.append(get_job_execution_serialized(execution))

return Response(data=serialized, status=200)
7 changes: 3 additions & 4 deletions src/ansible-webui/aw/api_endpoints/job_util.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from django.conf import settings
from rest_framework import serializers

from aw.config.hardcoded import SHORT_TIME_FORMAT, JOB_EXECUTION_LIMIT
from aw.model.job import Job, CHOICES_JOB_EXEC_STATUS, JobExecution
from aw.utils.permission import get_viewable_jobs
from aw.utils.util import datetime_from_db, get_next_cron_execution_str
from aw.base import USERS


class JobReadResponse(serializers.ModelSerializer):
Expand Down Expand Up @@ -36,14 +36,14 @@ class Meta:


def get_job_execution_serialized(execution: JobExecution) -> dict:
# pylint: disable=E1101
serialized = {
'id': execution.id,
'job': execution.job.id,
'job_name': execution.job.name,
'job_comment': execution.job.comment,
'user': execution.user.id if execution.user is not None else None,
'user_name': execution.user.username if execution.user is not None else 'Scheduled',
'command': execution.command,
'status': execution.status,
'status_name': CHOICES_JOB_EXEC_STATUS[execution.status][1],
'time_start': datetime_from_db(execution.created).strftime(SHORT_TIME_FORMAT),
Expand All @@ -67,7 +67,6 @@ def get_job_execution_serialized(execution: JobExecution) -> dict:


def get_job_executions_serialized(job: Job, execution_count: int = JOB_EXECUTION_LIMIT) -> list[dict]:
# pylint: disable=E1101
serialized = []
for execution in JobExecution.objects.filter(job=job).order_by('-updated')[:execution_count]:
serialized.append(get_job_execution_serialized(execution))
Expand All @@ -76,7 +75,7 @@ def get_job_executions_serialized(job: Job, execution_count: int = JOB_EXECUTION


def get_viewable_jobs_serialized(
user: settings.AUTH_USER_MODEL, executions: bool = False,
user: USERS, executions: bool = False,
execution_count: int = None
) -> list[dict]:
serialized = []
Expand Down
16 changes: 6 additions & 10 deletions src/ansible-webui/aw/api_endpoints/permission.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from django.conf import settings
from django.contrib.auth.models import User, Group
from django.core.exceptions import ObjectDoesNotExist
from django.db.utils import IntegrityError
from rest_framework.generics import GenericAPIView
Expand All @@ -14,8 +12,7 @@
from aw.api_endpoints.base import API_PERMISSION, GenericResponse, get_api_user
from aw.utils.permission import get_permission_name
from aw.utils.util import is_set

# pylint: disable=E1101
from aw.base import USERS, GROUPS


class PermissionReadResponse(serializers.ModelSerializer):
Expand Down Expand Up @@ -48,14 +45,13 @@ class Meta:
groups = serializers.MultipleChoiceField(allow_blank=True, choices=[])

def __init__(self, *args, **kwargs):
# pylint: disable=E1101
super().__init__(*args, **kwargs)
self.fields['jobs'] = serializers.MultipleChoiceField(choices=[job.id for job in Job.objects.all()])
self.fields['credentials'] = serializers.MultipleChoiceField(
choices=[creds.id for creds in JobGlobalCredentials.objects.all()]
)
self.fields['users'] = serializers.MultipleChoiceField(choices=[user.id for user in User.objects.all()])
self.fields['groups'] = serializers.MultipleChoiceField(choices=[group.id for group in Group.objects.all()])
self.fields['users'] = serializers.MultipleChoiceField(choices=[user.id for user in USERS.objects.all()])
self.fields['groups'] = serializers.MultipleChoiceField(choices=[group.id for group in GROUPS.objects.all()])

@staticmethod
def create_or_update(validated_data: dict, perm: JobPermission = None):
Expand Down Expand Up @@ -98,7 +94,7 @@ def create_or_update(validated_data: dict, perm: JobPermission = None):
users = []
for user_id in validated_data['users']:
try:
users.append(User.objects.get(id=user_id))
users.append(USERS.objects.get(id=user_id))

except ObjectDoesNotExist:
continue
Expand All @@ -109,7 +105,7 @@ def create_or_update(validated_data: dict, perm: JobPermission = None):
groups = []
for group_id in validated_data['groups']:
try:
groups.append(Group.objects.get(id=group_id))
groups.append(GROUPS.objects.get(id=group_id))

except ObjectDoesNotExist:
continue
Expand Down Expand Up @@ -178,7 +174,7 @@ def build_permissions(perm_id_filter: int = None) -> (list, dict):
return permissions


def has_permission_privileges(user: settings.AUTH_USER_MODEL) -> bool:
def has_permission_privileges(user: USERS) -> bool:
# todo: create explicit privilege
return user.is_staff

Expand Down
5 changes: 5 additions & 0 deletions src/ansible-webui/aw/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from django.conf import settings
from django.contrib.auth.models import Group

USERS = settings.AUTH_USER_MODEL
GROUPS = Group
Loading

0 comments on commit 7eb0182

Please sign in to comment.