AI coding assistants: Read this file first. For structured/machine-readable data, see
.ai/context.yaml.
argus is a unified security scanning framework by Huntridge Labs.
- What it does: Orchestrates 14 security scanners (SAST, secrets, containers, IaC, DAST) via the argus Python SDK or GitHub Actions composite actions
- Primary interface:
python -m argus scan --config argus.yml - Current version: 1.6.0
- License: AGPL-3.0
Python SDK and composite GitHub Actions that orchestrate 14+ security scanners with unified CLI, SARIF upload, and PR comments.
The argus Python SDK (python -m argus scan) is the primary interface. Composite actions remain available for GitHub Actions users.
argus/ # Python SDK (primary interface)
├── core/ # Models, config, engine
├── scanners/ # Scanner modules
├── reporters/ # Output reporters (terminal, markdown, sarif, json)
└── tests/ # SDK test suite
.github/
├── actions/ # Composite actions (GitHub Actions interface)
│ └── scanner-*/ # Each: action.yml, scripts/, tests/
├── workflows/ # CI/CD and test workflows
examples/workflows/ # User-facing workflow examples
tests/ # Test infrastructure
docs/ # Detailed documentation
| Category | Actions | Purpose |
|---|---|---|
| SAST | codeql, bandit, opengrep | Code security analysis |
| Secrets | gitleaks | Credential detection |
| Dependencies | osv, dependency-review | Vulnerability & license scanning |
| Container | trivy, grype, syft | Container scanning |
| IaC | trivy-iac, checkov | Infrastructure as Code |
| Malware | clamav | File malware detection |
| DAST | zap | Dynamic web app security |
| Compliance | scn-detector | FedRAMP change notifications |
SDK (recommended):
pip install pyyaml
python -m argus scan --config argus.ymlGitHub Actions (composite actions):
- uses: huntridge-labs/argus/.github/actions/scanner-gitleaks@1.6.0
with:
enable_code_security: true
fail_on_severity: high
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}# Clone and install
git clone <repo>
pip install -r requirements.txt
# Dev container (recommended)
# Open in VS Code → "Reopen in Container"
# Or manual setup
pip install -r .devcontainer/requirements.txt# Run all tests
pytest
# With coverage
pytest --cov
# Fast validation (no coverage)
pytest --no-cov -q
# Linting
npm run lint- Overall: 80%+
For simple actions (scanners with 2 scripts):
- Unit tests: Test parse/summary scripts with fixtures
- Integration: Run action in test workflow
For complex actions (multi-script with logic):
-
Level 1 - Unit Tests: Test individual Python functions
pytest .github/actions/my-action/tests/test_*.py -v -
Level 2 - Script Integration: Test scripts end-to-end with mock data
python scripts/classify.py --input mock-data.json --output results.json
-
Level 3 - Action Integration: Test full action with
actlocallyact pull_request -j test-job --secret GITHUB_TOKEN=$TOKEN -
Level 4 - Full Workflow: Test in real GitHub Actions environment
- Create test branch with real changes
- Open PR, verify action runs correctly
-
Level 5 - AI Fallback: Test external API integration (mock in CI)
@patch('requests.post') def test_ai_classification(mock_post): mock_post.return_value.json.return_value = {...}
-
Level 6 - Performance: Large inputs, stress testing
-
Level 7 - Edge Cases: Empty files, malformed configs, API failures
Test Organization:
tests/
├── fixtures/ # Mock data, sample configs
│ ├── api-responses/ # Mock AI/API responses
│ └── sample-data/ # Real-world examples
├── unit/ # Fast unit tests
└── integration/ # Slower integration tests
- SDK modules:
argus/scanners/{name}.py - Actions:
.github/actions/scanner-{name}/ - Tests: Co-located in
tests/subdirectory of each action or SDK module
Scanner Pattern (2-script, parse + summarize):
.github/actions/scanner-{name}/
├── action.yml # Inputs, outputs, steps
├── scripts/
│ ├── parse-results.py # Scanner output → JSON
│ └── generate-summary.py # JSON → Markdown summary
├── tests/
│ ├── test_parse_results.py
│ ├── test_generate_summary.py
│ └── conftest.py (optional)
└── README.md
Multi-Script Pattern (complex workflows with multiple stages):
.github/actions/{name}/
├── action.yml # Orchestrates multiple scripts
├── scripts/
│ ├── analyze.py # Data analysis/extraction
│ ├── classify.py # Classification/decision logic
│ ├── generate-report.py # Report generation
│ └── create-issue.py # GitHub integration (optional)
├── tests/
│ ├── test_analyze.py
│ ├── test_classify.py
│ ├── test_generate_report.py
│ ├── test_create_issue.py
│ └── conftest.py
└── README.md
# Example: scn-detector (FedRAMP compliance)
# - analyze_iac_changes.py: Extract IaC changes from git diff
# - classify_changes.py: Classify using rules + AI fallback
# - generate_scn_report.py: Create compliance reports
# - create_scn_issue.py: GitHub Issues with timelines
Follow Conventional Commits:
feat(scanner): add support for X
fix(trivy): handle empty results
docs: update scanner reference
test(bandit): add edge case pytest coverage
Hybrid Classification (Rules + AI Fallback) When building actions that need intelligent decision-making:
- Rule-based first: Fast, deterministic, cost-free
- AI fallback: For ambiguous cases that rules can't handle
- Confidence thresholds: If AI confidence < threshold, flag for manual review
- Mock AI in tests: Use fixtures for reliable testing
# Example from scn-detector
def classify_change(self, change: Dict) -> Dict:
# Try rule-based first
result = self.classify_with_rules(change)
if result:
return result
# Fallback to AI if enabled
if self.enable_ai:
return self.classify_with_ai(change)
# Flag for manual review
return {"category": "MANUAL_REVIEW"}Generic vs. Cloud-Specific Patterns For broader applicability across clouds/platforms:
- ✅ Generic attributes:
encryption,region,capacity,authentication - ❌ Cloud-specific:
aws_bedrock,azure_openai,google_vertex_ai
# Good: Works across AWS, Azure, GCP, custom platforms
transformative:
- pattern: "ai_service|ml_service|ml_model"
description: "AI/ML capabilities"
- attribute: "region|location|datacenter"
description: "Geographic changes"
# Bad: Only works for AWS
transformative:
- resource: "aws_bedrock.*"
description: "AWS Bedrock only"Rule Ordering & Priority When processing rules for classification:
- Within category: Check specific patterns before generic ones
- Across categories: Order categories by desired precedence
- First match wins: Stop processing after first successful match
# Example: Check transformative (specific) before routine (generic)
transformative:
- resource: "aws_bedrock.*" # Specific resource type
operation: "create"
routine:
- attribute: "description" # Generic attribute
# This would match almost anything, so check lastBusiness Day Calculations For compliance/audit timelines:
- Exclude weekends from calculations
- Use
datetime+timedelta+ weekend checks - Document timezone assumptions (usually UTC)
def calculate_business_days(start_date: datetime, num_days: int) -> datetime:
current = start_date
days_added = 0
while days_added < num_days:
current += timedelta(days=1)
if current.weekday() < 5: # Monday=0, Sunday=6
days_added += 1
return currentAI API Integration with Fallback When integrating external AI APIs (Anthropic, OpenAI, etc.):
-
Make it optional: AI should be fallback, not requirement
inputs: enable_ai_fallback: default: 'true' anthropic_api_key: required: false
-
Graceful degradation: Handle API failures
def classify(self, data): # Try rule-based first result = self.classify_with_rules(data) if result: return result # AI fallback if enabled and API key present if self.enable_ai and self.api_key: try: return self.classify_with_ai(data) except Exception as e: logger.warning(f"AI fallback failed: {e}") return {"category": "MANUAL_REVIEW"} return {"category": "MANUAL_REVIEW"}
-
Mock in tests: Never make real API calls in CI
@patch('anthropic.Anthropic') def test_ai_classification(self, mock_anthropic): mock_client = Mock() mock_client.messages.create.return_value = Mock( content=[Mock(text='{"category": "TRANSFORMATIVE"}')] ) mock_anthropic.return_value = mock_client result = classifier.classify_with_ai(change) assert result['category'] == 'TRANSFORMATIVE'
-
Use fixtures for API responses:
tests/fixtures/api-responses/ ├── classification-high-confidence.json ├── classification-low-confidence.json └── classification-error.json -
Document API costs: Claude Haiku ~$0.25/million input tokens
SDK approach (recommended):
# Create argus.yml
cat > argus.yml << 'EOF'
scanners:
- gitleaks
- bandit
- osv
scan_path: "."
severity_threshold: high
EOF
# Run scan
pip install pyyaml
python -m argus scan --config argus.ymlGitHub Actions approach (composite actions):
# .github/workflows/security.yml
name: Security Scan
on: [push, pull_request]
permissions:
contents: read
security-events: write
pull-requests: write
jobs:
sast:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: huntridge-labs/argus/.github/actions/scanner-gitleaks@1.6.0
with:
fail_on_severity: high
enable_code_security: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- uses: huntridge-labs/argus/.github/actions/scanner-bandit@1.6.0
with:
fail_on_severity: high
enable_code_security: truepython -m argus scan container --severity-threshold high- Create
.github/actions/scanner-{name}/action.yml - Add
scripts/parse-results.py(convert output → JSON) - Add
scripts/generate-summary.py(JSON → Markdown) - Add pytest tests in
tests/directory - Update
docs/scanners.md - Add to matrix in main orchestrator
PR Comments (Standard for most scanners):
- name: Post PR Comment
if: github.event_name == 'pull_request'
uses: huntridge-labs/argus/.github/actions/comment-pr@1.6.0
with:
comment_file: summary.mdGitHub Issues (For audit trails, compliance, tracking):
# Use PyGithub or direct API calls
from github import Github
g = Github(os.environ['GITHUB_TOKEN'])
repo = g.get_repo(os.environ['GITHUB_REPOSITORY'])
issue = repo.create_issue(
title=f"🔐 Compliance: {category} - {resource}",
body=issue_body,
labels=['compliance', f'scn:{category.lower()}']
)When to use Issues vs PR Comments:
- PR Comments: Immediate feedback, scanner results, validation
- Issues: Audit trail, compliance tracking, follow-up tasks, timelines
Required Permissions:
permissions:
pull-requests: write # For PR comments
issues: write # For Issue creation
security-events: write # For SARIF uploadCause: Missing permissions Fix: Add to workflow:
permissions:
security-events: write
pull-requests: writeCause: Invalid scanner name
Valid names: codeql, bandit, gitleaks, opengrep, trivy, grype, syft, checkov, trivy-iac, clamav, zap, osv, dependency-review
Cause: GitHub Advanced Security not enabled Fix: Settings → Security → Enable "GitHub Advanced Security"
Fix: Ensure enable_pr_comment: true and pull-requests: write permission
- Never commit registry credentials in config files
- Always use GitHub Secrets for sensitive values
- Pin to version tags (
@main), never@main - Enable SARIF upload when GitHub Advanced Security available
- Review scanner findings before suppressing
NEVER commit directly to main. Always use feature branches and create draft PRs for team review.
# Create feature branch
git checkout -b feat/my-feature
# Make changes and commit
git add .
git commit -m "feat(component): description"
# Push to origin
git push origin feat/my-feature
# Create draft PR for team review
gh pr create --draft --title "..." --body "..."
# Or use GitHub UI: Check "Create as draft"- All tests pass (
pytest) - No linting errors (
npm run lint) - Conventional commit messages used
- Documentation updated if needed
- Action README updated if action changed
- Feature branch (not main)
- Draft PR for team review
## Summary
Brief description of changes
## Type
- [ ] Bug fix
- [ ] New feature
- [ ] Documentation
- [ ] Test improvement
## Testing
How was this tested?
## Checklist
- [ ] Tests added/updated
- [ ] Docs updated
- [ ] CHANGELOG entry (if user-facing)| Decision | Reason |
|---|---|
| SDK as primary interface | Platform-independent, works locally and in CI |
| Composite actions for GitHub Actions | GHES doesn't support cross-repo workflow_call |
| SARIF as output format | GitHub Security tab integration, industry standard |
| Python for all scripts | Single language, one test framework (pytest), unified coverage |
| Co-located tests | Tests live next to code they test |
| Single version.yaml | Prevents version drift across 20+ files |
| Feature branches + draft PRs | Team review required, never commit to main |
| Hybrid classification (rules + AI) | Fast/deterministic rules, AI handles ambiguity |
| Generic patterns over cloud-specific | Broader applicability (AWS, Azure, GCP, custom) |
| GitHub Issues for compliance | Audit trail with 90-day artifact retention |
| Rule-based before AI | Cost-free, deterministic, testable |
This project uses AI Context as Code (AICaC) for token-efficient documentation.
Tools that support structured context should read files in .ai/ directory:
| File | Purpose |
|---|---|
.ai/context.yaml |
Project metadata, identity, glossary |
.ai/architecture.yaml |
Components, dependencies, data flow |
.ai/workflows.yaml |
Common tasks with exact commands |
.ai/decisions.yaml |
Architectural Decision Records (ADRs) |
.ai/errors.yaml |
Error patterns → solutions |
Additional reference files:
CLAUDE.md- Claude-specific extended context
- This file (AGENTS.md) - Quick orientation
.ai/context.yaml- Project overview.ai/architecture.yaml- How it's built.ai/workflows.yaml- How to do tasks.ai/errors.yaml- Troubleshooting.ai/decisions.yaml- Why decisions were madedocs/scanners.md- Scanner configuration detailsexamples/- Working code examples
- "How do I scan X?" → See Common Tasks section
- "What scanners exist?" → See Supported Scanners table
- "Why doesn't X work?" → See Error Resolution section
- "Which implementation?" → Composite actions (default), reusable workflows for backwards compat
After making changes to this project, you MUST update the relevant .ai/ files.
| When you change... | Update... |
|---|---|
| Components/structure | .ai/architecture.yaml |
| Commands/tasks | .ai/workflows.yaml |
| Make design decisions | .ai/decisions.yaml |
| Fix common errors | .ai/errors.yaml |
| Project metadata | .ai/context.yaml |
See the mapping table above for what to update and when.
Before completing any task, verify:
[ ] Relevant .ai/ files updated (or confirmed not needed)
| Need | Location |
|---|---|
| SDK entry point | python -m argus scan |
| SDK source | argus/ |
| SDK config | argus.yml |
| Composite actions | .github/actions/scanner-*/ |
| All scanners | docs/scanners.md |
| Examples | examples/workflows/ |
| Container config schema | .github/actions/parse-container-config/schemas/container-config.schema.json |
| Version | version.yaml |
| Changelog | CHANGELOG.md |