Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
f44cb0a
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
2b34294
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
628e31a
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
57b4053
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
a3f2640
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
e806d1d
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 25, 2026
6f10489
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
c22b9e2
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
fb17cac
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
d066873
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
3821da7
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
d8b60b7
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
900133b
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
734f190
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 26, 2026
21453e7
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 27, 2026
22e0c56
[feat]: [AH-2903]: add support for upload/download for raw files
PragyeshMishra01 Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/gitness/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

51 changes: 51 additions & 0 deletions registry/app/api/controller/mocks/package_wrapper.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions registry/app/api/controller/pkg/generic/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ type Controller struct {
quarantineFinder quarantine.Finder
dependencyFirewallChecker interfaces.DependencyFirewallChecker
auditService audit.Service
packageWrapper interfaces.PackageWrapper
}

type DBStore struct {
Expand All @@ -82,6 +83,7 @@ func NewController(
quarantineFinder quarantine.Finder,
dependencyFirewallChecker interfaces.DependencyFirewallChecker,
auditService audit.Service,
packageWrapper interfaces.PackageWrapper,
) *Controller {
return &Controller{
SpaceStore: spaceStore,
Expand All @@ -95,6 +97,7 @@ func NewController(
quarantineFinder: quarantineFinder,
dependencyFirewallChecker: dependencyFirewallChecker,
auditService: auditService,
packageWrapper: packageWrapper,
}
}

Expand Down
43 changes: 30 additions & 13 deletions registry/app/api/controller/pkg/generic/v2.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import (
"fmt"
"io"

artifact2 "github.com/harness/gitness/registry/app/api/openapi/contracts/artifact"
"github.com/harness/gitness/registry/app/pkg"
"github.com/harness/gitness/registry/app/pkg/base"
generic2 "github.com/harness/gitness/registry/app/pkg/generic"
genericpkg "github.com/harness/gitness/registry/app/pkg/generic"
"github.com/harness/gitness/registry/app/pkg/response"
"github.com/harness/gitness/registry/app/pkg/types/generic"
registrytypes "github.com/harness/gitness/registry/types"
Expand All @@ -34,14 +35,18 @@ func (c Controller) DownloadFile(
) *GetArtifactResponse {
f := func(registry registrytypes.Registry, a pkg.Artifact) response.Response {
info.UpdateRegistryInfo(registry)
genericRegistry, ok := a.(generic2.Registry)
if !ok {

// Check if file operations are supported for this package type
if !c.packageWrapper.IsFileOperationSupported(string(registry.PackageType)) {
return &GetArtifactResponse{
BaseResponse: BaseResponse{
Error: fmt.Errorf("invalid registry type: expected generic.Registry, got %T", a),
Error: fmt.Errorf("file operations not supported for package type: %s", registry.PackageType),
},
}
}

//nolint:errcheck
genericRegistry := base.GetRegistry(artifact2.PackageTypeGENERIC, registry.Type).(genericpkg.Registry)
headers, fileReader, readCloser, redirectURL, err := genericRegistry.DownloadFile(ctx, info, filePath)
return &GetArtifactResponse{
BaseResponse: BaseResponse{
Expand Down Expand Up @@ -89,14 +94,18 @@ func (c Controller) HeadFile(
) *HeadArtifactResponse {
f := func(registry registrytypes.Registry, a pkg.Artifact) response.Response {
info.UpdateRegistryInfo(registry)
genericRegistry, ok := a.(generic2.Registry)
if !ok {

// Check if file operations are supported for this package type
if !c.packageWrapper.IsFileOperationSupported(string(registry.PackageType)) {
return &HeadArtifactResponse{
BaseResponse: BaseResponse{
Error: fmt.Errorf("invalid registry type: expected generic.Registry, got %T", a),
Error: fmt.Errorf("file operations not supported for package type: %s", registry.PackageType),
},
}
}

//nolint:errcheck
genericRegistry := base.GetRegistry(artifact2.PackageTypeGENERIC, registry.Type).(genericpkg.Registry)
headers, err := genericRegistry.HeadFile(ctx, info, filePath)
return &HeadArtifactResponse{
BaseResponse: BaseResponse{
Expand Down Expand Up @@ -128,14 +137,18 @@ func (c Controller) HeadFile(
func (c Controller) DeleteFile(ctx context.Context, info generic.ArtifactInfo) *DeleteArtifactResponse {
f := func(registry registrytypes.Registry, a pkg.Artifact) response.Response {
info.UpdateRegistryInfo(registry)
genericRegistry, ok := a.(generic2.Registry)
if !ok {

// Check if file operations are supported for this package type
if !c.packageWrapper.IsFileOperationSupported(string(registry.PackageType)) {
return &DeleteArtifactResponse{
BaseResponse: BaseResponse{
Error: fmt.Errorf("invalid registry type: expected generic.Registry, got %T", a),
Error: fmt.Errorf("file operations not supported for package type: %s", registry.PackageType),
},
}
}

//nolint:errcheck
genericRegistry := base.GetRegistry(artifact2.PackageTypeGENERIC, registry.Type).(genericpkg.Registry)
headers, err := genericRegistry.DeleteFile(ctx, info)
return &DeleteArtifactResponse{
BaseResponse: BaseResponse{
Expand Down Expand Up @@ -172,14 +185,18 @@ func (c Controller) PutFile(
) *PutArtifactResponse {
f := func(registry registrytypes.Registry, a pkg.Artifact) response.Response {
info.UpdateRegistryInfo(registry)
genericRegistry, ok := a.(generic2.Registry)
if !ok {

// Check if file operations are supported for this package type
if !c.packageWrapper.IsFileOperationSupported(string(registry.PackageType)) {
return &PutArtifactResponse{
BaseResponse: BaseResponse{
Error: fmt.Errorf("invalid registry type: expected generic.Registry, got %T", a),
Error: fmt.Errorf("file operations not supported for package type: %s", registry.PackageType),
},
}
}

//nolint:errcheck
genericRegistry := base.GetRegistry(artifact2.PackageTypeGENERIC, registry.Type).(genericpkg.Registry)
headers, sha256, err := genericRegistry.PutFile(ctx, info, reader, contentType)
return &PutArtifactResponse{
BaseResponse: BaseResponse{
Expand Down
2 changes: 2 additions & 0 deletions registry/app/api/controller/pkg/generic/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ func ControllerProvider(
quarantineFinder quarantine.Finder,
dependencyFirewallChecker interfaces.DependencyFirewallChecker,
auditService audit.Service,
packageWrapper interfaces.PackageWrapper,
) *Controller {
return NewController(
spaceStore,
Expand All @@ -64,6 +65,7 @@ func ControllerProvider(
quarantineFinder,
dependencyFirewallChecker,
auditService,
packageWrapper,
)
}

Expand Down
112 changes: 96 additions & 16 deletions registry/app/api/handler/generic/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ import (
generic2 "github.com/harness/gitness/registry/app/pkg/types/generic"
refcache2 "github.com/harness/gitness/registry/app/services/refcache"
"github.com/harness/gitness/registry/request"
regtypes "github.com/harness/gitness/registry/types"
coretypes "github.com/harness/gitness/types"

"github.com/go-chi/chi/v5"
"github.com/rs/zerolog/log"
Expand Down Expand Up @@ -193,23 +195,9 @@ func (h *Handler) GetGenericArtifactInfoV2(r *http.Request) (generic2.ArtifactIn
path := r.URL.Path
path = strings.TrimPrefix(path, "/")
splits := strings.Split(path, "/")
filePath := strings.Join(splits[6:], "/")
fileName := splits[len(splits)-1]

rootIdentifier, registryIdentifier, packageName, version :=
chi.URLParam(r, "rootIdentifier"),
chi.URLParam(r, "registryIdentifier"),
chi.URLParam(r, "package"),
chi.URLParam(r, "version")

if err := validatePackageVersionV2(packageName, version); err != nil {
return generic2.ArtifactInfo{}, fmt.Errorf("invalid image name/version/fileName: %q/%q %w", packageName,
version, err)
}

if err := validateFilePath(filePath); err != nil {
return generic2.ArtifactInfo{}, usererror.BadRequestf("%v", err)
}
rootIdentifier := chi.URLParam(r, "rootIdentifier")
registryIdentifier := chi.URLParam(r, "registryIdentifier")

rootSpace, err := h.SpaceFinder.FindByRef(ctx, rootIdentifier)
if err != nil {
Expand All @@ -226,6 +214,46 @@ func (h *Handler) GetGenericArtifactInfoV2(r *http.Request) (generic2.ArtifactIn
rootSpace.Identifier)
}

if registry.PackageType != artifact2.PackageTypeGENERIC {
return h.buildFileArtifactInfo(ctx, registry, rootSpace, rootIdentifier, registryIdentifier, path, splits)
}

// Handle GENERIC package type
// Path format: /pkg/{rootIdentifier}/{registryIdentifier}/files/*
// splits[0] = "pkg", splits[1] = rootIdentifier, splits[2] = registryIdentifier, splits[3] = "files"
// Remaining path starts at splits[4]
remainingSegments := splits[4:]

if len(remainingSegments) == 0 {
return generic2.ArtifactInfo{}, usererror.BadRequestf("Invalid request: no file path provided")
}

// For GENERIC package type:
// remainingSegments = [a, b, c, d, e]
// packageName = a (first segment)
// version = b (second segment)
// fileName = e (last segment)
// filePath = c/d/e (segments from index 2 onwards)
if len(remainingSegments) < 3 {
return generic2.ArtifactInfo{}, usererror.BadRequestf(
"Invalid request: expected at least package/version/file , got: %s",
strings.Join(remainingSegments, "/"))
}

packageName := remainingSegments[0]
version := remainingSegments[1]
fileName := remainingSegments[len(remainingSegments)-1]
filePath := strings.Join(remainingSegments[2:], "/")

if err = validatePackageVersionV2(packageName, version); err != nil {
return generic2.ArtifactInfo{}, fmt.Errorf("invalid package name/version/fileName: %q/%q %w", packageName,
version, err)
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

if err = validateFilePath(filePath); err != nil {
return generic2.ArtifactInfo{}, usererror.BadRequestf("%v", err)
}

info := generic2.ArtifactInfo{
ArtifactInfo: pkg.ArtifactInfo{
BaseInfo: &pkg.BaseInfo{
Expand Down Expand Up @@ -268,6 +296,58 @@ func (h *Handler) GetGenericArtifactInfoV2(r *http.Request) (generic2.ArtifactIn
return info, nil
}

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]
remainingSegments := splits[4:]

if len(remainingSegments) == 0 {
log.Ctx(ctx).Error().
Str("path", path).
Str("registryIdentifier", registryIdentifier).
Msg("No file path provided in request")
return generic2.ArtifactInfo{}, usererror.BadRequestf("Invalid request: no file path provided")
}

fileName := remainingSegments[len(remainingSegments)-1]
filePath := strings.Join(remainingSegments, "/")

if err := validateFilePath(filePath); err != nil {
log.Ctx(ctx).Error().Err(err).
Str("filePath", filePath).
Str("registryIdentifier", registryIdentifier).
Msg("Invalid file path")
return generic2.ArtifactInfo{}, usererror.BadRequestf("%v", err)
}

info := generic2.ArtifactInfo{
ArtifactInfo: pkg.ArtifactInfo{
BaseInfo: &pkg.BaseInfo{
PathPackageType: registry.PackageType,
ParentID: registry.ParentID,
RootIdentifier: rootIdentifier,
RootParentID: rootSpace.ID,
},
RegIdentifier: registryIdentifier,
RegistryID: registry.ID,
Registry: *registry,
},
FileName: fileName,
FilePath: filePath,
}
log.Ctx(ctx).Info().Msgf("Dispatch: URI: %s", path)
return info, nil
}

func (h *Handler) GetPackageArtifactInfo(r *http.Request) (pkg.PackageArtifactInfo, error) {
path := r.URL.Path
path = strings.TrimPrefix(path, "/")
Expand Down
Loading