Schema: ldapSyntaxes, X- extension flags, SUP-chain syntax resolution - #63
Merged
Conversation
The neutral mechanics a consumer needs to classify attribute values from a server's schema (issue #61); the binary-vs-text policy itself stays with consumers by design. - LdapSyntax (RFC 4512 §4.1.5): OID, DESC, X- extensions, plus NAME — not in the RFC grammar, but slapd accepts it and its own shipped pmi.schema uses it (slaptest-verified; the vendored corpus caught this the moment the ldapsyntax directive started parsing). NotHumanReadable and BinaryTransferRequired read OpenLDAP's X- extensions with the TRUE-only rule implemented once: a published 'FALSE' is not an assertion. - Parsed from all three inputs: slapd.conf ldapsyntax directives (slaptest-verified that slapd accepts them), strict LdapSyntax.Parse, and a lenient ParseSubschema overload taking ldapSyntaxes values (bucketed into UnparsedDefinitions with the new Syntax kind on failure). - FindSyntax strips {bound} before lookup — OpenLDAP publishes bounded SYNTAX references, and the bound is not part of the OID's identity; one StripLengthBound implementation now serves the SYNTAX keyword parser and the lookup. - ResolveSyntaxOid walks the SUP chain (cycle-guarded with a visited set): OpenLDAP publishes cn as "SUP name" with no SYNTAX, so reading Syntax alone leaves most of a live schema unresolved. The generator's private depth-capped twin is deleted in favor of it. - AttributeDescription (core): TypeOf ("cn;lang-en" -> "cn"), HasOption (";binary", case-insensitive per RFC 4512 §2.5), and IsValid — the writer's private definition made public, with the writer now calling it. The issue's bare-OID accessor item needed no code: LdapAttributeType.Syntax has stripped bounds since the parser landed, pinned by an existing test. Proven against the captured OpenLDAP 2.6 fixture (33 ldapSyntaxes values, zero unparsed; cn resolves to Directory String through real published data) and against a live slapd in the differential suite, which was run in a Linux container before pushing. Closes #61. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e pins From adversarial review of the previous commit (4 of 9 findings accepted, the rest refuted or surfaced as pre-existing questions): - Parses_every_schema_in_corpus claimed "nothing silently dropped" while its line-scan counted only attribute types and object classes; ldapsyntax definitions are now counted and asserted the same way. - The "slaptest-verified" comments are now a CI assertion instead: a new differential test runs slaptest against the vendored pmi.schema — the file whose ldapsyntax NAME extension forced the parser beyond RFC 4512 — pinning both sides of the "we accept what slapd accepts" claim. - The undefined multi-valued flag-extension case is pinned: the first value is the assertion, matching the consumer parser this API supersedes. - The three-parameter ParseSubschema overload's null guards get direct tests, matching the two-parameter overload's. Surfaced, not fixed (pre-existing, deliberate-looking): RfcGrammar's IsNumericOid implements RFC 2849's ldap-oid (leading-zero arcs allowed), which is looser than RFC 4512's numericoid; tightening it would be a cross-cutting behavior change shared by LDIF and schema parsing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… rule The flag-extension pin now exercises BinaryTransferRequired alongside NotHumanReadable, its comment claims only what is witnessed (the captured corpus and the consumer parser's read of values[0], not "every observed server"), and the slaptest test's comment says what it actually pins: slapd's acceptance of the one file that motivated the NAME extension, not the parser's general compatibility. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
joshmakestuff
added a commit
that referenced
this pull request
Aug 3, 2026
) IsNumericOid deliberately implements RFC 2849's looser ldap-oid grammar (leading-zero arcs, single-arc OIDs) rather than RFC 4512's numericoid. That is spec-correct on every LDIF boundary (control OIDs, attribute descriptions), and empirically matched to slapd on the schema boundary: slaptest against OpenLDAP 2.6.10 (2026-08-03) accepted attributetype directives with 01.2.3.4.5, 1.02.3, and bare 1. Tightening toward RFC 4512 would reject schema files slapd loads. Raised as a finding in PR #63's adversarial review and surfaced there for a ruling; ruled working-as-intended on the probe evidence. These tests turn that ruling into something that fails the build if someone later "fixes" the grammar without re-probing slapd. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
joshmakestuff
added a commit
that referenced
this pull request
Aug 4, 2026
IsNumericOid deliberately implements RFC 2849's looser ldap-oid grammar (leading-zero arcs, single-arc OIDs) rather than RFC 4512's numericoid. That is spec-correct on every LDIF boundary (control OIDs, attribute descriptions), and empirically matched to slapd on the schema boundary: slaptest against OpenLDAP 2.6.10 (2026-08-03) accepted attributetype directives with 01.2.3.4.5, 1.02.3, and bare 1. Tightening toward RFC 4512 would reject schema files slapd loads. Raised as a finding in PR #63's adversarial review and surfaced there for a ruling; ruled working-as-intended on the probe evidence. These tests turn that ruling into something that fails the build if someone later "fixes" the grammar without re-probing slapd.
joshmakestuff
added a commit
that referenced
this pull request
Aug 4, 2026
) IsNumericOid deliberately implements RFC 2849's looser ldap-oid grammar (leading-zero arcs, single-arc OIDs) rather than RFC 4512's numericoid. That is spec-correct on every LDIF boundary (control OIDs, attribute descriptions), and empirically matched to slapd on the schema boundary: slaptest against OpenLDAP 2.6.10 (2026-08-03) accepted attributetype directives with 01.2.3.4.5, 1.02.3, and bare 1. Tightening toward RFC 4512 would reject schema files slapd loads. Raised as a finding in PR #63's adversarial review and surfaced there for a ruling; ruled working-as-intended on the probe evidence. These tests turn that ruling into something that fails the build if someone later "fixes" the grammar without re-probing slapd.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #61.
What
The neutral mechanics a consumer needs to classify attribute values from a server's schema; the binary-vs-text policy stays with consumers, per the issue's non-goals.
LdapSyntax(RFC 4512 §4.1.5): OID, DESC, X- extensions — plusNAME, which is not in the RFC grammar but is a slapd extension its own shippedpmi.schemauses. The vendored corpus caught this the moment theldapsyntaxdirective started parsing, and a new differential test pins slapd's acceptance of that exact file in CI.NotHumanReadable/BinaryTransferRequiredread OpenLDAP's X- extensions with the TRUE-only rule implemented once (a published'FALSE'is not an assertion; first value is the assertion, matching the consumer parser this supersedes).ldapsyntaxslapd.conf directives (slaptest-verified, now CI-pinned), strictLdapSyntax.Parse, and a lenient three-parameterParseSubschemaoverload (failures bucket intoUnparsedDefinitionswith the newSyntaxkind).FindSyntaxstrips{bound}before lookup — OpenLDAP publishes bounded SYNTAX references and the bound is not part of the OID's identity; oneStripLengthBoundimplementation now serves both the SYNTAX keyword parser and the lookup.ResolveSyntaxOidwalks the SUP chain, cycle-guarded — OpenLDAP publishescnasSUP namewith no SYNTAX, soSyntaxalone leaves most of a live schema unresolved. The generator's private depth-capped twin is deleted in favor of it.AttributeDescription(core, besideDn):TypeOf("cn;lang-en")→"cn",HasOption(…, "binary")(case-insensitive per RFC 4512 §2.5), andIsValid— the writer's private definition made public, with the writer now calling it. One semantic, one implementation.The issue's bare-OID accessor checkbox needed no code:
LdapAttributeType.Syntaxhas stripped bounds since the parser landed, pinned by an existing test.Proven against real OpenLDAP
The captured 2.6 fixture's 33
ldapSyntaxesvalues parse with zero unparsed;cnresolves to Directory String through real published data; Audio/Certificate flags read correctly. The live differential test now fetches and parsesldapSyntaxestoo, and the full differential suite (5 tests, including the new slaptest pin) passed in a Linux container (slapd 2.6.10) before pushing.Review
Two adversarial review rounds (independent reviewer models; round 1's parallel fork needed one retry after returning empty output). Round 1: 9 findings — 4 accepted and fixed in
0ada36b(corpus counter now covers syntaxes so "nothing silently dropped" is honest, slaptest CI pin, multi-value flag-rule pin, 3-param null-guard tests), the rest refuted with evidence or surfaced. Round 2: 4 findings — 3 accepted and fixed inc22adf1(both flags pinned, two overclaiming comments scoped to their evidence), 1 declined (the naive line-scan oracle is deliberately independent of the parser; its failure direction is loud, and the green corpus is the agreement witness).Surfaced for a maintainer ruling, not fixed:
RfcGrammar.IsNumericOidimplements RFC 2849'sldap-oid(leading-zero arcs like01.2accepted), looser than RFC 4512'snumericoid. Its doc comment cites both grammars, so this reads as a deliberate single shared definition; tightening it would be a cross-cutting behavior change to LDIF and schema parsing alike.Public API changes (core:
AttributeDescription; Schema:LdapSyntax,Syntaxes,FindSyntax,ResolveSyntaxOid, 3-paramParseSubschema,Syntaxenum member) reviewed line-by-line and re-approved.