Repository: ansible/eda-server
Pull request #1259: Remove old Credential model 
Author: login: ShaiahWren
Labels: name: run-e2e
Created: 2025-04-04T19:44:23Z | Merged: 2025-04-09T17:33:07Z

https://issues.redhat.com/browse/AAP-21988
Remove the Credential model located at aap_eda/core/models/credential.py and all references of the model. And methods and tests using this model are also deleted. 





Diff:
diff --git a/src/aap_eda/core/management/commands/create_initial_data.py b/src/aap_eda/core/management/commands/create_initial_data.py
index aff1ba635..c2b7e992c 100644
--- a/src/aap_eda/core/management/commands/create_initial_data.py
+++ b/src/aap_eda/core/management/commands/create_initial_data.py
@@ -14,7 +14,6 @@
 import hashlib
 import logging
 import os
-from urllib.parse import urlparse
 
 from ansible_base.rbac import permission_registry
 from ansible_base.rbac.models import DABPermission, RoleDefinition
@@ -1287,8 +1286,6 @@ def handle(self, *args, **options):
         settings_registry.persist_registry_data()
         self._preload_credential_types()
         self._update_postgres_credentials()
-        self._copy_registry_credentials()
-        self._copy_scm_credentials()
         self._create_org_roles()
         self._create_obj_roles()
         self._remove_deprecated_credential_kinds()
@@ -1307,107 +1304,6 @@ def _preload_credential_types(self):
                 f"New credential type {credential_type.name} is added."
             )
 
-    def _copy_registry_credentials(self):
-        credentials = models.Credential.objects.filter(
-            credential_type=enums.CredentialType.REGISTRY
-        ).all()
-        if not credentials:
-            return
-
-        default_organization = get_default_organization()
-
-        cred_type = models.CredentialType.objects.filter(
-            name=enums.DefaultCredentialType.REGISTRY
-        ).first()
-        for cred in credentials:
-            de = models.DecisionEnvironment.objects.filter(
-                credential=cred
-            ).first()
-            host = "quay.io"
-            if de:
-                image_url = (
-                    de.image_url.replace("http://", "")
-                    .replace("https://", "")
-                    .replace("//", "")
-                )
-                host = urlparse(f"//{image_url}").hostname
-            inputs = {
-                "host": host,
-                "username": cred.username,
-                "password": cred.secret.get_secret_value(),
-            }
-            eda_cred, created = models.EdaCredential.objects.get_or_create(
-                name=cred.name,
-                defaults={
-                    "description": cred.description,
-                    "managed": False,
-                    "credential_type": cred_type,
-                    "inputs": inputs_to_store(inputs),
-                    "organization": default_organization,
-                },
-            )
-            if created:
-                models.DecisionEnvironment.objects.filter(
-                    credential=cred
-                ).update(eda_credential=eda_cred, credential=None)
-                cred.delete()
-            else:
-                info_msg = (
-                    f"Registry Credential {cred.name} already converted to "
-                    "EdaCredential. Skip the duplicated one."
-                )
-                LOGGER.info(info_msg)
-
-        self.stdout.write(
-            "All REGISTRY credentials are converted to Container Registry "
-            "eda-credentials"
-        )
-
-    def _copy_scm_credentials(self):
-        types = [enums.CredentialType.GITHUB, enums.CredentialType.GITLAB]
-        credentials = models.Credential.objects.filter(
-            credential_type__in=types
-        ).all()
-        if not credentials:
-            return
-
-        default_organization = get_default_organization()
-
-        cred_type = models.CredentialType.objects.filter(
-            name=enums.DefaultCredentialType.SOURCE_CONTROL
-        ).first()
-        for cred in credentials:
-            inputs = {
-                "username": cred.username,
-                "password": cred.secret.get_secret_value(),
-            }
-            eda_cred, created = models.EdaCredential.objects.get_or_create(
-                name=cred.name,
-                defaults={
-                    "description": cred.description,
-                    "managed": False,
-                    "credential_type": cred_type,
-                    "inputs": inputs_to_store(inputs),
-                    "organization": default_organization,
-                },
-            )
-            if created:
-                models.Project.objects.filter(credential=cred).update(
-                    eda_credential=eda_cred, credential=None
-                )
-                cred.delete()
-            else:
-                info_msg = (
-                    f"Git Credential {cred.name} already converted to "
-                    "EdaCredential. Skip the duplicated one."
-                )
-                LOGGER.info(info_msg)
-
-        self.stdout.write(
-            "All GITHUB and GITLAB credentials are converted to Source "
-            "Control eda-credentials"
-        )
-
     def _update_postgres_credentials(self):
         cred_type = models.CredentialType.objects.get(
             name=enums.DefaultCredentialType.POSTGRES
diff --git a/src/aap_eda/core/migrations/0063_remove_decisionenvironment_credential_and_more.py b/src/aap_eda/core/migrations/0063_remove_decisionenvironment_credential_and_more.py
new file mode 100644
index 000000000..4d6696aa9
--- /dev/null
+++ b/src/aap_eda/core/migrations/0063_remove_decisionenvironment_credential_and_more.py
@@ -0,0 +1,23 @@
+# Generated by Django 4.2.16 on 2025-04-07 18:48
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+    dependencies = [
+        ("core", "0062_setting"),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name="decisionenvironment",
+            name="credential",
+        ),
+        migrations.RemoveField(
+            model_name="project",
+            name="credential",
+        ),
+        migrations.DeleteModel(
+            name="Credential",
+        ),
+    ]
diff --git a/src/aap_eda/core/models/__init__.py b/src/aap_eda/core/models/__init__.py
index 828e7fe58..1180587ec 100644
--- a/src/aap_eda/core/models/__init__.py
+++ b/src/aap_eda/core/models/__init__.py
@@ -15,7 +15,6 @@
 from ansible_base.rbac import permission_registry
 
 from .activation import Activation
-from .credential import Credential
 from .credential_type import CredentialType
 from .decision_environment import DecisionEnvironment
 from .eda_credential import EdaCredential
@@ -57,7 +56,6 @@
     "Rulebook",
     "User",
     "AwxToken",
-    "Credential",
     "CredentialType",
     "EdaCredential",
     "DecisionEnvironment",
diff --git a/src/aap_eda/core/models/credential.py b/src/aap_eda/core/models/credential.py
deleted file mode 100644
index c86ef59de..000000000
--- a/src/aap_eda/core/models/credential.py
+++ /dev/null
@@ -1,43 +0,0 @@
-#  Copyright 2023 Red Hat, Inc.
-#
-#  Licensed under the Apache License, Version 2.0 (the "License");
-#  you may not use this file except in compliance with the License.
-#  You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-from django.db import models
-
-from aap_eda.core.enums import CredentialType
-from aap_eda.core.utils.crypto.fields import EncryptedTextField
-
-__all__ = ("Credential",)
-
-
-class Credential(models.Model):
-    class Meta:
-        db_table = "core_credential"
-        constraints = [
-            models.CheckConstraint(
-                check=~models.Q(name=""),
-                name="ck_empty_credential_name",
-            )
-        ]
-
-    name = models.TextField(null=False, unique=True)
-    description = models.TextField(default="", blank=True, null=False)
-    credential_type = models.TextField(
-        choices=CredentialType.choices(),
-        default=CredentialType.REGISTRY,
-    )
-    username = models.TextField(null=True)
-    secret = EncryptedTextField(null=False)
-    vault_identifier = models.TextField(null=True)
-    created_at = models.DateTimeField(auto_now_add=True, null=False)
-    modified_at = models.DateTimeField(auto_now=True, null=False)
diff --git a/src/aap_eda/core/models/decision_environment.py b/src/aap_eda/core/models/decision_environment.py
index d5a3777c9..dc5900439 100644
--- a/src/aap_eda/core/models/decision_environment.py
+++ b/src/aap_eda/core/models/decision_environment.py
@@ -33,14 +33,6 @@ class Meta:
 
     description = models.TextField(default="", blank=True, null=False)
     image_url = models.TextField(blank=False, null=False)
-    # TODO: used by migration, remove it later
-    credential = models.ForeignKey(
-        "Credential",
-        blank=True,
-        null=True,
-        default=None,
-        on_delete=models.SET_NULL,
-    )
     eda_credential = models.ForeignKey(
         "EdaCredential",
         blank=True,
diff --git a/src/aap_eda/core/models/project.py b/src/aap_eda/core/models/project.py
index 7e6c9b873..df8b026ce 100644
--- a/src/aap_eda/core/models/project.py
+++ b/src/aap_eda/core/models/project.py
@@ -60,14 +60,6 @@ class ScmType(models.TextChoices):
     proxy = EncryptedTextField(blank=True, default="")
     git_hash = models.TextField()
     verify_ssl = models.BooleanField(default=True)
-    # TODO: used by migration, remove it later
-    credential = models.ForeignKey(
-        "Credential",
-        blank=True,
-        null=True,
-        default=None,
-        on_delete=models.SET_NULL,
-    )
     eda_credential = models.ForeignKey(
         "EdaCredential",
         blank=True,
diff --git a/tests/integration/api/test_project.py b/tests/integration/api/test_project.py
index ec34d277f..7e1a7733e 100644
--- a/tests/integration/api/test_project.py
+++ b/tests/integration/api/test_project.py
@@ -625,8 +625,8 @@ def test_update_project_with_400(
     data = {
         "name": new_project.name,
         "git_hash": default_project.git_hash,
-        "credential_id": default_project.credential_id,
     }
+
     # test empty string validator
     response = admin_client.patch(
         f"{api_url_v1}/projects/{default_project.id}/", data={"name": ""}
diff --git a/tests/integration/core/test_create_initial_data.py b/tests/integration/core/test_create_initial_data.py
index a115d6574..c401c1a6e 100644
--- a/tests/integration/core/test_create_initial_data.py
+++ b/tests/integration/core/test_create_initial_data.py
@@ -16,12 +16,10 @@
 from ansible_base.rbac import permission_registry
 from ansible_base.rbac.models import DABPermission, RoleDefinition
 
-from aap_eda.core import enums, models
 from aap_eda.core.management.commands.create_initial_data import (
     ORG_ROLES,
     Command,
 )
-from aap_eda.core.utils.credentials import inputs_from_store
 
 
 #################################################################
@@ -87,82 +85,3 @@ def test_remove_extra_permission():
     assert perm in auditor_role.permissions.all()
     Command().handle()
     assert perm not in auditor_role.permissions.all()
-
-
-#################################################################
-# Credentials
-#################################################################
-def create_old_registry_credential(default_organization: models.Organization):
-    credential = models.Credential.objects.create(
-        name="registry cred",
-        credential_type=enums.CredentialType.REGISTRY,
-        username="fred",
-        secret="mysec",
-    )
-    de = models.DecisionEnvironment.objects.create(
-        name="my DE",
-        image_url="private-reg.com/fred/de",
-        credential=credential,
-        organization=default_organization,
-    )
-    return credential, de
-
-
-def create_old_git_credential(default_organization: models.Organization):
-    credential = models.Credential.objects.create(
-        name="git cred",
-        credential_type=enums.CredentialType.GITHUB,
-        username="fred",
-        secret="mysec",
-    )
-    project = models.Project.objects.create(
-        name="my project",
-        url="github.com/fred/projects",
-        credential=credential,
-        organization=default_organization,
-    )
-    return credential, project
-
-
-@pytest.mark.django_db
-def test_copy_registry_credentials(
-    default_organization: models.Organization, caplog
-):
-    credential, de = create_old_registry_credential(default_organization)
-    Command().handle()
-
-    assert not models.Credential.objects.filter(id=credential.id).exists()
-    de.refresh_from_db()
-    assert de.eda_credential.name == credential.name
-    assert not de.eda_credential.managed
-    inputs = inputs_from_store(de.eda_credential.inputs.get_secret_value())
-    assert inputs["host"] == "private-reg.com"
-    assert inputs["username"] == "fred"
-    assert inputs["password"] == "mysec"
-
-    credential.id = None
-    credential.save()
-    Command().handle()
-    assert models.Credential.objects.filter(id=credential.id).exists()
-
-
-@pytest.mark.django_db
-def test_copy_project_credentials(
-    default_organization: models.Organization, caplog
-):
-    credential, project = create_old_git_credential(default_organization)
-    Command().handle()
-
-    assert not models.Credential.objects.filter(id=credential.id).exists()
-    project.refresh_from_db()
-    assert project.eda_credential.name == credential.name
-    assert not project.eda_credential.managed
-    inputs = inputs_from_store(
-        project.eda_credential.inputs.get_secret_value()
-    )
-    assert inputs["username"] == "fred"
-    assert inputs["password"] == "mysec"
-    credential.id = None
-    credential.save()
-    Command().handle()
-    assert models.Credential.objects.filter(id=credential.id).exists()


Reviews:
user: login: bzwei
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-08T12:52:01Z
user: login: zkayyali812
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-08T19:14:49Z
user: login: bzwei
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-08T20:37:11Z
user: login: ttuffin
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-09T07:18:39Z

Review comments:
diff_hunk: @@ -61,13 +61,6 @@ class ScmType(models.TextChoices):
     git_hash = models.TextField()
     verify_ssl = models.BooleanField(default=True)
     # TODO: used by migration, remove it later
path: src/aap_eda/core/models/project.py
user: login: bzwei
body: remove this line
created_at: 2025-04-08T12:48:16Z
author_association: COLLABORATOR
diff_hunk: @@ -34,13 +34,6 @@ class Meta:
     description = models.TextField(default="", blank=True, null=False)
     image_url = models.TextField(blank=False, null=False)
     # TODO: used by migration, remove it later
path: src/aap_eda/core/models/decision_environment.py
user: login: bzwei
body: remove this line
created_at: 2025-04-08T12:48:28Z
author_association: COLLABORATOR
diff_hunk: @@ -625,7 +625,7 @@ def test_update_project_with_400(
     data = {
         "name": new_project.name,
         "git_hash": default_project.git_hash,
-        "credential_id": default_project.credential_id,
+        "eda_credential_id": default_project.eda_credential_id,
path: tests/integration/api/test_project.py
user: login: bzwei
body: Is this line needed? Can we just delete it?
created_at: 2025-04-08T12:50:43Z
author_association: COLLABORATOR

PR comments:
user: login: bzwei
created_at: 2025-04-07T13:28:59Z
body: @ShaiahWren you need to create a migration for deleting a model
author_association: COLLABORATOR
user: login: codecov-commenter
created_at: 2025-04-07T19:34:24Z
body: ## [Codecov](https://app.codecov.io/gh/ansible/eda-server/pull/1259?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible) Report
:white_check_mark: All modified and coverable lines are covered by tests.
:white_check_mark: Project coverage is 94.55%. Comparing base ([`048501b`](https://app.codecov.io/gh/ansible/eda-server/commit/048501b611cbc3bcec492cb609b5371964571f16?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible)) to head ([`742a329`](https://app.codecov.io/gh/ansible/eda-server/commit/742a3299ac20c339eeb6e58b52ae68df01068520?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible)).
:warning: Report is 179 commits behind head on main.

```diff
@@            Coverage Diff             @@
##             main    #1259      +/-   ##
==========================================
- Coverage   94.58%   94.55%   -0.03%     
==========================================
  Files         314      314              
  Lines       18349    18254      -95     
==========================================
- Hits        17355    17260      -95     
  Misses        994      994              
```

| [Flag](https://app.codecov.io/gh/ansible/eda-server/pull/1259/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible) | Coverage Δ | |
|---|---|---|
| [unit-int-tests-3.11](https://app.codecov.io/gh/ansible/eda-server/pull/1259/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible) | `94.49% <100.00%> (-0.03%)` | :arrow_down: |
| [unit-int-tests-3.12](https://app.codecov.io/gh/ansible/eda-server/pull/1259/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible) | `94.55% <100.00%> (-0.03%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Files with missing lines](https://app.codecov.io/gh/ansible/eda-server/pull/1259?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible) | Coverage Δ | |
|---|---|---|
| [...da/core/management/commands/create\_initial\_data.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=src%2Faap_eda%2Fcore%2Fmanagement%2Fcommands%2Fcreate_initial_data.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-c3JjL2FhcF9lZGEvY29yZS9tYW5hZ2VtZW50L2NvbW1hbmRzL2NyZWF0ZV9pbml0aWFsX2RhdGEucHk=) | `98.73% <ø> (-0.26%)` | :arrow_down: |
| [...\_remove\_decisionenvironment\_credential\_and\_more.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=src%2Faap_eda%2Fcore%2Fmigrations%2F0063_remove_decisionenvironment_credential_and_more.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-c3JjL2FhcF9lZGEvY29yZS9taWdyYXRpb25zLzAwNjNfcmVtb3ZlX2RlY2lzaW9uZW52aXJvbm1lbnRfY3JlZGVudGlhbF9hbmRfbW9yZS5weQ==) | `100.00% <100.00%> (ø)` | |
| [src/aap\_eda/core/models/\_\_init\_\_.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=src%2Faap_eda%2Fcore%2Fmodels%2F__init__.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-c3JjL2FhcF9lZGEvY29yZS9tb2RlbHMvX19pbml0X18ucHk=) | `100.00% <ø> (ø)` | |
| [src/aap\_eda/core/models/decision\_environment.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=src%2Faap_eda%2Fcore%2Fmodels%2Fdecision_environment.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-c3JjL2FhcF9lZGEvY29yZS9tb2RlbHMvZGVjaXNpb25fZW52aXJvbm1lbnQucHk=) | `100.00% <ø> (ø)` | |
| [src/aap\_eda/core/models/project.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=src%2Faap_eda%2Fcore%2Fmodels%2Fproject.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-c3JjL2FhcF9lZGEvY29yZS9tb2RlbHMvcHJvamVjdC5weQ==) | `97.14% <ø> (-0.08%)` | :arrow_down: |
| [tests/integration/api/test\_project.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=tests%2Fintegration%2Fapi%2Ftest_project.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-dGVzdHMvaW50ZWdyYXRpb24vYXBpL3Rlc3RfcHJvamVjdC5weQ==) | `100.00% <ø> (ø)` | |
| [tests/integration/core/test\_create\_initial\_data.py](https://app.codecov.io/gh/ansible/eda-server/pull/1259?src=pr&el=tree&filepath=tests%2Fintegration%2Fcore%2Ftest_create_initial_data.py&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ansible#diff-dGVzdHMvaW50ZWdyYXRpb24vY29yZS90ZXN0X2NyZWF0ZV9pbml0aWFsX2RhdGEucHk=) | `100.00% <ø> (ø)` | |
<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
author_association: NONE
user: login: Alex-Izquierdo
created_at: 2025-04-08T20:09:03Z
body: Hi @ShaiahWren can you update the PR title with a more meaningful content? 
author_association: COLLABORATOR
user: login: sonarqubecloud[bot]
created_at: 2025-04-09T16:16:44Z
body: ## [![Quality Gate Passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/qg-passed-20px.png 'Quality Gate Passed')](https://sonarcloud.io/dashboard?id=ansible_eda-server&pullRequest=1259) **Quality Gate passed**  
Issues  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 New issues](https://sonarcloud.io/project/issues?id=ansible_eda-server&pullRequest=1259&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/accepted-16px.png '') [0 Accepted issues](https://sonarcloud.io/project/issues?id=ansible_eda-server&pullRequest=1259&issueStatuses=ACCEPTED)

Measures  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=ansible_eda-server&pullRequest=1259&issueStatuses=OPEN,CONFIRMED&sinceLeakPeriod=true)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Coverage on New Code](https://sonarcloud.io/component_measures?id=ansible_eda-server&pullRequest=1259&metric=new_coverage&view=list)  
![](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/passed-16px.png '') [0.0% Duplication on New Code](https://sonarcloud.io/component_measures?id=ansible_eda-server&pullRequest=1259&metric=new_duplicated_lines_density&view=list)  
  
[See analysis details on SonarQube Cloud](https://sonarcloud.io/dashboard?id=ansible_eda-server&pullRequest=1259)


author_association: NONE