diff --git a/.claude/skills/ave-record-authoring/SKILL.md b/.claude/skills/ave-record-authoring/SKILL.md index fef22d3..c7c6e76 100644 --- a/.claude/skills/ave-record-authoring/SKILL.md +++ b/.claude/skills/ave-record-authoring/SKILL.md @@ -62,4 +62,4 @@ it is not a record yet; generalize to the class or stop. - A record is published when CI validates it and PiranhaDB serves it; `?schema=1.1` must strip 1.2 fields, and the contract test for both versions must stay green. - Backfill lands as reviewed PR batches; each batch updates the triage counter on - ave.bawbel.io. + aveproject.org. diff --git a/.github/workflows/code-scan.yml b/.github/workflows/code-scan.yml index 8fddd15..b5052e7 100644 --- a/.github/workflows/code-scan.yml +++ b/.github/workflows/code-scan.yml @@ -17,12 +17,12 @@ jobs: contents: read security-events: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@ce5e7eeac396d720fe2d802714996c8ce561e311 # v3.39.0 with: languages: python - name: Perform CodeQL analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@ce5e7eeac396d720fe2d802714996c8ce561e311 # v3.39.0 with: category: "/language:python" diff --git a/.github/workflows/dependency-scan.yml b/.github/workflows/dependency-scan.yml index 8bfd058..cb2ce5f 100644 --- a/.github/workflows/dependency-scan.yml +++ b/.github/workflows/dependency-scan.yml @@ -18,13 +18,13 @@ jobs: contents: read pull-requests: write steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Dependency Review - uses: actions/dependency-review-action@v5 + uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0 with: fail-on-severity: high - name: Set up Python - uses: actions/setup-python@v7 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.11" - name: Audit installed dependencies for known vulnerabilities diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c8343fb..62f0276 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -4,13 +4,16 @@ on: release: types: [published] +permissions: + contents: read + jobs: test: name: Verify Tests runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.11" - name: Install package with dev dependencies @@ -25,8 +28,8 @@ jobs: needs: [test] runs-on: ubuntu-latest steps: - - uses: actions/checkout@v7 - - uses: actions/setup-python@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.11" - name: Install build @@ -39,7 +42,7 @@ jobs: /tmp/verify-venv/bin/pip install dist/*.whl /tmp/verify-venv/bin/bawbel-gate --version - name: Store distributions - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: python-package-distributions path: dist/ @@ -55,12 +58,12 @@ jobs: id-token: write # mandatory for trusted publishing; no API token stored steps: - name: Download distributions - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: python-package-distributions path: dist/ - name: Publish to TestPyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: repository-url: https://test.pypi.org/legacy/ skip-existing: true @@ -80,9 +83,9 @@ jobs: id-token: write # mandatory for trusted publishing; no API token stored steps: - name: Download distributions - uses: actions/download-artifact@v4 + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: python-package-distributions path: dist/ - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index f16be9f..3a5be91 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -18,25 +18,25 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@v7 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@v2.5.0 + uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0 with: results_file: results.sarif results_format: sarif publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@v4.38.2 + uses: github/codeql-action/upload-sarif@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2 with: sarif_file: results.sarif diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 1f66eb2..3726311 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -16,7 +16,7 @@ jobs: permissions: contents: read steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Run Gitleaks diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 806c609..cdceeb4 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -20,7 +20,7 @@ versioned, public interface. No layer reaches around another. │ LAYER 5b bawbel platform [PLANNED] │ │ │ │ multi-org SaaS, ingest at scale │ │ │ ├────────────────────────────────────────────────────────┤ │ │ -│ LAYER 5a bawbel-hub [DESIGN → M7] │ │ │ +│ LAYER 5a bawbel-hub [M7 partial] │ │ │ │ self-hosted fleet console, one org/team, │ │ │ │ 5-50 gates · FIRST PAID TIER │ │ │ ├────────────────────────────────────────────────────────┤ │ │ @@ -31,14 +31,14 @@ versioned, public interface. No layer reaches around another. │ api.piranha.bawbel.io │ │ │ │ queryable AVE corpus, mitigation endpoint │ │ │ ├────────────────────────────────────────────────────────┤ ▼ │ -│ LAYER 2.5 bawbel-gate [DESIGN → M1] │ classes findings +│ LAYER 2.5 bawbel-gate [alpha 0.1.0] │ classes findings │ runtime enforcement: manifests, taint, │ → rules → decisions │ trifecta invariant, audit chain │ → stanzas → audit chains ├────────────────────────────────────────────────────────┤ → pins → new class │ LAYER 2 bawbel-scanner [LIVE v1.3.0] │ │ candidates │ static detection: CLI, pre-commit, CI │ │ │ ├────────────────────────────────────────────────────────┤ │ │ -│ LAYER 1 AVE [LIVE, 51 records] │ ▼ │ +│ LAYER 1 AVE [LIVE, 87 records] │ ▼ │ │ the standard: behavioral vulnerability │ │ │ classes for agentic systems, AIVSS-scored │ ────────────────┘ └────────────────────────────────────────────────────────┘ @@ -67,7 +67,7 @@ flowchart TB end subgraph L2["Layers 2 / 2.5 · detection and enforcement"] SCN["bawbel-scanner
v1.3.0 · LIVE"] - GATE["bawbel-gate
DESIGN → M1"] + GATE["bawbel-gate
alpha 0.1.0 · M5, M7 partial"] end subgraph EDGE["edge surfaces"] IDE["vscode-bawbel"] @@ -75,7 +75,7 @@ flowchart TB CI["bawbel-integrations"] end subgraph L5A["Layer 5a · team tier, first paid product"] - HUB["bawbel-hub
DESIGN → M7 · self-hosted"] + HUB["bawbel-hub
M7 partial · self-hosted"] end subgraph PLAN["planned layers"] REG["Layer 4 · Registry"] @@ -89,7 +89,7 @@ flowchart TB PDB --> BMCP SCN -->|"findings, SARIF"| CI SCN -->|"diagnostics"| IDE - GATE -->|"Flow D · audit chain, push-only mTLS"| HUB + GATE -->|"Flow D · audit chain, push-only mTLS (specified)"| HUB HUB -.->|"federated rollup, planned"| PLAT REG -.->|"signed manifest baselines"| GATE PLAT -.->|"deny patterns → class candidates"| AVE @@ -151,6 +151,10 @@ flowchart LR B -.->|"audit evidence"| R ``` +Status: AVE records do not carry `capability_mitigation` yet (0 of 87 on aveproject/ave +main, 2026-10-18), so the record-to-stanza step is planned. Today `harden --ave` reads +stanzas from gate's own `mitigations/ave-mitigations.json` (2 entries). + ### Flow D · Telemetry: evidence, upward ``` @@ -173,22 +177,28 @@ patterns across teams are the eventual pipeline for new AVE class candidates via federated platform, which closes the loop back to Flow A, but that hop is planned, not required for the hub to deliver its value today. +Status: the hub side of Flow D (ingest, per-session chain verification, fleet state) is +implemented. The gate-side push and the per-gate mTLS channel are specified, not +implemented (DESIGN.md 14.3). See the bawbel-hub project entry below. + ## 3. Projects Each project: what it is, what it consumes, what it produces, and the interface it is held to. -### ave (Layer 1, live: schema 1.2, 51 records) +### ave (Layer 1, independent project aveproject/ave; live: schema 1.1.0, 87 records) -The standard. CWE-shaped behavioral class definitions for agentic-system -vulnerabilities, scored with OWASP AIVSS v0.8. Since schema 1.2, records carry a -provenance vector (where in the context supply chain the class enters), a trifecta -profile (which legs make it exploitable), and an executable mitigation stanza. +The standard, governed separately from Bawbel. CWE-shaped behavioral class definitions +for agentic-system vulnerabilities, scored with OWASP AIVSS v0.8. Records carry a +provenance vector (where in the context supply chain the class enters; 87 of 87) and a +trifecta profile (which legs make it exploitable; 77 of 87). The executable mitigation +stanza (`capability_mitigation`) is defined but populated in 0 of 87. - **Consumes:** research, incident reports, fleet deny patterns (Flow D). - **Produces:** versioned JSON records; JSON Schemas for records and capability manifests. -- **Interface:** git repo + `schemas/ave-1.2.json`; docs at ave.bawbel.io. +- **Interface:** git repo (github.com/aveproject/ave) + + `schema/ave-record-1.1.0.schema.json`; site at aveproject.org. - **Strategic gate:** second independent implementer before OWASP/MITRE outreach. ### bawbel-scanner (Layer 2, live: v1.3.0, PyPI) @@ -203,7 +213,7 @@ hook, and CI job; emits JSON and SARIF. - **Interface:** CLI contract + SARIF 2.1.0; secret-detector set shared with the gate as a library, not forked. -### bawbel-gate (Layer 2.5, DESIGN.md complete, M1 next) +### bawbel-gate (Layer 2.5, alpha 0.1.0 on PyPI, M5 and M7 partial) Runtime enforcement. MCP multiplexer proxy enforcing capability manifests, session taint, and the rule-of-two trifecta invariant, with a hash-chained audit log, @@ -216,10 +226,11 @@ embedded console (v1.2). - **Interface:** capability-manifest/v1 schema; Console API (DESIGN.md 13.1); ingest protocol (DESIGN.md 13.2). -### piranhadb (Layer 3, live: Railway) +### piranhadb (Layer 3, offline) -Read-only corpus API at `api.piranha.bawbel.io`. Serves AVE records with schema -negotiation, the per-record mitigation endpoint, and (post-backfill) posture queries. +The hosted API at `api.piranha.bawbel.io` is offline: the host does not resolve. AVE +records are served by `api.aveproject.org/records`. As built, it was a read-only corpus +API with schema negotiation, a per-record mitigation endpoint, and posture queries. - **Consumes:** ave repo on deploy (CI publishes validated records). - **Produces:** `GET /records`, `GET /records/{id}/mitigation`, `?schema=`, @@ -239,7 +250,7 @@ trifecta-minimal: no private-data tools, no egress tools. ### vscode-bawbel (Layer 2 edge, live: v1.1.1, Marketplace) IDE surface. Inline diagnostics from scanner findings while editing agent code and -MCP configs; each diagnostic links to its AVE record on ave.bawbel.io. +MCP configs; each diagnostic links to its AVE record. - **Consumes:** bawbel-scanner output (local invocation). - **Produces:** editor diagnostics, quick links, quick-fix hints where a stanza @@ -267,22 +278,28 @@ entries are signed; `harden` and `learn synthesize` consume them as baselines. - **Interface:** HTTPS + sigstore-style verification (open design question: signing identity, see DESIGN.md 12). -### bawbel-hub (Layer 5a, DESIGN.md 14 complete, M7 next, first paid tier) +### bawbel-hub (Layer 5a, DESIGN.md 14 complete, M7 partial, first paid tier) Self-hosted fleet console for one team or org: 5-50 gates, one console. Every -developer's gate pushes its audit chain to the hub over mTLS; the hub replays it into -fleet state and serves the posture view, per-developer drill-down, and the CISO -report fleet-wide. No command channel: the hub cannot decide approvals, cannot reach -into a gate, and cannot push configuration. bawbel-gate (including its own embedded +developer's gate is specified to push its audit chain to the hub over mTLS; the hub +replays it into fleet state and serves the posture view, per-developer drill-down, and +the CISO report fleet-wide. No command channel: the hub cannot decide approvals, cannot +reach into a gate, and cannot push configuration. bawbel-gate (including its own embedded console, 13.1) stays free and fully standalone; the hub is the paid line, drawn at "more than one gate." -- **Consumes:** gate audit chains (push, mTLS); manifest repo (read, for drift - cross-check). +- **Consumes:** gate audit chains (push over mTLS, specified; gates do not send yet); + manifest repo (read, for drift cross-check). - **Produces:** fleet posture, per-gate config-drift flags, fleet-wide CISO posture report. - **Interface:** ingest protocol 13.2 (same protocol the M6 stub server proves); - enrollment via single-use token, gate identity via per-gate mTLS client cert. + enrollment via single-use token (implemented); gate identity via per-gate mTLS client + cert (specified, not implemented). +- **Status:** implemented on the hub side: ingest with per-session chain verification, + SQLite fleet state, single-use enrollment tokens, `GET /v1/fleet/state`. Not + implemented: the gate-side sender, per-gate identity (ingest authenticates with the + hub's shared admin token, and `gate_id` comes from the request path), TLS, and + enrollment token expiry. ### bawbel platform (Layer 5b, planned) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 89267b8..34ac220 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -52,7 +52,7 @@ is officially representing the project in public spaces. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to **security@bawbel.io**. All complaints will be reviewed and +reported to **bawbel.io@gmail.com**. All complaints will be reviewed and investigated promptly and fairly. The maintainer is obligated to respect the privacy and security of the reporter diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d388e07..51d93da 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -150,9 +150,10 @@ Do not open a public issue or PR that demonstrates a security bypass. See ## Scope boundaries with other Bawbel repos - Changes to the AVE record schema or the capability-manifest schema itself: - propose in the `ave` repository, since bawbel-gate is a consumer of that + propose in [aveproject/ave](https://github.com/aveproject/ave), an independent + project (aveproject.org@gmail.com), since bawbel-gate is a consumer of that schema, not its owner (see ARCHITECTURE.md §4.3, interface freeze points). -- Detection rule changes: `bawbel-scanner`. +- Detection rule changes: [bawbel/scanner](https://github.com/bawbel/scanner). - Fleet console / multi-gate features: DESIGN.md §14 (bawbel-hub) describes the boundary between what ships free in the gate's embedded console and what is hub-only; check there before adding fleet-shaped functionality to this repo. diff --git a/README.md b/README.md index 472b4a5..5087219 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The gate never reads model output. Every decision is made on structured JSON-RPC [![License](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/bawbel/gate/blob/main/LICENSE) [![PyPI](https://img.shields.io/pypi/v/bawbel-gate)](https://pypi.org/project/bawbel-gate/) [![Python](https://img.shields.io/badge/python-3.10%2B-blue)](https://github.com/bawbel/gate/blob/main/pyproject.toml) -[![Status](https://img.shields.io/badge/status-alpha%20(0.1.x)-orange)](https://github.com/bawbel/gate#status-alpha-01x) +[![Status](https://img.shields.io/badge/status-alpha%20(0.1.x)-orange)](https://github.com/bawbel/gate#status-v010-feature-complete-pre-release) [![Tests](https://img.shields.io/badge/tests-passing-brightgreen)](https://github.com/bawbel/gate#install-development) [![Fail-closed](https://img.shields.io/badge/fail--closed-enforced-critical)](https://github.com/bawbel/gate/blob/main/DESIGN.md) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/bawbel/gate/badge)](https://scorecard.dev/viewer/?uri=github.com/bawbel/gate) @@ -399,6 +399,8 @@ the session, which ends when the client disconnects. the JSON-RPC channel, and clients log them as parse errors ([#28](https://github.com/bawbel/gate/issues/28)). - Error responses for malformed JSON-RPC from the client. A line that is not JSON is dropped with a stderr warning: no response, no audit record. +- Fleet ingest from gates to bawbel-hub. Gates do not send records yet, and the hub has + no per-gate identity or TLS. See [bawbel-hub (M7)](https://github.com/bawbel/gate#bawbel-hub-m7). ## Commands @@ -497,6 +499,11 @@ Self-hosted fleet manager for teams running more than one gate. Push-only by des the hub never connects to a gate. The hub side below is implemented. The gate-side push client (`ingest/client.py`) is not wired into `serve`, so gates do not send records yet. +Also not implemented: per-gate identity and TLS. Ingest authenticates with the hub's +shared admin token (the one `hub serve` prints at startup), `gate_id` is taken from the +request path, and `hub serve` listens on plain HTTP. DESIGN.md 14.3 specifies a per-gate +mTLS client certificate. Enrollment tokens are single-use but do not expire. + - Ingest service (`POST /v1/gates/{gate_id}/records`): verifies the hash chain per session and stores records idempotently by `(gate_id, session_id, seq)`. A batch with a broken chain is rejected with HTTP 409 `chain_mismatch`; nothing from it is @@ -561,8 +568,9 @@ log records the underlying decisions either way. ## Related projects -- [AVE](https://ave.bawbel.io) - the behavioral vulnerability classification - standard bawbel-gate enforces against (`bawbel-gate harden --ave`). +- [AVE](https://aveproject.org) - the behavioral vulnerability classification + standard bawbel-gate enforces against (`bawbel-gate harden --ave`), an independent + project ([aveproject/ave](https://github.com/aveproject/ave)). - [bawbel-scanner](https://pypi.org/project/bawbel-scanner/) - static detection for agent codebases, MCP configs, and server cards. - PiranhaDB - the queryable AVE corpus API. No public endpoint yet. diff --git a/SECURITY.md b/SECURITY.md index b5bc6cb..7f3bfee 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,8 +11,9 @@ tracker, trifecta invariant, MCP multiplexer, argument guards, audit chain, integrity pinning, learning mode, and the Console API (once shipped). **Out of scope, report to the relevant repo instead:** -- AVE record content or the AVE schema: the `ave` repository. -- bawbel-scanner detection rules: the `bawbel-scanner` repository. +- AVE record content or the AVE schema: [aveproject/ave](https://github.com/aveproject/ave), + an independent project. Contact: aveproject.org@gmail.com. +- bawbel-scanner detection rules: [bawbel/scanner](https://github.com/bawbel/scanner). - PiranhaDB API availability or data correctness: the `piranha-api` repository. **Explicitly in scope even though they may look like "just a bug":** @@ -33,7 +34,7 @@ integrity pinning, learning mode, and the Console API (once shipped). - GitHub Security Advisories: use the "Report a vulnerability" button under this repository's Security tab. -- Email: **security@bawbel.io**. PGP is not required; if you want to encrypt, +- Email: **bawbel.io@gmail.com**. PGP is not required; if you want to encrypt, ask for a key first and we will provide one. Include, as far as you have it: