fix(19.6.1-04): refuse code-declared role capture and wrap Administrators Runs
- Roles create and update refuse a submitted code that code-declared grants attach to - compileActionExtensions wraps contributed Administrators Runs with guardOutranked - Prove both holes on Postgres; keep the boot smoke callable with a superuser principal Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -261,6 +261,72 @@ func TestRolesCodeDeclaredLocks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestRolesCodeDeclaredCodeRefused (CR-01, SC-2, D-07, D-16): a role never
|
||||
// becomes a code-declared system role through the Roles screen. Create and
|
||||
// rename onto a code that pact.Permission.Roles attaches grants to answer
|
||||
// 422 code_locked, including when the editor is a superuser. A unique
|
||||
// non-declared code still creates and a same-code save of a system role
|
||||
// still succeeds.
|
||||
func TestRolesCodeDeclaredCodeRefused(t *testing.T) {
|
||||
declared := fmt.Sprintf("plugcap-%d", time.Now().UnixNano())
|
||||
env := newScreensEnv(t, grantPlugin{id: "acme.capturer", grants: []pact.Permission{{Code: "acme.capturer.secret", Roles: []string{declared}}}})
|
||||
editor := env.seedAdmin(t, adminSeed{Name: "codecap-editor", RolePermissions: map[string]int{cabana.PermissionManageRoles: 1}})
|
||||
editorToken := env.login(t, editor.Login)
|
||||
mutable := env.seedRole(t, roleSeed{Name: "codecap-mutable"})
|
||||
before := env.roleRow(t, mutable.ID)
|
||||
|
||||
env.expectFieldRefusal(t, http.StatusUnprocessableEntity, http.MethodPut, roleURL(mutable.ID), editorToken,
|
||||
roleBody(mutable, map[string]any{"code": declared}), "code", enCodeLocked, false)
|
||||
if env.roleRow(t, mutable.ID) != before {
|
||||
t.Fatal("a refused rename onto a code-declared code touched the role")
|
||||
}
|
||||
|
||||
env.expectFieldRefusal(t, http.StatusUnprocessableEntity, http.MethodPost, rolesPath, editorToken,
|
||||
map[string]any{"name": "Capture " + env.stamp, "code": declared}, "code", enCodeLocked, false)
|
||||
if env.roleCountByCode(t, declared) != 0 {
|
||||
t.Fatal("a refused create inserted a role with the code-declared code")
|
||||
}
|
||||
|
||||
super := env.seedAdmin(t, adminSeed{Name: "codecap-super", Superuser: true})
|
||||
superToken := env.login(t, super.Login)
|
||||
env.expectFieldRefusal(t, http.StatusUnprocessableEntity, http.MethodPut, roleURL(mutable.ID), superToken,
|
||||
roleBody(mutable, map[string]any{"code": declared}), "code", enCodeLocked, false)
|
||||
if env.roleRow(t, mutable.ID) != before {
|
||||
t.Fatal("a superuser rename onto a code-declared code touched the role")
|
||||
}
|
||||
env.expectFieldRefusal(t, http.StatusUnprocessableEntity, http.MethodPost, rolesPath, superToken,
|
||||
map[string]any{"name": "Super capture " + env.stamp, "code": declared}, "code", enCodeLocked, false)
|
||||
if env.roleCountByCode(t, declared) != 0 {
|
||||
t.Fatal("a superuser create inserted a role with the code-declared code")
|
||||
}
|
||||
|
||||
plain := "plain-" + env.stamp
|
||||
created := dataOf(env.expect(t, http.StatusCreated, http.MethodPost, rolesPath, editorToken,
|
||||
map[string]any{"name": "Plain " + env.stamp, "code": plain, "description": "Not declared"}))
|
||||
createdID := uint(created["id"].(float64))
|
||||
t.Cleanup(func() { env.gdb.Exec(`DELETE FROM backend_user_roles WHERE id = ?`, createdID) })
|
||||
|
||||
var developer cabana.BackendUserRole
|
||||
if err := env.gdb.Where("code = ?", "developer").First(&developer).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
env.expect(t, http.StatusOK, http.MethodPut, roleURL(developer.ID), superToken,
|
||||
roleBody(developer, map[string]any{"description": "Same code " + env.stamp}))
|
||||
t.Cleanup(func() {
|
||||
env.gdb.Exec(`UPDATE backend_user_roles SET description = ? WHERE id = ?`, developer.Description, developer.ID)
|
||||
})
|
||||
}
|
||||
|
||||
// roleCountByCode counts backend_user_roles rows with code.
|
||||
func (e *screensEnv) roleCountByCode(t *testing.T, code string) int64 {
|
||||
t.Helper()
|
||||
var n int64
|
||||
if err := e.gdb.Raw(`SELECT count(*) FROM backend_user_roles WHERE code = ?`, code).Scan(&n).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
// reloadRoleByCode reads the role with code.
|
||||
func (e *screensEnv) reloadRoleByCode(t *testing.T, code string) cabana.BackendUserRole {
|
||||
t.Helper()
|
||||
|
||||
Reference in New Issue
Block a user