security-knowledge-os 0.2.0__tar.gz → 0.4.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.
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/PKG-INFO +10 -9
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/PUBLICATION_MANIFEST.md +45 -14
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/README.md +9 -8
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/REVIEW_PACKAGE.md +2 -2
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/__init__.py +1 -1
- security_knowledge_os-0.4.0/app/adapters/capgraph.py +219 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/adapters/mcp_config.py +100 -23
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/cli.py +110 -24
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/facts.py +7 -2
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/constraints.txt +1 -1
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/acceptance-criteria.md +1 -1
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/knowledge-corpus.md +10 -7
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/pack-schema.md +28 -2
- security_knowledge_os-0.4.0/knowledge/public/prompt-security/KU-0015-role-confusion.md +122 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/pyproject.toml +1 -1
- security_knowledge_os-0.4.0/rules/prompt/PI-004.yaml +28 -0
- security_knowledge_os-0.4.0/safe_tests/ST-RC-001.yaml +43 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/sbom.json +3 -3
- security_knowledge_os-0.4.0/tests/unit/test_capgraph.py +380 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_cli.py +2 -2
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_mcp_scan.py +5 -2
- security_knowledge_os-0.4.0/tests/unit/test_pi004_role_confusion.py +143 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_rule_loader.py +3 -1
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_safe_test.py +3 -1
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/.env.example +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/.github/workflows/ci.yml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/.github/workflows/publish.yml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/.gitignore +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/LICENSE +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/NOTICE +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/REVIEW_CHECKLIST.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/adapters/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/config.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/eval/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/eval/metrics.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/chunker.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/loader.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/parser.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/snapshot.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/ingestion/validator.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/llm/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/llm/anthropic_client.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/llm/base.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/llm/factory.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/llm/mock.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/main.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/_credential_shapes.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/answer.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/assessment.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/context.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/knowledge.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/llm_io.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/pack.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/policy_outcome.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/report.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/retrieval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/reviewer_output.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/risk.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/models/rule_clause.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/pack_cli.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/archive.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/build.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/diff.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/license.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/loader.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/manifest.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/signing.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/store.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/trusted_keys.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/packs/verify.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/policy/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/policy/classification.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/policy/human_gate.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/policy/knowledge_guard.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/policy/safe_test.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/retrieval/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/retrieval/base.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/retrieval/bm25.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/retrieval/hybrid.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/retrieval/index.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/answers.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/assess.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/attack_surface.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/clause_eval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/evidence.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/extensions.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/llm_review.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/normalize.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/questions.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/report.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/rollup.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/rule_engine.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/rule_loader.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/reviewer/vocabulary.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/safe_errors.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/storage/__init__.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/storage/db.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/storage/integrity.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/app/storage/repository.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/architecture.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/attribution.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/history-rewrite-map.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/knowledge-schema.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/rule-schema.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/safe-test-schema.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/safety-boundaries.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/docs/threat-model.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/private/README.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/private/confidential/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/private/internal/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/agent-security/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/agent-security/KU-0004-excessive-agency-least-privilege.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/agent-security/KU-0005-human-approval-gates.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/agent-security/KU-0006-outbound-channels-allowlist.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/credential-security/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/credential-security/KU-0008-secrets-not-reachable-by-model.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/credential-security/KU-0009-credential-broker-pattern.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/governance/KU-0012-human-oversight.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/incidents/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/incidents/KU-0014-llm-payload-identifier-leak.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/memory-security/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/memory-security/KU-0007-persistent-memory-poisoning.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/methodology/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/methodology/KU-0011-improper-output-handling.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/methodology/KU-0013-assume-compromise-ja.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/prompt-security/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/prompt-security/KU-0001-direct-prompt-injection.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/prompt-security/KU-0010-system-prompt-leakage.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/rag-security/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/rag-security/KU-0002-indirect-prompt-injection.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/knowledge/public/rag-security/KU-0003-untrusted-content-isolation.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/agent/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/agent/OUT-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/agent/TOOL-000.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/agent/TOOL-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/credential/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/credential/CRED-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/governance/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/governance/GOV-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/memory/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/memory/MEM-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/prompt/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/rag/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/rules/rag/PI-003.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/safe_tests/ST-CRED-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/safe_tests/ST-IPI-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/safe_tests/ST-MEM-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/safe_tests/ST-TOOL-001.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/_scheduled_cross_review.sh +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/assess.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/build_index.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/evaluate.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/generate_sbom.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/ingest.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/issue_license.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/preflight.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/run_cross_review.sh +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/secret_scan.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/validate_knowledge.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/validate_rules.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/scripts/validate_safe_tests.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/conftest.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/safe/S-001-prompt-only.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/safe/S-002-rag-trusted-no-actions.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/safe/S-003-readonly-tool-with-approval.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/safe/S-004-credential-proxy.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/unknown/U-001-tool-permissions-missing.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/unknown/U-002-memory-persistence-unspecified.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/unknown/U-003-outbound-destination-unspecified.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/unknown/U-004-credential-handling-unspecified.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/unknown/U-005-tool-permission-unrecognized.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/vulnerable/V-001-indirect-injection-auto-email.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/vulnerable/V-002-rag-delete-tool-no-approval.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/vulnerable/V-003-persistent-memory-untrusted.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/vulnerable/V-004-env-secret-readable.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/assessments/vulnerable/V-005-unlisted-rag-source-untrusted-memory.yaml +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/private/confidential/KU-1020-confidential-tool-matrix.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/private/internal/KU-1010-internal-memory-heuristic.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/public/credential-security/KU-1003-env-secret-exposure.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/public/prompt-security/KU-1001-instruction-data-boundary.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/public/rag-security/KU-1002-indirect-injection-external-document.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus/secret/KU-1099-secret-must-not-index.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/corpus_alt/public/methodology/KU-2001-alt-corpus-marker.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/invalid/KU-0010-mislabeled.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/invalid/bad-classification.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/invalid/bad-id.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/invalid/missing-fields.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/invalid/no-front-matter.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/private/internal/KU-0002-internal-note.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/public/methodology/KU-0003-sparse.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/public/prompt-security/KU-0001-instruction-hierarchy.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/fixtures/knowledge/secret/KU-0009-secret.md +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/integration/.gitkeep +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_answers.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_anthropic_client.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_api.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_assess.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_assess_m4.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_assess_m5.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_assess_script.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_assessment_input.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_build_index_script.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_classification_gate.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_classification_leakage.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_clause_eval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_config.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_cross_review_script.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_db.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_eval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_evaluate_script.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_evidence.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_fail_closed.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_finding_boundary.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_generate_sbom.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_human_gate.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_ingest_script.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_ja_retrieval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_knowledge_corpus.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_knowledge_guard.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_knowledge_root_config.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_knowledge_schema.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_llm_adapter.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_llm_boundary.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_llm_output_schema.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_llm_review.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_loader.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_no_code_execution.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_no_secret_echo.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_normalize.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_packs.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_packs_cli.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_parser.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_policy_outcome.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_preflight_manifest.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_questions.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_reindex.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_report.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_repository.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_retrieval.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_rollup.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_rule_engine.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_secret_scan.py +0 -0
- {security_knowledge_os-0.2.0 → security_knowledge_os-0.4.0}/tests/unit/test_snapshot.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: security-knowledge-os
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Deterministic security assessment engine + knowledge retrieval + optional LLM assistance
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -141,11 +141,11 @@ treated as data, never as a control instruction. Details in
|
|
|
141
141
|
| --- | --- | --- |
|
|
142
142
|
| **M1 — Skeleton + Schema + Validator** | done | directory tree, `app/models/*`, `app/ingestion/validator.py`, `scripts/validate_knowledge.py`, `docs/knowledge-schema.md` |
|
|
143
143
|
| **M2 — Knowledge Loader + FTS5 Retrieval** | done | `app/ingestion/{loader,chunker}.py`, `app/storage/{db,repository}.py`, `app/retrieval/{base,bm25,hybrid,index}.py`, `scripts/{ingest,build_index}.py` |
|
|
144
|
-
| **M3 — Deterministic Rule Engine** | done | `app/models/rule_clause.py`, `app/reviewer/{facts,clause_eval,rule_loader,rule_engine,normalize,attack_surface,evidence,rollup,assess}.py`, `rules/**` (
|
|
144
|
+
| **M3 — Deterministic Rule Engine** | done | `app/models/rule_clause.py`, `app/reviewer/{facts,clause_eval,rule_loader,rule_engine,normalize,attack_surface,evidence,rollup,assess}.py`, `rules/**` (8 rules), `scripts/validate_rules.py`, `docs/rule-schema.md` |
|
|
145
145
|
| **M4 — LLM Adapter + Reviewer** | done | `app/llm/{base,mock,anthropic_client,factory}.py`, `app/models/{reviewer_output,llm_io}.py`, `app/reviewer/{llm_review,questions}.py`, `assess()` full, `scripts/assess.py` |
|
|
146
|
-
| **M5 — Safe Test + Human Gate** | done | `app/models/policy_outcome.py`, `app/policy/{human_gate,knowledge_guard,safe_test}.py`, `app/storage/integrity.py`, `safe_tests/**` (
|
|
146
|
+
| **M5 — Safe Test + Human Gate** | done | `app/models/policy_outcome.py`, `app/policy/{human_gate,knowledge_guard,safe_test}.py`, `app/storage/integrity.py`, `safe_tests/**` (5 templates), `scripts/validate_safe_tests.py` |
|
|
147
147
|
| **M6 — Orchestrator + CLI + API** | done | `app/models/report.py`, `app/reviewer/report.py`, `app/cli.py` (`skos`), `app/main.py` (FastAPI), `app/retrieval/index.py::reindex_atomic` |
|
|
148
|
-
| **M7 — Fixtures + Evaluation + starter KUs** | done | `knowledge/public/**` (
|
|
148
|
+
| **M7 — Fixtures + Evaluation + starter KUs** | done | `knowledge/public/**` (15 KUs), `tests/fixtures/assessments/{safe,vulnerable,unknown}/`, `app/eval/metrics.py`, `scripts/evaluate.py`, JA retrieval (trigram) |
|
|
149
149
|
| **M8 — Docs + hardening** | done | Security disclaimer (AC-15–18), KU `provenance` schema, `docs/{attribution,threat-model,architecture}.md`, `sbom.json`, `scripts/{secret_scan,generate_sbom,preflight}.py` |
|
|
150
150
|
|
|
151
151
|
## Install
|
|
@@ -193,16 +193,17 @@ python3.12 -m venv .venv
|
|
|
193
193
|
.venv/bin/pytest -q
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
The MVP ships **
|
|
196
|
+
The MVP ships **15 public Knowledge Units** (`knowledge/public/`; 13 from
|
|
197
197
|
published standards - OWASP LLM Top 10 2025, MITRE ATLAS, NIST AI RMF / AI 600-1;
|
|
198
|
-
one in Japanese - plus
|
|
199
|
-
class this project's own pre-publication review process actually found
|
|
198
|
+
one in Japanese - plus KU-0014, an original write-up of a vulnerability
|
|
199
|
+
class this project's own pre-publication review process actually found, and
|
|
200
|
+
KU-0015, a summary of published research on prompt injection as role confusion). Each
|
|
200
201
|
unit carries `provenance` (source title, URL, version, licence, derivation
|
|
201
202
|
status, last-verified date). See `docs/knowledge-corpus.md` and
|
|
202
203
|
`docs/attribution.md`.
|
|
203
204
|
|
|
204
205
|
**Internal fixture evaluation** (`scripts/evaluate.py`, 14 artificial fixtures ×
|
|
205
|
-
|
|
206
|
+
15 indexed KUs):
|
|
206
207
|
|
|
207
208
|
```
|
|
208
209
|
Classification Leakage = 0
|
|
@@ -354,7 +355,7 @@ See `.env.example`.
|
|
|
354
355
|
- `docs/knowledge-schema.md` — Knowledge Unit schema (front matter + `provenance` + body)
|
|
355
356
|
- `docs/rule-schema.md` — data-only rule schema and operators
|
|
356
357
|
- `docs/safe-test-schema.md` — safe-test schema, validator rules, Human Gate, read-only guard
|
|
357
|
-
- `docs/knowledge-corpus.md` — the
|
|
358
|
+
- `docs/knowledge-corpus.md` — the 15 shipped Knowledge Units and their sources
|
|
358
359
|
- `docs/attribution.md` — third-party sources, licences, derivation status
|
|
359
360
|
- `docs/acceptance-criteria.md` — AC-01..20 status and §24 evaluation metrics
|
|
360
361
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# Publication Manifest — Security Knowledge OS v0.
|
|
1
|
+
# Publication Manifest — Security Knowledge OS v0.4.0
|
|
2
2
|
|
|
3
3
|
Snapshot of what the first public push contains. Generated for the pre-publication
|
|
4
4
|
review; regenerate with `git ls-files` after any change.
|
|
5
5
|
|
|
6
|
-
- Commit: `
|
|
6
|
+
- Commit: `4ac7982` (v0.4.0: role-confusion KU-0015 / rule PI-004 / safe test ST-RC-001 + urllib3 2.8.0; v0.3.0 `2627b44` added whole-agent capability labels for the `capgraph` pack; 0.2.0 was `316e8c6`, 0.1.0 `a7f463d`)
|
|
7
7
|
- History: rewritten once on 2026-09-20, before first publication, to normalise author/committer identity to the
|
|
8
8
|
GitHub no-reply address (one commit message also scrubbed of a local account name). Every commit's tree is
|
|
9
9
|
identical before and after, so the reviewed content is the published content; commit hashes cited in the
|
|
10
10
|
review records below are the **pre-rewrite** ones - see `docs/history-rewrite-map.md` for old -> new.
|
|
11
11
|
- Licence: **Apache-2.0** (`LICENSE`, `NOTICE`, `pyproject.toml`)
|
|
12
|
-
- Tracked files: **
|
|
13
|
-
- Tests: **
|
|
12
|
+
- Tracked files: **248**
|
|
13
|
+
- Tests: **992** items (991 pass, 1 skip = JA-R02)
|
|
14
14
|
- `scripts/preflight.py`: **PASS** (now also verifies the documented
|
|
15
15
|
quickstart `pip install -e` command installs every declared extra,
|
|
16
16
|
pins `constraints.txt`, AND passes `--build-constraint constraints.txt`
|
|
@@ -798,6 +798,32 @@ review; regenerate with `git ls-files` after any change.
|
|
|
798
798
|
empty value in a URL, or a flag with no value, is reported as a literal
|
|
799
799
|
secret - a false positive).
|
|
800
800
|
|
|
801
|
+
**v0.3.0 capability-label review** (2026-09-29, scoped to `master..2627b44`:
|
|
802
|
+
`app/adapters/capgraph.py`, the `skos scan mcp --client` / `_agent.yaml` /
|
|
803
|
+
`capability-labels.json` changes in `app/adapters/mcp_config.py` and
|
|
804
|
+
`app/cli.py`, plus the separate data-only `capgraph` pack source). Codex,
|
|
805
|
+
three rounds, each CHANGES-REQUIRED and fixed: round 1 (`5b6a115`) 10
|
|
806
|
+
findings (4 HIGH: package impersonation via launcher path or environment,
|
|
807
|
+
server identity bound to file names, browser and memory profiles claiming
|
|
808
|
+
absent capabilities); round 2 (`75f146f`) residuals plus 2 new (HIGH: a pack
|
|
809
|
+
failing verification treated as not installed); round 3 (`2cc494b`) one
|
|
810
|
+
residual HIGH (`pnpm exec`/`yarn exec` run a local command) and one LOW
|
|
811
|
+
(npx server arguments). Fixed in `970a1b1`, reviewed by Antigravity:
|
|
812
|
+
**PASS-with-nits**; the test nit was added in `2627b44`. The medium-rule
|
|
813
|
+
suppression Codex flagged as G10 is documented in the pack README (engine
|
|
814
|
+
policy), not changed.
|
|
815
|
+
|
|
816
|
+
**v0.4.0 role-confusion review** (2026-10-07 -- 2026-10-08, scoped to
|
|
817
|
+
`3fdd7f8..62fea58`: KU-0015, rule PI-004 and fact `has_unapproved_shell_tool`,
|
|
818
|
+
safe test ST-RC-001, urllib3 2.7.0 -> 2.8.0 for PYSEC-2026-4175/4176/4177).
|
|
819
|
+
Codex round 1 (`43ca56f`) **CHANGES-REQUIRED**: 1 must-fix (KU-0015 claimed a
|
|
820
|
+
model-side fix was required although the source paper evaluates no defence)
|
|
821
|
+
and 5 nice-to-have (PI-004 checked all high-impact tools, RAG-only scope not
|
|
822
|
+
stated, loose test assertions, ST-RC-001 conflated a gate block with no role
|
|
823
|
+
confusion, stale counts); all fixed in `416229d`. Codex round 2 (`bd61f34`)
|
|
824
|
+
**PASS-with-nits**, all round-1 findings confirmed resolved; the one test nit
|
|
825
|
+
(unknown check with manual_review stays UNKNOWN) added in `62fea58`.
|
|
826
|
+
|
|
801
827
|
## Tracked files by area
|
|
802
828
|
|
|
803
829
|
Per-area counts below were last verified at round 2 (commit `bcd9519`) and
|
|
@@ -807,11 +833,11 @@ check enforces (total tracked files, total tests) are kept current above.
|
|
|
807
833
|
|
|
808
834
|
| area | files | notes |
|
|
809
835
|
| --- | --- | --- |
|
|
810
|
-
| `app/` |
|
|
811
|
-
| `tests/` |
|
|
812
|
-
| `knowledge/` |
|
|
813
|
-
| `rules/` |
|
|
814
|
-
| `safe_tests/` |
|
|
836
|
+
| `app/` | 77 (.py) | engine, models, policy, retrieval, reviewer, llm, storage, eval, cli, main, packs (Update Pack manager), adapters (MCP config scan, capability labels) |
|
|
837
|
+
| `tests/` | 88 | 57 test modules + fixtures |
|
|
838
|
+
| `knowledge/` | 25 | 15 public KUs + `private/` skeleton (README + 2 `.gitkeep`) + category `.gitkeep`s |
|
|
839
|
+
| `rules/` | 14 | 8 rule YAMLs + category `.gitkeep`s |
|
|
840
|
+
| `safe_tests/` | 5 | 5 vetted templates |
|
|
815
841
|
| `scripts/` | 13 | validators, ingest/build_index, assess, evaluate, sbom, secret_scan, preflight, cross-review runner, issue_license |
|
|
816
842
|
| `docs/` | 11 | see below |
|
|
817
843
|
| `reviews/` | 2 | `.gitignore` + `README.md` only — cross-review output `.md`/`.log` files are gitignored, never tracked |
|
|
@@ -833,13 +859,15 @@ Docs: `architecture`, `threat-model`, `safety-boundaries`, `knowledge-schema`,
|
|
|
833
859
|
Verified: no `secret/`, no `.env`, no private-KU content tracked
|
|
834
860
|
(`scripts/preflight.py`).
|
|
835
861
|
|
|
836
|
-
## Public Knowledge Units (
|
|
862
|
+
## Public Knowledge Units (15)
|
|
837
863
|
|
|
838
864
|
All `classification: public`, `status: reviewed`. 13 are `derivation: summary`
|
|
839
865
|
(original prose, no verbatim third-party text, citing a published standard).
|
|
840
866
|
KU-0014 is `derivation: original` / `source_type: incident` — a first-party
|
|
841
867
|
write-up of a vulnerability class found by this project's own pre-publication
|
|
842
|
-
cross-AI review (rounds 9-14), not sourced from any external standard.
|
|
868
|
+
cross-AI review (rounds 9-14), not sourced from any external standard.
|
|
869
|
+
KU-0015 is `derivation: summary` / `source_type: manual` — own-prose summary of a
|
|
870
|
+
published research paper (arXiv:2603.12277), no verbatim text. Full
|
|
843
871
|
list + per-unit sources in `docs/knowledge-corpus.md`; licence analysis in
|
|
844
872
|
`docs/attribution.md`.
|
|
845
873
|
|
|
@@ -859,12 +887,14 @@ list + per-unit sources in `docs/knowledge-corpus.md`; licence analysis in
|
|
|
859
887
|
| KU-0012 | governance | NIST AI RMF 1.0 |
|
|
860
888
|
| KU-0013 | methodology (Japanese) | MITRE ATLAS + OWASP LLM06 |
|
|
861
889
|
| KU-0014 | incident | original (this project's own cross-AI review, rounds 9-14) |
|
|
890
|
+
| KU-0015 | prompt-security | arXiv:2603.12277 (ICML 2026), summarised not reproduced |
|
|
862
891
|
|
|
863
892
|
Source licences: OWASP CC-BY-SA-4.0 · MITRE ATLAS Terms of Use · NIST public
|
|
864
|
-
domain · KU-0014 original (no external licence applies)
|
|
893
|
+
domain · KU-0014 original (no external licence applies) · KU-0015 summarises an
|
|
894
|
+
arXiv paper (arXiv non-exclusive licence; no text reproduced). No content in the
|
|
865
895
|
repo is under terms incompatible with Apache-2.0 redistribution.
|
|
866
896
|
|
|
867
|
-
## Rules (
|
|
897
|
+
## Rules (8)
|
|
868
898
|
|
|
869
899
|
`rules/` — data-only YAML, operators `{eq, ne, in, contains, is_unknown}`, facts
|
|
870
900
|
from `app/reviewer/facts.py::FACT_SPEC` (whitelist).
|
|
@@ -872,6 +902,7 @@ from `app/reviewer/facts.py::FACT_SPEC` (whitelist).
|
|
|
872
902
|
| id | severity | category | detects |
|
|
873
903
|
| --- | --- | --- | --- |
|
|
874
904
|
| PI-003 | high | rag-security | indirect injection + outbound path |
|
|
905
|
+
| PI-004 | high | prompt-security | declared untrusted retrieval + shell tool (role confusion) |
|
|
875
906
|
| MEM-001 | high | memory-security | persistent memory + untrusted ingestion |
|
|
876
907
|
| TOOL-001 | high | agent-security | high-impact tool without approval |
|
|
877
908
|
| TOOL-000 | medium | agent-security | tool permissions unspecified -> UNKNOWN |
|
|
@@ -879,7 +910,7 @@ from `app/reviewer/facts.py::FACT_SPEC` (whitelist).
|
|
|
879
910
|
| GOV-001 | medium | governance | high-impact actions without approval coverage |
|
|
880
911
|
| OUT-001 | medium | agent-security | outbound enabled without a destination allow-list |
|
|
881
912
|
|
|
882
|
-
Safe-test templates (
|
|
913
|
+
Safe-test templates (5): `ST-IPI-001`, `ST-MEM-001`, `ST-TOOL-001`, `ST-CRED-001`, `ST-RC-001`.
|
|
883
914
|
|
|
884
915
|
## Fixtures
|
|
885
916
|
|
|
@@ -115,11 +115,11 @@ treated as data, never as a control instruction. Details in
|
|
|
115
115
|
| --- | --- | --- |
|
|
116
116
|
| **M1 — Skeleton + Schema + Validator** | done | directory tree, `app/models/*`, `app/ingestion/validator.py`, `scripts/validate_knowledge.py`, `docs/knowledge-schema.md` |
|
|
117
117
|
| **M2 — Knowledge Loader + FTS5 Retrieval** | done | `app/ingestion/{loader,chunker}.py`, `app/storage/{db,repository}.py`, `app/retrieval/{base,bm25,hybrid,index}.py`, `scripts/{ingest,build_index}.py` |
|
|
118
|
-
| **M3 — Deterministic Rule Engine** | done | `app/models/rule_clause.py`, `app/reviewer/{facts,clause_eval,rule_loader,rule_engine,normalize,attack_surface,evidence,rollup,assess}.py`, `rules/**` (
|
|
118
|
+
| **M3 — Deterministic Rule Engine** | done | `app/models/rule_clause.py`, `app/reviewer/{facts,clause_eval,rule_loader,rule_engine,normalize,attack_surface,evidence,rollup,assess}.py`, `rules/**` (8 rules), `scripts/validate_rules.py`, `docs/rule-schema.md` |
|
|
119
119
|
| **M4 — LLM Adapter + Reviewer** | done | `app/llm/{base,mock,anthropic_client,factory}.py`, `app/models/{reviewer_output,llm_io}.py`, `app/reviewer/{llm_review,questions}.py`, `assess()` full, `scripts/assess.py` |
|
|
120
|
-
| **M5 — Safe Test + Human Gate** | done | `app/models/policy_outcome.py`, `app/policy/{human_gate,knowledge_guard,safe_test}.py`, `app/storage/integrity.py`, `safe_tests/**` (
|
|
120
|
+
| **M5 — Safe Test + Human Gate** | done | `app/models/policy_outcome.py`, `app/policy/{human_gate,knowledge_guard,safe_test}.py`, `app/storage/integrity.py`, `safe_tests/**` (5 templates), `scripts/validate_safe_tests.py` |
|
|
121
121
|
| **M6 — Orchestrator + CLI + API** | done | `app/models/report.py`, `app/reviewer/report.py`, `app/cli.py` (`skos`), `app/main.py` (FastAPI), `app/retrieval/index.py::reindex_atomic` |
|
|
122
|
-
| **M7 — Fixtures + Evaluation + starter KUs** | done | `knowledge/public/**` (
|
|
122
|
+
| **M7 — Fixtures + Evaluation + starter KUs** | done | `knowledge/public/**` (15 KUs), `tests/fixtures/assessments/{safe,vulnerable,unknown}/`, `app/eval/metrics.py`, `scripts/evaluate.py`, JA retrieval (trigram) |
|
|
123
123
|
| **M8 — Docs + hardening** | done | Security disclaimer (AC-15–18), KU `provenance` schema, `docs/{attribution,threat-model,architecture}.md`, `sbom.json`, `scripts/{secret_scan,generate_sbom,preflight}.py` |
|
|
124
124
|
|
|
125
125
|
## Install
|
|
@@ -167,16 +167,17 @@ python3.12 -m venv .venv
|
|
|
167
167
|
.venv/bin/pytest -q
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
-
The MVP ships **
|
|
170
|
+
The MVP ships **15 public Knowledge Units** (`knowledge/public/`; 13 from
|
|
171
171
|
published standards - OWASP LLM Top 10 2025, MITRE ATLAS, NIST AI RMF / AI 600-1;
|
|
172
|
-
one in Japanese - plus
|
|
173
|
-
class this project's own pre-publication review process actually found
|
|
172
|
+
one in Japanese - plus KU-0014, an original write-up of a vulnerability
|
|
173
|
+
class this project's own pre-publication review process actually found, and
|
|
174
|
+
KU-0015, a summary of published research on prompt injection as role confusion). Each
|
|
174
175
|
unit carries `provenance` (source title, URL, version, licence, derivation
|
|
175
176
|
status, last-verified date). See `docs/knowledge-corpus.md` and
|
|
176
177
|
`docs/attribution.md`.
|
|
177
178
|
|
|
178
179
|
**Internal fixture evaluation** (`scripts/evaluate.py`, 14 artificial fixtures ×
|
|
179
|
-
|
|
180
|
+
15 indexed KUs):
|
|
180
181
|
|
|
181
182
|
```
|
|
182
183
|
Classification Leakage = 0
|
|
@@ -328,7 +329,7 @@ See `.env.example`.
|
|
|
328
329
|
- `docs/knowledge-schema.md` — Knowledge Unit schema (front matter + `provenance` + body)
|
|
329
330
|
- `docs/rule-schema.md` — data-only rule schema and operators
|
|
330
331
|
- `docs/safe-test-schema.md` — safe-test schema, validator rules, Human Gate, read-only guard
|
|
331
|
-
- `docs/knowledge-corpus.md` — the
|
|
332
|
+
- `docs/knowledge-corpus.md` — the 15 shipped Knowledge Units and their sources
|
|
332
333
|
- `docs/attribution.md` — third-party sources, licences, derivation status
|
|
333
334
|
- `docs/acceptance-criteria.md` — AC-01..20 status and §24 evaluation metrics
|
|
334
335
|
|
|
@@ -133,7 +133,7 @@ secret/ OUTSIDE the repository. Never indexed, never sent to an LLM.
|
|
|
133
133
|
- Retrieval filters by `is_retrievable(classification, mode, allow_confidential)`
|
|
134
134
|
in SQL **and** re-checks each returned chunk (defence in depth); a leak raises
|
|
135
135
|
`PolicyBlocked`.
|
|
136
|
-
- All
|
|
136
|
+
- All 15 shipped Knowledge Units are `classification: public`.
|
|
137
137
|
- `PolicyOutcome` enum: `ALLOWED` / `HUMAN_APPROVAL_REQUIRED` / `POLICY_BLOCKED` /
|
|
138
138
|
`READ_ONLY_VIOLATION` (typed, never a bare string).
|
|
139
139
|
|
|
@@ -149,7 +149,7 @@ secret/ OUTSIDE the repository. Never indexed, never sent to an LLM.
|
|
|
149
149
|
| JA-R02 (cross-language retrieval) | out of MVP scope; test skipped |
|
|
150
150
|
| Update Pack / Pack Manager | not in this codebase (M9-M10, separate track); the ZIP-import attack surface it introduces is future work |
|
|
151
151
|
| snapshot consistency vs. a COORDINATING writer | whole-tree re-verification catches ordinary concurrent updates; a writer that swaps directory generations during the verification pass itself is accepted (trust boundary: the tree root must not be writable by untrusted parties; a writer with write access can replace a rule directly). See `docs/threat-model.md` (Codex#1, round 23) |
|
|
152
|
-
| trigram tokenizer | substring matching; can over-retrieve on a large corpus (fine for
|
|
152
|
+
| trigram tokenizer | substring matching; can over-retrieve on a large corpus (fine for 15 KUs) |
|
|
153
153
|
|
|
154
154
|
## 10. How to run
|
|
155
155
|
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
"""Capability labels for one agent, derived from its MCP client config.
|
|
2
|
+
|
|
3
|
+
Each server gets six labels - ``untrusted_input``, ``sensitive_read``,
|
|
4
|
+
``egress``, ``exec``, ``write``, ``persistence`` - valued ``True`` /
|
|
5
|
+
``False`` / ``None`` (unknown). A label is ``True`` only when the config
|
|
6
|
+
(package identity, launch options) establishes it, and ``False`` only when
|
|
7
|
+
the absence is established the same way; a server the scanner does not know
|
|
8
|
+
keeps every label ``None``. Tool descriptions are never used: they can lie.
|
|
9
|
+
|
|
10
|
+
The agent is the union of its servers and the client's own built-in tools,
|
|
11
|
+
combined with a three-valued OR (any ``True`` -> ``True``; all ``False`` ->
|
|
12
|
+
``False``; otherwise ``None``). When the client is not declared, nothing is
|
|
13
|
+
known about its built-in tools, so an aggregate ``False`` becomes ``None``.
|
|
14
|
+
|
|
15
|
+
The result feeds the ``capgraph`` Update Pack (``extensions.capgraph``) and
|
|
16
|
+
is also written as ``capability-labels.json`` for runtime enforcement (for
|
|
17
|
+
example a gateway that decides trust from the same labels). Only server
|
|
18
|
+
names from the config appear in either output (project paths are replaced by
|
|
19
|
+
opaque ids), never configuration values.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import json
|
|
25
|
+
from dataclasses import dataclass, field
|
|
26
|
+
|
|
27
|
+
from app.adapters.mcp_config import ServerScan
|
|
28
|
+
|
|
29
|
+
LABELS = ("untrusted_input", "sensitive_read", "egress", "exec", "write", "persistence")
|
|
30
|
+
# Written to extensions.capgraph; every key becomes a ``capgraph_<key>`` fact.
|
|
31
|
+
FACT_KEYS = (*LABELS, "flow_gated", "egress_gated")
|
|
32
|
+
SCHEMA = "capgraph/v0"
|
|
33
|
+
AGENT_FILE_STEM = "_agent" # reserved: no server may be written under this name
|
|
34
|
+
CLIENTS = ("claude-code", "none")
|
|
35
|
+
|
|
36
|
+
Label = bool | None
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
@dataclass(frozen=True)
|
|
40
|
+
class _Caps:
|
|
41
|
+
"""What a known package can do beyond the MCP scanner's own facts."""
|
|
42
|
+
|
|
43
|
+
sensitive_read: Label = None
|
|
44
|
+
persistence: Label = None
|
|
45
|
+
write_scope: str | None = None # "fs" = the scanner's fs_scope
|
|
46
|
+
# the scanner's "no shell" does not mean "no code": a browser runs
|
|
47
|
+
# JavaScript on the pages it drives
|
|
48
|
+
exec_unknown: bool = False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# By exact (ecosystem, package) identity, like the scanner's own profiles.
|
|
52
|
+
_KNOWN: dict[tuple[str, str], _Caps] = {
|
|
53
|
+
# scope-dependent: see _labels()
|
|
54
|
+
("npm", "@modelcontextprotocol/server-filesystem"): _Caps(None, True, "fs"),
|
|
55
|
+
# private repositories/messages behind the token; pushes can change CI
|
|
56
|
+
("npm", "@modelcontextprotocol/server-github"): _Caps(True, True, "remote"),
|
|
57
|
+
("npm", "@modelcontextprotocol/server-gitlab"): _Caps(True, True, "remote"),
|
|
58
|
+
("npm", "@modelcontextprotocol/server-slack"): _Caps(True, None, "remote"),
|
|
59
|
+
# a browser reaches intranet pages and the host's services, submits forms
|
|
60
|
+
# and can store content that is loaded again later (Codex capgraph G03)
|
|
61
|
+
("npm", "@modelcontextprotocol/server-puppeteer"): _Caps(None, None, "remote", True),
|
|
62
|
+
("npm", "@playwright/mcp"): _Caps(None, None, "remote", True),
|
|
63
|
+
("npm", "@modelcontextprotocol/server-brave-search"): _Caps(False, False, "none"),
|
|
64
|
+
# what it stores is loaded into later sessions; what it holds - and where
|
|
65
|
+
# the file is - is not visible (Codex capgraph G04)
|
|
66
|
+
("npm", "@modelcontextprotocol/server-memory"): _Caps(None, True, None),
|
|
67
|
+
("npm", "@wonderwhy-er/desktop-commander"): _Caps(True, True, "root"),
|
|
68
|
+
# fetch can reach localhost and intranet URLs
|
|
69
|
+
("pypi", "mcp-server-fetch"): _Caps(None, False, "none"),
|
|
70
|
+
("pypi", "mcp-server-git"): _Caps(None, None, "project"),
|
|
71
|
+
("pypi", "mcp-server-time"): _Caps(False, False, "none"),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
# Built-in tools of an agent client, by --client name. "none" declares a
|
|
75
|
+
# client without built-in tools (e.g. a custom agent that only uses MCP).
|
|
76
|
+
_CLIENTS: dict[str, dict[str, Label]] = {
|
|
77
|
+
# Bash, Read/Edit/Write, WebFetch/WebSearch
|
|
78
|
+
"claude-code": {
|
|
79
|
+
"untrusted_input": True, "sensitive_read": True, "egress": True,
|
|
80
|
+
"exec": True, "write": True, "persistence": True,
|
|
81
|
+
},
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
@dataclass
|
|
86
|
+
class ServerLabels:
|
|
87
|
+
name: str # the scan's file stem (used in notes and file names)
|
|
88
|
+
server: str # exact server name in the config
|
|
89
|
+
scope: str # "global" or "project-<id>"
|
|
90
|
+
labels: dict[str, Label]
|
|
91
|
+
write_scope: str | None
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@dataclass
|
|
95
|
+
class AgentLabels:
|
|
96
|
+
client: str | None
|
|
97
|
+
servers: list[ServerLabels]
|
|
98
|
+
labels: dict[str, Label] = field(default_factory=dict)
|
|
99
|
+
contributors: dict[str, list[str]] = field(default_factory=dict)
|
|
100
|
+
|
|
101
|
+
def facts(self) -> dict[str, Label]:
|
|
102
|
+
"""The ``extensions.capgraph`` block. The gates (``flow_gated``,
|
|
103
|
+
``egress_gated``) are not visible in a config: they are left for the
|
|
104
|
+
operator and asked when a combination they guard applies."""
|
|
105
|
+
return {**self.labels, "flow_gated": None, "egress_gated": None}
|
|
106
|
+
|
|
107
|
+
def notes(self) -> list[str]:
|
|
108
|
+
out = []
|
|
109
|
+
if self.client is None:
|
|
110
|
+
out.append(
|
|
111
|
+
"client not declared (--client): its built-in tools are unknown, so no label "
|
|
112
|
+
"is claimed absent"
|
|
113
|
+
)
|
|
114
|
+
for label in LABELS:
|
|
115
|
+
if self.contributors.get(label):
|
|
116
|
+
out.append(f"{label} <- {', '.join(self.contributors[label])}")
|
|
117
|
+
return out
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _labels(scan: ServerScan) -> ServerLabels:
|
|
121
|
+
f = scan.facts
|
|
122
|
+
labels: dict[str, Label] = {
|
|
123
|
+
"untrusted_input": f.get("ingests_untrusted_content"),
|
|
124
|
+
"sensitive_read": None,
|
|
125
|
+
"egress": f.get("can_send"),
|
|
126
|
+
"exec": f.get("shell_exec"),
|
|
127
|
+
"write": f.get("can_write"),
|
|
128
|
+
"persistence": None,
|
|
129
|
+
}
|
|
130
|
+
write_scope: str | None = None
|
|
131
|
+
caps = None
|
|
132
|
+
if scan.package is not None and scan.ecosystem is not None:
|
|
133
|
+
caps = _KNOWN.get((scan.ecosystem, scan.package))
|
|
134
|
+
if caps is not None:
|
|
135
|
+
labels["sensitive_read"] = caps.sensitive_read
|
|
136
|
+
labels["persistence"] = caps.persistence
|
|
137
|
+
write_scope = caps.write_scope
|
|
138
|
+
if caps.exec_unknown:
|
|
139
|
+
labels["exec"] = None
|
|
140
|
+
if caps.write_scope == "fs":
|
|
141
|
+
scope = f.get("fs_scope")
|
|
142
|
+
write_scope = scope if scope in ("project", "home", "root") else None
|
|
143
|
+
# the whole home directory or / holds credentials and private files;
|
|
144
|
+
# a project directory may (.env) but that is not visible here
|
|
145
|
+
labels["sensitive_read"] = True if scope in ("home", "root") else None
|
|
146
|
+
if labels["exec"] is True and f.get("sandboxed") is not True:
|
|
147
|
+
# an unsandboxed shell reads and writes anything the user can
|
|
148
|
+
labels["sensitive_read"] = labels["write"] = labels["persistence"] = True
|
|
149
|
+
write_scope = write_scope or "root"
|
|
150
|
+
if labels["write"] is False and labels["exec"] is False and labels["persistence"] is None:
|
|
151
|
+
labels["persistence"] = False
|
|
152
|
+
return ServerLabels(scan.name, scan.server, scan.scope, labels, write_scope)
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _or(values: list[Label]) -> Label:
|
|
156
|
+
if any(v is True for v in values):
|
|
157
|
+
return True
|
|
158
|
+
if values and all(v is False for v in values):
|
|
159
|
+
return False
|
|
160
|
+
return None
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def agent_labels(scans: list[ServerScan], client: str | None) -> AgentLabels:
|
|
164
|
+
if client is not None and client not in CLIENTS:
|
|
165
|
+
raise ValueError(f"unknown client {client!r} (known: {', '.join(CLIENTS)})")
|
|
166
|
+
servers = [_labels(s) for s in scans]
|
|
167
|
+
builtin = _CLIENTS.get(client) if client else None
|
|
168
|
+
agent = AgentLabels(client, servers)
|
|
169
|
+
for label in LABELS:
|
|
170
|
+
values = [s.labels[label] for s in servers]
|
|
171
|
+
sources = [s.name for s in servers if s.labels[label] is True]
|
|
172
|
+
if builtin is not None:
|
|
173
|
+
values.append(builtin[label])
|
|
174
|
+
if builtin[label] is True:
|
|
175
|
+
sources.insert(0, f"client:{client}")
|
|
176
|
+
value = _or(values)
|
|
177
|
+
if value is False and client is None:
|
|
178
|
+
value = None
|
|
179
|
+
agent.labels[label] = value
|
|
180
|
+
agent.contributors[label] = sources
|
|
181
|
+
return agent
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def labels_json(agent: AgentLabels, source_name: str) -> str:
|
|
185
|
+
doc = {
|
|
186
|
+
"schema": SCHEMA,
|
|
187
|
+
"source": source_name,
|
|
188
|
+
"client": agent.client,
|
|
189
|
+
"agent": agent.labels,
|
|
190
|
+
"contributors": agent.contributors,
|
|
191
|
+
# identify a server by (scope, exact name) - the file stem is only a
|
|
192
|
+
# file name and may be renamed to stay unique (Codex capgraph G02)
|
|
193
|
+
"servers": [
|
|
194
|
+
{
|
|
195
|
+
"server": s.server, "scope": s.scope, "file": s.name,
|
|
196
|
+
"labels": s.labels, "write_scope": s.write_scope,
|
|
197
|
+
}
|
|
198
|
+
for s in agent.servers
|
|
199
|
+
],
|
|
200
|
+
}
|
|
201
|
+
return json.dumps(doc, indent=2, ensure_ascii=False) + "\n"
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def agent_yaml(agent: AgentLabels, source_name: str) -> str:
|
|
205
|
+
import yaml
|
|
206
|
+
|
|
207
|
+
body = yaml.safe_dump(
|
|
208
|
+
{"name": f"agent:{source_name}", "extensions": {"capgraph": agent.facts()}},
|
|
209
|
+
sort_keys=False,
|
|
210
|
+
allow_unicode=True,
|
|
211
|
+
)
|
|
212
|
+
header = [
|
|
213
|
+
f"# generated by `skos scan mcp` from {source_name} (the whole agent: every server"
|
|
214
|
+
+ (f" + client {agent.client}" if agent.client else "") + ")",
|
|
215
|
+
"# null = not established by the config. Answer what you can, then `skos assess` this"
|
|
216
|
+
" file.",
|
|
217
|
+
]
|
|
218
|
+
header += [f"# note: {n}" for n in agent.notes()]
|
|
219
|
+
return "\n".join(header) + "\n" + body
|