mnemosyne-guard 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mnemosyne_guard-0.1.0/.github/CODEOWNERS +8 -0
- mnemosyne_guard-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +43 -0
- mnemosyne_guard-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
- mnemosyne_guard-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +33 -0
- mnemosyne_guard-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- mnemosyne_guard-0.1.0/.github/dependabot.yml +22 -0
- mnemosyne_guard-0.1.0/.github/workflows/ci.yml +83 -0
- mnemosyne_guard-0.1.0/.github/workflows/release.yml +47 -0
- mnemosyne_guard-0.1.0/.gitignore +45 -0
- mnemosyne_guard-0.1.0/.pre-commit-config.yaml +39 -0
- mnemosyne_guard-0.1.0/CHANGELOG.md +47 -0
- mnemosyne_guard-0.1.0/CITATION.cff +29 -0
- mnemosyne_guard-0.1.0/CODE_OF_CONDUCT.md +53 -0
- mnemosyne_guard-0.1.0/CONTRIBUTING.md +80 -0
- mnemosyne_guard-0.1.0/Dockerfile +44 -0
- mnemosyne_guard-0.1.0/LICENSE +202 -0
- mnemosyne_guard-0.1.0/Makefile +39 -0
- mnemosyne_guard-0.1.0/PKG-INFO +336 -0
- mnemosyne_guard-0.1.0/README.md +293 -0
- mnemosyne_guard-0.1.0/SECURITY.md +55 -0
- mnemosyne_guard-0.1.0/docker-compose.yml +26 -0
- mnemosyne_guard-0.1.0/docs/ARCHITECTURE.md +110 -0
- mnemosyne_guard-0.1.0/docs/NIST_CONTROL_MAPPING.md +149 -0
- mnemosyne_guard-0.1.0/docs/THREAT_MODEL.md +148 -0
- mnemosyne_guard-0.1.0/examples/README.md +19 -0
- mnemosyne_guard-0.1.0/examples/langchain_memory_guard.py +140 -0
- mnemosyne_guard-0.1.0/examples/quickstart.py +119 -0
- mnemosyne_guard-0.1.0/pyproject.toml +93 -0
- mnemosyne_guard-0.1.0/scripts/gen_nist_doc.py +81 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/__init__.py +36 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/api/__init__.py +1 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/api/main.py +136 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/cli.py +79 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/core/__init__.py +38 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/core/config.py +79 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/core/exceptions.py +30 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/core/gateway.py +417 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/core/models.py +198 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/__init__.py +62 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/anomaly.py +161 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/base.py +51 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/injection.py +166 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/obfuscation.py +168 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/detectors/secrets_pii.py +111 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/integrity/__init__.py +13 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/integrity/audit.py +115 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/integrity/signer.py +72 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/nist/__init__.py +186 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/policy/__init__.py +5 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/policy/default_policy.yaml +64 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/policy/engine.py +161 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/py.typed +0 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/store/__init__.py +17 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/store/base.py +102 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/store/sqlite.py +76 -0
- mnemosyne_guard-0.1.0/src/mnemosyne/telemetry/__init__.py +111 -0
- mnemosyne_guard-0.1.0/tests/conftest.py +27 -0
- mnemosyne_guard-0.1.0/tests/test_api.py +151 -0
- mnemosyne_guard-0.1.0/tests/test_detectors.py +187 -0
- mnemosyne_guard-0.1.0/tests/test_gateway.py +193 -0
- mnemosyne_guard-0.1.0/tests/test_integrity.py +60 -0
- mnemosyne_guard-0.1.0/tests/test_nist.py +65 -0
- mnemosyne_guard-0.1.0/tests/test_policy.py +198 -0
- mnemosyne_guard-0.1.0/tests/test_redteam_corpus.py +247 -0
- mnemosyne_guard-0.1.0/tests/test_store.py +119 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a defect in Mnemosyne
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for filing a bug. **Do not report security vulnerabilities here** —
|
|
9
|
+
see [SECURITY.md](../../SECURITY.md) for private disclosure.
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: what-happened
|
|
12
|
+
attributes:
|
|
13
|
+
label: What happened?
|
|
14
|
+
description: A clear description of the bug and what you expected instead.
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
- type: textarea
|
|
18
|
+
id: repro
|
|
19
|
+
attributes:
|
|
20
|
+
label: Steps to reproduce
|
|
21
|
+
description: Minimal code or commands that reproduce the issue.
|
|
22
|
+
render: python
|
|
23
|
+
validations:
|
|
24
|
+
required: true
|
|
25
|
+
- type: input
|
|
26
|
+
id: version
|
|
27
|
+
attributes:
|
|
28
|
+
label: Mnemosyne version
|
|
29
|
+
placeholder: "0.1.0"
|
|
30
|
+
validations:
|
|
31
|
+
required: true
|
|
32
|
+
- type: input
|
|
33
|
+
id: python
|
|
34
|
+
attributes:
|
|
35
|
+
label: Python version
|
|
36
|
+
placeholder: "3.12"
|
|
37
|
+
validations:
|
|
38
|
+
required: true
|
|
39
|
+
- type: textarea
|
|
40
|
+
id: logs
|
|
41
|
+
attributes:
|
|
42
|
+
label: Relevant logs / traceback
|
|
43
|
+
render: shell
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest a capability or improvement
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem / threat
|
|
9
|
+
description: What gap or ASI06 attack vector does this address?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
- type: textarea
|
|
13
|
+
id: proposal
|
|
14
|
+
attributes:
|
|
15
|
+
label: Proposed solution
|
|
16
|
+
description: What should Mnemosyne do? Include detector/policy/API impact if relevant.
|
|
17
|
+
validations:
|
|
18
|
+
required: true
|
|
19
|
+
- type: textarea
|
|
20
|
+
id: alternatives
|
|
21
|
+
attributes:
|
|
22
|
+
label: Alternatives considered
|
|
23
|
+
- type: checkboxes
|
|
24
|
+
id: scope
|
|
25
|
+
attributes:
|
|
26
|
+
label: Area
|
|
27
|
+
options:
|
|
28
|
+
- label: Detector
|
|
29
|
+
- label: Policy engine
|
|
30
|
+
- label: Integrity / audit
|
|
31
|
+
- label: Store / segmentation
|
|
32
|
+
- label: API / CLI
|
|
33
|
+
- label: Docs / NIST mapping
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
## Summary
|
|
2
|
+
|
|
3
|
+
<!-- What does this change and why? Reference any related issue. -->
|
|
4
|
+
|
|
5
|
+
## Type of change
|
|
6
|
+
|
|
7
|
+
- [ ] Bug fix
|
|
8
|
+
- [ ] New feature (detector / policy / endpoint)
|
|
9
|
+
- [ ] Refactor / internal
|
|
10
|
+
- [ ] Docs / NIST mapping
|
|
11
|
+
|
|
12
|
+
## Security considerations
|
|
13
|
+
|
|
14
|
+
<!-- Does this touch a trust boundary? If it changes the policy, the cardinal
|
|
15
|
+
INSTRUCTION-surface invariant, or any detector, explain the threat rationale. -->
|
|
16
|
+
|
|
17
|
+
## Checklist
|
|
18
|
+
|
|
19
|
+
- [ ] `make all` passes locally (ruff, mypy, bandit, pytest)
|
|
20
|
+
- [ ] Added/updated tests; security-relevant changes extend the red-team corpus
|
|
21
|
+
- [ ] The cardinal invariant (untrusted content never reaches `INSTRUCTION`) is intact
|
|
22
|
+
- [ ] Updated docs and, if the control catalog changed, ran `python scripts/gen_nist_doc.py`
|
|
23
|
+
- [ ] Updated `CHANGELOG.md`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: "pip"
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: "weekly"
|
|
7
|
+
groups:
|
|
8
|
+
python-dependencies:
|
|
9
|
+
patterns: ["*"]
|
|
10
|
+
labels: ["dependencies"]
|
|
11
|
+
|
|
12
|
+
- package-ecosystem: "github-actions"
|
|
13
|
+
directory: "/"
|
|
14
|
+
schedule:
|
|
15
|
+
interval: "weekly"
|
|
16
|
+
labels: ["dependencies", "ci"]
|
|
17
|
+
|
|
18
|
+
- package-ecosystem: "docker"
|
|
19
|
+
directory: "/"
|
|
20
|
+
schedule:
|
|
21
|
+
interval: "weekly"
|
|
22
|
+
labels: ["dependencies", "docker"]
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
quality:
|
|
18
|
+
name: Lint, type-check & security
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.12"
|
|
27
|
+
cache: pip
|
|
28
|
+
|
|
29
|
+
- name: Install
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install -e ".[api,dev]"
|
|
33
|
+
|
|
34
|
+
- name: Ruff (lint)
|
|
35
|
+
run: ruff check src tests
|
|
36
|
+
|
|
37
|
+
- name: Mypy (type-check)
|
|
38
|
+
run: mypy
|
|
39
|
+
|
|
40
|
+
- name: Bandit (static security scan)
|
|
41
|
+
run: bandit -q -r src -c pyproject.toml
|
|
42
|
+
|
|
43
|
+
- name: pip-audit (dependency vulnerabilities)
|
|
44
|
+
run: pip-audit
|
|
45
|
+
|
|
46
|
+
- name: NIST doc is in sync with catalog
|
|
47
|
+
run: |
|
|
48
|
+
python scripts/gen_nist_doc.py
|
|
49
|
+
git diff --exit-code docs/NIST_CONTROL_MAPPING.md \
|
|
50
|
+
|| (echo "::error::docs/NIST_CONTROL_MAPPING.md is stale; run 'make docs'" && exit 1)
|
|
51
|
+
|
|
52
|
+
test:
|
|
53
|
+
name: Tests (py${{ matrix.python-version }})
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
strategy:
|
|
56
|
+
fail-fast: false
|
|
57
|
+
matrix:
|
|
58
|
+
python-version: ["3.10", "3.11", "3.12"]
|
|
59
|
+
steps:
|
|
60
|
+
- uses: actions/checkout@v4
|
|
61
|
+
|
|
62
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
63
|
+
uses: actions/setup-python@v5
|
|
64
|
+
with:
|
|
65
|
+
python-version: ${{ matrix.python-version }}
|
|
66
|
+
cache: pip
|
|
67
|
+
|
|
68
|
+
- name: Install
|
|
69
|
+
run: |
|
|
70
|
+
python -m pip install --upgrade pip
|
|
71
|
+
pip install -e ".[api,dev]"
|
|
72
|
+
|
|
73
|
+
- name: Run tests
|
|
74
|
+
run: pytest -q
|
|
75
|
+
|
|
76
|
+
docker:
|
|
77
|
+
name: Build container image
|
|
78
|
+
runs-on: ubuntu-latest
|
|
79
|
+
needs: [quality, test]
|
|
80
|
+
steps:
|
|
81
|
+
- uses: actions/checkout@v4
|
|
82
|
+
- name: Build image
|
|
83
|
+
run: docker build -t mnemosyne-guard:ci .
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build distributions
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
- name: Build sdist and wheel
|
|
21
|
+
run: |
|
|
22
|
+
python -m pip install --upgrade pip build
|
|
23
|
+
python -m build
|
|
24
|
+
- name: Check metadata
|
|
25
|
+
run: |
|
|
26
|
+
pip install twine
|
|
27
|
+
twine check dist/*
|
|
28
|
+
- uses: actions/upload-artifact@v4
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish:
|
|
34
|
+
name: Publish to PyPI
|
|
35
|
+
needs: build
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
# Requires a configured PyPI "Trusted Publisher" for this repo + environment.
|
|
38
|
+
environment: release
|
|
39
|
+
permissions:
|
|
40
|
+
id-token: write # OIDC for trusted publishing; no API token needed
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/download-artifact@v4
|
|
43
|
+
with:
|
|
44
|
+
name: dist
|
|
45
|
+
path: dist/
|
|
46
|
+
- name: Publish
|
|
47
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
build/
|
|
8
|
+
dist/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.eggs/
|
|
11
|
+
*.egg
|
|
12
|
+
|
|
13
|
+
# Virtual environments
|
|
14
|
+
.venv/
|
|
15
|
+
venv/
|
|
16
|
+
env/
|
|
17
|
+
ENV/
|
|
18
|
+
|
|
19
|
+
# Test / coverage / type-check caches
|
|
20
|
+
.pytest_cache/
|
|
21
|
+
.ruff_cache/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.coverage
|
|
24
|
+
.coverage.*
|
|
25
|
+
htmlcov/
|
|
26
|
+
coverage.xml
|
|
27
|
+
|
|
28
|
+
# Runtime artifacts
|
|
29
|
+
*.db
|
|
30
|
+
*.sqlite
|
|
31
|
+
*.sqlite3
|
|
32
|
+
*.log
|
|
33
|
+
audit.jsonl
|
|
34
|
+
|
|
35
|
+
# Secrets / local env (never commit)
|
|
36
|
+
.env
|
|
37
|
+
.env.*
|
|
38
|
+
*.pem
|
|
39
|
+
*.key
|
|
40
|
+
|
|
41
|
+
# Editor / OS
|
|
42
|
+
.idea/
|
|
43
|
+
.vscode/
|
|
44
|
+
*.swp
|
|
45
|
+
.DS_Store
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Mnemosyne pre-commit hooks. Install with: pre-commit install
|
|
2
|
+
# Mirrors the CI quality gate so issues are caught before they are pushed.
|
|
3
|
+
minimum_pre_commit_version: "3.5.0"
|
|
4
|
+
|
|
5
|
+
repos:
|
|
6
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
+
rev: v4.6.0
|
|
8
|
+
hooks:
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: check-toml
|
|
13
|
+
- id: check-added-large-files
|
|
14
|
+
- id: check-merge-conflict
|
|
15
|
+
- id: detect-private-key
|
|
16
|
+
|
|
17
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
18
|
+
rev: v0.6.9
|
|
19
|
+
hooks:
|
|
20
|
+
- id: ruff
|
|
21
|
+
args: [--fix]
|
|
22
|
+
- id: ruff-format
|
|
23
|
+
|
|
24
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
25
|
+
rev: v1.11.2
|
|
26
|
+
hooks:
|
|
27
|
+
- id: mypy
|
|
28
|
+
additional_dependencies:
|
|
29
|
+
- pydantic>=2
|
|
30
|
+
- pydantic-settings
|
|
31
|
+
args: ["--config-file=pyproject.toml"]
|
|
32
|
+
pass_filenames: false
|
|
33
|
+
|
|
34
|
+
- repo: https://github.com/PyCQA/bandit
|
|
35
|
+
rev: 1.7.10
|
|
36
|
+
hooks:
|
|
37
|
+
- id: bandit
|
|
38
|
+
args: ["-c", "pyproject.toml", "-r", "src"]
|
|
39
|
+
pass_filenames: false
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
|
|
5
|
+
adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.1.0] - 2026-06-13
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Memory-integrity gateway** with two guarded operations, `guard_write` and
|
|
13
|
+
`guard_read`, enforcing the cardinal ASI06 invariant: content below the
|
|
14
|
+
`TRUSTED` tier can never reach an `INSTRUCTION` (control-plane) surface.
|
|
15
|
+
- **Provenance → trust-tier** resolution and **surface**-aware policy
|
|
16
|
+
(`INSTRUCTION` / `KNOWLEDGE` / `EPISODIC` / `SCRATCH`).
|
|
17
|
+
- **Detectors:**
|
|
18
|
+
- `injection` — instruction-override, role-reassignment, persistence,
|
|
19
|
+
tooling/config manipulation, exfiltration, delimiter smuggling, and
|
|
20
|
+
**delayed/conditional execution** (Gemini-style "delayed tool invocation").
|
|
21
|
+
- `secrets_pii` — cloud/provider keys, JWTs, private keys, and PII with
|
|
22
|
+
Luhn-checked card detection; redaction helper.
|
|
23
|
+
- `anomaly` — size/entropy checks plus a per-writer behavioral baseline with a
|
|
24
|
+
robust MAD z-score for gradual-erosion ("sleeper agent") detection.
|
|
25
|
+
- `obfuscation` — invisible-Unicode smuggling: Unicode Tag characters,
|
|
26
|
+
bidirectional overrides (Trojan Source), and zero-width interleaving, with
|
|
27
|
+
emoji-ZWJ awareness and a `strip()` sanitiser.
|
|
28
|
+
- **Declarative YAML policy engine** (most-restrictive-wins) with a secure
|
|
29
|
+
default policy.
|
|
30
|
+
- **Integrity:** HMAC-SHA256 record signing (constant-time verify, KMS/HSM hook)
|
|
31
|
+
and a hash-chained, tamper-evident audit log with chain verification.
|
|
32
|
+
- **Storage:** `MemoryStore` / `QuarantineStore` protocols with in-memory and
|
|
33
|
+
SQLite backends; namespace segmentation; human-in-the-loop quarantine
|
|
34
|
+
promotion that elevates trust to the target surface's requirement.
|
|
35
|
+
- **FastAPI sidecar** (bearer auth) and `mnemosyne` **CLI** (`scan`/`nist`/`version`).
|
|
36
|
+
- **NIST/OWASP control catalog** (MN-01…MN-11) mapping to NIST SP 800-53 Rev 5,
|
|
37
|
+
SP 800-218A, AI 600-1, and CSF 2.0; surfaced via `GET /v1/compliance`,
|
|
38
|
+
`mnemosyne nist`, and a generated `docs/NIST_CONTROL_MAPPING.md`.
|
|
39
|
+
- **Telemetry:** structured JSON logging and Prometheus metrics.
|
|
40
|
+
- **Tests:** 131 tests including a red-team corpus that asserts 100% detection
|
|
41
|
+
of the bundled ASI06 payloads and a 0% false-positive rate on benign writes.
|
|
42
|
+
- **Tooling & ops:** ruff, mypy, bandit, pip-audit, pre-commit, GitHub Actions
|
|
43
|
+
CI (lint/type/security/test matrix + doc-sync check), Dockerfile,
|
|
44
|
+
docker-compose, and a release workflow.
|
|
45
|
+
|
|
46
|
+
[Unreleased]: https://github.com/rsh1k/mnemosyne/compare/v0.1.0...HEAD
|
|
47
|
+
[0.1.0]: https://github.com/rsh1k/mnemosyne/releases/tag/v0.1.0
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
title: "Mnemosyne: A NIST-aligned Memory Integrity & Context-Provenance Firewall for Agentic AI"
|
|
3
|
+
message: "If you use this software, please cite it using these metadata."
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- name: "rsh1k"
|
|
7
|
+
alias: rsh1k
|
|
8
|
+
repository-code: "https://github.com/rsh1k/mnemosyne"
|
|
9
|
+
url: "https://github.com/rsh1k/mnemosyne"
|
|
10
|
+
abstract: >-
|
|
11
|
+
Mnemosyne is a defense-in-depth library and gateway service that protects the
|
|
12
|
+
persistent memory and context surfaces of agentic AI systems against OWASP
|
|
13
|
+
ASI06 (Memory & Context Poisoning). It enforces a provenance-to-trust-tier
|
|
14
|
+
invariant that prevents untrusted content from reaching instruction
|
|
15
|
+
(control-plane) surfaces, runs pluggable detectors (injection, secrets/PII,
|
|
16
|
+
statistical anomaly, and invisible-Unicode obfuscation), signs records with
|
|
17
|
+
HMAC-SHA256, keeps a hash-chained tamper-evident audit log, and maps its
|
|
18
|
+
controls to NIST SP 800-53, SP 800-218A, AI 600-1, and CSF 2.0.
|
|
19
|
+
keywords:
|
|
20
|
+
- ai-security
|
|
21
|
+
- agentic-ai
|
|
22
|
+
- owasp
|
|
23
|
+
- asi06
|
|
24
|
+
- memory-poisoning
|
|
25
|
+
- prompt-injection
|
|
26
|
+
- nist
|
|
27
|
+
license: Apache-2.0
|
|
28
|
+
version: 0.1.0
|
|
29
|
+
date-released: "2026-06-13"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our
|
|
6
|
+
community a harassment-free experience for everyone, regardless of age, body
|
|
7
|
+
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
|
8
|
+
identity and expression, level of experience, education, socio-economic status,
|
|
9
|
+
nationality, personal appearance, race, religion, or sexual identity and
|
|
10
|
+
orientation.
|
|
11
|
+
|
|
12
|
+
We pledge to act and interact in ways that contribute to an open, welcoming,
|
|
13
|
+
diverse, inclusive, and healthy community.
|
|
14
|
+
|
|
15
|
+
## Our Standards
|
|
16
|
+
|
|
17
|
+
Examples of behavior that contributes to a positive environment include
|
|
18
|
+
demonstrating empathy and kindness, being respectful of differing opinions,
|
|
19
|
+
giving and gracefully accepting constructive feedback, accepting responsibility
|
|
20
|
+
and apologizing to those affected by our mistakes, and focusing on what is best
|
|
21
|
+
for the overall community.
|
|
22
|
+
|
|
23
|
+
Unacceptable behavior includes the use of sexualized language or imagery,
|
|
24
|
+
trolling, insulting or derogatory comments, public or private harassment,
|
|
25
|
+
publishing others' private information without explicit permission, and other
|
|
26
|
+
conduct which could reasonably be considered inappropriate in a professional
|
|
27
|
+
setting.
|
|
28
|
+
|
|
29
|
+
## Enforcement Responsibilities
|
|
30
|
+
|
|
31
|
+
Community leaders are responsible for clarifying and enforcing our standards and
|
|
32
|
+
will take appropriate and fair corrective action in response to any behavior
|
|
33
|
+
they deem inappropriate, threatening, offensive, or harmful.
|
|
34
|
+
|
|
35
|
+
## Scope
|
|
36
|
+
|
|
37
|
+
This Code of Conduct applies within all community spaces and also applies when
|
|
38
|
+
an individual is officially representing the community in public spaces.
|
|
39
|
+
|
|
40
|
+
## Enforcement
|
|
41
|
+
|
|
42
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
|
43
|
+
reported to the community leaders responsible for enforcement via the contact
|
|
44
|
+
listed in the repository profile. All complaints will be reviewed and
|
|
45
|
+
investigated promptly and fairly.
|
|
46
|
+
|
|
47
|
+
## Attribution
|
|
48
|
+
|
|
49
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
|
50
|
+
version 2.1, available at
|
|
51
|
+
<https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
|
|
52
|
+
|
|
53
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
Thanks for your interest in improving Mnemosyne. This project guards a security
|
|
4
|
+
boundary, so contributions are held to a high bar for tests and clarity.
|
|
5
|
+
|
|
6
|
+
## Development setup
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/rsh1k/mnemosyne.git
|
|
10
|
+
cd mnemosyne
|
|
11
|
+
python -m venv .venv && source .venv/bin/activate
|
|
12
|
+
pip install -e ".[api,dev]"
|
|
13
|
+
pre-commit install
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## The golden rule
|
|
17
|
+
|
|
18
|
+
Every change is checked by `make all` (lint, type-check, security scan, tests).
|
|
19
|
+
CI runs the same targets. Run it locally before opening a PR:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
make all
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Individual targets:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
make test # pytest
|
|
29
|
+
make lint # ruff
|
|
30
|
+
make typecheck # mypy
|
|
31
|
+
make security # bandit + pip-audit
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Tests are mandatory
|
|
35
|
+
|
|
36
|
+
- New detectors, policy rules, or gateway behaviour **must** come with tests.
|
|
37
|
+
- Security-relevant changes should extend the **red-team corpus**
|
|
38
|
+
(`tests/test_redteam_corpus.py`). If you add a detection capability, add the
|
|
39
|
+
attack payloads it catches; if you relax something, prove benign writes still
|
|
40
|
+
pass. The aggregate detection-rate / false-positive-rate assertions must stay
|
|
41
|
+
green.
|
|
42
|
+
- The cardinal invariant (untrusted content never reaches the `INSTRUCTION`
|
|
43
|
+
surface) is sacred. A PR that weakens it will not be merged without an
|
|
44
|
+
explicit, documented security rationale.
|
|
45
|
+
|
|
46
|
+
## Adding a detector
|
|
47
|
+
|
|
48
|
+
1. Implement the `Detector` protocol in `src/mnemosyne/detectors/`.
|
|
49
|
+
2. Return a `ScanResult` of `Finding`s with a `severity`, a `score` in `[0,1]`,
|
|
50
|
+
and a `metadata["kind"]` (use `secret`/`pii` only for sensitive-data findings
|
|
51
|
+
— the policy engine routes those through the dedicated secrets rule).
|
|
52
|
+
3. Register it in `default_registry()` (or document it as opt-in).
|
|
53
|
+
4. Add unit tests and, where relevant, corpus entries.
|
|
54
|
+
|
|
55
|
+
## Changing policy
|
|
56
|
+
|
|
57
|
+
The default posture lives in `src/mnemosyne/policy/default_policy.yaml`. It is
|
|
58
|
+
security-critical configuration — explain the threat rationale in the PR. Keep
|
|
59
|
+
"most restrictive wins" intact.
|
|
60
|
+
|
|
61
|
+
## Updating the NIST mapping
|
|
62
|
+
|
|
63
|
+
The catalog in `src/mnemosyne/nist/__init__.py` is the single source of truth.
|
|
64
|
+
After editing it, regenerate the doc:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
python scripts/gen_nist_doc.py
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Style
|
|
71
|
+
|
|
72
|
+
- Code is formatted/linted by `ruff` (line length 100) and type-checked by
|
|
73
|
+
`mypy`. Public functions get type hints and a docstring explaining the *why*.
|
|
74
|
+
- Prefer clarity over cleverness; this is security code that will be audited.
|
|
75
|
+
|
|
76
|
+
## Commit / PR hygiene
|
|
77
|
+
|
|
78
|
+
- Small, focused PRs with a clear description of the threat or behaviour changed.
|
|
79
|
+
- Reference any related issue.
|
|
80
|
+
- By contributing you agree your contributions are licensed under Apache-2.0.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# syntax=docker/dockerfile:1
|
|
2
|
+
|
|
3
|
+
# ---- builder ---------------------------------------------------------------
|
|
4
|
+
FROM python:3.12-slim AS builder
|
|
5
|
+
|
|
6
|
+
ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
7
|
+
PIP_NO_CACHE_DIR=1
|
|
8
|
+
|
|
9
|
+
WORKDIR /build
|
|
10
|
+
COPY pyproject.toml README.md ./
|
|
11
|
+
COPY src ./src
|
|
12
|
+
|
|
13
|
+
# Build a wheel so the runtime image installs a clean, pinned artifact.
|
|
14
|
+
RUN pip install --upgrade pip build && python -m build --wheel --outdir /dist
|
|
15
|
+
|
|
16
|
+
# ---- runtime ---------------------------------------------------------------
|
|
17
|
+
FROM python:3.12-slim AS runtime
|
|
18
|
+
|
|
19
|
+
ENV PYTHONDONTWRITEBYTECODE=1 \
|
|
20
|
+
PYTHONUNBUFFERED=1 \
|
|
21
|
+
PIP_DISABLE_PIP_VERSION_CHECK=1 \
|
|
22
|
+
PIP_NO_CACHE_DIR=1
|
|
23
|
+
|
|
24
|
+
# Create an unprivileged user to run the service.
|
|
25
|
+
RUN groupadd --system mnemosyne && useradd --system --gid mnemosyne --create-home mnemosyne
|
|
26
|
+
|
|
27
|
+
WORKDIR /app
|
|
28
|
+
COPY --from=builder /dist/*.whl /tmp/
|
|
29
|
+
RUN pip install /tmp/*.whl "mnemosyne-guard[api]" && rm -f /tmp/*.whl
|
|
30
|
+
|
|
31
|
+
# Drop privileges.
|
|
32
|
+
USER mnemosyne
|
|
33
|
+
|
|
34
|
+
EXPOSE 8000
|
|
35
|
+
|
|
36
|
+
# NOTE: provide a real key at runtime, e.g.
|
|
37
|
+
# docker run -e MNEMOSYNE_INTEGRITY_KEY=... -e MNEMOSYNE_API_KEYS=... ...
|
|
38
|
+
ENV MNEMOSYNE_LOG_JSON=true
|
|
39
|
+
|
|
40
|
+
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
41
|
+
CMD python -c "import urllib.request,sys; sys.exit(0 if urllib.request.urlopen('http://127.0.0.1:8000/healthz').status==200 else 1)"
|
|
42
|
+
|
|
43
|
+
ENTRYPOINT ["uvicorn", "mnemosyne.api.main:factory", "--factory", \
|
|
44
|
+
"--host", "0.0.0.0", "--port", "8000"]
|