Content
<p align="center">
<img src="https://raw.githubusercontent.com/evidiq/evidiq-bastion-mcp/main/assets/evidiq-bastion.png" width="200" alt="EVIDIQ Bastion" />
</p>
<h1 align="center">EVIDIQ Bastion</h1>
<p align="center"><strong>Is this deployment configuration safe to apply?</strong></p>
<p align="center">
Deterministic infrastructure configuration auditor for Dockerfiles, GitHub Actions workflows, Kubernetes manifests, and IaC (Terraform / Compose). Non-root execution, secret protection, supply chain integrity, resource bounds, and signed attestations.
</p>
<p align="center">
<a href="https://evidiq.dev">evidiq.dev</a> ·
<a href="https://evidiq.dev/docs/bastion">Bastion Docs</a> ·
<a href="https://mcp.evidiq.dev/bastion/skill.md">Agent Skill</a> ·
<a href="https://github.com/evidiq/evidiq">EVIDIQ Main</a> ·
<a href="https://github.com/evidiq/evidiq-bastion-mcp">Bastion MCP</a>
</p>
<p align="center">
<a href="https://mcp.evidiq.dev/bastion/mcp"><img src="https://img.shields.io/badge/MCP%20Server-Active-3CCF4E?style=flat-square" alt="MCP Server active" /></a> <a href="https://evidiq.dev/docs/bastion"><img src="https://img.shields.io/badge/Audits-Docker%20%2B%20CI%20%2B%20K8s%20%2B%20IaC-0284C7?style=flat-square" alt="Audits Docker + CI + K8s + IaC" /></a> <a href="https://www.oklink.com/xlayer"><img src="https://img.shields.io/badge/X%20Layer-USDT0-3CCF4E?style=flat-square" alt="X Layer USDT0" /></a> <a href="https://mcp.evidiq.dev/bastion/x402"><img src="https://img.shields.io/badge/x402-0.005%E2%80%930.03%20USDT0-2563EB?style=flat-square" alt="x402: 0.005 to 0.03 USDT0" /></a> <a href="https://web3.okx.com/onchainos/dev-docs/payments/service-seller-sdk"><img src="https://img.shields.io/badge/Payments-Official%20OKX%20SDK-121212?style=flat-square&logo=okx&logoColor=white" alt="Official OKX Payment SDK" /></a> <a href="https://www.okx.ai/agents/10359"><img src="https://img.shields.io/badge/OKX.AI-Agent%20%2310359-121212?style=flat-square&logo=okx&logoColor=white" alt="OKX.AI Agent 10359 listed" /></a> <a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-3DA639?style=flat-square" alt="License: MIT" /></a>
</p>
---
Infrastructure as Code and deployment configurations define the security perimeter of autonomous agent services. An agent service configured to run container workloads as `root`, expose `0.0.0.0/0` ingress rules, use unpinned GitHub Actions, or mount host network paths introduces immediate cluster compromise risks before any code executes.
**EVIDIQ Bastion is the pre-deployment security gate for infrastructure configurations.**
Pass it Dockerfiles, GitHub Actions CI workflows, Kubernetes manifests, or Terraform HCL / Compose files. It evaluates 14 deterministic security rules — enforcing non-root execution, credential insulation, supply-chain integrity, resource bounds, and signed attestations.
**Bastion never deploys infrastructure, never executes input manifests, and never accepts private keys.**
## What it does
- **Non-Root Execution Enforcement** — Detects root user execution (`USER root` or missing non-root `USER` directive) in container builds.
- **Supply-Chain Action Pinning** — Enforces full 40-character commit SHA pinning for GitHub Actions (blocking mutable `@v3` / `@main` tags) and immutable SHA-256 digests for Docker base images.
- **Credential Insulation** — Detects hardcoded secrets, API keys, or private keys in build ARG/ENV directives, plaintext IaC variable defaults, and Kubernetes secret environment variables.
- **Kubernetes Workload Hardening** — Identifies privileged containers (`privileged: true`), `hostPath` volume mounts, `hostNetwork` exposure, and missing CPU/memory resource bounds.
- **IaC Exposure Auditing** — Audits Terraform HCL and Docker Compose for open world ingress (`0.0.0.0/0`), public S3 buckets, and unrestricted container capabilities.
- **CI/CD Pipeline Attack Vectors** — Detects untrusted code checkout risks in `pull_request_target` triggers, unescaped `github.event` expression injection in `run` steps, and overly broad `permissions: write-all`.
- **Signed Attestations** — `attest_deployment` binds the configuration digest, evaluation findings, and verdict into an EIP-191 signed attestation and anchors it on 0G storage.
- **Deterministic Verdicts** — Any failing `blocker` yields `BLOCK`; otherwise any failing `high` yields `REVIEW`; clean evaluations yield `PASS`.
- **Pay per check** — Five paid analysis tools at `0.005–0.03 USDT0`; five preflight and verification tools are free.
## Route to Bastion when
Use Bastion **before applying or deploying infrastructure code**: before building container images, before merging CI/CD workflow pull requests, before applying Kubernetes manifests (`kubectl apply`), or before executing Terraform (`terraform apply`).
Do **not** send it private keys — ever. Do not route smart contract calldata here (that is **Assay**), source code is **Warden**, endpoint reachability is **Sentinel**, dependency manifests are **Lineage**, and durable action logging is **Vault**.
A natural chain: `validate_config` → `scan_dockerfile` / `scan_workflow` → `attest_deployment` → `append_record` (Vault).
## Use it from any agent
```bash
# Read the public Skill document
curl -s https://mcp.evidiq.dev/bastion/skill.md
# Inspect current x402 pricing discovery
curl -s https://mcp.evidiq.dev/bastion/x402
# Connect the remote MCP server (OpenClaw)
openclaw mcp add evidiq-bastion --transport streamable-http --url https://mcp.evidiq.dev/bastion/mcp
# Connect the remote MCP server (Claude Code)
claude mcp add --transport http evidiq-bastion https://mcp.evidiq.dev/bastion/mcp
```
Public endpoints:
| Endpoint | Purpose |
|----------|---------|
| `https://mcp.evidiq.dev/bastion/mcp` | Remote Streamable HTTP MCP transport |
| `https://mcp.evidiq.dev/bastion/skill.md` | Agent-readable usage and safety guide |
| `https://mcp.evidiq.dev/bastion/x402` | x402 v2 pricing and payment discovery |
| `https://mcp.evidiq.dev/bastion/health` | Service health & payment gate status |
| `https://evidiq.dev/docs/bastion` | Technical documentation |
## MCP tools
### Paid analysis & attestations
| Tool | Cost | Atomic | Description |
|------|------|-------:|-------------|
| `scan_dockerfile` | `0.005 USDT0` | `5000` | Audit Dockerfile for root user, unpinned base images, build-stage secrets, and ADD URLs |
| `scan_workflow` | `0.01 USDT0` | `10000` | Audit GitHub Actions workflow YAML for unpinned actions, `pull_request_target` risks, and script injection |
| `scan_manifest` | `0.015 USDT0` | `15000` | Audit Kubernetes manifests for privileged mode, `hostPath`/`hostNetwork`, and missing resource limits |
| `scan_iac` | `0.02 USDT0` | `20000` | Audit Terraform HCL and Docker Compose for `0.0.0.0/0` ingress, public storage buckets, and plaintext secrets |
| `attest_deployment` | `0.03 USDT0` | `30000` | Bind deployment configuration digest and verdict into an EIP-191 signed attestation anchored on 0G storage |
### Free preflight and verification
| Tool | Cost | Description |
|------|------|-------------|
| `bastion_capabilities` | Free | Rule catalog with severities, supported config kinds, limits, full pricing, and tool list |
| `validate_config` | Free | Free preflight parse-check: auto-detects config type, computes SHA-256 digest, checks for input secrets, and reports severity counts |
| `estimate_cost` | Free | Price quotation lookup tool; with no argument, quotes full pricing table |
| `verify_bastion_report` | Free | Offline SHA-256 content digest and EIP-191 signature validator |
| `get_artifact` | Free | Retrieve stored report or attestation by artifactId (10-minute TTL) |
## Test Verification & Automated Harness Output
Every rule and payment gate in EVIDIQ Bastion is validated via an automated test harness (`tester/harness.mjs`) on VPS.
### 1. Automated Harness Fixture Matrix (14/14 PASS)
| Fixture | Tool | Expected Verdict | Actual Verdict | Set-Equality Match |
|:---|:---|:---:|:---:|:---:|
| `dockerfile/root-user.Dockerfile` | `scan_dockerfile` | `BLOCK` | `BLOCK` | `true` (`BASTION_ROOT_USER`) |
| `dockerfile/latest-tag.Dockerfile` | `scan_dockerfile` | `REVIEW` | `REVIEW` | `true` (`BASTION_UNPINNED_BASE`) |
| `dockerfile/secret-in-arg.Dockerfile` | `scan_dockerfile` | `BLOCK` | `BLOCK` | `true` (`BASTION_SECRET_IN_BUILD_ARG`) |
| `dockerfile/clean.Dockerfile` | `scan_dockerfile` | `PASS` | `PASS` | `true` (Clean) |
| `workflow/pr-target-checkout.yml` | `scan_workflow` | `BLOCK` | `BLOCK` | `true` (`BASTION_PR_TARGET_UNTRUSTED`) |
| `workflow/unpinned-action.yml` | `scan_workflow` | `REVIEW` | `REVIEW` | `true` (`BASTION_ACTION_NOT_PINNED`) |
| `workflow/script-injection.yml` | `scan_workflow` | `BLOCK` | `BLOCK` | `true` (`BASTION_EXPR_INJECTION`) |
| `workflow/clean.yml` | `scan_workflow` | `PASS` | `PASS` | `true` (Clean) |
| `manifest/privileged.yaml` | `scan_manifest` | `BLOCK` | `BLOCK` | `true` (`BASTION_PRIVILEGED`) |
| `manifest/no-limits.yaml` | `scan_manifest` | `REVIEW` | `REVIEW` | `true` (`BASTION_NO_RESOURCE_LIMITS`) |
| `manifest/helm-templated.yaml` | `scan_manifest` | `REVIEW` | `REVIEW` | `true` (Clean template) |
| `iac/open-ingress.tf` | `scan_iac` | `BLOCK` | `BLOCK` | `true` (`BASTION_WORLD_INGRESS`) |
| `iac/plaintext-secret.tf` | `scan_iac` | `BLOCK` | `BLOCK` | `true` (`BASTION_PLAINTEXT_SECRET`) |
| `iac/clean.tf` | `scan_iac` | `PASS` | `PASS` | `true` (Clean) |
### 2. Verification Harness Logs (`node tester/harness.mjs`)
```text
=== Starting EVIDIQ Bastion MCP Test Harness ===
Test Container Endpoint: http://127.0.0.1:4012/mcp
Production Endpoint: http://127.0.0.1:3012/mcp
--- Step 1: Verify Test Container Health & Bypass ---
PASS: Test container health is 200 OK
PASS: Test container carries bypass header 'x-x402-bypass: true'
PASS: Test container response includes 'x402Bypass: true' in body
--- Step 2 & 3: Bare Call Sweep & Fixture Verification (14 Fixtures) ---
PASS: 14/14 Fixture Assertions Passed with Exact Set-Equality Match
--- Step 4: Determinism & Digest Stability ---
PASS: Repeated scan yields byte-identical SHA-256 digest: 274cd946dd164d373f6472ef66ab9d85450733f3c167dc4a066d25238a3eeeea
--- Step 5: Test Build Markers Check ---
PASS: Response carries 'testBuild: true' marker
--- Step 6: Production Unpaid 402 Probes ---
PASS: Production /health is 200 OK
PASS: Production paymentGate is 'enforced'
PASS: Production HEAD /mcp returns 402 Payment Required
PASS: Production unpaid scan_dockerfile returns HTTP 402
=================================================
SUCCESS: All EVIDIQ Bastion MCP test harness assertions PASSED!
```
### 3. OpenClaw Autonomous Agent Execution Traces
**Agent Run 1 — Dockerfile Audit (`scan_dockerfile`):**
```text
openclaw@evidiq-vps:~$ openclaw agent --session-id bastion-dockerfile-audit \
--message "Use tool scan_dockerfile from evidiq-bastion MCP to audit: 'FROM node:22-alpine\nCMD [\"node\"]'" --local
[provider-transport-fetch] start provider=zerog model=glm-5.2 method=POST url=https://router-api.0g.ai/v1/chat/completions
[evidiq-bastion] Executing tool scan_dockerfile (content-length: 32 bytes)
## Dockerfile Audit Results
Verdict: 🚫 BLOCK (1 blocker finding)
Finding:
• [BASTION_ROOT_USER] Blocker (Line 2)
Why: Container runs as root by default. A container escape gives root access on the host node.
Remediation: Add 'USER node' instruction (node:22-alpine ships with UID 1000).
Report Integrity:
Digest: 86e0124f52a23e277f9864190fcbff9
Signer: 0x131E4A54aB221929834815c99195dAec316aC270
Artifact ID: art_86e0124f52a23e27
```
**Agent Run 2 — GitHub Actions Workflow Audit (`scan_workflow`):**
```text
openclaw@evidiq-vps:~$ openclaw agent --session-id bastion-workflow-audit \
--message "Use tool scan_workflow from evidiq-bastion MCP to audit GitHub Actions workflow" --local
[provider-transport-fetch] start provider=zerog model=glm-5.2 method=POST url=https://router-api.0g.ai/v1/chat/completions
[evidiq-bastion] Executing tool scan_workflow (content-length: 88 bytes)
## GitHub Actions Workflow Audit
Verdict: ⚠️ REVIEW (0 Blocker, 1 High, 0 Medium)
Finding:
• [BASTION_ACTION_NOT_PINNED] High Severity
Detail: actions/checkout@v3 is pinned to a mutable tag instead of commit SHA.
Why: Mutable tags can be hijacked. Pinning to a SHA prevents untrusted action code updates.
Remediation: Pin action to immutable 40-character commit SHA (e.g., actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11).
Integrity:
Signature: EIP-191 signed by 0x131E4A54aB221929834815c99195dAec316aC270
Artifact ID: art_960389b236d8cb9f
```
## Recommended workflow
Settlement happens **before** a paid tool runs, so a malformed argument is still a paid call. Preflight for free first:
1. `bastion_capabilities` — rule set catalog, supported config types, limits, prices.
2. `validate_config` — confirms config type, detects input secrets, and returns severity counts without charging.
3. `estimate_cost` — exact price of the operation you intend to run.
4. One paid call per request (`scan_dockerfile`, `scan_workflow`, `scan_manifest`, `scan_iac`, or `attest_deployment`).
5. `verify_bastion_report` — free, offline verification of the signature and report digest.
## Rule Families & Verdict Engine
Bastion enforces 14 deterministic security rules across 6 families:
- **Privilege**: `BASTION_ROOT_USER`, `BASTION_PRIVILEGED`
- **Exposure**: `BASTION_WORLD_INGRESS`, `BASTION_PUBLIC_STORAGE`, `BASTION_HOST_NETWORK`
- **Secrets**: `BASTION_SECRET_IN_BUILD_ARG`, `BASTION_PLAINTEXT_SECRET`, `BASTION_SECRET_ENV`
- **Supply Chain**: `BASTION_UNPINNED_BASE`, `BASTION_ACTION_NOT_PINNED`, `BASTION_PR_TARGET_UNTRUSTED`, `BASTION_EXPR_INJECTION`
- **Resource**: `BASTION_NO_RESOURCE_LIMITS`
- **Hygiene**: `BASTION_ADD_URL`, `BASTION_UNPINNED_PKG_INSTALL`
**Verdict Logic:**
- Failing any `blocker` rule → **`BLOCK`**
- Failing any `high` rule (with 0 blockers) → **`REVIEW`**
- Clean evaluation (0 blockers, 0 high findings) → **`PASS`**
## What a report proves, and what it does not
- It **does** prove that this exact deployment configuration, evaluated under the deterministic 14-rule engine version, produced this content digest, finding set, and verdict.
- It **does** produce an EIP-191 signature signed by Bastion's trusted key, anchorable on 0G storage.
- It **does not** guarantee runtime application security beyond the static configuration. Dynamic application bugs or live network attacks outside IaC definition are out of static scope.
---
## Architecture
```mermaid
flowchart TB
agent["<b>AI agent</b><br/>MCP client"]
request{"Tool call<br/>free or paid?"}
agent -->|POST /bastion/mcp| request
free["Free preflight<br/>capabilities · validate_config<br/>estimate · verify · get_artifact"]
gate["x402 v2 gate<br/>EIP-3009 exact · pay per config scan"]
xlayer[("X Layer<br/>USD₮0 · eip155:196")]
request -->|free helper| free
request -->|paid config scan| gate
gate -. verify and settle .-> xlayer
subgraph bastion["EVIDIQ Bastion trust boundary"]
direction TB
parse["1. Config parser<br/>Dockerfile · YAML · HCL · manifest"]
rules["2. 14-rule engine<br/>privilege · exposure · secrets · supply chain · resources"]
report["3. Canonical report<br/>SHA-256 digest · EIP-191 signature"]
artifacts["4. Content-addressed artifacts<br/>scan reports & attestations"]
parse --> rules --> report --> artifacts
end
free --> parse
gate --> parse
response["<b>MCP response</b><br/>verdict + findings + attestation"]
artifacts --> response
classDef client fill:#312e81,stroke:#a78bfa,color:#ffffff,stroke-width:2px;
classDef payment fill:#052e16,stroke:#4ade80,color:#ffffff,stroke-width:2px;
classDef core fill:#0f172a,stroke:#38bdf8,color:#ffffff,stroke-width:2px;
classDef output fill:#4c1d95,stroke:#c4b5fd,color:#ffffff,stroke-width:2px;
class agent,request client;
class free,gate,xlayer payment;
class parse,rules,report,artifacts core;
class response output;
style bastion fill:#0f172a,stroke:#38bdf8,color:#e0f2fe,stroke-width:2px;
```
## TypeScript SDK
A typed client for the live endpoint lives in [`sdk/index.ts`](sdk/index.ts) — 10 tools (5 free, 5 paid). Free tools answer a bare call; paid tools run the x402 flow automatically (402 challenge → `pay` hook → replay with the `x-payment` header). No key lives in the file.
```ts
import { BastionClient } from "./sdk/index.js";
const client = new BastionClient(); // endpoint defaults to https://mcp.evidiq.dev/bastion/mcp
// free
const caps = await client.callTool("bastion_capabilities", {});
// paid — settle the 402 challenge via the constructor's pay hook, or omit it
// to receive a PaymentRequiredError carrying the full x402 v2 challenge
const result = await client.callTool("some_paid_tool", { arg: "value" });
```
The `pay` hook receives the decoded x402 v2 challenge (`{ x402Version, resource, accepts[] }` — payTo, asset, amount) and returns the value for the `x-payment` header, e.g. an EIP-3009 `transferWithAuthorization` settled via the official OKX SDK. Without a hook, paid calls throw `PaymentRequiredError` so the caller can settle however it wants.
## License
EVIDIQ owns and licenses its original Bastion code under MIT. Third-party dependencies preserve their own open-source licenses in `THIRD_PARTY_NOTICES.md`.
Connection Info
You Might Also Like
Train-in-Silence
The first Task-Aware MCP server and automated VRAM calculator for LLM...
stacklit
108,000 lines of code. 4,000 tokens of index. One command makes any repo...
AppClaw
AI-powered mobile automation agent — describe what you want in plain...
pdf-mcp
Production-ready MCP server for PDF processing with intelligent caching....
kotadb
Local-only code intelligence API for AI developer workflows (Bun +...
gemini-api-docs-mcp
A remote HTTP MCP server for searching Google Gemini API documentation.