Skip to content

Commit

Permalink
Merge pull request #70 from portainer/feat/add-ns-validation
Browse files Browse the repository at this point in the history
feat: added namespace validation to prevent unwanted operations to pr…
  • Loading branch information
deviantony authored Oct 5, 2023
2 parents 3dc4209 + ea9a9a0 commit f2c3906
Show file tree
Hide file tree
Showing 45 changed files with 190 additions and 67 deletions.
3 changes: 1 addition & 2 deletions internal/api/apis/apps/deployments/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import (
)

func (svc DeploymentService) CreateDeployment(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)

deployment := &appsv1.Deployment{}

err := httputils.ParseJSONBody(r.Request, &deployment)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
5 changes: 3 additions & 2 deletions internal/api/apis/apps/deployments/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import (
"net/http"

"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/api/utils"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func (svc DeploymentService) DeleteDeployment(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
deploymentName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

deploymentName := r.PathParameter("name")
svc.adapter.DeleteContainer(r.Request.Context(), deploymentName, namespace)

w.WriteAsJson(metav1.Status{
Expand Down
6 changes: 6 additions & 0 deletions internal/api/apis/apps/deployments/deployments.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package deployments
import (
"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/adapter"
"github.com/portainer/k2d/internal/api/utils"
"github.com/portainer/k2d/internal/controller"
)

Expand Down Expand Up @@ -30,6 +31,7 @@ func (svc DeploymentService) RegisterDeploymentAPI(ws *restful.WebService) {
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))

ws.Route(ws.POST("/v1/namespaces/{namespace}/deployments").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.CreateDeployment).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))
Expand All @@ -38,6 +40,7 @@ func (svc DeploymentService) RegisterDeploymentAPI(ws *restful.WebService) {
To(svc.ListDeployments))

ws.Route(ws.GET("/v1/namespaces/{namespace}/deployments").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.ListDeployments).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")))

Expand All @@ -46,6 +49,7 @@ func (svc DeploymentService) RegisterDeploymentAPI(ws *restful.WebService) {
Param(ws.PathParameter("name", "name of the deployment").DataType("string")))

ws.Route(ws.DELETE("/v1/namespaces/{namespace}/deployments/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.DeleteDeployment).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the deployment").DataType("string")))
Expand All @@ -55,6 +59,7 @@ func (svc DeploymentService) RegisterDeploymentAPI(ws *restful.WebService) {
Param(ws.PathParameter("name", "name of the deployment").DataType("string")))

ws.Route(ws.GET("/v1/namespaces/{namespace}/deployments/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.GetDeployment).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the deployment").DataType("string")))
Expand All @@ -66,6 +71,7 @@ func (svc DeploymentService) RegisterDeploymentAPI(ws *restful.WebService) {
AddExtension("x-kubernetes-group-version-kind", deploymentGVKExtension))

ws.Route(ws.PATCH("/v1/namespaces/{namespace}/deployments/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.PatchDeployment).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the deployment").DataType("string")).
Expand Down
2 changes: 1 addition & 1 deletion internal/api/apis/apps/deployments/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func (svc DeploymentService) GetDeployment(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)
deploymentName := r.PathParameter("name")

deployment, err := svc.adapter.GetDeployment(r.Request.Context(), deploymentName, namespace)
Expand Down
2 changes: 1 addition & 1 deletion internal/api/apis/apps/deployments/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func (svc DeploymentService) ListDeployments(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)

utils.ListResources(
r,
Expand Down
4 changes: 2 additions & 2 deletions internal/api/apis/apps/deployments/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
)

func (svc DeploymentService) PatchDeployment(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
deploymentName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

deploymentName := r.PathParameter("name")
patch, err := io.ReadAll(r.Request.Body)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
6 changes: 6 additions & 0 deletions internal/api/core/v1/configmaps/configmaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package configmaps
import (
"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/adapter"
"github.com/portainer/k2d/internal/api/utils"
"github.com/portainer/k2d/internal/controller"
)

Expand Down Expand Up @@ -30,6 +31,7 @@ func (svc ConfigMapService) RegisterConfigMapAPI(ws *restful.WebService) {
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))

ws.Route(ws.POST("/v1/namespaces/{namespace}/configmaps").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.CreateConfigMap).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))
Expand All @@ -38,6 +40,7 @@ func (svc ConfigMapService) RegisterConfigMapAPI(ws *restful.WebService) {
To(svc.ListConfigMaps))

ws.Route(ws.GET("/v1/namespaces/{namespace}/configmaps").
Filter(utils.NamespaceValidation(svc.adapter)).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
To(svc.ListConfigMaps))

Expand All @@ -46,6 +49,7 @@ func (svc ConfigMapService) RegisterConfigMapAPI(ws *restful.WebService) {
Param(ws.PathParameter("name", "name of the configmap").DataType("string")))

ws.Route(ws.DELETE("/v1/namespaces/{namespace}/configmaps/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.DeleteConfigMap).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the configmap").DataType("string")))
Expand All @@ -55,6 +59,7 @@ func (svc ConfigMapService) RegisterConfigMapAPI(ws *restful.WebService) {
Param(ws.PathParameter("name", "name of the configmap").DataType("string")))

ws.Route(ws.GET("/v1/namespaces/{namespace}/configmaps/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.GetConfigMap).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the configmap").DataType("string")))
Expand All @@ -66,6 +71,7 @@ func (svc ConfigMapService) RegisterConfigMapAPI(ws *restful.WebService) {
AddExtension("x-kubernetes-group-version-kind", configMapGVKExtension))

ws.Route(ws.PATCH("/v1/namespaces/{namespace}/configmaps/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.PatchConfigMap).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the configmap").DataType("string")).
Expand Down
3 changes: 1 addition & 2 deletions internal/api/core/v1/configmaps/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import (
)

func (svc ConfigMapService) CreateConfigMap(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)

configMap := &corev1.ConfigMap{}

err := httputils.ParseJSONBody(r.Request, &configMap)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/configmaps/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

func (svc ConfigMapService) DeleteConfigMap(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
configMapName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

configMapName := r.PathParameter("name")
err := svc.adapter.DeleteConfigMap(configMapName, namespace)
if err != nil {
utils.HttpError(r, w, http.StatusInternalServerError, fmt.Errorf("unable to delete configmap: %w", err))
Expand Down
2 changes: 1 addition & 1 deletion internal/api/core/v1/configmaps/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func (svc ConfigMapService) GetConfigMap(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)
configMapName := r.PathParameter("name")

configMap, err := svc.adapter.GetConfigMap(configMapName, namespace)
Expand Down
2 changes: 1 addition & 1 deletion internal/api/core/v1/configmaps/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func (svc ConfigMapService) ListConfigMaps(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)

utils.ListResources(
r,
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/configmaps/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ import (
)

func (svc ConfigMapService) PatchConfigMap(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
configMapName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

configMapName := r.PathParameter("name")
patch, err := io.ReadAll(r.Request.Body)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
2 changes: 2 additions & 0 deletions internal/api/core/v1/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package events
import (
"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/adapter"
"github.com/portainer/k2d/internal/api/utils"
)

type EventService struct {
Expand All @@ -20,5 +21,6 @@ func (svc EventService) RegisterEventAPI(ws *restful.WebService) {
To(svc.ListEvents))

ws.Route(ws.GET("/v1/namespaces/{namespace}/events").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.ListEvents))
}
2 changes: 1 addition & 1 deletion internal/api/core/v1/namespaces/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

func (svc NamespaceService) DeleteNamespace(r *restful.Request, w *restful.Response) {
namespaceName := r.PathParameter("name")
namespaceName := utils.GetNamespaceFromRequest(r)

err := svc.adapter.DeleteNamespace(r.Request.Context(), namespaceName)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/namespaces/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
)

func (svc NamespaceService) GetNamespace(r *restful.Request, w *restful.Response) {
name := r.PathParameter("name")
namespaceName := utils.GetNamespaceFromRequest(r)

namespace, err := svc.adapter.GetNamespace(r.Request.Context(), name)
namespace, err := svc.adapter.GetNamespace(r.Request.Context(), namespaceName)
if err != nil {
if errors.Is(err, adaptererr.ErrResourceNotFound) {
w.WriteHeader(http.StatusNotFound)
Expand Down
16 changes: 10 additions & 6 deletions internal/api/core/v1/namespaces/namespaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package namespaces
import (
"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/adapter"
"github.com/portainer/k2d/internal/api/utils"
"github.com/portainer/k2d/internal/controller"
)

Expand Down Expand Up @@ -32,17 +33,20 @@ func (svc NamespaceService) RegisterNamespaceAPI(ws *restful.WebService) {
ws.Route(ws.GET("/v1/namespaces").
To(svc.ListNamespaces))

ws.Route(ws.GET("/v1/namespaces/{name}").
ws.Route(ws.GET("/v1/namespaces/{namespace}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.GetNamespace).
Param(ws.PathParameter("name", "name of the namespace").DataType("string")))
Param(ws.PathParameter("namespace", "name of the namespace").DataType("string")))

ws.Route(ws.PATCH("/v1/namespaces/{name}").
ws.Route(ws.PATCH("/v1/namespaces/{namespace}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.PatchNamespace).
Param(ws.PathParameter("name", "name of the namespace").DataType("string")).
Param(ws.PathParameter("namespace", "name of the namespace").DataType("string")).
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")).
AddExtension("x-kubernetes-group-version-kind", namespaceGVKExtension))

ws.Route(ws.DELETE("/v1/namespaces/{name}").
ws.Route(ws.DELETE("/v1/namespaces/{namespace}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.DeleteNamespace).
Param(ws.PathParameter("name", "name of the namespace").DataType("string")))
Param(ws.PathParameter("namespace", "name of the namespace").DataType("string")))
}
2 changes: 1 addition & 1 deletion internal/api/core/v1/namespaces/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (
)

func (svc NamespaceService) PatchNamespace(r *restful.Request, w *restful.Response) {
namespaceName := r.PathParameter("name")
namespaceName := utils.GetNamespaceFromRequest(r)

patch, err := io.ReadAll(r.Request.Body)
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/persistentvolumeclaims/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import (
)

func (svc PersistentVolumeClaimService) CreatePersistentVolumeClaim(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
persistentVolumeClaim := &corev1.PersistentVolumeClaim{}
namespace := utils.GetNamespaceFromRequest(r)

persistentVolumeClaim := &corev1.PersistentVolumeClaim{}
err := httputils.ParseJSONBody(r.Request, &persistentVolumeClaim)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/persistentvolumeclaims/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import (
)

func (svc PersistentVolumeClaimService) DeletePersistentVolumeClaim(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
persistentVolumeClaimName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

persistentVolumeClaimName := r.PathParameter("name")
err := svc.adapter.DeletePersistentVolumeClaim(r.Request.Context(), persistentVolumeClaimName, namespace)
if err != nil {
utils.HttpError(r, w, http.StatusInternalServerError, fmt.Errorf("unable to delete persistent volume claim: %w", err))
Expand Down
2 changes: 1 addition & 1 deletion internal/api/core/v1/persistentvolumeclaims/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

func (svc PersistentVolumeClaimService) GetPersistentVolumeClaim(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)
persistentVolumeClaimName := r.PathParameter("name")

persistentVolumeClaim, err := svc.adapter.GetPersistentVolumeClaim(r.Request.Context(), persistentVolumeClaimName, namespace)
Expand Down
2 changes: 1 addition & 1 deletion internal/api/core/v1/persistentvolumeclaims/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
)

func (svc PersistentVolumeClaimService) ListPersistentVolumeClaims(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
namespace := utils.GetNamespaceFromRequest(r)

utils.ListResources(
r,
Expand Down
4 changes: 2 additions & 2 deletions internal/api/core/v1/persistentvolumeclaims/patch.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import (
)

func (svc PersistentVolumeClaimService) PatchPersistentVolumeClaim(r *restful.Request, w *restful.Response) {
namespace := r.PathParameter("namespace")
persistentVolumeClaimName := r.PathParameter("name")
namespace := utils.GetNamespaceFromRequest(r)

persistentVolumeClaimName := r.PathParameter("name")
patch, err := io.ReadAll(r.Request.Body)
if err != nil {
utils.HttpError(r, w, http.StatusBadRequest, fmt.Errorf("unable to parse request body: %w", err))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package persistentvolumeclaims
import (
"github.com/emicklei/go-restful/v3"
"github.com/portainer/k2d/internal/adapter"
"github.com/portainer/k2d/internal/api/utils"
"github.com/portainer/k2d/internal/controller"
)

Expand Down Expand Up @@ -30,22 +31,25 @@ func (svc PersistentVolumeClaimService) RegisterPersistentVolumeClaimAPI(ws *res
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))

ws.Route(ws.POST("/v1/namespaces/{namespace}/persistentvolumeclaims").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.CreatePersistentVolumeClaim).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.QueryParameter("dryRun", "when present, indicates that modifications should not be persisted").DataType("string")))

ws.Route(ws.GET("/v1/persistentvolumeclaims").
To(svc.ListPersistentVolumeClaims))

ws.Route(ws.GET("/v1/persistentvolumeclaims/{name}").
To(svc.GetPersistentVolumeClaim).
Param(ws.PathParameter("name", "name of the persistentvolumeclaims").DataType("string")))

ws.Route(ws.GET("/v1/namespaces/{namespace}/persistentvolumeclaims").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.ListPersistentVolumeClaims).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")))

ws.Route(ws.GET("/v1/persistentvolumeclaims/{name}").
To(svc.GetPersistentVolumeClaim).
Param(ws.PathParameter("name", "name of the persistentvolumeclaims").DataType("string")))

ws.Route(ws.GET("/v1/namespaces/{namespace}/persistentvolumeclaims/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.GetPersistentVolumeClaim).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the persistentvolumeclaim").DataType("string")))
Expand All @@ -55,6 +59,7 @@ func (svc PersistentVolumeClaimService) RegisterPersistentVolumeClaimAPI(ws *res
Param(ws.PathParameter("name", "name of the persistentvolumeclaim").DataType("string")))

ws.Route(ws.DELETE("/v1/namespaces/{namespace}/persistentvolumeclaims/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.DeletePersistentVolumeClaim).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the persistentvolumeclaim").DataType("string")))
Expand All @@ -66,6 +71,7 @@ func (svc PersistentVolumeClaimService) RegisterPersistentVolumeClaimAPI(ws *res
AddExtension("x-kubernetes-group-version-kind", persistentVolumeClaimGVKExtension))

ws.Route(ws.PATCH("/v1/namespaces/{namespace}/persistentvolumeclaims/{name}").
Filter(utils.NamespaceValidation(svc.adapter)).
To(svc.PatchPersistentVolumeClaim).
Param(ws.PathParameter("namespace", "namespace name").DataType("string")).
Param(ws.PathParameter("name", "name of the persistentvolumeclaim").DataType("string")).
Expand Down
Loading

0 comments on commit f2c3906

Please sign in to comment.