Add: LDAP schema move from models to directories#958
Add: LDAP schema move from models to directories#958milov-dmitriy wants to merge 47 commits intodevfrom
Conversation
…ma_move_from_models_to_directories
…ma_move_from_models_to_directories
…ma_move_from_models_to_directories
There was a problem hiding this comment.
Pull request overview
This PR continues the migration of LDAP schema handling from in-model entities to directory-backed storage, introducing new schema directory creation use-cases and “deprecated” appendix DAOs/use-cases to support migration paths.
Changes:
- Reworked
AttributeType/ObjectClasspersistence to rely onDirectory+Attributerows, with new “create directory like …” use-cases. - Updated LDAP search/subschema generation to use schema use-cases and raw-definition renderers (
*RawDisplay). - Adjusted setup/migrations/tests to seed schema and entity types accordingly (with several tests temporarily stubbed).
Reviewed changes
Copilot reviewed 62 out of 64 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tests/test_shedule.py | Switches test dependency from DAO to EntityType use-case. |
| tests/test_ldap/test_util/test_search.py | Temporarily disables some LDAP utility integration tests. |
| tests/test_ldap/test_util/test_modify.py | Temporarily disables some modify-related integration tests. |
| tests/test_ldap/test_util/test_add.py | Temporarily disables ldapadd access-control integration test. |
| tests/test_ldap/test_roles/test_search.py | Temporarily disables multiple role-based search tests. |
| tests/test_ldap/test_roles/test_multiple_access.py | Temporarily disables multiple-ACE role test. |
| tests/test_ldap/test_ldap_schema/test_attribute_type_use_case.py | Updates replication-flag tests to create test attribute types first. |
| tests/test_ldap/test_ldap3_definition_parse.py | Updates raw-definition parsing tests to operate on DTOs + RawDisplay renderers. |
| tests/test_api/test_main/test_router/test_search.py | Expands expected subtree dirs to include Configuration. |
| tests/test_api/test_main/test_router/conftest.py | Updates test setup to use EntityTypeUseCase in SetupGateway wiring. |
| tests/test_api/test_ldap_schema/test_object_class_router.py | Adjusts pagination size; temporarily disables part of modification assertions. |
| tests/test_api/test_ldap_schema/test_attribute_type_router_datasets.py | Uses AttributeTypeUpdateSchema objects for patch datasets. |
| tests/test_api/test_ldap_schema/test_attribute_type_router.py | Uses model_dump() for patch JSON, adjusts page size. |
| tests/test_api/test_auth/test_router.py | Adds setup_session fixture for disabled-user auth test. |
| tests/constants.py | Adds configuration directory + explicit entity_type_name fields across test seed data. |
| tests/conftest.py | Major test-container wiring changes for new schema flow + deprecated appendix use-cases. |
| interface | Updates git submodule pointer. |
| docker-compose.test.yml | Adds -W ignore::SyntaxWarning during pytest in container. |
| app/repo/pg/tables.py | Imports schema entities from entities_appendix instead of entities. |
| app/ldap_protocol/utils/raw_definition_parser.py | Refactors raw-definition parser to produce DTOs (no DB session). |
| app/ldap_protocol/policies/password/dao.py | Minor formatting change for create() signature. |
| app/ldap_protocol/ldap_schema/object_class_use_case.py | Moves object-class creation logic to directory-backed creation + validation. |
| app/ldap_protocol/ldap_schema/object_class_raw_display.py | New: render ObjectClass DTO as RFC4512-style raw definition. |
| app/ldap_protocol/ldap_schema/object_class_dir_create_use_case.py | New: creates object-class directories under Configuration. |
| app/ldap_protocol/ldap_schema/object_class_dao.py | Reworks DAO to read from Directories/Attributes instead of schema tables. |
| app/ldap_protocol/ldap_schema/entity_type_use_case.py | Adds attach-to-directories logic and optional validation bypass for first setup. |
| app/ldap_protocol/ldap_schema/entity_type_dao.py | Removes DAO-level attach logic; shifts object-class validation out of DAO. |
| app/ldap_protocol/ldap_schema/constants.py | Removes compiled regex constant; keeps pattern. |
| app/ldap_protocol/ldap_schema/attribute_type_use_case.py | Reworks attribute-type creation via directory-backed creation and deprecated exceptions. |
| app/ldap_protocol/ldap_schema/attribute_type_raw_display.py | New: render AttributeType DTO as RFC4512-ish raw definition. |
| app/ldap_protocol/ldap_schema/attribute_type_dir_create_use_case.py | New: creates attribute-type directories under Configuration. |
| app/ldap_protocol/ldap_schema/attribute_type_dao.py | Reworks DAO to read from Directories/Attributes instead of schema tables. |
| app/ldap_protocol/ldap_schema/appendix/object_class_appendix/object_class_appendix_use_case.py | New: deprecated object-class use-case for migration. |
| app/ldap_protocol/ldap_schema/appendix/object_class_appendix/object_class_appendix_dao.py | New: deprecated object-class DAO for migration + table drop helper. |
| app/ldap_protocol/ldap_schema/appendix/attribute_type_appendix/attribute_type_appendix_use_case.py | New: deprecated attribute-type use-case for migration. |
| app/ldap_protocol/ldap_schema/appendix/attribute_type_appendix/attribute_type_appendix_dao.py | New: deprecated attribute-type DAO for migration + table drop helper. |
| app/ldap_protocol/ldap_requests/search.py | Switches subschema generation to use schema use-cases + RawDisplay. |
| app/ldap_protocol/ldap_requests/modify.py | Switches entity-type attach from DAO to use-case. |
| app/ldap_protocol/ldap_requests/contexts.py | Updates request contexts to carry schema use-cases and EntityTypeUseCase. |
| app/ldap_protocol/ldap_requests/add.py | Switches entity-type lookup/attach from DAO to use-case. |
| app/ldap_protocol/filter_interpreter.py | Reworks ANR attribute lookup to query directory-backed attribute-type flags. |
| app/ldap_protocol/auth/use_cases.py | Seeds new directory-based schema from deprecated tables during setup. |
| app/ldap_protocol/auth/setup_gateway.py | Uses EntityTypeUseCase to attach entity types during environment setup. |
| app/ioc.py | Adds wiring for deprecated appendix DAOs/use-cases and dir-create use-cases. |
| app/extra/scripts/add_domain_controller.py | Uses EntityTypeUseCase instead of EntityTypeDAO. |
| app/extra/alembic_utils.py | Adds temporary_stub_column2() helper for migrations. |
| app/enums.py | Adds EntityTypeNames for Configuration/Attribute Type/Object Class; removes auth rule constant. |
| app/entities_appendix.py | New: deprecated schema dataclasses (AttributeType/ObjectClass). |
| app/entities.py | Moves schema dataclasses out; keeps AttributeType type via appendix import. |
| app/constants.py | Adds Configuration dir in first setup data + entity types for schema entities. |
| app/api/ldap_schema/schema.py | Switches constants import to API-local constants module. |
| app/api/ldap_schema/attribute_type_router.py | Formatting-only change for update call. |
| app/api/ldap_schema/adapters/object_class.py | Replaces adaptix converter with manual mapping supporting Directory/DTO. |
| app/api/ldap_schema/adapters/entity_type.py | Switches constants import to API-local constants module. |
| app/api/ldap_schema/adapters/attribute_type.py | Switches constants import to API-local constants module. |
| app/alembic/versions/f24ed0e49df2_add_filter_anr.py | Migration now uses deprecated use-case via dishka + add temp stub column. |
| app/alembic/versions/c4888c68e221_fix_admin_attr_and_policy.py | Uses EntityTypeUseCase for attaching entity types during migration. |
| app/alembic/versions/ba78cef9700a_initial_entity_type.py | Uses EntityTypeUseCase; defers creation of new schema-related entity types. |
| app/alembic/versions/759d196145ae_.py | New migration to create new schema-related entity types + copy schema to directories. |
| app/alembic/versions/2dadf40c026a_add_system_flags_to_attribute_types.py | Migration now uses deprecated use-case for replication flags. |
| app/alembic/versions/275222846605_initial_ldap_schema.py | Refactors initial schema seed to use DTO collection + deprecated use-cases. |
| app/alembic/versions/01f3f05a5b11_add_primary_group_id.py | Uses EntityTypeUseCase for directory entity-type attachment in migration. |
Comments suppressed due to low confidence (8)
app/ldap_protocol/utils/raw_definition_parser.py:1
tmp.values()yieldsAttributeTypeInfo/ObjectClassInfoobjects, but_list_to_string()is meant for iterables of strings and returnsstr | None. As written, both methods will return the wrong type (and may returnNone) despite their return annotations, breaking parsing at runtime. Fix by returning the single parsed info object directly (e.g., pick the only value from the mapping) and keep_list_to_string()for actual string-list fields likeinfo.name/info.superior.
app/ldap_protocol/utils/raw_definition_parser.py:1- This error message is misleading in the object-class path (
collect_object_class_dto_from_info). It should reference 'Object Class name' (not 'Attribute Type name') to help diagnose parsing failures correctly.
app/ldap_protocol/ldap_schema/entity_type_use_case.py:1 EntityTypeUseCaseusesself.__session, but the diff does not show it being initialized in__init__. This will raiseAttributeErrorwhenattach_entity_type_to_directories()runs (e.g., from migrations). InjectAsyncSessioninto the use-case (like other use-cases) and assign it, or refactor to execute these queries via a DAO that owns the session.
app/ldap_protocol/ldap_schema/object_class_dir_create_use_case.py:1- This uses the loop variable
valuefrom the priorfor value in valuesloop, so theisinstance(value, str)check is unrelated todir_.object_classand will be wrong (or even reference a stale value). Usedir_.object_classconsistently in the check (as done in the AttributeType variant), or remove this extraobjectClassinsertion entirely ifdata['attributes']['objectClass']already sets it. Also consider settingDirectory.object_classto a meaningful value (e.g.,classSchema) instead of\"\"to avoid creating an emptyobjectClassattribute.
app/ldap_protocol/ldap_schema/object_class_dao.py:1 - This update path is inconsistent with the new directory-backed schema storage:
self.get(name)returns a DTO, so mutatingobj.attribute_types_*won't persist changes. Additionally,AttributeTypehere is imported fromentities_appendix(a dataclass), soselect(AttributeType)is not a valid SQLAlchemy selectable and will fail at runtime. To fix, load the underlyingDirectory+ itsAttributerows (viaget_dir()), then update/replace the appropriateAttributerecords (attribute_types_must/attribute_types_may,superior_name, etc.), and flush.
app/ldap_protocol/ldap_schema/object_class_dao.py:1 - The method name
get_object_class_names_include_attribute_type1looks like a temporary name and is unclear/confusing. Rename it to a stable API name (or remove it if superseded byget_object_class_names_include_attribute_type).
tests/test_ldap/test_util/test_search.py:1 - Early
returneffectively disables the test while still reporting it as passed, which can hide regressions in the schema-migration work. Preferpytest.skip(\"TODO: ...\")(orpytest.mark.xfail) so the test suite clearly reports the missing coverage; the same applies to the other newly-added early returns in this PR.
docker-compose.test.yml:1 - Ignoring
SyntaxWarningin CI can mask real issues introduced by the refactor (especially around SQLAlchemy queries and deprecated APIs). Consider removing this ignore, or narrowing it to a specific known warning source (module/class) so newly introduced warnings still fail or are visible.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 62 out of 64 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (11)
app/ldap_protocol/utils/raw_definition_parser.py:1
_get_attribute_type_info()/get_object_class_info()now return_list_to_string(tmp.values()), but_list_to_string()returnsstr | None(and is intended for strings), notAttributeTypeInfo/ObjectClassInfo. This will break parsing at runtime. Restore returning the single...Infoinstance (e.g., take the only element fromtmp.values()), or generalize_list_to_string()with a TypeVar so it can return the single element of any iterable while preserving the return type.
app/ldap_protocol/utils/raw_definition_parser.py:1- The error message is incorrect for this context: this is parsing an Object Class name, but it raises
ValueError(\"Attribute Type name is required\"). Update the message to refer to the Object Class name to make debugging actionable.
app/ldap_protocol/ldap_schema/object_class_dir_create_use_case.py:1 valuehere comes from thefor name, values in data[\"attributes\"].items(): for value in values:loop above, so after the loop it will be the last iterated attribute value (or may be undefined if attributes is empty). This makes theobjectClassattribute value incorrect/non-deterministic. Usedir_.object_class(and checkisinstance(dir_.object_class, str)), or explicitly set the intended objectClass value(s) without relying on a loop-scoped variable.
app/ldap_protocol/ldap_schema/object_class_dao.py:1attributes_dict.get(\"...\")can returnNone, and indexing[0]will raiseTypeError. This is especially likely for optional fields likesuperior_name. Consider using a safe default (e.g.,dir_.attributes_dict.get(\"superior_name\", [None])[0]) and similarly guard required fields with a clearer error when missing.
app/ldap_protocol/ldap_schema/object_class_dao.py:1update()now loadsobjviaself.get(name), which returns anObjectClassDTO, not a mutable ORM model/Directory entity. The method then tries to mutateobj.attribute_types_mustwith ORMAttributeTypeobjects, which will either fail (DTO shape) or corrupt the DTO type (list[str]vslist[AttributeType]). Refactorupdate()to load and mutate the underlyingDirectory+Attributerows (or delegate updates to the new Directory-backed create/update use case) instead of using the DTO.
app/ldap_protocol/ldap_schema/object_class_dao.py:1update()now loadsobjviaself.get(name), which returns anObjectClassDTO, not a mutable ORM model/Directory entity. The method then tries to mutateobj.attribute_types_mustwith ORMAttributeTypeobjects, which will either fail (DTO shape) or corrupt the DTO type (list[str]vslist[AttributeType]). Refactorupdate()to load and mutate the underlyingDirectory+Attributerows (or delegate updates to the new Directory-backed create/update use case) instead of using the DTO.
app/ldap_protocol/ldap_schema/attribute_type_dao.py:1get_all()converts eachDirectoryusingattributes_dict, but the query does not eager-loadDirectory.attributes. That risks N+1 lazy loads and may produce incompleteattributes_dictdepending on how it's computed. Align with other queries in this PR by addingselectinload(qa(Directory.attributes))(and any other required relationships) before converting.
app/ldap_protocol/ldap_schema/attribute_type_use_case.py:1set_attr_replication_flag()still exists on the use case, but its permission mapping was removed. If authorization enforcement relies onPERMISSIONS, this creates an authorization gap or breaks expected policy checks. Either re-add a permission mapping forset_attr_replication_flag(and keep/restore the correspondingAuthorizationRulesentry), or remove/relocate the method if it is intentionally no longer part of the public service surface.
app/ldap_protocol/ldap_schema/object_class_use_case.py:1superior_nameis always stored as[str(dto.superior_name)]. Whendto.superior_nameisNone, this persists the literal string'None', which will later be treated as a real superior name. Only includesuperior_namewhen it is notNone, or store an empty list/omit the attribute entirely.
tests/test_ldap/test_util/test_search.py:1- Returning early from a test makes it pass without exercising behavior or assertions, which can hide regressions in CI. Prefer
pytest.skip(\"...\")(explicitly marking it as skipped with a reason) orpytest.xfail(\"...\")if it is expected to fail until the refactor is complete.
docker-compose.test.yml:1 - Ignoring
SyntaxWarningglobally can mask real issues (especially around invalid escapes, deprecated syntax, or runtime parsing warnings) and makes the test signal weaker. Consider scoping the filter to the specific warning source/module or fixing the underlying warnings instead of suppressing them across the entire test run.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 82 out of 84 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (11)
app/ldap_protocol/ldap_schema/entity_type/entity_type_use_case.py:1
EntityTypeUseCasecallsself.__session.execute(...), but__sessionis never defined/initialized in this class (only DAOs are injected). This will raiseAttributeErrorat runtime. InjectAsyncSessioninto the use-case (and assign it), or rewrite the method to execute via the DAO (e.g., add a DAO method to fetch directories missingentity_type_id).
app/ldap_protocol/ldap_schema/object_class/object_class_dir_create_use_case.py:1- This uses the loop variable
valuefrom the priorfor value in values:loop, so theisinstance(value, str)check depends on the last attribute value seen, not ondir_.object_class. This can incorrectly storeNULLforobjectClass. Usedir_.object_classconsistently (as in the attribute-type dir-create use-case) and avoid referencing the prior loop variable.
app/ldap_protocol/ldap_schema/object_class/object_class_use_case.py:1 - Two schema fields are being serialized in a way that can persist invalid values into LDAP-like storage: (1)
superior_namebecomes the string'None'whendto.superior_name is None; (2)kindis stored viastr(dto.kind)which for Enums typically yields'KindType.STRUCTURAL'rather than the expected value (e.g.'STRUCTURAL'). Only includesuperior_namewhen it is notNone, and serializekindusingdto.kind.value(or otherwise the enum value that the DTO/API expects).
app/ldap_protocol/ldap_schema/object_class/object_class_dao.py:1 dir_.attributes_dict.get('superior_name')(andkind) can beNoneor an empty list depending on how the Directory entry was created/seeded. Indexing[0]will raiseTypeError/IndexError. Handle optional attributes safely (e.g., default toNonewhen the key is missing or list is empty), matching the DTO's optionality forsuperior_name.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_dao.py:1- Per the docstring,
is_included_anrshould be modifiable for all attributes (system and non-system). In the current logic,is_included_anris only updated for system attributes, and never updated for non-system attributes. Updateis_included_anrregardless ofdir_.is_system(and restrict onlysyntax/single_value/no_user_modificationfor system attributes).
app/ldap_protocol/utils/raw_definition_parser.py:1 _list_to_stringis typed asIterable[str] -> str|None, but it is used withtmp.values()where elements areAttributeTypeInfo/ObjectClassInfo, and the callers annotate the return type asAttributeTypeInfo/ObjectClassInfo. This is a type/contract mismatch that can hide real bugs (including returningNone). Consider making the helper generic (e.g.,Iterable[T] -> T) and raising a clearer error when the iterable is empty.
app/ldap_protocol/utils/raw_definition_parser.py:1_list_to_stringis typed asIterable[str] -> str|None, but it is used withtmp.values()where elements areAttributeTypeInfo/ObjectClassInfo, and the callers annotate the return type asAttributeTypeInfo/ObjectClassInfo. This is a type/contract mismatch that can hide real bugs (including returningNone). Consider making the helper generic (e.g.,Iterable[T] -> T) and raising a clearer error when the iterable is empty.
app/ldap_protocol/utils/raw_definition_parser.py:1_list_to_stringis typed asIterable[str] -> str|None, but it is used withtmp.values()where elements areAttributeTypeInfo/ObjectClassInfo, and the callers annotate the return type asAttributeTypeInfo/ObjectClassInfo. This is a type/contract mismatch that can hide real bugs (including returningNone). Consider making the helper generic (e.g.,Iterable[T] -> T) and raising a clearer error when the iterable is empty.
app/ldap_protocol/utils/raw_definition_parser.py:1- This error message is incorrect for the object-class code path: it says 'Attribute Type name is required' while validating an Object Class name. Update the message to 'Object Class name is required' (or similar) to aid debugging.
app/extra/alembic_utils.py:1 - If
func(*args, **kwargs)raises, the temporary stub column will never be dropped, potentially leaving the DB in an inconsistent state for subsequent retries. Wrap the call intry/finallysoop.drop_column(...)always executes.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_use_case.py:1 set_attr_replication_flagremains a public use-case method that mutates schema state, but it is no longer present in thePERMISSIONSmapping. If authorization is enforced viaAbstractService.PERMISSIONS, this can accidentally remove protection for this operation (or make it inconsistently enforced). Either add a dedicated authorization rule back and include it inPERMISSIONS, or make the method private/internal if it should not be externally callable.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 87 out of 89 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (8)
app/ldap_protocol/ldap_schema/raw_definition_parser.py:1
_get_attribute_type_info()/get_object_class_info()returnstr | None(via_list_to_string) but are annotated/used asAttributeTypeInfo/ObjectClassInfo. This will crash later when accessing fields like.name/.oid. Return the parsed info object (e.g., first element oftmp.values()), and keep_list_to_stringonly for converting lists of names/superiors.
app/ldap_protocol/ldap_schema/entity_type/entity_type_use_case.py:1EntityTypeUseCaseusesself.__sessionbut the class never defines/initializes__session. Callingattach_entity_type_to_directories()will raiseAttributeError. InjectAsyncSessioninto this use-case (like other use-cases), or execute via a DAO method that already owns the session.
app/ldap_protocol/ldap_schema/object_class/object_class_use_case.py:1superior_nameis optional, but it is always persisted withvalues=[str(dto.superior_name)]. Whendto.superior_name is None, this stores the literal string'None', which breaks semantic meaning and will leak into API responses / LDAP raw definitions. Buildattributesdynamically: only includesubClassOfwhendto.superior_nameis notNone(and/or store an empty values list, depending on howattributes_dictis expected to behave).
app/ldap_protocol/ldap_schema/object_class/object_class_dao.py:1attributes_dict.get(...)can returnNone(or an empty list), and indexing[0]will raise at runtime. This is especially relevant for optional fields likeSUPERIOR_NAME(root object classes). Consider using safer defaults (e.g.,superior_vals = ...get(..., [])thensuperior_name = superior_vals[0] if superior_vals else None) and similarly guard required fields with a clearerObjectClassNotFoundError/validation error if missing.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_dao.py:1- The docstring states ANR (
is_included_anr) can be modified for all attributes (including system ones). Current logic updates ANR only for system attributes, but for non-system attributes it never updatesNames.IS_INCLUDED_ANR. Update the loop to always handleIS_INCLUDED_ANR, while still restrictingSYNTAX/SINGLE_VALUE/NO_USER_MODIFICATIONupdates to non-system attributes.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_use_case.py:1 set_attr_replication_flag()is still a public method on the service, but it is missing from thePERMISSIONSmap. If authorization is enforced viaAbstractService.PERMISSIONS, this can lead to the endpoint being unintentionally unprotected or unintentionally blocked (depending on framework behavior). Add an explicit permission mapping forset_attr_replication_flag(and ensure the correspondingAuthorizationRulesvalue still exists).
app/ldap_protocol/roles/migrations_ace_dao.py:1- This performs one
UPDATEstatement per ACE row, which can be slow on large datasets during migration. Prefer a single bulk update strategy (e.g.,UPDATE ... FROM (VALUES ...)/ temporary table join, or aCASEexpression keyed by ACE id) to reduce round-trips and transaction time.
app/ldap_protocol/ldap_schema/raw_definition_parser.py:1 - This error is raised while collecting an ObjectClass DTO, but the message says "Attribute Type name is required". Update it to something like "Object Class name is required" to make debugging accurate.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 87 out of 89 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (10)
app/ldap_protocol/ldap_schema/entity_type/entity_type_use_case.py:1
EntityTypeUseCaseusesself.__session, but no session field is defined/initialized in this class. This will raiseAttributeErrorat runtime (and affects multiple migrations callingattach_entity_type_to_directories). InjectAsyncSessioninto the use-case (like other use-cases), or move the query/flush logic into the DAO which already owns the session.
app/ldap_protocol/ldap_schema/object_class/object_class_use_case.py:1- When
dto.superior_nameisNone, this stores the literal string'None'assubClassOf. That will leak into API responses and LDAP raw definitions (e.g.,SUP None) and breaks the meaning of “no superior”. MakeSUPERIOR_NAMEattribute conditional: only include it whendto.superior_nameis notNone(or store an empty list / omit the attribute).
app/ldap_protocol/ldap_schema/object_class/object_class_dao.py:1 superior_name=dir_.attributes_dict.get(...)[0]will throw whensubClassOfis absent (which is valid for root object classes). This will also blow up if earlier migrations accidentally omit the attribute. Handle absence explicitly (e.g., read the list via.get(..., [])and setsuperior_name=Nonewhen empty), and consider normalizing a stored'None'string back toNonewhile data is being migrated.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_dao.py:1- The docstring above says ANR inclusion can be modified for all attributes (including non-system). Current logic updates
aNRonly for system attributes and never updates it for non-system attributes. Update the logic soNames.IS_INCLUDED_ANRis handled regardless ofdir_.is_system, while keeping the restrictions forsyntax/single_value/no_user_modificationon system attributes.
app/ldap_protocol/roles/migrations_ace_dao.py:1 - Unmapped ACEs are silently skipped (
if row.name in directory_by_name). After the FK is switched toDirectory.id, any remaining legacy ids inAccessControlEntries.attributeTypeIdcan cause foreign key violations (or worse: point to unrelated directories if IDs overlap). Consider enforcing completeness (raise if anyrow.nameis missing), or explicitly settingattribute_type_idtoNULLfor unmapped rows, or creating missingATTRIBUTE_TYPEdirectories before rebinding.
app/ldap_protocol/roles/migrations_ace_dao.py:1 - This performs one UPDATE per ACE row, which can be slow on large datasets. Prefer a bulk update strategy (e.g., executemany with bind params, or a single
UPDATE ... FROM (VALUES ...)style statement) to reduce roundtrips and lock time during migrations.
app/ldap_protocol/ldap_schema/raw_definition_parser.py:1 - The error message is incorrect for this context: this is parsing an ObjectClass definition, not an AttributeType. Please change it to something like
Object Class name is requiredto make debugging clearer.
app/ldap_protocol/ldap_schema/schema_create_use_case.py:1 - Selecting the Configuration container by
Directory.namealone is ambiguous: regular user data could also contain acn=Configurationsomewhere else. Since this method defines the parent for all schema directories, it should be uniquely identified (e.g., joinEntityTypeand requireEntityType.name == EntityTypeNames.CONFIGURATION, and/or constrain by being a base child). Otherwise schema objects may be created under the wrong subtree.
docker-compose.test.yml:1 - Ignoring
SyntaxWarningin the test runner can hide real issues (e.g., invalid escapes in regex strings) and make regressions harder to detect. Consider fixing the underlying warnings and removing this filter, or scoping it to the specific module/message that triggers the warning.
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_use_case.py:1 set_attr_replication_flagis still part of the use-case API, but it is not included in thePERMISSIONSmapping anymore. If authorization relies onAbstractService.PERMISSIONS, this can lead to inconsistent access control (e.g., missing permission enforcement or runtime errors when resolving permissions). Either add an appropriate permission mapping back, or remove/relocate this method if it’s intentionally no longer exposed.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 88 out of 90 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (7)
app/ldap_protocol/ldap_schema/entity_type/entity_type_use_case.py:1
EntityTypeUseCaseusesself.__session, but the session is never set in__init__, so callingattach_entity_type_to_directories()will raiseAttributeErrorat runtime. Fix by injectingAsyncSessioninto the constructor (like other use-cases) and assigning it toself.__session, or by moving the query logic intoEntityTypeDAO(which already has a session) and calling it from the use-case.
app/ldap_protocol/ldap_schema/object_class/object_class_use_case.py:1- When
dto.superior_nameisNone, this stores the literal string'None'in Directory attributes, which breaks the API contract (superior_nameshould be null/None, not'None'). Recommended fix: only include theSUPERIOR_NAMEattribute whendto.superior_nameis not None (or use an emptyvalues=()and adjust DAO conversion accordingly).
app/ldap_protocol/ldap_schema/object_class/object_class_dao.py:1 attributes_dict.get(...)[0]will throw when the key is missing (e.g.,superior_nameis optional). This also returns raw strings for fields that are likely enums (kind) and should be converted consistently. Suggested fix: use safe defaults (e.g.NoneforSUPERIOR_NAME) and explicitly coerce/validate types (e.g. mapkindstring back toKindType).
app/ldap_protocol/ldap_schema/attribute_type/attribute_type_dao.py:1- The docstring says ANR inclusion can be modified for all attributes (including system ones), but the implementation only updates
aNRfor system attributes and never updates it for non-system attributes. Also,breakstops scanning attributes early, which is risky if other update logic is added later. Fix: updateaNRregardless ofdir_.is_system, and keep the system/non-system restriction only forsyntax/single_value/no_user_modification.
app/ldap_protocol/roles/migrations_ace_dao.py:1 - This migration updates ACE rows one-by-one, which can be very slow on large databases. Prefer a set-based update (e.g., a single
UPDATE ... FROMjoin betweenAccessControlEntriesandDirectory/EntityType, or aCASE WHENupdate over a VALUES table) to reduce round-trips and lock time.
app/ldap_protocol/ldap_schema/raw_definition_parser.py:1 - The error message is misleading for object class parsing (
collect_object_class_dto_from_info): it should refer to the object class name (e.g., 'Object Class name is required') rather than 'Attribute Type'.
docker-compose.test.yml:1 - Ignoring
SyntaxWarningin CI can mask real issues (including invalid escape sequences and some forward-compat problems). Prefer fixing the underlying warnings and keeping CI strict, or suppress only specific known-warning modules/lines if needed.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Нужно перевести представление LDAP схемы из двух таблиц (не считая двух линковочных)
AttributeTypesиObjectClassesна Директории, т.е. чтобы было полностью по аналогии.!!! Обязательное требование: API ручки не трогать, не менять, контракты оставить прежними.
Задача: 1258