Skip to content
Draft
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
10 changes: 7 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
## Setup

```bash
git clone https://github.com/thisrohangupta/harness-mcp-v2.git
cd harness-mcp-v2
git clone https://github.com/harness/mcp-server.git
cd mcp-server
pnpm install
pnpm build
```
Expand All @@ -24,6 +24,10 @@ pnpm typecheck # Type-check without emitting
pnpm test # Run all tests
pnpm test:watch # Run tests in watch mode
pnpm inspect # Launch MCP Inspector for interactive testing
pnpm docs:generate # Refresh generated README counts from the built registry
pnpm docs:check # Verify README counts and clone instructions are current
pnpm sync-schemas # Refresh checked-in JSON Schemas for harness_schema
pnpm check-schema-coverage # Verify schema examples cover registered schemas
```

## Project Structure
Expand All @@ -38,7 +42,7 @@ src/
index.ts # Registry class + dispatch logic
types.ts # ResourceDefinition, ToolsetDefinition, etc.
toolsets/ # One file per toolset (declarative data)
tools/ # 10 generic MCP tools (thin dispatch wrappers)
tools/ # 11 generic MCP tools (thin dispatch wrappers, including harness_schema)
resources/ # MCP resource providers
prompts/ # MCP prompt templates
utils/ # Errors, logger, rate limiter, deep links, etc.
Expand Down
21 changes: 20 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -1260,6 +1260,14 @@ SEI resources are consolidated for token efficiency. Use `metric` or `aspect` pa
| `security_issue_filter` | x | | | | | |
| `security_exemption` | x | | | | | `approve`, `reject`, `promote` |

Security exemption execute workflow:

- Use `harness_list` with `resource_type="security_exemption"` and an explicit `status` such as `Pending`, `Approved`, `Rejected`, `Expired`, or `Canceled`.
- Use `harness_execute` with `action="approve"` only for project-level approval. The server auto-fills `body.approver_id` from the authenticated user when omitted; `body.comment` is optional.
- Use `action="reject"` to reject an exemption. `body.approver_id` is also auto-filled when omitted.
- Use `action="promote"` directly when the requested outcome is approval plus promotion to another scope. Do not call `approve` first for org, account, pipeline, or target promotion.
- Promotion requires `body.scope`: `ACCOUNT`, `ORG`, `PROJECT`, `PIPELINE`, or `TARGET`. For `PIPELINE`, also pass `body.pipeline_id`; for `TARGET`, also pass `body.target_id`.


### Access Control

Expand Down Expand Up @@ -1576,6 +1584,16 @@ pnpm test:watch

# Interactive MCP Inspector
pnpm inspect

# Refresh generated README counts from the built registry
pnpm docs:generate

# Verify README counts and clone instructions are current
pnpm docs:check

# Sync and verify JSON Schemas used by harness_schema
pnpm sync-schemas
pnpm check-schema-coverage
```

### Project Structure
Expand All @@ -1597,7 +1615,7 @@ src/
ccm.ts
access-control.ts
...
tools/ # 10 generic MCP tools
tools/ # 11 generic MCP tools
harness-list.ts
harness-get.ts
harness-create.ts
Expand All @@ -1608,6 +1626,7 @@ src/
harness-diagnose.ts
harness-describe.ts
harness-status.ts
harness-schema.ts

resources/ # MCP resource providers
pipeline-yaml.ts
Expand Down
11 changes: 6 additions & 5 deletions docs/gemini.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Harness MCP Server — Gemini CLI Context

This extension connects Gemini CLI to the Harness Platform through 10 consolidated MCP tools that cover 137 resource types across 29 toolsets.
This extension connects Gemini CLI to the Harness Platform through 11 consolidated MCP tools that cover 169 resource types across 31 toolsets.

## How This Server Works

Expand All @@ -23,6 +23,7 @@ Unlike traditional MCP servers with one tool per API endpoint, this server uses
- `harness_search` — Search across multiple resource types at once
- `harness_diagnose` — Diagnose pipelines, connectors, delegates, and GitOps applications
- `harness_status` — Project health overview: failed, running, and recent executions
- `harness_schema` — Fetch exact JSON Schemas for creating or updating supported resources

## Available Capabilities

Expand Down Expand Up @@ -50,7 +51,7 @@ Unlike traditional MCP servers with one tool per API endpoint, this server uses
- Track commitment coverage, utilisation, and savings

### Security & Compliance
- Security Test Orchestration (STO): manage issues, approve/reject exemptions
- Security Test Orchestration (STO): manage issues; approve, reject, or promote exemptions with explicit scope
- Supply Chain Security (SCS): track artifacts, compliance, SBOMs, chain of custody
- Audit trail: comprehensive audit logs for governance

Expand Down Expand Up @@ -125,8 +126,8 @@ Secret values are never exposed — only metadata (name, type, scope).
```
HARNESS_API_KEY=pat.xxxxx.xxxxx.xxxxx
HARNESS_ACCOUNT_ID=your_account_id # Optional for PATs, required for non-PAT API keys
HARNESS_ORG=default
HARNESS_PROJECT=your_project
HARNESS_ORG=your_org_id # Optional default; omit to pass org_id per request
HARNESS_PROJECT=your_project_id # Optional default; omit to pass project_id per request
HARNESS_RATE_LIMIT_RPS=10 # Optional: client-side throttling
HARNESS_MAX_BODY_SIZE_MB=10 # Optional: HTTP mode request size limit
```
Expand All @@ -146,4 +147,4 @@ Secret values are never exposed — only metadata (name, type, scope).

**Toolset filtering:**
- Set `HARNESS_TOOLSETS=pipelines,services,connectors` in `.env` to limit which resource types are available
- Leave empty to enable all 29 toolsets
- Leave empty to enable all default toolsets
24 changes: 13 additions & 11 deletions docs/testing/security_exemption/test_plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@
| TC-se-007 | List | Combined status + search | `harness_list(resource_type="security_exemption", status="Pending", search="critical")` | Returns Pending exemptions matching search |
| TC-se-008 | List | Pagination - page 0, size 5 | `harness_list(resource_type="security_exemption", page=0, size=5)` | Returns first 5 exemptions |
| TC-se-009 | List | Pagination - page 1 | `harness_list(resource_type="security_exemption", page=1, size=5)` | Returns second page of exemptions |
| TC-se-010 | Execute | Approve exemption | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Approved"})` | Exemption status changes to Approved |
| TC-se-011 | Execute | Approve without comment | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={approver_id: "<uuid>"})` | Exemption approved without comment |
| TC-se-012 | Execute | Reject exemption | `harness_execute(resource_type="security_exemption", action="reject", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Rejected - risk too high"})` | Exemption status changes to Rejected |
| TC-se-013 | Execute | Promote exemption | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Promoting to org level"})` | Exemption promoted to org/account level |
| TC-se-014 | Execute | Promote with pipeline_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", pipeline_id: "<pid>"})` | Exemption promoted scoped to pipeline |
| TC-se-015 | Execute | Promote with target_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", target_id: "<tid>"})` | Exemption promoted scoped to target |
| TC-se-010 | Execute | Approve exemption at project scope | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={comment: "Approved"})` | Exemption is approved at project scope; server auto-fills approver_id from the authenticated user |
| TC-se-011 | Execute | Approve without body | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>")` | Exemption is approved without a comment; server auto-fills approver_id |
| TC-se-012 | Execute | Reject exemption | `harness_execute(resource_type="security_exemption", action="reject", exemption_id="<id>", body={comment: "Rejected - risk too high"})` | Exemption is rejected; server auto-fills approver_id |
| TC-se-013 | Execute | Promote exemption to org scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "ORG", comment: "Promoting to org level"})` | Exemption is approved and promoted to org scope in one call |
| TC-se-014 | Execute | Promote with pipeline_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "PIPELINE", pipeline_id: "<pid>"})` | Exemption is approved and promoted to the specified pipeline scope |
| TC-se-015 | Execute | Promote with target_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "TARGET", target_id: "<tid>"})` | Exemption is approved and promoted to the specified target scope |
| TC-se-016 | Scope | Custom org and project | `harness_list(resource_type="security_exemption", org_id="custom_org", project_id="custom_project")` | Returns exemptions for specified org/project |
| TC-se-017 | Error | Approve without approver_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={})` | Returns validation error — approver_id required |
| TC-se-018 | Error | Invalid exemption_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="nonexistent", body={approver_id: "<uuid>"})` | Returns not found error |
| TC-se-017 | Error | Promote without scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={comment: "Missing scope"})` | Returns validation or API error because promote requires `body.scope` |
| TC-se-018 | Error | Invalid exemption_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="nonexistent", body={comment: "Approved"})` | Returns not found error |
| TC-se-019 | Error | Invalid action name | `harness_execute(resource_type="security_exemption", action="invalid_action", exemption_id="<id>")` | Returns error — unknown action |
| TC-se-020 | Edge | Approve already-approved exemption | `harness_execute(resource_type="security_exemption", action="approve", ...)` on approved exemption | Returns error or idempotent success |
| TC-se-021 | Describe | Resource metadata | `harness_describe(resource_type="security_exemption")` | Returns metadata with execute actions (approve, reject, promote) and body schemas |
Expand All @@ -43,7 +43,9 @@
- List endpoint is POST-based at `/sto/api/v2/frontend/exemptions`
- status filter enum: Pending, Approved, Rejected, Expired, Canceled
- Execute actions use PUT method with path params
- approve body: `approver_id` (required), `comment` (optional)
- reject body: `approver_id` (required), `comment` (optional)
- promote body: `approver_id` (required), `comment` (optional), `pipeline_id` (optional), `target_id` (optional)
- approve is for project-scope approval only. Do not use it before org/account/pipeline/target promotion.
- approve body: `approver_id` (optional; auto-derived from authenticated user), `comment` (optional)
- reject body: `approver_id` (optional; auto-derived from authenticated user), `comment` (optional)
- promote approves and promotes in one call; call it directly for ACCOUNT, ORG, PROJECT, PIPELINE, or TARGET scope.
- promote body: `scope` (required), `approver_id` (optional; auto-derived from authenticated user), `comment` (optional), `pipeline_id` (required when `scope` is `PIPELINE`), `target_id` (required when `scope` is `TARGET`)
- STO gateway may have auth limitations with x-api-key PATs
16 changes: 8 additions & 8 deletions docs/testing/security_exemption/test_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
| TC-se-007 | Combined status + search | `harness_list(resource_type="security_exemption", status="Pending", search="critical")` | Returns Pending exemptions matching search | ⬜ Pending | | |
| TC-se-008 | Pagination - page 0, size 5 | `harness_list(resource_type="security_exemption", page=0, size=5)` | Returns first 5 exemptions | ⬜ Pending | | |
| TC-se-009 | Pagination - page 1 | `harness_list(resource_type="security_exemption", page=1, size=5)` | Returns second page of exemptions | ⬜ Pending | | |
| TC-se-010 | Approve exemption | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Approved"})` | Exemption status changes to Approved | ⬜ Pending | | |
| TC-se-011 | Approve without comment | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={approver_id: "<uuid>"})` | Exemption approved without comment | ⬜ Pending | | |
| TC-se-012 | Reject exemption | `harness_execute(resource_type="security_exemption", action="reject", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Rejected - risk too high"})` | Exemption status changes to Rejected | ⬜ Pending | | |
| TC-se-013 | Promote exemption | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", comment: "Promoting to org level"})` | Exemption promoted to org/account level | ⬜ Pending | | |
| TC-se-014 | Promote with pipeline_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", pipeline_id: "<pid>"})` | Exemption promoted scoped to pipeline | ⬜ Pending | | |
| TC-se-015 | Promote with target_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={approver_id: "<uuid>", target_id: "<tid>"})` | Exemption promoted scoped to target | ⬜ Pending | | |
| TC-se-010 | Approve exemption at project scope | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={comment: "Approved"})` | Exemption is approved at project scope; server auto-fills approver_id from the authenticated user | ⬜ Pending | | |
| TC-se-011 | Approve without body | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>")` | Exemption is approved without a comment; server auto-fills approver_id | ⬜ Pending | | |
| TC-se-012 | Reject exemption | `harness_execute(resource_type="security_exemption", action="reject", exemption_id="<id>", body={comment: "Rejected - risk too high"})` | Exemption is rejected; server auto-fills approver_id | ⬜ Pending | | |
| TC-se-013 | Promote exemption to org scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "ORG", comment: "Promoting to org level"})` | Exemption is approved and promoted to org scope in one call | ⬜ Pending | | |
| TC-se-014 | Promote with pipeline_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "PIPELINE", pipeline_id: "<pid>"})` | Exemption is approved and promoted to the specified pipeline scope | ⬜ Pending | | |
| TC-se-015 | Promote with target_id scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={scope: "TARGET", target_id: "<tid>"})` | Exemption is approved and promoted to the specified target scope | ⬜ Pending | | |
| TC-se-016 | Custom org and project | `harness_list(resource_type="security_exemption", org_id="custom_org", project_id="custom_project")` | Returns exemptions for specified org/project | ⬜ Pending | | |
| TC-se-017 | Approve without approver_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="<id>", body={})` | Returns validation error — approver_id required | ⬜ Pending | | |
| TC-se-018 | Invalid exemption_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="nonexistent", body={approver_id: "<uuid>"})` | Returns not found error | ⬜ Pending | | |
| TC-se-017 | Promote without scope | `harness_execute(resource_type="security_exemption", action="promote", exemption_id="<id>", body={comment: "Missing scope"})` | Returns validation or API error because promote requires `body.scope` | ⬜ Pending | | |
| TC-se-018 | Invalid exemption_id | `harness_execute(resource_type="security_exemption", action="approve", exemption_id="nonexistent", body={comment: "Approved"})` | Returns not found error | ⬜ Pending | | |
| TC-se-019 | Invalid action name | `harness_execute(resource_type="security_exemption", action="invalid_action", exemption_id="<id>")` | Returns error — unknown action | ⬜ Pending | | |
| TC-se-020 | Approve already-approved exemption | `harness_execute(resource_type="security_exemption", action="approve", ...)` on approved exemption | Returns error or idempotent success | ⬜ Pending | | |
| TC-se-021 | Resource metadata | `harness_describe(resource_type="security_exemption")` | Returns metadata with execute actions (approve, reject, promote) and body schemas | ⬜ Pending | | |
Expand Down
15 changes: 8 additions & 7 deletions src/prompts/exemption-review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,13 @@ Steps:
- **Recommendation**: Approve, Reject, or Request more info
4. **Present review table**:
- Exemption ID, vulnerability, severity, requestor, justification, recommendation
5. **Batch actions**: Group exemptions by recommendation:
- **Approve**: Low-risk with valid justification and compensating controls
- **Reject**: High-risk without adequate mitigation
- **Needs review**: Insufficient justification or missing context
5. **Batch actions**: Group exemptions by recommendation and target scope:
- **Approve at project scope**: Low-risk with valid justification and compensating controls. Use action="approve" only when the user explicitly wants project-level approval.
- **Promote**: If the user wants approval at ACCOUNT, ORG, PIPELINE, TARGET, or another non-project scope, use action="promote" directly. Do not call action="approve" first.
- **Reject**: High-risk without adequate mitigation.
- **Needs review**: Insufficient justification or missing context.

To take action, I can use harness_execute with resource_type="security_exemption" and action="approve", "reject", or "promote" — but only after you confirm each decision.
To take action, I can use harness_execute with resource_type="security_exemption" and action="approve", "reject", or "promote" — but only after you confirm each decision. For promote, the body must include scope: "ACCOUNT" | "ORG" | "PROJECT" | "PIPELINE" | "TARGET"; PIPELINE also requires pipeline_id, and TARGET also requires target_id. approver_id is optional for approve/reject/promote because the server derives it from the authenticated user when omitted.

## Suggested next steps

Expand All @@ -49,10 +50,10 @@ across multiple exemptions.
Format: a markdown bullet list of complete, send-as-is sentences.

Example shape (use real titles/types/targets from your output, not these literals):
- Approve: SQL injection in payment-api (Critical, mitigation in place)
- Approve at project scope: SQL injection in payment-api (Critical, mitigation in place)
- Reject: Hardcoded API key in auth-service (no justification)
- Reject all Pending SECRET-type exemptions for target payment-api
- Approve all Pending Low-severity SCA exemptions for target shared-libs
- Promote all Pending Low-severity SCA exemptions for target shared-libs to ORG scope
- Show all Approved exemptions for target auth-service

Rules:
Expand Down
Loading
Loading