ssh-mcp-pro 1.1.5 → 1.2.1
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.
- package/CHANGELOG.md +29 -0
- package/README.md +47 -7
- package/SECURITY.md +4 -0
- package/SECURITY_DECISIONS.md +32 -1
- package/dist/agent-bin.js +0 -0
- package/dist/connector-profile.d.ts +3 -0
- package/dist/connector-profile.d.ts.map +1 -1
- package/dist/connector-profile.js +36 -14
- package/dist/connector-profile.js.map +1 -1
- package/dist/http-security.d.ts.map +1 -1
- package/dist/http-security.js +19 -4
- package/dist/http-security.js.map +1 -1
- package/dist/http-server-lifecycle.d.ts +17 -0
- package/dist/http-server-lifecycle.d.ts.map +1 -0
- package/dist/http-server-lifecycle.js +122 -0
- package/dist/http-server-lifecycle.js.map +1 -0
- package/dist/http-server-router.d.ts +28 -0
- package/dist/http-server-router.d.ts.map +1 -0
- package/dist/http-server-router.js +108 -0
- package/dist/http-server-router.js.map +1 -0
- package/dist/http-server-runtime.d.ts +21 -0
- package/dist/http-server-runtime.d.ts.map +1 -0
- package/dist/http-server-runtime.js +415 -0
- package/dist/http-server-runtime.js.map +1 -0
- package/dist/http-session-registry.d.ts.map +1 -1
- package/dist/http-session-registry.js.map +1 -1
- package/dist/index.js +12 -5
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +8 -1
- package/dist/prompts.js.map +1 -1
- package/dist/remote/agent-cli.d.ts.map +1 -1
- package/dist/remote/agent-cli.js +20 -1
- package/dist/remote/agent-cli.js.map +1 -1
- package/dist/remote/agent-connection-lifecycle.d.ts +47 -0
- package/dist/remote/agent-connection-lifecycle.d.ts.map +1 -0
- package/dist/remote/agent-connection-lifecycle.js +304 -0
- package/dist/remote/agent-connection-lifecycle.js.map +1 -0
- package/dist/remote/agent-executor.d.ts.map +1 -1
- package/dist/remote/agent-executor.js +93 -68
- package/dist/remote/agent-executor.js.map +1 -1
- package/dist/remote/agent-handler.d.ts +22 -8
- package/dist/remote/agent-handler.d.ts.map +1 -1
- package/dist/remote/agent-handler.js +151 -98
- package/dist/remote/agent-handler.js.map +1 -1
- package/dist/remote/config.d.ts.map +1 -1
- package/dist/remote/config.js +14 -0
- package/dist/remote/config.js.map +1 -1
- package/dist/remote/control-plane.d.ts.map +1 -1
- package/dist/remote/control-plane.js +3 -0
- package/dist/remote/control-plane.js.map +1 -1
- package/dist/remote/policy-update-guard.d.ts +14 -0
- package/dist/remote/policy-update-guard.d.ts.map +1 -0
- package/dist/remote/policy-update-guard.js +27 -0
- package/dist/remote/policy-update-guard.js.map +1 -0
- package/dist/remote/policy.d.ts.map +1 -1
- package/dist/remote/policy.js +13 -2
- package/dist/remote/policy.js.map +1 -1
- package/dist/remote/safe-file.d.ts +5 -0
- package/dist/remote/safe-file.d.ts.map +1 -0
- package/dist/remote/safe-file.js +194 -0
- package/dist/remote/safe-file.js.map +1 -0
- package/dist/remote/store.d.ts.map +1 -1
- package/dist/remote/store.js.map +1 -1
- package/dist/remote/types.d.ts +5 -0
- package/dist/remote/types.d.ts.map +1 -1
- package/dist/remote/websocket.d.ts +38 -13
- package/dist/remote/websocket.d.ts.map +1 -1
- package/dist/remote/websocket.js +90 -126
- package/dist/remote/websocket.js.map +1 -1
- package/dist/render-http.js +2 -1
- package/dist/render-http.js.map +1 -1
- package/dist/retry.d.ts.map +1 -1
- package/dist/retry.js +4 -2
- package/dist/retry.js.map +1 -1
- package/dist/server-http.d.ts +1 -1
- package/dist/server-http.d.ts.map +1 -1
- package/dist/server-http.js +1 -421
- package/dist/server-http.js.map +1 -1
- package/dist/tools/connector.provider.d.ts.map +1 -1
- package/dist/tools/connector.provider.js +2 -1
- package/dist/tools/connector.provider.js.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/docs/agent-runtime-config.md +34 -0
- package/docs/development/api-stability.md +44 -0
- package/docs/development/coding-standards.md +35 -0
- package/docs/development/commit-conventions.md +35 -0
- package/docs/development/dependency-management.md +60 -0
- package/docs/development/deprecation-policy.md +29 -0
- package/docs/development/local-setup.md +46 -0
- package/docs/development/release-process.md +57 -0
- package/docs/development/testing-policy.md +47 -0
- package/docs/explanation/architecture.md +44 -0
- package/docs/how-to/README.md +14 -0
- package/docs/how-to/configure-ssh-policy.md +50 -0
- package/docs/openssf-evidence.md +75 -0
- package/docs/openssf-gap-analysis.md +63 -0
- package/docs/openssf-proposal-links.md +37 -0
- package/docs/professionalization-plan.md +81 -0
- package/docs/reference/README.md +21 -0
- package/docs/reference/cli.md +41 -0
- package/docs/reference/compatibility.md +46 -0
- package/docs/reference/configuration.md +72 -0
- package/docs/remote-mcp-hardening.md +10 -0
- package/docs/repo-maturity-report.md +565 -0
- package/docs/security/assurance-case.md +58 -0
- package/docs/security/dependency-audit-exceptions.json +4 -0
- package/docs/security/dependency-audit-exceptions.md +15 -0
- package/docs/security/input-validation.md +54 -0
- package/docs/security/release-integrity.md +28 -0
- package/docs/security/scanning-policy.md +50 -0
- package/docs/security/secrets-management.md +49 -0
- package/docs/security/threat-model.md +65 -0
- package/docs/testing.md +24 -0
- package/docs/troubleshooting.md +56 -0
- package/docs/tutorials/getting-started.md +84 -0
- package/mcp.json +1 -1
- package/package.json +82 -68
- package/registry/ssh-mcp-pro/mcp.json +1 -1
- package/server.json +3 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# API Stability
|
|
2
|
+
|
|
3
|
+
This project has never made an explicit stability statement before this document. It's
|
|
4
|
+
written now to describe intent going forward, not to claim a history of enforcement
|
|
5
|
+
that doesn't exist — see [docs/repo-maturity-report.md](../repo-maturity-report.md)
|
|
6
|
+
("API/CLI stability") for the audit that identified this gap.
|
|
7
|
+
|
|
8
|
+
## What is considered "the public API"
|
|
9
|
+
|
|
10
|
+
For SemVer purposes, going forward:
|
|
11
|
+
|
|
12
|
+
1. **MCP tool/resource/prompt schemas** exposed by the `full` profile — names, required
|
|
13
|
+
parameters, and result shapes. Covered by `test/unit/mcp-contract.test.ts`.
|
|
14
|
+
2. **CLI flags** in `docs/reference/cli.md` (mirrors `src/cli.ts`).
|
|
15
|
+
3. **`SSH_MCP_*` environment variables** and their default values.
|
|
16
|
+
4. **The two published binaries' existence and basic invocation** (`ssh-mcp-pro`,
|
|
17
|
+
`ssh-mcp-pro-agent`).
|
|
18
|
+
|
|
19
|
+
## What is explicitly not covered
|
|
20
|
+
|
|
21
|
+
- Internal module structure under `src/` (anything not re-exported).
|
|
22
|
+
- Exact wording of error messages and log lines.
|
|
23
|
+
- The shape of `SSH_MCP_POLICY_FILE` beyond what's documented — see the config-schema
|
|
24
|
+
gap noted in the maturity report; this will need its own versioning story before it
|
|
25
|
+
can be a stability guarantee.
|
|
26
|
+
- Tool profiles *other than* `full` gaining new tools without a version bump — adding a
|
|
27
|
+
tool to a restricted profile is additive from that profile's consumer's perspective,
|
|
28
|
+
but is still called out here as unresolved: **Needs human confirmation** on whether
|
|
29
|
+
profile membership changes should be treated as SemVer-significant.
|
|
30
|
+
|
|
31
|
+
## What counts as breaking
|
|
32
|
+
|
|
33
|
+
Per Conventional Commits (`!` / `BREAKING CHANGE:` — see
|
|
34
|
+
[commit-conventions.md](commit-conventions.md)): removing or renaming a tool/flag/env
|
|
35
|
+
var, changing a tool's required parameters, changing a default value that changes
|
|
36
|
+
security posture (e.g. flipping a deny-by-default to allow-by-default), or removing a
|
|
37
|
+
supported Node.js version ahead of its own EOL.
|
|
38
|
+
|
|
39
|
+
## Current honest caveat
|
|
40
|
+
|
|
41
|
+
The project is on `1.x` but is 5 days old with zero external consumers on record. This
|
|
42
|
+
policy is aspirational until it's been exercised against a real breaking change and a
|
|
43
|
+
real major version bump — that will be the first real test of whether this document
|
|
44
|
+
holds up in practice.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Coding Standards
|
|
2
|
+
|
|
3
|
+
This is a reference index, not a new rulebook — every rule below is already enforced by
|
|
4
|
+
a config file or CI job. It exists so "what are the coding standards" has one answer
|
|
5
|
+
instead of requiring a tour of five config files.
|
|
6
|
+
|
|
7
|
+
| Concern | Enforced by | Command |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Formatting | [.prettierrc.json](../../.prettierrc.json), [.editorconfig](../../.editorconfig) | `pnpm run format:check` |
|
|
10
|
+
| Linting | [eslint.config.mjs](../../eslint.config.mjs) | `pnpm run lint` |
|
|
11
|
+
| Type safety | [tsconfig.json](../../tsconfig.json) (`strict` mode) | `pnpm run typecheck` |
|
|
12
|
+
| Module size | [scripts/check-module-size.mjs](../../scripts/check-module-size.mjs) | `pnpm run check:module-size` |
|
|
13
|
+
| Circular dependencies | [.dependency-cruiser.mjs](../../.dependency-cruiser.mjs) | `pnpm run check:circular` |
|
|
14
|
+
| Unused code/exports | [knip.jsonc](../../knip.jsonc) | `pnpm run check:knip` |
|
|
15
|
+
| Commit messages | [.commitlintrc.json](../../.commitlintrc.json) | see [commit-conventions.md](commit-conventions.md) |
|
|
16
|
+
| Documentation prose | [scripts/check-doc-language.mjs](../../scripts/check-doc-language.mjs) | `pnpm run check:doc-language` |
|
|
17
|
+
|
|
18
|
+
Run everything at once with `pnpm run check:maintainability` (module size + circular
|
|
19
|
+
deps + unused exports) or `pnpm run check:quality` (formatting, lint, typecheck, audit,
|
|
20
|
+
licenses, and more — see [CONTRIBUTING.md](../../CONTRIBUTING.md) for the full gate).
|
|
21
|
+
|
|
22
|
+
## Security-sensitive code
|
|
23
|
+
|
|
24
|
+
Files covered by [.github/CODEOWNERS](../../.github/CODEOWNERS) (`src/safety.ts`,
|
|
25
|
+
`src/session.ts`, `src/logging.ts`, `src/tools/`) and the mutation-tested surfaces listed
|
|
26
|
+
in [testing-policy.md](testing-policy.md) receive extra scrutiny. Changes there should
|
|
27
|
+
be justified against [SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md), not just
|
|
28
|
+
against passing tests.
|
|
29
|
+
|
|
30
|
+
## Pre-commit / pre-push hooks
|
|
31
|
+
|
|
32
|
+
[.pre-commit-config.yaml](../../.pre-commit-config.yaml) and the git hooks installed by
|
|
33
|
+
`scripts/setup-git-hooks.mjs` (run automatically via the `prepare` npm script) run a
|
|
34
|
+
subset of the above on staged files before commit, and the full `check:push` gate before
|
|
35
|
+
push. See [CONTRIBUTING.md](../../CONTRIBUTING.md#git-hooks) for details.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# Commit Conventions
|
|
2
|
+
|
|
3
|
+
ssh-mcp-pro uses [Conventional Commits](https://www.conventionalcommits.org/), enforced
|
|
4
|
+
by [.commitlintrc.json](../../.commitlintrc.json) and
|
|
5
|
+
[scripts/lint-commits.mjs](../../scripts/lint-commits.mjs) (`pnpm run lint:commits`).
|
|
6
|
+
PR titles are additionally linted by
|
|
7
|
+
[scripts/lint-pr-title.mjs](../../scripts/lint-pr-title.mjs) (`pnpm run lint:pr-title`),
|
|
8
|
+
since release-please derives the changelog and version bump from these.
|
|
9
|
+
|
|
10
|
+
## Format
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
<type>[optional !][: ]<description>
|
|
14
|
+
|
|
15
|
+
[optional body]
|
|
16
|
+
|
|
17
|
+
[optional footer(s)]
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Types in use
|
|
21
|
+
|
|
22
|
+
`feat`, `fix`, `docs`, `test`, `refactor`, `build`, `ci`, `chore` — see
|
|
23
|
+
[CONTRIBUTING.md](../../CONTRIBUTING.md) for the authoritative list and examples.
|
|
24
|
+
|
|
25
|
+
## Breaking changes
|
|
26
|
+
|
|
27
|
+
Mark with `!` after the type (e.g. `feat!:`) or a `BREAKING CHANGE:` footer.
|
|
28
|
+
Release-please uses this to trigger a major version bump and a distinct CHANGELOG
|
|
29
|
+
section — see [docs/development/release-process.md](release-process.md) and
|
|
30
|
+
[MIGRATION.md](../../MIGRATION.md).
|
|
31
|
+
|
|
32
|
+
## Branch naming
|
|
33
|
+
|
|
34
|
+
`feature/*`, `fix/*`, `docs/*`, `chore/*` (and project-specific prefixes such as
|
|
35
|
+
`codex/SSH-*`) — see [CONTRIBUTING.md](../../CONTRIBUTING.md) for current conventions.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Dependency Management
|
|
2
|
+
|
|
3
|
+
## Two update bots, two ecosystems, by design
|
|
4
|
+
|
|
5
|
+
- **[renovate.json](../../renovate.json)** manages the `npm` ecosystem (production and
|
|
6
|
+
dev dependencies). Patch/minor devDependency updates automerge; the MCP SDK
|
|
7
|
+
(`@modelcontextprotocol/sdk`) is explicitly excluded from automerge given how central
|
|
8
|
+
it is; typescript-eslint packages are grouped.
|
|
9
|
+
- **[.github/dependabot.yml](../../.github/dependabot.yml)** manages the
|
|
10
|
+
`github-actions` ecosystem only, weekly, capped at 5 open PRs.
|
|
11
|
+
|
|
12
|
+
npm dependencies are deliberately **not** duplicated into `dependabot.yml` — running two
|
|
13
|
+
bots against the same ecosystem tends to produce competing PRs for the same bump. If
|
|
14
|
+
you're looking for why Dependabot doesn't also open npm PRs, this is why; it's a design
|
|
15
|
+
choice, not an oversight (see the corresponding row in
|
|
16
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md)).
|
|
17
|
+
|
|
18
|
+
## Vulnerability response
|
|
19
|
+
|
|
20
|
+
- `pnpm audit --audit-level moderate` (the `audit` script) runs as part of
|
|
21
|
+
`check:quality`.
|
|
22
|
+
- The `Dependency Review` job in [ci.yml](../../.github/workflows/ci.yml) is the single
|
|
23
|
+
canonical dependency review for pull requests. It uses
|
|
24
|
+
`dependency-review-action` with `fail-on-severity: moderate`, so a newly introduced
|
|
25
|
+
advisory rated moderate, high, or critical blocks the pull request. A second standalone
|
|
26
|
+
dependency-review workflow is intentionally not used because duplicate checks can apply
|
|
27
|
+
contradictory thresholds and create ambiguous merge signals.
|
|
28
|
+
- The same job enforces the repository license allowlist. The allowlist is kept identical
|
|
29
|
+
to [scripts/check-licenses.mjs](../../scripts/check-licenses.mjs) by a regression test;
|
|
30
|
+
changing either policy requires a reviewed pull request that updates both surfaces.
|
|
31
|
+
- GitHub Dependabot alerts (vulnerability scanning, distinct from the version-update
|
|
32
|
+
bot config above) apply automatically on a public GitHub repository. Whether
|
|
33
|
+
"Dependabot security updates" (automatic fix PRs) is enabled is a repository Settings
|
|
34
|
+
toggle — see the manual actions list in the maturity report.
|
|
35
|
+
|
|
36
|
+
### Published artifact verification
|
|
37
|
+
|
|
38
|
+
`pnpm run audit:packed` installs the generated npm tarball in a clean consumer project
|
|
39
|
+
and audits the resolved production graph without inheriting workspace overrides. Any
|
|
40
|
+
remaining finding must match the machine-readable, time-bounded policy in
|
|
41
|
+
[dependency-audit-exceptions.json](../security/dependency-audit-exceptions.json) and the
|
|
42
|
+
public rationale in [Dependency Audit Exceptions](../security/dependency-audit-exceptions.md).
|
|
43
|
+
Unexpected, expired, or stale exceptions fail the package gate.
|
|
44
|
+
|
|
45
|
+
## License compliance
|
|
46
|
+
|
|
47
|
+
[scripts/check-licenses.mjs](../../scripts/check-licenses.mjs) enforces an allowlist
|
|
48
|
+
(MIT, Apache-2.0, BSD-2/3-Clause, BlueOak-1.0.0, CC-\*, ISC, Python-2.0, Unlicense)
|
|
49
|
+
against every resolved dependency, run via `pnpm run licenses:check` as part of
|
|
50
|
+
`check:quality`.
|
|
51
|
+
|
|
52
|
+
## Freshness (advisory)
|
|
53
|
+
|
|
54
|
+
`pnpm run check:freshness` (`scripts/check-dependency-freshness.mjs`) compares the
|
|
55
|
+
pinned Node.js floor, pnpm version, and dependency versions against upstream metadata,
|
|
56
|
+
producing `artifacts/dependency-freshness.{json,md}`. It's advisory unless a pinned
|
|
57
|
+
version is unsupported, EOL, deprecated, or vulnerable — see
|
|
58
|
+
[CONTRIBUTING.md](../../CONTRIBUTING.md) for the exact policy and
|
|
59
|
+
[docs/audit/2026-06-05-ecosystem-audit.md](../audit/2026-06-05-ecosystem-audit.md) for
|
|
60
|
+
the most recent full audit.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Deprecation Policy
|
|
2
|
+
|
|
3
|
+
No formal deprecation has ever happened in this project's history (it's 5 days old at
|
|
4
|
+
time of writing), so this document states intent, not a track record — consistent with
|
|
5
|
+
[docs/development/api-stability.md](api-stability.md).
|
|
6
|
+
|
|
7
|
+
## Policy going forward
|
|
8
|
+
|
|
9
|
+
1. **Announce before removing.** A deprecated tool, flag, or environment variable is
|
|
10
|
+
marked as such in `CHANGELOG.md` and, where feasible, the tool/flag continues to
|
|
11
|
+
function with a warning for at least one minor release before removal.
|
|
12
|
+
2. **Removal is a breaking change.** Per
|
|
13
|
+
[docs/development/api-stability.md](api-stability.md), actual removal happens in a
|
|
14
|
+
major version bump, using Conventional Commits' `!`/`BREAKING CHANGE:` convention.
|
|
15
|
+
3. **Security-driven deprecation is the exception.** If a default or feature is found
|
|
16
|
+
to be actively unsafe (not just superseded), it may be deprecated and disabled faster
|
|
17
|
+
than the normal window, with the rationale documented in
|
|
18
|
+
[SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md) — safety takes priority over the
|
|
19
|
+
standard notice period.
|
|
20
|
+
4. **`MIGRATION.md` is the landing page** for any deprecation that requires action from
|
|
21
|
+
users upgrading between versions.
|
|
22
|
+
|
|
23
|
+
## What this policy does not yet cover
|
|
24
|
+
|
|
25
|
+
- A specific minimum notice period (e.g. "one minor version" vs. "90 days") — left
|
|
26
|
+
unspecified until there's a real deprecation to calibrate against.
|
|
27
|
+
- Deprecation of MCP tool schema fields specifically (as opposed to whole tools) — see
|
|
28
|
+
the open question in [docs/development/api-stability.md](api-stability.md) about
|
|
29
|
+
whether profile/schema changes are SemVer-significant.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Local Setup
|
|
2
|
+
|
|
3
|
+
The authoritative setup steps are in
|
|
4
|
+
[CONTRIBUTING.md#setup](../../CONTRIBUTING.md#setup) — this page doesn't duplicate them,
|
|
5
|
+
it adds the one-command shortcuts.
|
|
6
|
+
|
|
7
|
+
## Fastest path
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
git clone https://github.com/oaslananka/ssh-mcp-pro.git
|
|
11
|
+
cd ssh-mcp-pro
|
|
12
|
+
task install # or: corepack enable && corepack prepare pnpm@11.5.1 --activate && pnpm install --frozen-lockfile
|
|
13
|
+
task verify # lint + format:check + typecheck + test + build
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
[Taskfile.yml](../../Taskfile.yml) wraps the same pnpm scripts CONTRIBUTING.md documents
|
|
17
|
+
— use whichever you prefer; there is no behavioral difference between `task lint` and
|
|
18
|
+
`pnpm run lint`.
|
|
19
|
+
|
|
20
|
+
## What `pnpm run prepare` does
|
|
21
|
+
|
|
22
|
+
Configures `core.hooksPath=.githooks` so pre-commit/pre-push hooks
|
|
23
|
+
(`pnpm run hook:pre-commit`, `pnpm run hook:pre-push`) run automatically. This runs
|
|
24
|
+
automatically after `pnpm install` via the `prepare` script — you don't need to invoke
|
|
25
|
+
it manually unless hooks stop working.
|
|
26
|
+
|
|
27
|
+
## Docker-based integration tests
|
|
28
|
+
|
|
29
|
+
Integration/E2E tests exercise a real SSH fixture via Docker, not a mock:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pnpm run docker:ssh-fixture:up
|
|
33
|
+
pnpm run test:integration
|
|
34
|
+
pnpm run docker:ssh-fixture:down
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
See [docker-compose.yml](../../docker-compose.yml) and
|
|
38
|
+
[Dockerfile.test](../../Dockerfile.test).
|
|
39
|
+
|
|
40
|
+
## No `.devcontainer` (by design, for now)
|
|
41
|
+
|
|
42
|
+
This repo doesn't ship a `.devcontainer/`. Given the toolchain is one `pnpm install`
|
|
43
|
+
away from working and Docker is only needed for integration tests, this was assessed as
|
|
44
|
+
optional rather than required — see "Developer experience maturity" in
|
|
45
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md). Revisit if Windows/macOS
|
|
46
|
+
contributors report toolchain friction that a devcontainer would solve.
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Release Process
|
|
2
|
+
|
|
3
|
+
## Versioning
|
|
4
|
+
|
|
5
|
+
Semantic Versioning, automated by [release-please](https://github.com/googleapis/release-please)
|
|
6
|
+
per [release-please-config.json](../../release-please-config.json) (`node` release
|
|
7
|
+
type). Conventional Commit types on `main` (see
|
|
8
|
+
[commit-conventions.md](commit-conventions.md)) drive whether the next release is a
|
|
9
|
+
patch, minor, or major bump.
|
|
10
|
+
|
|
11
|
+
## How a release happens
|
|
12
|
+
|
|
13
|
+
1. Conventional commits land on `main`.
|
|
14
|
+
2. The `release` job in [.github/workflows/release.yml](../../.github/workflows/release.yml)
|
|
15
|
+
runs `googleapis/release-please-action`, which opens or updates a release PR
|
|
16
|
+
(updating `CHANGELOG.md`, `.release-please-manifest.json`, and the version fields
|
|
17
|
+
release-please is configured to touch — see `extra-files` in
|
|
18
|
+
`release-please-config.json`, which includes `mcp.json`, `server.json`, and the MCP
|
|
19
|
+
registry record).
|
|
20
|
+
3. Merging that PR triggers `release_created`, which runs the `release-assets` job:
|
|
21
|
+
- `pnpm run check` (full quality gate) must pass.
|
|
22
|
+
- `pnpm run sbom` generates a CycloneDX SBOM.
|
|
23
|
+
- The package is packed with `pnpm pack`, and both the tarball and the SBOM get a
|
|
24
|
+
`sha256sum` checksum file.
|
|
25
|
+
- `actions/attest-build-provenance` runs twice — once for the package, once for the
|
|
26
|
+
SBOM — producing verifiable build provenance attestations.
|
|
27
|
+
- All artifacts (tarball, SBOM, checksums) are attached to the GitHub Release.
|
|
28
|
+
- npm publish only happens if the repository variable `AUTO_RELEASE_PUBLISH` is
|
|
29
|
+
`"true"`; otherwise the step is a documented no-op ("npm publishing is disabled by
|
|
30
|
+
AUTO_RELEASE_PUBLISH").
|
|
31
|
+
|
|
32
|
+
## Verifying a release artifact
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
sha256sum -c ssh-mcp-pro-<version>.tgz.sha256
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
For provenance, use [GitHub CLI attestation verification](https://cli.github.com/manual/gh_attestation_verify):
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gh attestation verify ssh-mcp-pro-<version>.tgz --owner oaslananka
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
See [docs/security/release-integrity.md](../security/release-integrity.md) for the full
|
|
45
|
+
supply-chain rationale.
|
|
46
|
+
|
|
47
|
+
## Current status
|
|
48
|
+
|
|
49
|
+
No release has been published yet (repository created 2026-06-28). Release PR #1
|
|
50
|
+
(`chore(main): release ssh-mcp-pro 1.2.0`) is open and is the first opportunity to
|
|
51
|
+
exercise this pipeline end-to-end — see [ROADMAP.md](../../ROADMAP.md).
|
|
52
|
+
|
|
53
|
+
## Container images
|
|
54
|
+
|
|
55
|
+
Published separately by [.github/workflows/docker.yml](../../.github/workflows/docker.yml)
|
|
56
|
+
on tagged releases; see [docs/docker.md](../docker.md) for tag policy and digest-pinned
|
|
57
|
+
usage.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Testing Policy
|
|
2
|
+
|
|
3
|
+
## Test layers
|
|
4
|
+
|
|
5
|
+
Defined in [vitest.config.ts](../../vitest.config.ts) as separate projects:
|
|
6
|
+
|
|
7
|
+
| Project | Location | Run with |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Unit | `test/unit/**` | `pnpm test` |
|
|
10
|
+
| Integration | `test/integration/**` | `pnpm run test:integration` |
|
|
11
|
+
| Windows command-path integration | `test/integration/windows-ssh.integration.test.ts` | `pnpm run test:integration:windows` |
|
|
12
|
+
| E2E | `test/e2e/**` | `pnpm run test:e2e` |
|
|
13
|
+
| Performance | `test/perf/**` | `pnpm run test:perf` (baseline: `test:perf:baseline`) |
|
|
14
|
+
|
|
15
|
+
Integration and E2E projects run sequentially (single worker, no file parallelism) —
|
|
16
|
+
they exercise a real SSH fixture (see `scripts/docker-ssh-fixture.mjs` and
|
|
17
|
+
[docker-compose.yml](../../docker-compose.yml)) and aren't safe to parallelize against
|
|
18
|
+
shared fixture state. Protected CI verifies the Docker fixture before each Linux suite and then checks the generated JUnit report to ensure the env-gated tests executed instead of being silently skipped. Failure runs retain sanitized container state, fixture logs, and JUnit evidence for 14 days.
|
|
19
|
+
|
|
20
|
+
The `Windows Command-Path Integration` job executes PowerShell-capable command selection and Windows package-manager paths locally on a Windows runner. It does not claim a network connection to a real Windows OpenSSH server.
|
|
21
|
+
|
|
22
|
+
## Coverage policy
|
|
23
|
+
|
|
24
|
+
`pnpm run test:coverage` enforces the thresholds in `vitest.config.ts`: 85% branches,
|
|
25
|
+
85% functions, 90% lines, 90% statements repo-wide, with a scoped 75/80/85/85 threshold
|
|
26
|
+
for `src/remote/**` (the remote control-plane surface, which has more integration-only
|
|
27
|
+
paths that are harder to unit-test in isolation). These thresholds are a CI gate, not a
|
|
28
|
+
suggestion — `check:quality`'s downstream `check` script fails the build below them.
|
|
29
|
+
|
|
30
|
+
## Mutation testing
|
|
31
|
+
|
|
32
|
+
`pnpm run test:mutation` runs [Stryker](../../stryker.conf.mjs) against specific line
|
|
33
|
+
ranges in the highest-consequence files: `auth.ts`, `policy.ts`, `safety.ts`,
|
|
34
|
+
`config.ts`, `session.ts`, `http-security.ts`, `oauth.ts`, and the `remote/*` control
|
|
35
|
+
plane. Thresholds are 80% mutation score to be considered healthy, 60% as the floor
|
|
36
|
+
(`break: null`, i.e. advisory rather than a hard CI failure today). See
|
|
37
|
+
[docs/testing.md](../testing.md) for the rationale behind the line-range allowlist and
|
|
38
|
+
promotion criteria for adding more files to it.
|
|
39
|
+
|
|
40
|
+
## What a PR is expected to include
|
|
41
|
+
|
|
42
|
+
Per [CONTRIBUTING.md](../../CONTRIBUTING.md): new functionality needs accompanying
|
|
43
|
+
tests, and `pnpm run check` (which includes `test:coverage`) must pass before a PR is
|
|
44
|
+
considered ready. There is currently no CI gate that *requires* a human reviewer's
|
|
45
|
+
approval before merge (see the branch-protection gap in
|
|
46
|
+
[docs/repo-maturity-report.md](../repo-maturity-report.md)) — treat the automated gate
|
|
47
|
+
as necessary, not sufficient.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Explanation: Architecture
|
|
2
|
+
|
|
3
|
+
This page is explanation-oriented (the "why"), per
|
|
4
|
+
[Diátaxis](https://diataxis.fr/explanation/). For the authoritative system diagram,
|
|
5
|
+
component breakdown, and ADRs, see [ARCHITECTURE.md](../../ARCHITECTURE.md) — this page
|
|
6
|
+
doesn't duplicate that content, it frames it.
|
|
7
|
+
|
|
8
|
+
## Why an MCP server for SSH, specifically
|
|
9
|
+
|
|
10
|
+
Model Context Protocol gives an LLM client a structured, typed set of tools instead of
|
|
11
|
+
free-form shell access. ssh-mcp-pro's core design bet is that "give the model SSH" is
|
|
12
|
+
unsafe as a primitive, but "give the model a curated set of SSH-backed tools, each with
|
|
13
|
+
its own policy check" is a workable middle ground between "no remote access" and
|
|
14
|
+
"unrestricted remote shell." That bet is why the codebase has a dedicated `policy`/
|
|
15
|
+
`safety` layer sitting between tool dispatch and the SSH session, rather than tools
|
|
16
|
+
calling `node-ssh` directly.
|
|
17
|
+
|
|
18
|
+
## Why defaults are deny-by-default
|
|
19
|
+
|
|
20
|
+
Every default documented in [SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md) —
|
|
21
|
+
strict host-key verification, no root login, no raw `sudo`, no destructive commands or
|
|
22
|
+
filesystem operations — exists because the honest threat model for this project is "an
|
|
23
|
+
LLM-driven client with SSH credentials, potentially acting on ambiguous or adversarial
|
|
24
|
+
instructions." See [docs/security/threat-model.md](../security/threat-model.md) for the
|
|
25
|
+
full reasoning. Architecturally, this means the safety checks live close to the tool
|
|
26
|
+
registry (so no tool can bypass them by construction), not scattered per-tool.
|
|
27
|
+
|
|
28
|
+
## Why there's a separate "remote control plane"
|
|
29
|
+
|
|
30
|
+
`src/remote/*` and the `ssh-mcp-pro-agent` binary exist because not every deployment
|
|
31
|
+
wants the MCP server itself reachable from the public internet. The control plane lets
|
|
32
|
+
an operator run a broker that mediates access, so the SSH-capable server can stay on a
|
|
33
|
+
private network while remote clients (ChatGPT connectors, Claude connectors) talk to the
|
|
34
|
+
broker instead. See [docs/remote-mcp-hardening.md](../remote-mcp-hardening.md) for the
|
|
35
|
+
operational guide and [ARCHITECTURE.md](../../ARCHITECTURE.md) for where this sits in
|
|
36
|
+
the request flow.
|
|
37
|
+
|
|
38
|
+
## Why tool profiles exist
|
|
39
|
+
|
|
40
|
+
`SSH_MCP_TOOL_PROFILE` (`full`, `remote-safe`, `chatgpt`, `claude`,
|
|
41
|
+
`remote-readonly`, `remote-broker`) exists because "expose every tool" is the right
|
|
42
|
+
default for a trusted local stdio client, but the wrong default for a remote connector
|
|
43
|
+
serving a broader audience. Profiles are an allowlist, not a denylist, so adding a new
|
|
44
|
+
profile can never accidentally widen an existing one's exposure.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# How-to Guides
|
|
2
|
+
|
|
3
|
+
How-to guides are goal-oriented: they assume you already know the basics (see the
|
|
4
|
+
[tutorial](../tutorials/getting-started.md) if not) and get you to a specific outcome.
|
|
5
|
+
Organized per the [Diátaxis](https://diataxis.fr/how-to-guides/) model.
|
|
6
|
+
|
|
7
|
+
- [How to run ssh-mcp-pro with Docker](../docker.md)
|
|
8
|
+
- [How to onboard a remote device / agent](../adding-a-device.md)
|
|
9
|
+
- [How to harden a public/remote MCP deployment](../remote-mcp-hardening.md)
|
|
10
|
+
- [How to set the SSH host-key and policy defaults](configure-ssh-policy.md)
|
|
11
|
+
|
|
12
|
+
If something's actually broken rather than a task you're trying to accomplish, see
|
|
13
|
+
[Troubleshooting](../troubleshooting.md) instead. If you're looking for exhaustive
|
|
14
|
+
option listings instead of a task, see [Reference](../reference/README.md).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# How to configure the SSH policy
|
|
2
|
+
|
|
3
|
+
This guide walks through the most common policy adjustments. Every setting here is one
|
|
4
|
+
row in the [environment variable reference](../../README.md#configuration) — this guide
|
|
5
|
+
just groups them by task.
|
|
6
|
+
|
|
7
|
+
## Loosen host-key checking for a lab environment
|
|
8
|
+
|
|
9
|
+
By default `SSH_MCP_HOST_KEY_POLICY=strict`, which requires every host to already be in
|
|
10
|
+
`SSH_MCP_KNOWN_HOSTS_PATH`. For a throwaway lab environment where you accept the risk:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
export SSH_MCP_HOST_KEY_POLICY=accept-new
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Do not set this to `insecure` outside of a fully isolated test environment — see
|
|
17
|
+
[SECURITY_DECISIONS.md](../../SECURITY_DECISIONS.md) for why `strict` is the default.
|
|
18
|
+
|
|
19
|
+
## Allow a specific destructive operation
|
|
20
|
+
|
|
21
|
+
Destructive commands and filesystem operations (like `fs_rmrf`) are denied by default.
|
|
22
|
+
To allow them for a specific deployment:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export SSH_MCP_ALLOW_DESTRUCTIVE_COMMANDS=true
|
|
26
|
+
export SSH_MCP_ALLOW_DESTRUCTIVE_FS=true
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Prefer narrowing scope with `SSH_MCP_COMMAND_ALLOW`/`SSH_MCP_COMMAND_DENY` and
|
|
30
|
+
`SSH_MCP_PATH_ALLOW_PREFIXES`/`SSH_MCP_PATH_DENY_PREFIXES` instead of a blanket allow,
|
|
31
|
+
where possible.
|
|
32
|
+
|
|
33
|
+
## Restrict which hosts can be targeted at all
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export SSH_MCP_ALLOWED_HOSTS="bastion.example.com,10.0.0.0/8"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Use a policy file instead of many environment variables
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
export SSH_MCP_POLICY_FILE=/etc/ssh-mcp-pro/policy.json
|
|
43
|
+
export SSH_MCP_POLICY_MODE=enforce
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Set `SSH_MCP_POLICY_MODE=explain` first in a non-production environment to see what the
|
|
47
|
+
policy *would* block without actually enforcing it, before flipping to `enforce`.
|
|
48
|
+
|
|
49
|
+
See [docs/security/input-validation.md](../security/input-validation.md) for how these
|
|
50
|
+
allow/deny lists are evaluated.
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# OpenSSF Best Practices — Evidence
|
|
2
|
+
|
|
3
|
+
Self-assessment against the [OpenSSF Best Practices Passing criteria](https://www.bestpractices.dev/en/criteria/0),
|
|
4
|
+
current as of 2026-07-03. This is a repo-side evidence log, not an official OpenSSF
|
|
5
|
+
artifact — the actual badge is issued by submitting these answers at
|
|
6
|
+
[bestpractices.dev](https://www.bestpractices.dev/). See `.bestpractices.json` for the
|
|
7
|
+
same answers in a structured tracking form used to prepare that submission.
|
|
8
|
+
|
|
9
|
+
Status legend: `Met` / `Partially met` / `Unmet` / `N/A`, matching the badge site's own
|
|
10
|
+
vocabulary.
|
|
11
|
+
|
|
12
|
+
## Basics
|
|
13
|
+
|
|
14
|
+
| Criterion | Status | Evidence |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| Project has a public repository with a version-controlled history | Met | github.com/oaslananka/ssh-mcp-pro |
|
|
17
|
+
| Project uses a common distributed version control system (Git) | Met | Git |
|
|
18
|
+
| Project has FLOSS license | Met | `LICENSE` (MIT), `REUSE.toml` |
|
|
19
|
+
| License is OSI-approved | Met | MIT |
|
|
20
|
+
| Documentation: basic description of purpose | Met | README.md intro |
|
|
21
|
+
| Documentation: how to obtain/provide feedback and contribute | Met | CONTRIBUTING.md, SUPPORT.md |
|
|
22
|
+
| Interim versions/releases are identifiable | Met | Conventional Commits + release-please tagging (pending first tag — see gap analysis) |
|
|
23
|
+
|
|
24
|
+
## Change control
|
|
25
|
+
|
|
26
|
+
| Criterion | Status | Evidence |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Public version-controlled source repository | Met | GitHub |
|
|
29
|
+
| Repository tracks changes with commit-level granularity | Met | Git history |
|
|
30
|
+
| Releases have version numbers following a documented convention | Met | SemVer via release-please |
|
|
31
|
+
| Project has release notes for each new major/minor release | Partially met | `CHANGELOG.md` follows Keep a Changelog; no release has actually been cut yet to verify end-to-end |
|
|
32
|
+
|
|
33
|
+
## Reporting
|
|
34
|
+
|
|
35
|
+
| Criterion | Status | Evidence |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| Project has a process for reporting bugs | Met | Issue templates, `.github/ISSUE_TEMPLATE/config.yml` |
|
|
38
|
+
| Project has a documented vulnerability reporting process | Met | `SECURITY.md` — private advisories, 7-day SLA |
|
|
39
|
+
| Project acknowledges vulnerability reports within a reasonable time | Unmet (no data) | No vulnerability report has been received yet to measure against the documented SLA |
|
|
40
|
+
|
|
41
|
+
## Quality
|
|
42
|
+
|
|
43
|
+
| Criterion | Status | Evidence |
|
|
44
|
+
| --- | --- | --- |
|
|
45
|
+
| Project uses at least one automated test suite | Met | Vitest: unit, integration, e2e, perf projects |
|
|
46
|
+
| Project has FLOSS automated test suite invoked on all commits/PRs | Met | `ci.yml` |
|
|
47
|
+
| New functionality has accompanying tests (documented expectation) | Met | `CONTRIBUTING.md` PR checklist requires it |
|
|
48
|
+
| Project has a general policy for test coverage | Met | `vitest.config.ts` enforces 85–90% thresholds |
|
|
49
|
+
| Project uses continuous integration | Met | `ci.yml` on push/PR/schedule |
|
|
50
|
+
| Project has at least one static analysis tool applied | Met | CodeQL, ESLint, mutation testing (Stryker) |
|
|
51
|
+
| All medium/high-severity static analysis findings are addressed | Met (2026-07-03) | All 8 CodeQL alerts closed: 1 fixed in code, 7 dismissed with rationale re-verified against current code — see `SECURITY_DECISIONS.md`. (Separately, Trivy container-image scanning added the same day found 50+ new findings against the built Docker image, mostly in the base image's bundled tooling rather than this project's source — tracked as an open item in `docs/repo-maturity-report.md`, not part of this specific criterion, which concerns source static analysis) |
|
|
52
|
+
|
|
53
|
+
## Security
|
|
54
|
+
|
|
55
|
+
| Criterion | Status | Evidence |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| Project has a documented security architecture / defaults | Met | SECURITY_DECISIONS.md, README "Security Defaults" |
|
|
58
|
+
| Cryptographic functions use public, well-reviewed protocols | Met | `jose` for JWT/OAuth verification (per `package.json` deps); no bespoke crypto identified |
|
|
59
|
+
| Secrets are not stored in the repository | Met (best-effort) | GitHub secret scanning + push protection enabled; `gitleaks.yml` added by this PR for defense-in-depth history scanning |
|
|
60
|
+
| Delivery mechanisms protect against MITM | Met | npm publish over registry.npmjs.org HTTPS with npm provenance; container images pinned by digest per `docs/docker.md` |
|
|
61
|
+
|
|
62
|
+
## Analysis
|
|
63
|
+
|
|
64
|
+
| Criterion | Status | Evidence |
|
|
65
|
+
| --- | --- | --- |
|
|
66
|
+
| Static analysis applied to any language used | Met | CodeQL (JS/TS query pack) |
|
|
67
|
+
| Dynamic analysis applied | Partially met | Mutation testing (Stryker) exercises runtime behavior of security-critical code paths; no fuzzing harness exists, and none is currently believed necessary (see repo-maturity-report.md, "Fuzzing: Not applicable") |
|
|
68
|
+
|
|
69
|
+
## Bottom line
|
|
70
|
+
|
|
71
|
+
As of 2026-07-03, the CodeQL blocker has been resolved. The remaining blocker is
|
|
72
|
+
"cut a first release," already tracked in [ROADMAP.md](../ROADMAP.md), plus triaging
|
|
73
|
+
the new Trivy container-image findings noted above. Nothing in this evidence log claims
|
|
74
|
+
Silver or Gold; see [docs/openssf-gap-analysis.md](openssf-gap-analysis.md) for why
|
|
75
|
+
those are out of reach right now.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# OpenSSF Gap Analysis
|
|
2
|
+
|
|
3
|
+
This document separates what's achievable now (Passing) from what genuinely requires
|
|
4
|
+
organizational change (Silver, Gold), so that neither this audit nor future readers
|
|
5
|
+
overclaim.
|
|
6
|
+
|
|
7
|
+
## Passing — achievable now
|
|
8
|
+
|
|
9
|
+
See [docs/openssf-evidence.md](openssf-evidence.md) for the full criterion table.
|
|
10
|
+
|
|
11
|
+
~~Seven open CodeQL alerts (one High) with no fully-current documented disposition.~~
|
|
12
|
+
**Resolved 2026-07-03** — see `SECURITY_DECISIONS.md`.
|
|
13
|
+
|
|
14
|
+
The remaining concrete blocker: no release has been cut yet, so "release notes exist
|
|
15
|
+
for each release" is unverified in practice even though the mechanism (release-please +
|
|
16
|
+
CHANGELOG) is implemented. Tracked in [ROADMAP.md](../ROADMAP.md) and as a recommended
|
|
17
|
+
issue in [docs/repo-maturity-report.md](repo-maturity-report.md).
|
|
18
|
+
|
|
19
|
+
A new, unrelated item surfaced the same day: Trivy container-image scanning (added
|
|
20
|
+
after this document was first written) found 50+ open findings against the built
|
|
21
|
+
Docker image — see "Package publishing maturity" in
|
|
22
|
+
[docs/repo-maturity-report.md](repo-maturity-report.md). This doesn't block Passing
|
|
23
|
+
(that criterion concerns source static analysis, not container base-image CVEs) but is
|
|
24
|
+
worth tracking as its own item.
|
|
25
|
+
|
|
26
|
+
## Silver — not yet achievable
|
|
27
|
+
|
|
28
|
+
OpenSSF Best Practices Silver adds requirements this project cannot honestly claim yet,
|
|
29
|
+
specifically:
|
|
30
|
+
|
|
31
|
+
- **Two or more unassociated significant contributors.** Current bus factor is 1
|
|
32
|
+
(single collaborator, `oaslananka`). Silver requires evidence of contribution from
|
|
33
|
+
people not all affiliated with the same entity.
|
|
34
|
+
- **A documented process for reviewing and responding to bug reports within a
|
|
35
|
+
well-defined window, evidenced by actual history.** The process is documented
|
|
36
|
+
(`SECURITY.md`, `SUPPORT.md`), but there is no report history yet to evidence it.
|
|
37
|
+
- **Basic floor for cryptographic practices is fully documented** (partially met —
|
|
38
|
+
`SECURITY_DECISIONS.md` covers several defaults but doesn't exhaustively enumerate
|
|
39
|
+
every cryptographic operation in the codebase).
|
|
40
|
+
|
|
41
|
+
**What would need to change:** a second active contributor with merged, substantive
|
|
42
|
+
PRs; at least one real vulnerability report handled end-to-end; and a pass over
|
|
43
|
+
`SECURITY_DECISIONS.md` to make the cryptographic inventory exhaustive.
|
|
44
|
+
|
|
45
|
+
## Gold — explicitly out of scope for a claim today
|
|
46
|
+
|
|
47
|
+
Per the audit's own instructions, Gold is only evaluated as a gap list when its
|
|
48
|
+
preconditions are absent — and they are absent here:
|
|
49
|
+
|
|
50
|
+
| Gold precondition | Current state |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Multiple active maintainers | 1 (see MAINTAINERS.md) |
|
|
53
|
+
| Independent contributor/reviewer | 0 non-bot PRs have ever been opened |
|
|
54
|
+
| Regular human PR review | 0 human-reviewed PRs to date |
|
|
55
|
+
| Branch protection | Not applied on GitHub (ruleset JSON exists but unapplied) |
|
|
56
|
+
| Sustainable governance | Solo-maintainer model, honestly documented in GOVERNANCE.md, not yet a multi-party governance structure |
|
|
57
|
+
| High test coverage sustained over time | Coverage thresholds exist (85–90%) but "sustained over time" needs release/version history that doesn't exist yet (repo is 5 days old) |
|
|
58
|
+
| Repeatable/reproducible release process | Implemented (SBOM, checksums, provenance) but never executed — zero releases published |
|
|
59
|
+
|
|
60
|
+
**This is a gap list, not a target with a date.** None of these should be worked toward
|
|
61
|
+
by editing files; they require either time (release/contribution history accruing
|
|
62
|
+
naturally) or a maintainer decision (branch protection, recruiting a co-maintainer).
|
|
63
|
+
Revisit this analysis after the "Silver" preconditions above are met.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# OpenSSF Proposal Links
|
|
2
|
+
|
|
3
|
+
Reference links for acting on the findings in
|
|
4
|
+
[docs/repo-maturity-report.md](repo-maturity-report.md) and
|
|
5
|
+
[docs/openssf-gap-analysis.md](openssf-gap-analysis.md). These are pointers to where a
|
|
6
|
+
maintainer takes the next action, not automated submissions — no badge or scorecard
|
|
7
|
+
submission has been made on the project's behalf by this audit.
|
|
8
|
+
|
|
9
|
+
## OpenSSF Best Practices badge
|
|
10
|
+
|
|
11
|
+
- Self-assessment form (submit once the CodeQL/first-release gaps in
|
|
12
|
+
`docs/openssf-gap-analysis.md` close): <https://www.bestpractices.dev/en/projects/new>
|
|
13
|
+
- Full criteria reference used for this audit: <https://www.bestpractices.dev/en/criteria/0>
|
|
14
|
+
- `.bestpractices.json` in the repo root tracks current self-assessment answers to make
|
|
15
|
+
filling out the form above mechanical.
|
|
16
|
+
|
|
17
|
+
## OpenSSF Scorecard
|
|
18
|
+
|
|
19
|
+
- Public checks reference: <https://github.com/ossf/scorecard/blob/main/docs/checks.md>
|
|
20
|
+
- Scorecard viewer for this repo (once `publish_results` is re-enabled or a manual run
|
|
21
|
+
is published): <https://securityscorecards.dev/viewer/?uri=github.com/oaslananka/ssh-mcp-pro>
|
|
22
|
+
- `ossf/scorecard-action` documentation for the `publish_results` requirements that are
|
|
23
|
+
currently blocking automatic publication: <https://github.com/ossf/scorecard-action#authenticated-workflow>
|
|
24
|
+
|
|
25
|
+
## GitHub repository configuration referenced by this audit
|
|
26
|
+
|
|
27
|
+
- Branch protection settings: `https://github.com/oaslananka/ssh-mcp-pro/settings/branches`
|
|
28
|
+
- Rulesets (to import `.github/rulesets/main-protection.json`):
|
|
29
|
+
`https://github.com/oaslananka/ssh-mcp-pro/settings/rules`
|
|
30
|
+
- Security & analysis settings (private vulnerability reporting, Dependabot security
|
|
31
|
+
updates): `https://github.com/oaslananka/ssh-mcp-pro/settings/security_analysis`
|
|
32
|
+
- Code scanning alerts: `https://github.com/oaslananka/ssh-mcp-pro/security/code-scanning`
|
|
33
|
+
|
|
34
|
+
## CHAOSS
|
|
35
|
+
|
|
36
|
+
- Metrics reference used for the Community maturity section:
|
|
37
|
+
<https://chaoss.community/metrics/>
|