Skip to content

Schema: ldapSyntaxes, X- extension flags, SUP-chain syntax resolution - #63

Merged
joshmakestuff merged 3 commits into
mainfrom
issue-61-ldapsyntaxes
Aug 3, 2026
Merged

Schema: ldapSyntaxes, X- extension flags, SUP-chain syntax resolution#63
joshmakestuff merged 3 commits into
mainfrom
issue-61-ldapsyntaxes

Conversation

@joshmakestuff

@joshmakestuff joshmakestuff commented Aug 3, 2026

Copy link
Copy Markdown
Owner

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 — plus NAME, which is not in the RFC grammar but is a slapd extension its own shipped pmi.schema uses. The vendored corpus caught this the moment the ldapsyntax directive started parsing, and a new differential test pins slapd's acceptance of that exact file in CI. NotHumanReadable / BinaryTransferRequired read 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).
  • Parsed from all three input shapes: ldapsyntax slapd.conf directives (slaptest-verified, now CI-pinned), strict LdapSyntax.Parse, and a lenient three-parameter ParseSubschema overload (failures bucket into UnparsedDefinitions with the new Syntax kind).
  • 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 both the SYNTAX keyword parser and the lookup.
  • ResolveSyntaxOid walks the SUP chain, cycle-guarded — OpenLDAP publishes cn as SUP name with no SYNTAX, so Syntax alone leaves most of a live schema unresolved. The generator's private depth-capped twin is deleted in favor of it.
  • AttributeDescription (core, beside Dn): 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. One semantic, one implementation.

The issue's bare-OID accessor checkbox needed no code: LdapAttributeType.Syntax has stripped bounds since the parser landed, pinned by an existing test.

Proven against real OpenLDAP

The captured 2.6 fixture's 33 ldapSyntaxes values parse with zero unparsed; cn resolves to Directory String through real published data; Audio/Certificate flags read correctly. The live differential test now fetches and parses ldapSyntaxes too, 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 in c22adf1 (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.IsNumericOid implements RFC 2849's ldap-oid (leading-zero arcs like 01.2 accepted), looser than RFC 4512's numericoid. 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-param ParseSubschema, Syntax enum member) reviewed line-by-line and re-approved.

joshmakestuff and others added 3 commits August 3, 2026 14:16
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
joshmakestuff merged commit 6233600 into main Aug 3, 2026
6 checks passed
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Schema: parse ldapSyntaxes and X- extensions; resolve attribute syntax through SUP chains

1 participant