Skip to content

Commit

Permalink
Merge branch 'master' into sms/k9s-support
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanmcshane committed Sep 20, 2023
2 parents cf1aeb0 + e101a54 commit 1f8486a
Show file tree
Hide file tree
Showing 189 changed files with 7,571 additions and 1,991 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/porter_stack_porter-ui.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ jobs:
cluster: "11"
host: https://dashboard.internal-tools.porter.run
project: "8"
token: ${{ secrets.PORTER_STACK_8_11 }}
token: ${{ secrets.PORTER_INTERNAL_TOOLS_DEPLOYMENT }}
6 changes: 3 additions & 3 deletions .github/workflows/production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
namespace: default
project: "5"
tag: ${{ steps.vars.outputs.sha_short }}
token: ${{ secrets.PORTER_TOKEN_5 }}
token: ${{ secrets.PORTER_PRODUCTION_DEPLOYMENT }}
- name: Update Porter Auth
timeout-minutes: 20
uses: porter-dev/[email protected]
Expand All @@ -58,7 +58,7 @@ jobs:
namespace: default
project: "5"
tag: ${{ steps.vars.outputs.sha_short }}
token: ${{ secrets.PORTER_TOKEN_5 }}
token: ${{ secrets.PORTER_PRODUCTION_DEPLOYMENT }}

deploy-worker-pool:
runs-on: ubuntu-latest
Expand All @@ -79,4 +79,4 @@ jobs:
namespace: default
project: "5"
tag: ${{ steps.vars.outputs.sha_short }}
token: ${{ secrets.PORTER_TOKEN_5 }}
token: ${{ secrets.PORTER_PRODUCTION_DEPLOYMENT }}
49 changes: 42 additions & 7 deletions api/client/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,23 @@ func NewClientWithConfig(ctx context.Context, input NewClientInput) (Client, err
// ErrNoAuthCredential returns an error when no auth credentials have been provided such as cookies or tokens
var ErrNoAuthCredential = errors.New("unable to create an API session with cookie nor token")

func (c *Client) getRequest(relPath string, data interface{}, response interface{}) error {
// getRequestConfig defines configuration for a GET request
type getRequestConfig struct {
retryCount uint
}

// withRetryCount is a convenience function for setting the retry count
func withRetryCount(retryCount uint) func(*getRequestConfig) {
return func(o *getRequestConfig) {
o.retryCount = retryCount
}
}

// getRequest makes a GET request to the API
func (c *Client) getRequest(relPath string, data interface{}, response interface{}, opts ...func(*getRequestConfig)) error {
vals := make(map[string][]string)
err := schema.NewEncoder().Encode(data, vals)
_ = schema.NewEncoder().Encode(data, vals)
var err error

urlVals := url.Values(vals)
encodedURLVals := urlVals.Encode()
Expand All @@ -106,15 +120,36 @@ func (c *Client) getRequest(relPath string, data interface{}, response interface
return err
}

if httpErr, err := c.sendRequest(req, response, true); httpErr != nil || err != nil {
if httpErr != nil {
return fmt.Errorf("%v", httpErr.Error)
config := &getRequestConfig{
retryCount: 1,
}

for _, opt := range opts {
opt(config)
}

var httpErr *types.ExternalError
for i := 0; i < int(config.retryCount); i++ {
httpErr, err = c.sendRequest(req, response, true)

if httpErr == nil && err == nil {
return nil
}

return err
if i != int(config.retryCount)-1 {
if httpErr != nil {
fmt.Fprintf(os.Stderr, "Error: %s (status code %d), retrying request...\n", httpErr.Error, httpErr.Code)
} else {
fmt.Fprintf(os.Stderr, "Error: %v, retrying request...\n", err)
}
}
}

return nil
if httpErr != nil {
return fmt.Errorf("%v", httpErr.Error)
}

return err
}

type postRequestOpts struct {
Expand Down
1 change: 1 addition & 0 deletions api/client/k8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ func (c *Client) GetRelease(
),
nil,
resp,
withRetryCount(3),
)

return resp, err
Expand Down
80 changes: 80 additions & 0 deletions api/client/porter_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"

"github.com/porter-dev/porter/api/server/handlers/porter_app"
"github.com/porter-dev/porter/internal/models"

"github.com/porter-dev/porter/api/types"
)
Expand Down Expand Up @@ -180,13 +181,15 @@ func (c *Client) ParseYAML(
func (c *Client) ValidatePorterApp(
ctx context.Context,
projectID, clusterID uint,
appName string,
base64AppProto string,
deploymentTarget string,
commitSHA string,
) (*porter_app.ValidatePorterAppResponse, error) {
resp := &porter_app.ValidatePorterAppResponse{}

req := &porter_app.ValidatePorterAppRequest{
AppName: appName,
Base64AppProto: base64AppProto,
DeploymentTargetId: deploymentTarget,
CommitSHA: commitSHA,
Expand All @@ -211,13 +214,15 @@ func (c *Client) ApplyPorterApp(
base64AppProto string,
deploymentTarget string,
appRevisionID string,
forceBuild bool,
) (*porter_app.ApplyPorterAppResponse, error) {
resp := &porter_app.ApplyPorterAppResponse{}

req := &porter_app.ApplyPorterAppRequest{
Base64AppProto: base64AppProto,
DeploymentTargetId: deploymentTarget,
AppRevisionID: appRevisionID,
ForceBuild: forceBuild,
}

err := c.postRequest(
Expand Down Expand Up @@ -383,3 +388,78 @@ func (c *Client) PredeployStatus(

return resp, err
}

// UpdateRevisionStatus updates the status of an app revision
func (c *Client) UpdateRevisionStatus(
ctx context.Context,
projectID uint, clusterID uint,
appName string, appRevisionId string,
status models.AppRevisionStatus,
) (*porter_app.UpdateAppRevisionStatusResponse, error) {
resp := &porter_app.UpdateAppRevisionStatusResponse{}

req := &porter_app.UpdateAppRevisionStatusRequest{
Status: status,
}

err := c.postRequest(
fmt.Sprintf(
"/projects/%d/clusters/%d/apps/%s/revisions/%s",
projectID, clusterID, appName, appRevisionId,
),
req,
resp,
)

return resp, err
}

// GetBuildEnv returns the build environment for a given app proto
func (c *Client) GetBuildEnv(
ctx context.Context,
projectID uint, clusterID uint,
appName string, appRevisionId string,
) (*porter_app.GetBuildEnvResponse, error) {
resp := &porter_app.GetBuildEnvResponse{}

err := c.getRequest(
fmt.Sprintf(
"/projects/%d/clusters/%d/apps/%s/revisions/%s/build-env",
projectID, clusterID, appName, appRevisionId,
),
nil,
resp,
)

return resp, err
}

// CreateOrUpdateAppEnvironment updates the app environment group and creates it if it doesn't exist
func (c *Client) CreateOrUpdateAppEnvironment(
ctx context.Context,
projectID uint, clusterID uint,
appName string,
deploymentTargetID string,
variables map[string]string,
secrets map[string]string,
) (*porter_app.UpdateAppEnvironmentResponse, error) {
resp := &porter_app.UpdateAppEnvironmentResponse{}

req := &porter_app.UpdateAppEnvironmentRequest{
DeploymentTargetID: deploymentTargetID,
Variables: variables,
Secrets: secrets,
HardUpdate: false,
}

err := c.postRequest(
fmt.Sprintf(
"/projects/%d/clusters/%d/apps/%s/update-environment",
projectID, clusterID, appName,
),
req,
resp,
)

return resp, err
}
16 changes: 11 additions & 5 deletions api/server/authz/policy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package authz

import (
"context"
"fmt"
"net/http"

"github.com/porter-dev/porter/api/server/authz/policy"
Expand All @@ -11,6 +10,7 @@ import (
"github.com/porter-dev/porter/api/server/shared/requestutils"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
)

type PolicyMiddleware struct {
Expand Down Expand Up @@ -39,11 +39,15 @@ type PolicyHandler struct {
}

func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx, span := telemetry.NewSpan(r.Context(), "serve-policy-handler")
defer span.End()

// get the full map of scopes to resource actions
reqScopes, reqErr := getRequestActionForEndpoint(r, h.endpointMeta)

if reqErr != nil {
apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, reqErr, true)
err := telemetry.Error(ctx, span, reqErr, "unable to get request action for endpoint")
apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest), true)
return
}

Expand All @@ -70,28 +74,30 @@ func (h *PolicyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
policyDocs, reqErr := h.loader.LoadPolicyDocuments(policyLoaderOpts)

if reqErr != nil {
apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, reqErr, true)
err := telemetry.Error(ctx, span, reqErr, "unable to load policy documents")
apierrors.HandleAPIError(h.config.Logger, h.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError), true)
return
}

// validate that the policy permits the action
hasAccess := policy.HasScopeAccess(policyDocs, reqScopes)

if !hasAccess {
err := telemetry.Error(ctx, span, nil, "insufficient permissions to perform action")
apierrors.HandleAPIError(
h.config.Logger,
h.config.Alerter,
w,
r,
apierrors.NewErrForbidden(fmt.Errorf("policy forbids action in project %d", policyLoaderOpts.ProjectID)),
apierrors.NewErrPassThroughToClient(err, http.StatusForbidden),
true,
)

return
}

// add the set of resource ids to the request context
ctx := NewRequestScopeCtx(r.Context(), reqScopes)
ctx = NewRequestScopeCtx(ctx, reqScopes)
r = r.Clone(ctx)
h.next.ServeHTTP(w, r)
}
Expand Down
4 changes: 2 additions & 2 deletions api/server/authz/policy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TestPolicyMiddlewareInvalidPermissions(t *testing.T) {
handler.ServeHTTP(rr, req)

assert.False(t, next.WasCalled, "next handler should not have been called")
apitest.AssertResponseForbidden(t, rr)
apitest.AssertForbiddenError(t, rr)
}

func TestPolicyMiddlewareFailInvalidLoader(t *testing.T) {
Expand Down Expand Up @@ -296,5 +296,5 @@ func assertInternalError(t *testing.T, next *testHandler, rr *httptest.ResponseR
// first assert that that the next middleware was not called
assert.False(next.WasCalled, "next handler should not have been called")

apitest.AssertResponseInternalServerError(t, rr)
apitest.AssertInternalServerError(t, rr)
}
2 changes: 1 addition & 1 deletion api/server/authz/preview_environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (p *PreviewEnvironmentScopedMiddleware) ServeHTTP(w http.ResponseWriter, r
project, _ := r.Context().Value(types.ProjectScope).(*models.Project)
cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)

if !project.PreviewEnvsEnabled {
if !project.GetFeatureFlag(models.PreviewEnvsEnabled, p.config.LaunchDarklyClient) {
apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r,
apierrors.NewErrForbidden(errPreviewProjectDisabled), true)
return
Expand Down
16 changes: 10 additions & 6 deletions api/server/authz/release.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/porter-dev/porter/api/server/shared/requestutils"
"github.com/porter-dev/porter/api/types"
"github.com/porter-dev/porter/internal/models"
"github.com/porter-dev/porter/internal/telemetry"
"github.com/stefanmcshane/helm/pkg/release"
)

Expand All @@ -35,22 +36,25 @@ type ReleaseScopedMiddleware struct {
}

func (p *ReleaseScopedMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
cluster, _ := r.Context().Value(types.ClusterScope).(*models.Cluster)
ctx, span := telemetry.NewSpan(r.Context(), "middleware-release-scope")
defer span.End()

helmAgent, err := p.agentGetter.GetHelmAgent(r.Context(), r, cluster, "")
cluster, _ := ctx.Value(types.ClusterScope).(*models.Cluster)

helmAgent, err := p.agentGetter.GetHelmAgent(ctx, r, cluster, "")
if err != nil {
apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrInternal(err), true)
apierrors.HandleAPIError(p.config.Logger, p.config.Alerter, w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError), true)
return
}

// get the name of the application
reqScopes, _ := r.Context().Value(types.RequestScopeCtxKey).(map[types.PermissionScope]*types.RequestAction)
reqScopes, _ := ctx.Value(types.RequestScopeCtxKey).(map[types.PermissionScope]*types.RequestAction)
name := reqScopes[types.ReleaseScope].Resource.Name

// get the version for the application
version, _ := requestutils.GetURLParamUint(r, types.URLParamReleaseVersion)

release, err := helmAgent.GetRelease(context.Background(), name, int(version), false)
release, err := helmAgent.GetRelease(ctx, name, int(version), false)
if err != nil {
// ugly casing since at the time of this commit Helm doesn't have an errors package.
// so we rely on the Helm error containing "not found"
Expand All @@ -66,7 +70,7 @@ func (p *ReleaseScopedMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Reque
return
}

ctx := NewReleaseContext(r.Context(), release)
ctx = NewReleaseContext(ctx, release)
r = r.Clone(ctx)
p.next.ServeHTTP(w, r)
}
Expand Down
2 changes: 1 addition & 1 deletion api/server/handlers/api_token/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (p *APITokenCreateHandler) ServeHTTP(w http.ResponseWriter, r *http.Request
user, _ := r.Context().Value(types.UserScope).(*models.User)
proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)

if !proj.APITokensEnabled {
if !proj.GetFeatureFlag(models.APITokensEnabled, p.Config().LaunchDarklyClient) {
p.HandleAPIError(w, r, apierrors.NewErrForbidden(fmt.Errorf("api token endpoints are not enabled for this project")))
return
}
Expand Down
2 changes: 1 addition & 1 deletion api/server/handlers/api_token/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func NewAPITokenGetHandler(
func (p *APITokenGetHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)

if !proj.APITokensEnabled {
if !proj.GetFeatureFlag(models.APITokensEnabled, p.Config().LaunchDarklyClient) {
p.HandleAPIError(w, r, apierrors.NewErrForbidden(fmt.Errorf("api token endpoints are not enabled for this project")))
return
}
Expand Down
2 changes: 1 addition & 1 deletion api/server/handlers/api_token/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func NewAPITokenListHandler(
func (p *APITokenListHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
proj, _ := r.Context().Value(types.ProjectScope).(*models.Project)

if !proj.APITokensEnabled {
if !proj.GetFeatureFlag(models.APITokensEnabled, p.Config().LaunchDarklyClient) {
p.HandleAPIError(w, r, apierrors.NewErrForbidden(fmt.Errorf("api token endpoints are not enabled for this project")))
return
}
Expand Down
Loading

0 comments on commit 1f8486a

Please sign in to comment.