Skip to content

Commit

Permalink
chore: make env secrets permission-based
Browse files Browse the repository at this point in the history
  • Loading branch information
cevian authored and jgpruitt committed Oct 24, 2024
1 parent 6649c6f commit 3978bbe
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 7 deletions.
17 changes: 10 additions & 7 deletions projects/extension/ai/secrets.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from backoff._typing import Details

GUC_SECRETS_MANAGER_URL = "ai.external_functions_executor_url"
GUC_SECRET_ENV_ENABLED = "ai.secret_env_enabled"

DEFAULT_SECRETS_MANAGER_PATH = "/api/v1/projects/secrets"

Expand Down Expand Up @@ -54,9 +55,15 @@ def reveal_secret(plpy, secret_name: str) -> str | None:
if secret != "":
return secret

env_secret = os.environ.get(secret_name.upper())
if env_secret is not None:
return env_secret
if not check_secret_permissions(plpy, secret_name):
plpy.error(f"user does not have access to secret '{secret_name}'")
return None

# check the env var, unless disabled by guc
if get_guc_value(plpy, GUC_SECRET_ENV_ENABLED, "true") == "true":
env_secret = os.environ.get(secret_name.upper())
if env_secret is not None:
return env_secret

if secret_manager_enabled(plpy):
secret_optional = fetch_secret(plpy, secret_name)
Expand All @@ -75,10 +82,6 @@ def fetch_secret(plpy, secret_name: str) -> str | None:
plpy.error("secrets manager is not enabled")
return None

if not check_secret_permissions(plpy, secret_name):
plpy.error(f"user does not have access to secret '{secret_name}'")
return None

the_url = urljoin(
get_guc_value(plpy, GUC_SECRETS_MANAGER_URL, ""),
DEFAULT_SECRETS_MANAGER_PATH,
Expand Down
13 changes: 13 additions & 0 deletions projects/extension/tests/privileges/test_privileges.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,13 +115,23 @@ def test_secret_privileges():
with pytest.raises(Exception, match="permission denied for table"):
cur.execute("select * from ai._secret_permissions")

# jill cannot access the env var
with psycopg.connect(db_url("jill", "privs")) as con:
with con.cursor() as cur:
cur.execute(
"SET ai.external_functions_executor_url='http://localhost:8000'"
)
with pytest.raises(Exception, match="user does not have access"):
cur.execute("select ai.reveal_secret('TEST_ENV_SECRET')")

# alice can access all the secrets and grant them to fred and joey
with psycopg.connect(db_url("alice", "privs")) as con:
with con.cursor() as cur:
cur.execute(
"SET ai.external_functions_executor_url='http://localhost:8000'"
)
cur.execute("select ai.reveal_secret('OPENAI_API_KEY')")
cur.execute("select ai.reveal_secret('TEST_ENV_SECRET')")
cur.execute("select ai.grant_secret('OPENAI_API_KEY', 'joey')")
cur.execute("select ai.grant_secret('*', 'joey2')")
cur.execute("select ai.grant_secret('OPENAI_API_KEY', 'fred')")
Expand All @@ -142,6 +152,7 @@ def test_secret_privileges():
"SET ai.external_functions_executor_url='http://localhost:8000'"
)
cur.execute("select ai.grant_secret('OPENAI_API_KEY', 'jill')")
cur.execute("select ai.grant_secret('TEST_ENV_SECRET', 'jill')")

# jill can access the secret granted to her but not the other one
with psycopg.connect(db_url("jill", "privs")) as con:
Expand All @@ -150,6 +161,7 @@ def test_secret_privileges():
"SET ai.external_functions_executor_url='http://localhost:8000'"
)
cur.execute("select ai.reveal_secret('OPENAI_API_KEY')")
cur.execute("select ai.reveal_secret('TEST_ENV_SECRET')")
with pytest.raises(Exception, match="user does not have access"):
cur.execute("select ai.reveal_secret('OPENAI_API_KEY_2')")

Expand Down Expand Up @@ -195,6 +207,7 @@ def test_secret_privileges():
)
cur.execute("select ai.reveal_secret('OPENAI_API_KEY')")
cur.execute("select ai.reveal_secret('OPENAI_API_KEY_2')")
cur.execute("select ai.reveal_secret('TEST_ENV_SECRET')")

# alice can revoke the * privilege from jill
with psycopg.connect(db_url("alice", "privs")) as con:
Expand Down

0 comments on commit 3978bbe

Please sign in to comment.