package access_test import ( "testing" "atlas9.dev/c/core" "atlas9.dev/c/core/assert" "atlas9.dev/c/core/iam" "atlas9.dev/c/demo/lib/access" ) var ( capA = iam.NewCap("test_capA") capB = iam.NewCap("test_capB") ) func TestAccessCheck(t *testing.T) { tenantA := core.NewID("t") tenantB := core.NewID("t") t.Run("nil access denies", func(t *testing.T) { var a *access.Access assert.Eq(t, a.Check(capA, tenantA, ""), iam.ErrForbidden) }) t.Run("zero value denies", func(t *testing.T) { var a access.Access assert.Eq(t, a.Check(capA, tenantA, ""), iam.ErrForbidden) }) t.Run("admin allows anything", func(t *testing.T) { a := access.Admin() assert.Ok(t, a.Check(capA, tenantA, "")) assert.Ok(t, a.Check(capB, tenantB, "x.y")) // Admin is the only access that passes with an empty tenant. assert.Ok(t, a.Check(capA, core.ID{}, "")) }) t.Run("system grant", func(t *testing.T) { var a access.Access a.GrantSystem(capA) // A system grant covers every tenant, but only its own cap. assert.Ok(t, a.Check(capA, tenantA, "")) assert.Ok(t, a.Check(capA, tenantB, "x.y")) assert.Eq(t, a.Check(capB, tenantA, ""), iam.ErrForbidden) // An empty tenant is denied before grants are consulted: every // non-admin check must be scoped to a tenant, even system-granted. assert.Eq(t, a.Check(capA, core.ID{}, ""), iam.ErrForbidden) }) t.Run("tenant grant", func(t *testing.T) { var a access.Access a.Grant(capA, tenantA, "") // An empty grant path covers the whole tenant. assert.Ok(t, a.Check(capA, tenantA, "")) assert.Ok(t, a.Check(capA, tenantA, "x.y")) assert.Eq(t, a.Check(capA, tenantB, ""), iam.ErrForbidden) assert.Eq(t, a.Check(capB, tenantA, ""), iam.ErrForbidden) }) t.Run("grant path containment", func(t *testing.T) { var a access.Access a.Grant(capA, tenantA, "a.b") // A path grant covers itself and its descendants. assert.Ok(t, a.Check(capA, tenantA, "a.b")) assert.Ok(t, a.Check(capA, tenantA, "a.b.c")) // Not its parent or siblings. assert.Eq(t, a.Check(capA, tenantA, "a"), iam.ErrForbidden) assert.Eq(t, a.Check(capA, tenantA, "a.c"), iam.ErrForbidden) // "a.bc" shares a string prefix with "a.b" but is not inside it. assert.Eq(t, a.Check(capA, tenantA, "a.bc"), iam.ErrForbidden) // An empty request path means the whole tenant, which a // path-scoped grant does not cover. assert.Eq(t, a.Check(capA, tenantA, ""), iam.ErrForbidden) }) t.Run("matching grant not first", func(t *testing.T) { var a access.Access a.Grant(capB, tenantB, "") a.Grant(capA, tenantA, "") assert.Ok(t, a.Check(capA, tenantA, "")) }) } func TestAccessPartial(t *testing.T) { tenantA := core.NewID("t") t.Run("nil and zero deny", func(t *testing.T) { var nilAccess *access.Access assert.Eq(t, nilAccess.Partial(capA), iam.ErrForbidden) var a access.Access assert.Eq(t, a.Partial(capA), iam.ErrForbidden) }) t.Run("admin allows", func(t *testing.T) { a := access.Admin() assert.Ok(t, a.Partial(capA)) }) t.Run("any grant of the cap allows", func(t *testing.T) { // Partial ignores tenant and path scope entirely; it only asks // whether the cap is granted somewhere. var a access.Access a.Grant(capA, tenantA, "x.y") assert.Ok(t, a.Partial(capA)) var b access.Access b.GrantSystem(capA) assert.Ok(t, b.Partial(capA)) assert.Eq(t, a.Partial(capB), iam.ErrForbidden) }) } func TestAccessSystem(t *testing.T) { tenantA := core.NewID("t") t.Run("nil and zero deny", func(t *testing.T) { var nilAccess *access.Access assert.Eq(t, nilAccess.System(capA), iam.ErrForbidden) var a access.Access assert.Eq(t, a.System(capA), iam.ErrForbidden) }) t.Run("admin allows", func(t *testing.T) { a := access.Admin() assert.Ok(t, a.System(capA)) }) t.Run("system grant allows its cap only", func(t *testing.T) { var a access.Access a.GrantSystem(capA) assert.Ok(t, a.System(capA)) assert.Eq(t, a.System(capB), iam.ErrForbidden) }) t.Run("tenant grant never satisfies a system check", func(t *testing.T) { var a access.Access a.Grant(capA, tenantA, "") assert.Eq(t, a.System(capA), iam.ErrForbidden) }) } // TestAuthenticated pins the baseline grant given to any logged-in principal: // system-scoped Tenants.Create and nothing else. func TestAuthenticated(t *testing.T) { var a access.Access a.Authenticated() assert.Ok(t, a.System(iam.CapTenantsCreate)) assert.Ok(t, a.Check(iam.CapTenantsCreate, core.NewID("t"), "")) assert.Eq(t, a.System(capA), iam.ErrForbidden) assert.Eq(t, a.Partial(capA), iam.ErrForbidden) } func TestContext(t *testing.T) { tenant := core.NewID("t") t.Run("Get on bare context returns nil", func(t *testing.T) { a := access.Get(t.Context()) assert.Eq(t, a == nil, true) assert.Eq(t, a.Check(capA, tenant, ""), iam.ErrForbidden) }) t.Run("Put and Get round trip", func(t *testing.T) { var a access.Access a.GrantSystem(capA) ctx := access.Put(t.Context(), a) assert.Ok(t, access.Get(ctx).Check(capA, tenant, "")) }) t.Run("Put stores a copy", func(t *testing.T) { var a access.Access ctx := access.Put(t.Context(), a) // Mutating the caller's value after Put must not grant // anything to the context. a.GrantSystem(capA) assert.Eq(t, access.Get(ctx).System(capA), iam.ErrForbidden) }) } func TestContextGuard(t *testing.T) { tenant := core.NewID("t") guard := access.ContextGuard{} t.Run("denies without access in context", func(t *testing.T) { ctx := t.Context() assert.Eq(t, guard.Check(ctx, capA, tenant, ""), iam.ErrForbidden) assert.Eq(t, guard.Partial(ctx, capA), iam.ErrForbidden) assert.Eq(t, guard.System(ctx, capA), iam.ErrForbidden) }) t.Run("allows with granted access in context", func(t *testing.T) { var a access.Access a.GrantSystem(capA) ctx := access.Put(t.Context(), a) assert.Ok(t, guard.Check(ctx, capA, tenant, "")) assert.Ok(t, guard.Partial(ctx, capA)) assert.Ok(t, guard.System(ctx, capA)) }) }