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
43 changes: 43 additions & 0 deletions .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# mcp-awareness — ambient system awareness for AI agents
# Copyright (C) 2026 Chris Means
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

name: gitleaks

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
scan:
name: scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
# gitleaks/gitleaks-action v2.3.9 (pinned by SHA).
# Scans the PR commit range (pull_request) or full history (push).
# Allowlist: .gitleaksignore at repo root.
- uses: gitleaks/gitleaks-action@ff98106e4c7b2bc287b24eaf42907196329070c7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITLEAKS_ENABLE_COMMENTS: false
GITLEAKS_ENABLE_SUMMARY: true
13 changes: 13 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Placeholder credentials in a deployment runbook — HAProxy stats admin
# password. Line 183 of the runbook explicitly instructs the user to
# replace with a value from KeePass on deploy; production is not running
# this value. The docs/superpowers/plans tree is planned to migrate to an
# awareness-infra repository separate from mcp-awareness.
#
# Two fingerprint formats are listed per finding: the commit-scoped form
# (used when gitleaks scans git history) and the path-scoped form (used
# when gitleaks scans the working tree with --no-git).
d7d821b5bc2a49ff5d9d5662c8e89cb148c48ab2:docs/superpowers/plans/2026-04-02-zero-downtime-deployment.md:curl-auth-user:166
d7d821b5bc2a49ff5d9d5662c8e89cb148c48ab2:docs/superpowers/plans/2026-04-02-zero-downtime-deployment.md:curl-auth-user:438
docs/superpowers/plans/2026-04-02-zero-downtime-deployment.md:curl-auth-user:207
docs/superpowers/plans/2026-04-02-zero-downtime-deployment.md:curl-auth-user:482
12 changes: 12 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Pre-commit hooks for mcp-awareness.
#
# Install once per clone: pre-commit install
# Run manually on all files: pre-commit run --all-files
#
# See CONTRIBUTING.md § Development setup.

repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.30.1
hooks:
- id: gitleaks
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Flake in `tests/test_store.py::test_do_cleanup_logs_errors`.** Test was using the `caplog.at_level(...)` context manager plus `caplog.text` substring check. That pattern failed intermittently on CI (observed on Python 3.11 and 3.14) even though the code under test (`_do_cleanup`) is fully synchronous — the flake was in pytest's log-capture path, not in the production code. Rewritten to use `caplog.set_level(...)` at fixture scope and inspect `caplog.records` directly (logger name + level + message substring), which is sturdier across pytest/Python versions and produces a richer failure message when it does fire. Verified 10/10 consecutive local runs post-fix. Closes [#374](https://github.com/cmeans/mcp-awareness/issues/374).

### Security
- **Gitleaks pre-commit hook + CI gate.** New `.pre-commit-config.yaml` pins `gitleaks v8.30.1` as a pre-commit hook; contributors install it once per clone with `pre-commit install` (documented in `CONTRIBUTING.md` §"Development setup"). A new `.github/workflows/gitleaks.yml` runs the same scanner in CI via `gitleaks/gitleaks-action@ff98106e…` (v2.3.9, SHA-pinned) on every PR and `main` push — belt-and-suspenders for contributors who haven't installed the hook locally. `.gitleaksignore` at repo root records the two pre-existing placeholder findings (`docs/superpowers/plans/2026-04-02-zero-downtime-deployment.md:curl-auth-user:{166,438}` in git-history form and `:{207,482}` in working-tree form) — documented HAProxy-stats example credentials the runbook explicitly instructs the operator to replace with a KeePass value on deploy; production is not running the published placeholder. CI bypass remains possible via `SKIP=gitleaks git commit`, but is discouraged and will be visible in the author's local shell history. `CONTRIBUTING.md` §"Do not commit secrets" updated to reflect that prevention is now automated. `pre-commit>=4.0,<5` added to dev deps. Closes [#367](https://github.com/cmeans/mcp-awareness/issues/367).
- **RLS property-based fuzz coverage** — new `tests/test_rls_property.py` (3 hypothesis-driven tests, 50 examples each) fuzzes the cross-tenant query-isolation invariant across randomly-generated (owner_a, owner_b, witness_tags) tuples. For every generated pair of distinct owners, the tests assert that `get_entries`, `get_tags`, and `get_sources` for one owner never observe entries, tags, or source values owned by the other. Complements the enumeration-based tests in `test_rls.py` (R1), `test_rls_background.py` (R2), and `test_rls_migration_safety.py` (R3) with ~150 random (owner, tag) pairs per CI run — hypothesis shrinks on any failure to report a minimal counter-example. `hypothesis>=6.100` added to dev deps (no runtime dep impact). Test-only change; no production code modified. ~4 s added to the suite. Closes R4 of [#359](https://github.com/cmeans/mcp-awareness/issues/359) and therefore the tracking issue itself; closes [#364](https://github.com/cmeans/mcp-awareness/issues/364).
- **RLS background-thread + pool edge-case coverage** — new `tests/test_rls_background.py` (11 tests) covers the execution contexts the request-path `rls_store` fixture doesn't exercise: the `_do_cleanup` daemon thread, the `upsert_embedding` path used by `server._embedding_pool`, and Postgres's transaction-local `set_config` semantics plus the combined pool/Postgres contract. Four cleanup tests and two embedding tests verify the full owner-scoped call paths (RLS policy + explicit `WHERE owner_id = %s` SQL filter + request-path `_set_rls_context`) catch cross-tenant regressions — tests pass only when all three defenses are intact, acknowledging the layered design rather than claiming any single layer is independently load-bearing. Five pool-guarantee tests: two use a raw `psycopg.connect` to directly verify Postgres's `set_config(..., is_local)` semantic (the `true` variant does NOT survive COMMIT; the `false` variant does), isolating the Postgres contract from `psycopg_pool`'s `RESET ALL` check-in reset; the remaining three codify the *combined* pool+Postgres behavior (no RLS residue across checkouts, after ROLLBACK, or across concurrent threads). Test-only change; no production code modified. ~2.6 s added to the suite; full suite: 998 → 1000 passing. Module docstring captures the audit summary: cleanup's owner enumeration relies on the pool role having `BYPASSRLS`, the per-owner DELETE is doubly scoped; embedding upsert is doubly scoped (SQL `owner_id = %s` + `_set_rls_context`). Closes R2 of [#359](https://github.com/cmeans/mcp-awareness/issues/359); closes [#362](https://github.com/cmeans/mcp-awareness/issues/362).
- **RLS migration-safety test** — new `tests/test_rls_migration_safety.py` walks the Alembic migration path (`N-1 → head`) with two-tenant data seeded at N-1, then asserts tenant isolation still holds after applying the head migration. Catches the class of bugs where a future migration regresses an RLS policy, weakens a `WITH CHECK`, renames `app.current_user`, or adds a new owner-scoped table without `ENABLE ROW LEVEL SECURITY` — failures no scanner catches at authoring time. Each test runs in its own database (`CREATE DATABASE` / `DROP DATABASE` inside the shared `pg_container`) for full isolation. ~2.5 s added to the suite. Closes R3 of [#359](https://github.com/cmeans/mcp-awareness/issues/359) (RLS harness coverage extension tracking); closes [#360](https://github.com/cmeans/mcp-awareness/issues/360). A follow-up companion test for the `_system`-schema carve-out migration specifically was prototyped but deferred — hit an unresolved FORCE-RLS/BYPASSRLS interaction on Postgres 17 during seed-path development; the core isolation invariant this PR ships is the scope R3 promised.
Expand Down
18 changes: 13 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,12 +61,19 @@ you from reporting a bug or asking a question — that's what issues are for.

```bash
pip install -e ".[dev]" # install with dev dependencies
pre-commit install # install git hooks (runs gitleaks on commit)
python -m pytest tests/ # run tests (requires Docker for Postgres)
ruff check src/ tests/ # lint
ruff format src/ tests/ # format
mypy src/mcp_awareness/ # type check
```

`pre-commit install` is a one-time step per clone. Configured hooks live in
`.pre-commit-config.yaml`; the gitleaks hook blocks commits that contain
secrets. To bypass a known false positive, add its fingerprint to
`.gitleaksignore` with a comment explaining why; don't use `SKIP=gitleaks`
unless you know exactly what you're doing.

## Pull request guidelines

- One concern per PR — don't mix unrelated changes
Expand Down Expand Up @@ -100,8 +107,9 @@ Never include `.env` contents, credentials, API tokens, signing keys, or
production configuration values in a PR diff, commit message, or PR body.
If you're testing with real credentials, scrub them before committing.

mcp-awareness has no secret-scanning gate on incoming PRs yet — human
review is the only line of defense, so please help make that review
possible. If you accidentally push a secret, rotate it immediately;
git history rewriting is best-effort and public mirrors may already
have the value.
mcp-awareness runs `gitleaks` as a pre-commit hook and as a CI gate
(`.github/workflows/gitleaks.yml`), but prevention beats detection —
please don't rely on the scanner to catch paste-ins for you. If you
accidentally push a secret, rotate it immediately; git history
rewriting is best-effort and public mirrors may already have the
value.
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dev = [
"pytest-cov",
"testcontainers[postgres]>=4.0",
"hypothesis>=6.100",
"pre-commit>=4.0,<5",
]

[build-system]
Expand Down
Loading