From 4775648230c642a96e542b3f7b6471041438d737 Mon Sep 17 00:00:00 2001 From: Zack King Date: Fri, 17 Jul 2026 15:18:48 -0500 Subject: [PATCH] Support native entity resolution of parameters in Content Packs --- .../plugins/views/search/Parameter.java | 17 ++++++++++++++++- .../graylog/plugins/views/search/Search.java | 4 +++- .../DefaultEntityDependencyResolver.java | 18 +++++++++++++----- .../model/entities/SearchEntity.java | 5 ++++- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/search/Parameter.java b/graylog2-server/src/main/java/org/graylog/plugins/views/search/Parameter.java index 9fc859da9e0c..9b5c4d91f8b2 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/search/Parameter.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/search/Parameter.java @@ -23,6 +23,9 @@ import com.google.common.collect.Maps; import org.graylog2.contentpacks.ContentPackable; import org.graylog2.contentpacks.EntityDescriptorIds; +import org.graylog2.contentpacks.NativeEntityConverter; +import org.graylog2.contentpacks.model.entities.EntityDescriptor; +import org.graylog2.contentpacks.model.entities.references.ValueReference; import javax.annotation.Nullable; import java.util.Map; @@ -43,7 +46,7 @@ property = Parameter.TYPE_FIELD, visible = true, defaultImpl = ValueParameter.class) -public interface Parameter extends ContentPackable { +public interface Parameter extends ContentPackable, NativeEntityConverter { String TYPE_FIELD = "type"; @JsonProperty(TYPE_FIELD) @@ -76,10 +79,22 @@ public interface Parameter extends ContentPackable { Parameter applyBindings(Map bindings); + @Override default Parameter toContentPackEntity(EntityDescriptorIds entityDescriptorIds) { return this; } + /** + * On content pack installation, resolve any content-pack entity references this parameter carries back to native + * entity ids using the resolved {@code nativeEntities}. Default is a no-op for parameters that reference no + * entities; the install-ordering counterpart is {@link NativeEntityConverter#resolveForInstallation}. + */ + @Override + default Parameter toNativeEntity(Map parameters, + Map nativeEntities) { + return this; + } + interface Builder { @JsonProperty(TYPE_FIELD) SELF type(String type); diff --git a/graylog2-server/src/main/java/org/graylog/plugins/views/search/Search.java b/graylog2-server/src/main/java/org/graylog/plugins/views/search/Search.java index 52f12f2487b6..1ded67615fef 100644 --- a/graylog2-server/src/main/java/org/graylog/plugins/views/search/Search.java +++ b/graylog2-server/src/main/java/org/graylog/plugins/views/search/Search.java @@ -324,7 +324,9 @@ public SearchEntity toContentPackEntity(EntityDescriptorIds entityDescriptorIds) .collect(Collectors.toCollection(LinkedHashSet::new)); final SearchEntity.Builder searchEntityBuilder = SearchEntity.builder() .queries(ImmutableSet.copyOf(queries)) - .parameters(this.parameters()) + .parameters(this.parameters().stream() + .map(parameter -> parameter.toContentPackEntity(entityDescriptorIds)) + .collect(ImmutableSet.toImmutableSet())) .requires(this.requires()) .createdAt(this.createdAt()); if (this.owner().isPresent()) { diff --git a/graylog2-server/src/main/java/org/graylog/security/entities/DefaultEntityDependencyResolver.java b/graylog2-server/src/main/java/org/graylog/security/entities/DefaultEntityDependencyResolver.java index 5579d6822dd0..898d7eefc689 100644 --- a/graylog2-server/src/main/java/org/graylog/security/entities/DefaultEntityDependencyResolver.java +++ b/graylog2-server/src/main/java/org/graylog/security/entities/DefaultEntityDependencyResolver.java @@ -77,11 +77,9 @@ protected ImmutableSet resolve(Collection entities) { dependencyGraph.predecessors(dependency).stream().anyMatch( predecessor -> !ModelTypes.STREAM_V1.equals(predecessor.type())) ) - // Ignore lookup tables, adapters, and caches as dependencies. Lookup tables don't have a corresponding - // GRN type registered and cannot be resolved for permission checks. - .filter(dependency -> !ModelTypes.LOOKUP_TABLE_V1.equals(dependency.type()) && - !ModelTypes.LOOKUP_ADAPTER_V1.equals(dependency.type()) && - !ModelTypes.LOOKUP_CACHE_V1.equals(dependency.type())) + // Ignore dependency types that have no corresponding GRN type registered and therefore cannot + // be resolved for permission checks (lookup tables, adapters, caches - see ignoredDependencyTypes()). + .filter(dependency -> !ignoredDependencyTypes().contains(dependency.type())) // TODO: Work around from using the content pack dependency resolver: // We've added stream_title content pack entities in https://github.com/Graylog2/graylog2-server/pull/17089, // but in this context we want to return the actual dependent Stream to add additional permissions to. @@ -98,6 +96,16 @@ protected ImmutableSet resolve(Collection entities) { .collect(ImmutableSet.toImmutableSet()); } + /** + * Content pack dependency types to exclude from permission dependency resolution: they have no + * corresponding GRN type registered and therefore cannot be resolved for permission checks. Lookup + * tables, adapters, and caches are excluded here because their access is not permission-gated in this + * context; subclasses may extend this for plugin-specific reference-only types. + */ + protected Set ignoredDependencyTypes() { + return Set.of(ModelTypes.LOOKUP_TABLE_V1, ModelTypes.LOOKUP_ADAPTER_V1, ModelTypes.LOOKUP_CACHE_V1); + } + @Override public EntityDescriptor descriptorFromGRN(GRN entity) { return descriptorFromGRN(entity, entityExcerpts(), grantService.getOwnersForTargets(ImmutableSet.of(entity))); diff --git a/graylog2-server/src/main/java/org/graylog2/contentpacks/model/entities/SearchEntity.java b/graylog2-server/src/main/java/org/graylog2/contentpacks/model/entities/SearchEntity.java index 61483ebc8204..16d52de4607a 100644 --- a/graylog2-server/src/main/java/org/graylog2/contentpacks/model/entities/SearchEntity.java +++ b/graylog2-server/src/main/java/org/graylog2/contentpacks/model/entities/SearchEntity.java @@ -122,7 +122,9 @@ public Search toNativeEntity(Map parameters, .collect(Collectors.toCollection(LinkedHashSet::new)); final Search.Builder searchBuilder = Search.builder() .queries(ImmutableSet.copyOf(queries)) - .parameters(this.parameters()) + .parameters(this.parameters().stream() + .map(parameter -> parameter.toNativeEntity(parameters, nativeEntities)) + .collect(ImmutableSet.toImmutableSet())) .requires(this.requires()) .createdAt(this.createdAt()); if (this.owner().isPresent()) { @@ -137,5 +139,6 @@ public void resolveForInstallation(EntityV1 entity, Map entities, MutableGraph graph) { queries().forEach(query -> query.resolveForInstallation(entity, parameters, entities, graph)); + parameters().forEach(parameter -> parameter.resolveForInstallation(entity, parameters, entities, graph)); } }