ogar-dir-core / ogar-ad / ogar-az: directory observation PoC - #313
Conversation
Read-only encoding of observed Active Directory and Entra ID objects into a fixed 512-byte, NodeRow-shaped record: 128-bit source GUID (textual byte order, MS mixed-endian converted), scope GUID, an 8x16-bit OU HHTL with an explicit per-parent dictionary (no hashing, collision-free, reversible), schema family/version separate from the ABI version, out-of-line value pool, and a 64-byte GUID-pair edge record (SynchronizesTo, evidenced by onPremisesImmutableId). AD ingest via LDIF; Graph ingest via a page body with a schema-derived $select. No classid mint, no IAM semantics, no writes. Design and conflicts with the canonical NodeGuid/HHTL: docs/DIRECTORY-ADAPTERS-POC.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configuration
📒 Files selected for processing (23)
✨ Finishing Touches📝 Generate docstrings
Warning Billing warning: we have not been able to collect payment for this subscription for more than 72 hours. Please update the payment method or pay any pending invoices in Billing to avoid service interruption. Comment |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit f464dfc. Configure here.
…i-values Bugbot on #313: - ldifde -f writes 'changetype: add' after every dn; it is the export marker, not a change record. Accept it; still refuse modify/delete/modrdn. - attr_str matched any pooled kind, so a MultiStr slot came back as its length-prefixed blob. Restrict it to AttrKind::Str and add attr_multi. Both covered by new tests that failed before the fix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8f8158a1d7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if dn.has_non_ou_container() { | ||
| rec.add_flags(FLAG_NON_OU_CONTAINER); | ||
| } | ||
| match onprem_dict.intern(&dn.ou_path_root_first()) { |
There was a problem hiding this comment.
Choose the OU dictionary by on-premises domain
When one Entra tenant contains users synchronized from multiple AD domains, ingest_page passes this same dictionary to every user even though OuDictionary IDs are defined per domain and onPremisesDomainName is available on each object. Consequently, allocation order from domain A changes domain B's HHTL IDs, so domain B's Entra records no longer align with records encoded using domain B's AD-side dictionary; dispatch to a domain-specific dictionary before interning the DN.
Useful? React with 👍 / 👎.
| let s = s.trim_end_matches('='); | ||
| if s.len() % 4 == 1 { | ||
| return None; |
There was a problem hiding this comment.
Reject malformed base64 padding and trailing bits
For padded or unpadded inputs, stripping every trailing = without validating its count or the discarded bits accepts malformed encodings: for example, ==== becomes an empty value, and nonzero unused bits in the final sextet are silently ignored. In sync_edges, this means a corrupted onPremisesImmutableId can decode to the same 16 bytes as a valid anchor and produce a synchronization edge instead of being rejected; enforce legal padding and zero unused trailing bits.
Useful? React with 👍 / 👎.

Read-only PoC that encodes observed Active Directory and Entra ID objects as versioned, source-native, fixed-size records. It is not an IAM: there is no provisioning, no reconciliation, no business rules and nothing writes to Graph.
The full design is in
docs/DIRECTORY-ADAPTERS-POC.md: the exact0x000..0x1FFlayout, the OU dictionary strategy, the attribute selection and the conflicts.Crates
ogar-dir-core(no dependencies). It holds:Guid128(textual byte order, with a Microsoft mixed-endian conversion)OuHhtl(8 × u16) with a per-parentOuDictionarythat allocates ids explicitly instead of hashing themValuePool,SchemaFamily/SchemaId/AttrDefDirRecord(512 bytes, followingNodeRow's 16/16/480 split)DirEdge(64 bytes)ogar-ad: AD schema v1, an LDIF reader andencode(entry).ogar-az: Graph schema v1, a$selectderived from that schema,ingest_page,sync_edges(built fromonPremisesImmutableId), and a read-only exampleaz_ingest.Conflicts with canon (flagged, nothing changed)
NodeGuidis a minted address. The source GUID therefore lives in the value slab, and the canonical key slot is left as zero.OuHhtl(8×16) is a separate tree from HEEL/HIP/TWIG andNiblePath.0x0Bis the natural home, but that is an operator decision.NodeRowmirror is not yet guarded by a test.Verification
-D warningsand fmt are clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01G22yT6htkcdyXsihxxXdrg
Generated by Claude Code
Summary by CodeRabbit