From ec2bf4476de241891c59e820c2433dbf0074b1cb Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Thu, 14 Jul 2016 11:16:16 -0400 Subject: [PATCH 01/21] ensure system admin/auditor can see orphan inventory scripts --- awx/api/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 2f58b776f4..bbbbabdb5d 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -1270,7 +1270,9 @@ class CustomInventoryScriptSerializer(BaseSerializer): if obj is None: return ret request = self.context.get('request', None) - if request.user not in obj.admin_role: + if request.user not in obj.admin_role and \ + not request.user.is_superuser and \ + not request.user.is_system_auditor: ret['script'] = None return ret From 2876bb169b26f7ffaa9d6f50eef72ece9084696b Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 15:49:24 -0400 Subject: [PATCH 02/21] switch order in migration --- awx/main/migrations/0026_v300_credential_unique.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/main/migrations/0026_v300_credential_unique.py b/awx/main/migrations/0026_v300_credential_unique.py index b354ce3d62..3c1d714327 100644 --- a/awx/main/migrations/0026_v300_credential_unique.py +++ b/awx/main/migrations/0026_v300_credential_unique.py @@ -20,7 +20,7 @@ class Migration(migrations.Migration): migrations.AlterField( model_name='credential', name='read_role', - field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'use_role', b'admin_role', b'organization.auditor_role'], to='main.Role', null=b'True'), + field=awx.main.fields.ImplicitRoleField(related_name='+', parent_role=[b'singleton:system_auditor', b'organization.auditor_role', b'use_role', b'admin_role'], to='main.Role', null=b'True'), ), migrations.RunPython(migration_utils.set_current_apps_for_migrations), migrations.RunPython(rbac.rebuild_role_hierarchy), From df940f811c86b231e6ba35debafcf3d967d6684a Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 14 Jul 2016 16:11:29 -0400 Subject: [PATCH 03/21] add read_role to organization select_related --- awx/api/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/api/views.py b/awx/api/views.py index 64ea980f66..cd9f96364f 100644 --- a/awx/api/views.py +++ b/awx/api/views.py @@ -653,7 +653,7 @@ class OrganizationList(OrganizationCountsMixin, ListCreateAPIView): def get_queryset(self): qs = Organization.accessible_objects(self.request.user, 'read_role') - qs = qs.select_related('admin_role', 'auditor_role', 'member_role') + qs = qs.select_related('admin_role', 'auditor_role', 'member_role', 'read_role') return qs def create(self, request, *args, **kwargs): From 73722ffb77d8554fd3742fef3d918f7b920e6aec Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Thu, 14 Jul 2016 23:08:02 -0400 Subject: [PATCH 04/21] resolves kickback on #2980 (#3008) --- awx/ui/client/src/helpers/JobDetail.js | 4 ++-- .../src/job-detail/host-events/host-events.controller.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/awx/ui/client/src/helpers/JobDetail.js b/awx/ui/client/src/helpers/JobDetail.js index dde9264109..3b7dcca1ce 100644 --- a/awx/ui/client/src/helpers/JobDetail.js +++ b/awx/ui/client/src/helpers/JobDetail.js @@ -687,7 +687,7 @@ export default scope.plays = []; url = scope.job.url + 'job_plays/?page_size=' + scope.playsMaxRows + '&order=id'; - url += (scope.search_play_name) ? '&play__icontains=' + scope.search_play_name : ''; + url += (scope.search_play_name) ? '&play__icontains=' + encodeURIComponent(scope.search_play_name) : ''; url += (scope.search_play_status === 'failed') ? '&failed=true' : ''; scope.playsLoading = true; Rest.setUrl(url); @@ -786,7 +786,7 @@ export default scope.tasks = []; if (scope.selectedPlay) { url = scope.job.url + 'job_tasks/?event_id=' + scope.selectedPlay; - url += (scope.search_task_name) ? '&task__icontains=' + scope.search_task_name : ''; + url += (scope.search_task_name) ? '&task__icontains=' + encodeURIComponent(scope.search_task_name) : ''; url += (scope.search_task_status === 'failed') ? '&failed=true' : ''; url += '&page_size=' + scope.tasksMaxRows + '&order=id'; scope.plays.every(function(p, idx) { diff --git a/awx/ui/client/src/job-detail/host-events/host-events.controller.js b/awx/ui/client/src/job-detail/host-events/host-events.controller.js index 55abf51e04..f56111bdb6 100644 --- a/awx/ui/client/src/job-detail/host-events/host-events.controller.js +++ b/awx/ui/client/src/job-detail/host-events/host-events.controller.js @@ -25,8 +25,8 @@ host_name: $scope.hostName, }; if ($scope.searchStr && $scope.searchStr !== ''){ - params.or__play__icontains = $scope.searchStr; - params.or__task__icontains = $scope.searchStr; + params.or__play__icontains = encodeURIComponent($scope.searchStr); + params.or__task__icontains = encodeURIComponent($scope.searchStr); } switch($scope.activeFilter){ From fc304899bd5d260f06a1447e4dfcadaec87207b3 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Thu, 14 Jul 2016 20:09:46 -0700 Subject: [PATCH 05/21] Jobs list page size (#3019) * changing jobs list page size to 20 by default it was previously set to 10 * adjustment to tag search check for null id --- awx/ui/client/src/controllers/Jobs.js | 2 ++ awx/ui/client/src/search/tagSearch.service.js | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/controllers/Jobs.js b/awx/ui/client/src/controllers/Jobs.js index 27cbd6f8f5..1e5d4067a7 100644 --- a/awx/ui/client/src/controllers/Jobs.js +++ b/awx/ui/client/src/controllers/Jobs.js @@ -66,6 +66,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa scope: jobs_scope, list: AllJobsList, id: 'active-jobs', + pageSize: 20, url: GetBasePath('unified_jobs') + '?status__in=pending,waiting,running,completed,failed,successful,error,canceled&order_by=-finished', searchParams: search_params, spinner: false @@ -77,6 +78,7 @@ export function JobsListController ($rootScope, $log, $scope, $compile, $statePa parent_scope: $scope, scope: scheduled_scope, list: ScheduledJobsList, + pageSize: 20, id: 'scheduled-jobs-tab', searchSize: 'col-lg-4 col-md-4 col-sm-4 col-xs-12', url: GetBasePath('schedules') + '?next_run__isnull=false' diff --git a/awx/ui/client/src/search/tagSearch.service.js b/awx/ui/client/src/search/tagSearch.service.js index fdd808d3ad..4e5e6ae3ec 100644 --- a/awx/ui/client/src/search/tagSearch.service.js +++ b/awx/ui/client/src/search/tagSearch.service.js @@ -85,7 +85,7 @@ export default ['Rest', '$q', 'GetBasePath', 'Wait', 'ProcessErrors', '$log', fu if (needsRequest.length) { // make the options request to reutrn the typeOptions var url = needsRequest[0].basePath ? GetBasePath(needsRequest[0].basePath) : basePath; - if(url.indexOf('null') === 0 ){ + if(url.indexOf('null') === -1 ){ Rest.setUrl(url); Rest.options() .success(function (data) { From 8c85035d1835aeef25909a76a9dd66a4a52c53b9 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Thu, 14 Jul 2016 23:10:26 -0400 Subject: [PATCH 06/21] Setting the local var CredentialList to the deep clone seems to be problematic. Moving this out so that the original object itself is overwritten which is how it's done in other places. (#3017) --- awx/ui/client/src/helpers/JobTemplates.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/awx/ui/client/src/helpers/JobTemplates.js b/awx/ui/client/src/helpers/JobTemplates.js index 55a4a9aa5f..2947c05546 100644 --- a/awx/ui/client/src/helpers/JobTemplates.js +++ b/awx/ui/client/src/helpers/JobTemplates.js @@ -25,7 +25,6 @@ angular.module('JobTemplatesHelper', ['Utilities']) return function(params) { var scope = params.scope, - CredentialList = _.cloneDeep(CredentialList), defaultUrl = GetBasePath('job_templates'), // generator = GenerateForm, form = JobTemplateForm(), @@ -37,6 +36,8 @@ angular.module('JobTemplatesHelper', ['Utilities']) // checkSCMStatus, getPlaybooks, callback, // choicesCount = 0; + CredentialList = _.cloneDeep(CredentialList); + // The form uses awPopOverWatch directive to 'watch' scope.callback_help for changes. Each time the // popover is activated, a function checks the value of scope.callback_help before constructing the content. scope.setCallbackHelp = function() { From c8fa2befb676b6f2cd351a41ff2121a51225ba17 Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Fri, 15 Jul 2016 10:35:15 -0400 Subject: [PATCH 07/21] Fixed bug where hitting enter in a password field in the job launch/survey maker modal would toggle the show/hide. --- .../job-submission/job-submission.partial.html | 16 ++++++++-------- .../shared/question-definition.form.js | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/awx/ui/client/src/job-submission/job-submission.partial.html b/awx/ui/client/src/job-submission/job-submission.partial.html index 95ca9df877..c6723ec347 100644 --- a/awx/ui/client/src/job-submission/job-submission.partial.html +++ b/awx/ui/client/src/job-submission/job-submission.partial.html @@ -54,9 +54,9 @@
- + - +
Please enter a password.
@@ -67,9 +67,9 @@
- + - +
Please enter a password.
@@ -80,9 +80,9 @@
- + - +
Please enter a password.
@@ -93,9 +93,9 @@
- + - +
Please enter a password.
diff --git a/awx/ui/client/src/job-templates/survey-maker/shared/question-definition.form.js b/awx/ui/client/src/job-templates/survey-maker/shared/question-definition.form.js index 32b1c1dd9a..56a3903f69 100644 --- a/awx/ui/client/src/job-templates/survey-maker/shared/question-definition.form.js +++ b/awx/ui/client/src/job-templates/survey-maker/shared/question-definition.form.js @@ -280,7 +280,7 @@ export default '
'+ '
'+ ''+ - ''+ + ''+ ''+ ''+ '
'+ From b9de0b196d59acf9505c0f0ce46075d31bd70814 Mon Sep 17 00:00:00 2001 From: Wayne Witzel III Date: Fri, 15 Jul 2016 10:32:52 -0400 Subject: [PATCH 08/21] add test for CustomInventoryScript serializer --- awx/main/tests/unit/api/test_serializers.py | 48 ++++++++++++++++++++- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/awx/main/tests/unit/api/test_serializers.py b/awx/main/tests/unit/api/test_serializers.py index a8fb25d005..2496ba9a2d 100644 --- a/awx/main/tests/unit/api/test_serializers.py +++ b/awx/main/tests/unit/api/test_serializers.py @@ -1,14 +1,31 @@ # Python import pytest import mock +from mock import PropertyMock import json # AWX -from awx.api.serializers import JobTemplateSerializer, JobSerializer, JobOptionsSerializer -from awx.main.models import Label, Job +from awx.api.serializers import ( + JobTemplateSerializer, + JobSerializer, + JobOptionsSerializer, + CustomInventoryScriptSerializer, +) +from awx.main.models import ( + Label, + Job, + CustomInventoryScript, + User, +) #DRF +from rest_framework.request import Request from rest_framework import serializers +from rest_framework.test import ( + APIRequestFactory, + force_authenticate, +) + def mock_JT_resource_data(): return ({}, []) @@ -189,3 +206,30 @@ class TestJobTemplateSerializerValidation(object): for ev in self.bad_extra_vars: with pytest.raises(serializers.ValidationError): serializer.validate_extra_vars(ev) + +class TestCustomInventoryScriptSerializer(object): + + @pytest.mark.parametrize("superuser,sysaudit,admin_role,value", + ((True, False, False, '#!/python'), + (False, True, False, '#!/python'), + (False, False, True, '#!/python'), + (False, False, False, None))) + def test_to_representation_orphan(self, superuser, sysaudit, admin_role, value): + with mock.patch.object(CustomInventoryScriptSerializer, 'get_summary_fields', return_value={}): + User.add_to_class('is_system_auditor', sysaudit) + user = User(username="root", is_superuser=superuser) + roles = [user] if admin_role else [] + + with mock.patch('awx.main.models.CustomInventoryScript.admin_role', new_callable=PropertyMock, return_value=roles): + cis = CustomInventoryScript(pk=1, script='#!/python') + serializer = CustomInventoryScriptSerializer() + + factory = APIRequestFactory() + wsgi_request = factory.post("/inventory_script/1", {'id':1}, format="json") + force_authenticate(wsgi_request, user) + + request = Request(wsgi_request) + serializer.context['request'] = request + + representation = serializer.to_representation(cis) + assert representation['script'] == value From e5cb497c2241a3f18860802485d69bb585c4991c Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Fri, 15 Jul 2016 10:45:36 -0400 Subject: [PATCH 09/21] Password enter show/hide fix --- awx/ui/client/src/shared/form-generator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/shared/form-generator.js b/awx/ui/client/src/shared/form-generator.js index 4b889eeb75..4c8382db38 100644 --- a/awx/ui/client/src/shared/form-generator.js +++ b/awx/ui/client/src/shared/form-generator.js @@ -922,7 +922,7 @@ angular.module('FormGenerator', [GeneratorHelpers.name, 'Utilities', listGenerat html += "'>\n"; // TODO: make it so that the button won't show up if the mode is edit, hasShowInputButton !== true, and there are no contents in the field. html += "\n"; - html += " +
From 5894e5eb654b0eae1a276377d3e70bca870dd9ca Mon Sep 17 00:00:00 2001 From: Michael Abashian Date: Mon, 18 Jul 2016 10:55:18 -0400 Subject: [PATCH 18/21] Fixed password show/hide on enter for survey maker password type previews --- .../survey-maker/render/survey-question.partial.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/job-templates/survey-maker/render/survey-question.partial.html b/awx/ui/client/src/job-templates/survey-maker/render/survey-question.partial.html index 72e772bd62..0777b94c90 100644 --- a/awx/ui/client/src/job-templates/survey-maker/render/survey-question.partial.html +++ b/awx/ui/client/src/job-templates/survey-maker/render/survey-question.partial.html @@ -17,7 +17,7 @@
- +
From b587b892b017b3ca0bcb70ee15237fce6983a50d Mon Sep 17 00:00:00 2001 From: Matthew Jones Date: Mon, 18 Jul 2016 12:27:53 -0400 Subject: [PATCH 19/21] Switch base class for StateConflict This fixes the output format for the 409 exception return --- awx/main/access.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index d3f8e50990..5b2ee91851 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -12,7 +12,7 @@ from django.contrib.auth.models import User from django.contrib.contenttypes.models import ContentType # Django REST Framework -from rest_framework.exceptions import ParseError, PermissionDenied, APIException +from rest_framework.exceptions import ParseError, PermissionDenied, ValidationError # AWX from awx.main.utils import * # noqa @@ -57,9 +57,8 @@ access_registry = { # ... } -class StateConflict(APIException): +class StateConflict(ValidationError): status_code = 409 - default_detail = 'Object state is not correct' def register_access(model_class, access_class): access_classes = access_registry.setdefault(model_class, []) From c0e02f4a65cb087d910b05a43b8d0dbe96109aac Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Mon, 18 Jul 2016 13:34:53 -0400 Subject: [PATCH 20/21] fix missing URI encoding in event summary serch, kickback on #2980 (#3050) --- .../src/job-detail/host-summary/host-summary.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js index 34763c838e..d5c826ac35 100644 --- a/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js +++ b/awx/ui/client/src/job-detail/host-summary/host-summary.controller.js @@ -104,7 +104,7 @@ Wait('start'); JobDetailService.getJobHostSummaries($stateParams.id, { page_size: page_size, - host_name__icontains: $scope.searchTerm, + host_name__icontains: encodeURIComponent($scope.searchTerm), }).success(function(res){ $scope.hosts = res.results; $scope.next = res.next; From 62e5defac384504fa367c591d545f9c9d574dffe Mon Sep 17 00:00:00 2001 From: Leigh Johnson Date: Mon, 18 Jul 2016 15:34:59 -0400 Subject: [PATCH 21/21] remove aws ask at runtime prompt from cred form config, resolves #3055 (#3058) --- awx/ui/client/src/forms/Credentials.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/awx/ui/client/src/forms/Credentials.js b/awx/ui/client/src/forms/Credentials.js index f23852cebc..fe61186cce 100644 --- a/awx/ui/client/src/forms/Credentials.js +++ b/awx/ui/client/src/forms/Credentials.js @@ -107,11 +107,6 @@ export default init: false }, autocomplete: false, - subCheckbox: { - variable: 'secret_key_ask', - text: 'Ask at runtime?', - ngChange: 'ask(\'secret_key\', \'undefined\')' - }, clear: false, hasShowInputButton: true, apiField: 'password',