Skip to content

fix: CMP tar should only pack annotation paths when use-manifest-generate-paths is enabled - #29326

Open
waterWang wants to merge 4 commits into
argoproj:masterfrom
waterWang:fix/cmp-manifest-generate-paths-inclusions
Open

fix: CMP tar should only pack annotation paths when use-manifest-generate-paths is enabled#29326
waterWang wants to merge 4 commits into
argoproj:masterfrom
waterWang:fix/cmp-manifest-generate-paths-inclusions

Conversation

@waterWang

Copy link
Copy Markdown

Bug

With --plugin-use-manifest-generate-paths enabled, the repo-server still packs the entire common-root directory of argocd.argoproj.io/manifest-generate-paths and streams it to the CMP sidecar, instead of sending only the annotation paths. In large monorepos this causes tar/gRPC/untar overhead proportional to the entire common-root tree, leading to GenerateManifest timeouts (~250× latency increase shown in reporter benchmarks).

Fix

  1. util/io/files/tar.go: Replace basename-based inclusions matching with path-based matching (pathMatchesInclusion / dirMayContainInclusion) so annotations like .;../../infra only include the paths specified, and SkipDir prunes unrelated trees.
  2. util/cmp/stream.go: Add WithInclusions option to SenderOption; pass it to CompressFiles instead of nil.
  3. reposerver/repository/utils.go: Add getManifestGenerateIncludeRels to compute relative inclusion paths from annotation.
  4. reposerver/repository/repository.go: Wire includeRels from runConfigManagementPluginSidecars through generateManifestsCMP to the CMP stream.

Fixes #29309

@waterWang
waterWang requested a review from a team as a code owner August 22, 2026 07:08
@bunnyshell

bunnyshell Bot commented Aug 22, 2026

Copy link
Copy Markdown

❗ Preview Environment deployment failed on Bunnyshell

See: Environment Details | Pipeline Logs

Available commands (reply to this comment):

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Fix CMP tar to only stream manifest-generate-paths inclusions

🐞 Bug fix 🕐 20-40 Minutes

Grey Divider

AI Description

• Limit CMP repo tar contents to annotation-specified paths when manifest-generate-paths is enabled.
• Add path-aware inclusion matching and directory pruning to avoid scanning unrelated monorepo
 trees.
• Wire inclusion relpaths from reposerver through CMP streaming to the tar compressor.
Diagram

graph TD
A["Repo-server"] --> B{{"use-manifest-generate-paths?"}} -->|"yes"| C["Compute root+includes"] --> D["cmp.SendRepoStream"] --> E["tgzstream.CompressFiles"] --> F["files.Tgz (path filter)"] --> G["CMP sidecar"]
B -->|"no"| D
Loading
High-Level Assessment

The chosen approach—keep the existing common-root calculation for correctness, but add inclusion relpaths and enforce them in the tar walker with directory pruning—is the most practical fix. Alternatives like restructuring CMP to accept multiple independent roots or changing plugin working-directory semantics would be more invasive and risk plugin incompatibilities.

Files changed (4) +118 / -20

Bug fix (4) +118 / -20
repository.goPropagate manifest-generate-paths inclusions into CMP streaming +9/-4

Propagate manifest-generate-paths inclusions into CMP streaming

• Computes includeRels when useManifestGeneratePaths is enabled and logs them alongside the common root. Threads includeRels through generateManifestsCMP and conditionally applies cmp.WithInclusions so the CMP tar can be filtered.

reposerver/repository/repository.go

utils.goAdd helper to compute CMP tar inclusion relpaths from annotation +27/-0

Add helper to compute CMP tar inclusion relpaths from annotation

• Introduces getManifestGenerateIncludeRels to turn manifest-generate-paths annotation values into paths relative to the computed rootPath. Ensures appPath is always included so the plugin working directory exists, and de-duplicates relpaths.

reposerver/repository/utils.go

stream.goAdd WithInclusions sender option and pass to compressor +15/-2

Add WithInclusions sender option and pass to compressor

• Extends CMP stream sender options with an inclusions list and a WithInclusions helper. Plumbs inclusions into tgzstream.CompressFiles so repo streaming can be constrained to selected paths.

util/cmp/stream.go

tar.goFix inclusion matching to be path-based and prune directories during tar walk +67/-14

Fix inclusion matching to be path-based and prune directories during tar walk

• Replaces basename-only inclusion checks with pathMatchesInclusion against tar-root-relative paths, supporting exact matches, directory prefixes, and globs. Adds dirMayContainInclusion to SkipDir when a directory cannot contain any included paths, reducing monorepo scan/tar overhead.

util/io/files/tar.go

@codecov

codecov Bot commented Aug 22, 2026

Copy link
Copy Markdown

Bundle Report

Changes will decrease total bundle size by 282 bytes (-0.0%) ⬇️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
argo-cd-ui-array-push 11.25MB -282 bytes (-0.0%) ⬇️

Affected Assets, Files, and Routes:

view changes for bundle: argo-cd-ui-array-push

Assets Changed:

Asset Name Size Change Total Size Change (%)
main.*.js -282 bytes 3.72MB -0.01%

@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (1) 📜 Skill insights (0)

Grey Divider


Action required

1. Inclusion filtering lacks tests 📘 Rule violation ☼ Reliability
Description
This PR changes CMP tar inclusion behavior (path-based matching plus directory pruning) but does not
add/adjust automated tests to validate the new inclusion semantics. Without coverage, regressions
could reintroduce over-inclusive tars or incorrectly exclude required files, impacting manifest
generation reliability.
Code

util/io/files/tar.go[R254-257]

+	if t.inclusions != nil && relativePath != "." {
+		if fi.IsDir() {
+			if !dirMayContainInclusion(relativePath, t.inclusions) {
+				return filepath.SkipDir
Evidence
Compliance requires adding automated tests for bug fixes/new logic. The PR adds new inclusion
matching/pruning behavior in tar creation and new wiring for passing inclusions to CompressFiles,
but existing tests only cover basic tgz creation and stream send/receive without any inclusion
filtering assertions.

AGENTS.md: All new features and bug fixes must include appropriate automated tests
util/io/files/tar.go[188-271]
util/cmp/stream.go[100-170]
reposerver/repository/utils.go[86-112]
util/io/files/tar_test.go[21-106]
util/cmp/stream_test.go[51-94]
reposerver/repository/utils_test.go[11-45]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The PR introduces new inclusion-filtering behavior for CMP tar creation (path-based matching and directory pruning), but there are no accompanying tests that fail before the fix and pass after.

## Issue Context
Key new logic was added in `util/io/files/tar.go` (`pathMatchesInclusion`, `dirMayContainInclusion`, and new inclusion handling in `tgzFile`), and wiring was added from reposerver -> CMP stream to pass inclusion paths.

## Fix Focus Areas
- util/io/files/tar_test.go[1-290]
- util/io/files/tar.go[188-271]
- util/cmp/stream_test.go[51-94]
- util/cmp/stream.go[100-170]
- reposerver/repository/utils_test.go[11-45]
- reposerver/repository/utils.go[86-112]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Basename inclusions broken 🐞 Bug ≡ Correctness
Description
files.Tgz inclusions now match against the full relative path and also prune directories, which
breaks callers that pass basename-only patterns (e.g. *.yaml) expecting them to match files
anywhere in the tree. This can cause argocd app diff --server-side-generate to send zero files
(and fail) despite the flag help text promising filename-based matching.
Code

util/io/files/tar.go[R199-203]

+	if strings.HasPrefix(relativePath, pattern+sep) {
+		return true
+	}
+	if matched, err := filepath.Match(pattern, relativePath); err == nil && matched {
+		return true
Evidence
The CLI flag --local-include explicitly states matching is based on filename, and the diff path
passes these patterns into tar creation. After this PR, inclusion matching is done against the full
relative path and directory pruning can SkipDir entire trees for filename-only patterns, so nested
matches no longer occur and packaging can result in zero files.

cmd/argocd/commands/app_diff.go[794-801]
util/manifeststream/stream.go[41-49]
util/tgzstream/stream.go[28-44]
util/io/files/tar.go[188-206]
util/io/files/tar.go[208-238]
util/io/files/tar.go[254-270]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`util/io/files/tar.go` changed inclusion matching from basename-only to full relative path. This breaks existing inclusion patterns used by the CLI/server-side diff path (`--local-include` defaults to `*.yaml,*.yml,*.json`) which explicitly documents filename-based matching.

### Issue Context
Call chain:
- `cmd/argocd/commands/app_diff.go` passes `localIncludes` to `manifeststream.SendApplicationManifestQueryWithFiles`.
- `util/manifeststream/stream.go` passes `inclusions` directly into `tgzstream.CompressFiles`.
- `util/tgzstream/stream.go` passes `included` into `files.Tgz`.
- `util/io/files/tar.go` now matches `filepath.Match(pattern, relativePath)` and prunes directories via `dirMayContainInclusion`, so patterns without path separators (e.g. `*.yaml` or `kustomization.yaml`) no longer match nested files and may even cause `SkipDir` to prune the entire tree.

### How to fix
1. Preserve backward-compatible behavior for inclusion patterns that do **not** contain a path separator:
  - If `pattern` contains no separator (`/` on linux), treat it as a basename pattern:
    - Match against `filepath.Base(relativePath)` (exact and glob).
  - Only treat patterns containing a separator as path-based patterns (current new behavior).
2. Update `dirMayContainInclusion` so that if any inclusion pattern contains no separator (basename-only), it returns `true` for all directories (cannot safely prune).
3. Add/extend unit tests in `util/io/files/tar_test.go` to cover:
  - `inclusions = []string{"*.yaml"}` includes nested YAML files.
  - `inclusions = []string{"kustomization.yaml"}` includes nested `kustomization.yaml`.
  - `inclusions = []string{"apps/app1"}` (path-based) still prunes unrelated directories.

### Fix Focus Areas
- util/io/files/tar.go[188-238]
- util/io/files/tar.go[254-270]
- cmd/argocd/commands/app_diff.go[794-801]
- util/manifeststream/stream.go[41-49]
- util/tgzstream/stream.go[28-44]
- util/io/files/tar_test.go[1-120]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can commit Qodo's fix in one click with committable suggestions (GitHub & GitLab)

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread util/io/files/tar.go
Comment on lines +254 to +257
if t.inclusions != nil && relativePath != "." {
if fi.IsDir() {
if !dirMayContainInclusion(relativePath, t.inclusions) {
return filepath.SkipDir

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Inclusion filtering lacks tests 📘 Rule violation ☼ Reliability

This PR changes CMP tar inclusion behavior (path-based matching plus directory pruning) but does not
add/adjust automated tests to validate the new inclusion semantics. Without coverage, regressions
could reintroduce over-inclusive tars or incorrectly exclude required files, impacting manifest
generation reliability.
Agent Prompt
## Issue description
The PR introduces new inclusion-filtering behavior for CMP tar creation (path-based matching and directory pruning), but there are no accompanying tests that fail before the fix and pass after.

## Issue Context
Key new logic was added in `util/io/files/tar.go` (`pathMatchesInclusion`, `dirMayContainInclusion`, and new inclusion handling in `tgzFile`), and wiring was added from reposerver -> CMP stream to pass inclusion paths.

## Fix Focus Areas
- util/io/files/tar_test.go[1-290]
- util/io/files/tar.go[188-271]
- util/cmp/stream_test.go[51-94]
- util/cmp/stream.go[100-170]
- reposerver/repository/utils_test.go[11-45]
- reposerver/repository/utils.go[86-112]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread util/io/files/tar.go
Comment on lines +199 to +203
if strings.HasPrefix(relativePath, pattern+sep) {
return true
}
if matched, err := filepath.Match(pattern, relativePath); err == nil && matched {
return true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Basename inclusions broken 🐞 Bug ≡ Correctness

files.Tgz inclusions now match against the full relative path and also prune directories, which
breaks callers that pass basename-only patterns (e.g. *.yaml) expecting them to match files
anywhere in the tree. This can cause argocd app diff --server-side-generate to send zero files
(and fail) despite the flag help text promising filename-based matching.
Agent Prompt
### Issue description
`util/io/files/tar.go` changed inclusion matching from basename-only to full relative path. This breaks existing inclusion patterns used by the CLI/server-side diff path (`--local-include` defaults to `*.yaml,*.yml,*.json`) which explicitly documents filename-based matching.

### Issue Context
Call chain:
- `cmd/argocd/commands/app_diff.go` passes `localIncludes` to `manifeststream.SendApplicationManifestQueryWithFiles`.
- `util/manifeststream/stream.go` passes `inclusions` directly into `tgzstream.CompressFiles`.
- `util/tgzstream/stream.go` passes `included` into `files.Tgz`.
- `util/io/files/tar.go` now matches `filepath.Match(pattern, relativePath)` and prunes directories via `dirMayContainInclusion`, so patterns without path separators (e.g. `*.yaml` or `kustomization.yaml`) no longer match nested files and may even cause `SkipDir` to prune the entire tree.

### How to fix
1. Preserve backward-compatible behavior for inclusion patterns that do **not** contain a path separator:
   - If `pattern` contains no separator (`/` on linux), treat it as a basename pattern:
     - Match against `filepath.Base(relativePath)` (exact and glob).
   - Only treat patterns containing a separator as path-based patterns (current new behavior).
2. Update `dirMayContainInclusion` so that if any inclusion pattern contains no separator (basename-only), it returns `true` for all directories (cannot safely prune).
3. Add/extend unit tests in `util/io/files/tar_test.go` to cover:
   - `inclusions = []string{"*.yaml"}` includes nested YAML files.
   - `inclusions = []string{"kustomization.yaml"}` includes nested `kustomization.yaml`.
   - `inclusions = []string{"apps/app1"}` (path-based) still prunes unrelated directories.

### Fix Focus Areas
- util/io/files/tar.go[188-238]
- util/io/files/tar.go[254-270]
- cmd/argocd/commands/app_diff.go[794-801]
- util/manifeststream/stream.go[41-49]
- util/tgzstream/stream.go[28-44]
- util/io/files/tar_test.go[1-120]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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.

repo-server CMP tar does not honor manifest-generate-paths

1 participant