Commit Graph
2384 Commits
Author SHA1 Message Date
4a886d970e fix seed SSRF (#942)
Co-authored-by: Sameer Kadam <sskadam6305@gmail.com>
Co-authored-by: Mohd Kaif <98801504+KaifAhmad1@users.noreply.github.com>
2026-08-19 17:36:01 +05:30
Guofang.Tang b77e3e8c3c fix(kg): preserve entity_id aliases during entity merging (#1086)
* fix(kg): preserve entity_id aliases during merge

* fix(kg): unify entity ID extraction semantics
2026-08-19 16:17:51 +05:00
Mohd Kaif 68f7ae3807 Merge pull request #1094 from cxzg007/fix/shacl-explain-violations-real-constraint-values
fix(ontology): render real SHACL constraint values in explain_violations
2026-08-19 15:54:45 +05:30
江俊杰 08a6e7c053 fix(ontology): render real SHACL constraint values in explain_violations
explain_violations previously rendered hardcoded placeholders (min_count=1,
max_count=1) and misused the violation message as the datatype/class value,
so plain-English explanations were inaccurate. The root cause is that
_run_pyshacl never read the real constraint parameters from sh:sourceShape
when building each SHACLViolation.

Changes:
- SHACLViolation: add min_count/max_count/datatype/class_ fields and include
  them in to_dict()
- _run_pyshacl: back-reference sh:sourceShape to extract the real
  sh:minCount/sh:maxCount/sh:datatype/sh:class values
- explain_violations: render the real values, falling back to "?" or
  descriptive text when unknown

Note: sh:qualifiedMinCount/qualifiedMaxCount are not handled and fall back to
the "?" placeholder.

Adds regression tests covering both the formatting path and the sh:sourceShape
back-reference (skips when pyshacl/rdflib are absent).
2026-08-19 16:30:36 +08:00
Mohd Kaif e6b159e5c5 Merge pull request #1040 from Kyou12138/fix/docs-explorer-auth-note
docs(explorer): update stale authentication notes after v0.6.5
2026-08-18 22:35:58 +05:30
Mohd Kaif 7db2e2f46b Merge pull request #1013 from yzxcj797/fix/1009-edge-labels
fix(explorer): enable edge label rendering on the graph canvas
2026-08-18 21:28:53 +05:30
Sameer6305 3fbe3cfd2d fix(explorer): address edge label review findings 2026-08-18 20:34:54 +05:30
Sameer Kadam 75bc6255d4 Merge branch 'main' into fix/1009-edge-labels 2026-08-18 20:01:47 +05:30
Sameer6305 a96f1590f1 docs(explorer): document WebSocket authentication 2026-08-18 19:20:44 +05:30
Sameer Kadam 063f447202 Merge branch 'main' into fix/docs-explorer-auth-note 2026-08-18 19:00:47 +05:30
cxzg007and江俊杰 a1194a155d feat(context): add to_kg_dict() adapter for canonical KG shape (#1081)
* feat(context): add to_kg_dict() adapter for canonical KG shape

Convert ContextGraph internal nodes/edges/source representation into the canonical entities/relationships/source_id shape consumed by RDFExporter and TemporalGraphQuery. Add entities_only filtering that drops dangling relationships, plus README examples and unit tests.

* fix(context): harden to_kg_dict against null props and non-str node ids

- Guard properties/metadata with 'or {}' so nodes loaded from JSON null
  no longer raise TypeError when copied (Qodo bug 1)
- Coerce entity id to str(n.node_id) so it matches ContextEdge's
  str-coerced endpoints, preventing valid relationships from being
  dropped during entities_only filtering (Qodo bug 3)

* fix(kg): accept source_id/target_id endpoints in validator and temporal query

to_kg_dict() emits canonical source_id/target_id keys, but GraphValidator
and TemporalGraphQuery only read the legacy source/target keys, so its
output failed validation and lost relationships (Qodo bug 2).

- GraphValidator: resolve endpoints from either key variant and treat a
  resolvable source/target (plus type) as satisfying required fields
- TemporalGraphQuery.analyze_evolution/find_paths: read either variant
- tests: add regression coverage for null props/metadata (bug 1),
  non-string node ids (bug 3), and KG-utility consumability (bug 2)

---------

Co-authored-by: 江俊杰 <jiangjunjie.37@jd.com>
2026-08-18 18:24:52 +05:00
Guofang.Tang 17d878cbf3 fix(kg): honor exact entity resolution (#1026)
* fix(kg): honor exact entity resolution

* fix(kg): preserve entities without identifiers

* fix(kg): ignore blank exact entity names

---------
2026-08-18 18:03:20 +05:00
Mohd Kaif 488e381247 Merge pull request #1079 from semantica-agi/security/edictum-disclosure-2026-08
fix(security): address privately disclosed zip-slip, SQLi, SSRF, XSS, and SPARQLi findings
2026-08-18 17:32:54 +05:30
Mohd Kaif 4acd2f9c33 Merge branch 'main' into security/edictum-disclosure-2026-08 2026-08-18 17:25:41 +05:30
Mohd Kaif 7cac8a6bc3 Update badge layout in README.md
Replaced table with flexbox layout for badges in README.
2026-08-18 17:08:11 +05:30
Mohd Kaif 6c77594ea6 Enhance README with Trendshift badges
Added Trendshift badges to the README for repository tracking.
2026-08-18 17:05:48 +05:30
Sameer Kadam 5109c6fab2 Merge branch 'main' into fix/docs-explorer-auth-note 2026-08-18 14:41:09 +05:30
Sameer6305 12b9694a8e fix(explorer): complete edge label rendering 2026-08-18 14:19:25 +05:30
KaifAhmad1 49707729ad fix(security): address Qodo review findings on the disclosure-fix PR
- export_table_data() re-raises ValidationError instead of masking it
  as ProcessingError via the blanket except Exception.
- _apply_connection_pin() restores the session's original Host header
  state on an unpinned hop instead of unconditionally clearing it,
  which was dropping a caller-supplied session's own Host override.
- SQL fragment blocklist now masks quoted string/identifier literal
  contents before matching, so legitimate data containing a blocked
  keyword (e.g. status = 'union') no longer false-positives; a
  malformed/unterminated quote stays unmasked and still scrutinized.
2026-08-18 14:18:54 +05:30
KaifAhmad1 430020c7c4 docs(changelog): add Security entry for the disclosure fixes in this PR
Documents the tarball path traversal, latent SQLi, DNS-rebinding TOCTOU,
stored XSS, and SPARQL injection fixes, plus the follow-up hardening
found in review, under [Unreleased] > Security.
2026-08-18 14:06:20 +05:30
KaifAhmad1 43b207c1c5 fix(security): address privately disclosed zip-slip, SQLi, SSRF, XSS, and SPARQLi findings
Fixes a set of runtime trust-boundary issues from a private security
disclosure (checkout 7c3372c0): tarball restore path traversal, latent
SQL injection in the DB exporter, a DNS-rebinding TOCTOU gap in the
shared SSRF guard, unescaped HTML in report generation, and unvalidated
SPARQL object IRIs in AnzoStore, plus several lower-severity hardening
items found in the same review.
2026-08-18 13:58:32 +05:30
Sameer Kadam 55bde673c9 Merge branch 'main' into fix/1009-edge-labels 2026-08-18 13:11:35 +05:30
5c2901ae27 docs(context): fix unrunnable ContextGraph docstring example (#921)
* docs(context): fix unrunnable ContextGraph docstring example

The module docstring's Example Usage block called add_node/add_edge with
keyword arguments they do not accept. add_node(node_id, node_type, ...) takes
node_type positionally and has no properties parameter, so the documented call
raised TypeError; add_edge's parameter is edge_type, so type= fell through to
**properties and polluted edge metadata while appearing to work.

Two of the three broken forms failed silently rather than raising, storing a
nested properties dict or a stray type key instead of erroring.

Add regression tests that execute the documented calls and assert the docstring
itself does not reintroduce the invalid kwargs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* test(context): close two blind spots in the docstring regression guards

The guards added in the previous commit could pass while checking nothing.

_example_block() terminated the capture at the first "\n\n". The Example
Usage block already contains ">>> " spacer lines, so any reformatting that
turned one into a bare blank line would truncate the capture -- potentially
to empty -- and the guards would then scan a block that no longer held the
add_node/add_edge calls they exist to police.

Both guards also iterated over re.findall() without asserting a match. Zero
matches meant zero assertions and a green test, so the two failure modes
compounded: a truncated block produced no matches, and no matches produced
a pass.

Terminate the block at the next top-level section header (^\S) or end of
docstring instead, so blank lines inside the example are harmless, and
assert the captured block, the parsed statement list, and each guard's
match list are all non-empty.

Extract statements with doctest.DocTestParser rather than a line regex.
This also catches a call reformatted across "..." continuation lines, which
the ">>> graph.add_node(.*" pattern silently skipped, and lets
test_documented_calls_execute exec the docstring's own statements instead
of a retyped copy that could drift from it. Full doctest.testmod isn't
usable here: add_node/add_edge return True and the docs carry no
expected-output lines, so it reports 4 spurious failures.

Narrow the kwarg check to (?<![\w])type\s*= so a legitimate node_type=
or edge_type= in the docs no longer trips a guard aimed at bare type=.

Verified by mutating the module docstring and re-running the guards: extra
blank lines with a valid example still pass; regressed add_node/add_edge,
a type= on a continuation line, deleted calls, and a deleted section all
fail; a legitimate node_type= passes. 6 passed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(context): correct precedent lookup in docstring example

---------

Co-authored-by: Pravit Ampapathini <pravitampapathini@Pravits-MacBook-Air-3.local>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Sameer Kadam <sskadam6305@gmail.com>
Co-authored-by: Mohd Kaif <98801504+KaifAhmad1@users.noreply.github.com>
2026-08-18 11:49:32 +05:30
Kyou0203 dae21166a1 docs(explorer): clarify auth behavior and document auth env vars
Address review feedback:

- State that only protected routes require the API key and note that
  /api/health and /api/info are intentionally unauthenticated.
- Note the CLI warning on non-loopback binds only fires in anonymous
  mode or when SEMANTICA_API_KEY is unset.
- Add SEMANTICA_API_KEY and SEMANTICA_ALLOW_ANONYMOUS to the Environment
  variables table.
2026-08-18 12:48:01 +08:00
Kyou0203 67be421533 Merge branch 'main' of https://github.com/semantica-agi/semantica into fix/docs-explorer-auth-note 2026-08-18 12:47:01 +08:00
Shubham Srivastava baf8f01f85 test(export): guard Parquet tests on pyarrow itself, not the exporter import (#1056)
* test(export): guard Parquet tests on pyarrow itself, not the exporter import

Closes #1054

* test(export): guard on PARQUET_AVAILABLE so the skip matches the runtime check

find_spec only proves pyarrow is discoverable, not importable. Addresses
review feedback on #1056.

---------
2026-08-18 02:18:39 +05:00
unknown c58686b4ec Address review: edge labels carry text and follow an Effects toggle
Two findings from the Qodo review:

- Sigma's edge label renderer draws data.label, but the graph stores the
  relationship type in edgeType — enabling renderEdgeLabels alone left
  edges blank. The edgeReducer now maps edgeType onto label (suppressed for
  hidden edges).

- renderEdgeLabels was hardcoded on with no way to disable it. It now
  follows a new edgeLabelsEnabled entry in the Effects panel (default on),
  wired through the existing GraphEffectToggle/GraphEffectsState plumbing,
  so dense graphs get their label-free edges back.
2026-08-18 03:06:16 +08:00
Sameer KadamandKaifAhmad1 04602a0e0e fix(security): prevent Authorization header leakage across redirects (#947) (#1067)
* fix(security): prevent auth header leakage across redirects

* fix(security): harden redirect credential handling

Address Copilot and Qodo review findings for #947.

- Remove unused variables, imports, and unnecessary pass statements from tests.
- Harden cross-origin redirect handling for per-request auth credentials.
- Strip session-level auth handlers before cross-origin redirect hops.
- Prevent session.auth from regenerating Authorization headers.
- Disable trust_env during cross-origin hops to prevent .netrc credential injection.
- Restore session auth and trust_env state reliably with try/finally.
- Add regression coverage for auth=, session.auth, trust_env, and multi-hop redirects.
- Preserve existing security behavior and same-origin authentication semantics.

Validated with 189/189 security and affected tests passing.

* fix(security): scope allow_private_ips to same-host redirects, fix error handling gaps

Follow-up to review findings on #1067:

- MCPClient hardcoded allow_private_ips=True for every redirect hop, not
  just its operator-configured host, so a compromised/malicious MCP server
  could 302 into private address space (e.g. cloud metadata) unchecked.
  request_with_ssrf_guard() gains allow_private_ips_on_redirect: a redirect
  target inherits the original host's private-IP trust only when it matches
  that host; MCPClient now pins it to False.
- detect_public_api() only caught requests.exceptions.RequestException, but
  the SSRF guard raises ValidationError for blocked hosts/redirects, unlike
  its sibling ingest_public_api(). Now catches and re-raises it the same way.
- detect_public_api()/ingest_public_api() forwarded session/allow_private_ips
  through **options into request_with_ssrf_guard(), which already passes
  both explicitly -- a caller supplying either would hit a duplicate-kwarg
  TypeError. Both are now popped from request_options first.

New regression coverage for all three in tests/ingest/, plus a CHANGELOG
entry under Unreleased/Security.

---------

Co-authored-by: KaifAhmad1 <kaifahmad087@gmail.com>
2026-08-17 18:55:38 +05:30
Shahzaib AhmadandShahzaib Ahmad eedf1425ca Fix flatten_dict key collisions (#1062)
* Fix flatten_dict key collisions

* Fix flatten_dict formatting

---------

Co-authored-by: Shahzaib Ahmad <malikshahzaib7145@example.com>
2026-08-17 14:30:12 +05:00
Mohd Kaif d4cb14c1fb Merge pull request #1042 from Accute9/spacy-cache-split-chunking
perf(split): avoid repeated spaCy model loading in split/chunking paths
2026-08-17 14:44:44 +05:30
KaifAhmad1 a8194dfc60 fix(split): catch broken-runtime spaCy failures in SemanticChunker
SemanticChunker.__init__ only caught OSError around load_spacy_model(),
while NERExtractor's identical call (fixed earlier in this PR) also
catches generic Exception for a model that is installed but fails at
runtime. Bring SemanticChunker in line so a broken spaCy config
degrades to fallback chunking instead of crashing __init__.

Adds a regression test mirroring the existing NERExtractor case, and a
CHANGELOG entry for #998/#1042.
2026-08-17 13:16:17 +05:30
Sameer6305 c7415f2e92 fix: complete spaCy model cache integration 2026-08-17 12:40:10 +05:30
Sameer Kadam 3331df28ad Merge branch 'main' into spacy-cache-split-chunking 2026-08-17 11:18:52 +05:30
Accute9 de5e20dc55 resolved merge conflict 2026-08-16 21:11:15 -04:00
Accute9 0f252ab355 Fixed max line length (88) issues and eager imports 2026-08-16 21:04:57 -04:00
Aneesh MandapatiandCopilot Autofix powered by AI 0b77e5fe94 Refactor for flake8 max line length (88) issue
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-08-16 20:31:06 -04:00
Accute9 893b6db3c3 regression tests added and tested for routing spaCy model loads through cache 2026-08-16 16:07:45 -04:00
Kyou0203 b8297b8077 docs(explorer): update stale authentication notes after v0.6.5
The Explorer API has required SEMANTICA_API_KEY (X-API-Key header) since
v0.6.5, failing closed with 503 when unconfigured. Both the explorer
README security note and docs/explorer-setup.md still claimed there was
no built-in authentication.

Update both to describe the actual behavior: API-key enforcement,
the 503 fail-closed mode, and the explicit SEMANTICA_ALLOW_ANONYMOUS=true
opt-in for local development.

Fixes #1028
2026-08-17 01:30:45 +08:00
Mohd Kaif 4d37920007 docs: surface explainability scope note near the top of the README (#1034)
Moves a concise version of the system-level vs. foundation-model
explainability clarification up next to the opening pitch, so it's
visible before readers scroll to the high-stakes-domains section.
2026-08-16 17:51:23 +05:30
Mohd Kaif 6416fbb669 docs: clarify explainability is system-level, not foundation-model internal (#1033)
Adds a consistent scope note to README and docs (concepts, FAQ, index)
stating Semantica does not expose or reconstruct an LLM's internal
reasoning/chain-of-thought. It explains and audits the AI system
around the model: context, provenance, policies, decisions, and
execution history.
2026-08-16 17:44:02 +05:30
hariandZohaib Hassnain 70aa9d01bf fix(normalize): validate symbol currencies (#940)
* fix(normalize): validate symbol currencies

Signed-off-by: Mr-Neutr0n <harikp2002@gmail.com>

* fix(normalize): match currency codes by token boundaries

Signed-off-by: Mr-Neutr0n <harikp2002@gmail.com>

---------

Signed-off-by: Mr-Neutr0n <harikp2002@gmail.com>
Co-authored-by: Zohaib Hassnain <109234410+ZohaibHassan16@users.noreply.github.com>
2026-08-16 15:24:34 +05:30
Mohd Kaif c53ca4e84b docs: formalize issue assignment and duplicate-PR triage workflow (#1030)
* docs(contributing): formalize issue assignment and duplicate-PR triage workflow

Comments are no longer required before an issue can be assigned - maintainers
may assign directly based on recent activity. Also documents the duplicate-PR
priority order for triage (contributor PR, claimed issue, activity tiebreak,
late duplicates, overlapping scope).

* docs(contributing): clarify assignment precedence and define activity tiebreak

Addresses Qodo review feedback on PR #1030: the duplicate-PR priority list
now states these rules apply on top of the assignment workflow (opening a PR
pre-assignment doesn't grant priority), and the "most active" tiebreak now
specifies a concrete 60-day window and signals instead of being subjective.
2026-08-16 15:18:55 +05:30
pravit-ampandPravit Ampapathini 15171fd31a fix(parse): import get_progress_tracker in ExcelParser (#1016)
ExcelParser.__init__ called get_progress_tracker() without importing it,
so every instantiation raised NameError and the class was unusable. The
existing test imported ExcelParser but never constructed it, so nothing
caught it. Same defect as #530 in SimilarityCalculator, which was fixed
without sweeping the rest of the codebase.

Add construction coverage for every parser exported from semantica.parse,
driven off __all__ so later additions are covered automatically. These
live outside test_parse_comprehensive.py, whose setUp patches
get_progress_tracker into each parse module and would mock away the
interaction under test.

Closes #1014

Co-authored-by: Pravit Ampapathini <pravitampapathini@Pravits-MacBook-Air-3.local>
2026-08-16 14:07:10 +05:00
Guofang.Tang 8177d88753 fix(kg): preserve isolated nodes in graph analytics (#1011)
* fix(kg): preserve isolated nodes in graph analytics

* fix(kg): support node fallbacks and community payloads

---------
2026-08-16 11:23:24 +05:00
Shinde vinayak rao patil d94d8f6ab8 Feat/crewai integration (#988)
* feat(crewai): add first-class CrewAI integration (#962)

Add native CrewAI support so Crew agents can share a ContextGraph and
AgentContext via BaseTool subclasses and a BaseKnowledgeSource, matching
the existing agno integration pattern.

- SemanticaKGTool: 5 KG actions (extract_entities, extract_relations,
  add_to_graph, query_graph, find_related) with sync run()/async arun()
- SemanticaDecisionTool: 5 decision-intelligence actions
  (record_decision, find_precedents, trace_causal_chain,
  analyze_impact, check_policy) over AgentContext
- SemanticaKnowledgeSource: serializes a ContextGraph into crew
  knowledge storage; bridges legacy load_content() and current
  validate_content()/aadd() contracts for crewai>=0.80.0
- All classes degrade gracefully when crewai is absent
- New pip extra crewai=... included in the all bundle
- 70 new tests (stub-based present-case + subprocess degradation path)
- Docs: integrations/crewai.md, docs.json nav, README matrix updates

* fix(crewai): harden tools against real Semantica dataclass shapes (#962)

Bugs found during live testing with crewai 1.15.16:

- SemanticaKGTool.add_to_graph crashed on real Entity/Relation dataclasses
  ('str' object has no attribute 'end_char'): string names were passed to
  extract_relations(entities=...), which requires Entity objects, and the
  tool read .name/.source/.target instead of Entity's .text/.label and
  Relation's .subject/.object. Add shape-agnostic field helpers.
- SemanticaDecisionTool() created an AgentContext without a knowledge_graph,
  so _decision_backend was never set and record_decision raised 'Decision
  tracking is not enabled'. Wire in a ContextGraph.
- record_decision hard-failed when the agent omitted optional fields; fall
  back to category='general', reasoning='agent decision',
  outcome='recorded'.

Add tests covering real Entity/Relation dataclass shapes and the live
auto-created AgentContext path (now 77 crewai tests, 212 total).

* fix(crewai): make find_related traverse edges undirected (#962)

ContextGraph.get_neighbors only follows outgoing edges, so a node whose
only edge is incoming (A -> B) reported no related concepts. Rebuild a
bidirectional adjacency from find_edges() in SemanticaKGTool._find_related
so 'related' honors both directions.

* fix(crewai): harden tools for checkpoint serialization and correct action semantics (#962)

- Exclude live graph/context/extractor state from JSON serialization
  (model_dump(mode="json")) so CrewAI checkpointing no longer raises
  PydanticSerializationError; model_post_init self-heals defaults on restore
- query_graph now searches node content via graph.query() plus id/type
- trace_causal_chain returns an explicit error when causal tracing is
  unavailable instead of substituting similarity precedents; call
  trace_decision_causality(..., max_depth=...) with the correct kwarg name
- find_precedents propagates max_precedents/limit to the backend instead of
  being silently capped at 10
- Serialize add_to_graph batches under a module lock to prevent concurrent
  double-counting; skip nameless entities instead of creating repr()-junk nodes
- aadd() runs CPU-bound serialization in a thread executor
- Mirror crewai args_schema serialize/restore in the conftest stub and add
  serialization regression tests (crewai: 92 tests)

* fix(crewai): correct check_policy coercion, guard causal tracing, and harden concurrency (#962)

- _eval_rule now coerces rule values type-aware: bool("false") was truthy, so
  'enabled == false' reported a violation for enabled=false, and string datums
  like "0.90" were compared lexicographically instead of numerically
- _trace_causal_chain no longer raises AttributeError (which escaped _run) when
  the decision context lacks knowledge_graph; returns honest error JSON
- SemanticaKnowledgeSource storage failures log an actionable ERROR; without a
  configured crew embedder agents previously retrieved nothing silently
- add_to_graph uses a per-graph re-entrant lock (WeakKeyDictionary) instead of a
  process-global one: independent graphs no longer serialize each other and
  re-entrant extractor callbacks cannot deadlock
- entity/relation confidence=None normalizes to 1.0 instead of failing the
  whole extraction with float(None)
- add subprocess integration test against real crewai covering Crew-level
  serialization round-trip and checkpoint restore (stub tests cannot see it)
- docs: embedder requirement for SemanticaKnowledgeSource; resume contract note

* fix(crewai): surface knowledge-source save failures at ERROR when storage is wired (#962)

Re-verification against real crewai showed the embedder-missing failure raises
ValueError even though storage IS wired, so the old except-ValueError branch
mislabeled it as 'storage not wired' and logged DEBUG — hiding the failure.
Distinguish by storage presence instead of exception type: storage is None ->
DEBUG keep-in-memory (legitimate standalone use); storage wired but save()
raises -> actionable ERROR. Add regression test mirroring real crewai's
ValueError-on-missing-embedder behavior.

* fix(crewai): expose run()/arun() entry points in degraded mode (#962)

The public crewai contract is run()/arun(); without crewai installed they were
missing (only the private _run existed), so the documented 'usable without
crewai' path raised AttributeError at the entry point. Define them in degraded
mode only, leaving crewai's BaseTool implementations untouched when present.
Extend the degradation subprocess test to exercise run() and arun().

* fix(crewai): standardize query shape, field-name rules, and restore-state flag

- _query_graph: id/type matches now return the same schema as content
  matches (id/type/label/content/score) instead of a bare list
- _eval_rule: non-greedy field capture so hyphen/dot/space JSON keys
  (e.g. "risk-score >= 0.9") are addressable in policy rules
- add had_live_state/reconstructed_state so checkpoint-restored tools
  and knowledge sources signal that their live graph/context was lost
  and an empty one reconstructed; knowledge source no longer hides the
  loss by eagerly rebuilding its graph inside __init__ (pydantic calls
  __init__ during model_validate)

* fix(crewai): address Qodo review — confidence errors, string trim, holistic availability

- record_decision: stop calling float() in _run, so malformed confidence
  values surface as JSON errors (via _record_decision's handling) instead
  of crashing the tool
- _coerce_value: return the stripped string for non-numeric literals so
  whitespace-padded decision_data fields match policy rules
- centralize crewai availability in _availability.py so the exported
  CREWAI_AVAILABLE flag is holistic across tools and knowledge source
  (previously each module probed crewai independently and the package
  flag came from decision_tool only)

* ci: regenerate requirements-ci.txt for the crewai extra

The crewai extra in pyproject.toml brings in crewai, crewai-tools and
transitive deps (chromadb, lancedb, ...). Recompile with
uv==0.12.1 per CONTRIBUTING.md so the CI staleness check passes.

* ci: keep crewai out of the locked CI dependency set

crewai (all versions) hard-requires chromadb~=1.1.0, which carries a
pre-authentication code-injection advisory (CVE-2026-45829 / GHSA-f4j7-r4q5-qw2c)
with NO fixed release — even the latest 1.5.9 is affected. Keeping crewai in
the 'all' extra failed pip-audit and the safety check on requirements-ci.txt.

- drop crewai from the 'all' aggregate (standalone semantica[crewai] extra is
  unchanged and still installs crewai)
- stop listing crewai-tools in the extra: the integration only uses crewai core
  (BaseTool, BaseKnowledgeSource) and crewai-tools pulled extra transitive deps
- regenerate requirements-ci.txt: OSV/pip-audit 0 vulnerabilities, safety 0
  vulnerabilities, staleness check matches

* docs(crewai): document crewai extra scope and chromadb CVE-2026-45829

- CHANGELOG: extra is crewai>=0.80.0 only (no crewai-tools) and is not
  part of the 'all' bundle, with the chromadb CVE-2026-45829 reason
- integrations/crewai/README.md: add a security warning that installing
  the extra pulls chromadb~=1.1.0, which is affected by the unpatched
  pre-auth code-injection CVE-2026-45829

---------
2026-08-16 11:15:43 +05:00
Accute9 83649f6821 forgot to remove comment 2026-08-15 20:56:39 -04:00
Accute9 2f04bc01a3 route spaCy model loads through process cache 2026-08-15 20:37:56 -04:00
5579851208 fix(export): harden YAML export input handling (#958)
* refactor(export): centralize graph-payload key normalization

Graph payloads circulate under two vocabularies, entities/relationships and nodes/edges, and consumers each reconciled them locally with competing idioms. The same payload could be exported, silently dropped, or rejected depending on which consumer read it.

Add normalize_graph_payload() to utils.helpers as the single place that decision is made. Both spellings present with one empty resolves to the populated one, which is the shape JSONExporter emits; both non-empty and different is refused, since there is no basis to prefer either and picking one would silently discard the other; a non-empty mapping with no recognized key raises rather than returning empty collections, with require_recognized=False for callers that should degrade.

Adopt it in the three exporters that genuinely alias. LPGExporter read nodes with entities as the default, so it dropped every entity when nodes was present but empty, losing everything on a JSON round-trip. ArangoAQLExporter had the same idiom plus a manual fallback. Neo4jCSVExporter routes its mapping branch through the shared resolver so the reference implementation cannot drift; its attribute branch stays local, since objects are not mappings.

Also feed LPGExporter._generate_indexes the resolved entities. It read entities directly, so a nodes/edges payload produced no indexes even once node generation was fixed.

CSVExporter and JSONExporter are deliberately excluded: they write entities, relationships, nodes and edges as separate outputs by design rather than reconciling two spellings of one collection, so normalizing there would rename output files.

* fix(export): reject non-mapping input to the YAML exporters

export_yaml declared Union[Dict[str, Any], List[Dict[str, Any]]], but both
YAML exporters read their payload by key, so a list reached .get() and
surfaced as a bare AttributeError from inside the exporter, naming neither
the offending argument nor the shape expected.

Reject rather than wrap. These formats distinguish entities from
relationships from triplets, so inferring which collection a bare list
represents would silently mislabel the records, and wrapping it under an
unrecognised key would write a structurally valid file with every
collection empty - trading a loud failure for silent data loss.

Validate in the exporters, matching the existing precedent in
Neo4jCSVExporter._normalize_graph, so direct users of the classes get the
same contract as callers of the convenience wrapper. Narrow the wrapper
type hint to Dict[str, Any] to match.

* fix(export): address YAML exporter review findings

- semantica/export/yaml_exporter.py — import Sequence from typing
  instead of collections.abc. `Sequence[str]` in _require_mapping's
  annotation is evaluated at function-definition time; collections.abc.Sequence
  only became subscriptable in Python 3.9, so on the 3.8 this project
  declares support for, importing this module raised TypeError.
  typing.Sequence has supported subscripting since 3.5.3. Mapping stays
  imported from collections.abc since it's only used for isinstance.
- tests/export/test_yaml_exporter_input_validation.py — clean up each
  test's tempfile.mkdtemp() dir via addCleanup instead of leaking it,
  and read exported YAML through a context manager instead of an
  unclosed yaml.safe_load(open(...)).

* fix(export): reject YAML export payloads with no recognized key

Both YAML exporters built their output from a fixed set of `.get(key, [])`
lookups, so a mapping keyed by anything else serialized to a structurally
valid file with every collection empty. Nothing signalled the loss: no
exception, no warning, and the progress log reported a completed export.
The only way to notice was to open the file. The realistic trigger is
re-exporting an `export_json` payload, whose `{"data", "count", "metadata"}`
envelope drops every record.

- SemanticNetworkYAMLExporter.export_semantic_network now resolves its
  collections through normalize_graph_payload(), which raises rather than
  returning empty collections for an unrecognized mapping. Adopting the
  shared resolver rather than repeating the check locally also brings the
  'nodes'/'edges' aliases, so ContextGraph.to_dict() — the most direct path
  from this library's own graph type to YAML, used in
  examples/capability_gap_context_graphs_example.py — exports its records
  instead of an empty file.
- export_for_pipeline built its nested semantic network from the same
  defaulted lookups and had the same defect; it goes through the resolver
  too.
- YAMLSchemaExporter.export_ontology_schema gets the equivalent check over
  its own key set. Schemas are a separate vocabulary with no aliasing, so
  _require_recognized_keys lives in this module rather than in the shared
  graph resolver.
- 'metadata' is deliberately not sufficient to make a payload recognized.
  An export_json envelope carries one, so accepting it would readmit the
  case this fix is most likely to be needed for.
- An empty mapping is still exported: an empty graph is legitimate and has
  no records to lose.
- SemanticNetworkYAMLExporter.export() serializes before creating the
  output directory, so a rejected export leaves nothing behind.

The two rejections keep distinct exception types, following what the
codebase already does: a payload of the wrong *type* cannot be exported at
all and raises ProcessingError, matching Neo4jCSVExporter._normalize_graph;
a mapping whose *contents* are unusable raises ValidationError, matching
normalize_graph_payload. _require_mapping therefore runs first at every
entry point, so a non-mapping never reaches the resolver.

Docstring Raises sections, export_usage.md and docs/reference/export.md
record the accepted input shapes and both failures.

Closes #953.

* fix(export): reject payloads whose records resolve to nothing

Addresses the Qodo findings on #958.

Presence-only recognition (finding 1): checking that a recognized key is
present answered "did the caller use our vocabulary" when the question that
matters is "did anything the caller supplied survive". A payload like
{"entities": [], "data": [...records...]} cleared the check, resolved to
empty, and dropped every record under 'data' -- the silent-empty export by a
narrower route.

- utils/helpers.py — split the check in two. _require_recognized_keys keeps
  the presence rule; _require_nothing_dropped runs after resolution and
  refuses a payload that resolved to nothing while an unread key still holds
  records. Only a non-empty list counts as evidence: ContextGraph.to_dict()
  always carries a populated 'statistics' dict, and an empty graph must stay
  exportable, so 'metadata', 'statistics' and 'count' are named as context
  rather than records.
- export/yaml_exporter.py — the schema path had the same hole and now runs
  both checks through the shared helpers rather than its own copy, so the
  two vocabularies cannot drift apart in what counts as a silent-empty
  export.

Progress reported success on a failed write (finding 3): export_semantic_
network stops its tracking as completed once serialization returns, but
export() then creates the directory and writes the file. A failure there
left the tracker showing a completed export with no output.

- export/yaml_exporter.py — the serialization span now says it serialized,
  not that it exported, and export() opens its own span around the
  filesystem work that stops as failed on error. Nothing reports a completed
  export until the bytes are on disk.

Finding 2 (export_yaml no longer accepts List[Dict]) is the intended
resolution of #952 rather than a regression: wrapping a bare list under a
guessed key is what would mislabel the records. The signature, docstring and
PR description already record the narrowed contract.

Tests cover both directions of each fix, including that an empty
ContextGraph still exports and that a failing write is not reported as
completed.

* fix(export): validate collection values and make Neo4j mappings strict

Two gaps at the boundary the shared normalizer is supposed to own.

_resolve_collection() resolved on truthiness alone, so a recognized key
could still hold something that is not a collection of records:
{"entities": "abc"} normalized to three single-character "records", and
{"entities": 42} surfaced as a raw TypeError from list() inside whichever
exporter happened to read it, naming the exporter rather than the payload
key at fault. Collection values are now validated before conversion --
strings, bytes, mappings, and non-iterable scalars are rejected by key
name, and each element must be a mapping or an attribute-carrying object,
the two record shapes the exporters actually read. None stays legal as an
absent collection, the spelling a JSON round-trip produces for []; it
cannot hide dropped records, since _require_nothing_dropped() still runs.
Every spelling present is validated, not just the one that wins, so a
malformed alias is not excused by a well-formed canonical key.

Neo4jCSVExporter._normalize_graph() opted out of the recognized-key check
for mappings, which left it able to turn {"data": [...]} into header-only
CSVs indistinguishable from a genuinely empty graph -- the exact failure
the rest of the change exists to prevent. Mapping payloads now go through
normalize_graph_payload() on its default terms. The attribute path for
graph objects is untouched. With no caller left opting out, the
require_recognized flag is removed rather than kept as a way back into
the silent-empty export.

Regression tests cover the malformed values end to end through every
export path that reads the normalizer, and assert the rejected Neo4j
export writes no CSV files.

* fix(export): close YAML schema and record validation gaps

Fix 1 -- _require_usable_schema silent data loss (P1):
_require_usable_schema() passed all values from _SCHEMA_KEYS into
_require_nothing_dropped() as evidence that records survived.  Scalar
metadata fields such as version='1.0' and uri='http://...' are truthy
strings, so any one of them caused _require_nothing_dropped() to return
early and silently discard records stored under an unread key alongside
them (e.g. {'version': '1.0', 'nodes': [{'id': 'c1'}]}).  Fixed by
building the resolved list from only non-empty list/tuple values of
recognised schema keys.

Fix 2 -- _is_record accepts modules and type objects (P2):
_is_record() accepted any object with __dict__, which includes Python
modules and class objects.  Elements that passed _coerce_records then
reached exporters and raised AttributeError (e.g. module 'math' has no
attribute 'get') rather than a ValidationError at the validation
boundary.  Fixed by excluding types.ModuleType and type from the
__dict__ branch while preserving support for all user-defined
attribute-bearing record objects.

Tests: 101 tests pass across
  tests/utils/test_normalize_graph_payload.py
  tests/export/test_yaml_exporter_key_recognition.py
  tests/export/test_yaml_exporter_input_validation.py
  tests/export/test_neo4j_csv_exporter.py

* fix(export): close exception-type and record-shape gaps in normalize_graph_payload

LPGExporter and ArangoAQLExporter called normalize_graph_payload() with no
type guard, so non-mapping input raised ValidationError from inside the
resolver while the YAML and Neo4j exporters raised ProcessingError for the
identical mistake -- inconsistent with the exception-type contract this PR
establishes. Both now use the shared _require_mapping() guard (moved from
yaml_exporter.py into utils/helpers.py so all three can use it).

Neo4jCSVExporter._normalize_graph checked isinstance(graph, dict), so a
non-dict Mapping (MappingProxyType, ChainMap) fell through to the
object-attribute branch and was rejected, even though the identical payload
exported fine via the other three exporters. Now checks isinstance(graph,
Mapping).

normalize_graph_payload() accepts dataclass/attribute-bearing object
records, but LPGExporter/ArangoAQLExporter call .get(...) directly on
resolved entities -- an object-shaped record passed validation only to
crash with a raw AttributeError once used, the exact failure this
boundary exists to prevent. Records are now converted to plain dicts at
the boundary (_coerce_records -> new _record_to_dict), so every consumer
gets a uniform shape regardless of which reading the caller used.

Two non-empty spellings of the same collection holding identical records
in a different order were rejected as conflicting, since the check used
plain list equality. Comparison is now an order-independent multiset of
each record's canonical JSON form.

* docs(changelog): add entry for #958 YAML export input hardening

Documents the full arc of #958 -- the normalize_graph_payload()
centralization, YAML input validation, both review rounds from
@Sameer6305, and the exception-type/record-shape follow-up fixes -- plus
closes #956, #952, #953.

---------

Co-authored-by: Pravit Ampapathini <pravitampapathini@Pravits-MacBook-Air-3.local>
Co-authored-by: Sameer Kadam <sskadam6305@gmail.com>
Co-authored-by: KaifAhmad1 <kaifahmad087@gmail.com>
2026-08-15 22:10:04 +05:30
yzxcj797 eaf51b3383 fix(explorer): enable edge label rendering on the graph canvas 2026-08-15 23:50:47 +08:00
Lakshay Saini 115e7965cd fix(explorer): gate temporal requests on graph load (#1003)
Explorer was firing temporal requests before the graph even loaded.

When the backend is down, /api/graph/nodes fails but the temporal
bounds and snapshot effects didn't care , they fired anyway, off in
their own corner, ignoring whether the graph actually came up. Every
page load with no backend meant three failed requests instead of one,
and a scrubber that had nothing to scrub.

Added two small predicate functions and gated the temporal effects on
them. Basically: don't ask for time-based data until you know the
graph itself loaded. An empty graph still counts as loaded, so that
case isn't broken.

Confirmed with the backend down, before and after: three failing
requests down to one.

Fixes #982.
2026-08-15 17:47:35 +05:00