Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions go/apps/api/routes/v2_keys_get_key/400_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,26 @@ func TestGetKeyBadRequest(t *testing.T) {
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

t.Run("empty keyId string", func(t *testing.T) {
req := handler.Request{
KeyId: "",
Decrypt: ptr.P(false),
}
req := handler.Request{
KeyId: "",
Decrypt: ptr.P(false),
}

t.Run("empty keyId string", func(t *testing.T) {
res := testutil.CallRoute[handler.Request, openapi.BadRequestErrorResponse](h, route, headers, req)
require.Equal(t, 400, res.Status)
require.NotNil(t, res.Body)
require.NotNil(t, res.Body.Error)
})

t.Run("invalid key format", func(t *testing.T) {
headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {"Bearer invalid_key_format_not_uid"},
}
res := testutil.CallRoute[handler.Request, openapi.UnauthorizedErrorResponse](h, route, headers, req)
require.Equal(t, 400, res.Status)
require.NotNil(t, res.Body)
require.NotNil(t, res.Body.Error)
})
}
49 changes: 48 additions & 1 deletion go/apps/api/routes/v2_keys_get_key/403_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
)

func TestGetKeyForbidden(t *testing.T) {

h := testutil.NewHarness(t)
ctx := context.Background()

Expand Down Expand Up @@ -199,4 +198,52 @@ func TestGetKeyForbidden(t *testing.T) {
require.Equal(t, 403, res.Status)
require.NotNil(t, res.Body)
})

t.Run("decrypt permission without read permission", func(t *testing.T) {
// Create root key with only decrypt permission, no read permission
rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "api.*.decrypt_key")

headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

// Try to get key
readReq := handler.Request{
KeyId: keyID,
Decrypt: ptr.P(false), // Even without decrypt, should fail on read permission
}

res := testutil.CallRoute[handler.Request, openapi.ForbiddenErrorResponse](h, route, headers, readReq)
require.Equal(t, 403, res.Status)
require.NotNil(t, res.Body)
})

t.Run("wrong resource type permissions", func(t *testing.T) {
// Create root key with permissions for different resource type
rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "workspace.*.read", "identity.*.read")

headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

res := testutil.CallRoute[handler.Request, openapi.ForbiddenErrorResponse](h, route, headers, req)
require.Equal(t, 403, res.Status)
require.NotNil(t, res.Body)
})

t.Run("specific API permission but wrong action", func(t *testing.T) {
// Create root key with permission for correct API but wrong action
rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, fmt.Sprintf("api.%s.delete_key", apiID))

headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

res := testutil.CallRoute[handler.Request, openapi.ForbiddenErrorResponse](h, route, headers, req)
require.Equal(t, 403, res.Status)
require.NotNil(t, res.Body)
})
}
28 changes: 28 additions & 0 deletions go/apps/api/routes/v2_keys_get_key/404_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
handler "github.com/unkeyed/unkey/go/apps/api/routes/v2_keys_get_key"
"github.com/unkeyed/unkey/go/pkg/ptr"
"github.com/unkeyed/unkey/go/pkg/testutil"
"github.com/unkeyed/unkey/go/pkg/testutil/seed"
"github.com/unkeyed/unkey/go/pkg/uid"
)

Expand Down Expand Up @@ -46,4 +47,31 @@ func TestGetKeyNotFound(t *testing.T) {
require.Contains(t, res.Body.Error.Detail, "We could not find the requested key")
})

t.Run("key from different workspace", func(t *testing.T) {
// Create a different workspace
otherWorkspace := h.CreateWorkspace()

// Create API and key in the other workspace
apiName := "other-workspace-api"
otherAPI := h.CreateApi(seed.CreateApiRequest{
WorkspaceID: otherWorkspace.ID,
Name: &apiName,
})

otherKey := h.CreateKey(seed.CreateKeyRequest{
KeyAuthID: otherAPI.KeyAuthID.String,
WorkspaceID: otherWorkspace.ID,
})

// Try to access the key from different workspace using our root key
req := handler.Request{
KeyId: otherKey.KeyID,
Decrypt: ptr.P(false),
}

res := testutil.CallRoute[handler.Request, openapi.NotFoundErrorResponse](h, route, headers, req)
require.Equal(t, 404, res.Status)
require.NotNil(t, res.Body)
require.Contains(t, res.Body.Error.Detail, "specified key was not found")
})
}
92 changes: 92 additions & 0 deletions go/apps/api/routes/v2_keys_get_key/412_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,96 @@ func TestPreconditionError(t *testing.T) {
require.NotNil(t, res.Body)
require.NotNil(t, res.Body.Error)
})

t.Run("api not set up for key encryption", func(t *testing.T) {
h := testutil.NewHarness(t)

apiName := "test-api"
api := h.CreateApi(seed.CreateApiRequest{
WorkspaceID: h.Resources().UserWorkspace.ID,
Name: &apiName,
})

rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "api.*.read_key", "api.*.decrypt_key")

headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

key := h.CreateKey(seed.CreateKeyRequest{
KeyAuthID: api.KeyAuthID.String,
WorkspaceID: h.Resources().UserWorkspace.ID,
})

route := &handler.Handler{
Logger: h.Logger,
DB: h.DB,
Keys: h.Keys,
Auditlogs: h.Auditlogs,
Vault: h.Vault,
}
h.Register(route)

req := handler.Request{
Decrypt: ptr.P(true),
KeyId: key.KeyID,
}

res := testutil.CallRoute[handler.Request, openapi.PreconditionFailedErrorResponse](
h,
route,
headers,
req,
)
require.Equal(t, 412, res.Status)
require.NotNil(t, res.Body)
require.NotNil(t, res.Body.Error)
require.Contains(t, res.Body.Error.Detail, "does not support key encryption")
})

t.Run("vault missing when decrypt requested", func(t *testing.T) {
h := testutil.NewHarness(t)

// Create API using testutil helper
apiName := "test-api"
api := h.CreateApi(seed.CreateApiRequest{
WorkspaceID: h.Resources().UserWorkspace.ID,
Name: &apiName,
})

// Create a root key with appropriate permissions
rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "api.*.read_key", "api.*.decrypt_key")

// Set up request headers
headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

key := h.CreateKey(seed.CreateKeyRequest{
KeyAuthID: api.KeyAuthID.String,
WorkspaceID: h.Resources().UserWorkspace.ID,
})

// Create route with nil vault
routeNoVault := &handler.Handler{
Logger: h.Logger,
DB: h.DB,
Keys: h.Keys,
Auditlogs: h.Auditlogs,
Vault: nil, // No vault
}
h.Register(routeNoVault)

req := handler.Request{
KeyId: key.KeyID,
Decrypt: ptr.P(true),
}

res := testutil.CallRoute[handler.Request, openapi.PreconditionFailedErrorResponse](h, routeNoVault, headers, req)
require.Equal(t, 412, res.Status)
require.NotNil(t, res.Body)
require.Contains(t, res.Body.Error.Detail, "Vault hasn't been set up")
})
}
46 changes: 46 additions & 0 deletions go/apps/api/routes/v2_keys_get_key/500_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package handler_test

import (
"fmt"
"net/http"
"testing"

"github.com/stretchr/testify/require"
"github.com/unkeyed/unkey/go/apps/api/openapi"
handler "github.com/unkeyed/unkey/go/apps/api/routes/v2_keys_get_key"
"github.com/unkeyed/unkey/go/pkg/ptr"
"github.com/unkeyed/unkey/go/pkg/testutil"
"github.com/unkeyed/unkey/go/pkg/uid"
)

func TestInternalError(t *testing.T) {
h := testutil.NewHarness(t)
route := &handler.Handler{
Logger: h.Logger,
DB: h.DB,
Keys: h.Keys,
Auditlogs: h.Auditlogs,
Vault: h.Vault,
}
h.Register(route)
rootKey := h.CreateRootKey(h.Resources().UserWorkspace.ID, "api.*.read_key")
headers := http.Header{
"Content-Type": {"application/json"},
"Authorization": {fmt.Sprintf("Bearer %s", rootKey)},
}

t.Run("database connection closed during request", func(t *testing.T) {
// Close the database connections to simulate a database failure
err := h.DB.Close()
require.NoError(t, err)
req := handler.Request{
KeyId: uid.New(uid.KeyPrefix),
Decrypt: ptr.P(false),
}

res := testutil.CallRoute[handler.Request, openapi.InternalServerErrorResponse](h, route, headers, req)
require.Equal(t, 500, res.Status)
require.NotNil(t, res.Body)
require.Contains(t, res.Body.Error.Detail, "We could not load the requested key")
})
}
Loading