Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,15 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2
# Core build (no MCP) guards the no-feature path used by release.yml.
# Core build (no MCP) guards the --no-default-features path used by release.yml.
- run: cargo build --release --no-default-features
# Default build now includes `mcp`, so this builds all binaries.
- run: cargo build --release
- run: cargo build --release --features mcp
# --features mcp is required for tests/hosts.rs.
# `mcp` is a default feature, so tests/hosts.rs runs without an extra flag.
# TODO: drop the --skip once "Stabilize the flaky S2 resource-cap test"
# (backlog.md) lands — burst_connections_above_cap_get_busy_response is
# timing-flaky in its setup assertion, not its security assertion.
- run: cargo test --features mcp -- --skip burst_connections_above_cap_get_busy_response
- run: cargo test -- --skip burst_connections_above_cap_get_busy_response

audit:
name: cargo audit
Expand Down
61 changes: 61 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: Publish

# Cut a release by pushing a `v*` tag (see CLAUDE.md). This publishes the crate
# to crates.io via Trusted Publishing (OIDC, no stored token) and then registers
# the server in the official MCP Registry via GitHub Actions OIDC, which grants
# the `io.github.tarides` namespace from the repo owner. release.yml builds the
# static tarball + GitHub release on the same tag, in parallel.

on:
push:
tags:
- "v*"

permissions:
id-token: write # OIDC for both crates.io Trusted Publishing and mcp-publisher
contents: read

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: Swatinem/rust-cache@v2

# crates.io Trusted Publishing: exchange the OIDC token for a short-lived
# publish token (configured at crates.io -> sudo-proxy -> Trusted Publishing).
- name: Authenticate to crates.io
uses: rust-lang/crates-io-auth-action@v1
id: auth

- name: Publish crate to crates.io
run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

# The MCP Registry validates ownership by reading the `mcp-name:` marker
# and the version from the crate on crates.io, so the crate must be served
# before we publish the server. Poll until the index catches up.
- name: Wait for crate to be live on crates.io
run: |
VERSION="${GITHUB_REF_NAME#v}"
for i in $(seq 1 30); do
if curl -fsS "https://crates.io/api/v1/crates/sudo-proxy/${VERSION}" >/dev/null; then
echo "sudo-proxy ${VERSION} is live"
exit 0
fi
echo "waiting for sudo-proxy ${VERSION} (attempt ${i})..."
sleep 10
done
echo "crate ${VERSION} did not appear on crates.io in time" >&2
exit 1

- name: Install mcp-publisher
run: |
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher

- name: Authenticate to MCP Registry
run: ./mcp-publisher login github-oidc

- name: Publish server to MCP Registry
run: ./mcp-publisher publish
4 changes: 2 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ jobs:
run: sudo apt-get update && sudo apt-get install -y musl-tools

- name: Build core binaries (no MCP)
run: cargo build --release --target x86_64-unknown-linux-musl
run: cargo build --release --target x86_64-unknown-linux-musl --no-default-features

- name: Build all binaries (with MCP)
run: cargo build --release --target x86_64-unknown-linux-musl --features mcp
run: cargo build --release --target x86_64-unknown-linux-musl

- name: Package tarball
run: |
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
## Build

```bash
cargo build --release --features mcp # all binaries
cargo build --release # core only (no MCP server)
cargo build --release # all binaries (mcp is a default feature)
cargo build --release --no-default-features # core only (no MCP server)
```

## Version bumps
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "sudo-proxy"
version = "0.12.0"
version = "1.0.0"
edition = "2021"
license = "MIT"
description = "Privileged command execution proxy with human approval via pkexec or sudo"
Expand Down Expand Up @@ -31,7 +31,11 @@ required-features = ["mcp"]
name = "sudo_proxy"
path = "src/lib.rs"

# `mcp` is on by default so `cargo install sudo-proxy` builds the
# `sudo-proxy-mcp` binary (the MCP Registry's cargo install path uses no extra
# flags). Build the core binaries alone with `--no-default-features`.
[features]
default = ["mcp"]
mcp = ["dep:rmcp", "dep:tokio", "dep:schemars"]

[lints.rust]
Expand Down
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ Install the binaries (needs a Rust toolchain; prebuilt static binaries are
on [Releases](https://github.com/tarides/sudo-proxy/releases)):

```bash
cargo install sudo-proxy --features mcp
cargo install sudo-proxy
```

Point your MCP client at the server — add to the project's `.mcp.json` or
Expand Down Expand Up @@ -77,6 +77,11 @@ Each `execute` shows the exact command in the TUI; press `y` to approve,
`N` (default) to deny. For remote hosts, pass `host` to `start_server` and
`execute`.

## MCP Registry

Listed in the official [MCP Registry](https://registry.modelcontextprotocol.io)
as `mcp-name: io.github.tarides/sudo-proxy`.

## Documentation

- [docs/install.md](docs/install.md) — install variants, remote deploy, building from source
Expand Down
21 changes: 11 additions & 10 deletions docs/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@
## From crates.io (with Rust toolchain)

```bash
# Core binaries only (sudo-proxy, sudo-request, pkexec-cache)
# Everything including the MCP server (mcp is a default feature)
cargo install sudo-proxy

# Everything including the MCP server
cargo install sudo-proxy --features mcp
# Core binaries only (sudo-proxy, sudo-request, pkexec-cache)
cargo install sudo-proxy --no-default-features
```

## From git (development version)

```bash
cargo install --git ssh://git@github.com/tarides/sudo-proxy.git --features mcp
cargo install --git ssh://git@github.com/tarides/sudo-proxy.git
```

The MCP server depends on `rmcp`, `tokio`, and `schemars`. These are
behind the `mcp` Cargo feature so the core binaries stay lean and compile
fast.
The MCP server depends on `rmcp`, `tokio`, and `schemars`. These are behind
the `mcp` Cargo feature, which is **on by default**. Pass
`--no-default-features` to build only the core binaries (no `rmcp`/`tokio`/
`schemars`), e.g. on a remote host that just needs the `sudo-proxy` server.

| Binary | Feature | Purpose |
|---|---|---|
Expand Down Expand Up @@ -54,7 +55,7 @@ remote side are SSH access and the `sudo-proxy` binary in `$PATH`.
Install all binaries and optionally set up polkit auth caching:

```bash
cargo install sudo-proxy --features mcp
cargo install sudo-proxy

# Optional: cache pkexec auth for ~5 minutes (like sudo)
sudo pkexec-cache --create
Expand All @@ -65,8 +66,8 @@ Then configure your MCP client — see [MCP server](mcp.md).
## Building locally

```bash
cargo build --release # core only
cargo build --release --features mcp # all
cargo build --release # all binaries (mcp is default)
cargo build --release --no-default-features # core only
```

## Cargo dependencies
Expand Down
Loading
Loading