Repository: goauthentik/authentik

Issue:
YAML schema does not match `ak export_blueprint`
**Describe the bug**
`ak export_blueprint` provides blueprints with UUIDs in several places where the schema however expects integers.

**To Reproduce**

1. Open a shell in the worker container
2. Run `ak export_blueprint`
3. Copy the generated blueprint (or a part of it) into VSCode and add the schema hint to the top (`# yaml-language-server: $schema=https://version-2023-10.goauthentik.io/blueprints/schema.json`)
4. Several fields with a UUID as a value are underlined with the error: `Incorrect type. Expected "integer". yaml-schema: Property mappings`

**Expected behavior**
The output generated by `ak export_blueprint` should match the structure expected by the schema (or vice versa).

**Version and Deployment (please complete the following information):**

-   authentik version: 2023.10.4
-   Deployment: docker-compose

**Additional context**
Also some of the entries generated have a `null` id. Not sure if that is intended.


Discussion:
The warnings happen due to the fact that YAML scheams don't know the value of any YAML tags, so this is sadly currently to be expected. I'm not aware of any YAML schema implementation that would correctly support this
Would it work to define the fields as `type: string, format: uuid`?
can you post a snippet of a segment that has this error? The field annotations should be correct as they're generated the same way the API schema is generated, which is directly from the database model (in most cases anyways)
```yaml
# yaml-language-server: $schema=https://version-2023-10.goauthentik.io/blueprints/schema.json
version: 1
entries:
- attrs:
    base_dn: dc=cde-ev,dc=de
    bind_cn: cn=admin,ou=duas,dc=cde-ev,dc=de
    enabled: true
    group_membership_field: uniqueMember
    group_object_filter: (objectClass=groupOfUniqueNames)
    name: CdEDB LDAP
    object_uniqueness_field: ipaUniqueID
    peer_certificate: 00c3af6b-be17-4b20-a0a1-9d0b10b7ed49
    policy_engine_mode: any
    property_mappings:
    - 0ff968ba-4bad-4491-819b-0bf4c3b32d72
    - cbe46010-46e7-4159-a61e-bf8760670972
    - 40047e31-1cc4-4eaa-8d53-a88bb31fe380
    - d60fedf2-55a5-4d72-b21f-d3ccdb399f29
    - f2187f0b-da68-4f2e-b1fb-a107439d9a15
    - c443f68e-b65c-412d-8047-1acafed906fb
    property_mappings_group:
    - c443f68e-b65c-412d-8047-1acafed906fb
    server_uri: ldaps://ldap
    slug: cdedb-ldap
    sni: true
    sync_groups: true
    sync_users: true
    user_matching_mode: identifier
    user_object_filter: (objectClass=inetOrgPerson)
    user_path_template: goauthentik.io/sources/%(slug)s
  conditions: []
  id: null
  identifiers:
    pk: 23b43253-98f3-4adc-a275-7900787a3ab6
  model: authentik_sources_ldap.ldapsource
  state: present
```
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
I will have to see if anything changed in recent releases

Resolving patch:
diff --git a/authentik/blueprints/management/commands/make_blueprint_schema.py b/authentik/blueprints/management/commands/make_blueprint_schema.py
--- a/authentik/blueprints/management/commands/make_blueprint_schema.py
+++ b/authentik/blueprints/management/commands/make_blueprint_schema.py
@@ -4,12 +4,14 @@
 from typing import Any
 
 from django.core.management.base import BaseCommand, no_translations
-from django.db.models import Model
-from drf_jsonschema_serializer.convert import field_to_converter
+from django.db.models import Model, fields
+from drf_jsonschema_serializer.convert import converter, field_to_converter
 from rest_framework.fields import Field, JSONField, UUIDField
+from rest_framework.relations import PrimaryKeyRelatedField
 from rest_framework.serializers import Serializer
 from structlog.stdlib import get_logger
 
+from authentik import __version__
 from authentik.blueprints.v1.common import BlueprintEntryDesiredState
 from authentik.blueprints.v1.importer import SERIALIZER_CONTEXT_BLUEPRINT, is_model_allowed
 from authentik.blueprints.v1.meta.registry import BaseMetaModel, registry
@@ -18,6 +20,23 @@
 LOGGER = get_logger()
 
 
+@converter
+class PrimaryKeyRelatedFieldConverter:
+    """Custom primary key field converter which is aware of non-integer based PKs
+
+    This is not an exhaustive fix for other non-int PKs, however in authentik we either
+    use UUIDs or ints"""
+
+    field_class = PrimaryKeyRelatedField
+
+    def convert(self, field: PrimaryKeyRelatedField):
+        model: Model = field.queryset.model
+        pk_field = model._meta.pk
+        if isinstance(pk_field, fields.UUIDField):
+            return {"type": "string", "format": "uuid"}
+        return {"type": "integer"}
+
+
 class Command(BaseCommand):
     """Generate JSON Schema for blueprints"""
 
@@ -29,7 +48,7 @@ def __init__(self, *args, **kwargs):
             "$schema": "http://json-schema.org/draft-07/schema",
             "$id": "https://goauthentik.io/blueprints/schema.json",
             "type": "object",
-            "title": "authentik Blueprint schema",
+            "title": f"authentik {__version__} Blueprint schema",
             "required": ["version", "entries"],
             "properties": {
                 "version": {
diff --git a/authentik/blueprints/v1/common.py b/authentik/blueprints/v1/common.py
--- a/authentik/blueprints/v1/common.py
+++ b/authentik/blueprints/v1/common.py
@@ -556,7 +556,11 @@ def represent(self, data) -> None:
 
             def factory(items):
                 final_dict = dict(items)
+                # Remove internal state variables
                 final_dict.pop("_state", None)
+                # Future-proof to only remove the ID if we don't set a value
+                if "id" in final_dict and final_dict.get("id") is None:
+                    final_dict.pop("id")
                 return final_dict
 
             data = asdict(data, dict_factory=factory)


Test patch: