Skip to content

fix: Hydrator wipes out entire branch when multiple Applications hydrate to the same branch with different path (fixes #24179) #24185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

adityaraj178
Copy link

@adityaraj178 adityaraj178 commented Aug 18, 2025

Hydrator wipes out entire branch when multiple Applications hydrate to the same branch with different path.

Description:

  • Fixes an issue where the Hydrator deletes the entire branch contents when multiple Applications hydrate into the same branch but with different paths.
  • Previously, CommitHydratedManifests would clean the full branch before writing manifests, which caused conflicts and data loss if multiple apps targeted the same branch under different directories.
  • This change ensures that only the specific path for the current Application is cleaned and re-written, leaving other paths intact.

Closes:

Why this PR is necessary:
Without this fix, hydrating multiple Applications to the same branch is destructive. This makes source hydrator unsafe in multi-application setups. With this fix, Applications can hydrate independently to different directories inside the same branch.

Demonstartion video: https://github.com/user-attachments/assets/c9c1a854-b7a2-4467-87f2-eeb6850dba52

Checklist:

  • Either (a) I've created an enhancement proposal and discussed it with the community, (b) this is a bug fix, or (c) this does not need to be in the release notes.
  • The title of the PR states what changed and the related issues number (used for the release note).
  • The title of the PR conforms to the Title of the PR
  • I've included "Closes [ISSUE #]" or "Fixes [ISSUE #]" in the description to automatically close the associated issue.
  • I've updated both the CLI and UI to expose my feature, or I plan to submit a second PR with them.
  • Does this PR require documentation updates?
  • I've updated documentation as required by this PR.
  • I have signed off all my commits as required by DCO
  • I have written unit and/or e2e tests for my change. PRs without these are unlikely to be merged.
  • My build is green (troubleshooting builds).
  • My new feature complies with the feature status guidelines.
  • I have added a brief description of why this PR is necessary and/or what this PR solves.
  • Optional. My organization is added to USERS.md.
  • Optional. For bug fixes, I've indicated what older releases this fix should be cherry-picked into (this may or may not happen depending on risk/complexity).

@adityaraj178 adityaraj178 requested a review from a team as a code owner August 18, 2025 09:02
Copy link

bunnyshell bot commented Aug 18, 2025

🔴 Preview Environment stopped on Bunnyshell

See: Environment Details | Pipeline Logs

Available commands (reply to this comment):

  • 🔵 /bns:start to start the environment
  • 🚀 /bns:deploy to redeploy the environment
  • /bns:delete to remove the environment

Copy link

codecov bot commented Aug 18, 2025

Codecov Report

❌ Patch coverage is 69.23077% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 60.14%. Comparing base (8c8902b) to head (53fb859).
⚠️ Report is 21 commits behind head on master.

Files with missing lines Patch % Lines
commitserver/commit/commit.go 70.00% 2 Missing and 1 partial ⚠️
util/git/client.go 66.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master   #24185      +/-   ##
==========================================
+ Coverage   60.11%   60.14%   +0.02%     
==========================================
  Files         347      348       +1     
  Lines       59856    59894      +38     
==========================================
+ Hits        35985    36025      +40     
+ Misses      20984    20980       -4     
- Partials     2887     2889       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

return "", "", fmt.Errorf("failed to clear path %s: %w", targetPath, err)
}
logCtx.Debugf("Recreating directory %s", targetPath)
if err := os.MkdirAll(targetPath, 0o755); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Doesn't WriteForPaths creates a directory already?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, WriteForPaths does attempt to create the target directory for each manifest path before writing the files. However, there are two reasons I explicitly ensure the directory exists in handleCommitRequest:

Path Deletion Race: Immediately after deleting a directory with os.RemoveAll, there can be a brief moment (especially under heavy parallelization or on some filesystems) where the directory is still being cleaned up. Explicitly recreating it guarantees a safe write regardless of timing.

Top-Level Metadata: The top-level hydrator.metadata is written to the root (dirPath), and in edge cases (such as root path hydration), it’s important to be sure dirPath wasn't accidentally removed or left missing.

Copy link
Member

Choose a reason for hiding this comment

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

Path Deletion Race: Immediately after deleting a directory with os.RemoveAll, there can be a brief moment (especially under heavy parallelization or on some filesystems) where the directory is still being cleaned up. Explicitly recreating it guarantees a safe write regardless of timing.

Did you try these changes locally? Woudln't you get an error if you're trying to create the same directory again provided it has already been created once?

Copy link
Author

Choose a reason for hiding this comment

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

Hello @nitishfy, i have run it locally and it's working good. The main reason i recreates the directory is because os.RemoveAll(targetPath) will remove everything at targetPath, including all files and the directory itself. So whenever i am calling os.RemoveAll(), i am recreating the directory after that.

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member

@nitishfy nitishfy left a comment

Choose a reason for hiding this comment

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

Something feels a bit off about changes....Please consider putting a demonstration video if possible OR prefer adding more tests to validate this behaviour. Thanks!

@nitishfy
Copy link
Member

Not related to PR changes.....

I see someone already asked about working on the issue. Although the person wasn't assigned but please get an issue assigned beforehand and raise a fix then. There are chances that the other person might have started working on the issue that would lead to wastage of efforts at the end.

@adityaraj178 adityaraj178 force-pushed the fix-24179 branch 4 times, most recently from 40c0a5a to f95155e Compare August 19, 2025 17:37
logCtx.Debug("Using root directory for manifests, no directory removal needed")
} else {
logCtx.Debugf("Clearing path %s", targetPath)
if err := os.RemoveAll(targetPath); err != nil {
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if err := os.RemoveAll(targetPath); err != nil {
if err := os.RemoveAll(targetPath); err != nil {

Why aren't we using gitClient.RemoveContents() anymore? I think we should modify the git client call than calling the os.RemoveAll function here.

Copy link
Member

@nitishfy nitishfy left a comment

Choose a reason for hiding this comment

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

This PR is a little bit related to fixing #23944. I'd suggest going through the PR that fixes that issue and take some inspiration from that. For now, this PR needs a lot of modification and I'd prefer having a demonstration video at the end to make sure everything is working before finally approving.

Also, if you want, you can bring this PR in Argo CD community call happening at Thursday (8:45 PM IST)

@adityaraj178
Copy link
Author

This PR is a little bit related to fixing #23944. I'd suggest going through the PR that fixes that issue and take some inspiration from that. For now, this PR needs a lot of modification and I'd prefer having a demonstration video at the end to make sure everything is working before finally approving.

Also, if you want, you can bring this PR in Argo CD community call happening at Thursday (8:45 PM IST)

Thanks, @nitishfy, for the reply and sharing the related issue #23944. I see that both issues are quite similar.

I believe stopping users from providing the root directory as a path might be restrictive since some users may want to store manifests directly in the root. Instead, focusing on cleaning only subdirectories during commits should solve the problem—since commits in the root directory will only modify files like README.md, manifests.yaml, and hydrator.metadata, leaving CI/CD config files unaffected.I will prepare and share a demonstration video to showcase this approach.

Thanks also for the insight on preferring gitClient.RemoveContents() over os.RemoveAll().
Lastly, I will ensure to get issues assigned before working on them next time.

Thanks again for the valuable feedback!

@adityaraj178
Copy link
Author

Demonstartion video: https://github.com/user-attachments/assets/c9c1a854-b7a2-4467-87f2-eeb6850dba52

Clip 1: The hydrator targets the subdirectory test, which contains .txt files. These files are properly removed and replaced during hydration.

Clip 2: The hydrator targets the root path, where a critical file config.yaml exists. This file remains unaffected by the hydration process, ensuring important root-level config files are preserved.

@adityaraj178 adityaraj178 requested a review from a team as a code owner August 21, 2025 20:12
@adityaraj178 adityaraj178 force-pushed the fix-24179 branch 3 times, most recently from 0a185eb to aa4892c Compare August 22, 2025 04:58
…ple Applications hydrate to the same branch with different path

Signed-off-by: Aditya Raj <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Hydrator wipes out entire branch when multiple Applications hydrate to the same branch with different path
2 participants