Skip to content

Commit

Permalink
feat: create some routes with rpc naming (#332)
Browse files Browse the repository at this point in the history
* feat: create some routes with rpc naming

* fix(workflow.json): change HTTP method from POST to GET for "Get Key" step

* fix(workflow.json): change "params" to "json" for consistency and clarity

* chore(deploy-agent.yaml): add MySQL service for testing
feat(deploy-agent.yaml): add DATABASE_DSN environment variable for testing

* chore(workflow.json): update step name from "Verify Key" to "Verify key again after removal"
fix(workflow.json): update expected value of jsonpath "$.valid" to false

* chore(workflow.json): remove unnecessary step for verifying key again after removal

* chore(workflow.json): add newline at the end of the file
  • Loading branch information
chronark authored Oct 1, 2023
1 parent 059e80e commit 5eb0657
Show file tree
Hide file tree
Showing 15 changed files with 325 additions and 65 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/deploy-agent.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,20 @@ on:
concurrency: deploy

jobs:

test:
name: Test Agent
runs-on: ubuntu-latest
services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: yes
MYSQL_DATABASE: unkey
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3

steps:
- uses: actions/checkout@v3

Expand All @@ -28,6 +39,8 @@ jobs:
- name: Test
run: go test -p 4 -v -json -shuffle=on --race ./... | gotestfmt
working-directory: apps/agent
env:
DATABASE_DSN: root@tcp(localhost:3306)/unkey

build:
name: Build Agent
Expand Down
61 changes: 55 additions & 6 deletions apps/agent/e2e/workflow.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
{
"name": "Create Key",
"http": {
"url": "${{env.baseUrl}}/v1/keys",
"url": "${{env.baseUrl}}/v1/keys.createKey",
"method": "POST",
"headers": {
"Content-Type": "application/json",
Expand All @@ -38,10 +38,18 @@
"apiId": "${{env.apiId}}"
},
"check": {
"status": "/^20/",
"status": 200,
"jsonpath": {
"$.keyId": [{ "isString": true }],
"$.key": [{ "isString": true }]
"$.keyId": [
{
"isString": true
}
],
"$.key": [
{
"isString": true
}
]
}
},
"captures": {
Expand All @@ -57,7 +65,7 @@
{
"name": "Verify Key",
"http": {
"url": "${{env.baseUrl}}/v1/keys/verify",
"url": "${{env.baseUrl}}/v1/keys.verifyKey",
"method": "POST",
"headers": {
"Content-Type": "application/json"
Expand All @@ -66,7 +74,7 @@
"key": "${{captures.key}}"
},
"check": {
"status": "/^20/",
"status": 200,
"jsonpath": {
"$.valid": true
}
Expand All @@ -92,6 +100,47 @@
}
}
}
},
{
"name": "Get Key",
"http": {
"url": "${{env.baseUrl}}/v1/keys.findKey",
"method": "GET",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${{secrets.rootKey}}"
},
"params": {
"keyId": "${{captures.keyId}}"
},
"check": {
"status": 200,
"jsonpath": {
"$.id": [
{
"isString": true
}
]
}
}
}
},
{
"name": "Remove Key",
"http": {
"url": "${{env.baseUrl}}/v1/keys.removeKey",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer ${{secrets.rootKey}}"
},
"json": {
"keyId": "${{captures.keyId}}"
},
"check": {
"status": 200
}
}
}
]
}
Expand Down
11 changes: 2 additions & 9 deletions apps/agent/pkg/server/key_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,10 @@ import (
"github.com/gofiber/fiber/v2"
)

type DeleteKeyRequest struct {
KeyId string `json:"keyId" validate:"required"`
}

type DeleteKeyResponse struct {
}

func (s *Server) deleteKey(c *fiber.Ctx) error {
ctx, span := s.tracer.Start(c.UserContext(), "server.deleteKey")
defer span.End()
req := DeleteKeyRequest{}
req := RemoveKeyRequestV1{}
err := c.ParamsParser(&req)
if err != nil {
return errors.NewHttpError(c, errors.BAD_REQUEST, err.Error())
Expand Down Expand Up @@ -59,5 +52,5 @@ func (s *Server) deleteKey(c *fiber.Ctx) error {
},
})

return c.JSON(DeleteKeyResponse{})
return c.JSON(RemoveKeyResponseV1{})
}
24 changes: 12 additions & 12 deletions apps/agent/pkg/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,27 +206,27 @@ func New(config Config) *Server {
s.app.Post("/v1/internal.removeRootKey", s.deleteRootKey)

// workspaceService
s.app.Post("/v1/workspace.createWorkspace", s.v1CreateWorkspace)
s.app.Post("/v1/workspaces.createWorkspace", s.v1CreateWorkspace)

// apiService
s.app.Post("/v1/api.createApi", s.v1CreateApi)
s.app.Post("/v1/api.removeApi", s.v1RemoveApi)
s.app.Get("/v1/api.findApi", s.getApi)
s.app.Get("/v1/api.listKeys", s.listKeys)
s.app.Post("/v1/apis.createApi", s.v1CreateApi)
s.app.Post("/v1/apis.removeApi", s.v1RemoveApi)
s.app.Get("/v1/apis.findApi", s.getApi)
s.app.Get("/v1/apis.listKeys", s.listKeys)

// keyService
s.app.Post("/v1/key.createKey", s.createKey)
s.app.Post("/v1/key.verifyKey", s.verifyKey)
s.app.Post("/v1/key.removeKey", s.deleteKey)
s.app.Post("/v1/key.updateKey", s.updateKey)
s.app.Get("/v1/key.findKey", s.getKey)
s.app.Post("/v1/keys.createKey", s.v1CreateKey)
s.app.Post("/v1/keys.verifyKey", s.v1VerifyKey)
s.app.Post("/v1/keys.removeKey", s.v1RemoveKey)
s.app.Post("/v1/keys.updateKey", s.updateKey)
s.app.Get("/v1/keys.findKey", s.v1FindKey)

// legacy
s.app.Post("/v1/keys", s.createKey)
s.app.Post("/v1/keys", s.v1CreateKey)
s.app.Get("/v1/keys/:keyId", s.getKey)
s.app.Put("/v1/keys/:keyId", s.updateKey)
s.app.Delete("/v1/keys/:keyId", s.deleteKey)
s.app.Post("/v1/keys/verify", s.verifyKey)
s.app.Post("/v1/keys/verify", s.v1VerifyKey)

s.app.Get("/v1/apis/:apiId", s.getApi)
s.app.Get("/v1/apis/:apiId/keys", s.listKeys)
Expand Down
4 changes: 2 additions & 2 deletions apps/agent/pkg/server/v1_apis_create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func TestV1ApisCreate(t *testing.T) {
testutil.Json(t, srv.app, testutil.JsonRequest{
Debug: true,
Method: "POST",
Path: "/v1/api.createApi",
Path: "/v1/apis.createApi",
Bearer: resources.UserRootKey,
Body: `{ "name":"simple" }`,
Response: &res,
Expand Down Expand Up @@ -80,7 +80,7 @@ func TestV1ApisCreate_RejectsUnauthorized(t *testing.T) {
testutil.Json(t, srv.app, testutil.JsonRequest{
Debug: true,
Method: "POST",
Path: "/v1/api.createApi",
Path: "/v1/apis.createApi",
Bearer: resources.UserRootKey,
Body: `{ "name":"simple" }`,
Response: &res,
Expand Down
2 changes: 1 addition & 1 deletion apps/agent/pkg/server/v1_apis_remove_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func TestV1ApisRemove(t *testing.T) {
res := RemoveApiResponse{}
testutil.Json(t, srv.app, testutil.JsonRequest{
Method: "POST",
Path: "/v1/api.removeApi",
Path: "/v1/apis.removeApi",
Bearer: resources.UserRootKey,
Body: fmt.Sprintf(`{
"apiId":"%s"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type CreateKeyResponse struct {
KeyId string `json:"keyId"`
}

func (s *Server) createKey(c *fiber.Ctx) error {
func (s *Server) v1CreateKey(c *fiber.Ctx) error {
ctx, span := s.tracer.Start(c.UserContext(), "server.createKey")
defer span.End()

Expand Down
File renamed without changes.
80 changes: 80 additions & 0 deletions apps/agent/pkg/server/v1_key_find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package server

import (
"fmt"

"github.com/gofiber/fiber/v2"
"github.com/unkeyed/unkey/apps/agent/pkg/cache"
"github.com/unkeyed/unkey/apps/agent/pkg/errors"
)

type GetKeyRequestV1 struct {
KeyId string `validate:"required"`
}

type GetKeyResponseV1 = keyResponse

func (s *Server) v1FindKey(c *fiber.Ctx) error {
ctx, span := s.tracer.Start(c.UserContext(), "server.v1FindKey")
defer span.End()
req := GetKeyRequest{
KeyId: c.Query("keyId"),
}

err := s.validator.Struct(req)
if err != nil {
return errors.NewHttpError(c, errors.BAD_REQUEST, err.Error())
}

authorizedWorkspaceId, err := s.authorizeRootKey(ctx, c)
if err != nil {
return errors.NewHttpError(c, errors.UNAUTHORIZED, err.Error())
}

key, found, err := cache.WithCache(s.keyCache, s.db.FindKeyById)(ctx, req.KeyId)
if err != nil {
return errors.NewHttpError(c, errors.INTERNAL_SERVER_ERROR, err.Error())
}
if !found {
return errors.NewHttpError(c, errors.NOT_FOUND, fmt.Sprintf("key %s not found", req.KeyId))
}
if key.WorkspaceId != authorizedWorkspaceId {
return errors.NewHttpError(c, errors.UNAUTHORIZED, "workspace access denied")
}
api, found, err := cache.WithCache(s.apiCache, s.db.FindApiByKeyAuthId)(ctx, key.KeyAuthId)
if err != nil {
return errors.NewHttpError(c, errors.INTERNAL_SERVER_ERROR, fmt.Sprintf("unable to find api: %s", err.Error()))
}
if !found {

return errors.NewHttpError(c, errors.NOT_FOUND, fmt.Sprintf("unable to find api: %s", err.Error()))
}

res := GetKeyResponse{
Id: key.Id,
ApiId: api.Id,
WorkspaceId: key.WorkspaceId,
Name: key.Name,
Start: key.Start,
OwnerId: key.OwnerId,
Meta: key.Meta,
CreatedAt: key.CreatedAt.UnixMilli(),
ForWorkspaceId: key.ForWorkspaceId,
}
if !key.Expires.IsZero() {
res.Expires = key.Expires.UnixMilli()
}
if key.Ratelimit != nil {
res.Ratelimit = &ratelimitSettng{
Type: key.Ratelimit.Type,
Limit: key.Ratelimit.Limit,
RefillRate: key.Ratelimit.RefillRate,
RefillInterval: key.Ratelimit.RefillInterval,
}
}
if key.Remaining != nil {
res.Remaining = key.Remaining
}

return c.JSON(res)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"io"
"net/http/httptest"
"strings"
"testing"
"time"

Expand All @@ -19,7 +20,7 @@ import (
"github.com/unkeyed/unkey/apps/agent/pkg/uid"
)

func KeyGetKey_Simple(t *testing.T) {
func TestKeyFindV1_Simple(t *testing.T) {
t.Parallel()
ctx := context.Background()
resources := testutil.SetupResources(t)
Expand Down Expand Up @@ -59,6 +60,11 @@ func KeyGetKey_Simple(t *testing.T) {
err = json.Unmarshal(body, &successResponse)
require.NoError(t, err)

require.Equal(t, key, successResponse)
require.Equal(t, key.Id, successResponse.Id)
require.Equal(t, resources.UserApi.Id, successResponse.ApiId)
require.Equal(t, key.WorkspaceId, successResponse.WorkspaceId)
require.Equal(t, key.Name, successResponse.Name)
require.True(t, strings.HasPrefix(key.Hash, successResponse.Start))
require.WithinDuration(t, key.CreatedAt, time.UnixMilli(successResponse.CreatedAt), time.Second)

}
Loading

1 comment on commit 5eb0657

@vercel
Copy link

@vercel vercel bot commented on 5eb0657 Oct 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

unkey – ./

unkey-unkey.vercel.app
unkey.vercel.app
unkey-git-main-unkey.vercel.app
unkey.dev
www.unkey.dev

Please sign in to comment.