public ImmutableSet<EntityDescriptor> resolve(GRN entity) {
        // TODO: Replace entity excerpt usage with GRNDescriptors once we implemented GRN descriptors for every entity
        final ImmutableMap<GRN, Optional<String>> entityExcerpts = contentPackService.listAllEntityExcerpts().stream()
                // TODO: Use the GRNRegistry instead of manually building a GRN. Requires all entity types to be in the registry.
                .collect(ImmutableMap.toImmutableMap(e -> GRNType.create(e.type().name(), e.type().name() + ":").newGRNBuilder().entity(e.id().id()).build(),
                        v -> Optional.ofNullable(v.title())));

        final Set<org.graylog2.contentpacks.model.entities.EntityDescriptor> descriptors = contentPackService.resolveEntities(Collections.singleton(org.graylog2.contentpacks.model.entities.EntityDescriptor.builder()
                .id(ModelId.of(entity.entity()))
                // TODO: This is a hack! Until we stop using the content-pack dependency resolver, we have to use a different version for dashboards here
                .type(ModelType.of(entity.type(), "dashboard".equals(entity.type()) ? "2" : "1")) // TODO: Any way of NOT hardcoding the version here?
                .build()));

        final ImmutableSet<GRN> dependencies = descriptors.stream()
                .filter(dep -> {
                    // Filter dependencies that aren't needed for grants sharing
                    // TODO This is another reason why we shouldn't be using the content pack resolver ¯\_(ツ)_/¯
                    final Set<ModelType> ignoredDeps = IGNORED_DEPENDENCIES.getOrDefault(entity.grnType(), ImmutableSet.of());
                    return !ignoredDeps.contains(dep.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.
                .map(descriptor -> ModelTypes.STREAM_REF_V1.equals(descriptor.type())
                        ? org.graylog2.contentpacks.model.entities.EntityDescriptor.create(descriptor.id(), ModelTypes.STREAM_V1)
                        : descriptor)
                .map(descriptor -> grnRegistry.newGRN(descriptor.type().name(), descriptor.id().id()))
                .filter(dependency -> !entity.equals(dependency)) // Don't include the given entity in dependencies
                .collect(ImmutableSet.toImmutableSet());

        final Map<GRN, Set<GRN>> targetOwners = grantService.getOwnersForTargets(dependencies);

        return dependencies.stream()
                .map(dependency -> {
                    String title = entityExcerpts.get(dependency) != null ? entityExcerpts.get(dependency).orElse("unnamed dependency: <" + dependency + ">") : "unknown dependency: <" + dependency + ">";
                    return EntityDescriptor.create(
                            dependency,
                            title,
                            getOwners(targetOwners.get(dependency))
                    );
                })
                .collect(ImmutableSet.toImmutableSet());
    }
@Test
    @DisplayName("Try a stream reference dependency resolve")
    void resolveStreamReference() {
        final String TEST_TITLE = "Test Stream Title";
        final EntityExcerpt streamExcerpt = EntityExcerpt.builder()
                .type(ModelTypes.STREAM_V1)
                .id(ModelId.of("54e3deadbeefdeadbeefaffe"))
                .title(TEST_TITLE).build();
        final EntityExcerpt streamRefExcerpt = EntityExcerpt.builder()
                .type(ModelTypes.STREAM_REF_V1)
                .id(ModelId.of("54e3deadbeefdeadbeefaffe"))
                .title(TEST_TITLE).build();
        when(contentPackService.listAllEntityExcerpts()).thenReturn(ImmutableSet.of(streamExcerpt, streamRefExcerpt));

        final EntityDescriptor streamDescriptor = EntityDescriptor.builder().type(ModelTypes.STREAM_REF_V1).id(ModelId.of("54e3deadbeefdeadbeefaffe")).build();
        when(contentPackService.resolveEntities(any())).thenReturn(ImmutableSet.of(streamDescriptor));

        when(grnDescriptorService.getDescriptor(any(GRN.class))).thenAnswer(a -> {
            GRN grnArg = a.getArgument(0);
            return GRNDescriptor.builder().grn(grnArg).title("dummy").build();
        });
        final GRN dashboard = grnRegistry.newGRN("dashboard", "33e3deadbeefdeadbeefaffe");

        final ImmutableSet<org.graylog.security.entities.EntityDescriptor> missingDependencies = entityDependencyResolver.resolve(dashboard);
        assertThat(missingDependencies).hasSize(1);
        assertThat(missingDependencies.asList().get(0)).satisfies(descriptor -> {
            assertThat(descriptor.id().toString()).isEqualTo("grn::::stream:54e3deadbeefdeadbeefaffe");
            assertThat(descriptor.title()).isEqualTo(TEST_TITLE);

            assertThat(descriptor.owners()).hasSize(1);
            assertThat(descriptor.owners().asList().get(0).grn().toString()).isEqualTo("grn::::user:jane");
        });
    }