ai-agentic-mcpscan 0.1.0__tar.gz
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.
- ai_agentic_mcpscan-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +32 -0
- ai_agentic_mcpscan-0.1.0/.github/ISSUE_TEMPLATE/config.yml +7 -0
- ai_agentic_mcpscan-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +22 -0
- ai_agentic_mcpscan-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +15 -0
- ai_agentic_mcpscan-0.1.0/.github/dependabot.yml +24 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/ci.yml +56 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/dependency-review.yml +27 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/pr-title.yml +38 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/release-please.yml +75 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/release.yml +52 -0
- ai_agentic_mcpscan-0.1.0/.github/workflows/sbom.yml +43 -0
- ai_agentic_mcpscan-0.1.0/.gitignore +31 -0
- ai_agentic_mcpscan-0.1.0/.gitmessage +27 -0
- ai_agentic_mcpscan-0.1.0/.release-please-manifest.json +3 -0
- ai_agentic_mcpscan-0.1.0/CHANGELOG.md +52 -0
- ai_agentic_mcpscan-0.1.0/CODEOWNERS +15 -0
- ai_agentic_mcpscan-0.1.0/CODE_OF_CONDUCT.md +80 -0
- ai_agentic_mcpscan-0.1.0/CONTRIBUTING.md +67 -0
- ai_agentic_mcpscan-0.1.0/LICENSE +201 -0
- ai_agentic_mcpscan-0.1.0/NOTICE +14 -0
- ai_agentic_mcpscan-0.1.0/PKG-INFO +142 -0
- ai_agentic_mcpscan-0.1.0/README.md +107 -0
- ai_agentic_mcpscan-0.1.0/SECURITY.md +47 -0
- ai_agentic_mcpscan-0.1.0/docs/.nojekyll +0 -0
- ai_agentic_mcpscan-0.1.0/docs/ARCHITECTURE.md +189 -0
- ai_agentic_mcpscan-0.1.0/docs/BACKLOG.md +170 -0
- ai_agentic_mcpscan-0.1.0/docs/BACKLOG_REVIEW.md +77 -0
- ai_agentic_mcpscan-0.1.0/docs/DECISIONS.md +120 -0
- ai_agentic_mcpscan-0.1.0/docs/DEVSECOPS.md +368 -0
- ai_agentic_mcpscan-0.1.0/docs/RELEASING.md +43 -0
- ai_agentic_mcpscan-0.1.0/docs/SECURITY_SIGNOFF.md +40 -0
- ai_agentic_mcpscan-0.1.0/docs/SPEC.md +296 -0
- ai_agentic_mcpscan-0.1.0/docs/STATUS.md +93 -0
- ai_agentic_mcpscan-0.1.0/docs/STATUS.yaml +228 -0
- ai_agentic_mcpscan-0.1.0/docs/index.html +188 -0
- ai_agentic_mcpscan-0.1.0/pyproject.toml +81 -0
- ai_agentic_mcpscan-0.1.0/release-please-config.json +15 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/__init__.py +17 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/adapters/__init__.py +7 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/adapters/base.py +55 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/adapters/claude.py +81 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/adapters/paths.py +71 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/checks/__init__.py +39 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/checks/exposure.py +39 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/checks/pinning.py +125 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/checks/secrets.py +140 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/checks/tool_scope.py +101 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/cli.py +134 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/discovery/__init__.py +3 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/discovery/probe.py +47 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/discovery/sockets.py +114 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/domain.py +119 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/engine.py +244 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/enrichment/__init__.py +9 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/enrichment/osv.py +77 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/io_safe.py +75 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/redaction.py +38 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/__init__.py +51 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/common.py +37 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/html.py +110 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/json_report.py +75 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/terminal.py +63 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/report/writer.py +33 -0
- ai_agentic_mcpscan-0.1.0/src/mcpscan/scoring.py +57 -0
- ai_agentic_mcpscan-0.1.0/tests/conftest.py +147 -0
- ai_agentic_mcpscan-0.1.0/tests/test_checks_other.py +102 -0
- ai_agentic_mcpscan-0.1.0/tests/test_checks_secrets.py +55 -0
- ai_agentic_mcpscan-0.1.0/tests/test_cli.py +90 -0
- ai_agentic_mcpscan-0.1.0/tests/test_domain.py +75 -0
- ai_agentic_mcpscan-0.1.0/tests/test_e2e_dogfood.py +150 -0
- ai_agentic_mcpscan-0.1.0/tests/test_engine.py +145 -0
- ai_agentic_mcpscan-0.1.0/tests/test_enrichment.py +201 -0
- ai_agentic_mcpscan-0.1.0/tests/test_io_safe.py +63 -0
- ai_agentic_mcpscan-0.1.0/tests/test_paths.py +59 -0
- ai_agentic_mcpscan-0.1.0/tests/test_probe.py +69 -0
- ai_agentic_mcpscan-0.1.0/tests/test_redaction.py +35 -0
- ai_agentic_mcpscan-0.1.0/tests/test_report.py +152 -0
- ai_agentic_mcpscan-0.1.0/tests/test_self_scan.py +34 -0
- ai_agentic_mcpscan-0.1.0/tests/test_sockets.py +75 -0
- ai_agentic_mcpscan-0.1.0/tests/test_status_sync.py +64 -0
- ai_agentic_mcpscan-0.1.0/tests/test_version_sync.py +37 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Report incorrect behavior (including false positives / false negatives)
|
|
4
|
+
title: "[bug] "
|
|
5
|
+
labels: bug
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**⚠️ Do not paste real secrets or full config contents.** Redact anything
|
|
9
|
+
sensitive — `mcpscan` is designed so you never need to share a secret to report
|
|
10
|
+
a bug.
|
|
11
|
+
|
|
12
|
+
## What happened
|
|
13
|
+
A clear description of the bug.
|
|
14
|
+
|
|
15
|
+
## Expected
|
|
16
|
+
What you expected instead.
|
|
17
|
+
|
|
18
|
+
## Finding accuracy (if relevant)
|
|
19
|
+
- [ ] False positive (flagged something that is actually fine)
|
|
20
|
+
- [ ] False negative (missed something it should have flagged)
|
|
21
|
+
|
|
22
|
+
A **minimal, sanitized** config that reproduces it:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{ }
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Environment
|
|
29
|
+
- mcpscan version (`mcpscan --version`):
|
|
30
|
+
- OS:
|
|
31
|
+
- Python version:
|
|
32
|
+
- Command used (with flags):
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: 🔒 Report a security vulnerability
|
|
4
|
+
url: https://github.com/IRsoctierDT/ai-agentic-mcpscan/security/advisories/new
|
|
5
|
+
about: >-
|
|
6
|
+
Please report vulnerabilities privately via a GitHub Security Advisory,
|
|
7
|
+
not a public issue. See SECURITY.md.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest a new check, host adapter, or capability
|
|
4
|
+
title: "[feat] "
|
|
5
|
+
labels: enhancement
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Problem
|
|
9
|
+
What posture gap or workflow pain does this address?
|
|
10
|
+
|
|
11
|
+
## Proposal
|
|
12
|
+
What you'd like the tool to do.
|
|
13
|
+
|
|
14
|
+
## Type
|
|
15
|
+
- [ ] New check (which posture dimension: exposure / credential / tool-scope / pinning?)
|
|
16
|
+
- [ ] New host adapter (which host?)
|
|
17
|
+
- [ ] Output / reporting
|
|
18
|
+
- [ ] Other
|
|
19
|
+
|
|
20
|
+
## Trust considerations
|
|
21
|
+
Does this involve network access, writing files, or handling secrets? If so, how
|
|
22
|
+
should it stay consistent with the offline-default, advise-only, redacted design?
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
## What & why
|
|
2
|
+
Briefly: what this changes and the motivation.
|
|
3
|
+
|
|
4
|
+
## Checklist
|
|
5
|
+
- [ ] `ruff check .`, `ruff format --check .`, `mypy src`, `bandit -r src`,
|
|
6
|
+
`pytest` all pass locally
|
|
7
|
+
- [ ] New logic has tests, including failure/edge cases
|
|
8
|
+
- [ ] New check ships with a clean/negative fixture (zero findings on good input)
|
|
9
|
+
- [ ] No raw secret can reach output, logs, or disk
|
|
10
|
+
- [ ] No egress added outside `enrichment/` / outside `--online`
|
|
11
|
+
- [ ] No writes to user config files (advise-only preserved)
|
|
12
|
+
- [ ] Docs updated if behavior/flags changed
|
|
13
|
+
|
|
14
|
+
## Notes for the reviewer
|
|
15
|
+
Anything you want a second set of eyes on (trust boundaries, false-positive risk).
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies (declared in pyproject.toml).
|
|
4
|
+
- package-ecosystem: "pip"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
day: "monday"
|
|
9
|
+
open-pull-requests-limit: 5
|
|
10
|
+
labels: ["dependencies"]
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "build"
|
|
13
|
+
include: "scope"
|
|
14
|
+
|
|
15
|
+
# GitHub Actions used by our workflows.
|
|
16
|
+
- package-ecosystem: "github-actions"
|
|
17
|
+
directory: "/"
|
|
18
|
+
schedule:
|
|
19
|
+
interval: "weekly"
|
|
20
|
+
day: "monday"
|
|
21
|
+
open-pull-requests-limit: 5
|
|
22
|
+
labels: ["ci", "dependencies"]
|
|
23
|
+
commit-message:
|
|
24
|
+
prefix: "ci"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: test (${{ matrix.os }}, py${{ matrix.python-version }})
|
|
15
|
+
runs-on: ${{ matrix.os }}
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
20
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- uses: actions/setup-python@v5
|
|
24
|
+
with:
|
|
25
|
+
python-version: ${{ matrix.python-version }}
|
|
26
|
+
- name: Install (editable + dev)
|
|
27
|
+
run: |
|
|
28
|
+
python -m pip install --upgrade pip
|
|
29
|
+
python -m pip install -e ".[dev]"
|
|
30
|
+
- name: Lint (ruff)
|
|
31
|
+
run: ruff check .
|
|
32
|
+
- name: Format check (ruff)
|
|
33
|
+
run: ruff format --check .
|
|
34
|
+
- name: Type check (mypy)
|
|
35
|
+
run: mypy src
|
|
36
|
+
- name: Tests
|
|
37
|
+
# Coverage gate (branch=true + fail_under) lives in pyproject.toml
|
|
38
|
+
# [tool.coverage.*], so this command enforces it without duplicating
|
|
39
|
+
# the threshold here. Under-threshold coverage fails the job.
|
|
40
|
+
run: pytest --cov=mcpscan --cov-report=term-missing
|
|
41
|
+
|
|
42
|
+
security:
|
|
43
|
+
name: security (SAST + SCA)
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
steps:
|
|
46
|
+
- uses: actions/checkout@v4
|
|
47
|
+
- uses: actions/setup-python@v5
|
|
48
|
+
with:
|
|
49
|
+
python-version: "3.11"
|
|
50
|
+
- run: |
|
|
51
|
+
python -m pip install --upgrade pip
|
|
52
|
+
python -m pip install -e ".[dev]"
|
|
53
|
+
- name: SAST (bandit)
|
|
54
|
+
run: bandit -r src
|
|
55
|
+
- name: SCA (pip-audit)
|
|
56
|
+
run: pip-audit
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Dependency Review
|
|
2
|
+
|
|
3
|
+
# Blocks a PR that introduces a dependency with a known vulnerability or a
|
|
4
|
+
# disallowed license. Runs on the PR's dependency diff.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
pull_request:
|
|
8
|
+
branches: [main]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
pull-requests: write # to post the summary comment on failure
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
review:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
# Dependency review needs the dependency graph, which is free on public
|
|
18
|
+
# repos and requires GitHub Advanced Security on private ones. Skip (neutral)
|
|
19
|
+
# while private; self-activates automatically when the repo goes public.
|
|
20
|
+
if: ${{ github.event.repository.visibility == 'public' }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
- name: Dependency review
|
|
24
|
+
uses: actions/dependency-review-action@v5
|
|
25
|
+
with:
|
|
26
|
+
fail-on-severity: high
|
|
27
|
+
comment-summary-in-pr: on-failure
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
name: PR Title
|
|
2
|
+
|
|
3
|
+
# Enforces Conventional Commit PR titles (the squash-merge commit subject).
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request_target:
|
|
7
|
+
types: [opened, edited, synchronize, reopened]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
pull-requests: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Validate PR title
|
|
17
|
+
uses: amannn/action-semantic-pull-request@v5
|
|
18
|
+
env:
|
|
19
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
20
|
+
with:
|
|
21
|
+
types: |
|
|
22
|
+
feat
|
|
23
|
+
fix
|
|
24
|
+
docs
|
|
25
|
+
style
|
|
26
|
+
refactor
|
|
27
|
+
perf
|
|
28
|
+
test
|
|
29
|
+
build
|
|
30
|
+
ci
|
|
31
|
+
security
|
|
32
|
+
chore
|
|
33
|
+
revert
|
|
34
|
+
requireScope: false
|
|
35
|
+
subjectPattern: ^(?![A-Z]).+$
|
|
36
|
+
subjectPatternError: |
|
|
37
|
+
The subject "{subject}" should start lowercase (imperative mood),
|
|
38
|
+
e.g. "feat(checks): add TLS-misconfig detection".
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: release-please
|
|
2
|
+
|
|
3
|
+
# Automated releases from Conventional Commits (Phase 3).
|
|
4
|
+
#
|
|
5
|
+
# On each push to main, release-please maintains a "release PR" that bumps the
|
|
6
|
+
# version in pyproject.toml and updates CHANGELOG.md. Merging that PR tags the
|
|
7
|
+
# release and creates a GitHub Release; the publish job then builds and pushes to
|
|
8
|
+
# PyPI via Trusted Publishing (OIDC — no stored token), gated on the `pypi`
|
|
9
|
+
# environment (add a required reviewer there for a manual production gate).
|
|
10
|
+
#
|
|
11
|
+
# NOTE: v0.1.0 is released via the manual path (.github/workflows/release.yml);
|
|
12
|
+
# the manifest is seeded at 0.1.0 so release-please starts proposing 0.1.1+.
|
|
13
|
+
#
|
|
14
|
+
# Operator step: on PyPI, add a Trusted Publisher for THIS workflow filename
|
|
15
|
+
# (release-please.yml) + environment `pypi`, alongside the existing release.yml
|
|
16
|
+
# one. See docs/DEVSECOPS.md.
|
|
17
|
+
|
|
18
|
+
on:
|
|
19
|
+
push:
|
|
20
|
+
branches: [main]
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: write
|
|
24
|
+
pull-requests: write
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
release-please:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
outputs:
|
|
30
|
+
release_created: ${{ steps.rp.outputs.release_created }}
|
|
31
|
+
tag_name: ${{ steps.rp.outputs.tag_name }}
|
|
32
|
+
steps:
|
|
33
|
+
- id: rp
|
|
34
|
+
uses: googleapis/release-please-action@v4
|
|
35
|
+
with:
|
|
36
|
+
token: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
|
|
38
|
+
publish:
|
|
39
|
+
needs: release-please
|
|
40
|
+
if: ${{ needs.release-please.outputs.release_created == 'true' }}
|
|
41
|
+
runs-on: ubuntu-latest
|
|
42
|
+
environment: pypi
|
|
43
|
+
permissions:
|
|
44
|
+
id-token: write # OIDC Trusted Publishing
|
|
45
|
+
contents: write # attach SBOM + checksums to the release
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
- uses: actions/setup-python@v5
|
|
49
|
+
with:
|
|
50
|
+
python-version: "3.11"
|
|
51
|
+
|
|
52
|
+
- name: Build distributions
|
|
53
|
+
run: |
|
|
54
|
+
python -m pip install --upgrade pip build
|
|
55
|
+
python -m build
|
|
56
|
+
|
|
57
|
+
- name: Generate checksums
|
|
58
|
+
run: sha256sum dist/* > SHA256SUMS
|
|
59
|
+
|
|
60
|
+
- name: Generate CycloneDX SBOM
|
|
61
|
+
run: |
|
|
62
|
+
python -m pip install cyclonedx-bom
|
|
63
|
+
python -m pip install .
|
|
64
|
+
cyclonedx-py environment -o sbom.cdx.json
|
|
65
|
+
|
|
66
|
+
- name: Publish to PyPI (Trusted Publishing)
|
|
67
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
68
|
+
|
|
69
|
+
- name: Attach SBOM + checksums to the release
|
|
70
|
+
uses: softprops/action-gh-release@v3
|
|
71
|
+
with:
|
|
72
|
+
tag_name: ${{ needs.release-please.outputs.tag_name }}
|
|
73
|
+
files: |
|
|
74
|
+
SHA256SUMS
|
|
75
|
+
sbom.cdx.json
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI via Trusted Publishing (OIDC) — NO API token stored in the
|
|
4
|
+
# repo. Runs only when a GitHub Release is published, so publishing is an
|
|
5
|
+
# explicit human action (create the release in the UI / `gh release create`).
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: read
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
build:
|
|
16
|
+
name: Build distributions
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.11"
|
|
23
|
+
- name: Verify tag matches package version
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
PKG_VERSION=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml','rb'))['project']['version'])")
|
|
27
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
28
|
+
echo "package=$PKG_VERSION tag=$TAG"
|
|
29
|
+
test "$PKG_VERSION" = "$TAG" || { echo "::error::tag ($TAG) != version ($PKG_VERSION)"; exit 1; }
|
|
30
|
+
- name: Build sdist + wheel
|
|
31
|
+
run: |
|
|
32
|
+
python -m pip install build
|
|
33
|
+
python -m build
|
|
34
|
+
- uses: actions/upload-artifact@v4
|
|
35
|
+
with:
|
|
36
|
+
name: dist
|
|
37
|
+
path: dist/
|
|
38
|
+
|
|
39
|
+
publish:
|
|
40
|
+
name: Publish to PyPI
|
|
41
|
+
needs: build
|
|
42
|
+
runs-on: ubuntu-latest
|
|
43
|
+
environment: pypi # add a manual-approval rule on this environment for extra safety
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write # required for Trusted Publishing (OIDC)
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/download-artifact@v4
|
|
48
|
+
with:
|
|
49
|
+
name: dist
|
|
50
|
+
path: dist/
|
|
51
|
+
- name: Publish
|
|
52
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: SBOM & Checksums
|
|
2
|
+
|
|
3
|
+
# On a published Release, attach a CycloneDX SBOM and SHA-256 checksums as
|
|
4
|
+
# release assets. Independent of release.yml (the publish path) so it can never
|
|
5
|
+
# affect publishing.
|
|
6
|
+
|
|
7
|
+
on:
|
|
8
|
+
release:
|
|
9
|
+
types: [published]
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write # attach assets to the release that triggered this run
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
sbom:
|
|
16
|
+
runs-on: ubuntu-latest
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.11"
|
|
22
|
+
|
|
23
|
+
- name: Build distributions
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip build
|
|
26
|
+
python -m build
|
|
27
|
+
|
|
28
|
+
- name: Generate checksums
|
|
29
|
+
run: (cd dist && sha256sum * > SHA256SUMS && cat SHA256SUMS)
|
|
30
|
+
|
|
31
|
+
- name: Generate CycloneDX SBOM
|
|
32
|
+
run: |
|
|
33
|
+
python -m pip install cyclonedx-bom
|
|
34
|
+
python -m pip install .
|
|
35
|
+
cyclonedx-py environment -o sbom.cdx.json
|
|
36
|
+
echo "wrote sbom.cdx.json"
|
|
37
|
+
|
|
38
|
+
- name: Attach SBOM + checksums to the release
|
|
39
|
+
uses: softprops/action-gh-release@v3
|
|
40
|
+
with:
|
|
41
|
+
files: |
|
|
42
|
+
dist/SHA256SUMS
|
|
43
|
+
sbom.cdx.json
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# macOS
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Secrets / local config — never commit (this is a security tool; lead by example)
|
|
5
|
+
.env
|
|
6
|
+
.env.*
|
|
7
|
+
!.env.example
|
|
8
|
+
*.pem
|
|
9
|
+
*.key
|
|
10
|
+
*.p12
|
|
11
|
+
|
|
12
|
+
# Python
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.py[cod]
|
|
15
|
+
.venv/
|
|
16
|
+
venv/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
dist/
|
|
23
|
+
build/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
|
|
26
|
+
# Tool output (stateless by design — never commit generated reports)
|
|
27
|
+
*.mcpscan.html
|
|
28
|
+
*.mcpscan.json
|
|
29
|
+
|
|
30
|
+
# Claude Code local settings
|
|
31
|
+
.claude/settings.local.json
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# <type>(<optional scope>): <subject> <- 50 chars, imperative, lowercase
|
|
2
|
+
#
|
|
3
|
+
# <body: what changed and WHY. Wrap at 72.>
|
|
4
|
+
#
|
|
5
|
+
# <footers: "Refs: #123", "BREAKING CHANGE: <desc>">
|
|
6
|
+
#
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Conventional Commits (https://www.conventionalcommits.org)
|
|
9
|
+
# Types:
|
|
10
|
+
# feat – a new feature (→ minor release)
|
|
11
|
+
# fix – a bug fix (→ patch release)
|
|
12
|
+
# perf – a performance improvement (→ patch release)
|
|
13
|
+
# security – a security fix/hardening (→ patch release)
|
|
14
|
+
# docs – documentation only
|
|
15
|
+
# test – tests only
|
|
16
|
+
# refactor – neither fixes a bug nor adds a feature
|
|
17
|
+
# style – formatting, no code change
|
|
18
|
+
# build – build system / dependencies
|
|
19
|
+
# ci – CI configuration
|
|
20
|
+
# chore – other maintenance
|
|
21
|
+
# revert – reverts a previous commit
|
|
22
|
+
#
|
|
23
|
+
# Breaking change: add "!" after the type/scope (feat!:) OR a
|
|
24
|
+
# "BREAKING CHANGE:" footer (→ major release).
|
|
25
|
+
#
|
|
26
|
+
# Enable this template once: git config commit.template .gitmessage
|
|
27
|
+
# ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.0]
|
|
8
|
+
|
|
9
|
+
First public release — a local-first, offline-by-default security posture
|
|
10
|
+
scanner for MCP / local-agent setups (CLI: `mcpscan`).
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **CLI** — `mcpscan scan` with `--root`, `--json`, `--html`, `--online`,
|
|
15
|
+
`--show-secrets`, `--absolute-paths`, and `--fail-on {critical,high,medium,low}`;
|
|
16
|
+
process exit code is driven by the highest finding severity versus the
|
|
17
|
+
threshold.
|
|
18
|
+
- **Discovery** — listening-socket enumeration via psutil (degrades gracefully
|
|
19
|
+
when the OS denies introspection), a loopback-only MCP confirmation probe
|
|
20
|
+
(`/mcp`, `/sse`), and declared-server discovery from Claude Code / Claude
|
|
21
|
+
Desktop configs through a `HostAdapter` seam.
|
|
22
|
+
- **Checks (four dimensions)** — exposure (non-loopback / `0.0.0.0` binds),
|
|
23
|
+
credentials (plaintext secrets by provider pattern + entropy, and secret-at-rest
|
|
24
|
+
file permission / git-tracking), tool scope (auto-approved and wildcard
|
|
25
|
+
permission grants), and version pinning (unpinned `npx`/`uvx`/etc.).
|
|
26
|
+
- **Scoring** — deterministic A–F grading per server, per dimension, and overall.
|
|
27
|
+
- **Reports** — ANSI terminal output, stable machine-readable JSON
|
|
28
|
+
(`schema_version` "1.0"), and a self-contained, offline HTML report.
|
|
29
|
+
- **Online enrichment** — opt-in `--online` OSV advisory lookups for pinned
|
|
30
|
+
packages; the egress module is isolated and imported only on this path.
|
|
31
|
+
- **Self-scan** (`mcpscan` passes its own checks) and cross-platform CI
|
|
32
|
+
(macOS/Linux/Windows × Python 3.11–3.13).
|
|
33
|
+
|
|
34
|
+
### Security & trust properties
|
|
35
|
+
|
|
36
|
+
- Offline by default; no network egress unless `--online` is passed.
|
|
37
|
+
- Loopback-only probing — non-loopback targets are refused (fail closed).
|
|
38
|
+
- Secrets are reduced to fingerprints at detection; raw values never reach the
|
|
39
|
+
domain model, reports, or logs. `--show-secrets` reveals only a masked form and
|
|
40
|
+
prints a warning.
|
|
41
|
+
- No file writes except the reports you explicitly request, created `0600` where
|
|
42
|
+
supported.
|
|
43
|
+
- Home directories are relativized to `~/…` by default (`--absolute-paths` opts
|
|
44
|
+
out).
|
|
45
|
+
|
|
46
|
+
### Packaging
|
|
47
|
+
|
|
48
|
+
- Apache-2.0 licensed, with a `NOTICE` file and per-file SPDX headers.
|
|
49
|
+
- Publishes to PyPI via Trusted Publishing (OIDC); the version is single-sourced
|
|
50
|
+
from `pyproject.toml`.
|
|
51
|
+
|
|
52
|
+
[0.1.0]: https://github.com/IRsoctierDT/ai-agentic-mcpscan/releases/tag/v0.1.0
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Code owners — auto-requested as reviewers on matching paths.
|
|
2
|
+
# Docs: https://docs.github.com/articles/about-code-owners
|
|
3
|
+
|
|
4
|
+
# Default owner for everything.
|
|
5
|
+
* @IRsoctierDT
|
|
6
|
+
|
|
7
|
+
# Security-critical surfaces get explicit ownership.
|
|
8
|
+
/src/mcpscan/redaction.py @IRsoctierDT
|
|
9
|
+
/src/mcpscan/enrichment/ @IRsoctierDT
|
|
10
|
+
/src/mcpscan/discovery/ @IRsoctierDT
|
|
11
|
+
|
|
12
|
+
# CI/CD, supply chain, and governance.
|
|
13
|
+
/.github/ @IRsoctierDT
|
|
14
|
+
/SECURITY.md @IRsoctierDT
|
|
15
|
+
/pyproject.toml @IRsoctierDT
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, caste, color, religion, or sexual
|
|
10
|
+
identity and orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment include:
|
|
18
|
+
|
|
19
|
+
- Demonstrating empathy and kindness toward other people
|
|
20
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
21
|
+
- Giving and gracefully accepting constructive feedback
|
|
22
|
+
- Accepting responsibility and apologizing to those affected by our mistakes,
|
|
23
|
+
and learning from the experience
|
|
24
|
+
- Focusing on what is best not just for us as individuals, but for the overall
|
|
25
|
+
community
|
|
26
|
+
|
|
27
|
+
Examples of unacceptable behavior include:
|
|
28
|
+
|
|
29
|
+
- The use of sexualized language or imagery, and sexual attention or advances of
|
|
30
|
+
any kind
|
|
31
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
32
|
+
- Public or private harassment
|
|
33
|
+
- Publishing others' private information, such as a physical or email address,
|
|
34
|
+
without their explicit permission
|
|
35
|
+
- Other conduct which could reasonably be considered inappropriate in a
|
|
36
|
+
professional setting
|
|
37
|
+
|
|
38
|
+
## Enforcement Responsibilities
|
|
39
|
+
|
|
40
|
+
Community leaders are responsible for clarifying and enforcing our standards of
|
|
41
|
+
acceptable behavior and will take appropriate and fair corrective action in
|
|
42
|
+
response to any behavior that they deem inappropriate, threatening, offensive,
|
|
43
|
+
or harmful.
|
|
44
|
+
|
|
45
|
+
## Scope
|
|
46
|
+
|
|
47
|
+
This Code of Conduct applies within all community spaces, and also applies when
|
|
48
|
+
an individual is officially representing the community in public spaces.
|
|
49
|
+
|
|
50
|
+
## Enforcement
|
|
51
|
+
|
|
52
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
53
|
+
reported to the community leaders responsible for enforcement at
|
|
54
|
+
**irozenblad@icloud.com**. All complaints will be reviewed and investigated
|
|
55
|
+
promptly and fairly. All community leaders are obligated to respect the privacy
|
|
56
|
+
and security of the reporter of any incident.
|
|
57
|
+
|
|
58
|
+
## Enforcement Guidelines
|
|
59
|
+
|
|
60
|
+
Community leaders will follow these Community Impact Guidelines in determining
|
|
61
|
+
the consequences for any action they deem in violation of this Code of Conduct:
|
|
62
|
+
|
|
63
|
+
1. **Correction** — Community Impact: use of inappropriate language or other
|
|
64
|
+
unprofessional behavior. Consequence: a private, written warning.
|
|
65
|
+
2. **Warning** — Community Impact: a violation through a single incident or
|
|
66
|
+
series of actions. Consequence: a warning with consequences for continued
|
|
67
|
+
behavior.
|
|
68
|
+
3. **Temporary Ban** — Community Impact: a serious violation of community
|
|
69
|
+
standards. Consequence: a temporary ban from any interaction with the
|
|
70
|
+
community.
|
|
71
|
+
4. **Permanent Ban** — Community Impact: demonstrating a pattern of violation of
|
|
72
|
+
community standards. Consequence: a permanent ban.
|
|
73
|
+
|
|
74
|
+
## Attribution
|
|
75
|
+
|
|
76
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
77
|
+
version 2.1, available at
|
|
78
|
+
https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
|
|
79
|
+
|
|
80
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Contributing to AI Agentic MCPscan
|
|
2
|
+
|
|
3
|
+
Thanks for your interest! This project aims to be exemplary, reviewable security
|
|
4
|
+
tooling, so contributions are held to a clear bar.
|
|
5
|
+
|
|
6
|
+
## Quick start
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/IRsoctierDT/ai-agentic-mcpscan.git
|
|
10
|
+
cd ai-agentic-mcpscan
|
|
11
|
+
python -m venv .venv && . .venv/bin/activate
|
|
12
|
+
python -m pip install -e ".[dev]"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Run the full gate before opening a PR
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
ruff check . # lint
|
|
19
|
+
ruff format --check . # formatting
|
|
20
|
+
mypy src # types (strict)
|
|
21
|
+
bandit -r src # SAST
|
|
22
|
+
pytest # tests
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
CI runs the same gate on macOS, Linux, and Windows across Python 3.11–3.13. All
|
|
26
|
+
of it must be green.
|
|
27
|
+
|
|
28
|
+
## Architecture & where things go
|
|
29
|
+
|
|
30
|
+
- The design is documented in [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md).
|
|
31
|
+
Read it first — the dependency direction (pure core, I/O at the edges) is
|
|
32
|
+
intentional.
|
|
33
|
+
- **New host support** → add a `HostAdapter` in `src/mcpscan/adapters/`. The
|
|
34
|
+
engine and checks must not need to change.
|
|
35
|
+
- **New check** → add a small, single-responsibility function in
|
|
36
|
+
`src/mcpscan/checks/`, plus a **clean/negative fixture** (an input that must
|
|
37
|
+
produce zero findings) alongside the positive test. False positives are
|
|
38
|
+
treated as bugs.
|
|
39
|
+
- **Anything touching the network** belongs only in `src/mcpscan/enrichment/`
|
|
40
|
+
and must stay behind `--online`.
|
|
41
|
+
|
|
42
|
+
## Non-negotiables (will block a PR)
|
|
43
|
+
|
|
44
|
+
- No raw secret value may reach output, logs, or disk. Route secrets through
|
|
45
|
+
`redaction`.
|
|
46
|
+
- No egress on a default (non-`--online`) run.
|
|
47
|
+
- No writing to a user's config files (advise-only).
|
|
48
|
+
- New logic ships with tests, including failure/edge cases.
|
|
49
|
+
|
|
50
|
+
## Commit style
|
|
51
|
+
|
|
52
|
+
Conventional commits (`feat:`, `fix:`, `docs:`, `chore:`, `test:`) scoped where
|
|
53
|
+
useful (e.g. `feat(checks): …`). PR titles are checked against this format by
|
|
54
|
+
CI. To get a helpful template in your editor:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
git config commit.template .gitmessage
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Workflow, branching & releases
|
|
61
|
+
|
|
62
|
+
The full Git workflow, CI/CD pipeline, branch-protection settings, semantic
|
|
63
|
+
versioning, rollback, and release process are documented in
|
|
64
|
+
[`docs/DEVSECOPS.md`](docs/DEVSECOPS.md). In short: branch `feature/*` off
|
|
65
|
+
`main`, keep it short-lived, open a PR, get CI green + one review, and squash-merge.
|
|
66
|
+
|
|
67
|
+
Participation is governed by our [Code of Conduct](CODE_OF_CONDUCT.md).
|