Monorepo for Tangled tangled.org
2

Configure Feed

Select the types of activity you want to include in your feed.

1package rbac_test 2 3import ( 4 "database/sql" 5 "testing" 6 7 "tangled.org/core/rbac" 8 9 adapter "github.com/Blank-Xu/sql-adapter" 10 "github.com/casbin/casbin/v2" 11 "github.com/casbin/casbin/v2/model" 12 _ "github.com/mattn/go-sqlite3" 13 "github.com/stretchr/testify/assert" 14) 15 16func setup(t *testing.T) *rbac.Enforcer { 17 db, err := sql.Open("sqlite3", ":memory:?_foreign_keys=1") 18 assert.NoError(t, err) 19 20 a, err := adapter.NewAdapter(db, "sqlite3", "acl") 21 assert.NoError(t, err) 22 23 m, err := model.NewModelFromString(rbac.Model) 24 assert.NoError(t, err) 25 26 e, err := casbin.NewSyncedEnforcer(m, a) 27 assert.NoError(t, err) 28 29 e.EnableAutoSave(false) 30 31 return &rbac.Enforcer{E: e} 32} 33 34func TestAddKnotAndRoles(t *testing.T) { 35 e := setup(t) 36 37 err := e.AddKnot("example.com") 38 assert.NoError(t, err) 39 40 err = e.AddKnotOwner("example.com", "did:plc:foo") 41 assert.NoError(t, err) 42 43 isOwner, err := e.IsKnotOwner("did:plc:foo", "example.com") 44 assert.NoError(t, err) 45 assert.True(t, isOwner) 46 47 isMember, err := e.IsKnotMember("did:plc:foo", "example.com") 48 assert.NoError(t, err) 49 assert.True(t, isMember) 50} 51 52func TestAddMember(t *testing.T) { 53 e := setup(t) 54 55 err := e.AddKnot("example.com") 56 assert.NoError(t, err) 57 58 err = e.AddKnotOwner("example.com", "did:plc:foo") 59 assert.NoError(t, err) 60 61 err = e.AddKnotMember("example.com", "did:plc:bar") 62 assert.NoError(t, err) 63 64 isMember, err := e.IsKnotMember("did:plc:foo", "example.com") 65 assert.NoError(t, err) 66 assert.True(t, isMember) 67 68 isMember, err = e.IsKnotMember("did:plc:bar", "example.com") 69 assert.NoError(t, err) 70 assert.True(t, isMember) 71 72 isOwner, err := e.IsKnotOwner("did:plc:foo", "example.com") 73 assert.NoError(t, err) 74 assert.True(t, isOwner) 75 76 // negated check here 77 isOwner, err = e.IsKnotOwner("did:plc:bar", "example.com") 78 assert.NoError(t, err) 79 assert.False(t, isOwner) 80} 81 82func TestAddRepoPermissions(t *testing.T) { 83 e := setup(t) 84 85 knot := "example.com" 86 87 fooUser := "did:plc:foo" 88 fooRepo := "did:plc:foo/my-repo" 89 90 barUser := "did:plc:bar" 91 barRepo := "did:plc:bar/my-repo" 92 93 _ = e.AddKnot(knot) 94 _ = e.AddKnotMember(knot, fooUser) 95 _ = e.AddKnotMember(knot, barUser) 96 97 err := e.AddRepo(fooUser, knot, fooRepo) 98 assert.NoError(t, err) 99 100 err = e.AddRepo(barUser, knot, barRepo) 101 assert.NoError(t, err) 102 103 canPush, err := e.IsPushAllowed(fooUser, knot, fooRepo) 104 assert.NoError(t, err) 105 assert.True(t, canPush) 106 107 canPush, err = e.IsPushAllowed(barUser, knot, barRepo) 108 assert.NoError(t, err) 109 assert.True(t, canPush) 110 111 // negated 112 canPush, err = e.IsPushAllowed(barUser, knot, fooRepo) 113 assert.NoError(t, err) 114 assert.False(t, canPush) 115 116 canDelete, err := e.E.Enforce(fooUser, knot, fooRepo, "repo:delete") 117 assert.NoError(t, err) 118 assert.True(t, canDelete) 119 120 // negated 121 canDelete, err = e.E.Enforce(barUser, knot, fooRepo, "repo:delete") 122 assert.NoError(t, err) 123 assert.False(t, canDelete) 124} 125 126func TestCollaboratorPermissions(t *testing.T) { 127 e := setup(t) 128 129 knot := "example.com" 130 repo := "did:plc:foo/my-repo" 131 owner := "did:plc:foo" 132 collaborator := "did:plc:bar" 133 134 _ = e.AddKnot(knot) 135 _ = e.AddRepo(owner, knot, repo) 136 137 err := e.AddCollaborator(collaborator, knot, repo) 138 assert.NoError(t, err) 139 140 // all collaborator permissions granted 141 perms := e.GetPermissionsInRepo(collaborator, knot, repo) 142 assert.ElementsMatch(t, []string{ 143 "repo:settings", "repo:push", "repo:collaborator", 144 }, perms) 145 146 err = e.RemoveCollaborator(collaborator, knot, repo) 147 assert.NoError(t, err) 148 149 // all permissions removed 150 perms = e.GetPermissionsInRepo(collaborator, knot, repo) 151 assert.ElementsMatch(t, []string{}, perms) 152} 153 154func TestGetCollaboratorsByRepo(t *testing.T) { 155 e := setup(t) 156 157 knot := "example.com" 158 repo := "did:plc:foo/my-repo" 159 otherRepo := "did:plc:foo/other-repo" 160 owner := "did:plc:foo" 161 collaborator1 := "did:plc:bar" 162 collaborator2 := "did:plc:baz" 163 164 _ = e.AddKnot(knot) 165 _ = e.AddRepo(owner, knot, repo) 166 _ = e.AddRepo(owner, knot, otherRepo) 167 168 err := e.AddCollaborator(collaborator1, knot, repo) 169 assert.NoError(t, err) 170 171 err = e.AddCollaborator(collaborator2, knot, repo) 172 assert.NoError(t, err) 173 174 byRepo, err := e.GetCollaboratorsByRepo(knot) 175 assert.NoError(t, err) 176 assert.ElementsMatch(t, []string{ 177 "did:plc:bar", // collaborator1 178 "did:plc:baz", // collaborator2 179 }, byRepo[repo]) 180 assert.NotContains(t, byRepo[repo], owner, "owner does not hold repo:collaborator and must not be listed") 181 assert.Empty(t, byRepo[otherRepo], "a repo without collaborators must not appear") 182} 183 184func TestGetPermissionsInRepo(t *testing.T) { 185 e := setup(t) 186 187 user := "did:plc:foo" 188 knot := "example.com" 189 repo := "did:plc:foo/my-repo" 190 191 _ = e.AddKnot(knot) 192 _ = e.AddRepo(user, knot, repo) 193 194 perms := e.GetPermissionsInRepo(user, knot, repo) 195 assert.ElementsMatch(t, []string{ 196 "repo:settings", "repo:push", "repo:owner", "repo:invite", "repo:delete", 197 }, perms) 198} 199 200func TestInvalidRepoFormat(t *testing.T) { 201 e := setup(t) 202 203 err := e.AddRepo("did:plc:foo", "example.com", "not-valid-format") 204 assert.Error(t, err) 205} 206 207func TestGetKnotssForUser(t *testing.T) { 208 e := setup(t) 209 _ = e.AddKnot("example.com") 210 _ = e.AddKnotOwner("example.com", "did:plc:foo") 211 _ = e.AddKnotMember("example.com", "did:plc:bar") 212 213 knots1, _ := e.GetKnotsForUser("did:plc:foo") 214 assert.Contains(t, knots1, "example.com") 215 216 knots2, _ := e.GetKnotsForUser("did:plc:bar") 217 assert.Contains(t, knots2, "example.com") 218} 219 220func TestGetKnotUsersByRole(t *testing.T) { 221 e := setup(t) 222 _ = e.AddKnot("example.com") 223 _ = e.AddKnotMember("example.com", "did:plc:foo") 224 _ = e.AddKnotOwner("example.com", "did:plc:bar") 225 226 members, _ := e.GetKnotUsersByRole("server:member", "example.com") 227 assert.Contains(t, members, "did:plc:foo") 228 assert.Contains(t, members, "did:plc:bar") // due to inheritance 229} 230 231func TestGetSpindleUsersByRole(t *testing.T) { 232 e := setup(t) 233 _ = e.AddSpindle("example.com") 234 _ = e.AddSpindleMember("example.com", "did:plc:foo") 235 _ = e.AddSpindleOwner("example.com", "did:plc:bar") 236 237 members, _ := e.GetSpindleUsersByRole("server:member", "example.com") 238 assert.Contains(t, members, "did:plc:foo") 239 assert.Contains(t, members, "did:plc:bar") // due to inheritance 240} 241 242func TestEmptyUserPermissions(t *testing.T) { 243 e := setup(t) 244 allowed, _ := e.IsPushAllowed("did:plc:nobody", "unknown.com", "did:plc:nobody/repo") 245 assert.False(t, allowed) 246} 247 248func TestDuplicatePolicyAddition(t *testing.T) { 249 e := setup(t) 250 _ = e.AddKnot("example.com") 251 _ = e.AddRepo("did:plc:foo", "example.com", "did:plc:foo/repo") 252 253 // add again 254 err := e.AddRepo("did:plc:foo", "example.com", "did:plc:foo/repo") 255 assert.NoError(t, err) // should not fail, but won't duplicate 256} 257 258func TestRemoveRepo(t *testing.T) { 259 e := setup(t) 260 repo := "did:plc:foo/repo" 261 _ = e.AddKnot("example.com") 262 _ = e.AddRepo("did:plc:foo", "example.com", repo) 263 264 allowed, _ := e.IsSettingsAllowed("did:plc:foo", "example.com", repo) 265 assert.True(t, allowed) 266 267 _ = e.RemoveRepo("did:plc:foo", "example.com", repo) 268 269 allowed, _ = e.IsSettingsAllowed("did:plc:foo", "example.com", repo) 270 assert.False(t, allowed) 271} 272 273func TestAddKnotAndSpindle(t *testing.T) { 274 e := setup(t) 275 276 err := e.AddKnot("k.com") 277 assert.NoError(t, err) 278 279 err = e.AddSpindle("s.com") 280 assert.NoError(t, err) 281 282 err = e.AddKnotOwner("k.com", "did:plc:foo") 283 assert.NoError(t, err) 284 285 err = e.AddSpindleOwner("s.com", "did:plc:foo") 286 assert.NoError(t, err) 287 288 knots, err := e.GetKnotsForUser("did:plc:foo") 289 assert.NoError(t, err) 290 assert.ElementsMatch(t, []string{ 291 "k.com", 292 }, knots) 293 294 spindles, err := e.GetSpindlesForUser("did:plc:foo") 295 assert.NoError(t, err) 296 assert.ElementsMatch(t, []string{ 297 "s.com", 298 }, spindles) 299} 300 301func TestAddSpindleAndRoles(t *testing.T) { 302 e := setup(t) 303 304 err := e.AddSpindle("s.com") 305 assert.NoError(t, err) 306 307 err = e.AddSpindleOwner("s.com", "did:plc:foo") 308 assert.NoError(t, err) 309 310 ok, err := e.IsSpindleOwner("did:plc:foo", "s.com") 311 assert.NoError(t, err) 312 assert.True(t, ok) 313 314 ok, err = e.IsSpindleMember("did:plc:foo", "s.com") 315 assert.NoError(t, err) 316 assert.True(t, ok) 317} 318 319func TestRemoveKnotOwner(t *testing.T) { 320 e := setup(t) 321 322 err := e.AddKnot("k.com") 323 assert.NoError(t, err) 324 325 err = e.AddKnotOwner("k.com", "did:plc:foo") 326 assert.NoError(t, err) 327 328 knots, err := e.GetKnotsForUser("did:plc:foo") 329 assert.NoError(t, err) 330 assert.ElementsMatch(t, []string{ 331 "k.com", 332 }, knots) 333 334 err = e.RemoveKnotOwner("k.com", "did:plc:foo") 335 assert.NoError(t, err) 336 337 knots, err = e.GetKnotsForUser("did:plc:foo") 338 assert.NoError(t, err) 339 assert.Empty(t, knots) 340} 341 342func TestRemoveKnotMember(t *testing.T) { 343 e := setup(t) 344 345 err := e.AddKnot("k.com") 346 assert.NoError(t, err) 347 348 err = e.AddKnotOwner("k.com", "did:plc:foo") 349 assert.NoError(t, err) 350 351 err = e.AddKnotMember("k.com", "did:plc:bar") 352 assert.NoError(t, err) 353 354 knots, err := e.GetKnotsForUser("did:plc:bar") 355 assert.NoError(t, err) 356 assert.ElementsMatch(t, []string{ 357 "k.com", 358 }, knots) 359 360 err = e.RemoveKnotMember("k.com", "did:plc:bar") 361 assert.NoError(t, err) 362 363 knots, err = e.GetKnotsForUser("did:plc:bar") 364 assert.NoError(t, err) 365 assert.Empty(t, knots) 366} 367 368func TestRemoveKnotRemovesRepoPolicies(t *testing.T) { 369 e := setup(t) 370 371 knot := "kelp.example" 372 owner := "did:plc:akshay" 373 collaborator := "did:plc:boltless" 374 repo := "did:plc:akshay/anemone" 375 376 assert.NoError(t, e.AddKnot(knot)) 377 assert.NoError(t, e.AddKnotOwner(knot, owner)) 378 assert.NoError(t, e.AddRepo(owner, knot, repo)) 379 assert.NoError(t, e.AddCollaborator(collaborator, knot, repo)) 380 381 isOwner, err := e.IsKnotOwner(owner, knot) 382 assert.NoError(t, err) 383 assert.True(t, isOwner) 384 385 err = e.RemoveKnot(knot) 386 assert.NoError(t, err) 387 388 isOwner, err = e.IsKnotOwner(owner, knot) 389 assert.NoError(t, err) 390 assert.False(t, isOwner) 391 392 assert.Empty(t, e.GetPermissionsInRepo(owner, knot, repo)) 393 assert.Empty(t, e.GetPermissionsInRepo(collaborator, knot, repo)) 394} 395 396func TestRemoveSpindleOwner(t *testing.T) { 397 e := setup(t) 398 399 err := e.AddSpindle("s.com") 400 assert.NoError(t, err) 401 402 err = e.AddSpindleOwner("s.com", "did:plc:foo") 403 assert.NoError(t, err) 404 405 spindles, err := e.GetSpindlesForUser("did:plc:foo") 406 assert.NoError(t, err) 407 assert.ElementsMatch(t, []string{ 408 "s.com", 409 }, spindles) 410 411 err = e.RemoveSpindleOwner("s.com", "did:plc:foo") 412 assert.NoError(t, err) 413 414 spindles, err = e.GetSpindlesForUser("did:plc:foo") 415 assert.NoError(t, err) 416 assert.Empty(t, spindles) 417} 418 419func TestRemoveSpindleMember(t *testing.T) { 420 e := setup(t) 421 422 err := e.AddSpindle("s.com") 423 assert.NoError(t, err) 424 425 err = e.AddSpindleOwner("s.com", "did:plc:foo") 426 assert.NoError(t, err) 427 428 err = e.AddSpindleMember("s.com", "did:plc:bar") 429 assert.NoError(t, err) 430 431 spindles, err := e.GetSpindlesForUser("did:plc:foo") 432 assert.NoError(t, err) 433 assert.ElementsMatch(t, []string{ 434 "s.com", 435 }, spindles) 436 437 spindles, err = e.GetSpindlesForUser("did:plc:bar") 438 assert.NoError(t, err) 439 assert.ElementsMatch(t, []string{ 440 "s.com", 441 }, spindles) 442 443 err = e.RemoveSpindleMember("s.com", "did:plc:bar") 444 assert.NoError(t, err) 445 446 spindles, err = e.GetSpindlesForUser("did:plc:bar") 447 assert.NoError(t, err) 448 assert.Empty(t, spindles) 449} 450 451func TestRemoveSpindle(t *testing.T) { 452 e := setup(t) 453 454 err := e.AddSpindle("s.com") 455 assert.NoError(t, err) 456 457 err = e.AddSpindleOwner("s.com", "did:plc:foo") 458 assert.NoError(t, err) 459 460 err = e.AddSpindleMember("s.com", "did:plc:bar") 461 assert.NoError(t, err) 462 463 users, err := e.GetSpindleUsersByRole("server:member", "s.com") 464 assert.NoError(t, err) 465 assert.ElementsMatch(t, []string{ 466 "did:plc:foo", 467 "did:plc:bar", 468 }, users) 469 470 err = e.RemoveSpindle("s.com") 471 assert.NoError(t, err) 472 473 // TODO: see this issue https://github.com/casbin/casbin/issues/1492 474 // s, err := e.E.GetAllDomains() 475 // assert.Empty(t, s) 476 477 spindles, err := e.GetSpindleUsersByRole("server:member", "s.com") 478 assert.NoError(t, err) 479 assert.Empty(t, spindles) 480} 481 482func TestWipeRepoPoliciesRemovesCollaborators(t *testing.T) { 483 e := setup(t) 484 485 knot := "example.com" 486 repo := "did:plc:akshay/my-repo" 487 owner := "did:plc:akshay" 488 collaborator := "did:plc:boltless" 489 490 _ = e.AddKnot(knot) 491 _ = e.AddRepo(owner, knot, repo) 492 err := e.AddCollaborator(collaborator, knot, repo) 493 assert.NoError(t, err) 494 495 err = e.WipeRepoPolicies(knot, repo) 496 assert.NoError(t, err) 497 498 assert.ElementsMatch(t, []string{}, e.GetPermissionsInRepo(collaborator, knot, repo), 499 "collaborator policies must be wiped on repo teardown") 500 assert.ElementsMatch(t, []string{}, e.GetPermissionsInRepo(owner, knot, repo), 501 "owner policies must be wiped on repo teardown") 502}