Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Lint
on:
push:
branches:
branches:
- "main"
pull_request:
branches:
Expand All @@ -19,8 +19,8 @@ jobs:
run: |
python -m pip install --upgrade pip
python -m pip install -r requirements-dev.txt
- name: Test with tox
- name: Lint with Ruff
run: |
tox run -e lint
ruff check
- name: Check uv.lock
run: make lock-check
run: make lock-check
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ lock-check:
done

lint:
uv run tox -e lint
uv tool run ruff check

test:
@set -e -o pipefail; \
Expand Down Expand Up @@ -88,7 +88,7 @@ publish:
done

format:
uv tool run --from 'tox==4.30.2' tox -e format
uv tool run ruff format

e2e-tests: build install
behave tests/e2e/features && cd ..
Expand Down
2 changes: 1 addition & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
pytest
pytest-asyncio
pytest-cov
tox
uv
ruff
37 changes: 37 additions & 0 deletions ruff.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Exclude a variety of commonly ignored directories plus some external
exclude = [
".pyenv",
".pytest_cache",
".pytype",
".ruff_cache",
".svn",
".tox",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need this now that we're moved away from tox?

".venv",
".vscode",
"__pypackages__",
"_build",
"build",
"dist",
"venv",
"src/dbtools-mcp-server",
"src/mysql-mcp-server",
"src/oci-pricing-mcp-server",
"src/oracle-db-doc-mcp-server",
"src/oci-database-mcp-server"
]

# Same as Black.
line-length = 110

[lint]
# Enable Pyflakes (`F`) and a subset of the pycodestyle (`E`) codes by default.
# Unlike Flake8, Ruff doesn't enable pycodestyle warnings (`W`) or
# McCabe complexity (`C901`) by default.
select = ["E701"]
ignore = []

# Allow fix for all enabled rules (when `--fix`) is provided.
fixable = ["ALL"]
unfixable = []

[format]
26 changes: 7 additions & 19 deletions scripts/oci-api-denylist-generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@


def get_oci_version():
result = subprocess.run(
["oci", "--version", "--raw-output"], capture_output=True, text=True
)
result = subprocess.run(["oci", "--version", "--raw-output"], capture_output=True, text=True)
return result.stdout.strip()


Expand All @@ -32,11 +30,9 @@ def get_services():

def get_sub_commands(command: str):
indentation_level = len(command.split())
print(f"{' '*indentation_level}Getting subcommands for: {command}")
print(f"{' ' * indentation_level}Getting subcommands for: {command}")
try:
result = subprocess.run(
f"oci {command} --help", shell=True, capture_output=True, text=True
)
result = subprocess.run(f"oci {command} --help", shell=True, capture_output=True, text=True)
output = result.stdout.splitlines()
sub_commands = []
in_commands_section = False
Expand All @@ -50,7 +46,7 @@ def get_sub_commands(command: str):
# match = re.match(r"^\s{2}(\w+)", line)
match = line.split()[0]
if match:
print(f"{' '*indentation_level}Appending sub command {match}")
print(f"{' ' * indentation_level}Appending sub command {match}")
sub_commands.append(match)
if not sub_commands:
return [command]
Expand Down Expand Up @@ -95,17 +91,11 @@ def create_denylist(version):
commands_file = f"commands_{version}.txt"

if os.path.exists(denylist_filename):
backup_filename = (
f"{denylist_filename}_backup_{datetime.now().strftime('%d%b%y_%H%M')}"
)
backup_filename = f"{denylist_filename}_backup_{datetime.now().strftime('%d%b%y_%H%M')}"
os.rename(denylist_filename, backup_filename)

with open(commands_file, "r") as f:
commands = [
line.strip()
for line in f
if not line.strip().startswith("#") and len(line.strip()) > 0
]
commands = [line.strip() for line in f if not line.strip().startswith("#") and len(line.strip()) > 0]

actions = [
"delete",
Expand All @@ -118,9 +108,7 @@ def create_denylist(version):
]

denied_commands = [
cmd.strip()
for cmd in commands
if any(cmd.split()[-1].startswith(action) for action in actions)
cmd.strip() for cmd in commands if any(cmd.split()[-1].startswith(action) for action in actions)
]

with open(denylist_filename, "w") as f:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ def remove_params_from_command(self, command: str) -> str:
i = 0
while i < len(command_parts):
if command_parts[i].startswith("--"):
i += (
1
if i + 1 >= len(command_parts)
or command_parts[i + 1].startswith("--")
else 2
)
i += 1 if i + 1 >= len(command_parts) or command_parts[i + 1].startswith("--") else 2
else:
filtered_parts.append(command_parts[i])
i += 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,10 +169,7 @@ def run_oci_command(
# Run OCI CLI command using subprocess
try:
result = subprocess.run(
["oci", "--profile"]
+ [profile]
+ ["--auth", "security_token"]
+ command.split(),
["oci", "--profile"] + [profile] + ["--auth", "security_token"] + command.split(),
env=env_copy,
capture_output=True,
text=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,11 @@ async def test_get_oci_command_help_success(self, mock_run):

async with Client(mcp) as client:
result = (
await client.call_tool(
"get_oci_command_help", {"command": "compute instance list"}
)
await client.call_tool("get_oci_command_help", {"command": "compute instance list"})
).structured_content["result"]

assert result == "Help output"
assert (
mock_run.call_args.kwargs["env"]["OCI_SDK_APPEND_USER_AGENT"]
== USER_AGENT
)
assert mock_run.call_args.kwargs["env"]["OCI_SDK_APPEND_USER_AGENT"] == USER_AGENT
mock_run.assert_called_once_with(
["oci", "compute", "instance", "list", "--help"],
env=ANY,
Expand All @@ -64,9 +59,7 @@ async def test_get_oci_command_help_failure(self, mock_run):

async with Client(mcp) as client:
result = (
await client.call_tool(
"get_oci_command_help", {"command": "compute instance list"}
)
await client.call_tool("get_oci_command_help", {"command": "compute instance list"})
).structured_content["result"]

assert "Error: Some error" in result
Expand All @@ -83,9 +76,7 @@ async def test_run_oci_command_success(self, mock_run):
mock_run.return_value = mock_result

async with Client(mcp) as client:
result = (
await client.call_tool("run_oci_command", {"command": command})
).data
result = (await client.call_tool("run_oci_command", {"command": command})).data

assert result == {
"command": command,
Expand All @@ -106,9 +97,7 @@ async def test_run_oci_command_string_success(self, mock_run):
mock_run.return_value = mock_result

async with Client(mcp) as client:
result = (
await client.call_tool("run_oci_command", {"command": command})
).data
result = (await client.call_tool("run_oci_command", {"command": command})).data

assert result == {
"command": command,
Expand All @@ -135,9 +124,7 @@ async def test_run_oci_command_failure(self, mock_run):
)

async with Client(mcp) as client:
result = (
await client.call_tool("run_oci_command", {"command": command})
).data
result = (await client.call_tool("run_oci_command", {"command": command})).data

assert result == {
"command": command,
Expand All @@ -158,10 +145,7 @@ async def test_get_oci_commands_success(self, mock_run):
result = (await client.read_resource("resource://oci-api-commands"))[0].text

assert result == "OCI commands output"
assert (
mock_run.call_args.kwargs["env"]["OCI_SDK_APPEND_USER_AGENT"]
== USER_AGENT
)
assert mock_run.call_args.kwargs["env"]["OCI_SDK_APPEND_USER_AGENT"] == USER_AGENT
mock_run.assert_called_once_with(
["oci", "--help"],
env=ANY,
Expand Down Expand Up @@ -200,9 +184,7 @@ async def test_run_oci_command_denied(self, mock_json_loads, mock_run):

async with Client(mcp) as client:
result = (
await client.call_tool(
"run_oci_command", {"command": "compute instance terminate"}
)
await client.call_tool("run_oci_command", {"command": "compute instance terminate"})
).data

assert "error" in result
Expand Down
8 changes: 2 additions & 6 deletions src/oci-api-mcp-server/oracle/oci_api_mcp_server/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,11 @@

def initAuditLogger(logger):
# Create a rotating file handler
handler = RotatingFileHandler(
"/tmp/audit.log", maxBytes=5 * 1024 * 1024, backupCount=1
)
handler = RotatingFileHandler("/tmp/audit.log", maxBytes=5 * 1024 * 1024, backupCount=1)
handler.setLevel(logging.INFO)

# Create a logging format
formatter = logging.Formatter(
"%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)

# Add the handler to the logger
Expand Down
Loading