Repository: nautobot/nautobot (Python)

Issue:
Add new secret - 'Validate' Button
### As ...

Nelly - Network Engineer

### I want ...

To confirm that the values entered in "Add new Secret" dialog are correct.

### So that ...

Data quality can be ensured without having to trigger some functionality that uses the newly created secret for validation.

### I know this is done when...

There should be a "Validate" button, that tries to retrieve the newly defined secret and displays "Secret was successfully retrieved!" or "Failed to get the secret!" message.

Maybe this validation could be automatically triggered when pressing the "Create" button. The secret should be stored without any further interaction when it is successfully validated else a confirmation dialog should be presented to "Nelly" ("Failed to retrieve secret! Store anyway?") to allow correcting the values or storing it anyhow. (e.g. preparing data for a new site where secret-server isn't available yet.)

### Optional - Feature groups this request pertains to.

- [ ] Automation
- [ ] Circuits
- [ ] DCIM
- [ ] IPAM
- [ ] Misc (including Data Sources)
- [ ] Organization
- [ ] Plugins (and other Extensibility)
- [ ] Security (Secrets, etc)
- [ ] Image Management
- [X] UI/UX
- [ ] Documentation
- [ ] Other (not directly a platform feature)

### Database Changes

None

### External Dependencies

None


Discussion: @bryanculver Is it possible to add the output of the following script on Advanced tab of a secret? 

So no call to the secret.provider is executed as long as someone clicks on the Advanced tab

```python
try: 
  secret.get_value()
  is_secret_valid = True
except SecError:
  is_secret_valid = False
```
I've added a pull request to nautobot-plugin-secrets-providers that solves this by adding a new "Check" tab to secret detail view.

https://github.com/nautobot/nautobot-plugin-secrets-providers/pull/62
Let’s upstream https://github.com/nautobot/nautobot-plugin-secrets-providers/pull/62



Fix (patch):
diff --git a/changes/1526.added b/changes/1526.added
new file mode 100644
index 00000000000..7f8a634abd1
--- /dev/null
+++ b/changes/1526.added
@@ -0,0 +1,1 @@
+Added UI button and REST API to validate a `Secret` can be retrieved.
diff --git a/nautobot/extras/api/views.py b/nautobot/extras/api/views.py
index b99d2ffd688..b11e58d0fe7 100644
--- a/nautobot/extras/api/views.py
+++ b/nautobot/extras/api/views.py
@@ -62,6 +62,7 @@
 )
 from nautobot.extras.models import CustomField, CustomFieldChoice
 from nautobot.extras.jobs import run_job
+from nautobot.extras.secrets.exceptions import SecretError
 from nautobot.extras.utils import get_job_content_type, get_worker_count
 from nautobot.utilities.exceptions import CeleryWorkerNotRunningException
 from nautobot.utilities.api import get_serializer_for_model
@@ -1140,6 +1141,31 @@ class SecretsViewSet(NautobotModelViewSet):
     serializer_class = serializers.SecretSerializer
     filterset_class = filters.SecretFilterSet
 
+    @extend_schema(
+        responses={
+            200: {
+                "type": "object",
+                "properties": {
+                    "result": {"type": "boolean"},
+                    "message": {"type": "string"},
+                },
+            }
+        },
+    )
+    @action(methods=["GET"], detail=True)
+    def check(self, request, pk):
+        """Check that a secret's value is accessible."""
+        result = False
+        message = "Unknown error"
+        try:
+            self.get_object().get_value()
+            result = True
+            message = "Passed"
+        except SecretError as e:
+            message = str(e)
+        response = {"result": result, "message": message}
+        return Response(response)
+
 
 class SecretsGroupViewSet(NautobotModelViewSet):
     """
diff --git a/nautobot/extras/templates/extras/secret.html b/nautobot/extras/templates/extras/secret.html
index 82880a307e8..a85596f9f38 100644
--- a/nautobot/extras/templates/extras/secret.html
+++ b/nautobot/extras/templates/extras/secret.html
@@ -1,6 +1,12 @@
 {% extends 'generic/object_detail.html' %}
 {% load helpers %}
 
+{% block extra_buttons %}
+    <a onClick="checkSecret()" class="btn btn-default">
+        Check Secret
+    </a>
+{% endblock extra_buttons %}
+
 {% block content_left_page %}
     <div class="panel panel-default">
         <div class="panel-heading">
@@ -35,3 +41,25 @@
 {% block content_right_page %}
     {% include 'utilities/obj_table.html' with table=groups_table table_template='panel_table.html' heading='Groups containing this secret' %}
 {% endblock content_right_page %}
+
+
+{% block javascript %}
+<script>
+    function checkSecret() {
+        $.ajax({
+            url: "{% url 'extras-api:secret-check' pk=object.pk %}",
+            dataType: 'json',
+            success: function(json) {
+                if(json.result) {
+                    alert("The secret was successfully retrieved.")
+                } else {
+                    alert("Error retrieving secret: \n\n" + json.message)
+                }
+            },
+            error: function(xhr) {
+                alert("Error checking secret: \n\n" + xhr.responseText);
+            }
+        });
+    }
+</script>
+{% endblock javascript %}