diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 018301f63f..acb3144d15 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -154,6 +154,7 @@ SUMMARIZABLE_FK_FIELDS = { 'source_project': DEFAULT_SUMMARY_FIELDS + ('status', 'scm_type'), 'project_update': DEFAULT_SUMMARY_FIELDS + ('status', 'failed'), 'credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'cloud', 'kubernetes', 'credential_type_id'), + 'signature_validation_credential': DEFAULT_SUMMARY_FIELDS + ('kind', 'credential_type_id'), 'job': DEFAULT_SUMMARY_FIELDS + ('status', 'failed', 'elapsed', 'type', 'canceled_on'), 'job_template': DEFAULT_SUMMARY_FIELDS, 'workflow_job_template': DEFAULT_SUMMARY_FIELDS, @@ -1470,6 +1471,7 @@ class ProjectSerializer(UnifiedJobTemplateSerializer, ProjectOptionsSerializer): 'allow_override', 'custom_virtualenv', 'default_environment', + 'signature_validation_credential', ) + ( 'last_update_failed', 'last_updated', diff --git a/awx/main/migrations/0167_project_signature_validation_credential.py b/awx/main/migrations/0167_project_signature_validation_credential.py new file mode 100644 index 0000000000..e8e3c6a92a --- /dev/null +++ b/awx/main/migrations/0167_project_signature_validation_credential.py @@ -0,0 +1,28 @@ +# Generated by Django 3.2.13 on 2022-08-24 14:02 + +from django.db import migrations, models +import django.db.models.deletion +from django.utils.translation import gettext_lazy as _ + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0166_alter_jobevent_host'), + ] + + operations = [ + migrations.AddField( + model_name='project', + name='signature_validation_credential', + field=models.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='projects_signature_validation', + to='main.credential', + help_text=_('An optional credential used for validating files in the project against unexpected changes.'), + ), + ), + ] diff --git a/awx/main/models/projects.py b/awx/main/models/projects.py index 5b8fabde97..431c603319 100644 --- a/awx/main/models/projects.py +++ b/awx/main/models/projects.py @@ -284,6 +284,17 @@ class Project(UnifiedJobTemplate, ProjectOptions, ResourceMixin, CustomVirtualEn help_text=_('Allow changing the SCM branch or revision in a job template ' 'that uses this project.'), ) + # credential (keys) used to validate content signature + signature_validation_credential = models.ForeignKey( + 'Credential', + related_name='%(class)ss_signature_validation', + blank=True, + null=True, + default=None, + on_delete=models.SET_NULL, + help_text=_('An optional credential used for validating files in the project against unexpected changes.'), + ) + scm_revision = models.CharField( max_length=1024, blank=True, diff --git a/awx_collection/plugins/modules/project.py b/awx_collection/plugins/modules/project.py index 632f35cefe..11f40519b0 100644 --- a/awx_collection/plugins/modules/project.py +++ b/awx_collection/plugins/modules/project.py @@ -169,6 +169,12 @@ options: required: False default: 2 type: float + signature_validation_credential: + description: + - Name of the credential to use for signature validation. + - If signature validation credential is provided, signature validation will be enabled. + type: str + extends_documentation_fragment: awx.awx.auth ''' @@ -279,10 +285,13 @@ def main(): wait=dict(type='bool', default=True), update_project=dict(default=False, type='bool'), interval=dict(default=2.0, type='float'), + signature_validation_credential=dict(type='str'), ) # Create a module for ourselves - module = ControllerAPIModule(argument_spec=argument_spec) + module = ControllerAPIModule( + argument_spec=argument_spec, + ) # Extract our parameters name = module.params.get('name') @@ -301,6 +310,8 @@ def main(): wait = module.params.get('wait') update_project = module.params.get('update_project') + signature_validation_credential = module.params.get('signature_validation_credential') + # Attempt to look up the related items the user specified (these will fail the module if not found) lookup_data = {} org_id = None @@ -330,6 +341,9 @@ def main(): if credential is not None: credential = module.resolve_name_to_id('credentials', credential) + if signature_validation_credential is not None: + signature_validation_credential = module.resolve_name_to_id('credentials', signature_validation_credential) + # Attempt to look up associated field items the user specified. association_fields = {} @@ -358,6 +372,7 @@ def main(): 'organization': org_id, 'scm_update_on_launch': scm_update_on_launch, 'scm_update_cache_timeout': scm_update_cache_timeout, + 'signature_validation_credential': signature_validation_credential, } for field_name in (