agentcheckup 0.4.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.
- agentcheckup-0.4.0/.gitattributes +13 -0
- agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/bug_report.yml +63 -0
- agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- agentcheckup-0.4.0/.github/ISSUE_TEMPLATE/rule_request.yml +72 -0
- agentcheckup-0.4.0/.github/pull_request_template.md +35 -0
- agentcheckup-0.4.0/.github/workflows/action-selftest.yml +59 -0
- agentcheckup-0.4.0/.github/workflows/ci.yml +66 -0
- agentcheckup-0.4.0/.github/workflows/publish.yml +59 -0
- agentcheckup-0.4.0/.gitignore +31 -0
- agentcheckup-0.4.0/CHANGELOG.md +141 -0
- agentcheckup-0.4.0/CODE_OF_CONDUCT.md +40 -0
- agentcheckup-0.4.0/CONTRIBUTING.md +122 -0
- agentcheckup-0.4.0/LICENSE +21 -0
- agentcheckup-0.4.0/Makefile +35 -0
- agentcheckup-0.4.0/PKG-INFO +261 -0
- agentcheckup-0.4.0/README.md +233 -0
- agentcheckup-0.4.0/README.zh-CN.md +174 -0
- agentcheckup-0.4.0/SECURITY.md +52 -0
- agentcheckup-0.4.0/action.yml +121 -0
- agentcheckup-0.4.0/conftest.py +15 -0
- agentcheckup-0.4.0/docs/github-action.md +117 -0
- agentcheckup-0.4.0/docs/rules.md +209 -0
- agentcheckup-0.4.0/pyproject.toml +53 -0
- agentcheckup-0.4.0/scripts/bootstrap.ps1 +151 -0
- agentcheckup-0.4.0/scripts/bootstrap.sh +58 -0
- agentcheckup-0.4.0/src/agentcheckup/__init__.py +27 -0
- agentcheckup-0.4.0/src/agentcheckup/__main__.py +6 -0
- agentcheckup-0.4.0/src/agentcheckup/cli.py +242 -0
- agentcheckup-0.4.0/src/agentcheckup/conflicts.py +253 -0
- agentcheckup-0.4.0/src/agentcheckup/discovery.py +206 -0
- agentcheckup-0.4.0/src/agentcheckup/engine.py +146 -0
- agentcheckup-0.4.0/src/agentcheckup/loader.py +214 -0
- agentcheckup-0.4.0/src/agentcheckup/models.py +166 -0
- agentcheckup-0.4.0/src/agentcheckup/report.py +274 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/__init__.py +12 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/base.py +91 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/config_rules.py +180 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/docs.py +124 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/injection.py +127 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/naming.py +100 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/safety.py +131 -0
- agentcheckup-0.4.0/src/agentcheckup/rules/schema.py +143 -0
- agentcheckup-0.4.0/src/agentcheckup/tokens.py +69 -0
- agentcheckup-0.4.0/tests/fixtures/bad_tools.json +80 -0
- agentcheckup-0.4.0/tests/fixtures/ci_config.json +12 -0
- agentcheckup-0.4.0/tests/fixtures/claude_desktop_config.json +24 -0
- agentcheckup-0.4.0/tests/fixtures/good_tools.json +38 -0
- agentcheckup-0.4.0/tests/fixtures/mock_server.py +168 -0
- agentcheckup-0.4.0/tests/test_cli.py +101 -0
- agentcheckup-0.4.0/tests/test_conflicts.py +130 -0
- agentcheckup-0.4.0/tests/test_discovery.py +144 -0
- agentcheckup-0.4.0/tests/test_rules.py +277 -0
- agentcheckup-0.4.0/tests/test_scoring.py +118 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Normalise line endings so Windows contributors don't produce whole-file diffs.
|
|
2
|
+
* text=auto eol=lf
|
|
3
|
+
|
|
4
|
+
# Windows-only scripts keep CRLF.
|
|
5
|
+
*.ps1 text eol=crlf
|
|
6
|
+
*.bat text eol=crlf
|
|
7
|
+
*.cmd text eol=crlf
|
|
8
|
+
|
|
9
|
+
# Binary-ish
|
|
10
|
+
*.png binary
|
|
11
|
+
*.jpg binary
|
|
12
|
+
*.gif binary
|
|
13
|
+
*.ico binary
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Something is wrong — a crash, a wrong finding, a missed finding.
|
|
3
|
+
title: "[bug] "
|
|
4
|
+
labels: ["bug"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Thanks for the report. The two most useful things you can include are the
|
|
10
|
+
**rule id** and a **minimal manifest** that reproduces it.
|
|
11
|
+
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: what-happened
|
|
14
|
+
attributes:
|
|
15
|
+
label: What happened
|
|
16
|
+
description: What did agentcheckup do, and what did you expect instead?
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
|
|
20
|
+
- type: input
|
|
21
|
+
id: rule
|
|
22
|
+
attributes:
|
|
23
|
+
label: Rule id (if the report is about a specific rule)
|
|
24
|
+
placeholder: AGT040
|
|
25
|
+
validations:
|
|
26
|
+
required: false
|
|
27
|
+
|
|
28
|
+
- type: textarea
|
|
29
|
+
id: repro
|
|
30
|
+
attributes:
|
|
31
|
+
label: Minimal reproduction
|
|
32
|
+
description: >
|
|
33
|
+
The smallest manifest or config that triggers it. Redact anything
|
|
34
|
+
sensitive — a single tool entry is usually enough.
|
|
35
|
+
render: json
|
|
36
|
+
placeholder: |
|
|
37
|
+
{"tools": [{"name": "x", "description": "..."}]}
|
|
38
|
+
validations:
|
|
39
|
+
required: true
|
|
40
|
+
|
|
41
|
+
- type: input
|
|
42
|
+
id: command
|
|
43
|
+
attributes:
|
|
44
|
+
label: Command you ran
|
|
45
|
+
placeholder: agentcheckup scan tools.json --fail-on warning
|
|
46
|
+
validations:
|
|
47
|
+
required: true
|
|
48
|
+
|
|
49
|
+
- type: textarea
|
|
50
|
+
id: output
|
|
51
|
+
attributes:
|
|
52
|
+
label: Actual output
|
|
53
|
+
render: shell
|
|
54
|
+
validations:
|
|
55
|
+
required: false
|
|
56
|
+
|
|
57
|
+
- type: input
|
|
58
|
+
id: version
|
|
59
|
+
attributes:
|
|
60
|
+
label: agentcheckup version and Python version
|
|
61
|
+
placeholder: agentcheckup 0.1.0, Python 3.12.7, Windows 11
|
|
62
|
+
validations:
|
|
63
|
+
required: true
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: Question or idea
|
|
4
|
+
url: https://github.com/wanjiaqing/agentcheckup/discussions
|
|
5
|
+
about: For open-ended discussion, use Discussions instead of an issue.
|
|
6
|
+
- name: Security vulnerability
|
|
7
|
+
url: https://github.com/wanjiaqing/agentcheckup/security/advisories/new
|
|
8
|
+
about: Please report security issues privately, not in a public issue.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Rule request
|
|
2
|
+
description: Propose a new lint rule, or argue that an existing one is wrong.
|
|
3
|
+
title: "[rule] "
|
|
4
|
+
labels: ["rule"]
|
|
5
|
+
body:
|
|
6
|
+
- type: markdown
|
|
7
|
+
attributes:
|
|
8
|
+
value: |
|
|
9
|
+
Rules are the point of this project. A good proposal is mostly *evidence*:
|
|
10
|
+
what goes wrong in the real world, and why a linter is the right place to
|
|
11
|
+
catch it.
|
|
12
|
+
|
|
13
|
+
- type: dropdown
|
|
14
|
+
id: kind
|
|
15
|
+
attributes:
|
|
16
|
+
label: What kind of request is this?
|
|
17
|
+
options:
|
|
18
|
+
- New rule
|
|
19
|
+
- Existing rule has false positives
|
|
20
|
+
- Existing rule should be a different severity
|
|
21
|
+
- Existing rule misses a case
|
|
22
|
+
validations:
|
|
23
|
+
required: true
|
|
24
|
+
|
|
25
|
+
- type: input
|
|
26
|
+
id: rule-id
|
|
27
|
+
attributes:
|
|
28
|
+
label: Rule id (leave empty for a new rule)
|
|
29
|
+
placeholder: AGT015
|
|
30
|
+
validations:
|
|
31
|
+
required: false
|
|
32
|
+
|
|
33
|
+
- type: textarea
|
|
34
|
+
id: failure
|
|
35
|
+
attributes:
|
|
36
|
+
label: What goes wrong without this rule
|
|
37
|
+
description: >
|
|
38
|
+
Describe the concrete failure — a wrong tool call, a leaked credential, a
|
|
39
|
+
confusing retry loop. "It's bad practice" is not enough.
|
|
40
|
+
validations:
|
|
41
|
+
required: true
|
|
42
|
+
|
|
43
|
+
- type: textarea
|
|
44
|
+
id: example
|
|
45
|
+
attributes:
|
|
46
|
+
label: Example input that should (or should not) be flagged
|
|
47
|
+
render: json
|
|
48
|
+
placeholder: |
|
|
49
|
+
{"name": "read_file", "description": "TODO: describe this tool"}
|
|
50
|
+
validations:
|
|
51
|
+
required: true
|
|
52
|
+
|
|
53
|
+
- type: dropdown
|
|
54
|
+
id: severity
|
|
55
|
+
attributes:
|
|
56
|
+
label: Proposed severity
|
|
57
|
+
options:
|
|
58
|
+
- error — breaks a run or endangers the host
|
|
59
|
+
- warning — likely to cause wrong behaviour
|
|
60
|
+
- info — a human should decide
|
|
61
|
+
validations:
|
|
62
|
+
required: true
|
|
63
|
+
|
|
64
|
+
- type: textarea
|
|
65
|
+
id: false-positives
|
|
66
|
+
attributes:
|
|
67
|
+
label: What legitimate input might this wrongly flag?
|
|
68
|
+
description: >
|
|
69
|
+
This is the question that decides acceptance. If you cannot think of any,
|
|
70
|
+
you probably have not looked hard enough.
|
|
71
|
+
validations:
|
|
72
|
+
required: true
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
<!-- One or two sentences. Link the issue if there is one. -->
|
|
4
|
+
|
|
5
|
+
Closes #
|
|
6
|
+
|
|
7
|
+
## Type
|
|
8
|
+
|
|
9
|
+
- [ ] New rule
|
|
10
|
+
- [ ] Rule fix (false positive / false negative / severity)
|
|
11
|
+
- [ ] Loader or output format
|
|
12
|
+
- [ ] Docs
|
|
13
|
+
- [ ] Refactor (no behaviour change)
|
|
14
|
+
|
|
15
|
+
## If this adds a rule
|
|
16
|
+
|
|
17
|
+
- Rule id:
|
|
18
|
+
- Severity:
|
|
19
|
+
- What it catches:
|
|
20
|
+
- **What legitimate input it might wrongly flag, and how you narrowed it:**
|
|
21
|
+
|
|
22
|
+
## Checklist
|
|
23
|
+
|
|
24
|
+
- [ ] `pytest` is green
|
|
25
|
+
- [ ] `ruff check .` is clean
|
|
26
|
+
- [ ] A test covers the new behaviour (both a positive and a negative case)
|
|
27
|
+
- [ ] No new runtime dependency
|
|
28
|
+
- [ ] `docs/rules.md` updated (for rule changes)
|
|
29
|
+
- [ ] Rule id is unused — checked with `agentcheckup rules`
|
|
30
|
+
- [ ] Severity is honest: `error` means "breaks a run or endangers the host"
|
|
31
|
+
|
|
32
|
+
## Notes for the reviewer
|
|
33
|
+
|
|
34
|
+
<!-- Anything you are unsure about. Saying "I'm not confident about the
|
|
35
|
+
false-positive rate here" is more useful than silence. -->
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Action self-test
|
|
2
|
+
|
|
3
|
+
# Exercises action.yml on a real runner, including spawning two MCP servers that
|
|
4
|
+
# collide. Without this the action is only ever tested by reading it.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches: [main]
|
|
9
|
+
pull_request:
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
self-test:
|
|
17
|
+
runs-on: ubuntu-latest
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: ./
|
|
22
|
+
id: doctor
|
|
23
|
+
with:
|
|
24
|
+
config: tests/fixtures/ci_config.json
|
|
25
|
+
fail-on: never
|
|
26
|
+
sarif-file: agentcheckup.sarif
|
|
27
|
+
|
|
28
|
+
- name: Assert the action produced a usable result
|
|
29
|
+
run: |
|
|
30
|
+
set -eu
|
|
31
|
+
echo "score=${{ steps.doctor.outputs.score }}"
|
|
32
|
+
echo "grade=${{ steps.doctor.outputs.grade }}"
|
|
33
|
+
echo "findings=${{ steps.doctor.outputs.findings }}"
|
|
34
|
+
|
|
35
|
+
test -n "${{ steps.doctor.outputs.score }}" || { echo "::error::score output is empty"; exit 1; }
|
|
36
|
+
test -n "${{ steps.doctor.outputs.grade }}" || { echo "::error::grade output is empty"; exit 1; }
|
|
37
|
+
test -f agentcheckup.sarif || { echo "::error::sarif file was not written"; exit 1; }
|
|
38
|
+
|
|
39
|
+
# The fixture deliberately exposes read_file from two servers.
|
|
40
|
+
grep -q "AGT201" agentcheckup.sarif || {
|
|
41
|
+
echo "::error::expected a hard-collision finding in the SARIF output"
|
|
42
|
+
cat agentcheckup.sarif
|
|
43
|
+
exit 1
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
- name: Assert the gate fails when it should
|
|
47
|
+
run: |
|
|
48
|
+
set +e
|
|
49
|
+
# Re-run through the CLI directly so the action's own exit-code plumbing
|
|
50
|
+
# is not what we are measuring here.
|
|
51
|
+
PYTHONPATH=src python -m agentcheckup audit \
|
|
52
|
+
--no-discover \
|
|
53
|
+
--config tests/fixtures/ci_config.json \
|
|
54
|
+
--fail-on error
|
|
55
|
+
code=$?
|
|
56
|
+
if [ "$code" -ne 1 ]; then
|
|
57
|
+
echo "::error::expected exit 1 for an error-level finding, got $code"
|
|
58
|
+
exit 1
|
|
59
|
+
fi
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
runs-on: ${{ matrix.os }}
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
os: [ubuntu-latest, windows-latest, macos-latest]
|
|
19
|
+
python: ["3.10", "3.11", "3.12", "3.13"]
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
- uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python }}
|
|
25
|
+
- name: Install dev tools
|
|
26
|
+
run: python -m pip install --upgrade pip pytest ruff
|
|
27
|
+
- name: Lint
|
|
28
|
+
run: ruff check .
|
|
29
|
+
- name: Test
|
|
30
|
+
run: pytest -q
|
|
31
|
+
|
|
32
|
+
self-lint:
|
|
33
|
+
# Dogfood: agentcheckup lints its own fixtures. If this job fails, the fixtures
|
|
34
|
+
# or a rule regressed.
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
permissions:
|
|
37
|
+
contents: read
|
|
38
|
+
# Required by upload-sarif. Without it the upload fails with
|
|
39
|
+
# "Resource not accessible by integration", which is how this job first
|
|
40
|
+
# broke in CI.
|
|
41
|
+
security-events: write
|
|
42
|
+
steps:
|
|
43
|
+
- uses: actions/checkout@v4
|
|
44
|
+
- uses: actions/setup-python@v5
|
|
45
|
+
with:
|
|
46
|
+
python-version: "3.12"
|
|
47
|
+
- name: Lint the clean fixture (must pass)
|
|
48
|
+
run: PYTHONPATH=src python -m agentcheckup scan tests/fixtures/good_tools.json --min-score 90
|
|
49
|
+
- name: Lint the dirty fixture (must fail)
|
|
50
|
+
run: |
|
|
51
|
+
set +e
|
|
52
|
+
PYTHONPATH=src python -m agentcheckup scan tests/fixtures/bad_tools.json --fail-on error
|
|
53
|
+
code=$?
|
|
54
|
+
if [ "$code" -ne 1 ]; then
|
|
55
|
+
echo "expected exit 1, got $code"
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
- name: Emit SARIF
|
|
59
|
+
if: always()
|
|
60
|
+
run: PYTHONPATH=src python -m agentcheckup scan tests/fixtures/bad_tools.json --format sarif --fail-on never > agentcheckup.sarif
|
|
61
|
+
- name: Upload SARIF
|
|
62
|
+
if: always()
|
|
63
|
+
# v3 is deprecated in December 2026.
|
|
64
|
+
uses: github/codeql-action/upload-sarif@v4
|
|
65
|
+
with:
|
|
66
|
+
sarif_file: agentcheckup.sarif
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI using Trusted Publishing (OIDC). No API token is stored
|
|
4
|
+
# anywhere: PyPI trusts this repository's workflow identity directly.
|
|
5
|
+
#
|
|
6
|
+
# One-time setup on PyPI (the project does not exist yet, so use "pending
|
|
7
|
+
# publisher"):
|
|
8
|
+
# https://pypi.org/manage/account/publishing/
|
|
9
|
+
# PyPI Project Name : agentcheckup
|
|
10
|
+
# Owner : wanjiaqing
|
|
11
|
+
# Repository name : agentcheckup
|
|
12
|
+
# Workflow name : publish.yml
|
|
13
|
+
# Environment : pypi
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
# Re-enable the release trigger once the PyPI pending publisher exists:
|
|
17
|
+
# on: release: types: [published]
|
|
18
|
+
# Until then a release would run this and fail with "environment: MISSING",
|
|
19
|
+
# which is noise on the repository home page.
|
|
20
|
+
workflow_dispatch:
|
|
21
|
+
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
build:
|
|
27
|
+
runs-on: ubuntu-latest
|
|
28
|
+
steps:
|
|
29
|
+
- uses: actions/checkout@v4
|
|
30
|
+
- uses: actions/setup-python@v5
|
|
31
|
+
with:
|
|
32
|
+
python-version: "3.12"
|
|
33
|
+
- name: Build sdist and wheel
|
|
34
|
+
run: |
|
|
35
|
+
python -m pip install --upgrade build
|
|
36
|
+
python -m build
|
|
37
|
+
- name: Check metadata
|
|
38
|
+
run: |
|
|
39
|
+
python -m pip install --upgrade twine
|
|
40
|
+
python -m twine check dist/*
|
|
41
|
+
- uses: actions/upload-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: dist
|
|
44
|
+
path: dist/
|
|
45
|
+
|
|
46
|
+
publish:
|
|
47
|
+
needs: build
|
|
48
|
+
runs-on: ubuntu-latest
|
|
49
|
+
# Must match the "Environment name" field of the PyPI pending publisher.
|
|
50
|
+
# PyPI recommends a dedicated environment so that only this job can publish.
|
|
51
|
+
environment: pypi
|
|
52
|
+
permissions:
|
|
53
|
+
id-token: write # required for Trusted Publishing
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/download-artifact@v4
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# --- Python ---
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
.eggs/
|
|
8
|
+
|
|
9
|
+
# --- Virtualenv (project-local, never committed) ---
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
.conda/
|
|
14
|
+
|
|
15
|
+
# --- Test / lint caches ---
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.mypy_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# --- Editors / OS ---
|
|
23
|
+
.vscode/
|
|
24
|
+
.idea/
|
|
25
|
+
*.swp
|
|
26
|
+
.DS_Store
|
|
27
|
+
Thumbs.db
|
|
28
|
+
|
|
29
|
+
# --- Local scratch ---
|
|
30
|
+
*.local.json
|
|
31
|
+
scratch/
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
|
|
5
|
+
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
Rule ids are permanent: once shipped, an id never changes meaning. New rules get
|
|
8
|
+
new ids, and removing a rule is a breaking change.
|
|
9
|
+
|
|
10
|
+
## [Unreleased]
|
|
11
|
+
|
|
12
|
+
## [0.4.0] - 2026-11-07
|
|
13
|
+
|
|
14
|
+
Calibration release, driven by the first run against real servers rather than
|
|
15
|
+
fixtures. Installing `mcp-server-fetch`, `mcp-server-git` and `mcp-server-time`
|
|
16
|
+
and auditing all three produced **Grade F, 0/100, 89 findings across 18 tools**.
|
|
17
|
+
A tool that scores the official reference implementations zero is a tool nobody
|
|
18
|
+
trusts, so the scoring and the report both changed.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **Score is normalised per tool.** Budget is 20 points per tool; a flat
|
|
23
|
+
subtraction punished manifests for being large and scored the official servers
|
|
24
|
+
0/100. Calibrated against four real inputs: clean 100, official servers 87,
|
|
25
|
+
a collision-plus-token config 79, deliberately broken 36.
|
|
26
|
+
- **Info findings are capped at 10 points total.** `AGT022` fired on 18 of 18
|
|
27
|
+
official tools and `AGT023` on 17 of 18 — a rule that fires on everything is a
|
|
28
|
+
preference, not a defect, and charging one point each buried the two findings
|
|
29
|
+
that mattered.
|
|
30
|
+
- **Repeated findings collapse.** Twelve tools missing parameter descriptions now
|
|
31
|
+
print as one line naming all twelve instead of twelve near-identical blocks.
|
|
32
|
+
Info findings are summarised one line per rule. The official-server report went
|
|
33
|
+
from 40 lines to 18.
|
|
34
|
+
- **`AGT011` (short description) is now `info`.** Short is a nudge; *missing* is
|
|
35
|
+
`AGT010`'s error.
|
|
36
|
+
- **`AGT105` (server did not return a tool list) is now `info`.** It means "not
|
|
37
|
+
checked", not "your config is wrong" — it fired on a machine without `npx` and
|
|
38
|
+
dragged the score down for an environment issue.
|
|
39
|
+
- **`AGT107` (plaintext credentials) is now `warning`.** It was `info`, which
|
|
40
|
+
under the new model made a stored token cost nothing.
|
|
41
|
+
|
|
42
|
+
### Added
|
|
43
|
+
|
|
44
|
+
- `tests/test_scoring.py`: score calibration, per-tool normalisation, info cap,
|
|
45
|
+
and aggregation behaviour, including the "12 findings print as one block" case.
|
|
46
|
+
- README section documenting the score model with the four calibration inputs.
|
|
47
|
+
|
|
48
|
+
### Notes
|
|
49
|
+
|
|
50
|
+
- Conflict detection produced **zero false positives** across the 18 real tools
|
|
51
|
+
from the three official servers. That is the number this project lives or dies
|
|
52
|
+
on, and it held.
|
|
53
|
+
|
|
54
|
+
## [0.3.0] - 2026-11-07
|
|
55
|
+
|
|
56
|
+
Distribution release. The tool worked; nobody could reach it from CI.
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **GitHub Action** (`action.yml`). Installs from its own checkout, so pinning
|
|
61
|
+
the action version pins the tool version and a PyPI release is not required.
|
|
62
|
+
Inputs: `config`, `fail-on`, `min-score`, `sarif-file`, `args`. Outputs:
|
|
63
|
+
`score`, `grade`, `findings`, `exit-code` — published even when the gate fails,
|
|
64
|
+
so a workflow can gate on score without parsing the log.
|
|
65
|
+
- `--json-out PATH` and `--sarif-out PATH`. One run now yields the human report,
|
|
66
|
+
machine-readable JSON and SARIF, instead of re-spawning every server to get a
|
|
67
|
+
second format.
|
|
68
|
+
- Config discovery covers **27 paths**: Claude Desktop, Claude Code, Cursor,
|
|
69
|
+
VS Code, Cline, Roo Code, Kilo Code, Windsurf, Zed, Codex CLI, Continue, plus
|
|
70
|
+
project-local files.
|
|
71
|
+
- VS Code's `mcp.servers` nesting and Zed's `context_servers` key are read.
|
|
72
|
+
- Codex CLI's TOML config is parsed via `tomllib` on Python 3.11+, and skipped
|
|
73
|
+
rather than adding a dependency on 3.10.
|
|
74
|
+
- `docs/github-action.md`.
|
|
75
|
+
|
|
76
|
+
### Changed
|
|
77
|
+
|
|
78
|
+
- Cline, Roo Code and Kilo Code paths are generated for every editor flavour on
|
|
79
|
+
every OS. Previously they were hardcoded Windows-only, so macOS and Linux users
|
|
80
|
+
got no Cline coverage at all.
|
|
81
|
+
|
|
82
|
+
### Fixed
|
|
83
|
+
|
|
84
|
+
- `discover()` walked a hardcoded Windows branch for extension paths; it now
|
|
85
|
+
derives from one platform table.
|
|
86
|
+
|
|
87
|
+
## [0.2.0] - 2026-11-07
|
|
88
|
+
|
|
89
|
+
Repositioned from "MCP manifest linter" to "agent setup doctor". The manifest
|
|
90
|
+
rules were already there; what was missing was the one question no other tool
|
|
91
|
+
answers: *what happens when five servers are loaded at once?*
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- **Cross-server conflict detection** (`AGT201`–`AGT203`). Hard name collisions,
|
|
96
|
+
normalised-name collisions, and description overlap between tools from
|
|
97
|
+
different servers. No embeddings, no network — token Jaccard with a shared-head-
|
|
98
|
+
noun guard to keep the false-positive rate usable.
|
|
99
|
+
- **`agentcheckup` with no arguments** now audits everything it can find: Claude
|
|
100
|
+
Desktop, Claude Code (including per-project `mcpServers`), Cursor, Windsurf,
|
|
101
|
+
Cline, and project-local `.mcp.json` / `.cursor/mcp.json` / `.vscode/mcp.json`.
|
|
102
|
+
- **`audit` subcommand** with `--config`, `--no-discover`, `--no-spawn`, `--timeout`.
|
|
103
|
+
- `AGT105` for servers that fail to start or cannot be introspected over stdio.
|
|
104
|
+
Reported and skipped, never fatal.
|
|
105
|
+
- `StdioSession` accepts an argv list and an `env` dict, so servers are launched
|
|
106
|
+
without shell quoting (which matters on Windows) and with the environment their
|
|
107
|
+
config declares.
|
|
108
|
+
- `discovery` module with config discovery and Claude Code's nested project layout.
|
|
109
|
+
- Report splits findings into **CONFLICTS** and **RISKS** sections for `audit`.
|
|
110
|
+
|
|
111
|
+
### Changed
|
|
112
|
+
|
|
113
|
+
- Renamed from `mcplint` to `agentcheckup`; rule prefix `MCP` → `AGT`.
|
|
114
|
+
- `Report` carries `server_count`; JSON output includes it.
|
|
115
|
+
- The text header for `audit` reports servers, tools and tokens on one line.
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- Plural stemming treated `files` as an `-es` plural and produced `fil`, so
|
|
120
|
+
`read_file` and `read_files` were not recognised as the same word.
|
|
121
|
+
- Conflict scoring was name-weighted enough that two tools with 71% description
|
|
122
|
+
overlap scored 0.543 and slipped under a 0.55 threshold. Description overlap is
|
|
123
|
+
now a primary signal, because that is what the model actually reads.
|
|
124
|
+
|
|
125
|
+
## [0.1.0] - 2026-11-07
|
|
126
|
+
|
|
127
|
+
First release. 32 rules, three output formats, two input modes.
|
|
128
|
+
|
|
129
|
+
### Added
|
|
130
|
+
|
|
131
|
+
- `scan` for saved manifests (`{"tools": [...]}`, a bare list, a JSON-RPC
|
|
132
|
+
`result.tools` envelope, or a session log with `messages`) and for live stdio
|
|
133
|
+
servers via `--cmd`.
|
|
134
|
+
- `config` to audit MCP client config files (`mcpServers`, `servers`,
|
|
135
|
+
`mcp_servers`).
|
|
136
|
+
- `rules` to list every rule with its id and severity.
|
|
137
|
+
- 32 rules across naming, documentation, schema, safety, injection, and config.
|
|
138
|
+
- Output formats: `text`, `json`, `sarif` (SARIF 2.1.0 for GitHub code scanning).
|
|
139
|
+
- `--fail-on error|warning|info|never` and `--min-score N` for CI gates.
|
|
140
|
+
- Manifest token estimation, reported on every run.
|
|
141
|
+
- Zero runtime dependencies. Python 3.10+.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Code of Conduct
|
|
2
|
+
|
|
3
|
+
## The short version
|
|
4
|
+
|
|
5
|
+
Be decent. Assume competence. Attack the idea, not the person.
|
|
6
|
+
|
|
7
|
+
## Scope
|
|
8
|
+
|
|
9
|
+
This applies to issues, pull requests, discussions, commit messages, and any
|
|
10
|
+
other space where you are representing this project.
|
|
11
|
+
|
|
12
|
+
## Expected
|
|
13
|
+
|
|
14
|
+
- Critique the code, the rule, or the reasoning — with specifics.
|
|
15
|
+
- Assume the other person knows something you do not. Most rule disagreements
|
|
16
|
+
come from different deployment contexts, not from carelessness.
|
|
17
|
+
- Accept "no" on a PR gracefully. A declined rule is not a judgement of you.
|
|
18
|
+
- Give credit for work you build on.
|
|
19
|
+
|
|
20
|
+
## Not acceptable
|
|
21
|
+
|
|
22
|
+
- Insults, dismissiveness, or "this is obviously wrong" without explanation.
|
|
23
|
+
- Harassment of any kind, public or private.
|
|
24
|
+
- Discriminatory language or imagery.
|
|
25
|
+
- Publishing someone's private information.
|
|
26
|
+
- Sustained disruption of discussions.
|
|
27
|
+
|
|
28
|
+
## Enforcement
|
|
29
|
+
|
|
30
|
+
Maintainers may edit, remove, or reject contributions that violate this, and may
|
|
31
|
+
block repeat offenders. If you need to report something, open a private security
|
|
32
|
+
advisory or contact the maintainer directly.
|
|
33
|
+
|
|
34
|
+
Reports are read by the maintainer and kept confidential.
|
|
35
|
+
|
|
36
|
+
## Attribution
|
|
37
|
+
|
|
38
|
+
This is a short, project-specific code of conduct rather than a full adoption of
|
|
39
|
+
the Contributor Covenant. It is deliberately brief because a long document nobody
|
|
40
|
+
reads protects nobody.
|