Raw LDAP adds/modifies bypassed FreeIPA's framework, so group/user creates
failed with Object Class Violation (no gidNumber/uidNumber/ipaUniqueID) and
deletes/mods needed ACIs the bind account couldn't exercise as a plain LDAP
write. Route all MUTATIONS through the FreeIPA JSON-RPC API instead; reads
stay on direct LDAP.
- internal/client/freeipa.go: new JSON-RPC client (form login_password →
ipa_session cookie, re-auth on 401, multi-server failover, TLS via the
configured CA). Derives the API host + login uid from the LDAP config.
- internal/service/ldap.go: CreateGroup/UpdateGroup/DeleteGroup/AddGroupMembers/
RemoveGroupMember → group_add/_mod/_del/_add_member/_remove_member;
CreateUser/UpdateUser/DisableUser/ResetPassword → user_add/_mod/_disable
(+_enable)/passwd. Services map → addattr(objectclass)/setattr. Writes error
cleanly when the IPA client is unconfigured.
- cmd/server/main.go: build the FreeIPA client from the LDAP config and inject
it into the LDAP service.
Verified live: group create (IPA-assigned gidNumber), get, add/remove member,
delete all succeed; reads unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This repo had no version control prior to this commit. The import is a
straight snapshot of the working tree at 2026-05-03; the deployed
binary on fihelvop01 was being rebuilt from this source via `make
build` + scp into place, with no upstream review path.
The snapshot already includes one in-flight fix made on 2026-05-03 to
internal/service/persona.go:GetSelfModel — the handler queried
`source` and `strength` columns plus an `is_active = true` filter on
persona.persona_commitments, none of which exist on that table (its
shape is session-bound commitments with `status`, `commitment_meta`,
etc.). The query returned a 500 every time SynapseHub bootstrapped a
persona's self-model, dropping the IdentityConstraints / Commitments /
ConscienceStandards layer from the assembled prompt. The patched
query reads existing columns only (commitment_text, commitment_type),
filters on `status='active'`, and synthesises Source="learned" /
Strength=1.0 to keep the SelfModel response shape stable for callers.
Verified live: `GET /api/v1/personas/70f7cfd9-.../self-model` now
returns 200 with `{identityConstraints:[],commitments:[],
conscienceStandards:[]}` instead of 500.
Future changes go through PRs against this repo — no more bin-only
deploys.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>