Skip to content

Add YAML/JSON backward compatibility for xDS resource files - #1324

Merged
minwoox merged 3 commits into
line:mainfrom
minwoox:xds_yaml_compat
Jul 3, 2026
Merged

Add YAML/JSON backward compatibility for xDS resource files#1324
minwoox merged 3 commits into
line:mainfrom
minwoox:xds_yaml_compat

Conversation

@minwoox

@minwoox minwoox commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Motivation:

  • xDS resources are currently stored as .json files, but are planned to be migrated to .yaml format.
  • To support safe rollout and rollback, the system must handle both .json and .yaml files coexisting in the same repository without errors.

Modifications:

  • XdsResourceWatchingService: accept EntryType.YAML alongside JSON during the initial repository scan; handle UPSERT_YAML change type in the diff watcher; normalize YAML content to JSON before invoking handleXdsResource() so all implementations continue to use JSON_MESSAGE_MARSHALLER without format-specific logic.
  • XdsResourceManager: add alternativeFileName() helper that swaps between .json and .yaml extensions; change updateOrDelete() to search for both the requested filename and its alternative so that update and delete operations locate the file regardless of which format it was stored in; pass the resolved filename back to the task via Function<String, Runnable> so the correct file is mutated; make push() emit Change.ofYamlUpsert when the resolved filename ends with .yaml.

Result:

  • .yaml and .json xDS resource files can coexist in the same group repository.

Motivation:
- xDS resources are currently stored as .json files, but are planned to
  be migrated to .yaml format.
- To support safe rollout and rollback, the system must handle both
  .json and .yaml files coexisting in the same repository without errors.

Modifications:
- XdsResourceWatchingService: accept EntryType.YAML alongside JSON
  during the initial repository scan; handle UPSERT_YAML change type in
  the diff watcher; normalize YAML content to JSON before invoking
  handleXdsResource() so all implementations continue to use
  JSON_MESSAGE_MARSHALLER without format-specific logic.
- XdsResourceManager: add alternativeFileName() helper that swaps
  between .json and .yaml extensions; change updateOrDelete() to search
  for both the requested filename and its alternative so that update and
  delete operations locate the file regardless of which format it was
  stored in; pass the resolved filename back to the task via
  Function<String, Runnable> so the correct file is mutated; make
  push() emit Change.ofYamlUpsert when the resolved filename ends
  with .yaml.

Result:
- .yaml and .json xDS resource files can coexist in the same group
  repository; the control plane, CRUD API, and endpoint read API all
  handle both formats transparently.
@minwoox minwoox added this to the 0.85.0 milestone Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR extends YAML handling through content transformation, XDS resource watching, endpoint read/update flows, and related tests while preserving JSON behavior.

Changes

YAML Support Across XDS and Change Application

Layer / File(s) Summary
ContentTransformer and TransformingChangesApplier YAML support
server/src/main/java/com/linecorp/centraldogma/server/command/ContentTransformer.java, server/src/main/java/com/linecorp/centraldogma/server/internal/storage/repository/git/TransformingChangesApplier.java
Constructor validation allows JSON or YAML entry types, and content application parses and writes YAML or JSON based on the entry type.
Resource watching JsonNode contract
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingService.java
The watch callback now receives JsonNode, and init/diff handling accepts JSON and YAML entries.
Control plane and K8s endpoint fetching
xds/src/main/java/com/linecorp/centraldogma/xds/internal/ControlPlaneService.java, xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
Parsed JsonNode content is merged into protobuf builders, and K8s endpoint fetching follows the same contract.
Resource manager dual-extension resolution
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
Update/delete now resolve the stored filename across .json and .yaml, and pushes use YAML upserts when appropriate.
Endpoint update scheduler lookup and merge
xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
Batch flush lookup checks alternate extensions, picks the transformer entry type from the resolved filename, and merges JSON trees by traversal.
Endpoint read service dual-format support
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadService.java, xds/src/main/java/com/linecorp/centraldogma/xds/internal/CentralDogmaXdsResources.java
Endpoint listing and reads now handle JSON and YAML, return the actual entry type, and search by base name across both extensions.
Tests for YAML endpoint, watching, and compatibility
xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointServiceTest.java, xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java, xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadServiceTest.java, xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java, xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsYamlCompatibilityTest.java
Tests add YAML coverage for endpoint CRUD, register/deregister flows, endpoint reading/listing, watch handling, and end-to-end compatibility with discovery.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

  • line/centraldogma#1151: Both PRs modify XdsEndpointUpdateScheduler to change how endpoint updates are batched and applied.
  • line/centraldogma#1229: Introduces the YAML primitives and entry/change types that this PR consumes in XDS and change application.

Suggested labels: new feature

Suggested reviewers: trustin, jrhee17, ikhoon

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding YAML/JSON compatibility for xDS resource files.
Description check ✅ Passed The description is directly related to the changeset and accurately describes the YAML/JSON compatibility work.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java (1)

183-202: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Detect duplicate endpoint files before transforming.

This lookup has the same ambiguity as the resource manager: if both endpoint variants exist, FIND_ONE_WITHOUT_CONTENT makes the batch update transform an arbitrary format/path. Fetch both candidates and reject the update when both *.json and *.yaml are present for the same endpoint.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`
around lines 183 - 202, The endpoint lookup in XdsEndpointUpdateScheduler is
ambiguous when both JSON and YAML variants exist because find(Revision.HEAD,
fileName + ',' + altFileName, FIND_ONE_WITHOUT_CONTENT) returns an arbitrary
match. Update this flow to explicitly inspect both candidates before creating
the ContentTransformer and BatchUpdateTransformer, and reject the update with an
error if both the primary and alternative endpoint files are present. Keep the
fix localized around the repository.find handling and the
resolvedFileName/entryType selection logic.
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java (1)

275-288: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Don’t hide duplicate JSON/YAML variants with FIND_ONE.

Using FIND_ONE_WITHOUT_CONTENT means the code cannot tell whether both foo.json and foo.yaml exist for the same logical resource; update/delete then mutates whichever entry is returned first. Fetch both candidates and fail with a deterministic conflict if both are present, or explicitly define precedence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`
around lines 275 - 288, Fetching with XdsResourceManager’s repository.find using
FIND_ONE_WITHOUT_CONTENT hides when both the primary and alternative files
exist, so update the resolution logic to inspect both candidates explicitly. In
XdsResourceManager around alternativeFileName and the repository.find/handle
flow, fetch both fileName and altFileName, detect when both entries are present,
and return a deterministic conflict/error instead of silently choosing the first
result. If only one exists, continue with that resolvedFileName; if neither
exists, keep the NOT_FOUND behavior.
xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java (1)

181-196: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Remove the generated .json endpoint when deleting a YAML aggregator.

Line 191 keeps the removed aggregator’s extension, but pushK8sEndpoints() writes generated endpoint files as .json on Line 318. Deleting /k8s/endpointAggregators/foo.yaml will try to remove /k8s/endpoints/foo.yaml and leave the generated /k8s/endpoints/foo.json stale.

Proposed fix
-        final String aggregatorName = "groups/" + groupName + path.substring(0, path.length() - 5);
+        final String aggregatorPath = path.substring(0, path.length() - 5);
+        final String aggregatorName = "groups/" + groupName + aggregatorPath;
         if (updaters != null) {
             final KubernetesEndpointsUpdater updater = updaters.get(aggregatorName);
             if (updater != null) {
                 updater.close();
             }
         }
 
         // Remove corresponding endpoints.
-        final String endpointPath = AGGREGATORS_REPLCACE_PATTERN.matcher(path).replaceFirst("/endpoints/");
+        final String endpointPath =
+                AGGREGATORS_REPLCACE_PATTERN.matcher(aggregatorPath).replaceFirst("/endpoints/") + ".json";
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java`
around lines 181 - 196, The endpoint removal path in
XdsKubernetesEndpointFetchingService should match the generated filename used by
pushK8sEndpoints(). When deleting an aggregator in the removal logic around
AGGATORS_REPLCACE_PATTERN and endpointPath, strip the source extension from the
aggregator name before building the corresponding /endpoints path so a deleted
.yaml aggregator removes the generated .json endpoint instead of leaving it
stale. Use the existing aggregatorName and endpointPath handling in
XdsKubernetesEndpointFetchingService to normalize the target name consistently
with pushK8sEndpoints().
🧹 Nitpick comments (1)
xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java (1)

56-121: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Executor threads leaked in new tests.

Both yamlFilesAreHandledLikeJson and yamlFilesLoadedDuringInit create a fresh newSingleThreadScheduledExecutor() per anonymous subclass instance but never shut it down, leaking a thread per test run (unlike TestXdsResourceWatchingService below, which reuses a single static executor).

♻️ Proposed fix (apply to both tests)
-            private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
+            private final ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
+            // ...

Add cleanup, e.g.:

         svc.init();
+        try {
             // test body
+        } finally {
+            exec.shutdownNow();
+        }

Also applies to: 138-183

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java`
around lines 56 - 121, The anonymous XdsResourceWatchingService test instances
leak their per-test ScheduledExecutorService because executor() returns a fresh
newSingleThreadScheduledExecutor() with no shutdown. Update both yaml-related
tests to either reuse a shared executor like TestXdsResourceWatchingService or
add cleanup that shuts down the executor after the test completes, referencing
the executor() override in XdsResourceWatchingServiceTest.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadService.java`:
- Around line 83-100: The endpoint selection in
XdsEndpointReadService.readByBase is relying on Repository.find() map iteration
order, so the returned format is not explicitly prioritized. Update readByBase
(and the getK8sEndpoint path it serves) to resolve the resource by checking the
.json variant first and then falling back to .yaml directly, instead of using
entries.values().iterator().next(); keep the existing get() fallback behavior
for the not-found case.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`:
- Around line 187-190: The create path in XdsResourceManager is only checking
the requested file name, so it can miss an existing migrated *.yaml resource and
create a duplicate *.json entry instead of failing with ALREADY_EXISTS. Update
the create branch around Change.ofJsonPatch in XdsResourceManager to check both
the requested extension and the alternate extension before constructing the
change, using the existing resource lookup logic that handles fileName and the
.yaml/.json variants.

---

Outside diff comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java`:
- Around line 183-202: The endpoint lookup in XdsEndpointUpdateScheduler is
ambiguous when both JSON and YAML variants exist because find(Revision.HEAD,
fileName + ',' + altFileName, FIND_ONE_WITHOUT_CONTENT) returns an arbitrary
match. Update this flow to explicitly inspect both candidates before creating
the ContentTransformer and BatchUpdateTransformer, and reject the update with an
error if both the primary and alternative endpoint files are present. Keep the
fix localized around the repository.find handling and the
resolvedFileName/entryType selection logic.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`:
- Around line 275-288: Fetching with XdsResourceManager’s repository.find using
FIND_ONE_WITHOUT_CONTENT hides when both the primary and alternative files
exist, so update the resolution logic to inspect both candidates explicitly. In
XdsResourceManager around alternativeFileName and the repository.find/handle
flow, fetch both fileName and altFileName, detect when both entries are present,
and return a deterministic conflict/error instead of silently choosing the first
result. If only one exists, continue with that resolvedFileName; if neither
exists, keep the NOT_FOUND behavior.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java`:
- Around line 181-196: The endpoint removal path in
XdsKubernetesEndpointFetchingService should match the generated filename used by
pushK8sEndpoints(). When deleting an aggregator in the removal logic around
AGGATORS_REPLCACE_PATTERN and endpointPath, strip the source extension from the
aggregator name before building the corresponding /endpoints path so a deleted
.yaml aggregator removes the generated .json endpoint instead of leaving it
stale. Use the existing aggregatorName and endpointPath handling in
XdsKubernetesEndpointFetchingService to normalize the target name consistently
with pushK8sEndpoints().

---

Nitpick comments:
In
`@xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java`:
- Around line 56-121: The anonymous XdsResourceWatchingService test instances
leak their per-test ScheduledExecutorService because executor() returns a fresh
newSingleThreadScheduledExecutor() with no shutdown. Update both yaml-related
tests to either reuse a shared executor like TestXdsResourceWatchingService or
add cleanup that shuts down the executor after the test completes, referencing
the executor() override in XdsResourceWatchingServiceTest.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 918855da-c4ec-4f41-984c-c75afd583066

📥 Commits

Reviewing files that changed from the base of the PR and between 6816166 and 6680dc6.

📒 Files selected for processing (14)
  • server/src/main/java/com/linecorp/centraldogma/server/command/ContentTransformer.java
  • server/src/main/java/com/linecorp/centraldogma/server/internal/storage/repository/git/TransformingChangesApplier.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointUpdateScheduler.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/CentralDogmaXdsResources.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/ControlPlaneService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingService.java
  • xds/src/main/java/com/linecorp/centraldogma/xds/k8s/v1/XdsKubernetesEndpointFetchingService.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsEndpointServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/endpoint/v1/XdsRegisterEndpointTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsEndpointReadServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsResourceWatchingServiceTest.java
  • xds/src/test/java/com/linecorp/centraldogma/xds/internal/XdsYamlCompatibilityTest.java

@minwoox
minwoox marked this pull request as ready for review July 2, 2026 01:51
}
task.run();
final String resolvedFileName = entries.keySet().iterator().next();
taskProvider.apply(resolvedFileName).run();

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.

Question) If Runnable is invoked immediately, should we simply take Function<String, Void> or Consumer<String>?

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.

Thanks! Fixed. 😉

final JsonNode jsonNode = Jackson.readTree(jsonText);
if (create) {
change = Change.ofJsonPatch(fileName, null, jsonNode);
} else if (fileName.endsWith(".yaml")) {

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.

I understand that only json files will be pushed in this version.

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.

That's correct because this is for compatibility.

});
return;
}
doPush(responseObserver, group, resourceName, fileName, summary, resource, author, false);

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.

Question) I'm wondering if there is a case where a.json is updated while a.json is being migrated to a.yaml? It seems I may not have understood the current mechanism correctly.

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.

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.

I understand a.json can't be modified due to the removal after a.yaml is created.

@jrhee17 jrhee17 left a comment

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.

👍 👍

Understood the changes as no migration logic, but just supporting read for both json/yaml formats

@coderabbitai coderabbitai 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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java (1)

180-208: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Residual cross-extension TOCTOU on create, despite the new pre-check.

The new pre-check (lines 187-204) closes the gap flagged in the previous review for the common case, but a narrow race remains: between the repository.find(...) check and the actual commit in doPush, a concurrent operation (e.g. a migration converting a.jsona.yaml, or another create request for the alternate extension) can create the alternate file. Since Change.ofJsonPatch(fileName, null, jsonNode) at line 218 only conflicts on the literal fileName, it will not detect that altFileName now exists, allowing both a.json and a.yaml to co-exist for the same logical resource — defeating the dual-extension invariant this PR is meant to preserve.

This is a narrow window and may be acceptable given how migrations are expected to run, but worth confirming it's an accepted tradeoff rather than an oversight.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`
around lines 180 - 208, The create-path pre-check in XdsResourceManager.push
still has a TOCTOU gap because the alternate extension can appear after
repository.find(...) but before doPush commits. Update the create flow so doPush
(or the commit path it uses, including Change.ofJsonPatch) revalidates both
fileName and alternativeFileName immediately before applying the change, or
otherwise makes the existence check atomic with the write. Keep the
dual-extension invariant enforced in the push/create path rather than relying
only on the earlier pre-check.
🧹 Nitpick comments (1)
xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java (1)

187-189: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated dual-extension lookup logic.

The comma-joined fileName + ',' + altFileName lookup and its find(...)/isEmpty() handling in the create pre-check (187-189) is duplicated almost verbatim in updateOrDelete (302-306). Consider extracting a shared private helper (e.g. findResolvedEntry(Repository, String fileName) returning the CompletableFuture<Map<String, Entry<?>>>) to avoid the two call sites drifting apart.

♻️ Sketch of a shared helper
+    private CompletableFuture<Map<String, Entry<?>>> findWithAlternative(
+            Repository repository, String fileName) {
+        final String altFileName = alternativeFileName(fileName);
+        return repository.find(Revision.HEAD, fileName + ',' + altFileName, FIND_ONE_WITHOUT_CONTENT);
+    }

Also applies to: 300-307

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`
around lines 187 - 189, The dual-extension lookup logic is duplicated between
the create pre-check and updateOrDelete paths. Extract the shared repository
lookup into a private helper such as findResolvedEntry(Repository, String) in
XdsResourceManager, and have both call sites use it for the
fileName/alternativeFileName find(...) plus empty-check handling so the behavior
stays consistent in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`:
- Around line 180-208: The create-path pre-check in XdsResourceManager.push
still has a TOCTOU gap because the alternate extension can appear after
repository.find(...) but before doPush commits. Update the create flow so doPush
(or the commit path it uses, including Change.ofJsonPatch) revalidates both
fileName and alternativeFileName immediately before applying the change, or
otherwise makes the existence check atomic with the write. Keep the
dual-extension invariant enforced in the push/create path rather than relying
only on the earlier pre-check.

---

Nitpick comments:
In
`@xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java`:
- Around line 187-189: The dual-extension lookup logic is duplicated between the
create pre-check and updateOrDelete paths. Extract the shared repository lookup
into a private helper such as findResolvedEntry(Repository, String) in
XdsResourceManager, and have both call sites use it for the
fileName/alternativeFileName find(...) plus empty-check handling so the behavior
stays consistent in one place.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c2743ddc-d0e6-427e-9441-3cd5cf6ca3bb

📥 Commits

Reviewing files that changed from the base of the PR and between 8ba05b1 and 5afe8fd.

📒 Files selected for processing (1)
  • xds/src/main/java/com/linecorp/centraldogma/xds/internal/XdsResourceManager.java

@ikhoon ikhoon left a comment

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.

👍 👍

@minwoox
minwoox merged commit e89d1d4 into line:main Jul 3, 2026
13 checks passed
@minwoox
minwoox deleted the xds_yaml_compat branch July 3, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants