Dynamic groups, activity intelligence, API keys, Swagger, maintenance #11
Reference in New Issue
Block a user
Delete Branch "development"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Merges the development line into main to cut a release. Includes: dynamic-group reconciliation + rule editor, activity/history, connection field fixes, attribute/value pickers, built-in schedules, trusted-proxy defaults, DB maintenance/retention, config import robustness, OpenAPI/Swagger + PowerShell example, and working API keys with read/read-write scopes.
Turns rules into Adaxes/Active-Roles style dynamic groups. The core new capability is a set-level SyncGroupMembership action that reconciles a target group's membership against the matched object set in one pass instead of the old add-only, per-object behaviour. Engine / reconciliation: - New ActionSyncGroupMembership runs once per target group after the match: resolve (and optionally create) the group, read its current members, diff against the matched set, and apply the adds/removes. - Three per-rule sync modes (types.SyncMode): FullSync (membership == matched set; removes stale members incl. manual adds), ManagedAdd (adds matches, removes only members this rule added), AddOnly (never removes). - Managed ownership tracked in a new managed_group_members table (migration 005) + repository, wired into the runner's engine so ManagedAdd removes only what it added. - Adds/removes are recorded as AddToGroup / RemoveFromGroupIfNoLongerMatched run-actions so the activity feed categorises them as syncs/removals. - Preview now computes an accurate, non-mutating diff for sync actions (+add / -remove / already-in-sync counts and per-member entries). - memberOf and memberOf-recursive (LDAP_MATCHING_RULE_IN_CHAIN) operators; Regex no longer silently degrades to equals. - Canonical group targets: CanonicalToLeafDN / NormalizeGroupTarget so a target group can be given as domain.com/OU/Group as well as a DN. Editor-facing APIs (backend-first; UI comes next): - Rule create/update now accept conditionGroups + actions and persist them via RuleRepository.ReplaceLogic (soft-delete + insert, preserving the rule_run_actions FK). Omitting them leaves existing logic untouched. - POST /api/v1/rules/preview evaluates an unsaved draft (live match panel). - GET /api/v1/rules/metadata serves the operator vocabulary (object types, operators, action types, sync modes, common attributes) so UI dropdowns stay in lock-step with the backend. - GET /api/v1/ad-connections/{id}/directory searches groups/OUs for the target pickers. Tests: reconciliation across all three modes + create-if-missing and the missing-group error path (fake directory client); canonical leaf-DN conversion; ReplaceLogic round-trip. Full suite green. Note: RuleRepository.GetByID nests a query (getConditionGroups holds a cursor while calling getConditions); safe under the production pool (25) but a follow-up should flatten it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Add two directory introspection endpoints the rule filter builder uses: - GET /ad-connections/{id}/attributes?objectType=&q= returns the schema attributes that APPLY to the given object type (User/Computer/Group). The applicable set is derived by walking the classSchema hierarchy from the object's class up through subClassOf to top, plus auxiliary classes, unioning each class's may/must-contain attributes; results are filtered by substring and returned with adminDescription. The per-(connection,object type) set is cached for 10 minutes so the walk is not repeated per keystroke. (Computer inherits user attributes, since AD's computer class subclasses user — reflected correctly.) - GET /ad-connections/{id}/attribute-values?attribute=&objectType=&q= samples objects and returns the distinct values present for one attribute, so the value field can suggest real directory values. Backed by a new bounded ldap Client.SearchWithLimit that tolerates the server's size-limit response. Attribute names are validated against the LDAP descriptor charset before use in a filter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>Database maintenance: - New MaintenanceService prunes rule_runs (+ their action detail) and audit_events older than their retention windows, then VACUUMs to reclaim space. Runs once at startup and then on an interval, bound to the run context. Configurable via ORCHESTRAD_RUN_RETENTION_DAYS (90), ORCHESTRAD_AUDIT_RETENTION_DAYS (180), ORCHESTRAD_MAINTENANCE_INTERVAL_HOURS (24), ORCHESTRAD_MAINTENANCE_VACUUM. This stops the database growing forever. (Log rotation already existed via lumberjack: ORCHESTRAD_LOG_MAX_SIZE_MB/_MAX_BACKUPS/_MAX_AGE_DAYS.) Config import: - Import now accepts either the wrapped {payload,dryRun} shape or a bare exported config object, so a file downloaded from Export re-imports directly (dryRun via ?dryRun=true) — useful for automation. Test covers retention pruning with FK-cascaded action rows. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>