Skip to content

fix: omit <Transforms> element when no transforms are specified - #542

Open
msheby wants to merge 4 commits into
node-saml:masterfrom
msheby:fix/omit-empty-transforms-clean
Open

fix: omit <Transforms> element when no transforms are specified#542
msheby wants to merge 4 commits into
node-saml:masterfrom
msheby:fix/omit-empty-transforms-clean

Conversation

@msheby

@msheby msheby commented Aug 11, 2026

Copy link
Copy Markdown

When addReference is called without transforms (or with an empty transforms array), createReferences previously always emitted an empty <Transforms></Transforms> element. This is invalid under SMPTE ST 430-3 §8.2, which requires the Transforms field to be absent when no transformations apply.

Changes:

  • Make transforms optional on the Reference interface
  • Remove the addReference guard that threw on empty/absent transforms
  • Guard <Transforms> emission in createReferences so the element is only written when at least one transform is present
  • Apply C14N fallback in getCanonXml for the empty-transforms case so sign and verify use the same canonical form (matching the existing loadReference behavior)

Closes #540

Summary by CodeRabbit

  • New Features

    • References can now be signed without specifying transforms.
    • Signature output omits the Transforms element when no transforms are configured.
    • Untransformed reference nodes are canonicalized correctly before digesting.
    • Transform configuration is now optional for references.
  • Bug Fixes

    • Improved namespace resolution during canonicalization.
    • Added coverage for signing and verification with transform-free references.

When addReference is called without transforms (or with an empty
transforms array), createReferences previously always emitted an empty
<Transforms></Transforms> element. This is invalid under SMPTE ST 430-3
§8.2, which requires the Transforms field to be absent when no
transformations apply.

Changes:
- Make `transforms` optional on the Reference interface
- Remove the addReference guard that threw on empty/absent transforms
- Guard <Transforms> emission in createReferences so the element is
  only written when at least one transform is present
- Apply C14N fallback in getCanonXml for the empty-transforms case
  so sign and verify use the same canonical form (matching the existing
  loadReference behavior)

Closes node-saml#540
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@msheby, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 28c14b60-681b-4573-89b1-43ee254034d3

📥 Commits

Reviewing files that changed from the base of the PR and between 21df3b8 and c5d1976.

📒 Files selected for processing (3)
  • src/signed-xml.ts
  • src/utils.ts
  • test/signature-unit-tests.spec.ts

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f5215b9e-c87f-4246-86f9-4cb3da65a70e

📥 Commits

Reviewing files that changed from the base of the PR and between e33343c and 21df3b8.

📒 Files selected for processing (1)
  • test/signature-unit-tests.spec.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/signature-unit-tests.spec.ts

📝 Walkthrough

Walkthrough

References now support absent or empty transforms. Signature generation omits the Transforms element in that case and applies inclusive C14N before digesting. Tests cover output omission and signing-verification round trips.

Changes

Reference transform handling

Layer / File(s) Summary
Reference contract and serialization
src/types.ts, src/signed-xml.ts, test/signature-unit-tests.spec.ts
Reference.transforms is optional. Signature generation emits Transforms only when transforms exist. Tests validate omitted and empty configurations.
Reference canonicalization and round-trip
src/signed-xml.ts, test/signature-unit-tests.spec.ts
Canonicalization resolves ancestor namespaces and applies inclusive C14N to untransformed DOM nodes. Tests verify signing and verification with SHA-256 and RSA-SHA256.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to 21df3

This change omits an invalid empty Transforms element while preserving signing behavior for references with transforms; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant SignatureGeneration
  participant getCanonXml
  participant DigestAlgorithm
  participant SignatureVerification
  SignatureGeneration->>getCanonXml: canonicalize referenced DOM node without transforms
  getCanonXml->>DigestAlgorithm: provide canonical XML
  DigestAlgorithm-->>SignatureGeneration: return DigestValue
  SignatureVerification->>getCanonXml: canonicalize referenced DOM node
  getCanonXml->>DigestAlgorithm: provide canonical XML
  DigestAlgorithm-->>SignatureVerification: compare digest
Loading

Possibly related PRs

Suggested labels: bug

Suggested reviewers: cjbarth

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: omitting the element when no transforms are specified.
Linked Issues check ✅ Passed The changes satisfy issue #540 by omitting empty or absent elements while preserving non-empty transforms and round-trip compatibility.
Out of Scope Changes check ✅ Passed The changes remain within scope and support the requested output cleanup, canonicalization fallback, API update, and related test coverage.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
test/signature-unit-tests.spec.ts (1)

1077-1100: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Test the empty-array input explicitly.

This test covers an omitted transforms property only. The API also promises identical serialization for transforms: [].

Add a second case, or parameterize this test, with transforms: []. Keep the assertion that no Transforms element exists.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/signature-unit-tests.spec.ts` around lines 1077 - 1100, Extend the
“omits Transforms element when no transforms are specified” test to also call
addReference with transforms explicitly set to an empty array. Preserve the
existing assertion that the generated signature contains no Transforms element,
either by adding a second case or parameterizing the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/signed-xml.ts`:
- Line 434: Update the ancestor-namespace lookup in addAllReferences to pass the
current matched node to findAncestorNs instead of ref.xpath, ensuring each
reference uses its own namespace scope. Add a test covering multiple matched
nodes under different namespace declarations and verify their generated
signature validates successfully.

In `@test/signature-unit-tests.spec.ts`:
- Around line 911-912: Update the assertions around ref.transforms to avoid
non-null assertions: assert the complete expected transform list directly using
the existing transform value, while preserving the expectation that it contains
exactly one canonicalization transform.

---

Nitpick comments:
In `@test/signature-unit-tests.spec.ts`:
- Around line 1077-1100: Extend the “omits Transforms element when no transforms
are specified” test to also call addReference with transforms explicitly set to
an empty array. Preserve the existing assertion that the generated signature
contains no Transforms element, either by adding a second case or parameterizing
the test.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e14fcfee-aee2-42f7-8d98-17f02170b629

📥 Commits

Reviewing files that changed from the base of the PR and between b673581 and 7e30184.

📒 Files selected for processing (3)
  • src/signed-xml.ts
  • src/types.ts
  • test/signature-unit-tests.spec.ts

Comment thread src/signed-xml.ts Outdated
Comment thread test/signature-unit-tests.spec.ts Outdated
Matthew Sheby added 3 commits August 11, 2026 13:41
Using ! on optional properties triggers the no-non-null-assertion
ESLint rule. Collapsing the two separate length/index checks into
a single deep.equal is also more readable.
…test

The previous test only verified that a missing transforms property
suppresses the <Transforms> element. Parameterize the test to also
cover transforms: [], which the API treats identically.
…ing xpath

getCanonReferenceXml passed ref.xpath to findAncestorNs, which always
uses docSubset[0] — the first XPath match. When addAllReferences creates
multiple references for the same xpath pattern and those matched elements
live under different ancestor namespace scopes, every reference beyond
the first was digested with the wrong namespace context, producing a
signature that verifiers would reject.

Fix: add findAncestorNsForNode(element) to utils and call it with the
node already in scope instead of re-executing the XPath. Also extract
the shared deduplication/filtering logic into buildAncestorNsForElement
to avoid code duplication between the two public helpers.

Adds a regression test: two <item> elements under sibling <section>
elements that each declare a different namespace prefix. The fix makes
sign+verify round-trip correctly; the old code would fail verification
for the second reference.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant