~stepbrobd/soft-serve

1de446f208019d90dc08fa24437ee63bbbc80667 — DongoDB 2 days ago 0540b4d master
fix: prevent enumeration of private repo (#614)

M pkg/ssh/cmd/branch.go => pkg/ssh/cmd/branch.go +5 -7
@@ 61,18 61,16 @@ func branchListCommand() *cobra.Command {

func branchDefaultCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "default REPOSITORY [BRANCH]",
		Short: "Set or get the default branch",
		Args:  cobra.RangeArgs(1, 2),
		Use:               "default REPOSITORY [BRANCH]",
		Short:             "Set or get the default branch",
		Args:              cobra.RangeArgs(1, 2),
		PersistentPreRunE: checkIfReadable,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)
			rn := strings.TrimSuffix(args[0], ".git")
			switch len(args) {
			case 1:
				if err := checkIfReadable(cmd, args); err != nil {
					return err
				}
				rr, err := be.Repository(ctx, rn)
				if err != nil {
					return err


@@ 149,7 147,7 @@ func branchDeleteCommand() *cobra.Command {
		Aliases:           []string{"remove", "rm", "del"},
		Short:             "Delete a branch",
		Args:              cobra.ExactArgs(2),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)

M pkg/ssh/cmd/cmd.go => pkg/ssh/cmd/cmd.go +11 -1
@@ 121,7 121,7 @@ func checkIfReadable(cmd *cobra.Command, args []string) error {
	user := proto.UserFromContext(ctx)
	auth := be.AccessLevelForUser(cmd.Context(), rn, user)
	if auth < access.ReadOnlyAccess {
		return proto.ErrUnauthorized
		return proto.ErrRepoNotFound
	}
	return nil
}


@@ 185,3 185,13 @@ func checkIfCollab(cmd *cobra.Command, args []string) error {
	}
	return nil
}

func checkIfReadableAndCollab(cmd *cobra.Command, args []string) error {
	if err := checkIfReadable(cmd, args); err != nil {
		return err
	}
	if err := checkIfCollab(cmd, args); err != nil {
		return err
	}
	return nil
}

M pkg/ssh/cmd/collab.go => pkg/ssh/cmd/collab.go +3 -3
@@ 28,7 28,7 @@ func collabAddCommand() *cobra.Command {
		Short:             "Add a collaborator to a repo",
		Long:              "Add a collaborator to a repo. LEVEL can be one of: no-access, read-only, read-write, or admin-access. Defaults to read-write.",
		Args:              cobra.RangeArgs(2, 3),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)


@@ 54,7 54,7 @@ func collabRemoveCommand() *cobra.Command {
		Use:               "remove REPOSITORY USERNAME",
		Args:              cobra.ExactArgs(2),
		Short:             "Remove a collaborator from a repo",
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)


@@ 73,7 73,7 @@ func collabListCommand() *cobra.Command {
		Use:               "list REPOSITORY",
		Short:             "List collaborators for a repo",
		Args:              cobra.ExactArgs(1),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)

M pkg/ssh/cmd/delete.go => pkg/ssh/cmd/delete.go +1 -1
@@ 11,7 11,7 @@ func deleteCommand() *cobra.Command {
		Aliases:           []string{"del", "remove", "rm"},
		Short:             "Delete a repository",
		Args:              cobra.ExactArgs(1),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)

M pkg/ssh/cmd/description.go => pkg/ssh/cmd/description.go +5 -8
@@ 9,20 9,17 @@ import (

func descriptionCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:     "description REPOSITORY [DESCRIPTION]",
		Aliases: []string{"desc"},
		Short:   "Set or get the description for a repository",
		Args:    cobra.MinimumNArgs(1),
		Use:               "description REPOSITORY [DESCRIPTION]",
		Aliases:           []string{"desc"},
		Short:             "Set or get the description for a repository",
		Args:              cobra.MinimumNArgs(1),
		PersistentPreRunE: checkIfReadable,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)
			rn := strings.TrimSuffix(args[0], ".git")
			switch len(args) {
			case 1:
				if err := checkIfReadable(cmd, args); err != nil {
					return err
				}

				desc, err := be.Description(ctx, rn)
				if err != nil {
					return err

M pkg/ssh/cmd/hidden.go => pkg/ssh/cmd/hidden.go +5 -8
@@ 7,20 7,17 @@ import (

func hiddenCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:     "hidden REPOSITORY [TRUE|FALSE]",
		Short:   "Hide or unhide a repository",
		Aliases: []string{"hide"},
		Args:    cobra.MinimumNArgs(1),
		Use:               "hidden REPOSITORY [TRUE|FALSE]",
		Short:             "Hide or unhide a repository",
		Aliases:           []string{"hide"},
		Args:              cobra.MinimumNArgs(1),
		PersistentPreRunE: checkIfReadable,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)
			repo := args[0]
			switch len(args) {
			case 1:
				if err := checkIfReadable(cmd, args); err != nil {
					return err
				}

				hidden, err := be.IsHidden(ctx, repo)
				if err != nil {
					return err

M pkg/ssh/cmd/private.go => pkg/ssh/cmd/private.go +4 -7
@@ 10,9 10,10 @@ import (

func privateCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:   "private REPOSITORY [true|false]",
		Short: "Set or get a repository private property",
		Args:  cobra.RangeArgs(1, 2),
		Use:               "private REPOSITORY [true|false]",
		Short:             "Set or get a repository private property",
		Args:              cobra.RangeArgs(1, 2),
		PersistentPreRunE: checkIfReadable,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)


@@ 20,10 21,6 @@ func privateCommand() *cobra.Command {

			switch len(args) {
			case 1:
				if err := checkIfReadable(cmd, args); err != nil {
					return err
				}

				isPrivate, err := be.IsPrivate(ctx, rn)
				if err != nil {
					return err

M pkg/ssh/cmd/project_name.go => pkg/ssh/cmd/project_name.go +5 -8
@@ 9,20 9,17 @@ import (

func projectName() *cobra.Command {
	cmd := &cobra.Command{
		Use:     "project-name REPOSITORY [NAME]",
		Aliases: []string{"project"},
		Short:   "Set or get the project name for a repository",
		Args:    cobra.MinimumNArgs(1),
		Use:               "project-name REPOSITORY [NAME]",
		Aliases:           []string{"project"},
		Short:             "Set or get the project name for a repository",
		Args:              cobra.MinimumNArgs(1),
		PersistentPreRunE: checkIfReadable,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)
			rn := strings.TrimSuffix(args[0], ".git")
			switch len(args) {
			case 1:
				if err := checkIfReadable(cmd, args); err != nil {
					return err
				}

				pn, err := be.ProjectName(ctx, rn)
				if err != nil {
					return err

M pkg/ssh/cmd/rename.go => pkg/ssh/cmd/rename.go +1 -1
@@ 11,7 11,7 @@ func renameCommand() *cobra.Command {
		Aliases:           []string{"mv", "move"},
		Short:             "Rename an existing repository",
		Args:              cobra.ExactArgs(2),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)

M pkg/ssh/cmd/tag.go => pkg/ssh/cmd/tag.go +1 -1
@@ 64,7 64,7 @@ func tagDeleteCommand() *cobra.Command {
		Aliases:           []string{"remove", "rm", "del"},
		Short:             "Delete a tag",
		Args:              cobra.ExactArgs(2),
		PersistentPreRunE: checkIfCollab,
		PersistentPreRunE: checkIfReadableAndCollab,
		RunE: func(cmd *cobra.Command, args []string) error {
			ctx := cmd.Context()
			be := backend.FromContext(ctx)

M testscript/testdata/repo-perms.txtar => testscript/testdata/repo-perms.txtar +14 -14
@@ 36,33 36,33 @@ soft repo collab list repo1

# regular user can't access it
! usoft repo info repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo tree repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo tag list repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo tag delete repo1 v1.0.0
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo blob repo1 README.md
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo description repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo description repo1 'new desc'
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo project-name repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo private repo1 true
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo private repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo rename repo1 repo11
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo branch default repo1
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo branch default repo1 main
stderr 'unauthorized'
stderr 'repository not found'
! usoft repo delete repo1
stderr 'unauthorized'
stderr 'repository not found'

# add user1 as collab
! soft repo collab add repo1 user1 foobar