Skip to content

[CDAP-21270] Allow disabling JEXL allowlist feature through directive config API - #1049

Merged
riyaa14 merged 1 commit into
developfrom
fix/jexl-allowlist
Sep 16, 2026
Merged

riyaa14 merged 1 commit into
developfrom
fix/jexl-allowlist

Conversation

@riyaa14

@riyaa14 riyaa14 commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Description

This PR introduces JexlConfiguration within DirectiveConfig to support enabling or disabling the JEXL allowlist feature dynamically through the Wrangler Directive Configuration API.

Changes

  1. Introduced JexlConfiguration and JexlConfigurationDeserializer:
  • Encapsulates jexlAllowlistEnabled (boolean flag) and jexlAllowlist (list of JexlAllowlist rules) under the jexlConfiguration field in DirectiveConfig.
  • Provides isJexlAllowlistEnabledOrDefault(boolean) to fall back to the system-level default when the flag is omitted.
  1. Updated DirectiveConfig and Context Resolution:
  • Replaced direct jexlAllowlist field in DirectiveConfig with jexlConfiguration.
  • Updated ConfigDirectiveContext to resolve whether JEXL allowlisting is active using jexlConfiguration.isJexlAllowlistEnabledOrDefault(...).
  1. Updated DirectivesHandler API Validation & Storage:
  • Added validation in DirectivesHandler to allow disabling JEXL allowlisting via the config API while preserving existing allowlist rules if omitted when disabled.
  • Corrected placement of Auth checks, should be checked before handling of JEXL feature flag and the checks should be enforced irrespective of whether feature flag is enabled or disabled.
  • Updated ConfigStore and callers (Wrangler, DataPrepServiceClient, RequestExtractor, RemoteExecutionTask) to serialize/deserialize JexlConfiguration.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request refactors the JEXL allowlist configuration by introducing a new JexlConfiguration class that encapsulates both the JEXL allowlist and an enabled flag, updating DirectiveConfig and its deserializers accordingly. The review feedback highlights three potential NullPointerException risks: a missing null check on config.getJexlConfiguration() in ConfigDirectiveContext, a potential null return from configStore.getConfig() in DirectivesHandler, and the use of contains(null) on a list in JexlConfiguration which can throw an exception depending on the list implementation.

Comment on lines 49 to 52
public boolean isJexlAllowlistEnabled() {
return jexlAllowlistEnabled;
return isJexlAllowlistFeatureFlagEnabled
&& config.getJexlConfiguration().isJexlAllowlistEnabledOrDefault(true);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If config.getJexlConfiguration() is null (which can happen if the configuration is empty or has not been fully initialized/migrated), calling isJexlAllowlistEnabledOrDefault will throw a NullPointerException. We should add a null check to safely default to true when the JEXL configuration is missing.

Suggested change
public boolean isJexlAllowlistEnabled() {
return jexlAllowlistEnabled;
return isJexlAllowlistFeatureFlagEnabled
&& config.getJexlConfiguration().isJexlAllowlistEnabledOrDefault(true);
}
public boolean isJexlAllowlistEnabled() {
return isJexlAllowlistFeatureFlagEnabled
&& (config.getJexlConfiguration() == null
|| config.getJexlConfiguration().isJexlAllowlistEnabledOrDefault(true));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please fix.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If the feature flag (isJexlAllowlistFeatureFlagEnabled) is true, getJexlConfiguration() won't be null. This is already handled in DirectivesHandler, we don't allow a null jexlConfiguration - Reference

Comment on lines 1110 to 1116
DirectiveConfig config = configStore.getConfig();
if (!jexlAllowlistEnabled) {
JsonObject configJson = config.toJson().getAsJsonObject();
configJson.remove(DirectiveConfig.JEXL_ALLOWLIST_KEY);
configJson.remove(DirectiveConfig.JEXL_CONFIGURATION_KEY);
return new ServiceResponse<>(configJson);
}
enforceDirectiveConfigPermission(StandardPermission.GET);
return new ServiceResponse<>(config);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If configStore.getConfig() returns null (e.g., in uninitialized or test environments), calling config.toJson() will throw a NullPointerException. It is safer to default to DirectiveConfig.EMPTY when the config is null.

      DirectiveConfig config = configStore.getConfig();
      if (config == null) {
        config = DirectiveConfig.EMPTY;
      }
      if (!jexlAllowlistEnabled) {
        JsonObject configJson = config.toJson().getAsJsonObject();
        configJson.remove(DirectiveConfig.JEXL_CONFIGURATION_KEY);
        return new ServiceResponse<>(configJson);
      }
      return new ServiceResponse<>(config);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This case is not possible, the directive config is never null in database because on dataprep service initialization, we initialize the database with default directive config. Reference - Wrangler PR#1040

Comment on lines +41 to +43
if (jexlAllowlist != null && jexlAllowlist.contains(null)) {
throw new IllegalArgumentException("JEXL allowlist cannot contain null entries.");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using jexlAllowlist.contains(null) can throw a NullPointerException depending on the underlying List implementation (for example, Guava's ImmutableList or Java 9+ List.of() throw NPE on contains(null)). It is safer to iterate through the list to check for null elements.

    if (jexlAllowlist != null) {
      for (JexlAllowlist entry : jexlAllowlist) {
        if (entry == null) {
          throw new IllegalArgumentException("JEXL allowlist cannot contain null entries.");
        }
      }
    }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is not needed at all, removed.

private final ImmutableList<JexlAllowlist> jexlAllowlist;

public JexlConfiguration(
@Nullable Boolean jexlAllowlistEnabled,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use Primitive data type boolean. No need to annotate with nullable.

@Nullable
private final Boolean jexlAllowlistEnabled;
@Nullable
private final ImmutableList<JexlAllowlist> jexlAllowlist;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: use List here. Underlying implementation could be ImmutableList.

Comment on lines +51 to +53
public boolean isJexlAllowlistEnabledOrDefault(boolean defaultValue) {
return jexlAllowlistEnabled != null ? jexlAllowlistEnabled : defaultValue;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Simplify

return new JexlConfiguration(
deserializeProperty(jexlConfigJsonObj, JexlConfiguration.JEXL_ALLOWLIST_ENABLED_KEY, Boolean.class, ctx),
deserializeProperty(jexlConfigJsonObj, JexlConfiguration.JEXL_ALLOWLIST_KEY, JEXL_ALLOWLIST_LIST_TYPE, ctx));
} catch (IllegalArgumentException e) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not the correct exception to throw in this case.

Let JsonParseException be propaged.

Comment on lines 49 to 52
public boolean isJexlAllowlistEnabled() {
return jexlAllowlistEnabled;
return isJexlAllowlistFeatureFlagEnabled
&& config.getJexlConfiguration().isJexlAllowlistEnabledOrDefault(true);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please fix.

}

@Nullable
private JexlConfiguration resolveJexlConfiguration(@Nullable JexlConfiguration userConfig)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

nit: change userConfig tojexlConfif

public JexlConfiguration(
@Nullable Boolean jexlAllowlistEnabled,
@Nullable List<JexlAllowlist> jexlAllowlist) {
if (jexlAllowlist != null && jexlAllowlist.contains(null)) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

jexlAllowlist.contains(null) is not needed as this will be handled in the deserializer.

@riyaa14
riyaa14 merged commit 64c8ae7 into develop Sep 16, 2026
9 checks passed
@riyaa14
riyaa14 deleted the fix/jexl-allowlist branch September 16, 2026 12:13
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.

3 participants