Skip to content

Change XPath available function check from denylist to allowlist - #369

Open
tompng wants to merge 1 commit into
ruby:masterfrom
tompng:function_allowlist
Open

Change XPath available function check from denylist to allowlist#369
tompng wants to merge 1 commit into
ruby:masterfrom
tompng:function_allowlist

Conversation

@tompng

@tompng tompng commented Sep 7, 2026

Copy link
Copy Markdown
Member

Define an allowlist of available xpath functions Instead of listing up all internal methods which isn't xpath function. REXML::FunctionsClass now strictly checks function names: local-name is allowed but local_name is rejected.
The compatibility layer that accepts local_name is in the call site.

Why allowlist?

Currently, REXML dropped/changed the way to add custom XPath functions in #329 that I opened.
I don't know if REXML officially supported this, it may be just a monkey patch, but perhaps it's an accidental breaking change.

# Add custom_func and custom-func

# REXML 3.4.4
def (REXML::Functions).custom_func() = 42

# Master branch (after #329)
class REXML::FunctionsClass; def custom_func() = 42; end

# After this PR
$VERBOSE = nil # or remove_const
REXML::FunctionsClass::AVAILABLE_FUNCTIONS += %w[custom-func custom_func]

If we're going to drop it forever, I think static allowlist in this PR is the simplest way.
If REXML needs to re-support custom XPath function with the old style: def (REXML::Functions).custom_func() = 42 , something needs to be done before releasing the next version. But I don't think it's easy to do it in a thread-safe way especially when the custom function touches @context.

About fallback: nil

def call(name, args:, fallback: nil) can't distinguish nil fallback from unspecified fallback but it's OK.
Fallback should be either bool, number, string, or NodeSet. nil is not allowed as a value of an expression of XPath.

Define an allowlist of available xpath functions instead of listing up all internal methods which isn't xpath function.
`REXML::FunctionsClass` now strictly checks function names: `local-name` is allowed but `local_name` is rejected.
The compatibility layer that accepts `local_name` is in the call site.
Copilot AI lite review requested due to automatic review settings September 7, 2026 14:31

Copilot AI 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.

🟢 Approval recommended

The changes are localized, internally consistent (parser + functions + tests), and the updated tests directly cover the new allowlist and compatibility behavior.

Pull request overview

This PR tightens XPath function dispatch in REXML by switching REXML::FunctionsClass from a denylist-based “anything except internal helpers” check to a strict allowlist of recognized XPath functions, while keeping backward-compatible underscore aliases at the call site.

Changes:

  • Introduces REXML::FunctionsClass::AVAILABLE_FUNCTIONS (a Set) and routes function invocation through a new FunctionsClass#call allowlist gate.
  • Updates XPathParser to invoke XPath functions via #call (with a compatibility normalization layer and fallback behavior).
  • Adjusts/extends tests to validate the allowlist, strictness for underscored names via #call, and compatibility via #send.
File summaries
File Description
test/functions/test_base.rb Updates tests to assert the allowlist contents and stricter function-name handling while preserving compatibility paths.
lib/rexml/xpath_parser.rb Switches function evaluation from send to FunctionsClass#call, providing underscore-to-hyphen compatibility and fallback behavior.
lib/rexml/functions.rb Adds AVAILABLE_FUNCTIONS allowlist and implements #call as the strict dispatch mechanism, with #send retained as a compatibility wrapper.
Review details
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

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.

2 participants