Skip to content

Commit 490214d

Browse files
authored
Merge pull request #477 from supabase/or/function_return_row_must_be_selectable
If a Function returns a table type, the table must be selectable
2 parents 08df171 + 7df8838 commit 490214d

File tree

3 files changed

+221
-1
lines changed

3 files changed

+221
-1
lines changed

src/graphql.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1284,10 +1284,20 @@ fn function_fields(schema: &Arc<__Schema>, volatilities: &[FunctionVolatility])
12841284
return None;
12851285
}
12861286
}
1287-
12881287
gql_args.extend(connection_args);
12891288
}
12901289

1290+
// If the return type is a table type, it must be selectable
1291+
if !match &return_type {
1292+
__Type::Node(table_type) => table_type.table.permissions.is_selectable,
1293+
__Type::Connection(table_type) => {
1294+
table_type.table.permissions.is_selectable
1295+
}
1296+
_ => true,
1297+
} {
1298+
return None;
1299+
}
1300+
12911301
Some(__Field {
12921302
name_: schema.graphql_function_field_name(func),
12931303
type_: __Type::FuncCallResponse(FuncCallResponseType {
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
begin;
2+
create table account(
3+
id serial primary key,
4+
email varchar(255) not null
5+
);
6+
create function returns_account()
7+
returns account language sql stable
8+
as $$ select id, email from account; $$;
9+
insert into account(email)
10+
values
11+
('aardvark@x.com');
12+
create role anon;
13+
grant usage on schema graphql to anon;
14+
grant select on account to anon;
15+
savepoint a;
16+
set local role anon;
17+
-- Should be visible
18+
select jsonb_pretty(
19+
graphql.resolve($$
20+
{
21+
__type(name: "Account") {
22+
__typename
23+
}
24+
}
25+
$$)
26+
);
27+
jsonb_pretty
28+
-------------------------------------
29+
{ +
30+
"data": { +
31+
"__type": { +
32+
"__typename": "Account"+
33+
} +
34+
} +
35+
}
36+
(1 row)
37+
38+
-- Should show an entrypoint on Query for returnAccount
39+
select jsonb_pretty(
40+
graphql.resolve($$
41+
query IntrospectionQuery {
42+
__schema {
43+
queryType {
44+
fields {
45+
name
46+
}
47+
}
48+
}
49+
}
50+
$$)
51+
);
52+
jsonb_pretty
53+
-----------------------------------------------------
54+
{ +
55+
"data": { +
56+
"__schema": { +
57+
"queryType": { +
58+
"fields": [ +
59+
{ +
60+
"name": "accountCollection"+
61+
}, +
62+
{ +
63+
"name": "node" +
64+
}, +
65+
{ +
66+
"name": "returnsAccount" +
67+
} +
68+
] +
69+
} +
70+
} +
71+
} +
72+
}
73+
(1 row)
74+
75+
rollback to a;
76+
revoke select on account from anon;
77+
set local role anon;
78+
-- We should no longer see "Account" types after revoking access
79+
select jsonb_pretty(
80+
graphql.resolve($$
81+
{
82+
__type(name: "Account") {
83+
__typename
84+
}
85+
}
86+
$$)
87+
);
88+
jsonb_pretty
89+
------------------------
90+
{ +
91+
"data": { +
92+
"__type": null+
93+
} +
94+
}
95+
(1 row)
96+
97+
-- We should no longer see returnAccount since it references an unknown return type "Account"
98+
select jsonb_pretty(
99+
graphql.resolve($$
100+
query IntrospectionQuery {
101+
__schema {
102+
queryType {
103+
fields {
104+
name
105+
}
106+
}
107+
}
108+
}
109+
$$)
110+
);
111+
jsonb_pretty
112+
----------------------------------------
113+
{ +
114+
"data": { +
115+
"__schema": { +
116+
"queryType": { +
117+
"fields": [ +
118+
{ +
119+
"name": "node"+
120+
} +
121+
] +
122+
} +
123+
} +
124+
} +
125+
}
126+
(1 row)
127+
128+
rollback;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
begin;
2+
3+
create table account(
4+
id serial primary key,
5+
email varchar(255) not null
6+
);
7+
8+
create function returns_account()
9+
returns account language sql stable
10+
as $$ select id, email from account; $$;
11+
12+
insert into account(email)
13+
values
14+
('aardvark@x.com');
15+
16+
17+
create role anon;
18+
grant usage on schema graphql to anon;
19+
grant select on account to anon;
20+
21+
savepoint a;
22+
23+
set local role anon;
24+
25+
-- Should be visible
26+
select jsonb_pretty(
27+
graphql.resolve($$
28+
{
29+
__type(name: "Account") {
30+
__typename
31+
}
32+
}
33+
$$)
34+
);
35+
36+
-- Should show an entrypoint on Query for returnAccount
37+
select jsonb_pretty(
38+
graphql.resolve($$
39+
query IntrospectionQuery {
40+
__schema {
41+
queryType {
42+
fields {
43+
name
44+
}
45+
}
46+
}
47+
}
48+
$$)
49+
);
50+
51+
rollback to a;
52+
53+
revoke select on account from anon;
54+
set local role anon;
55+
56+
-- We should no longer see "Account" types after revoking access
57+
select jsonb_pretty(
58+
graphql.resolve($$
59+
{
60+
__type(name: "Account") {
61+
__typename
62+
}
63+
}
64+
$$)
65+
);
66+
67+
-- We should no longer see returnAccount since it references an unknown return type "Account"
68+
select jsonb_pretty(
69+
graphql.resolve($$
70+
query IntrospectionQuery {
71+
__schema {
72+
queryType {
73+
fields {
74+
name
75+
}
76+
}
77+
}
78+
}
79+
$$)
80+
);
81+
82+
rollback;

0 commit comments

Comments
 (0)