Skip to content

Commit

Permalink
Merge pull request #2311 from posit-dev/dotnomad/get-secrets-api
Browse files Browse the repository at this point in the history
Add GET configuration secrets endpoint
  • Loading branch information
dotNomad authored Sep 25, 2024
2 parents 8f2f461 + 6f9bc1b commit 1db45a8
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 0 deletions.
4 changes: 4 additions & 0 deletions internal/services/api/api_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ func RouterHandlerFunc(base util.AbsolutePath, lister accounts.AccountList, log
r.Handle(ToPath("configurations", "{name}", "files"), PostConfigFilesHandlerFunc(base, log)).
Methods(http.MethodPost)

// GET /api/configurations/$NAME/secrets
r.Handle(ToPath("configurations", "{name}", "secrets"), GetConfigSecretsHandlerFunc(base, log)).
Methods(http.MethodGet)

// GET /api/configurations/$NAME/packages/python
r.Handle(ToPath("configurations", "{name}", "packages", "python"), NewGetConfigPythonPackagesHandler(base, log)).
Methods(http.MethodGet)
Expand Down
57 changes: 57 additions & 0 deletions internal/services/api/get_config_secrets.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package api

// Copyright (C) 2024 by Posit Software, PBC.

import (
"errors"
"io/fs"
"net/http"

"github.com/gorilla/mux"
"github.com/posit-dev/publisher/internal/config"
"github.com/posit-dev/publisher/internal/logging"
"github.com/posit-dev/publisher/internal/types"
"github.com/posit-dev/publisher/internal/util"
)

func GetConfigSecretsHandlerFunc(base util.AbsolutePath, log logging.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, req *http.Request) {
name := mux.Vars(req)["name"]

projectDir, _, err := ProjectDirFromRequest(base, w, req, log)
if err != nil {
// Response already returned by ProjectDirFromRequest
return
}

configPath := config.GetConfigPath(projectDir, name)
cfg, err := configFromFile(configPath)
if err != nil {
if aerr, ok := err.(*types.AgentError); ok {
if aerr.Code == types.ErrorUnknownTOMLKey {
apiErr := APIErrorUnknownTOMLKeyFromAgentError(*aerr)
apiErr.JSONResponse(w)
return
}

if aerr.Code == types.ErrorInvalidTOML {
apiErr := APIErrorInvalidTOMLFileFromAgentError(*aerr)
apiErr.JSONResponse(w)
return
}
}

if errors.Is(err, fs.ErrNotExist) {
http.NotFound(w, req)
} else {
InternalError(w, req, log, err)
}
return
}

response := make([]string, 0)
response = append(response, cfg.Secrets...)

JsonResult(w, http.StatusOK, response)
}
}
104 changes: 104 additions & 0 deletions internal/services/api/get_config_secrets_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package api

// Copyright (C) 2024 by Posit Software, PBC.

import (
"encoding/json"
"net/http"
"net/http/httptest"
"testing"

"github.com/gorilla/mux"
"github.com/posit-dev/publisher/internal/config"
"github.com/posit-dev/publisher/internal/logging"
"github.com/posit-dev/publisher/internal/util"
"github.com/posit-dev/publisher/internal/util/utiltest"
"github.com/spf13/afero"
"github.com/stretchr/testify/suite"
)

type GetConfigSecretsSuite struct {
utiltest.Suite
cwd util.AbsolutePath
log logging.Logger
h http.HandlerFunc
}

func TestGetConfigSecretsSuite(t *testing.T) {
suite.Run(t, new(GetConfigSecretsSuite))
}

func (s *GetConfigSecretsSuite) SetupSuite() {
s.log = logging.New()
}

func (s *GetConfigSecretsSuite) SetupTest() {
fs := afero.NewMemMapFs()
cwd, err := util.Getwd(fs)
s.Nil(err)
s.cwd = cwd
s.h = GetConfigSecretsHandlerFunc(s.cwd, s.log)
}

func (s *GetConfigSecretsSuite) TestGetConfigSecrets() {
cfg := config.New()
cfg.Type = config.ContentTypeHTML
cfg.Secrets = []string{
"secret1",
"secret2",
}
err := cfg.WriteFile(config.GetConfigPath(s.cwd, "myConfig"))
s.NoError(err)

rec := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/api/configurations/myConfig/secrets", nil)
s.NoError(err)
req = mux.SetURLVars(req, map[string]string{"name": "myConfig"})

s.h(rec, req)

s.Equal(http.StatusOK, rec.Result().StatusCode)
s.Equal("application/json", rec.Header().Get("content-type"))

res := []string{}
dec := json.NewDecoder(rec.Body)
dec.DisallowUnknownFields()
s.NoError(dec.Decode(&res))
s.NotNil(res)
s.Equal(cfg.Secrets, res)
}

func (s *GetConfigSecretsSuite) TestGetConfigSecretsEmptySecrets() {
cfg := config.New()
cfg.Type = config.ContentTypeHTML
err := cfg.WriteFile(config.GetConfigPath(s.cwd, "myConfig"))
s.NoError(err)

rec := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/api/configurations/myConfig/secrets", nil)
s.NoError(err)
req = mux.SetURLVars(req, map[string]string{"name": "myConfig"})

s.h(rec, req)

s.Equal(http.StatusOK, rec.Result().StatusCode)
s.Equal("application/json", rec.Header().Get("content-type"))

res := []string{}
dec := json.NewDecoder(rec.Body)
dec.DisallowUnknownFields()
s.NoError(dec.Decode(&res))
s.NotNil(res)
s.Equal([]string{}, res)
}

func (s *GetConfigSecretsSuite) TestGetConfigSecretsNotFound() {
rec := httptest.NewRecorder()
req, err := http.NewRequest("GET", "/api/configurations/myConfig/secrets", nil)
s.NoError(err)
req = mux.SetURLVars(req, map[string]string{"name": "myConfig"})

s.h(rec, req)

s.Equal(http.StatusNotFound, rec.Result().StatusCode)
}

0 comments on commit 1db45a8

Please sign in to comment.