Skip to content

Commit 4f8262f

Browse files
authored
1.0.0 readiness: version-resolution, parser, security, and release fixes (#28)
* chore(release): bump workspace to 1.0.0 and add package metadata Set the workspace version to 1.0.0 and add distribution metadata: license (MIT), rust-version (1.85, matching edition 2024), repository, description, readme, keywords, categories, and publish = false (the project ships as a binary via release artifacts and `cargo install --path .`, not to crates.io). Add the semver dependency to the core crate for version-requirement resolution. * fix(checks): resolve ranged/partial versions and normalize policy names check_package forwarded the raw requested version to an exact-match lookup, so a range or partial requirement (`react` "18", "^4.17.0", `serde` "1", `requests` ">=2") was denied as a nonexistent "hallucinated" version — a false block on the primary agent workflow, on all three registries. Resolve the requirement per ecosystem to the best matching published version (semver for npm/cargo, PEP 440 specifiers for PyPI); only a concrete exact version that is genuinely absent is still flagged. Also compare canonical names in denylist/allowlist/dependency-confusion matching so an equivalent spelling (case, and `-`/`_`/`.` per PyPI/crates.io rules) cannot bypass a rule (e.g. denylisting `evil-pkg` now also blocks `evil_pkg`). * fix(parsers): skip non-registry deps and split PyPI specifiers correctly npm and PyPI manifests emitted local/git/URL dependencies as if they were registry packages, producing false "does not exist" findings for a project's own path/git/private deps (cargo already filtered these). Skip `file:`, git, tarball-URL, and `workspace:`/`link:` (npm) and `path`/`git`/`url` (Poetry) and PEP 508 `name @ url` dependencies; resolve npm aliases (`npm:real-pkg@1.2.3`) to the real target. PyPI requirement lines were split by operator list-order, so multi-specifier lines like `torch>1.9,<2.0` and `numpy!=1.24.0,>=1.20` were mis-split and silently dropped. Split on the leftmost operator instead. * fix(mcp): advertise safe-pkgs server identity to MCP hosts get_info did not set server_info, so rmcp reported its own crate name and version (`rmcp`/<rmcp version>) to every MCP host. Advertise the crate's own name and version instead. * fix(registry): only send bearer token over secure transport The npm and PyPI clients attached a private-registry bearer token unconditionally, while the base URL is env-overridable to http://, so a token could be sent in cleartext to a remote mirror. Gate the token on HTTPS (or an http loopback host for local testing), mirroring the audit and remote-config guards. The token is still sent only to the metadata host, never to the downloads or popularity hosts. * docs+ci: correct README, gate the workspace in CI, add CHANGELOG Fix the README rmcp badge (1.x) and the decision-payload metadata note (advisories are evidence, not metadata). Run clippy and test with --workspace so every crate is gated in CI. Add a 1.0.0 CHANGELOG and ignore stray .tmp/.cache/WORKFLOW.md.
1 parent 0594e45 commit 4f8262f

16 files changed

Lines changed: 517 additions & 57 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ jobs:
3535
run: cargo fmt --all -- --check
3636

3737
- name: Lint with Clippy
38-
run: cargo clippy --all-targets -- -D warnings
38+
run: cargo clippy --workspace --all-targets -- -D warnings
3939

4040
- name: Run tests
4141
shell: bash
4242
run: |
4343
set -o pipefail
44-
cargo test 2>&1 | tee test-output.log
44+
cargo test --workspace 2>&1 | tee test-output.log
4545
test_status=${PIPESTATUS[0]}
4646
4747
# Emit inline annotations for panic locations so PR diffs highlight failures.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
/target
22
.claude
33
/site
4+
.cache
5+
.tmp
6+
WORKFLOW.md

CHANGELOG.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Changelog
2+
3+
All notable changes to this project are documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] - 2026-07-20
9+
10+
First stable release. This release focuses on correctness of version and dependency
11+
handling across all three ecosystems, plus security and release hardening.
12+
13+
### Fixed
14+
15+
- **`check_package` now accepts ranged and partial versions.** A request such as
16+
`check_package(name="react", version="18")`, `"^4.17.0"`, `serde "1"`, or
17+
`requests ">=2"` was previously denied as a nonexistent ("hallucinated") version.
18+
Version requirements are now resolved per ecosystem to the best matching published
19+
version; only a concrete exact version that is genuinely absent is flagged.
20+
- **npm/PyPI manifests no longer flag local, git, and URL dependencies.** `file:`,
21+
`git`/`github:`, tarball URL, `workspace:`/`link:` (npm) and `path`/`git`/`url`
22+
(Poetry) and PEP 508 `name @ url` dependencies are skipped rather than looked up on
23+
the public registry and reported as nonexistent. npm aliases (`npm:real-pkg@1.2.3`)
24+
now audit the real target.
25+
- **PyPI requirement lines with multiple specifiers are no longer dropped.** Lines such
26+
as `torch>1.9,<2.0` and `numpy!=1.24.0,>=1.20` are now split on the leftmost
27+
operator and audited instead of being silently skipped.
28+
- **Denylist, allowlist, and dependency-confusion matching now compare canonical
29+
names.** An equivalent spelling (case, and `-`/`_`/`.` per PyPI/crates.io rules) can
30+
no longer bypass a rule (for example, a denylisted `evil-pkg` now also blocks
31+
`evil_pkg`).
32+
- **The MCP server now advertises its own identity** (`safe-pkgs`/version) instead of
33+
the underlying `rmcp` crate name and version.
34+
- Private-registry bearer tokens are no longer sent over cleartext `http://` (except to
35+
loopback hosts), matching the audit and remote-config guards.
36+
37+
### Changed
38+
39+
- Version bumped to `1.0.0`.
40+
- Package metadata added for distribution: `license = "MIT"`, `rust-version = "1.85"`,
41+
`repository`, `description`; the workspace is marked `publish = false` (distributed as
42+
a binary via release artifacts and `cargo install --path .`).
43+
- CI now runs `clippy` and `test` with `--workspace`, so all crates are gated.
44+
- README: corrected the rmcp version badge and the decision-payload `metadata` note.
45+
46+
### Known limitations
47+
48+
- A lockfile that pins the same package at multiple versions (for example
49+
`windows-sys` 0.48 and 0.52 in a `Cargo.lock`) is currently audited at a single
50+
version; the other pinned version is not evaluated. This is tracked for a follow-up
51+
release.

Cargo.lock

Lines changed: 15 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@ members = [
1010
resolver = "2"
1111

1212
[workspace.package]
13-
version = "0.2.0"
13+
version = "1.0.0"
1414
edition = "2024"
15+
rust-version = "1.85"
16+
license = "MIT"
17+
repository = "https://github.com/math280h/safe-pkgs"
1518

1619
[workspace.dependencies]
1720
anyhow = "1"
@@ -37,6 +40,15 @@ wiremock = "0.6"
3740
name = "safe-pkgs"
3841
version.workspace = true
3942
edition.workspace = true
43+
rust-version.workspace = true
44+
license.workspace = true
45+
repository.workspace = true
46+
description = "Package safety checks for AI agents before install — MCP server + CLI with allow/deny decisions, risk scoring, and audit logs."
47+
readme = "README.md"
48+
keywords = ["mcp", "security", "supply-chain", "dependencies", "cli"]
49+
categories = ["command-line-utilities", "development-tools"]
50+
# Distributed as a binary (cargo install --path . / release binaries), not published to crates.io.
51+
publish = false
4052

4153
[dependencies]
4254
# External dependencies

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
<p align="center">
1414
<img src="https://img.shields.io/badge/rust-stable-orange" alt="Rust" />
15-
<img src="https://img.shields.io/badge/MCP-rmcp%200.15-blue" alt="MCP" />
15+
<img src="https://img.shields.io/badge/MCP-rmcp%201.x-blue" alt="MCP" />
1616
<img src="https://img.shields.io/badge/cache-SQLite-green" alt="Cache" />
1717
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fmath280h.github.io%2Fsafe-pkgs%2Fbadges%2Fcoverage.json" alt="Coverage" />
1818
</p>
@@ -41,7 +41,7 @@ Decision payload includes:
4141
- `risk`: `low | medium | high | critical`
4242
- `reasons`: human-readable findings
4343
- `evidence`: structured findings (`kind`, stable `id`, `severity`, `message`, `facts`)
44-
- `metadata`: package context (latest, publish date, downloads, advisories)
44+
- `metadata`: package context (latest, publish date, downloads)
4545
- `fingerprints`: deterministic hashes (`config`, `policy`)
4646

4747
## Install + Run in 60 Seconds

crates/core/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition.workspace = true
66
[dependencies]
77
async-trait.workspace = true
88
chrono.workspace = true
9+
semver.workspace = true
910
serde.workspace = true
1011
thiserror.workspace = true
1112

0 commit comments

Comments
 (0)