Skip to content

Enhancement Search Index #26669

Merged
harshach merged 83 commits intomainfrom
reindex-logger
Mar 31, 2026
Merged

Enhancement Search Index #26669
harshach merged 83 commits intomainfrom
reindex-logger

Conversation

@mohityadav766
Copy link
Copy Markdown
Member

@mohityadav766 mohityadav766 commented Mar 21, 2026

Describe your changes:

Fixes #26678

I worked on ... because ...

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.

Summary by Gitar

  • Search Index fixes:
    • Added boundary validation in BoundedListFilter to prevent out-of-range pagination
    • Enhanced SearchIndexExecutor error handling with sink cleanup on failure
    • Fixed queryChangeDescription check in search index workflow
  • Test coverage:
    • Added BoundedListFilterTest for boundary condition validation
    • Enhanced SearchIndexExecutorControlFlowTest with additional control flow scenarios
  • App lifecycle:
    • Added tryStopOutsideQuartz() hook to handle stopping distributed jobs outside Quartz scheduler

This will update automatically on new commits.

Copilot AI review requested due to automatic review settings March 21, 2026 04:56
@github-actions github-actions bot added backend safe to test Add this label to run secure Github workflows on PRs labels Mar 21, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces infrastructure to capture and persist per-application-run logs (notably for reindex/SearchIndex runs) and improves SearchIndex stats accuracy/refresh behavior, backed by new unit tests.

Changes:

  • Add a Logback Appender + buffered file writer to capture app-run logs into logs/app-runs/{appName}/{timestamp}-{serverId}.log.
  • Wire log-capture lifecycle into Quartz job execution via OmAppJobListener (start/stop capture, MDC setup/cleanup, thread-prefix capture for reindex workers).
  • Improve SearchIndex stats consistency by adjusting totals when processed counts exceed initial totals and periodically syncing sink stats; add tests for these cases.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
openmetadata-service/src/main/java/org/openmetadata/service/apps/scheduler/OmAppJobListener.java Starts/stops app-run log capture around Quartz job execution and manages MDC/thread-prefix capture.
openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java New Logback appender that routes matching events to per-run buffers/files and performs retention cleanup.
openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/RunLogBuffer.java New buffered writer with periodic flushing and max-line cap for app-run log persistence.
openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexExecutor.java Periodic sink stat sync and total-records adjustments to keep stats internally consistent.
openmetadata-service/src/test/java/org/openmetadata/service/apps/logging/AppRunLogAppenderTest.java New tests covering capture behavior, cleanup, listing timestamps, and concurrency safety of app-run logging.
openmetadata-service/src/test/java/org/openmetadata/service/apps/logging/RunLogBufferTest.java New tests for buffer append/flush/close behavior and max-line handling.
openmetadata-service/src/test/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexStatsTest.java New tests validating adjusted totals and reader/job totals consistency.

Comment on lines +229 to +232
static void resetForTest() {
registered = false;
threadPrefixBindings.clear();
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

resetForTest() only clears registered and threadPrefixBindings but leaves other static state mutated by tests (e.g., logDirectory, maxRunsPerApp, maxLinesPerRun) and does not remove the appender from the root logger if it was registered. This can leak state across test classes within the same JVM; consider resetting static defaults and detaching/stopping the root appender in resetForTest().

Copilot uses AI. Check for mistakes.
@AfterEach
void tearDown() {
AppRunLogAppender.getActiveBuffers().clear();
AppRunLogAppender.resetForTest();
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

setUp() mutates static state via AppRunLogAppender.setLogDirectoryForTest(...), but tearDown() does not restore it (and resetForTest() currently doesn’t reset logDirectory). This can leak configuration into other test classes in the same JVM. Restore the defaults in tearDown() (or enhance resetForTest() to reset logDirectory/limits and detach any root-logger appender registered by startCapture).

Suggested change
AppRunLogAppender.resetForTest();
AppRunLogAppender.resetForTest();
AppRunLogAppender.setLogDirectoryForTest(null);

Copilot uses AI. Check for mistakes.
Comment on lines +90 to +93
String batchText = String.join("\n", batch);
writeToFile(batchText);
AppRunLogMetrics.recordFlush(appName, batch.size());
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

flush() calls AppRunLogMetrics.recordFlush(...), but there is no AppRunLogMetrics class in the codebase (repo-wide search only finds these references). This will fail compilation; either add the missing metrics implementation or remove/replace these calls with an existing metrics facility.

Copilot uses AI. Check for mistakes.
Comment on lines +60 to +72
void startFlusher() {
try {
Files.createDirectories(logFile.getParent());
writer =
Files.newBufferedWriter(
logFile,
StandardCharsets.UTF_8,
StandardOpenOption.CREATE,
StandardOpenOption.APPEND);
} catch (IOException e) {
LOG.error("Failed to open log file {}: {}", logFile, e.getMessage());
return;
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

If startFlusher() fails to open the log file (IOException), it logs and returns, but the buffer remains usable and will keep accumulating pending lines (up to maxLines) without ever flushing. Consider returning a success/failure signal (or throwing) so the caller can stop capture/remove the buffer, or mark the buffer as closed/disabled on failure.

Copilot uses AI. Check for mistakes.
Comment on lines +121 to +172
public static RunLogBuffer startCapture(
String appRunId, String appId, String appName, String serverId, String... threadPrefixes) {
ensureRegistered();
cleanupOldRuns(appName);
Path logFile = resolveLogFile(appName, Long.parseLong(appRunId), serverId);
RunLogBuffer buffer =
new RunLogBuffer(
appId, appName, serverId, Long.parseLong(appRunId), maxLinesPerRun, logFile);
activeBuffers.put(bufferKey(appName, appRunId), buffer);

for (String prefix : threadPrefixes) {
threadPrefixBindings.add(new ThreadPrefixBinding(prefix, buffer));
}

buffer.startFlusher();
AppRunLogMetrics.recordRunStarted(appName, serverId);
return buffer;
}

public static void stopCapture(String appName, String appRunId) {
RunLogBuffer buffer = activeBuffers.remove(bufferKey(appName, appRunId));
if (buffer != null) {
threadPrefixBindings.removeIf(b -> b.buffer == buffer);
long durationMs = System.currentTimeMillis() - buffer.getRunTimestamp();
AppRunLogMetrics.recordRunCompleted(appName, buffer.getServerId(), durationMs);
AppRunLogMetrics.recordLinesCapture(appName, buffer.getTotalLineCount());
buffer.close();
}
}

public static RunLogBuffer getBuffer(String appName, String runTimestamp) {
return activeBuffers.get(bufferKey(appName, runTimestamp));
}

static void cleanupOldRuns(String appName) {
List<Long> timestamps = listRunTimestamps(appName);
if (timestamps.size() <= maxRunsPerApp) {
return;
}
List<Long> toDelete = timestamps.subList(maxRunsPerApp, timestamps.size());
Path appDir = resolveAppDir(appName);
for (long ts : toDelete) {
try (DirectoryStream<Path> stream = Files.newDirectoryStream(appDir, ts + "-*.log")) {
for (Path entry : stream) {
Files.deleteIfExists(entry);
}
} catch (IOException e) {
// best-effort cleanup
}
}
AppRunLogMetrics.recordCleanup(appName, toDelete.size());
}
Copy link

Copilot AI Mar 21, 2026

Choose a reason for hiding this comment

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

startCapture/stopCapture/cleanupOldRuns invoke AppRunLogMetrics.*, but there is no AppRunLogMetrics class in the repository (only these references). This makes the module uncompilable; add the missing metrics class or remove/replace these calls.

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 23, 2026 04:26
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment on lines +135 to +137
buffer.startFlusher();
AppRunLogMetrics.recordRunStarted(appName, serverId);
return buffer;
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

AppRunLogAppender references AppRunLogMetrics (e.g., recordRunStarted) but there is no AppRunLogMetrics class in the codebase, so this will not compile. Either add the missing metrics implementation (and wiring) or remove these calls / replace with the existing metrics facility used elsewhere in the service.

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +29
* <p>Configured via the {@code logging:} section in {@code openmetadata.yaml}. Uses two-tier
* matching: MDC for the scheduler thread, thread name prefixes for worker threads.
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

The class-level Javadoc says this appender is configured via openmetadata.yaml, but the implementation self-registers programmatically via ensureRegistered() and does not read Dropwizard logging config. Please update the Javadoc to reflect the actual configuration/registration mechanism (and how operators can disable/enable it).

Suggested change
* <p>Configured via the {@code logging:} section in {@code openmetadata.yaml}. Uses two-tier
* matching: MDC for the scheduler thread, thread name prefixes for worker threads.
* <p>This appender is registered programmatically and is not wired through Dropwizard's
* {@code logging:} section in {@code openmetadata.yaml}. Call {@link #ensureRegistered()} once
* during application startup to attach it to the appropriate {@link LoggerContext}. Operators
* who do not want per-run app logs can avoid invoking {@code ensureRegistered()} (or remove this
* appender from the {@link LoggerContext} at runtime).

Copilot uses AI. Check for mistakes.
Comment on lines +85 to +92
void flush() {
List<String> batch = drainPending();
if (batch.isEmpty()) {
return;
}
String batchText = String.join("\n", batch);
writeToFile(batchText);
}
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

flush() drains pending even when the file writer is not available (e.g., if startFlusher() failed to open the log file or was never called). Since writeToFile() returns early when writer == null, this causes buffered log lines to be dropped silently. Consider short-circuiting flush() when writer is null (or lazily opening/retrying the writer) so pending lines are preserved until they can be written.

Copilot uses AI. Check for mistakes.
Comment on lines +1580 to +1581
if (readerStats != null && totalRecords > readerStats.getTotalRecords()) {
readerStats.setTotalRecords(totalRecords);
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

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

readerStats.getTotalRecords() can be null (e.g., if reader stats were created elsewhere without initializing totalRecords). The comparison totalRecords > readerStats.getTotalRecords() will then throw an NPE. Please null-guard (treat null as 0) before comparing/updating the reader total.

Suggested change
if (readerStats != null && totalRecords > readerStats.getTotalRecords()) {
readerStats.setTotalRecords(totalRecords);
if (readerStats != null) {
Integer readerTotalRecords = readerStats.getTotalRecords();
int safeReaderTotalRecords = readerTotalRecords != null ? readerTotalRecords : 0;
if (totalRecords > safeReaderTotalRecords) {
readerStats.setTotalRecords(totalRecords);
}

Copilot uses AI. Check for mistakes.
Copilot AI review requested due to automatic review settings March 23, 2026 09:39
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 256 out of 258 changed files in this pull request and generated 6 comments.

Comment on lines +15 to +30
import java.lang.reflect.Field;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.openmetadata.schema.entity.app.App;
import org.openmetadata.service.Entity;
import org.openmetadata.service.jdbi3.AppRepository;
import org.openmetadata.service.jdbi3.CollectionDAO;
import sun.misc.Unsafe;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This test uses sun.misc.Unsafe.allocateInstance() to instantiate AppResource. Accessing JDK internals via reflection is brittle on Java 21+ (module encapsulation) and can fail in CI without explicit --add-opens. Prefer constructing AppResource normally (or via a test-friendly constructor/factory) and injecting dependencies via setters/constructors, or use a Mockito spy/subclass to override the repository as needed.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
package org.openmetadata.service.apps.scheduler;

import static org.junit.jupiter.api.Assertions.assertFalse;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This file is missing the standard Apache 2.0 license header block before the package declaration. Please add the license header at the top of the file.

Copilot uses AI. Check for mistakes.
Comment on lines +11 to +29
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.MockedStatic;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.openmetadata.schema.entity.app.App;
import org.openmetadata.service.Entity;
import org.openmetadata.service.apps.AbstractNativeApplication;
import org.openmetadata.service.apps.ApplicationHandler;
import org.openmetadata.service.jdbi3.CollectionDAO;
import org.openmetadata.service.search.SearchRepository;
import org.quartz.Scheduler;
import sun.misc.Unsafe;

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This test uses sun.misc.Unsafe.allocateInstance() to instantiate AppScheduler. This is fragile on Java 21+ and may fail under module encapsulation. Prefer using a real constructor (or a package-private test constructor), or refactor AppScheduler to allow injecting the Scheduler dependency for tests without relying on Unsafe.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
package org.openmetadata.service.apps;

import static org.junit.jupiter.api.Assertions.assertFalse;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This file is missing the standard Apache 2.0 license header block before the package declaration. Please add the license header at the top of the file.

Copilot uses AI. Check for mistakes.
Comment on lines +47 to +66
const VECTOR_INDEXABLE_ENTITIES = new Set([
'table',
'glossary',
'glossaryterm',
'chart',
'dashboard',
'dashboarddatamodel',
'database',
'databaseschema',
'dataproduct',
'pipeline',
'mlmodel',
'metric',
'apiendpoint',
'apicollection',
'page',
'storedprocedure',
'searchindex',
'topic',
]);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The new constant VECTOR_INDEXABLE_ENTITIES hardcodes the list of entity types that support vector embeddings. This is likely to drift from backend capabilities over time; consider deriving vector-indexability from the stats payload itself (e.g., presence of vectorSuccessRecords/vectorFailedRecords) or from a single shared source of truth instead of duplicating the list in UI utils.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
package org.openmetadata.service.resources.apps;

import static org.junit.jupiter.api.Assertions.assertEquals;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This file is missing the standard Apache 2.0 license header block before the package declaration (consistent across other Java sources/tests in this repo). Please add the license header at the top of the file.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 256 out of 259 changed files in this pull request and generated 8 comments.

Comment on lines +1673 to 1674
"retry-count": "Contagem de tentativas",
"return": "بازگشت",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This locale file is predominantly Persian, but the newly added retry-count translation here is Portuguese. Please translate it to Persian to avoid mixed-language UI.

Copilot uses AI. Check for mistakes.
Comment on lines +2820 to 2821
"no-retry-queue-records": "Nenhum registro de tentativa de indexação ao vivo encontrado. Todas as entidades foram indexadas com sucesso.",
"no-roles-assigned": "هیچ نقشی اختصاص داده نشده است.",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This locale file is predominantly Persian, but the newly added no-retry-queue-records message here is Portuguese. Please translate it to Persian so users don’t see mixed-language messages.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
package org.openmetadata.service.apps.scheduler;

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java test files are expected to include the Apache 2.0 license header before the package declaration (see e.g. openmetadata-service/src/test/java/org/openmetadata/service/jdbi3/BulkExecutorTest.java:1-13). Please add the standard header block here as well.

Copilot uses AI. Check for mistakes.
]
: []),
];
}, [appData, jsonSchema, loadingState]);
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This tabs useMemo uses t(...) for labels (including the newly added Live Indexing tab), but t is not included in the dependency array. This can cause tab labels to not update when the UI language changes.

Copilot uses AI. Check for mistakes.
Comment on lines +1145 to 1146
"live-indexing": "Indexação ao vivo",
"load-more": "بارگذاری بیشتر",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This locale file is predominantly Persian, but the newly added live-indexing translation here is Portuguese. Please translate it to Persian so the locale remains consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +276 to +280
...(successContext?.stats?.vectorStats?.totalRecords
? [
{
title: t('label.vector-embedding-plural'),
dataIndex: 'vectorEmbeddings',
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The vector-embeddings column is only enabled when successContext?.stats?.vectorStats?.totalRecords is truthy. This hides vector stats for failed runs (where only failureContext may be present) even though per-entity vectorSuccessRecords/vectorFailedRecords can still exist. Consider gating the column on either context (or on presence of vectorEmbeddings in the data) so the column appears consistently for failed runs too.

Copilot uses AI. Check for mistakes.
Comment on lines +2187 to 2188
"vector-embedding-plural": "Embeddings vetoriais",
"vector-stat-plural": "Vector Stats",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This locale file is predominantly Persian, but the newly added vector-embedding-plural translation here is Portuguese. Please translate it to Persian so the locale remains consistent.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +2
package org.openmetadata.service.apps;

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java test files are expected to include the Apache 2.0 license header before the package declaration (see e.g. openmetadata-service/src/test/java/org/openmetadata/service/jdbi3/BulkExecutorTest.java:1-13). Please add the standard header block here as well.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 254 out of 257 changed files in this pull request and generated 3 comments.

Comment on lines +1 to +5
package org.openmetadata.service.resources.apps;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java test file is missing the standard Apache 2.0 license header block before the package declaration (required across Java source/tests in this repo). Add the license header at the top of the file.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
package org.openmetadata.service.apps.scheduler;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java test file is missing the standard Apache 2.0 license header block before the package declaration. Add the license header at the top of the file to match the repo convention.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
package org.openmetadata.service.apps;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.mockito.Mockito.mock;

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java test file is missing the standard Apache 2.0 license header block before the package declaration. Add the license header at the top of the file to match other Java sources/tests.

Copilot uses AI. Check for mistakes.
chirag-madlani
chirag-madlani previously approved these changes Mar 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 254 out of 257 changed files in this pull request and generated 2 comments.

Comment on lines +45 to +49
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
appResource = (AppResource) unsafe.allocateInstance(AppResource.class);

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This test uses sun.misc.Unsafe to instantiate AppResource, which is an internal JDK API and can break under stricter module access or future JDKs. Prefer constructing the resource normally (or via a test subclass) and injecting mocks via constructor/setters, or use reflection without Unsafe if necessary.

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +190
export interface SearchIndexRetryRecord {
entityId: string;
entityFqn: string;
failureReason: string;
status: string;
entityType: string;
retryCount: number;
claimedAt: string | null;
}
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

claimedAt is backed by a java.sql.Timestamp on the server side; with the default Jackson settings this typically serializes as an epoch number, not a string. Align the UI type with the actual API payload (e.g., number | null, or a union if the API is intentionally stringified).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 255 out of 258 changed files in this pull request and generated 2 comments.

Comment on lines +43 to +52
// Verify vector-indexable entities get a number (0 when no vectorSuccessRecords in mock)
const tableEntry = resultData.find((e) => e.name === 'Table');

expect(tableEntry?.vectorEmbeddings).toBe(0);

// Verify non-vector-indexable entities get null
const userEntry = resultData.find((e) => e.name === 'User');

expect(userEntry?.vectorEmbeddings).toBeNull();

Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This test validates the presence of vectorEmbeddings, but it never asserts the non-zero path where vectorSuccessRecords is provided. Add a case that includes a vector-indexable entity with vectorSuccessRecords set and assert that getEntityStatsData() maps it correctly, so the new behavior is actually covered by tests.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +415 to +422
@Min(0)
@Max(1000)
int limitParam,
@Parameter(description = "Offset records. (0 to 1000000, default = 0)")
@DefaultValue("0")
@QueryParam("offset")
@Min(0)
int offset) {
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The validation annotations/descriptions are inconsistent: limit is documented as "1 to 1000" but @min(0) allows 0, and offset is documented as up to 1,000,000 but has no @max. Align the constraints (and/or descriptions) with the intended supported ranges to avoid confusing API consumers and potential large scans.

Suggested change
@Min(0)
@Max(1000)
int limitParam,
@Parameter(description = "Offset records. (0 to 1000000, default = 0)")
@DefaultValue("0")
@QueryParam("offset")
@Min(0)
int offset) {
@Min(1)
@Max(1000)
int limitParam,
@Parameter(description = "Offset records. (0 to 1000000, default = 0)")
@DefaultValue("0")
@QueryParam("offset")
@Min(0)
@Max(1000000) int offset) {

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 259 out of 262 changed files in this pull request and generated 2 comments.

Comment on lines +1 to +5
package org.openmetadata.service.jdbi3;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java file is missing the standard Apache 2.0 license header block before the package declaration. Add the license header to comply with the repo’s Java file convention (see existing Java sources/tests).

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
package org.openmetadata.service.jdbi3;

import org.openmetadata.schema.type.Include;

/**
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

New Java source file is missing the standard Apache 2.0 license header block before the package declaration. Add the license header to comply with the repo’s Java file convention.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 259 out of 262 changed files in this pull request and generated 3 comments.

Comment on lines 706 to 712
"entity-distribution": "توزیع {{entity}}",
"entity-failed": "{{entity}} ناموفق",
"entity-feed-plural": "فیدهای نهاد",
"entity-fqn": "FQN da entidade",
"entity-hyphen-value": "{{entity}} - {{value}}",
"entity-id": "شناسه {{entity}}",
"entity-id-match": "مطابقت با شناسه",
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

The new translations added in this file appear to be Portuguese (e.g., "FQN da entidade", "Indexação ao vivo") while the rest of the locale content is Persian. Please replace these with correct Persian translations so the locale stays consistent.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,33 @@
package org.openmetadata.service.jdbi3;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This new Java file is missing the standard Apache 2.0 license header block before the package declaration. Please add the project’s license header at the top of the file to match repository conventions.

Copilot uses AI. Check for mistakes.
@@ -0,0 +1,67 @@
package org.openmetadata.service.jdbi3;
Copy link

Copilot AI Mar 30, 2026

Choose a reason for hiding this comment

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

This new test file is missing the standard Apache 2.0 license header block before the package declaration. Please add the license header at the top to match repository conventions.

Copilot uses AI. Check for mistakes.
@gitar-bot
Copy link
Copy Markdown

gitar-bot bot commented Mar 31, 2026

Code Review 🚫 Blocked 22 resolved / 29 findings

Search index enhancement blocked due to 9 open critical and important findings including lost entity icon mappings (~30 EntityType keys), uncleaned auth login polling with up to 100 recursive timeouts, and empty MatillionDPC schema allowing invalid authentication. Additionally, 4 minor issues require resolution including buffer newline loss, repeated method calls on hot paths, and unsafe float overflow.

🚨 Bug: Entity icon mapping lost ~30 EntityType keys during refactor

The entityIconMapping was moved from inside getEntityIcon() to module level, but in the process many EntityType keys were removed. The old mapping had dual entries (both SearchIndex.X and EntityType.X) for most entity types, but the new mapping only retains one key per entity. Since SearchIndex and EntityType enums have different string values for several entities (e.g., SearchIndex.ML_MODEL_SERVICE = 'mlModelService' vs EntityType.MLMODEL_SERVICE = 'mlmodelService'), and some EntityType values have no SearchIndex equivalent at all (e.g., CLASSIFICATION, BOT, TEAM, APPLICATION, PERSONA, ROLE, POLICY, EVENT_SUBSCRIPTION, INGESTION_PIPELINE, ALERT, KPI, DATA_CONTRACT, USER), callers passing EntityType values will get undefined from the mapping — resulting in missing icons across the UI.

This will affect any component that calls getEntityIcon() with an EntityType string, which is widespread in the codebase.

Suggested fix
Restore the removed EntityType keys in the mapping, or add a normalization step in `getEntityIcon` that maps EntityType values to their SearchIndex equivalents before the lookup. At minimum, re-add:
```ts
[EntityType.DATABASE]: DatabaseIcon,
[EntityType.TABLE]: TableIcon,
[EntityType.TOPIC]: TopicIcon,
// ... all other removed EntityType entries
```
⚠️ Performance: getCertificationClassification() called repeatedly on hot paths

The method getCertificationClassification() is called on every entity read (via getCertification() and getTags()), every tag update (via updateTags()), and every entity create. Each call goes through SettingsCache.getSettingOrDefault() which involves JSON serialization/deserialization (pojoToJson + readValue). For batch operations like applyCertificationBatch(), it's called once which is fine, but getTags() is called per-entity during reads and list operations, making this a hot path.

While SettingsCache caches the raw setting, the method still does JSON round-trip deserialization on every call to extract the classification name. For bulk entity listing (e.g., listing 100 entities), this means 200+ unnecessary JSON parse cycles (once for getTags filtering, once for getCertification).

Suggested fix
Cache the certification classification name at the EntityRepository instance level (or as a static with TTL), avoiding repeated JSON deserialization:

private volatile String cachedCertClassification;
private volatile long certClassificationTs;

protected String getCertificationClassification() {
  if (!supportsCertification) return null;
  long now = System.currentTimeMillis();
  if (cachedCertClassification != null && now - certClassificationTs < 60_000) {
    return cachedCertClassification;
  }
  // ... existing logic ...
  certClassificationTs = now;
  return cachedCertClassification = result;
}
⚠️ Edge Case: MatillionDPC schema has no required fields, allows empty auth

The new matillionDPC.json schema defines "required": [], meaning a MatillionDPCAuth object can be created with no credentials at all — no clientId, no clientSecret, and no personalAccessToken. This will pass schema validation but fail at runtime when attempting to authenticate against the Matillion DPC API.

Typically, OAuth2 client credentials (clientId + clientSecret) or a personalAccessToken should be required. At minimum, consider requiring clientId and clientSecret, or use a oneOf/anyOf to enforce that at least one authentication method is provided.

Suggested fix
"required": ["clientId", "clientSecret"],
💡 Edge Case: RunLogBuffer.flush() loses the trailing newline between batches

In RunLogBuffer.flush(), lines are joined with `` via String.join(" ", batch) and then written with `writer.newLine()` after the joined text. This means each batch is separated by a newline, but when the file is read back, consecutive batches produce correct JSON-lines format.

However, if a single batch contains one line, the output is line. If the next batch also has one line, it's line. This is correct. But the actual concern is: String.join(" ", batch) for a batch of ["a", "b"] produces a b, then writer.newLine() adds another ``, giving a b. This is correct JSON-lines format. No issue here — disregard.

💡 Edge Case: handleAddRow uses Date.now() for IDs risking duplicates

In RelatedTerms.tsx, both handleStartAdding and handleAddRow use String(Date.now()) to generate row IDs. If a user clicks the add button rapidly (or programmatically), two rows could receive the same ID since Date.now() has millisecond resolution. This would cause React key collisions and make handleRemoveRow/handleRelationTypeChange/handleTermsChange operate on the wrong row.

Suggested fix
Use an incrementing counter instead:

const nextRowId = useRef(0);
// then in handlers:
id: String(nextRowId.current++)
💡 Edge Case: Decimal-to-float overflow can produce non-JSON-safe Infinity

On line 110, float(value) is called when value.is_finite() is True, but a finite Decimal with magnitude beyond float range (e.g. Decimal('1e999')) overflows to float('inf'), which is not valid JSON and will cause json.dumps / model_dump_json() to raise.

In practice this is extremely unlikely for database sample data, and the outer exception handler in ingest_table_sample_data would catch the downstream serialization failure gracefully, so impact is low.

Suggested fix
if isinstance(value, decimal.Decimal):
    if not value.is_finite():
        return str(value)
    f = float(value)
    return f if math.isfinite(f) else str(value)
💡 Security: BigQuery region-aware queries use string format, not params

The new BIGQUERY_GET_STORED_PROCEDURES_BY_REGION and BIGQUERY_GET_TABLE_DDLS_BY_REGION queries interpolate {region} via Python string .format() directly into the SQL string. While the region value comes from the BigQuery API (dataset_obj.location) rather than user input, this pattern is fragile — an unexpected character in the location string could break the query or cause unintended behavior. The existing non-region queries use the same .format() pattern for database_name and schema_name, so this is consistent with the codebase, but worth noting.

✅ 22 resolved
Bug: AppRunLogMetrics class is missing — code will not compile

📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/RunLogBuffer.java:92 📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:136 📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:145-146 📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:171
The AppRunLogMetrics class is referenced in both RunLogBuffer.java (line 92) and AppRunLogAppender.java (lines 136, 145, 146, 171) but does not exist anywhere in the codebase. This will cause a compile-time failure. All four static method calls (recordFlush, recordRunStarted, recordRunCompleted, recordLinesCapture, recordCleanup) have no backing implementation.

Bug: periodicSyncSinkStats has check-then-act race on volatile field

📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexExecutor.java:135-136 📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/bundles/searchIndex/SearchIndexExecutor.java:1522-1528
The lastSinkSyncTime field is declared volatile, but periodicSyncSinkStats() performs a non-atomic read-compare-write: it reads the field, checks if enough time has passed, then writes the new timestamp. Multiple consumer threads (up to 40 from consumerExecutor) call this concurrently via processTask(), so several threads may simultaneously observe a stale value and all trigger syncSinkStatsFromBulkSink(). The practical impact is limited to redundant sync calls (no data corruption), but it defeats the throttling intent.

Edge Case: Thread prefix matching can cross-capture logs between apps

📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:65-73 📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:131-133
Thread prefix bindings are stored in a flat global list (threadPrefixBindings). If two apps run concurrently and both register the same thread prefix (e.g., "reindex-"), the append() method iterates the list and the first matching binding wins, routing worker-thread logs to the wrong app's buffer. This could also happen if a previous capture's prefixes were not cleaned up before a new one starts.

Edge Case: abbreviateLoggerName crashes on empty package segments

📄 openmetadata-service/src/main/java/org/openmetadata/service/apps/logging/AppRunLogAppender.java:96-97
If loggerName contains consecutive dots (e.g., "org..service.Foo"), split("\.") produces an empty string element, and parts[i].charAt(0) throws StringIndexOutOfBoundsException. While malformed logger names are unlikely in practice, a guard would make the helper more robust.

Bug: Developer-local config defaults committed to openmetadata.yaml

📄 conf/openmetadata.yaml:244 📄 conf/openmetadata.yaml:249 📄 conf/openmetadata.yaml:252 📄 conf/openmetadata.yaml:269 📄 conf/openmetadata.yaml:448 📄 conf/openmetadata.yaml:463 📄 conf/openmetadata.yaml:483-484 📄 conf/openmetadata.yaml:602
The conf/openmetadata.yaml template has multiple default values changed that appear to be developer-local settings rather than intentional changes for this PR:

  1. DB driver/scheme/port: MySQL → PostgreSQL (lines 244, 249) — breaks the documented default for MySQL users
  2. searchType: elasticsearchopensearch (line 448)
  3. semanticSearchEnabled: falsetrue (line 483)
  4. embeddingProvider: bedrockdjl (line 484)
  5. fernetKey: Changed to a different sample key (line 602)
  6. Connection pool tuning: maxSize 100→150, leakDetectionThreshold 60s→5min, maxConnTotal 30→50

These changes will affect every developer and deployment that relies on the default configuration template. The database driver change alone would cause startup failures for anyone running MySQL (the documented default). If the pool tuning and search type changes are intentional, they should be in a separate commit with justification.

...and 17 more resolved from earlier reviews

🤖 Prompt for agents
Code Review: Search index enhancement blocked due to 9 open critical and important findings including lost entity icon mappings (~30 EntityType keys), uncleaned auth login polling with up to 100 recursive timeouts, and empty MatillionDPC schema allowing invalid authentication. Additionally, 4 minor issues require resolution including buffer newline loss, repeated method calls on hot paths, and unsafe float overflow.

1. 💡 Edge Case: RunLogBuffer.flush() loses the trailing newline between batches

   In `RunLogBuffer.flush()`, lines are joined with `
   ` via `String.join("
   ", batch)` and then written with `writer.newLine()` after the joined text. This means each batch is separated by a newline, but when the file is read back, consecutive batches produce correct JSON-lines format.
   
   However, if a single batch contains one line, the output is `line
   `. If the next batch also has one line, it's `line
   `. This is correct. But the actual concern is: `String.join("
   ", batch)` for a batch of ["a", "b"] produces `a
   b`, then `writer.newLine()` adds another `
   `, giving `a
   b
   `. This is correct JSON-lines format. No issue here — disregard.

2. ⚠️ Performance: getCertificationClassification() called repeatedly on hot paths

   The method `getCertificationClassification()` is called on every entity read (via `getCertification()` and `getTags()`), every tag update (via `updateTags()`), and every entity create. Each call goes through `SettingsCache.getSettingOrDefault()` which involves JSON serialization/deserialization (`pojoToJson` + `readValue`). For batch operations like `applyCertificationBatch()`, it's called once which is fine, but `getTags()` is called per-entity during reads and list operations, making this a hot path.
   
   While SettingsCache caches the raw setting, the method still does JSON round-trip deserialization on every call to extract the classification name. For bulk entity listing (e.g., listing 100 entities), this means 200+ unnecessary JSON parse cycles (once for getTags filtering, once for getCertification).

   Suggested fix:
   Cache the certification classification name at the EntityRepository instance level (or as a static with TTL), avoiding repeated JSON deserialization:
   
   private volatile String cachedCertClassification;
   private volatile long certClassificationTs;
   
   protected String getCertificationClassification() {
     if (!supportsCertification) return null;
     long now = System.currentTimeMillis();
     if (cachedCertClassification != null && now - certClassificationTs < 60_000) {
       return cachedCertClassification;
     }
     // ... existing logic ...
     certClassificationTs = now;
     return cachedCertClassification = result;
   }

3. 💡 Edge Case: handleAddRow uses Date.now() for IDs risking duplicates

   In `RelatedTerms.tsx`, both `handleStartAdding` and `handleAddRow` use `String(Date.now())` to generate row IDs. If a user clicks the add button rapidly (or programmatically), two rows could receive the same ID since `Date.now()` has millisecond resolution. This would cause React key collisions and make `handleRemoveRow`/`handleRelationTypeChange`/`handleTermsChange` operate on the wrong row.

   Suggested fix:
   Use an incrementing counter instead:
   
   const nextRowId = useRef(0);
   // then in handlers:
   id: String(nextRowId.current++)

4. 💡 Edge Case: Decimal-to-float overflow can produce non-JSON-safe Infinity

   On line 110, `float(value)` is called when `value.is_finite()` is True, but a finite `Decimal` with magnitude beyond `float` range (e.g. `Decimal('1e999')`) overflows to `float('inf')`, which is not valid JSON and will cause `json.dumps` / `model_dump_json()` to raise.
   
   In practice this is extremely unlikely for database sample data, and the outer exception handler in `ingest_table_sample_data` would catch the downstream serialization failure gracefully, so impact is low.

   Suggested fix:
   if isinstance(value, decimal.Decimal):
       if not value.is_finite():
           return str(value)
       f = float(value)
       return f if math.isfinite(f) else str(value)

5. ⚠️ Edge Case: MatillionDPC schema has no required fields, allows empty auth

   The new `matillionDPC.json` schema defines `"required": []`, meaning a MatillionDPCAuth object can be created with no credentials at all — no `clientId`, no `clientSecret`, and no `personalAccessToken`. This will pass schema validation but fail at runtime when attempting to authenticate against the Matillion DPC API.
   
   Typically, OAuth2 client credentials (`clientId` + `clientSecret`) or a `personalAccessToken` should be required. At minimum, consider requiring `clientId` and `clientSecret`, or use a `oneOf`/`anyOf` to enforce that at least one authentication method is provided.

   Suggested fix:
   "required": ["clientId", "clientSecret"],

6. 🚨 Bug: Entity icon mapping lost ~30 EntityType keys during refactor

   The `entityIconMapping` was moved from inside `getEntityIcon()` to module level, but in the process many EntityType keys were removed. The old mapping had dual entries (both `SearchIndex.X` and `EntityType.X`) for most entity types, but the new mapping only retains one key per entity. Since `SearchIndex` and `EntityType` enums have different string values for several entities (e.g., `SearchIndex.ML_MODEL_SERVICE = 'mlModelService'` vs `EntityType.MLMODEL_SERVICE = 'mlmodelService'`), and some EntityType values have no SearchIndex equivalent at all (e.g., `CLASSIFICATION`, `BOT`, `TEAM`, `APPLICATION`, `PERSONA`, `ROLE`, `POLICY`, `EVENT_SUBSCRIPTION`, `INGESTION_PIPELINE`, `ALERT`, `KPI`, `DATA_CONTRACT`, `USER`), callers passing EntityType values will get `undefined` from the mapping — resulting in missing icons across the UI.
   
   This will affect any component that calls `getEntityIcon()` with an EntityType string, which is widespread in the codebase.

   Suggested fix:
   Restore the removed EntityType keys in the mapping, or add a normalization step in `getEntityIcon` that maps EntityType values to their SearchIndex equivalents before the lookup. At minimum, re-add:
   ```ts
   [EntityType.DATABASE]: DatabaseIcon,
   [EntityType.TABLE]: TableIcon,
   [EntityType.TOPIC]: TopicIcon,
   // ... all other removed EntityType entries
   ```

7. 💡 Security: BigQuery region-aware queries use string format, not params

   The new `BIGQUERY_GET_STORED_PROCEDURES_BY_REGION` and `BIGQUERY_GET_TABLE_DDLS_BY_REGION` queries interpolate `{region}` via Python string `.format()` directly into the SQL string. While the `region` value comes from the BigQuery API (`dataset_obj.location`) rather than user input, this pattern is fragile — an unexpected character in the location string could break the query or cause unintended behavior. The existing non-region queries use the same `.format()` pattern for `database_name` and `schema_name`, so this is consistent with the codebase, but worth noting.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 260 out of 263 changed files in this pull request and generated 5 comments.

Comments suppressed due to low confidence (2)

openmetadata-service/src/main/java/org/openmetadata/service/search/indexes/QueryCostRecordIndex.java:34

  • The catch (EntityNotFoundException) block logs "skipping indexing" but then rethrows the exception, which will still fail indexing for the QueryCostRecord. If the intent is to skip indexing when the referenced Query is missing, return the partially-built doc (or omit the query field) instead of throwing; otherwise, update the log message to reflect that indexing will fail.
    } catch (EntityNotFoundException ex) {
      LOG.warn(
          "Query entity [{}] not found for QueryCostRecord, skipping indexing: {}",
          queryReference != null ? queryReference.getId() : "null",
          ex.getMessage());
      throw ex;
    }

openmetadata-service/src/main/java/org/openmetadata/service/search/indexes/QueryCostRecordIndex.java:34

  • The method logs "skipping indexing" when the referenced Query is missing, but then rethrows the exception, which will still fail indexing. Either actually skip (return the partial doc / omit the query fields) or change the log level/message and wrap into the expected indexing error handling.
    } catch (EntityNotFoundException ex) {
      LOG.warn(
          "Query entity [{}] not found for QueryCostRecord, skipping indexing: {}",
          queryReference != null ? queryReference.getId() : "null",
          ex.getMessage());
      throw ex;
    }

Comment on lines +183 to +187
fetchRetryQueue(0);
},
}}
paginationVisible={records.length > 0 && paging.total > pageSize}
rowKey={(record) => `${record.entityId}-${record.entityFqn}`}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

Table component props (TableComponentProps) do not define a paginationVisible prop, so passing paginationVisible={...} here will fail TypeScript compilation. Use the existing pagination controls (pagination={false} / conditional pagination config, or customPaginationProps.showPagination) instead of an unsupported prop, or add/implement paginationVisible in the shared Table component if that's intended.

Copilot uses AI. Check for mistakes.
Comment on lines 2818 to 2822
"no-related-terms-available": "هیچ واژه مرتبطی موجود نیست.",
"no-relations-found": "رابطه‌ای برای این اصطلاح یافت نشد",
"no-retry-queue-records": "Nenhum registro de tentativa de indexação ao vivo encontrado. Todas as entidades foram indexadas com sucesso.",
"no-roles-assigned": "هیچ نقشی اختصاص داده نشده است.",
"no-rule-found": "هیچ قانونی یافت نشد.",
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This newly added message is in Portuguese in a Persian locale file. Please translate it to Persian (or use the project’s standard fallback language) so the empty state text is not shown in the wrong language.

Copilot uses AI. Check for mistakes.
Comment on lines +184 to +187
},
}}
paginationVisible={records.length > 0 && paging.total > pageSize}
rowKey={(record) => `${record.entityId}-${record.entityFqn}`}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

Table component props do not include paginationVisible, so this will fail TypeScript compilation (or be ignored at runtime). Use the existing customPaginationProps.showPagination pattern, or extend TableComponentProps to support paginationVisible consistently.

Copilot uses AI. Check for mistakes.
Comment on lines +423 to +427
App app = repository.getByName(uriInfo, name, repository.getFields("id"));
if (!"SearchIndexingApplication".equals(app.getName())) {
throw new BadRequestException(
"Live indexing queue is only available for SearchIndexingApplication");
}
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This endpoint returns live indexing retry queue records without any authorization check. Other AppResource actions call authorizer.authorize(...) with an appropriate OperationContext; please add an authorization check before returning queue data.

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +31
// Verify basic structure
expect(resultData.length).toBeGreaterThan(0);

// Verify the result matches the sorted mock data
expect(resultData).toEqual(sortedMockData);
// Verify sorted by name
for (let i = 1; i < resultData.length; i++) {
expect(
resultData[i - 1].name.localeCompare(resultData[i].name)
).toBeLessThanOrEqual(0);
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

This test no longer asserts the expected values for totalRecords/successRecords/failedRecords per entity, so regressions in the mapping/sorting logic could slip through. Consider keeping the previous full expected-array assertion and extend it to cover vectorEmbeddings for vector-indexable vs non-indexable entities.

Copilot generated this review using guidance from repository custom instructions.
@sonarqubecloud
Copy link
Copy Markdown

@sonarqubecloud
Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend safe to test Add this label to run secure Github workflows on PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Search-Issue] Issue in ES/OS

4 participants