144 lines
4.6 KiB
Go
144 lines
4.6 KiB
Go
package controller
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/glebarez/sqlite"
|
|
"github.com/heicode/manager/common"
|
|
"github.com/heicode/manager/model"
|
|
"github.com/stretchr/testify/require"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
func TestNormalizeResourcePayloadAcceptsP1ResourceModel(t *testing.T) {
|
|
payload, err := normalizeResourcePayload(resourcePayload{
|
|
TenantId: " tenant-a ",
|
|
ProjectId: " project-a ",
|
|
Name: " repo ",
|
|
Type: model.ResourceTypeGit,
|
|
Target: "https://github.com/example/repo",
|
|
Metadata: map[string]any{
|
|
"repo_url": "https://github.com/example/repo",
|
|
"ref": "main",
|
|
},
|
|
Scopes: []string{" read ", "write", "read", ""},
|
|
Constraints: map[string]any{
|
|
"allowed_paths": []any{".", "docs"},
|
|
},
|
|
SecretRef: "vault://tenant-a/git/repo",
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, "tenant-a", payload.TenantId)
|
|
require.Equal(t, "project-a", payload.ProjectId)
|
|
require.Equal(t, "custom", payload.Provider)
|
|
require.Equal(t, "active", payload.Status)
|
|
require.Equal(t, []string{"read", "write"}, payload.Scopes)
|
|
}
|
|
|
|
func TestNormalizeResourcePayloadRejectsRawSecretMaterial(t *testing.T) {
|
|
_, err := normalizeResourcePayload(resourcePayload{
|
|
TenantId: "tenant-a",
|
|
ProjectId: "project-a",
|
|
Name: "cloud",
|
|
Type: model.ResourceTypeCloudAccount,
|
|
Target: "azure-subscription-1",
|
|
Metadata: map[string]any{
|
|
"access_token": "must-not-be-saved",
|
|
},
|
|
})
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "must not contain raw secret material")
|
|
}
|
|
|
|
func TestNormalizeResourceGrantPayloadRequiresAgnetRoleBinding(t *testing.T) {
|
|
payload, err := normalizeResourceGrantPayload(resourceGrantPayload{
|
|
TenantId: "tenant-a",
|
|
ProjectId: "project-a",
|
|
ResourceId: 42,
|
|
AgnetId: "builder-1",
|
|
Role: "developer",
|
|
Scopes: []string{"read", "read", "write"},
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
require.Equal(t, []string{"read", "write"}, payload.Scopes)
|
|
require.Equal(t, "active", payload.Status)
|
|
}
|
|
|
|
func TestResourceHandlersCreateResourceAndGrant(t *testing.T) {
|
|
originalDB := model.DB
|
|
db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{})
|
|
require.NoError(t, err)
|
|
require.NoError(t, db.AutoMigrate(&model.Resource{}, &model.ResourceGrant{}))
|
|
model.DB = db
|
|
t.Cleanup(func() { model.DB = originalDB })
|
|
|
|
resourceBody := []byte(`{
|
|
"tenant_id":"tenant-a",
|
|
"project_id":"project-a",
|
|
"name":"repo",
|
|
"type":"git",
|
|
"target":"https://github.com/example/repo",
|
|
"metadata":{"repo_url":"https://github.com/example/repo","ref":"main"},
|
|
"scopes":["read","write"],
|
|
"constraints":{"allowed_paths":["."]},
|
|
"secret_ref":"vault://tenant-a/git/repo"
|
|
}`)
|
|
resourceRecorder := callResourceHandler(t, http.MethodPost, "/api/resources/", resourceBody, CreateResource)
|
|
var resourceEnvelope struct {
|
|
Success bool `json:"success"`
|
|
Data struct {
|
|
Id int `json:"id"`
|
|
SecretRef string `json:"secret_ref"`
|
|
Scopes []string `json:"scopes"`
|
|
} `json:"data"`
|
|
}
|
|
require.NoError(t, common.Unmarshal(resourceRecorder.Body.Bytes(), &resourceEnvelope))
|
|
require.True(t, resourceEnvelope.Success)
|
|
require.NotZero(t, resourceEnvelope.Data.Id)
|
|
require.Equal(t, "vault://tenant-a/git/repo", resourceEnvelope.Data.SecretRef)
|
|
require.Equal(t, []string{"read", "write"}, resourceEnvelope.Data.Scopes)
|
|
|
|
grantBody := []byte(`{
|
|
"tenant_id":"tenant-a",
|
|
"project_id":"project-a",
|
|
"resource_id":` + strconv.Itoa(resourceEnvelope.Data.Id) + `,
|
|
"agnet_id":"builder-1",
|
|
"role":"developer",
|
|
"scopes":["read"]
|
|
}`)
|
|
grantRecorder := callResourceHandler(t, http.MethodPost, "/api/resource-grants/", grantBody, CreateResourceGrant)
|
|
var grantEnvelope struct {
|
|
Success bool `json:"success"`
|
|
Data struct {
|
|
ResourceId int `json:"resource_id"`
|
|
AgnetId string `json:"agnet_id"`
|
|
Role string `json:"role"`
|
|
} `json:"data"`
|
|
}
|
|
require.NoError(t, common.Unmarshal(grantRecorder.Body.Bytes(), &grantEnvelope))
|
|
require.True(t, grantEnvelope.Success)
|
|
require.Equal(t, resourceEnvelope.Data.Id, grantEnvelope.Data.ResourceId)
|
|
require.Equal(t, "builder-1", grantEnvelope.Data.AgnetId)
|
|
require.Equal(t, "developer", grantEnvelope.Data.Role)
|
|
}
|
|
|
|
func callResourceHandler(t *testing.T, method string, target string, body []byte, handler gin.HandlerFunc) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
recorder := httptest.NewRecorder()
|
|
ctx, _ := gin.CreateTestContext(recorder)
|
|
ctx.Request = httptest.NewRequest(method, target, bytes.NewReader(body))
|
|
ctx.Request.Header.Set("Content-Type", "application/json")
|
|
ctx.Set("id", 7)
|
|
handler(ctx)
|
|
return recorder
|
|
}
|