Skip to content

Commit

Permalink
Docs: remove IRC/ML/google.gropus remnants No-Issue
Browse files Browse the repository at this point in the history
No-Issue

ALLOW_LOCAL_RESOURCE_MANAGEMENT truthiness (ansible#2255)

Add fuzzy logic to ui/v2/users for ALLOW_LOCAL_RESOURCE_MANAGEMENT.

No-Issue

Signed-off-by: James Tanner <[email protected]>

Add CI upload junit xml test results (ansible#2257)

* upload junit xml test results
* run only in ansible repo
* upload inside the docker
No-Issue

Fix SonarCloud readability issues (ansible#2221)

No-Issue

Exclude vendored code from SonarCloud analysis (ansible#2264)

No-Issue

Mark more 2.5 tests (ansible#2262)

mark more 2.5 tests

No-Issue
  • Loading branch information
Andersson007 committed Sep 16, 2024
1 parent c72c28d commit a1bfb34
Show file tree
Hide file tree
Showing 26 changed files with 724 additions and 159 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/ci_full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,18 @@ jobs:
- name: run the unit test playbook
run: cd dev/playbooks; ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook -i 'localhost,' --forks=1 -v run_unit_tests.yaml

- name: upload jUnit XML test results
if: github.event_name == 'push' && github.repository == 'ansible/galaxy_ng' && github.ref_name == 'master'
continue-on-error: true
run: >-
docker exec pulp /bin/bash -c 'curl -v --user "${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_USER }}:${{ secrets.PDE_ORG_RESULTS_UPLOAD_PASSWORD }}"
--form "xunit_xml=@/tmp/galaxy_ng-test-results.xml"
--form "component_name=hub"
--form "git_commit_sha=${{ github.sha }}"
--form "git_repository_url=https://github.com/${{ github.repository }}"
"${{ vars.PDE_ORG_RESULTS_AGGREGATOR_UPLOAD_URL }}/api/results/upload/"'
# FIXME: do we really care about these anymore ... ?
#- name: run the functional test playbook
# run: cd dev/playbooks; ANSIBLE_STDOUT_CALLBACK=yaml ansible-playbook -i 'localhost,' --forks=1 -v run_functional_tests.yaml
5 changes: 3 additions & 2 deletions .sonarcloud.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
sonar.sources = galaxy_ng
sonar.exclusions = galaxy_ng/tests/**/*
sonar.exclusions = \
galaxy_ng/tests/**, \
galaxy_ng/_vendor/**

sonar.tests = galaxy_ng/tests

sonar.python.version = 3.11

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ View the latest version of the spec at https://galaxy.ansible.com/api/v3/swagger

* If you're interested in jumping in and helping out, [view the contributing guide](https://github.com/ansible/galaxy_ng/wiki#contributing-to-galaxyng).
* To setup your development environment, [view the development setup guide](https://github.com/ansible/galaxy_ng/wiki/Development-Setup).
* Chat with us on irc.libera.chat: #ansible-galaxy
* Reach out to us on the [Ansible Forum](https://forum.ansible.com/tag/galaxy-ng).
* Found a bug or have a feature idea? Please [open an issue](https://issues.redhat.com/projects/AAH/issues).

## Installation
Expand Down
1 change: 1 addition & 0 deletions dev/playbooks/files/run_units.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ PYTEST_FLAGS=""
PYTEST_FLAGS="$PYTEST_FLAGS --cov-report term-missing:skip-covered --cov=galaxy_ng"
PYTEST_FLAGS="$PYTEST_FLAGS -v -r sx --color=yes"
PYTEST_FLAGS="$PYTEST_FLAGS -p no:pulpcore"
PYTEST_FLAGS="$PYTEST_FLAGS --junit-xml=/tmp/galaxy_ng-test-results.xml"

# This command will run all unit tests in galaxy_ng/tests/unit.
# If you need to run a single test, include '-k <substring>' in the PYTEST_FLAGS variable
Expand Down
6 changes: 3 additions & 3 deletions docs/community/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ around https://galaxy.ansible.com.

### Galaxy

Galaxy launched in 2013 by the company later known as "Ansible". The [release announcement](https://groups.google.com/g/ansible-project/c/W40GgVxbU6U/m/uk1ruEdC-TAJ) gives an interesting perspective
of the original intent for the site that helps provide context for where we need the future of the galaxy_ng project to go.
Galaxy launched in 2013 by the company later known as "Ansible".

> What’s Galaxy? Ansible Galaxy is an automation content site designed from the ground up with an emphasis on being very dynamic — offering up a lot of new ways to find content.
Expand Down Expand Up @@ -50,7 +49,8 @@ We do not yet have a timeline for the migration or the cut over.

## Communication and Feedback.

The galaxy dev team, contributors and community can mostly be found on libera.chat's #ansible-galaxy irc channel.
The galaxy dev team, contributors and community can mostly be found on the [Ansible Forum](https://forum.ansible.com/tag/galaxy-ng).
See the [Ansible communication guide](https://docs.ansible.com/ansible/devel/community/communication.html) to learn more.

For bug reports and feature requests, see "Filing Issues".

Expand Down
2 changes: 1 addition & 1 deletion galaxy_ng/app/api/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def __init__(self, *args, **kwargs):
# This should only be included as a sub serializer and shouldn't be used for
# updating objects, so set read_only to true
kwargs['read_only'] = True
return super().__init__(*args, **kwargs)
super().__init__(*args, **kwargs)

def to_representation(self, instance):
result = OrderedDict()
Expand Down
2 changes: 0 additions & 2 deletions galaxy_ng/app/api/ui/v1/serializers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@
# distribution
'DistributionSerializer',
# container
'ContainerRepositorySerializer',
'ContainerRepositoryImageSerializer',
'ContainerRegistryRemoteSerializer',
'ContainerRemoteSerializer',
# Search
Expand Down
1 change: 0 additions & 1 deletion galaxy_ng/app/api/ui/v1/viewsets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,4 @@
'MyDistributionViewSet',
'ContainerRegistryRemoteViewSet',
'ContainerRemoteViewSet',
'ContainerTagViewset'
)
90 changes: 90 additions & 0 deletions galaxy_ng/app/api/ui/v2/permissions.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
from django.conf import settings
from rest_framework.permissions import BasePermission, SAFE_METHODS

from ansible_base.rbac.api.permissions import AnsibleBaseUserPermissions
from galaxy_ng.app.models.auth import User


class IsSuperUserOrReadOnly(BasePermission):
"""
Expand All @@ -16,3 +20,89 @@ def has_permission(self, request, view):
return True
# Otherwise, deny access
return False


class ComplexUserPermissions(AnsibleBaseUserPermissions):
"""
ComplexUserPermissions complies with the "complex" requirements
of a system where there is a resource server that syncs users
and a jwt that creates users and a confusing mix of how is_superuser
can get populated on galaxy when ALLOW_LOCAL_RESOURCE_MANAGEMENT
is False,
To try to break down the logic when ALLOW_LOCAL_RESOURCE_MANAGEMENT=False:
- users CAN NOT be created/edited/deleted directly in galaxy, except ...
- if the request is a PATCH or a PUT that is only modifying the value
of is_superuser, then it can be allowed
- if the caller is a superuser, they can set the is_superuser flag for
a user to True or False
- if the caller is the user being modified, they can only set the flag
to False
- No user can be demoted from superuser when they are the last superuser
Note: this is only designed to work for the _ui/v2/users/ viewset.
"""

def has_permission(self, request, view):
if (
request.user.is_superuser
and settings.get('ALLOW_LOCAL_RESOURCE_MANAGEMENT') is not False
):
return True

if (
request.method not in ('GET', 'HEAD', 'PUT', 'PATCH')
and settings.get('ALLOW_LOCAL_RESOURCE_MANAGEMENT') is False
):
return False

return super().has_permission(request, view)

def has_object_permission(self, request, view, obj):
if (
request.user.is_superuser
and settings.get('ALLOW_LOCAL_RESOURCE_MANAGEMENT') is not False
):
return True

# these can be modified ... kinda
allowed_fields = ['is_superuser']

# these are ignored in the serializer
ignored_fields = [
'groups',
'teams',
'organizations',
'date_joined',
'resource',
'auth_provider',
'model_permissions'
]

# compare new data vs current object data
for field, value in request.data.items():

if field in ignored_fields:
continue

if getattr(obj, field) == value:
continue

if field not in allowed_fields:
return False

# we can't allow the last superuser to get demoted
if request.data.get('is_superuser') is False:
if User.objects.filter(is_superuser=True).count() == 1 and obj.is_superuser:
return False

# superuser can set the value to True or False
if request.user.is_superuser:
return True

# user can set themself only to False
if request.user == obj:
if request.data.get('is_superuser') is False:
return True

return False
3 changes: 2 additions & 1 deletion galaxy_ng/app/api/ui/v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def get_organizations(self, obj):
return []


class UserCreateUpdateSerializer(UserDetailSerializer):
class UserCreateUpdateDeleteSerializer(UserDetailSerializer):

groups = serializers.ListField(
child=serializers.DictField(), required=False, default=[]
Expand Down Expand Up @@ -193,6 +193,7 @@ def update(self, instance, validated_data):
instance.first_name = validated_data.get('first_name', instance.first_name)
instance.last_name = validated_data.get('last_name', instance.last_name)
instance.email = validated_data.get('email', instance.email)
instance.is_superuser = validated_data.get('is_superuser', instance.is_superuser)

# If password is provided, update it securely
password = validated_data.get('password', None)
Expand Down
7 changes: 7 additions & 0 deletions galaxy_ng/app/api/ui/v2/urls.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.urls import include, path
from rest_framework.routers import DefaultRouter

from .views import CurrentUserViewSet
from .views import UserViewSet
from .views import GroupViewSet
from .views import OrganizationViewSet
Expand All @@ -19,5 +20,11 @@

urlpatterns = [
path('', include(router.urls)),
path(
'me/',
CurrentUserViewSet.as_view({'get': 'retrieve'}),
name='me'
),

]
urlpatterns.extend(dab_rbac_urls)
23 changes: 19 additions & 4 deletions galaxy_ng/app/api/ui/v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from rest_framework.response import Response
from rest_framework import status
from rest_framework.exceptions import ValidationError
from rest_framework import mixins
from rest_framework import views

from ansible_base.rest_pagination.default_paginator import DefaultPaginator
Expand All @@ -12,11 +13,12 @@
from .filters import OrganizationFilter
from .filters import TeamFilter
from .serializers import UserDetailSerializer
from .serializers import UserCreateUpdateSerializer
from .serializers import UserCreateUpdateDeleteSerializer
from .serializers import GroupSerializer
from .serializers import OrganizationSerializer
from .serializers import TeamSerializer
from .permissions import IsSuperUserOrReadOnly
from .permissions import ComplexUserPermissions

from galaxy_ng.app.models.auth import User
from galaxy_ng.app.models.auth import Group
Expand Down Expand Up @@ -45,17 +47,30 @@ class BaseViewSet(viewsets.ModelViewSet):
permission_classes = [IsSuperUserOrReadOnly]


class CurrentUserViewSet(
BaseViewSet,
mixins.RetrieveModelMixin,
):
serializer_class = UserDetailSerializer
model = User

def get_object(self):
return self.request.user


class UserViewSet(BaseViewSet):
queryset = User.objects.all().order_by('id')
filterset_class = UserViewFilter
permission_classes = [ComplexUserPermissions]
# permission_classes = [IsSuperUserOrReadOnly]

def get_serializer_class(self):
# FIXME - a single serializer for this viewset
# seems painful to implement.
if self.action in ['list', 'retrieve', 'destroy']:
if self.action in ['list', 'retrieve']:
return UserDetailSerializer
elif self.action in ['create', 'update', 'partial_update']:
return UserCreateUpdateSerializer
elif self.action in ['create', 'update', 'partial_update', 'destroy']:
return UserCreateUpdateDeleteSerializer
return super().get_serializer_class()

def create(self, request, *args, **kwargs):
Expand Down
20 changes: 9 additions & 11 deletions galaxy_ng/app/api/v1/viewsets/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

from .roles import (
LegacyRolesViewSet,
# LegacyRoleViewSet,
LegacyRoleContentViewSet,
LegacyRoleVersionsViewSet,
LegacyRoleImportsViewSet
Expand All @@ -22,14 +21,13 @@


__all__ = (
LegacyNamespacesViewSet,
LegacyNamespaceOwnersViewSet,
LegacyNamespaceProvidersViewSet,
LegacyUsersViewSet,
LegacyRolesViewSet,
LegacyRolesSyncViewSet,
# LegacyRoleViewSet,
LegacyRoleContentViewSet,
LegacyRoleVersionsViewSet,
LegacyRoleImportsViewSet,
"LegacyNamespacesViewSet",
"LegacyNamespaceOwnersViewSet",
"LegacyNamespaceProvidersViewSet",
"LegacyUsersViewSet",
"LegacyRolesViewSet",
"LegacyRolesSyncViewSet",
"LegacyRoleContentViewSet",
"LegacyRoleVersionsViewSet",
"LegacyRoleImportsViewSet",
)
Loading

0 comments on commit a1bfb34

Please sign in to comment.