Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/macaron.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: macaron_security_analysis

on:
push:
pull_request:
workflow_dispatch:

permissions:
contents: read

jobs:
analyze:
runs-on: ubuntu-latest

steps:
- name: Check out python-select-ai repository code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

- name: Run Macaron GitHub Actions policy
uses: oracle/macaron@4ddb55e3c9ef2c77b548be55c557078c4476fd9c # v0.24.0
with:
repo_path: ./
policy_file: check-github-actions
policy_purl: "pkg:github.com/oracle/python-select-ai@.*"
reports_retention_days: 90
7 changes: 5 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
name: select_ai_py_tests
on: push

permissions:
contents: read

jobs:
test:
runs-on: ${{ matrix.os }}
Expand All @@ -12,10 +15,10 @@ jobs:

steps:
- name: Check out python-select-ai repository code
uses: actions/checkout@v5
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v6
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: ${{ matrix.python-version }}

Expand Down
4 changes: 1 addition & 3 deletions src/select_ai/credential.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ def _validate_credential(credential: Mapping[str, str]):
}
for k in credential.keys():
if k.lower() not in valid_keys:
raise ValueError(
f"Invalid value {k}: {credential[k]} for credential object"
)
raise ValueError(f"Invalid key {k} for credential object")


async def async_create_credential(credential: Mapping, replace: bool = False):
Expand Down
19 changes: 15 additions & 4 deletions src/select_ai/privilege.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
)


def _normalize_schema_user(user: str) -> str:
user = user.strip()
if len(user) >= 2 and user[0] == '"' and user[-1] == '"':
return user
return user.upper()


async def async_grant_privileges(users: Union[str, List[str]]):
"""
This method grants execute privilege on the packages DBMS_CLOUD,
Expand All @@ -26,7 +33,8 @@ async def async_grant_privileges(users: Union[str, List[str]]):

async with async_cursor() as cr:
for user in users:
await cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
cr_user = _normalize_schema_user(user)
await cr.execute(GRANT_PRIVILEGES_TO_USER, user=cr_user)


async def async_revoke_privileges(users: Union[str, List[str]]):
Expand All @@ -40,7 +48,8 @@ async def async_revoke_privileges(users: Union[str, List[str]]):

async with async_cursor() as cr:
for user in users:
await cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
cr_user = _normalize_schema_user(user)
await cr.execute(REVOKE_PRIVILEGES_FROM_USER, user=cr_user)


async def async_grant_http_access(
Expand Down Expand Up @@ -90,7 +99,8 @@ def grant_privileges(users: Union[str, List[str]]):
users = [users]
with cursor() as cr:
for user in users:
cr.execute(GRANT_PRIVILEGES_TO_USER.format(user.strip()))
cr_user = _normalize_schema_user(user)
cr.execute(GRANT_PRIVILEGES_TO_USER, user=cr_user)


def revoke_privileges(users: Union[str, List[str]]):
Expand All @@ -102,7 +112,8 @@ def revoke_privileges(users: Union[str, List[str]]):
users = [users]
with cursor() as cr:
for user in users:
cr.execute(REVOKE_PRIVILEGES_FROM_USER.format(user.strip()))
cr_user = _normalize_schema_user(user)
cr.execute(REVOKE_PRIVILEGES_FROM_USER, user=cr_user)


def grant_http_access(users: Union[str, List[str]], provider_endpoint: str):
Expand Down
14 changes: 12 additions & 2 deletions src/select_ai/sql.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@
DECLARE
TYPE array_t IS VARRAY(4) OF VARCHAR2(60);
v_packages array_t;
v_user VARCHAR2(261);
BEGIN
v_user := DBMS_ASSERT.ENQUOTE_NAME(
DBMS_ASSERT.SCHEMA_NAME(:user),
FALSE
);
v_packages := array_t(
'DBMS_CLOUD',
'DBMS_CLOUD_AI',
Expand All @@ -18,7 +23,7 @@
);
FOR i in 1..v_packages.count LOOP
EXECUTE IMMEDIATE
'GRANT EXECUTE ON ' || v_packages(i) || ' TO {0}';
'GRANT EXECUTE ON ' || v_packages(i) || ' TO ' || v_user;
END LOOP;
END;
"""
Expand All @@ -27,7 +32,12 @@
DECLARE
TYPE array_t IS VARRAY(4) OF VARCHAR2(60);
v_packages array_t;
v_user VARCHAR2(261);
BEGIN
v_user := DBMS_ASSERT.ENQUOTE_NAME(
DBMS_ASSERT.SCHEMA_NAME(:user),
FALSE
);
v_packages := array_t(
'DBMS_CLOUD',
'DBMS_CLOUD_AI',
Expand All @@ -36,7 +46,7 @@
);
FOR i in 1..v_packages.count LOOP
EXECUTE IMMEDIATE
'REVOKE EXECUTE ON ' || v_packages(i) || ' FROM {0}';
'REVOKE EXECUTE ON ' || v_packages(i) || ' FROM ' || v_user;
END LOOP;
END;
"""
Expand Down
8 changes: 8 additions & 0 deletions src/select_ai/synthetic_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,14 @@ class SyntheticDataAttributes(SelectAIDataClass):
user_prompt: Optional[str] = None

def __post_init__(self):
super().__post_init__()

if isinstance(self.params, str):
self.params = json.loads(self.params)

if isinstance(self.params, Mapping):
self.params = SyntheticDataParams(**self.params)

if self.params and not isinstance(self.params, SyntheticDataParams):
raise TypeError(
"'params' must be an object of" " type SyntheticDataParams'"
Expand Down
2 changes: 1 addition & 1 deletion src/select_ai/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
# http://oss.oracle.com/licenses/upl.
# -----------------------------------------------------------------------------

__version__ = "1.3.0"
__version__ = "1.3.1"
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _grant_basic_schema_privileges(cur, username: str):

def _grant_select_ai_privileges(cur, username: str):
try:
cur.execute(GRANT_PRIVILEGES_TO_USER.format(username.strip()))
cur.execute(GRANT_PRIVILEGES_TO_USER, user=username)
except Exception as exc:
msg = str(exc)
if (
Expand Down
12 changes: 12 additions & 0 deletions tests/gsd/test_2000_synthetic_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,3 +189,15 @@ def test_2008_generate_with_none_attributes(synthetic_profile):
ValueError, match="'synthetic_data_attributes' cannot be None"
):
synthetic_profile.generate_synthetic_data(None)


def test_2009_params_json_string_is_coerced():
"""JSON-string params are coerced into SyntheticDataParams"""
attributes = SyntheticDataAttributes(
object_name="people",
params='{"sample_rows": 1, "table_statistics": "true"}',
)

assert isinstance(attributes.params, SyntheticDataParams)
assert attributes.params.sample_rows == 1
assert attributes.params.table_statistics is True