security-advisor 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pkg/__init__.py ADDED
File without changes
pkg/sarif_report.py ADDED
@@ -0,0 +1,180 @@
1
+ from datetime import datetime, timezone
2
+ import json
3
+
4
+ # ---------------------------------------------------------------------------
5
+ # SARIF 2.1.0 builder
6
+ # ---------------------------------------------------------------------------
7
+
8
+ def _severity_to_sarif_level(severity: str) -> str:
9
+ """Map a tool-specific severity string to a SARIF notification level."""
10
+ mapping = {
11
+ "critical": "error",
12
+ "high": "error",
13
+ "medium": "warning",
14
+ "low": "note",
15
+ "info": "note",
16
+ }
17
+ return mapping.get(severity.lower(), "warning")
18
+
19
+
20
+ def _parse_sast_results(sast_json: dict) -> tuple[list, list]:
21
+ """Convert Semgrep JSON output to SARIF rules + results."""
22
+ rules, results = [], []
23
+ seen_rule_ids: set[str] = set()
24
+
25
+ for finding in sast_json.get("results", []):
26
+ rule_id = finding.get("check_id", "unknown-rule")
27
+ message = finding.get("extra", {}).get("message", "No message.")
28
+ severity = finding.get("extra", {}).get("severity", "warning")
29
+ file_path = finding.get("path", "")
30
+ start = finding.get("start", {})
31
+ end = finding.get("end", {})
32
+
33
+ if rule_id not in seen_rule_ids:
34
+ seen_rule_ids.add(rule_id)
35
+ rules.append({
36
+ "id": rule_id,
37
+ "name": rule_id,
38
+ "shortDescription": {"text": message[:200]},
39
+ "helpUri": finding.get("extra", {}).get("metadata", {}).get("references", [None])[0],
40
+ "properties": {"tags": ["SAST", "semgrep"]},
41
+ })
42
+
43
+ results.append({
44
+ "ruleId": rule_id,
45
+ "level": _severity_to_sarif_level(severity),
46
+ "message": {"text": message},
47
+ "locations": [{
48
+ "physicalLocation": {
49
+ "artifactLocation": {"uri": file_path, "uriBaseId": "%SRCROOT%"},
50
+ "region": {
51
+ "startLine": start.get("line", 1),
52
+ "startColumn": start.get("col", 1),
53
+ "endLine": end.get("line", start.get("line", 1)),
54
+ "endColumn": end.get("col", 1),
55
+ },
56
+ }
57
+ }],
58
+ })
59
+
60
+ return rules, results
61
+
62
+
63
+ def _parse_trivy_results(trivy_json: dict, scan_type: str) -> tuple[list, list]:
64
+ """Convert Trivy JSON output (vuln or config) to SARIF rules + results."""
65
+ rules, results = [], []
66
+ seen_rule_ids: set[str] = set()
67
+ tags = ["SCA", "trivy"] if scan_type == "sca" else ["IaC", "trivy"]
68
+
69
+ for target_block in trivy_json.get("Results", []):
70
+ target = target_block.get("Target", "")
71
+ findings = target_block.get("Vulnerabilities") or target_block.get("Misconfigurations") or []
72
+
73
+ for finding in findings:
74
+ # Vulnerabilities use VulnerabilityID; Misconfigurations use ID
75
+ rule_id = finding.get("VulnerabilityID") or finding.get("ID", "unknown")
76
+ title = finding.get("Title") or finding.get("Description", rule_id)
77
+ desc = finding.get("Description", title)
78
+ severity = finding.get("Severity", "UNKNOWN")
79
+ pkg_name = finding.get("PkgName", "")
80
+ fixed_ver = finding.get("FixedVersion", "")
81
+ refs = finding.get("References") or finding.get("References", [])
82
+
83
+ if rule_id not in seen_rule_ids:
84
+ seen_rule_ids.add(rule_id)
85
+ help_uri = refs[0] if refs else None
86
+ rules.append({
87
+ "id": rule_id,
88
+ "name": rule_id,
89
+ "shortDescription": {"text": title[:200]},
90
+ "fullDescription": {"text": desc[:1000]},
91
+ **({"helpUri": help_uri} if help_uri else {}),
92
+ "properties": {"tags": tags},
93
+ })
94
+
95
+ message_parts = [f"{title} in `{pkg_name or target}`."]
96
+ if fixed_ver:
97
+ message_parts.append(f"Fixed in version: {fixed_ver}.")
98
+
99
+ results.append({
100
+ "ruleId": rule_id,
101
+ "level": _severity_to_sarif_level(severity),
102
+ "message": {"text": " ".join(message_parts)},
103
+ "locations": [{
104
+ "physicalLocation": {
105
+ "artifactLocation": {"uri": target, "uriBaseId": "%SRCROOT%"},
106
+ }
107
+ }],
108
+ })
109
+
110
+ return rules, results
111
+
112
+
113
+ def build_sarif_report(sast_raw: str, sca_raw: str, iac_raw: str) -> dict:
114
+ """
115
+ Aggregate SAST, SCA, and IaC scan outputs into a single SARIF 2.1.0 document.
116
+ Returns the SARIF document as a Python dict.
117
+ """
118
+ sast_json = json.loads(sast_raw) if sast_raw.strip() else {}
119
+ sca_json = json.loads(sca_raw) if sca_raw.strip() else {}
120
+ iac_json = json.loads(iac_raw) if iac_raw.strip() else {}
121
+
122
+ sast_rules, sast_results = _parse_sast_results(sast_json)
123
+ sca_rules, sca_results = _parse_trivy_results(sca_json, "sca")
124
+ iac_rules, iac_results = _parse_trivy_results(iac_json, "iac")
125
+
126
+ sarif: dict = {
127
+ "$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
128
+ "version": "2.1.0",
129
+ "runs": [
130
+ # ── SAST run (Semgrep) ──────────────────────────────────────────
131
+ {
132
+ "tool": {
133
+ "driver": {
134
+ "name": "Semgrep",
135
+ "informationUri": "https://semgrep.dev",
136
+ "version": "latest",
137
+ "rules": sast_rules,
138
+ }
139
+ },
140
+ "results": sast_results,
141
+ "invocations": [{
142
+ "executionSuccessful": True,
143
+ "endTimeUtc": datetime.now(timezone.utc).isoformat(),
144
+ }],
145
+ },
146
+ # ── SCA run (Trivy – vulnerabilities) ──────────────────────────
147
+ {
148
+ "tool": {
149
+ "driver": {
150
+ "name": "Trivy",
151
+ "informationUri": "https://trivy.dev",
152
+ "version": "latest",
153
+ "rules": sca_rules,
154
+ }
155
+ },
156
+ "results": sca_results,
157
+ "invocations": [{
158
+ "executionSuccessful": True,
159
+ "endTimeUtc": datetime.now(timezone.utc).isoformat(),
160
+ }],
161
+ },
162
+ # ── IaC run (Trivy – misconfigurations) ────────────────────────
163
+ {
164
+ "tool": {
165
+ "driver": {
166
+ "name": "Trivy",
167
+ "informationUri": "https://trivy.dev",
168
+ "version": "latest",
169
+ "rules": iac_rules,
170
+ }
171
+ },
172
+ "results": iac_results,
173
+ "invocations": [{
174
+ "executionSuccessful": True,
175
+ "endTimeUtc": datetime.now(timezone.utc).isoformat(),
176
+ }],
177
+ },
178
+ ],
179
+ }
180
+ return sarif
@@ -0,0 +1,279 @@
1
+ Metadata-Version: 2.4
2
+ Name: security-advisor
3
+ Version: 0.1.0
4
+ Summary: Add your description here
5
+ Requires-Python: >=3.14
6
+ Description-Content-Type: text/markdown
7
+ License-File: LICENSE
8
+ Requires-Dist: fastmcp>=3.2.4
9
+ Requires-Dist: mcp>=1.27.1
10
+ Dynamic: license-file
11
+
12
+ # 🛡️ Security Advisor
13
+
14
+ An **MCP (Model Context Protocol) server** that orchestrates comprehensive security scans — SAST, SCA, and IaC — across any project and produces a unified **SARIF 2.1.0** report consumable by GitHub Advanced Security, VS Code, and other industry-standard tooling.
15
+
16
+ ---
17
+
18
+ ## Overview
19
+
20
+ Security Advisor exposes four MCP tools that an AI assistant (e.g., Claude, Gemini) can invoke to analyse a codebase:
21
+
22
+ | Tool | Description |
23
+ |---|---|
24
+ | `security_sast_skill` | Static Application Security Testing via **Semgrep** |
25
+ | `security_sca_skill` | Software Composition Analysis via **Trivy** (dependency vulnerabilities) |
26
+ | `security_iac_scan_skill` | Infrastructure-as-Code misconfiguration scan via **Trivy** (Terraform, K8s, Docker) |
27
+ | `security_advisor_skill` | **Master skill** — runs all three scans in parallel and exports a unified SARIF report |
28
+
29
+ ### How It Works
30
+
31
+ ```
32
+ AI Assistant
33
+
34
+ └─► security_advisor_skill(project_path)
35
+
36
+ ├─► security_sast_skill → Semgrep JSON
37
+ ├─► security_sca_skill → Trivy vuln JSON
38
+ └─► security_iac_scan_skill → Trivy config JSON
39
+
40
+
41
+ build_sarif_report() ← pkg/sarif_report.py
42
+
43
+
44
+ <project_path>/Security-Advisor-Report.sarif
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Prerequisites
50
+
51
+ Ensure the following are installed and available on your `PATH` before running Security Advisor.
52
+
53
+ ### System Tools
54
+
55
+ | Tool | Version | Install |
56
+ |---|---|---|
57
+ | **Python** | ≥ 3.14 | [python.org](https://www.python.org/downloads/) |
58
+ | **uv** | latest | `curl -LsSf https://astral.sh/uv/install.sh \| sh` |
59
+ | **Semgrep** | latest | `pip install semgrep` or `brew install semgrep` |
60
+ | **Trivy** | latest | `brew install trivy` or see [trivy.dev](https://trivy.dev/latest/getting-started/installation/) |
61
+
62
+ ### Verify Prerequisites
63
+
64
+ ```bash
65
+ python3 --version # Should be 3.14+
66
+ uv --version
67
+ semgrep --version
68
+ trivy --version
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Project Structure
74
+
75
+ ```
76
+ security-advisor/
77
+ ├── main.py # MCP server entry point — exposes all scan tools
78
+ ├── pkg/
79
+ │ ├── __init__.py
80
+ │ └── sarif_report.py # SARIF 2.1.0 builder (parses Semgrep + Trivy JSON)
81
+ ├── pyproject.toml # Project metadata and dependencies
82
+ ├── uv.lock # Locked dependency manifest
83
+ ├── .python-version # Pinned Python version (3.14)
84
+ └── README.md
85
+ ```
86
+
87
+ ---
88
+
89
+ ## Installation
90
+
91
+ ### 1. Clone the repository
92
+
93
+ ```bash
94
+ git clone <repository-url>
95
+ cd security-advisor
96
+ ```
97
+
98
+ ### 2. Create and activate a virtual environment with `uv`
99
+
100
+ ```bash
101
+ uv venv
102
+ source .venv/bin/activate # macOS / Linux
103
+ # .venv\Scripts\activate # Windows
104
+ ```
105
+
106
+ ### 3. Install dependencies
107
+
108
+ ```bash
109
+ uv pip install -e .
110
+ ```
111
+
112
+ This installs:
113
+ - [`fastmcp`](https://github.com/jlowin/fastmcp) ≥ 3.2.4 — high-level MCP server framework
114
+ - [`mcp`](https://github.com/modelcontextprotocol/python-sdk) ≥ 1.27.1 — Model Context Protocol Python SDK
115
+
116
+ ---
117
+
118
+ ## Development
119
+
120
+ ### Running the MCP Server Locally
121
+
122
+ ```bash
123
+ uv run main.py
124
+ ```
125
+
126
+ Or via the standard Python entrypoint:
127
+
128
+ ```bash
129
+ python main.py
130
+ ```
131
+
132
+ The server starts and listens for MCP tool calls over **stdio** (default FastMCP transport).
133
+
134
+ ### Running with `fastmcp` dev mode
135
+
136
+ ```bash
137
+ fastmcp dev main.py
138
+ ```
139
+
140
+ This launches an interactive MCP inspector at `http://localhost:6274` so you can test tools manually.
141
+
142
+ ---
143
+
144
+ ## MCP Client Configuration
145
+
146
+ To connect Security Advisor to an AI assistant, add it to your MCP client config.
147
+
148
+ ### Claude Desktop (`claude_desktop_config.json`)
149
+
150
+ ```json
151
+ {
152
+ "mcpServers": {
153
+ "security-advisor": {
154
+ "command": "uv",
155
+ "args": [
156
+ "--directory",
157
+ "/absolute/path/to/security-advisor",
158
+ "run",
159
+ "main.py"
160
+ ]
161
+ }
162
+ }
163
+ }
164
+ ```
165
+
166
+ ### Gemini / Antigravity (`.gemini/settings.json`)
167
+
168
+ ```json
169
+ {
170
+ "mcpServers": {
171
+ "security-advisor": {
172
+ "command": "uv",
173
+ "args": [
174
+ "--directory",
175
+ "/absolute/path/to/security-advisor",
176
+ "run",
177
+ "main.py"
178
+ ]
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ > **Tip:** Replace `/absolute/path/to/security-advisor` with the actual path on your machine.
185
+
186
+ ---
187
+
188
+ ## Usage
189
+
190
+ ### Via an AI Assistant
191
+
192
+ Once the MCP server is connected, instruct your assistant:
193
+
194
+ ```
195
+ Run a full security analysis on /path/to/my-project
196
+ ```
197
+
198
+ The assistant will invoke `security_advisor_skill`, which:
199
+ 1. Runs Semgrep SAST, Trivy SCA, and Trivy IaC scans **in parallel**
200
+ 2. Aggregates all findings into a SARIF 2.1.0 document
201
+ 3. Writes the report to `<project_path>/Security-Advisor-Report.sarif`
202
+ 4. Returns a human-readable summary
203
+
204
+ ### Individual Tools
205
+
206
+ You can also invoke individual scan tools:
207
+
208
+ ```
209
+ Run a SAST scan on /path/to/my-project
210
+ Run an SCA scan on /path/to/my-project
211
+ Run an IaC scan on /path/to/my-project
212
+ ```
213
+
214
+ ---
215
+
216
+ ## SARIF Report
217
+
218
+ The exported **`Security-Advisor-Report.sarif`** is a valid [SARIF 2.1.0](https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html) document containing three `runs`:
219
+
220
+ | Run | Tool | Findings |
221
+ |---|---|---|
222
+ | `runs[0]` | Semgrep | SAST code-level issues |
223
+ | `runs[1]` | Trivy | SCA dependency vulnerabilities |
224
+ | `runs[2]` | Trivy | IaC misconfigurations |
225
+
226
+ ### Severity Mapping
227
+
228
+ | Tool Severity | SARIF Level |
229
+ |---|---|
230
+ | `CRITICAL`, `HIGH` | `error` |
231
+ | `MEDIUM` | `warning` |
232
+ | `LOW`, `INFO` | `note` |
233
+
234
+ ### Viewing the Report
235
+
236
+ - **GitHub**: Upload to [Code Scanning](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github) via `gh` CLI or Actions
237
+ - **VS Code**: Install the [SARIF Viewer extension](https://marketplace.visualstudio.com/items?itemName=MS-SarifVSCode.sarif-viewer)
238
+ - **Any SARIF-compatible tool**: The file adheres to the official OASIS schema
239
+
240
+ ```bash
241
+ # Upload to GitHub Code Scanning
242
+ gh api \
243
+ --method POST \
244
+ /repos/{owner}/{repo}/code-scanning/sarifs \
245
+ --field commit_sha=$(git rev-parse HEAD) \
246
+ --field ref=$(git symbolic-ref HEAD) \
247
+ --field sarif=@Security-Advisor-Report.sarif
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Dependencies
253
+
254
+ | Package | Version | Purpose |
255
+ |---|---|---|
256
+ | `fastmcp` | ≥ 3.2.4 | MCP server framework |
257
+ | `mcp` | ≥ 1.27.1 | Model Context Protocol Python SDK |
258
+
259
+ External CLI tools (not Python packages):
260
+
261
+ | Tool | Purpose |
262
+ |---|---|
263
+ | `semgrep` | SAST scanning |
264
+ | `trivy` | SCA + IaC scanning |
265
+
266
+ ---
267
+
268
+ ## Contributing
269
+
270
+ 1. Fork the repository and create a feature branch
271
+ 2. Make your changes and ensure the server starts cleanly (`uv run main.py`)
272
+ 3. Test manually using `fastmcp dev main.py`
273
+ 4. Open a pull request with a clear description of the changes
274
+
275
+ ---
276
+
277
+ ## License
278
+
279
+ This project is licensed under the **MIT License**.
@@ -0,0 +1,7 @@
1
+ pkg/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ pkg/sarif_report.py,sha256=jeg4aonATV_alU4ACvi4QWBdmlrYsWv_2h2Q41nXHtI,7444
3
+ security_advisor-0.1.0.dist-info/licenses/LICENSE,sha256=BqSdBAFLSGpS17yvP58nw1oG--7fKcwjPWxy-gyPl-4,1071
4
+ security_advisor-0.1.0.dist-info/METADATA,sha256=XZ-H3kLAnpZP9u4to-aEIYQqODlErihm3F0ndafk9xE,7071
5
+ security_advisor-0.1.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
6
+ security_advisor-0.1.0.dist-info/top_level.txt,sha256=8jjfKuFvlaNGG7JiuNtS31gIuwOm8thUcUQoNbsxxls,4
7
+ security_advisor-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aditya Byreddy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ pkg