Release note · August 6, 2026

A relationship match is not case-sensitive

By SybilGambleyyu · DocFence 0.59.0

A relationship selector's placement and attributes are syntax. Once that syntax is valid, the OPC Relationships Transform defines exactly which stored relationships the selector chooses. ECMA-376 Open Packaging Conventions §10.6 says that matching is ASCII case-insensitive. DocFence 0.59 now applies that rule in its bounded static coverage audit.

Selection is an algorithm, not a string lookup

Consider a stored relationship and a well-shaped selector:

<Relationship Id="rIdStyles"
  Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
  Target="styles.xml"/>

<opc:RelationshipReference SourceId="RIDSTYLES"/>

Those two ID values differ only in ASCII letter case. The transform selects the relationship. The same rule applies to a RelationshipsGroupReference/@SourceType and a stored relationship Type. If several stored IDs differ only by ASCII case, every matching relationship is selected.

Earlier DocFence coverage resolution used exact string equality. A standards-shaped declaration with a case-only difference could therefore look unresolved or uncovered even though the OPC transform would select it. That is a correctness gap in an audit meant to state what stored declarations cover.

A deliberately narrow correction

0.59 folds only ASCII AZ when comparing selector values with stored relationship IDs and types. It does not apply broad Unicode normalization, rewrite package content, widen the selector syntax accepted in 0.58, execute a transform, canonicalize XML, recompute a digest, verify XMLDSIG, or make a trust decision.

The global boundary remains strict: selectors must be direct, child-free children of a Relationship Transform with exactly their required attribute. The change occurs only after that syntax passes, when DocFence reports bounded declared package-signature coverage.

version: 1
rules:
  require_complete_package_signature_coverage: true
  no_package_signature_coverage_changes: true

Evidence and use

The 70-test suite now covers case-insensitive SourceId matching, case-insensitive SourceType matching, and a selector that must select multiple case-colliding IDs. Across the 29 DOCX fixtures in the public OOXML Signature Security artifacts, 21 XML signature parts parse successfully. Their 38 Relationship Transforms contain 106 direct selectors; none has a case-only stored match or a folded-ID collision, so their public profiles remain identical to 0.58.

Main and tagged CI passed. Two independent epoch-fixed builds were byte-identical; anonymous downloads of the published wheel and source distribution matched those artifacts byte-for-byte. SHA-256: wheel 94aca4b08950ba5f9e586c65424361620a654db53d87029522aa2b8ce787a625; source distribution 31ca90d4c5fb8131b1df0bb960d2ac78344667b923e9c0c402391aac4e5ccdee.

python -m pip install https://github.com/SybilGambleyyu/docfence/releases/download/v0.59.0/docfence-0.59.0-py3-none-any.whl

docfence check approved.docx candidate.docx --policy docfence.yml --format sarif --output docfence.sarif

The tagged policy reference, threat model, and validation notes describe the exact scope. A coverage statement should follow the transform it is describing—no more, and no less.