Skip to content

[feat]: [AH-2903]: add support for upload/download for raw files#100

Open
abhinavcode wants to merge 16 commits into
mainfrom
raw-paths-support
Open

[feat]: [AH-2903]: add support for upload/download for raw files#100
abhinavcode wants to merge 16 commits into
mainfrom
raw-paths-support

Conversation

@abhinavcode

@abhinavcode abhinavcode commented Feb 25, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • New Features

    • Raw file upload/download now supported for additional non-GENERIC package artifacts with conflict checks and SHA verification.
    • File-operation availability is checked per package type; unsupported types return a clear error.
    • Artifact metadata now includes richer registry/root context for improved traceability.
  • Bug Fixes

    • Improved URL path parsing and validation with clearer Not Found / Bad Request responses.
  • Refactor

    • Simplified file routing and consolidated file-handling flows with improved logging.
  • Tests

    • Added URL path parsing tests for generic and non-generic paths.

@greptile-apps greptile-apps 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.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai

coderabbitai Bot commented Feb 25, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds raw file upload/download support for non‑GENERIC package types, refactors artifact-info resolution with a new buildFileArtifactInfo helper, updates routing for /files to a flat layout, extends LocalBase with UploadRawFile/DownloadRawFile, and propagates a new packageWrapper dependency and file‑support checks.

Changes

Cohort / File(s) Summary
API handler
registry/app/api/handler/generic/base.go
Adds buildFileArtifactInfo; refactors GetGenericArtifactInfoV2 to branch GENERIC vs non‑GENERIC, validate/assemble filePath/fileName for non‑GENERIC, and add logging.
Routing
registry/app/api/router/packages/route.go
Flattens /files routing by removing per‑package/version nested grouping and consolidates middleware and file handlers under a single route block.
Local base storage
registry/app/pkg/base/base.go
Adds UploadRawFile and DownloadRawFile to LocalBase and implements existence/conflict checks, session enforcement, file manager upload/download, returning SHA256 and redirect URL.
Generic package layer
registry/app/pkg/generic/local.go
Routes non‑GENERIC PutFile/DownloadFile to new uploadRawFile/downloadRawFile helpers that call LocalBase raw methods; preserves GENERIC flow.
Path utilities & types
registry/app/pkg/base/utils.go, registry/app/pkg/types/generic/types.go
GetCompletePath returns original filePath when image and version are empty; GetImageVersion treats empty Image+Version as a valid FilePath case.
Controller wiring & DI
cmd/gitness/wire_gen.go, registry/app/api/controller/pkg/generic/wire.go, registry/app/api/controller/pkg/generic/controller.go
Introduces packageWrapper into wiring and Controller; updates constructors/providers to accept and propagate the new dependency.
Package helper interfaces & implementations
registry/app/api/interfaces/package_type_factory.go, registry/app/api/interfaces/package_wrapper.go, registry/app/helpers/pkg/*.go
Adds IsFileOperationSupported() to PackageHelper and PackageWrapper, implements it across concrete package types and in packageWrapper (mostly returning false except generic).
Public factory wrappers
registry/app/pkg/base/wrapper.go
Exposes internal lookup helpers as public: Factory(key string) and GetFactoryKey(packageType, registryType).
Tests & mocks
registry/app/api/handler/generic/base_test.go, registry/app/pkg/python/local_helper_test.go
Adds TestURLPathParsing (duplicated) and extends mocks with ExistsByFilePath, UploadRawFile, DownloadRawFile methods.
Other
registry/app/helpers/pkg/*
Added IsFileOperationSupported() implementations for each package type file (cargo, docker, go, helm, huggingface, maven, npm, nuget, python, rpm).

Sequence Diagram

sequenceDiagram
    actor Client
    participant Handler as Handler\n(GetGenericArtifactInfoV2)
    participant Resolver as Space/Registry\n(resolver)
    participant TypeCheck as PackageType\n(detector)
    participant RawBuilder as buildFileArtifactInfo
    participant GenericFlow as GENERIC\n(flow)
    participant LocalBase as LocalBase\n(Upload/DownloadRawFile)
    participant Storage as File\nStorage

    Client->>Handler: HTTP file request
    Handler->>Resolver: resolve root space & registry
    Handler->>TypeCheck: determine package type
    alt Non-GENERIC
        TypeCheck->>RawBuilder: delegate to buildFileArtifactInfo
        RawBuilder->>RawBuilder: validate path, assemble filePath/fileName
        RawBuilder->>LocalBase: UploadRawFile / DownloadRawFile(filePath)
        LocalBase->>Storage: upload/download by filePath
        Storage-->>LocalBase: SHA256 or FileReader + redirect
        LocalBase-->>RawBuilder: headers, sha/url
    else GENERIC
        TypeCheck->>GenericFlow: delegate to GENERIC flow
        GenericFlow->>LocalBase: existing GENERIC upload/download
        LocalBase->>Storage: store/retrieve by artifact layout
        Storage-->>LocalBase: response
    end
    Handler-->>Client: respond (status / artifact info / redirect)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 I hopped through roots and registry light,
Paths split to generic and raw tonight.
Files found, uploaded, and sent on their way,
A rabbit claps for routes made fey—
Hooray for tidy hops and bytes so bright!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main feature: adding support for upload/download of raw files, which aligns with the comprehensive changes across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch raw-paths-support

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 and usage tips.

@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 (2)
registry/app/api/handler/generic/base.go (1)

373-383: ⚠️ Potential issue | 🔴 Critical

Routing condition incorrectly rejects valid non-GENERIC paths with fewer than 7 segments.

The first branch requires len(splits) >= 7, which is right for GENERIC paths (/pkg/root/reg/files/pkg/version/file). However, non-GENERIC raw file paths only need one path segment after files/, e.g., /pkg/root/reg/files/artifact.ziplen(splits) == 5. This falls through to the second branch at Line 379, which matches (len >= 4 && splits[3] == "files") and returns a misleading "expected package/version/file" error, completely breaking non-GENERIC single-segment uploads/downloads.

The condition should route to GetGenericArtifactInfoV2 whenever len(splits) >= 5 (at least one path component after files/), and the >= 7 guard should only apply to GENERIC type validation within GetGenericArtifactInfoV2 itself (which already does this).

🐛 Proposed fix
-	if len(splits) >= 7 && splits[0] == "pkg" && splits[3] == "files" {
+	if len(splits) >= 5 && splits[0] == "pkg" && splits[3] == "files" {
		artifactInfo, err := h.GetGenericArtifactInfoV2(r)
		if err != nil {
			return nil, fmt.Errorf("failed to get generic artifact info: %w", err)
		}
		return artifactInfo, nil
-	} else if len(splits) >= 4 && splits[0] == "pkg" && splits[3] == "files" {
-		// Missing required path segments (version or filepath)
-		return nil, usererror.BadRequestf(
-			"Invalid request path: expected /pkg/{root}/{registry}/files/{package}/{version}/{filepath}, got: %s",
-			r.URL.Path)
	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 373 - 383, The routing
check incorrectly requires len(splits) >= 7 before calling
GetGenericArtifactInfoV2, which rejects valid non-GENERIC file paths; change the
first branch condition to call GetGenericArtifactInfoV2 when len(splits) >= 5
and splits[0] == "pkg" && splits[3] == "files" (so any request with at least one
path segment after "files" is routed to GetGenericArtifactInfoV2), and let
GetGenericArtifactInfoV2 perform stricter GENERIC-specific validation (remove or
update the redundant else-if that repeats splits[3] == "files" so it no longer
misreports valid single-segment file requests).
registry/app/pkg/generic/local.go (1)

81-83: ⚠️ Potential issue | 🟠 Major

GetPackageTypes() advertises only GENERIC, but PutFile/DownloadFile handle non-GENERIC types.

The methods explicitly route non-GENERIC package types (lines 92 and 115) to uploadRawFile() and downloadRawFile(), yet GetPackageTypes() returns only PackageTypeGENERIC. This creates a dispatch inconsistency: the Register() function in registry/app/pkg/base/wrapper.go (lines 39-42) uses GetPackageTypes() to populate the routing registry. Non-GENERIC types will not be registered for this registry, causing dispatch logic to incorrectly believe this registry cannot handle those types despite being able to do so.

Update GetPackageTypes() to return all package types that are actually supported by the PutFile and DownloadFile implementations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/generic/local.go` around lines 81 - 83, GetPackageTypes
currently only lists artifact.PackageTypeGENERIC but PutFile and DownloadFile
route non-GENERIC types to uploadRawFile/downloadRawFile, so update
GetPackageTypes() in localRegistry to return every artifact.PackageType that
PutFile/DownloadFile actually support (include GENERIC and the other concrete
PackageType values used by uploadRawFile/downloadRawFile) so the registry
registration (Register) will correctly advertise this backend; reference the
GetPackageTypes function and ensure its returned slice includes the same package
types handled by PutFile/DownloadFile and their internal helpers
uploadRawFile/downloadRawFile.
🧹 Nitpick comments (4)
registry/app/api/handler/generic/base.go (2)

348-353: Redundant empty-field check — unreachable after prior validation.

By Line 348, packageName, version, fileName, and filePath are guaranteed non-empty: packageName and version passed validatePackageVersionV2 (Line 318), filePath passed validateFilePath (Line 323), and fileName is the last element of remainingSegments whose length was checked. The info.Image == "" || ... guard will never fire and should be removed.

♻️ Proposed removal
 	log.Ctx(ctx).Info().Msgf("Dispatch: URI: %s", path)
-	if info.Image == "" || info.Version == "" || info.FileName == "" || info.FilePath == "" {
-		log.Ctx(ctx).Warn().Msgf("Invalid request")
-		return generic2.ArtifactInfo{}, usererror.BadRequestf("Invalid request Image: %q, Version: %q, FileName: %q",
-			info.Image, info.Version,
-			info.FileName)
-	}
-
 	if info.Image != "" && info.Version != "" && info.FilePath != "" {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 348 - 353, Remove the
redundant empty-field guard that checks info.Image, info.Version, info.FileName,
and info.FilePath in the function (the block starting with "if info.Image == ""
|| ..."). Those fields are already guaranteed non-empty by earlier validations
(validatePackageVersionV2, validateFilePath and the remainingSegments length
check), so delete this conditional and its log/BadRequest return to avoid
unreachable code; keep the surrounding logic intact and rely on the prior
validators to enforce non-empty values.

262-289: Double space/registry DB lookup when delegating to GetFileArtifactInfoV2.

GetGenericArtifactInfoV2 resolves rootSpace (Line 271) and registry (Line 277), then for non-GENERIC types immediately delegates to GetFileArtifactInfoV2 (Line 288), which resolves both again (Lines 203–215). This results in 4 DB calls instead of 2 on every non-GENERIC request.

Consider passing the already-resolved registry into GetFileArtifactInfoV2 (or extracting a shared private helper), to avoid the duplicate lookups.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 262 - 289,
GetGenericArtifactInfoV2 currently resolves rootSpace via SpaceFinder.FindByRef
and registry via RegistryFinder.FindByRootRef and then immediately calls
GetFileArtifactInfoV2 for non-GENERIC types, causing duplicate DB lookups
because GetFileArtifactInfoV2 re-resolves the same values; refactor by adding an
overload or helper so GetFileArtifactInfoV2 can accept an already-resolved
registry (or factor out the shared resolution into a private helper used by both
functions), update calls to pass the registry variable when delegating from
GetGenericArtifactInfoV2, and remove the redundant FindByRef/FindByRootRef calls
in the delegated path.
registry/app/pkg/base/base.go (1)

216-219: Double registry lookup on every raw file operation.

Both UploadRawFile and DownloadRawFile re-execute registryFinder.FindByRootParentID, even though GetFileArtifactInfoV2 already resolved and embedded the registry in info.ArtifactInfo.Registry. Consider passing the already-resolved registry.ID directly via info.RegistryID to avoid redundant DB round trips.

Also applies to: 261-264

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/base/base.go` around lines 216 - 219, UploadRawFile and
DownloadRawFile each re-run registryFinder.FindByRootParentID even though
GetFileArtifactInfoV2 already resolved the registry into
info.ArtifactInfo.Registry; change the flow to avoid the duplicate DB lookup by
propagating the resolved registry ID from GetFileArtifactInfoV2 into the
returned info (e.g., set info.RegistryID = info.ArtifactInfo.Registry.ID) and
update UploadRawFile and DownloadRawFile to use info.RegistryID instead of
calling registryFinder.FindByRootParentID; ensure any existing code paths that
still need the full registry object fall back to using the embedded
info.ArtifactInfo.Registry when present.
registry/app/api/router/packages/route.go (1)

97-111: Missing bandwidth stat tracking for /files uploads and downloads.

The old /generic route block applied TrackBandwidthStatForGenericArtifacts middleware for both upload and download. The new /files block omits it entirely. Bandwidth metrics will be silently absent for all raw file operations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/router/packages/route.go` around lines 97 - 111, The /files
route block is missing the TrackBandwidthStatForGenericArtifacts middleware, so
add middleware.TrackBandwidthStatForGenericArtifacts(packageHandler) into the
middleware chain for raw artifact uploads and downloads: include it in the
.With(...) chains that build Get("/*", genericHandler.GetFile) and Head("/*",
genericHandler.HeadFile) for downloads and in the chain for Put("/*",
genericHandler.PutFile) for uploads (use the same placement pattern as
middleware.CheckQuarantineStatus and middleware.RequestPackageAccess around
packageHandler and genericHandler).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@registry/app/pkg/base/base.go`:
- Around line 232-242: The call to request.AuthSessionFrom(ctx) in base.go
ignores the returned error and may allow session.Principal.ID to be zero when
calling l.fileManager.UploadFile; change code around AuthSessionFrom to capture
and check the error (AuthSessionFrom) and, if no session is present, either
return an error or enforce a fallback (reject upload or require authentication)
before calling l.fileManager.UploadFile so you never pass a zero principal ID
(session.Principal.ID) into UploadFile; ensure the handler/function returns a
clear error when the session is missing.

In `@registry/app/pkg/generic/local.go`:
- Line 150: The call to c.localBase.UploadRawFile(ctx, info.ArtifactInfo,
info.FilePath, reader, true) hardcodes failOnConflict=true so raw files can
never be overwritten; change this to pass a configurable boolean instead (e.g.,
a field on the incoming info struct or an explicit parameter) and wire that
through to UploadRawFile so callers can opt into overwrite semantics; update the
caller site in registry/app/pkg/generic/local.go (the UploadRawFile invocation)
and any upstream call sites or API surface that creates the info/parameters so
the overwrite flag is plumbed through.

---

Outside diff comments:
In `@registry/app/api/handler/generic/base.go`:
- Around line 373-383: The routing check incorrectly requires len(splits) >= 7
before calling GetGenericArtifactInfoV2, which rejects valid non-GENERIC file
paths; change the first branch condition to call GetGenericArtifactInfoV2 when
len(splits) >= 5 and splits[0] == "pkg" && splits[3] == "files" (so any request
with at least one path segment after "files" is routed to
GetGenericArtifactInfoV2), and let GetGenericArtifactInfoV2 perform stricter
GENERIC-specific validation (remove or update the redundant else-if that repeats
splits[3] == "files" so it no longer misreports valid single-segment file
requests).

In `@registry/app/pkg/generic/local.go`:
- Around line 81-83: GetPackageTypes currently only lists
artifact.PackageTypeGENERIC but PutFile and DownloadFile route non-GENERIC types
to uploadRawFile/downloadRawFile, so update GetPackageTypes() in localRegistry
to return every artifact.PackageType that PutFile/DownloadFile actually support
(include GENERIC and the other concrete PackageType values used by
uploadRawFile/downloadRawFile) so the registry registration (Register) will
correctly advertise this backend; reference the GetPackageTypes function and
ensure its returned slice includes the same package types handled by
PutFile/DownloadFile and their internal helpers uploadRawFile/downloadRawFile.

---

Nitpick comments:
In `@registry/app/api/handler/generic/base.go`:
- Around line 348-353: Remove the redundant empty-field guard that checks
info.Image, info.Version, info.FileName, and info.FilePath in the function (the
block starting with "if info.Image == "" || ..."). Those fields are already
guaranteed non-empty by earlier validations (validatePackageVersionV2,
validateFilePath and the remainingSegments length check), so delete this
conditional and its log/BadRequest return to avoid unreachable code; keep the
surrounding logic intact and rely on the prior validators to enforce non-empty
values.
- Around line 262-289: GetGenericArtifactInfoV2 currently resolves rootSpace via
SpaceFinder.FindByRef and registry via RegistryFinder.FindByRootRef and then
immediately calls GetFileArtifactInfoV2 for non-GENERIC types, causing duplicate
DB lookups because GetFileArtifactInfoV2 re-resolves the same values; refactor
by adding an overload or helper so GetFileArtifactInfoV2 can accept an
already-resolved registry (or factor out the shared resolution into a private
helper used by both functions), update calls to pass the registry variable when
delegating from GetGenericArtifactInfoV2, and remove the redundant
FindByRef/FindByRootRef calls in the delegated path.

In `@registry/app/api/router/packages/route.go`:
- Around line 97-111: The /files route block is missing the
TrackBandwidthStatForGenericArtifacts middleware, so add
middleware.TrackBandwidthStatForGenericArtifacts(packageHandler) into the
middleware chain for raw artifact uploads and downloads: include it in the
.With(...) chains that build Get("/*", genericHandler.GetFile) and Head("/*",
genericHandler.HeadFile) for downloads and in the chain for Put("/*",
genericHandler.PutFile) for uploads (use the same placement pattern as
middleware.CheckQuarantineStatus and middleware.RequestPackageAccess around
packageHandler and genericHandler).

In `@registry/app/pkg/base/base.go`:
- Around line 216-219: UploadRawFile and DownloadRawFile each re-run
registryFinder.FindByRootParentID even though GetFileArtifactInfoV2 already
resolved the registry into info.ArtifactInfo.Registry; change the flow to avoid
the duplicate DB lookup by propagating the resolved registry ID from
GetFileArtifactInfoV2 into the returned info (e.g., set info.RegistryID =
info.ArtifactInfo.Registry.ID) and update UploadRawFile and DownloadRawFile to
use info.RegistryID instead of calling registryFinder.FindByRootParentID; ensure
any existing code paths that still need the full registry object fall back to
using the embedded info.ArtifactInfo.Registry when present.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38525c3 and f44cb0a.

📒 Files selected for processing (5)
  • registry/app/api/handler/generic/base.go
  • registry/app/api/router/packages/route.go
  • registry/app/pkg/base/base.go
  • registry/app/pkg/base/utils.go
  • registry/app/pkg/generic/local.go

Comment thread registry/app/pkg/base/base.go Outdated
Msgf("Uploading raw file for package type: %s, filePath: %s",
info.Registry.PackageType, info.FilePath)

headers, sha256, err := c.localBase.UploadRawFile(ctx, info.ArtifactInfo, info.FilePath, reader, 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.

⚠️ Potential issue | 🟠 Major

failOnConflict is hardcoded to true — raw files can never be updated.

Every re-upload of an existing raw file will return a 409 Conflict with no way for callers to opt into an overwrite. If update semantics are needed (e.g., CI pushing a new build artifact to the same path), there is currently no path to do so.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/generic/local.go` at line 150, The call to
c.localBase.UploadRawFile(ctx, info.ArtifactInfo, info.FilePath, reader, true)
hardcodes failOnConflict=true so raw files can never be overwritten; change this
to pass a configurable boolean instead (e.g., a field on the incoming info
struct or an explicit parameter) and wire that through to UploadRawFile so
callers can opt into overwrite semantics; update the caller site in
registry/app/pkg/generic/local.go (the UploadRawFile invocation) and any
upstream call sites or API surface that creates the info/parameters so the
overwrite flag is plumbed through.

@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: 3

♻️ Duplicate comments (1)
registry/app/api/handler/generic/base.go (1)

330-334: ⚠️ Potential issue | 🔴 Critical

Same splits[4:] panic risk as in buildFileArtifactInfo.

The GENERIC path in GetGenericArtifactInfoV2 also accesses splits[4:] without a prior length check. Add the same bounds guard (or extract a shared helper) here.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 330 - 334,
GetGenericArtifactInfoV2 currently slices splits[4:] without verifying splits
has at least 5 elements, risking a panic; add the same bounds guard used in
buildFileArtifactInfo (or extract a helper like validatePathSegments) to check
len(splits) >= 5 before computing remainingSegments := splits[4:], and return a
usererror.BadRequestf("Invalid request: no file path provided") (or equivalent)
when the check fails so the function safely handles short paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@registry/app/api/handler/generic/base.go`:
- Around line 196-221: GetFileArtifactInfoV2 forwards URL path segments (splits)
to buildFileArtifactInfo without ensuring there are at least 4 segments, which
can cause a panic when buildFileArtifactInfo slices splits[4:]; update
buildFileArtifactInfo to validate len(splits) (or the specific index access)
before using splits[4:] and return a user-friendly NotFound or BadRequest error
when the path is too short; reference the functions
Handler.GetFileArtifactInfoV2 and Handler.buildFileArtifactInfo and the variable
splits/splits[4:] when making the change.
- Around line 353-356: The fmt.Errorf wrapping around validatePackageVersionV2's
error discards the usererror HTTP 400; instead, when
validatePackageVersionV2(packageName, version) returns an error, propagate it as
a usererror (preserve the *usererror.Error) or convert it to a
usererror.BadRequestf so callers see a 400. Update the branch that currently
returns generic2.ArtifactInfo{} with fmt.Errorf to either (1) detect and return
the original *usererror.Error from validatePackageVersionV2, or (2) always
return usererror.BadRequestf("invalid image name/version/fileName: %q/%q: %v",
packageName, version, err) so the HTTP 400 status is preserved (fix the code
around validatePackageVersionV2 and the fmt.Errorf usage).

In `@registry/app/pkg/base/base.go`:
- Around line 226-250: Move the authentication gate before the file-existence
probe to avoid unauthenticated path probing: call request.AuthSessionFrom(ctx)
first and return usererror.ErrUnauthorized (with the same logging used now) if
unauthenticated, then call l.ExistsByFilePath(ctx, registry.ID, filePath) and
proceed with the existing failOnConflict handling; ensure you preserve the
existing return values (responseHeaders, "", error types) and keep the same log
messages around AuthSessionFrom and ExistsByFilePath so behavior and diagnostics
remain consistent.

---

Duplicate comments:
In `@registry/app/api/handler/generic/base.go`:
- Around line 330-334: GetGenericArtifactInfoV2 currently slices splits[4:]
without verifying splits has at least 5 elements, risking a panic; add the same
bounds guard used in buildFileArtifactInfo (or extract a helper like
validatePathSegments) to check len(splits) >= 5 before computing
remainingSegments := splits[4:], and return a usererror.BadRequestf("Invalid
request: no file path provided") (or equivalent) when the check fails so the
function safely handles short paths.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f44cb0a and 2b34294.

📒 Files selected for processing (3)
  • registry/app/api/handler/generic/base.go
  • registry/app/pkg/base/base.go
  • registry/app/pkg/generic/local.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • registry/app/pkg/generic/local.go

Comment thread registry/app/api/handler/generic/base.go Outdated
Comment thread registry/app/api/handler/generic/base.go
Comment thread registry/app/pkg/base/base.go Outdated
Comment on lines +226 to +250
exists, err := l.ExistsByFilePath(ctx, registry.ID, filePath)
if err != nil {
log.Ctx(ctx).Error().Err(err).
Int64("registryID", registry.ID).
Str("filePath", filePath).
Msg("Failed to check if file exists")
return responseHeaders, "", errcode.ErrCodeUnknown.WithDetail(err)
}

if exists && failOnConflict {
log.Ctx(ctx).Warn().
Str("filePath", filePath).
Int64("registryID", registry.ID).
Msg("File already exists and failOnConflict is true")
return responseHeaders, "", usererror.Conflict(
fmt.Sprintf("File already exists at path: %s", filePath))
}

session, ok := request.AuthSessionFrom(ctx)
if !ok {
log.Ctx(ctx).Error().
Str("filePath", filePath).
Msg("Authentication required for raw file upload")
return responseHeaders, "", usererror.ErrUnauthorized
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Auth check should precede the existence check to prevent unauthenticated path probing.

An unauthenticated caller can distinguish between a 409 Conflict response (file exists) and a 401 Unauthorized response (file doesn't exist or wrong path), leaking file-existence information without any authentication.

🛡️ Proposed fix: move auth check before existence check
+	session, ok := request.AuthSessionFrom(ctx)
+	if !ok {
+		log.Ctx(ctx).Error().
+			Str("filePath", filePath).
+			Msg("Authentication required for raw file upload")
+		return responseHeaders, "", usererror.ErrUnauthorized
+	}
+
 	// Check if file already exists
 	exists, err := l.ExistsByFilePath(ctx, registry.ID, filePath)
 	if err != nil {
 		...
 	}
 
 	if exists && failOnConflict {
 		...
 	}
 
-	session, ok := request.AuthSessionFrom(ctx)
-	if !ok {
-		...
-	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/base/base.go` around lines 226 - 250, Move the
authentication gate before the file-existence probe to avoid unauthenticated
path probing: call request.AuthSessionFrom(ctx) first and return
usererror.ErrUnauthorized (with the same logging used now) if unauthenticated,
then call l.ExistsByFilePath(ctx, registry.ID, filePath) and proceed with the
existing failOnConflict handling; ensure you preserve the existing return values
(responseHeaders, "", error types) and keep the same log messages around
AuthSessionFrom and ExistsByFilePath so behavior and diagnostics remain
consistent.

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

♻️ Duplicate comments (3)
registry/app/pkg/base/base.go (1)

215-237: ⚠️ Potential issue | 🟠 Major

Auth check should precede the existence check to prevent unauthenticated path probing.

An unauthenticated caller can distinguish between a 409 Conflict (file exists) and a 401 Unauthorized (no session), leaking file-existence information. Move the auth check before ExistsByFilePath.

🛡️ Proposed fix: reorder auth and existence checks
 func (l *localBase) UploadRawFile(
 	ctx context.Context,
 	info pkg.ArtifactInfo,
 	filePath string,
 	file io.ReadCloser,
 	failOnConflict bool,
 ) (*commons.ResponseHeaders, string, error) {
 	responseHeaders := &commons.ResponseHeaders{
 		Headers: make(map[string]string),
 		Code:    0,
 	}
+	session, ok := request.AuthSessionFrom(ctx)
+	if !ok {
+		log.Ctx(ctx).Error().
+			Str("filePath", filePath).
+			Msg("Authentication required for raw file upload")
+		return responseHeaders, "", usererror.ErrUnauthorized
+	}
 	exists, err := l.ExistsByFilePath(ctx, info.RegistryID, filePath)
 	if err != nil {
 		log.Ctx(ctx).Error().Err(err).
 			Int64("registryID", info.RegistryID).
 			Str("filePath", filePath).
 			Msg("Failed to check if file exists")
 		return responseHeaders, "", errcode.ErrCodeUnknown.WithDetail(err)
 	}
 	if exists && failOnConflict {
 		log.Ctx(ctx).Warn().
 			Str("filePath", filePath).
 			Int64("registryID", info.RegistryID).
 			Msg("File already exists and failOnConflict is true")
 		return responseHeaders, "", usererror.Conflict(
 			fmt.Sprintf("File already exists at path: %s", filePath))
 	}
-	session, ok := request.AuthSessionFrom(ctx)
-	if !ok {
-		log.Ctx(ctx).Error().
-			Str("filePath", filePath).
-			Msg("Authentication required for raw file upload")
-		return responseHeaders, "", usererror.ErrUnauthorized
-	}
 	fileInfo, err := l.fileManager.UploadFile(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/base/base.go` around lines 215 - 237, Reorder the
authentication and existence checks so the request.AuthSessionFrom(ctx) call
happens before calling l.ExistsByFilePath(ctx, info.RegistryID, filePath);
specifically, call request.AuthSessionFrom and return usererror.ErrUnauthorized
if no session before invoking l.ExistsByFilePath, then proceed to check exists
and handle failOnConflict as before; ensure log messages remain appropriate (use
the same log lines around AuthSessionFrom and ExistsByFilePath) and preserve the
same error/return behavior for the existence-check path.
registry/app/api/handler/generic/base.go (2)

248-251: ⚠️ Potential issue | 🟠 Major

fmt.Errorf wrapping strips the HTTP 400 status from usererror.

validatePackageVersionV2 returns a *usererror.Error (HTTP 400), but wrapping it with fmt.Errorf discards the HTTP status. Callers will receive a generic error, likely causing a 500 instead of 400.

🐛 Proposed fix
 	if err = validatePackageVersionV2(packageName, version); err != nil {
-		return generic2.ArtifactInfo{}, fmt.Errorf("invalid package name/version/fileName: %q/%q %w", packageName,
-			version, err)
+		return generic2.ArtifactInfo{}, usererror.BadRequestf("invalid package name/version/fileName: %q/%q: %v",
+			packageName, version, err)
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 248 - 251, The
fmt.Errorf wrapper around the error returned by validatePackageVersionV2 loses
the original *usererror.Error semantics (HTTP 400) for callers; instead do not
wrap the error with fmt.Errorf—either return the original err directly from the
function or attach context using a helper that preserves the usererror type
(e.g., usererror.WithMessage or equivalent) so validatePackageVersionV2's
*usererror.Error remains detectable by callers.

309-313: ⚠️ Potential issue | 🟡 Minor

Missing bounds check before splits[4:] could cause panic on malformed paths.

While the router typically provides well-formed paths, if splits has fewer than 4 elements, splits[4:] will panic. Add a defensive guard.

🛡️ Proposed fix
 func (h *Handler) buildFileArtifactInfo(
 	ctx context.Context,
 	registry *regtypes.Registry,
 	rootSpace *coretypes.SpaceCore,
 	rootIdentifier string,
 	registryIdentifier string,
 	path string,
 	splits []string,
 ) (generic2.ArtifactInfo, error) {
 	// Path format: /pkg/{rootIdentifier}/{registryIdentifier}/files/*
 	// splits[0] = "pkg", splits[1] = rootIdentifier, splits[2] = registryIdentifier, splits[3] = "files"
 	// Remaining path starts at splits[4]
+	if len(splits) < 4 {
+		return generic2.ArtifactInfo{}, usererror.BadRequestf(
+			"Invalid request path: expected /pkg/{root}/{registry}/files/..., got: %s", path)
+	}
 	remainingSegments := splits[4:]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base.go` around lines 309 - 313, The code
slices splits with splits[4:] without validating length which can panic on
malformed paths; add a defensive guard before computing remainingSegments (check
len(splits) >= 4) and return a clear error (or handle it) when the path is too
short. Update the logic around the remainingSegments assignment (the code that
sets remainingSegments := splits[4:]) to first validate splits, and reference
the variables splits and remainingSegments (and the surrounding handler/function
that computes ArtifactInfo) when making the change.
🧹 Nitpick comments (1)
registry/app/api/handler/generic/base_test.go (1)

405-493: Test verifies parsing logic inline rather than testing handler methods.

This test duplicates the path parsing logic instead of testing the actual GetGenericArtifactInfoV2 or buildFileArtifactInfo methods. While useful as a specification, it won't catch regressions if the handler's parsing logic diverges.

Consider refactoring to test the actual handler methods with mock dependencies, or at minimum, extract the parsing logic into a shared helper that both the test and handler use.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base_test.go` around lines 405 - 493, The
test duplicates inline path-parsing logic instead of exercising the real parsing
used by the handler; extract the parsing into a single helper (e.g.,
ParseArtifactPath or similar) or reuse the existing handler logic by calling
GetGenericArtifactInfoV2/buildFileArtifactInfo, then update the test to call
that helper or the handler with minimal mocks; specifically, move the
segment-splitting and package/version/filePath derivation out of
TestURLPathParsing into a shared function, update
GetGenericArtifactInfoV2/buildFileArtifactInfo to call that helper, and replace
the inline assertions in TestURLPathParsing with calls to the helper or to the
handler (using mocked dependencies) so the test verifies the actual
implementation rather than a duplicated copy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@registry/app/api/handler/generic/base.go`:
- Around line 248-251: The fmt.Errorf wrapper around the error returned by
validatePackageVersionV2 loses the original *usererror.Error semantics (HTTP
400) for callers; instead do not wrap the error with fmt.Errorf—either return
the original err directly from the function or attach context using a helper
that preserves the usererror type (e.g., usererror.WithMessage or equivalent) so
validatePackageVersionV2's *usererror.Error remains detectable by callers.
- Around line 309-313: The code slices splits with splits[4:] without validating
length which can panic on malformed paths; add a defensive guard before
computing remainingSegments (check len(splits) >= 4) and return a clear error
(or handle it) when the path is too short. Update the logic around the
remainingSegments assignment (the code that sets remainingSegments :=
splits[4:]) to first validate splits, and reference the variables splits and
remainingSegments (and the surrounding handler/function that computes
ArtifactInfo) when making the change.

In `@registry/app/pkg/base/base.go`:
- Around line 215-237: Reorder the authentication and existence checks so the
request.AuthSessionFrom(ctx) call happens before calling l.ExistsByFilePath(ctx,
info.RegistryID, filePath); specifically, call request.AuthSessionFrom and
return usererror.ErrUnauthorized if no session before invoking
l.ExistsByFilePath, then proceed to check exists and handle failOnConflict as
before; ensure log messages remain appropriate (use the same log lines around
AuthSessionFrom and ExistsByFilePath) and preserve the same error/return
behavior for the existence-check path.

---

Nitpick comments:
In `@registry/app/api/handler/generic/base_test.go`:
- Around line 405-493: The test duplicates inline path-parsing logic instead of
exercising the real parsing used by the handler; extract the parsing into a
single helper (e.g., ParseArtifactPath or similar) or reuse the existing handler
logic by calling GetGenericArtifactInfoV2/buildFileArtifactInfo, then update the
test to call that helper or the handler with minimal mocks; specifically, move
the segment-splitting and package/version/filePath derivation out of
TestURLPathParsing into a shared function, update
GetGenericArtifactInfoV2/buildFileArtifactInfo to call that helper, and replace
the inline assertions in TestURLPathParsing with calls to the helper or to the
handler (using mocked dependencies) so the test verifies the actual
implementation rather than a duplicated copy.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b34294 and 6f10489.

📒 Files selected for processing (5)
  • registry/app/api/handler/generic/base.go
  • registry/app/api/handler/generic/base_test.go
  • registry/app/pkg/base/base.go
  • registry/app/pkg/base/utils.go
  • registry/app/pkg/types/generic/types.go

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@registry/app/api/controller/pkg/generic/v2.go`:
- Around line 48-50: The code performs an unchecked type assertion on
base.Factory(key) into generic2.Registry before calling methods like
DownloadFile, HeadFile, DeleteFile, and PutFile, which can cause a nil pointer
panic; update each use (the DownloadFile call where genericRegistry is assigned,
and the analogous places for HeadFile, DeleteFile, PutFile) to perform the
two-value assertion (e.g., r, ok := base.Factory(key).(generic2.Registry)), and
if !ok or r == nil, return an appropriate error response (or log and return)
instead of calling methods on the nil interface to avoid dereference panics.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f10489 and c22b9e2.

📒 Files selected for processing (19)
  • cmd/gitness/wire_gen.go
  • registry/app/api/controller/pkg/generic/controller.go
  • registry/app/api/controller/pkg/generic/v2.go
  • registry/app/api/controller/pkg/generic/wire.go
  • registry/app/api/interfaces/package_type_factory.go
  • registry/app/api/interfaces/package_wrapper.go
  • registry/app/helpers/package_wrapper.go
  • registry/app/helpers/pkg/cargo.go
  • registry/app/helpers/pkg/docker.go
  • registry/app/helpers/pkg/generic.go
  • registry/app/helpers/pkg/gopkg.go
  • registry/app/helpers/pkg/helm.go
  • registry/app/helpers/pkg/huggingface.go
  • registry/app/helpers/pkg/maven.go
  • registry/app/helpers/pkg/npm.go
  • registry/app/helpers/pkg/nuget.go
  • registry/app/helpers/pkg/python.go
  • registry/app/helpers/pkg/rpm.go
  • registry/app/pkg/base/wrapper.go

Comment on lines 48 to 50
key := base.GetFactoryKey(artifact2.PackageTypeGENERIC, registry.Type)
genericRegistry, _ := base.Factory(key).(generic2.Registry)
headers, fileReader, readCloser, redirectURL, err := genericRegistry.DownloadFile(ctx, info, filePath)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Nil pointer dereference risk: type assertion result not validated.

The type assertion ignores the ok boolean. If base.Factory(key) returns nil or a type that doesn't implement generic2.Registry, genericRegistry will be nil, causing a panic on genericRegistry.DownloadFile(...).

This same issue exists at lines 108, 151, and 199.

🐛 Proposed fix to handle failed type assertion
 		key := base.GetFactoryKey(artifact2.PackageTypeGENERIC, registry.Type)
-		genericRegistry, _ := base.Factory(key).(generic2.Registry)
+		genericRegistry, ok := base.Factory(key).(generic2.Registry)
+		if !ok || genericRegistry == nil {
+			return &GetArtifactResponse{
+				BaseResponse: BaseResponse{
+					Error: fmt.Errorf("failed to resolve generic registry for type: %s", registry.Type),
+				},
+			}
+		}
 		headers, fileReader, readCloser, redirectURL, err := genericRegistry.DownloadFile(ctx, info, filePath)

Apply the same pattern to HeadFile (line 108), DeleteFile (line 151), and PutFile (line 199).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/controller/pkg/generic/v2.go` around lines 48 - 50, The code
performs an unchecked type assertion on base.Factory(key) into generic2.Registry
before calling methods like DownloadFile, HeadFile, DeleteFile, and PutFile,
which can cause a nil pointer panic; update each use (the DownloadFile call
where genericRegistry is assigned, and the analogous places for HeadFile,
DeleteFile, PutFile) to perform the two-value assertion (e.g., r, ok :=
base.Factory(key).(generic2.Registry)), and if !ok or r == nil, return an
appropriate error response (or log and return) instead of calling methods on the
nil interface to avoid dereference panics.

@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

🧹 Nitpick comments (1)
registry/app/api/handler/generic/base_test.go (1)

446-492: Consider testing actual parsing functions instead of inline logic.

This test implements URL path parsing inline rather than invoking production code. While useful as documentation of expected parsing behavior, it won't catch regressions if the actual parsing logic in production code changes.

If there's an existing parsing function (or one to be added), consider refactoring this test to call it directly and validate the returned values.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base_test.go` around lines 446 - 492, The
test currently duplicates URL path parsing inline which won’t catch regressions;
refactor the test to call the production parsing function (e.g., implement or
use a function like ParseRegistryPath/ParsePackagePath or
ParseGenericFileRequest that accepts the raw urlPath and returns isGeneric,
packageName, version, fileName, filePath, error) and assert its returned values
against tt.want* fields instead of re-parsing inside the test; update or add the
parsing function in the handler/generic package (exported or package-private) so
tests can exercise the real logic and adjust test cases to call that function
and check for errors and returned values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@registry/app/api/handler/generic/base_test.go`:
- Around line 453-455: The test currently logs an error when the segment counts
differ but continues execution, which can cause panics when later accessing
remainingSegments; change the check in the test (the block comparing
len(remainingSegments) and len(tt.wantSegments) that calls t.Errorf) to stop
execution immediately on mismatch—replace the t.Errorf with a fatal-style stop
(e.g., t.Fatalf or t.FailNow) or return from the test so subsequent index access
on remainingSegments is skipped; target the comparison around remainingSegments
and tt.wantSegments in the failing test.

In `@registry/app/pkg/python/local_helper_test.go`:
- Around line 101-104: There are two identical method declarations for
MockLocalBase.ExistsByFilePath which causes a compile error; remove one of the
duplicate implementations so only a single ExistsByFilePath(ctx context.Context,
registryID int64, filePath string) (bool, error) method remains on the
MockLocalBase receiver, preserving the existing implementation that calls
m.Called(ctx, registryID, filePath) and returns args.Bool(0), args.Error(1).

---

Nitpick comments:
In `@registry/app/api/handler/generic/base_test.go`:
- Around line 446-492: The test currently duplicates URL path parsing inline
which won’t catch regressions; refactor the test to call the production parsing
function (e.g., implement or use a function like
ParseRegistryPath/ParsePackagePath or ParseGenericFileRequest that accepts the
raw urlPath and returns isGeneric, packageName, version, fileName, filePath,
error) and assert its returned values against tt.want* fields instead of
re-parsing inside the test; update or add the parsing function in the
handler/generic package (exported or package-private) so tests can exercise the
real logic and adjust test cases to call that function and check for errors and
returned values.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c22b9e2 and fb17cac.

📒 Files selected for processing (4)
  • cmd/gitness/wire_gen.go
  • registry/app/api/handler/generic/base_test.go
  • registry/app/helpers/pkg/generic.go
  • registry/app/pkg/python/local_helper_test.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • registry/app/helpers/pkg/generic.go
  • cmd/gitness/wire_gen.go

Comment on lines +453 to +455
if len(remainingSegments) != len(tt.wantSegments) {
t.Errorf("Expected %d segments, got %d", len(tt.wantSegments), len(remainingSegments))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Missing early return after segment count mismatch.

When the segment count doesn't match expectations, the test logs an error but continues execution. Subsequent index accesses on remainingSegments may produce misleading errors or panic if the count is significantly different.

Proposed fix
 if len(remainingSegments) != len(tt.wantSegments) {
     t.Errorf("Expected %d segments, got %d", len(tt.wantSegments), len(remainingSegments))
+    return
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if len(remainingSegments) != len(tt.wantSegments) {
t.Errorf("Expected %d segments, got %d", len(tt.wantSegments), len(remainingSegments))
}
if len(remainingSegments) != len(tt.wantSegments) {
t.Errorf("Expected %d segments, got %d", len(tt.wantSegments), len(remainingSegments))
return
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/api/handler/generic/base_test.go` around lines 453 - 455, The
test currently logs an error when the segment counts differ but continues
execution, which can cause panics when later accessing remainingSegments; change
the check in the test (the block comparing len(remainingSegments) and
len(tt.wantSegments) that calls t.Errorf) to stop execution immediately on
mismatch—replace the t.Errorf with a fatal-style stop (e.g., t.Fatalf or
t.FailNow) or return from the test so subsequent index access on
remainingSegments is skipped; target the comparison around remainingSegments and
tt.wantSegments in the failing test.

Comment on lines +101 to +104
func (m *MockLocalBase) ExistsByFilePath(ctx context.Context, registryID int64, filePath string) (bool, error) {
args := m.Called(ctx, registryID, filePath)
return args.Bool(0), args.Error(1)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

rg -nP 'func\s+\(m\s+\*MockLocalBase\)\s+ExistsByFilePath\s*\(' registry/app/pkg/python/local_helper_test.go

Repository: abhinavcode/harness

Length of output: 296


🏁 Script executed:

# Get the file size to understand scope
wc -l registry/app/pkg/python/local_helper_test.go

Repository: abhinavcode/harness

Length of output: 111


🏁 Script executed:

# Inspect both claimed locations
sed -n '100,105p' registry/app/pkg/python/local_helper_test.go
sed -n '145,152p' registry/app/pkg/python/local_helper_test.go

Repository: abhinavcode/harness

Length of output: 481


Remove duplicate ExistsByFilePath method declaration.

MockLocalBase declares ExistsByFilePath twice (line 101 and line 148 in the same file), which causes a Go compile error. Keep one declaration and remove the other.

Duplicate method locations

Lines 101-104 and lines 148-151 both contain identical ExistsByFilePath implementations on the MockLocalBase receiver.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/pkg/python/local_helper_test.go` around lines 101 - 104, There
are two identical method declarations for MockLocalBase.ExistsByFilePath which
causes a compile error; remove one of the duplicate implementations so only a
single ExistsByFilePath(ctx context.Context, registryID int64, filePath string)
(bool, error) method remains on the MockLocalBase receiver, preserving the
existing implementation that calls m.Called(ctx, registryID, filePath) and
returns args.Bool(0), args.Error(1).

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.

2 participants