HH-437: harden production auth and tenant authorization (#84)

* HH-437 harden auth and account authorization

* HH-437 reject revoked platform access

---------

Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
Rogee
2026-08-21 19:13:10 +08:00
committed by GitHub
co-authored by rogee
parent 04c1654086
commit cf263d10b4
22 changed files with 442 additions and 90 deletions
@@ -93,10 +93,10 @@ func setupPlatformTokenTestE2E(t *testing.T) (*gin.Engine, *repository.Permissib
platformGroup.DELETE("/users/:id", platformUser.Destroy)
platformGroup.GET("/accounts", platformAccount.List)
platformGroup.GET("/accounts/:id", platformAccount.Show)
platformGroup.GET("/accounts/:account_id", platformAccount.Show)
platformGroup.POST("/accounts", platformAccount.Create)
platformGroup.PATCH("/accounts/:id", platformAccount.Update)
platformGroup.DELETE("/accounts/:id", platformAccount.Destroy)
platformGroup.PATCH("/accounts/:account_id", platformAccount.Update)
platformGroup.DELETE("/accounts/:account_id", platformAccount.Destroy)
platformGroup.GET("/agent_bots", platformAgentBot.List)
platformGroup.GET("/agent_bots/:id", platformAgentBot.Show)
@@ -105,11 +105,10 @@ func setupPlatformTokenTestE2E(t *testing.T) (*gin.Engine, *repository.Permissib
platformGroup.DELETE("/agent_bots/:id", platformAgentBot.Destroy)
platformGroup.POST("/agent_bots/:id/delete_avatar", platformAgentBot.DeleteAvatar)
// Gin wildcard constraint: nested routes under accounts/:id must reuse :id.
platformGroup.GET("/accounts/:id/account_users", platformAccountUser.Index)
platformGroup.POST("/accounts/:id/account_users", platformAccountUser.Create)
platformGroup.DELETE("/accounts/:id/account_users/destroy", platformAccountUser.Destroy)
platformGroup.DELETE("/accounts/:id/account_users/:user_id", platformAccountUser.Destroy)
platformGroup.GET("/accounts/:account_id/account_users", platformAccountUser.Index)
platformGroup.POST("/accounts/:account_id/account_users", platformAccountUser.Create)
platformGroup.DELETE("/accounts/:account_id/account_users/destroy", platformAccountUser.Destroy)
platformGroup.DELETE("/accounts/:account_id/account_users/:user_id", platformAccountUser.Destroy)
return engine, permissibleRepo, userRepo, accountRepo
}
@@ -334,6 +333,25 @@ func TestPlatformAccountE2E_Show(t *testing.T) {
assert.Equal(t, "Show Account", showData["name"])
}
func TestPlatformAccountE2E_Update(t *testing.T) {
engine, _, _, _ := setupPlatformTokenTestE2E(t)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/platform/api/v1/accounts", bytes.NewBufferString(`{"name":"Original Account"}`))
req.Header.Set("Content-Type", "application/json")
engine.ServeHTTP(w, req)
require.Equal(t, http.StatusCreated, w.Code)
accountID := parseID(t, unpackData(t, w.Body.Bytes()))
w = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodPatch, "/platform/api/v1/accounts/"+accountID, bytes.NewBufferString(`{"name":"Updated Account"}`))
req.Header.Set("Content-Type", "application/json")
engine.ServeHTTP(w, req)
require.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, "Updated Account", unpackData(t, w.Body.Bytes())["name"])
}
func TestPlatformAccountE2E_Destroy(t *testing.T) {
engine, _, _, _ := setupPlatformTokenTestE2E(t)
@@ -465,6 +483,27 @@ func TestPlatformAccountUserE2E_Create(t *testing.T) {
assert.Equal(t, "administrator", accountUser["role"])
}
func TestPlatformAccountUserE2E_CreateRejectsNonPermissibleUser(t *testing.T) {
engine, _, userRepo, _ := setupPlatformTokenTestE2E(t)
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodPost, "/platform/api/v1/accounts", bytes.NewBufferString(`{"name":"Permissible Account"}`))
req.Header.Set("Content-Type", "application/json")
engine.ServeHTTP(w, req)
require.Equal(t, http.StatusCreated, w.Code)
accountID := parseID(t, unpackData(t, w.Body.Bytes()))
user := &model.User{Name: "Non-permissible User", Email: "non-permissible@example.com", Provider: "email", Active: true}
require.NoError(t, userRepo.Create(t.Context(), user))
w = httptest.NewRecorder()
req = httptest.NewRequest(http.MethodPost, "/platform/api/v1/accounts/"+accountID+"/account_users", bytes.NewBufferString(fmt.Sprintf(`{"user_id":%d}`, user.ID)))
req.Header.Set("Content-Type", "application/json")
engine.ServeHTTP(w, req)
assert.Equal(t, http.StatusForbidden, w.Code)
}
func TestPlatformAccountUserE2E_Index(t *testing.T) {
engine, _, _, _ := setupPlatformTokenTestE2E(t)