Commit Graph

4 Commits

Author SHA1 Message Date
Alphaeus Mote 429e8bd398 fix(rules): record last run outcome on the rule row
The runner updated the rule_runs history but never wrote the rules table's
last_run_utc / last_run_result columns, so the rules list showed blank Last
Run / Last Result. Add RuleRepository.UpdateLastRun and call it from the
runner's finalize and fail paths with the run's completion time and status.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 17:48:27 -04:00
Alphaeus Mote 5920b690d1 feat(rules): dynamic-group reconciliation + editor-facing APIs
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>
2026-09-02 14:57:30 -04:00
GraceSolutions 807b95e92a feat(api): add rule preview and run endpoints
Adds RulesHandler exposing POST /api/v1/rules/{id}/preview and
POST /api/v1/rules/{id}/run. Preview returns the generated LDAP filter,
matched objects, and planned actions. Run triggers an immediate execution
via the Runner using the X-Triggered-By header (defaults to 'api').

Also adds Runner.PreviewRule so the handler can delegate without having to
load the rule, connection, and LDAP client itself.
2026-04-23 12:16:37 -04:00
GraceSolutions bca862ca01 feat(rules): implement end-to-end rule execution pipeline
- Add engine.Execute() that searches AD, iterates matches, runs actions,
  honors StopOnError and PreviewOnly, and supports context cancellation
- Resolve base DN and search scope from rule override then connection defaults
- Add actionExecutor covering AddToGroup, AddGroupToGroup, EnsureGroupExists,
  MoveToOu, and RemoveFromGroupIfNoLongerMatched with dynamic DN expansion
- Add RuleRunRepository persisting rule_runs and rule_run_actions
- Add Runner coordinator that loads rule+connection, builds an LDAP client,
  invokes the engine, and records the run + per-action outcomes
- Expose ConnectionService.BuildClient / BuildLDAPConfig for reuse
- Scheduler now accepts a RuleRunner and invokes it when a scheduled rule fires
2026-04-23 12:12:59 -04:00