zettelforge 2.4.2__tar.gz → 2.5.1__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.
- zettelforge-2.5.1/.github/CODEOWNERS +8 -0
- zettelforge-2.5.1/.github/workflows/ci.yml +158 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/workflows/docs.yml +2 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/workflows/publish.yml +3 -3
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/workflows/snyk-security.yml +13 -6
- {zettelforge-2.4.2 → zettelforge-2.5.1}/CHANGELOG.md +114 -0
- zettelforge-2.5.1/CODEOWNERS +13 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/CONTRIBUTING.md +8 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/PKG-INFO +12 -1
- zettelforge-2.5.1/SECURITY.md +75 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/locomo_benchmark.py +94 -19
- zettelforge-2.5.1/benchmarks/locomo_results.json +287 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/config.default.yaml +72 -4
- zettelforge-2.5.1/docs/THREAT_MODEL.md +248 -0
- zettelforge-2.5.1/docs/how-to/configure-pii.md +217 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/configure-typedb.md +1 -1
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/integrate-llm-agent.md +2 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/upgrade.md +45 -5
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/index.md +32 -10
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/configuration.md +139 -24
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-009-enrichment-pipeline-v2.md +66 -3
- zettelforge-2.5.1/docs/rfcs/RFC-011-local-llm-backend-config.md +435 -0
- zettelforge-2.5.1/docs/rfcs/RFC-012-litellm-unified-provider.md +369 -0
- zettelforge-2.5.1/docs/rfcs/RFC-013-presidio-pii-detection.md +517 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-24-phase-0.5-attribution-prelim.md +6 -3
- zettelforge-2.5.1/docs/superpowers/research/2026-04-25-graph-retriever-silence.md +117 -0
- zettelforge-2.5.1/docs/superpowers/research/2026-04-25-phase-0.5-attribution.md +230 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/tutorials/01-quickstart.md +12 -2
- zettelforge-2.5.1/governance/controls.yaml +125 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/pyproject.toml +49 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/__init__.py +34 -34
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/alias_resolver.py +3 -4
- zettelforge-2.5.1/src/zettelforge/blended_retriever.py +128 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/cache.py +4 -4
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/config.py +74 -13
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/consolidation.py +30 -30
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/demo.py +1 -1
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/detection/base.py +11 -11
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/detection/explainer.py +3 -3
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/entity_indexer.py +118 -56
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/extensions.py +2 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/fact_extractor.py +17 -4
- zettelforge-2.5.1/src/zettelforge/governance_validator.py +166 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/graph_retriever.py +7 -8
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/integrations/langchain_retriever.py +5 -5
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/intent_classifier.py +4 -5
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/json_parse.py +1 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/knowledge_graph.py +103 -49
- zettelforge-2.5.1/src/zettelforge/lance_maintenance.py +242 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/llm_client.py +40 -17
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/llm_providers/__init__.py +18 -7
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/llm_providers/base.py +2 -2
- zettelforge-2.5.1/src/zettelforge/llm_providers/litellm_provider.py +141 -0
- zettelforge-2.5.1/src/zettelforge/llm_providers/local_provider.py +332 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/llm_providers/mock_provider.py +3 -3
- zettelforge-2.5.1/src/zettelforge/llm_providers/ollama_provider.py +129 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/llm_providers/registry.py +3 -4
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/log.py +25 -4
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/mcp/server.py +2 -3
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/memory_evolver.py +23 -8
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/memory_manager.py +117 -57
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/memory_store.py +80 -24
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/memory_updater.py +5 -6
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/note_constructor.py +6 -6
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/note_schema.py +23 -24
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/observability.py +2 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/ocsf.py +41 -18
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/ontology.py +37 -41
- zettelforge-2.5.1/src/zettelforge/pii_validator.py +218 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/retry.py +4 -2
- zettelforge-2.5.1/src/zettelforge/scripts/compact_lance.py +309 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/scripts/human_eval_sampler.py +6 -6
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/scripts/telemetry_aggregator.py +17 -17
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/scripts/telemetry_dashboard.py +10 -10
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/entities.py +8 -8
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/ingest.py +4 -4
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/tags.py +2 -3
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sqlite_backend.py +32 -31
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/storage_backend.py +23 -22
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/synthesis_generator.py +10 -11
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/synthesis_validator.py +3 -4
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/telemetry.py +25 -25
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/vector_memory.py +37 -22
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/vector_retriever.py +89 -35
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/entities.py +9 -9
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/ingest.py +6 -8
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_blended_retriever.py +68 -5
- zettelforge-2.5.1/tests/test_entity_indexer_races.py +189 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_governance_spec_drift.py +25 -10
- zettelforge-2.5.1/tests/test_kg_edge_schema.py +135 -0
- zettelforge-2.5.1/tests/test_lance_maintenance.py +280 -0
- zettelforge-2.5.1/tests/test_llm_providers.py +725 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_logging_compliance.py +88 -0
- zettelforge-2.5.1/tests/test_pii_validator.py +341 -0
- zettelforge-2.4.2/.github/CODEOWNERS +0 -4
- zettelforge-2.4.2/.github/workflows/ci.yml +0 -118
- zettelforge-2.4.2/CODEOWNERS +0 -4
- zettelforge-2.4.2/SECURITY.md +0 -157
- zettelforge-2.4.2/benchmarks/locomo_results.json +0 -962
- zettelforge-2.4.2/governance/controls.yaml +0 -59
- zettelforge-2.4.2/src/zettelforge/blended_retriever.py +0 -47
- zettelforge-2.4.2/src/zettelforge/governance_validator.py +0 -61
- zettelforge-2.4.2/src/zettelforge/llm_providers/local_provider.py +0 -96
- zettelforge-2.4.2/src/zettelforge/llm_providers/ollama_provider.py +0 -69
- zettelforge-2.4.2/tests/test_llm_providers.py +0 -333
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/SECURITY.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/dependabot.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.github/pull_request_template.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/.gitignore +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/ARCHITECTURE.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/CODE_OF_CONDUCT.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/Dockerfile +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/GOVERNANCE.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/LICENSE +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/MANIFEST.in +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/README.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/BENCHMARK_REPORT.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/LOCOMO_BENCHMARK_COMPARISON.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/auto_ralph.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/benchmark_harness.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/cti_benchmark_v2.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/cti_retrieval_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/cti_retrieval_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/cti_v2_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/ctibench_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/ctibench_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/dataset.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/enterprise-attack.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/evolve_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/evolve_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/graph_test.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/locomo_results_v1.3.0_baseline.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/memoryagentbench.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/memoryagentbench_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/mempalace_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/mempalace_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/naive_memory.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/opencti_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/ragas_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/ragas_cti_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/ragas_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/results/benchmark_report.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/results/ralph_optimization_log.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/scale_benchmark.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/benchmarks/scale_results.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/config.example.yaml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docker/docker-compose.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/.well-known/security.txt +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/CNAME +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/architecture-diagram.mmd +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/archive/PACKAGE_SUMMARY.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/archive/README.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/archive/SKILL.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/ZettelForge_Architecture.mmd +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/architecture-overview.mmd +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/architecture-read-path.mmd +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/architecture-write-path.mmd +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/cf-analytics.js +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/demo.gif +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-16.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-32.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-512.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-64.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-apple-touch.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon-old.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/favicon.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/logo.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/social-preview.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-lockup-monogram.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-lockup.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-logo-flat.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-logo-philosophy.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-logo.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/threatrecall-mark.png +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/zettelforge_architecture-light.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/assets/zettelforge_architecture.svg +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/brand/brandIdentity.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/brand/colors_and_type.css +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/explanation/architecture.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/explanation/epistemic-tiers.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/explanation/stix-in-zettelforge.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/explanation/two-phase-pipeline.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/explanation/zettelkasten-philosophy.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/configure-lancedb.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/configure-opencti.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/ingest-news-report.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/migrate-jsonl-to-sqlite.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/query-apt-tools.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/reproduce-benchmarks.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/resolve-aliases.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/run-temporal-query.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/store-threat-actor.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/how-to/troubleshoot.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/human-evaluation-rubric.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/llms.txt +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/narrative/2026-04-16-the-memory-problem.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/overrides/main.html +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/architecture-deep-dive.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/governance-controls.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/memory-manager-api.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/module-inventory.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/retrieval-policies.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/reference/stix-schema.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-001-conversational-entity-extractor.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-002-universal-llm-provider.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-003-adversarial-review.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-003-read-path-depth-routing.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-007-operational-telemetry.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/rfcs/RFC-010-enrichment-hotfix.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/stylesheets/brand-tokens.css +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/stylesheets/extra.css +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/stylesheets/fonts/Neuropol.otf +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-09-ctibench-ragas-benchmarks.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-09-fastembed-local-embeddings.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-09-hybrid-typedb-lancedb-architecture.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-09-local-llm-llama-cpp.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-anti-aversion-cleanup.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-causal-graph.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-ctibench-ate-fix.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-format-stability.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-memory-evolution.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-merge-consolidation.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-persistence-semantics.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-15-sqlite-migration.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/2026-04-17-test-suite-audit.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/research/README.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/superpowers/specs/2026-04-15-p1-features-prd.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/docs/tutorials/02-first-cti-report.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/examples/athf_bridge.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/examples/mcp_claude_code.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/examples/quickstart.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/mkdocs.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/migrate_jsonl_to_sqlite.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/rebuild_index.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/record-demo.sh +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/typedb-setup.sh +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/zettelforge-rebuild.service +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/scripts/zettelforge-rebuild.timer +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/server.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/skills/claude-code-skill.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/skills/openclaw-skill.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/__main__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/backend_factory.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/detection/__init__.py +1 -1
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/detection/consumers.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/edition.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/integrations/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/mcp/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/mcp/__main__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/__init__.py +1 -1
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/cli.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/parser.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/schemas/NOTICE.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/schemas/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/schemas/sigma-correlation-rules-schema.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/schemas/sigma-detection-rule-schema.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/sigma/schemas/sigma-filters-schema.json +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/cccs_metadata.py +2 -2
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/cli.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/parser.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/schemas/CCCS_YARA.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/schemas/CCCS_YARA_values.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/schemas/NOTICE.md +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/schemas/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/src/zettelforge/yara/tags.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/__init__.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/benchmark_scale.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/conftest.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/sigma/cloud_example.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/sigma/correlation_example.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/sigma/process_creation_example.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/sigma/tagged_example.yml +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/yara/malware_hash.yar +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/yara/technique_loader.yar +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/fixtures/yara/webshell.yar +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_basic.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_causal_extraction.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_config.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_consolidation.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_conversational_entities.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_core.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_cti_integration.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_detection_explainer.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_detection_rule_entities.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_edition.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_embedding.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_extensions.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_fact_extractor.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_governance.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_graph_retriever.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_human_eval_sampler.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_intent_classifier.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_json_parse.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_langchain_retriever.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_llm_client.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_mcp_server.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_memory_evolver.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_memory_updater.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_performance.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_recall_integration.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_sigma_entities.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_sigma_ingest.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_sigma_parser.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_sqlite_backend.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_sqlite_integration.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_storage_backend.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_telemetry_aggregator.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_telemetry_collector.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_telemetry_dashboard.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_telemetry_integration.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_temporal_graph.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_two_phase_e2e.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_typedb_client.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_yara_entities.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_yara_ingest.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/tests/test_yara_parser.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/web/app.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/web/auth.py +0 -0
- {zettelforge-2.4.2 → zettelforge-2.5.1}/web/mcp_server.py +0 -0
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [ master ]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [ master ]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
lint:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
20
|
+
with:
|
|
21
|
+
python-version: '3.12'
|
|
22
|
+
|
|
23
|
+
- name: Install linting tools
|
|
24
|
+
run: pip install ruff
|
|
25
|
+
|
|
26
|
+
- name: Lint with ruff
|
|
27
|
+
run: ruff check src/zettelforge/
|
|
28
|
+
|
|
29
|
+
- name: Format check with ruff
|
|
30
|
+
run: ruff format --check src/zettelforge/
|
|
31
|
+
|
|
32
|
+
# GOV-009 §"Vulnerability Response": runs on every PR, fails on
|
|
33
|
+
# HIGH/CRITICAL. Token-free complement to Snyk (which gates on
|
|
34
|
+
# SNYK_TOKEN being set as a repo secret). Audit H-5.
|
|
35
|
+
pip-audit:
|
|
36
|
+
runs-on: ubuntu-latest
|
|
37
|
+
steps:
|
|
38
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
39
|
+
- name: Set up Python
|
|
40
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
41
|
+
with:
|
|
42
|
+
python-version: '3.12'
|
|
43
|
+
- name: Install pip-audit
|
|
44
|
+
run: pip install pip-audit
|
|
45
|
+
- name: Audit dependencies (any reported vuln blocks)
|
|
46
|
+
run: |
|
|
47
|
+
pip install -e ".[dev]" || pip install -e "."
|
|
48
|
+
# pip-audit fails non-zero on any reported vuln. Add
|
|
49
|
+
# --ignore-vuln=CVE-... with a citation when the finding is
|
|
50
|
+
# explicitly accepted per GOV-009 §"Vulnerability Response".
|
|
51
|
+
#
|
|
52
|
+
# CVE-2026-3219: vulnerability in `pip` itself (the package
|
|
53
|
+
# manager), not a project dependency. The runner's pip is
|
|
54
|
+
# supplied by GitHub's setup-python image and is not something
|
|
55
|
+
# ZettelForge's pyproject can pin or upgrade. Risk-accepted
|
|
56
|
+
# because the pip vulnerability surface is exposed during
|
|
57
|
+
# install, not at runtime; CI builds in ephemeral runners with
|
|
58
|
+
# no persistent state. Re-evaluate when GitHub's images ship a
|
|
59
|
+
# patched pip.
|
|
60
|
+
pip-audit --strict --vulnerability-service=osv \
|
|
61
|
+
--ignore-vuln=CVE-2026-3219
|
|
62
|
+
|
|
63
|
+
test:
|
|
64
|
+
runs-on: ubuntu-latest
|
|
65
|
+
needs: lint
|
|
66
|
+
strategy:
|
|
67
|
+
fail-fast: false
|
|
68
|
+
matrix:
|
|
69
|
+
python-version: ['3.12', '3.13']
|
|
70
|
+
|
|
71
|
+
steps:
|
|
72
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
73
|
+
|
|
74
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
75
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
76
|
+
with:
|
|
77
|
+
python-version: ${{ matrix.python-version }}
|
|
78
|
+
|
|
79
|
+
- name: Install dependencies
|
|
80
|
+
run: |
|
|
81
|
+
python -m pip install --upgrade pip
|
|
82
|
+
# If [dev] install fails, fall back to bare install + manually
|
|
83
|
+
# add the pytest deps. Parenthesizing the fallback prevents shell
|
|
84
|
+
# precedence from running the "pytest pytest-cov pytest-asyncio"
|
|
85
|
+
# step when [dev] already succeeded (audit L-4).
|
|
86
|
+
pip install -e ".[dev]" || (pip install -e "." && pip install pytest pytest-cov pytest-asyncio)
|
|
87
|
+
|
|
88
|
+
- name: Pre-download fastembed model
|
|
89
|
+
run: |
|
|
90
|
+
python -c "from fastembed import TextEmbedding; TextEmbedding('nomic-ai/nomic-embed-text-v1.5-Q')"
|
|
91
|
+
|
|
92
|
+
- name: Test with pytest
|
|
93
|
+
env:
|
|
94
|
+
ZETTELFORGE_BACKEND: sqlite
|
|
95
|
+
ZETTELFORGE_EMBEDDING_PROVIDER: fastembed
|
|
96
|
+
run: |
|
|
97
|
+
# GOV-007 §"Coverage Requirements" mandates ≥80% line / ≥70% branch.
|
|
98
|
+
# We start the ratchet at 67 (matches governance/controls.yaml's
|
|
99
|
+
# current declaration) so today's pipeline does not break, and #51
|
|
100
|
+
# tracks raising it toward 80% across v2.5.x. Audit finding H-2.
|
|
101
|
+
pytest tests/ -v --cov=zettelforge --cov-report=xml --cov-report=term-missing --cov-fail-under=67
|
|
102
|
+
|
|
103
|
+
- name: Upload coverage
|
|
104
|
+
if: matrix.python-version == '3.12'
|
|
105
|
+
uses: codecov/codecov-action@57e3a136b779b570ffcdbf80b3bdc90e7fab3de2
|
|
106
|
+
with:
|
|
107
|
+
file: ./coverage.xml
|
|
108
|
+
fail_ci_if_error: false
|
|
109
|
+
|
|
110
|
+
governance:
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
needs: lint
|
|
113
|
+
steps:
|
|
114
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
115
|
+
|
|
116
|
+
- name: Set up Python
|
|
117
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
118
|
+
with:
|
|
119
|
+
python-version: '3.12'
|
|
120
|
+
|
|
121
|
+
- name: Install dependencies
|
|
122
|
+
run: |
|
|
123
|
+
python -m pip install --upgrade pip
|
|
124
|
+
# See "Install dependencies" comment above (audit L-4).
|
|
125
|
+
pip install -e ".[dev]" || (pip install -e "." && pip install pytest pytest-cov)
|
|
126
|
+
|
|
127
|
+
- name: GOV-012 — Logging compliance tests
|
|
128
|
+
env:
|
|
129
|
+
ZETTELFORGE_BACKEND: sqlite
|
|
130
|
+
run: |
|
|
131
|
+
pytest tests/test_logging_compliance.py -v
|
|
132
|
+
|
|
133
|
+
- name: Governance spec-drift check
|
|
134
|
+
run: |
|
|
135
|
+
pytest tests/test_governance_spec_drift.py -v
|
|
136
|
+
|
|
137
|
+
build:
|
|
138
|
+
runs-on: ubuntu-latest
|
|
139
|
+
needs: [test, governance]
|
|
140
|
+
|
|
141
|
+
steps:
|
|
142
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
143
|
+
|
|
144
|
+
- name: Set up Python
|
|
145
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
146
|
+
with:
|
|
147
|
+
python-version: '3.12'
|
|
148
|
+
|
|
149
|
+
- name: Install build dependencies
|
|
150
|
+
run: |
|
|
151
|
+
python -m pip install --upgrade pip
|
|
152
|
+
pip install build twine
|
|
153
|
+
|
|
154
|
+
- name: Build package
|
|
155
|
+
run: python -m build
|
|
156
|
+
|
|
157
|
+
- name: Check package
|
|
158
|
+
run: twine check dist/*
|
|
@@ -14,8 +14,8 @@ jobs:
|
|
|
14
14
|
deploy:
|
|
15
15
|
runs-on: ubuntu-latest
|
|
16
16
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
18
|
-
- uses: actions/setup-python@
|
|
17
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
18
|
+
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
19
19
|
with:
|
|
20
20
|
python-version: '3.12'
|
|
21
21
|
- run: pip install mkdocs-material
|
|
@@ -11,10 +11,10 @@ jobs:
|
|
|
11
11
|
id-token: write # trusted publishing
|
|
12
12
|
|
|
13
13
|
steps:
|
|
14
|
-
- uses: actions/checkout@
|
|
14
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
15
15
|
|
|
16
16
|
- name: Set up Python
|
|
17
|
-
uses: actions/setup-python@
|
|
17
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
18
18
|
with:
|
|
19
19
|
python-version: '3.12'
|
|
20
20
|
|
|
@@ -25,4 +25,4 @@ jobs:
|
|
|
25
25
|
run: python -m build
|
|
26
26
|
|
|
27
27
|
- name: Publish to PyPI
|
|
28
|
-
uses: pypa/gh-action-pypi-publish@
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b
|
|
@@ -17,10 +17,10 @@ jobs:
|
|
|
17
17
|
actions: read
|
|
18
18
|
runs-on: ubuntu-latest
|
|
19
19
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
20
|
+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
21
21
|
|
|
22
22
|
- name: Set up Python
|
|
23
|
-
uses: actions/setup-python@
|
|
23
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405
|
|
24
24
|
with:
|
|
25
25
|
python-version: '3.12'
|
|
26
26
|
|
|
@@ -30,7 +30,7 @@ jobs:
|
|
|
30
30
|
pip install -e ".[dev]" || pip install -e "."
|
|
31
31
|
|
|
32
32
|
- name: Set up Snyk CLI
|
|
33
|
-
uses: snyk/actions/setup@
|
|
33
|
+
uses: snyk/actions/setup@9adf32b1121593767fc3c057af55b55db032dc04
|
|
34
34
|
env:
|
|
35
35
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
36
36
|
|
|
@@ -44,21 +44,28 @@ jobs:
|
|
|
44
44
|
echo "has_token=true" >> "$GITHUB_OUTPUT"
|
|
45
45
|
fi
|
|
46
46
|
|
|
47
|
+
# GOV-009 §"Vulnerability Response" + GOV-011 §"Testing Phase":
|
|
48
|
+
# HIGH/CRITICAL Snyk findings must fail the gate. Audit H-5 found
|
|
49
|
+
# both Snyk steps suffixed with `|| true`, so real findings shipped
|
|
50
|
+
# silently. Now: --severity-threshold=high so MEDIUM stays advisory
|
|
51
|
+
# and only HIGH/CRITICAL break the build. SARIF is still emitted via
|
|
52
|
+
# --sarif-file-output even when the test fails (snyk-code) so the
|
|
53
|
+
# subsequent Upload SARIF step has artifacts to publish.
|
|
47
54
|
- name: Snyk Code test (SAST)
|
|
48
55
|
if: steps.check_token.outputs.has_token == 'true'
|
|
49
|
-
run: snyk code test --sarif
|
|
56
|
+
run: snyk code test --sarif-file-output=snyk-code.sarif --severity-threshold=high
|
|
50
57
|
env:
|
|
51
58
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
52
59
|
|
|
53
60
|
- name: Snyk Open Source test (SCA)
|
|
54
61
|
if: steps.check_token.outputs.has_token == 'true'
|
|
55
|
-
run: snyk test --all-projects
|
|
62
|
+
run: snyk test --all-projects --severity-threshold=high
|
|
56
63
|
env:
|
|
57
64
|
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
|
|
58
65
|
|
|
59
66
|
- name: Upload SARIF to GitHub
|
|
60
67
|
if: steps.check_token.outputs.has_token == 'true'
|
|
61
|
-
uses: github/codeql-action/upload-sarif@
|
|
68
|
+
uses: github/codeql-action/upload-sarif@b25d0ebf40e5b63ee81e1bd6e5d2a12b7c2aeb61
|
|
62
69
|
with:
|
|
63
70
|
sarif_file: snyk-code.sarif
|
|
64
71
|
continue-on-error: true
|
|
@@ -6,6 +6,120 @@ Versioning follows [Semantic Versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [2.5.1] - 2026-04-25
|
|
10
|
+
|
|
11
|
+
Hotfix release. Surfaced during the v2.5.0 perf benchmark run.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- **`KnowledgeGraph._cache_edge` crashed on legacy-schema edges**.
|
|
16
|
+
Long-running deployments accumulated `kg_edges.jsonl` entries written
|
|
17
|
+
by a now-removed pre-v2.5.x writer that used
|
|
18
|
+
`{source_id, target_id, relation_type}` instead of the canonical
|
|
19
|
+
`{from_node_id, to_node_id, relationship}` keys. The loader hard-failed
|
|
20
|
+
with `KeyError: 'from_node_id'` on the first such row, taking down
|
|
21
|
+
every `recall()` and `synthesize()` that touches the KG. Affects any
|
|
22
|
+
workspace with mixed-schema edge history; observed locally with 189k
|
|
23
|
+
edges where ~80k were the legacy shape.
|
|
24
|
+
`_normalize_edge_schema()` now remaps legacy keys to canonical on load
|
|
25
|
+
and silently drops entries that are still un-normalizable, with a
|
|
26
|
+
count logged at WARNING so operators can see the skip volume.
|
|
27
|
+
Six new regression tests in `tests/test_kg_edge_schema.py` cover
|
|
28
|
+
pass-through, remap, missing-fields, non-dict, mixed-batch, and
|
|
29
|
+
corrupt-JSON cases. The previously-broken environment-dependent
|
|
30
|
+
`test_basic.py::test_ingest_relationship` now passes deterministically.
|
|
31
|
+
|
|
32
|
+
## [2.5.0] - 2026-04-25
|
|
33
|
+
|
|
34
|
+
Compliance-driven minor release. Closes every CRITICAL and HIGH audit
|
|
35
|
+
finding except H-3 (mypy strict) and the ANN slice of H-1, both of
|
|
36
|
+
which need per-module ratchet plans. Also adds two new optional LLM
|
|
37
|
+
backends, a Presidio PII detector, and supply-chain hardening.
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **RFC-011 — Local LLM backend selection** (#104). New `local_backend`
|
|
42
|
+
config knob picks between `llama-cpp-python` (GGUF) and
|
|
43
|
+
`onnxruntime-genai` (ONNX) at runtime. Both ship as optional extras
|
|
44
|
+
(`pip install zettelforge[local]` or `[local-onnx]`).
|
|
45
|
+
- **RFC-012 — LiteLLM unified provider** (#108). Routes to 100+
|
|
46
|
+
upstream LLM providers via the LiteLLM SDK. Optional extra
|
|
47
|
+
(`pip install zettelforge[litellm]`); the base package never imports
|
|
48
|
+
it unless the SDK is present.
|
|
49
|
+
- **RFC-013 — Microsoft Presidio PII detection** (#118). Optional PII
|
|
50
|
+
validator with three policies (`log` / `redact` / `block`),
|
|
51
|
+
configurable via `governance.pii.*`. CTI allowlist excludes
|
|
52
|
+
`IP_ADDRESS` / `URL` / `DOMAIN_NAME` from detection so legitimate
|
|
53
|
+
threat-intel indicators flow through unmodified. Soft dependency —
|
|
54
|
+
`pip install zettelforge[pii]` to activate; the base package never
|
|
55
|
+
imports `presidio_analyzer` unless the SDK is present.
|
|
56
|
+
- **GOV-009 Snyk SCA + SAST declared in `controls.yaml`** (#114). The
|
|
57
|
+
spec-drift validator now walks every `.github/workflows/*.yml` so
|
|
58
|
+
controls whose CI step lives outside `ci.yml` (Snyk's separate
|
|
59
|
+
workflow) can be honestly declared.
|
|
60
|
+
- **GOV-006 solo-maintainer compensating controls** (#117). New
|
|
61
|
+
`controls.yaml` entry pins the existing CI gates (lint, tests,
|
|
62
|
+
governance spec-drift) as compensating controls for the GOV-006
|
|
63
|
+
two-person review rule that cannot be physically satisfied with one
|
|
64
|
+
human maintainer. CODEOWNERS updated with explanatory comment.
|
|
65
|
+
- **`SECURITY.md` + CODEOWNERS** added to the repo root for vulnerability
|
|
66
|
+
disclosure and review attribution.
|
|
67
|
+
|
|
68
|
+
### Changed
|
|
69
|
+
|
|
70
|
+
- **All GitHub Actions are now SHA-pinned** (audit H-5 hardening). Every
|
|
71
|
+
`uses: org/repo@vX` reference replaced with `uses: org/repo@<full-sha> # vX.Y.Z`
|
|
72
|
+
to prevent supply-chain attacks via tag rewrites.
|
|
73
|
+
- **Ruff rule set ratcheted to GOV-003 §"Tooling and Automation" minus
|
|
74
|
+
ANN** (#106 + #107 + #109 + #111 + #113). Active `select` list:
|
|
75
|
+
`{E, F, I, W, N, T20, B, UP, SIM, RUF, S}`. Per-line `# noqa: SXXX`
|
|
76
|
+
annotations document each accepted exception (best-effort fallbacks,
|
|
77
|
+
non-crypto RNG, `?`-bound SQL with constant column lists).
|
|
78
|
+
`RUF002`/`RUF003` ignored globally for stylistic en-dash and ×.
|
|
79
|
+
- **CI install-step shell precedence fixed** (#112). The
|
|
80
|
+
`pip install -e ".[dev]" || pip install -e "." && pip install pytest...`
|
|
81
|
+
chain parsed as `(A || B) && C`, so the pytest install ran on
|
|
82
|
+
every success path including when `[dev]` already provided pytest.
|
|
83
|
+
Wrapped the fallback in parentheses.
|
|
84
|
+
- **CONTRIBUTING.md accuracy** (#115). Documents `ruff format`
|
|
85
|
+
(project hasn't used black for a while) and lists what CI actually
|
|
86
|
+
enforces so new contributors have a green-build target.
|
|
87
|
+
|
|
88
|
+
### Compliance audit closure (`tasks/compliance-audit-2026-04-25.md`)
|
|
89
|
+
|
|
90
|
+
| Severity | Finding | Status |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| CRITICAL | C-1 branch protection | CLOSED (with required status checks) |
|
|
93
|
+
| CRITICAL | C-2 fabricated `no_hardcoded_secrets` claim | CLOSED (#100) |
|
|
94
|
+
| HIGH | H-1 ruff full select per GOV-003 | CLOSED for {E,F,I,W,N,T20,B,UP,SIM,RUF,S}; ANN ratcheting per-module |
|
|
95
|
+
| HIGH | H-2 coverage threshold not enforced | CLOSED (#100) |
|
|
96
|
+
| HIGH | H-4 GOV-006 / CODEOWNERS solo-maintainer | CLOSED on the zettelforge side (#117); GOV-006 doc amendment in `rolandpg/governance` repo is separate scope |
|
|
97
|
+
| HIGH | H-5 SCA gate + SHA-pinned actions | CLOSED (#102 + #114 + SHA-pin commit) |
|
|
98
|
+
| MEDIUM | M-1 bare `except:` in production | CLOSED (#100) |
|
|
99
|
+
| MEDIUM | M-3 OCSF `timezone_offset` field | CLOSED (#100) |
|
|
100
|
+
| LOW | L-4 CI install-step shell precedence | CLOSED (#112) |
|
|
101
|
+
|
|
102
|
+
Outstanding: H-3 (mypy --strict in CI; needs per-module ratchet plan
|
|
103
|
+
for 393 errors across 38 files), M-2 (rewrite GOV-016 to match the
|
|
104
|
+
YAML-frontmatter practice already in use), M-4 (lock file), H-1 ANN
|
|
105
|
+
ratchet (121 findings across 38 files).
|
|
106
|
+
|
|
107
|
+
## [2.4.3] - 2026-04-25
|
|
108
|
+
|
|
109
|
+
Patch release. Three small but consequential fixes that landed during the post-v2.4.2 Vigil live-test session, plus the standalone `compact_lance` maintenance script and Nexus's Tier 0/1/2 LLM observability instrumentation.
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
|
|
113
|
+
- **OCSF `metadata.product.version` self-correct** (#96). `ocsf.py:_resolve_product_version()` now prefers the source `pyproject.toml` reachable from `__file__` and falls back to `importlib.metadata.version("zettelforge")`. Editable installs — where `git checkout vX.Y.Z` updates the source tree but not the installed-metadata record — no longer emit stale version strings. Observed live on Vigil 2026-04-24: v2.4.2 source was emitting `product.version=2.4.1` events because the editable-install metadata hadn't been refreshed.
|
|
114
|
+
- **`ZETTELFORGE_LOG_LEVEL` env var honored** (#96). `log.py:get_logger()` now resolves the log level via env var → `config.yaml log.level` → INFO default. Operators can flip DEBUG without editing code or restarting agent boot order. Resolves the "config.yaml `log.level=DEBUG` was dead code" trap hit on Vigil 2026-04-24, where the auto-configure hardcoded INFO and locked `_configured=True` before any caller could read config.
|
|
115
|
+
- **Fastembed preload** (#96). New `vector_memory.preload_embedding_model()` invoked from `MemoryManager.__init__`. Moves the ~800 ms fastembed model-load cost off the first `remember()` and onto agent startup. Best-effort, no-op when `provider != fastembed`. Phase 0.5 measurement: cold `construct=799ms` vs warm `construct=37ms`.
|
|
116
|
+
- **`compact_lance` maintenance script** (#94). New `python -m zettelforge.scripts.compact_lance` for offline LanceDB shard maintenance. Discovers all `<name>.lance/` tables under `<data-dir>/vectordb/`, supports `--dry-run` / `--table` / `--all` / `--mode {compact,optimize}` / `--force`, emits a per-table JSON report with before/after fragment count, on-disk bytes, row count, and elapsed seconds. Operationalized the Phase 0.5 cleanup intervention (see "Vigil incident response" below).
|
|
117
|
+
- **Tier 0/1/2 LLM observability** (#95, Nexus). `ollama_provider.py` now logs every LLM call (model, prompt_chars, response_chars, response_preview, prompt_preview, duration_ms, eval_count, prompt_eval_count, done_reason). `memory_evolver.py` retries log prompt and raw response previews instead of just `neighbor_id`. `fact_extractor.py` empty completions now emit `parse_failed{schema="fact_extraction", reason="empty_completion"}` (`fact_extractor.py:69-71`) instead of silently returning `[]`. `entity_indexer.py` LLM extractions log prompt previews. `structlog.contextvars`-based `trace_id` propagates through `remember()` so every event in a single note's pipeline shares one correlation key.
|
|
118
|
+
|
|
119
|
+
### Operational notes
|
|
120
|
+
|
|
121
|
+
The 2026-04-24/25 Vigil live-test session — driven by the v2.4.2 Phase 0.5 instrumentation — found and fixed a 5.66 GB LanceDB version-history bloat on Vigil's `notes_cti` shard. `cleanup_old_versions()` shrank it 5.69 GB → 29 MB and collapsed `remember()` p95 from 49.8 s → ~250 ms. Full evidence in `docs/superpowers/research/2026-04-25-phase-0.5-attribution.md`. The periodic-cleanup feature itself ships in v2.5.0 as RFC-009 Phase 1.5; the v2.4.3 `compact_lance` script supports the one-shot operator workflow until then.
|
|
122
|
+
|
|
9
123
|
## [2.4.2] - 2026-04-24
|
|
10
124
|
|
|
11
125
|
Patch release bundling the RFC-010 enrichment-pipeline hotfix with the
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# ZettelForge Code Owners
|
|
2
|
+
# These users are automatically requested for review on PRs.
|
|
3
|
+
#
|
|
4
|
+
# Solo-maintainer mode (see governance/controls.yaml GOV-006): the
|
|
5
|
+
# project currently has one human maintainer, so the GOV-006 §"Approval
|
|
6
|
+
# Requirements" two-person rule cannot be physically satisfied. Until a
|
|
7
|
+
# second maintainer is added, the compensating controls declared under
|
|
8
|
+
# GOV-006 in controls.yaml (CI-green required, lint, governance
|
|
9
|
+
# spec-drift, plus GOV-009 SCA/SAST gates) substitute for a second set
|
|
10
|
+
# of human eyes. The audit trail of compensating controls is recoverable
|
|
11
|
+
# from CI logs and branch-protection settings.
|
|
12
|
+
|
|
13
|
+
* @rolandpg
|
|
@@ -18,10 +18,16 @@ No external services (Ollama, TypeDB, Docker) are required for development. Zett
|
|
|
18
18
|
2. Make your changes
|
|
19
19
|
3. Run tests: `pytest tests/ -v`
|
|
20
20
|
4. Run linting: `ruff check src/zettelforge/`
|
|
21
|
-
5. Run formatting: `
|
|
22
|
-
6. Commit with
|
|
21
|
+
5. Run formatting: `ruff format src/zettelforge/`
|
|
22
|
+
6. Commit with a Conventional Commits message (see "Commit Messages" below)
|
|
23
23
|
7. Push and create a pull request
|
|
24
24
|
|
|
25
|
+
CI enforces the same `ruff check` and `ruff format --check` invocations
|
|
26
|
+
plus `pytest --cov-fail-under=67`, `pip-audit`, governance spec-drift,
|
|
27
|
+
and Snyk SCA/SAST. The full active rule set is `{E, F, I, W, N, T20,
|
|
28
|
+
B, UP, SIM, RUF, S}` per GOV-003 §"Tooling and Automation"; only ANN
|
|
29
|
+
remains and is being ratcheted per-module.
|
|
30
|
+
|
|
25
31
|
## Where to contribute
|
|
26
32
|
|
|
27
33
|
All of `src/zettelforge/` is MIT-licensed and open to contributions.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: zettelforge
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.1
|
|
4
4
|
Summary: ZettelForge: Agentic Memory System with vector search, knowledge graph, and synthesis
|
|
5
5
|
Project-URL: Homepage, https://github.com/rolandpg/zettelforge
|
|
6
6
|
Project-URL: Documentation, https://docs.threatrecall.ai
|
|
@@ -46,8 +46,19 @@ Provides-Extra: extensions
|
|
|
46
46
|
Requires-Dist: zettelforge-enterprise>=2.1.0; extra == 'extensions'
|
|
47
47
|
Provides-Extra: langchain
|
|
48
48
|
Requires-Dist: langchain-core>=0.2.0; extra == 'langchain'
|
|
49
|
+
Provides-Extra: litellm
|
|
50
|
+
Requires-Dist: litellm>=1.60.0; extra == 'litellm'
|
|
49
51
|
Provides-Extra: local
|
|
50
52
|
Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local'
|
|
53
|
+
Provides-Extra: local-all
|
|
54
|
+
Requires-Dist: llama-cpp-python>=0.3.0; extra == 'local-all'
|
|
55
|
+
Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-all'
|
|
56
|
+
Provides-Extra: local-onnx
|
|
57
|
+
Requires-Dist: onnxruntime-genai>=0.4.0; extra == 'local-onnx'
|
|
58
|
+
Provides-Extra: pii
|
|
59
|
+
Requires-Dist: presidio-analyzer>=2.2.0; extra == 'pii'
|
|
60
|
+
Requires-Dist: presidio-anonymizer>=2.2.0; extra == 'pii'
|
|
61
|
+
Requires-Dist: spacy>=3.5.0; extra == 'pii'
|
|
51
62
|
Provides-Extra: web
|
|
52
63
|
Requires-Dist: fastapi>=0.100.0; extra == 'web'
|
|
53
64
|
Requires-Dist: uvicorn>=0.20.0; extra == 'web'
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting a Vulnerability
|
|
4
|
+
|
|
5
|
+
This is a solo-maintainer project. For security-related issues:
|
|
6
|
+
- Open a GitHub Security Advisory in the repository
|
|
7
|
+
- Tag with `security` label
|
|
8
|
+
- Expect acknowledgement within 48 hours
|
|
9
|
+
|
|
10
|
+
## Supported Versions
|
|
11
|
+
|
|
12
|
+
| Version | Supported |
|
|
13
|
+
|---------|-----------|
|
|
14
|
+
| latest release | ✅ |
|
|
15
|
+
| master branch | ✅ (CI gates) |
|
|
16
|
+
| older releases | ❌ |
|
|
17
|
+
|
|
18
|
+
## Supply Chain Security
|
|
19
|
+
|
|
20
|
+
This project implements:
|
|
21
|
+
- SHA-pinned GitHub Actions (all third-party actions pinned by commit SHA)
|
|
22
|
+
- PyPI trusted publishing (OIDC, no long-lived tokens)
|
|
23
|
+
- pip-audit on every CI run (HIGH/CRITICAL must pass)
|
|
24
|
+
- Dependabot for weekly dependency updates
|
|
25
|
+
- Snyk SAST scanning on every push/PR
|
|
26
|
+
|
|
27
|
+
## Known Security Architecture
|
|
28
|
+
|
|
29
|
+
See [THREAT_MODEL.md](docs/THREAT_MODEL.md) for the complete STRIDE threat model.
|
|
30
|
+
|
|
31
|
+
### Data at Rest
|
|
32
|
+
|
|
33
|
+
- Notes, the knowledge graph, and the entity index are stored in a local SQLite database (WAL mode) under the configured data directory. No encryption at rest is applied by ZettelForge itself -- encrypt the filesystem or volume at the OS level for sensitive deployments.
|
|
34
|
+
- LanceDB vector index files live alongside the SQLite database and carry the same recommendation.
|
|
35
|
+
|
|
36
|
+
### PII Protection
|
|
37
|
+
|
|
38
|
+
- As of v2.5.0 (RFC-013), optional PII detection via Microsoft Presidio scans content before `remember()` storage. Three modes: log (discovery), redact (compliance), block (strict). Disabled by default. Requires `pip install zettelforge[pii]` to activate.
|
|
39
|
+
- Raw PII text is never written to structured logs. Only entity type and detection score are recorded.
|
|
40
|
+
|
|
41
|
+
### LLM Provider Security
|
|
42
|
+
|
|
43
|
+
- Four providers: `local` (in-process, no network), `ollama` (localhost HTTP), `litellm` (cloud APIs), `mock` (testing). Each is configurable via `llm.provider` in config.yaml.
|
|
44
|
+
- `local` provider is fully offline. `ollama` runs on localhost only. `litellm` makes outbound HTTPS calls to configured cloud APIs.
|
|
45
|
+
- API keys use `${ENV_VAR}` resolution -- never committed to YAML. Redacted from all log output via `LLMConfig.__repr__`.
|
|
46
|
+
- Provider timeout is configurable (default 60s). LiteLLM provider supports configurable retry count.
|
|
47
|
+
|
|
48
|
+
### Injection Defenses
|
|
49
|
+
|
|
50
|
+
- As of v2.1.1, all LanceDB query expressions are parameterized. String-interpolated queries were present in v2.1.0 and earlier (see CVE advisory, if issued, or CHANGELOG v2.1.1 P0-3).
|
|
51
|
+
|
|
52
|
+
### File Locking
|
|
53
|
+
|
|
54
|
+
- As of v2.1.1, all JSONL and entity index write paths use `fcntl.flock()` exclusive locks to prevent concurrent-write corruption.
|
|
55
|
+
|
|
56
|
+
### Audit Logging
|
|
57
|
+
|
|
58
|
+
- All security-relevant operations emit OCSF v1.3 structured events via `structlog`. Authorization decisions, API activity, and file activity are auditable in any SIEM that ingests JSON logs.
|
|
59
|
+
|
|
60
|
+
### Air-Gap Deployments
|
|
61
|
+
|
|
62
|
+
- ZettelForge supports fully offline operation (fastembed ONNX + llama-cpp-python). No telemetry or external calls are made in this configuration.
|
|
63
|
+
|
|
64
|
+
## Disclosure Policy
|
|
65
|
+
|
|
66
|
+
ZettelForge follows a coordinated disclosure model:
|
|
67
|
+
|
|
68
|
+
1. Reporter submits vulnerability privately via email.
|
|
69
|
+
2. We acknowledge within 48 hours and begin assessment.
|
|
70
|
+
3. We develop and test a fix on a private branch.
|
|
71
|
+
4. We notify the reporter when a fix is ready and agree on a disclosure date.
|
|
72
|
+
5. We release the fix and publish a security advisory simultaneously.
|
|
73
|
+
6. We credit the reporter in the advisory (unless they opt out).
|
|
74
|
+
|
|
75
|
+
We ask reporters to give us a reasonable time to fix issues before public disclosure. We will not take legal action against good-faith security researchers who follow this policy.
|