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
46 changes: 21 additions & 25 deletions .github/workflows/quality-gates.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,37 +21,30 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Cache pip dependencies
uses: actions/cache@v3
- name: Install uv and dependencies
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements*.txt') }}
restore-keys: |
${{ runner.os }}-pip-

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pyright bandit safety pytest-cov
enable-cache: true
- name: Sync dependencies
run: uv sync --frozen

- name: Run Static Analysis (Pyright)
run: |
pyright --strict
uv run pyright

- name: Run Linting (Ruff)
run: |
ruff check --output-format=github
ruff format --check
uv run ruff check --output-format=github
uv run ruff format --check

- name: Run Security Scan (Bandit)
run: |
bandit -r argus -f json -o bandit-report.json || true
bandit -r argus
uv run bandit -r argus -f json -o bandit-report.json || true
uv run bandit -r argus

- name: Run Tests with Coverage
run: |
pytest --cov=argus --cov-report=xml --cov-report=html --cov-fail-under=80
uv run pytest --cov=argus --cov-report=xml --cov-report=html --cov-fail-under=80

- name: Upload Coverage to Codecov
uses: codecov/codecov-action@v3
Expand All @@ -62,13 +55,13 @@ jobs:

- name: Run Quality Gates
run: |
python -m argus.core.quality.cli run \
uv run python -m argus.core.quality.cli run \
--output=quality-report.json \
--format=json \
--fail-on-warning

- name: Upload Quality Report
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify unpinned action refs in this workflow
rg -n 'uses:\s*actions/upload-artifact@v4\b' .github/workflows/quality-gates.yml

# Optional: list all non-SHA action refs in the workflow
rg -n 'uses:\s*[^@]+@[^[:space:]]+$' .github/workflows/quality-gates.yml | rg -v '@[0-9a-fA-F]{40}$'

Repository: DsThakurRawat/Argus

Length of output: 464


Pin actions/upload-artifact to a full commit SHA.

Lines 64 and 136 use actions/upload-artifact@v4, which is mutable. Pin to a full commit SHA to prevent supply-chain drift.

🧰 Tools
🪛 zizmor (1.25.2)

[error] 64-64: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/quality-gates.yml at line 64, Replace the mutable ref
"uses: actions/upload-artifact@v4" with a pinned full commit SHA for the
upload-artifact action (e.g. "uses: actions/upload-artifact@<full-commit-sha>")
in every occurrence found in the workflow (the lines currently showing "uses:
actions/upload-artifact@v4"); ensure both occurrences are updated to the same
verified commit SHA to prevent supply-chain drift.

Source: Linters/SAST tools

if: always()
with:
name: quality-report
Expand Down Expand Up @@ -124,20 +117,23 @@ jobs:
python-version: '3.12'

- name: Install dependencies
uses: astral-sh/setup-uv@e58605a9b6da7c637471fab8847a5e5a6b8df081 # v5
with:
enable-cache: true
- name: Sync dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
pip install psutil
uv sync --frozen
uv pip install psutil
Comment on lines 124 to +126

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether psutil is already represented in project dependency sources
for f in $(fd -i 'pyproject.toml|uv.lock'); do
  echo "### $f"
  rg -n 'psutil|optional-dependencies|dependency-groups|dependencies' "$f" || true
done

Repository: DsThakurRawat/Argus

Length of output: 4870


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "uv pip install psutil|uv sync --frozen" .github/workflows/quality-gates.yml
sed -n '90,160p' .github/workflows/quality-gates.yml

Repository: DsThakurRawat/Argus

Length of output: 1651


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n "uv pip install psutil|uv sync --frozen" .github/workflows/quality-gates.yml
sed -n '90,160p' .github/workflows/quality-gates.yml

Repository: DsThakurRawat/Argus

Length of output: 1651


Remove uv pip install psutil from the frozen CI flow

In .github/workflows/quality-gates.yml (lines 124-126), the job runs:

uv sync --frozen
uv pip install psutil

psutil is already declared in pyproject.toml and present in uv.lock, so uv sync --frozen should install it deterministically; the extra uv pip install psutil is redundant and bypasses lockfile reproducibility. Remove the ad-hoc install step.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/quality-gates.yml around lines 124 - 126, Remove the
ad-hoc package install that bypasses the lockfile: in the workflow step where
the commands run "uv sync --frozen" and "uv pip install psutil", delete the "uv
pip install psutil" line so only "uv sync --frozen" remains; this ensures psutil
(already declared in pyproject.toml and uv.lock) is installed deterministically
from the lockfile.


- name: Run Performance Gates
run: |
python -m argus.core.quality.cli run \
uv run python -m argus.core.quality.cli run \
--gates=performance \
--output=performance-report.json \
--format=json

- name: Upload Performance Report
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: performance-report
path: performance-report.json
14 changes: 3 additions & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,26 @@
repos:
# Ruff for linting and formatting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.6
rev: v0.12.0
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]
- id: ruff-format

# Pyright for type checking
- repo: https://github.com/RobertCraigie/pyright-python
rev: v1.1.350
rev: v1.1.405
hooks:
- id: pyright
args: [--strict]

# Security scanning
- repo: https://github.com/PyCQA/bandit
rev: 1.7.5
rev: 1.8.0
hooks:
- id: bandit
args: [-r, argus, -f, json]
exclude: ^tests/

# Import sorting
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: [--profile, black, --line-length, 100]

# General hooks
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
Expand Down
3 changes: 0 additions & 3 deletions argus/agents/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
EnhancedTriageAgent,
)
from .response_models import AnalysisResult, CodeResponse, TextResponse
from .specialized.analysis_agent import EnhancedAnalysisAgent
from .specialized.code_agent import EnhancedCodeAgent
from .specialized.text_agent import EnhancedTextAgent

__all__ = [
# Base agents
Expand Down
13 changes: 3 additions & 10 deletions argus/agents/agent_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,7 @@
# ============================================================================


class StatusCode(str, Enum):
"""Standard status codes for agent responses."""

SUCCESS = "success"
ERROR = "error"
WARNING = "warning"
PENDING = "pending"
PARTIAL = "partial"


class SeverityLevel(str, Enum):
Expand Down Expand Up @@ -89,6 +82,7 @@ class ActionType(str, Enum):
# Base models; Response models; Supporting models; Factory functions; Registry and utilities
from .response_models import (
AGENT_RESPONSE_MODELS,
StatusCode,
AnalysisFinding,
AnalysisResult,
BaseAgentResponse,
Expand Down Expand Up @@ -120,7 +114,7 @@ class ActionType(str, Enum):
PersistentAgentData,
StateManager,
StateSnapshot,
StateTransition, # State enums; State models; State utilities
StateTransitionEnum, # State enums
WorkflowContext,
WorkflowState,
WorkflowStep,
Expand Down Expand Up @@ -235,9 +229,8 @@ def validate_agent_data(
# State models
"AgentState",
"WorkflowState",
"StateTransitionEnum",
"StateSnapshot",
"StateTransition",
"StateTransitionEnum",
Comment on lines 232 to +233

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The StateTransition class was renamed to StateTransitionEnum in argus/agents/state_models.py. Exporting StateTransition in __all__ will raise an ImportError at runtime.

Suggested change
"StateSnapshot",
"StateTransition",
"StateTransitionEnum",
"StateSnapshot",
"StateTransitionEnum",

"AgentExecutionContext",
"AgentExecutionMetrics",
"AgentExecutionState",
Expand Down
2 changes: 1 addition & 1 deletion argus/agents/enhanced_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def __init__(
if self.enable_enhancements:
self._init_enhanced_agent()

def _init_enhanced_agent(self) -> None:
def _init_enhanced_agent(self) -> Any:
legacy_class_name = self.legacy_agent.__class__.__name__
primary_model = getattr(self.legacy_agent, "primary_model", None)
fallback_model = getattr(self.legacy_agent, "fallback_model", None)
Expand Down
154 changes: 0 additions & 154 deletions argus/agents/enhanced_analysis_agent.py

This file was deleted.

6 changes: 3 additions & 3 deletions argus/agents/enhanced_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,12 +305,12 @@ async def _select_model(

# Create strategy context
strategy_context = StrategyContext(
task_type=self.model_type_preference,
task_type=self.model_type_preference.value if self.model_type_preference else "smart",
max_cost=self.max_cost,
min_performance=self.min_performance,
min_quality=self.min_quality,
business_hours_only=self.business_hours_only,
provider_preference=self.provider_preference,
provider_preference=[p.value for p in self.provider_preference] if self.provider_preference else None,
)

# Select model using strategy manager
Expand Down Expand Up @@ -460,7 +460,7 @@ def get_conversation_context(self) -> list[dict[str, Any]]:
"""Get the current conversation context."""
return self._conversation_context.copy()

def clear_conversation_context(self) -> None:
def clear_conversation_context(self) -> Any:
"""Clear the conversation context."""
self._conversation_context.clear()

Expand Down
Loading
Loading