network-ai 5.8.9 → 5.9.0

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.
@@ -564,4 +564,4 @@ Run these before declaring the integration production-ready:
564
564
 
565
565
  ---
566
566
 
567
- *Network-AI v5.8.9 · MIT License · https://github.com/Jovancoding/Network-AI*
567
+ *Network-AI v5.9.0 · MIT License · https://github.com/Jovancoding/Network-AI*
package/README.md CHANGED
@@ -5,7 +5,7 @@
5
5
  [![Website](https://img.shields.io/badge/website-network--ai.org-4b9df2?style=flat&logo=web&logoColor=white)](https://network-ai.org/)
6
6
  [![CI](https://github.com/Jovancoding/Network-AI/actions/workflows/ci.yml/badge.svg)](https://github.com/Jovancoding/Network-AI/actions/workflows/ci.yml)
7
7
  [![CodeQL](https://github.com/Jovancoding/Network-AI/actions/workflows/codeql.yml/badge.svg)](https://github.com/Jovancoding/Network-AI/actions/workflows/codeql.yml)
8
- [![Release](https://img.shields.io/badge/release-v5.8.9-blue.svg)](https://github.com/Jovancoding/Network-AI/releases)
8
+ [![Release](https://img.shields.io/badge/release-v5.9.0-blue.svg)](https://github.com/Jovancoding/Network-AI/releases)
9
9
  [![npm](https://img.shields.io/npm/dw/network-ai.svg?label=npm%20downloads)](https://www.npmjs.com/package/network-ai)
10
10
  [![Tests](https://img.shields.io/badge/tests-3136%20passing-brightgreen.svg)](#testing)
11
11
  [![Adapters](https://img.shields.io/badge/frameworks-29%20supported-blueviolet.svg)](#adapter-system)
package/SKILL.md CHANGED
@@ -754,7 +754,7 @@ The following findings are drawn from the **MAESTRO Agent Security Threat** fram
754
754
 
755
755
  | Control | How Network-AI addresses it |
756
756
  |---|---|
757
- | **Exact version pinning** | npm `package.json` uses exact `"version": "5.8.9"` — no semver range specifiers; `clawhub install network-ai` pins to a specific published version |
757
+ | **Exact version pinning** | npm `package.json` uses exact `"version": "5.9.0"` — no semver range specifiers; `clawhub install network-ai` pins to a specific published version |
758
758
  | **Zero transitive dependency drift** | All bundled Python scripts use Python stdlib only — `pip install` is never required; there are no third-party packages to drift, be compromised upstream, or introduce CVEs |
759
759
  | **Signed, tagged releases** | Every release is committed with a signed Git tag (`v5.7.x`); commit hash is verifiable against CHANGELOG.md; GitHub releases link tag → diff → changelog entry |
760
760
  | **Supply chain monitoring** | npm package continuously scored by Socket.dev (score A); any new dependency or permission change triggers an alert |
@@ -767,7 +767,7 @@ This skill is scanned on every publish. The following Notes are flagged by desig
767
767
 
768
768
  | Finding | Severity | Why it recurs | Documented control |
769
769
  |---------|----------|---------------|--------------------|
770
- | **ASI01** Agent Goal Hijack | High | Orchestrator skill forces 3-sub-task decomposition by design | Use this skill only when multi-agent orchestration is desired; disable for simple one-shot tasks |
770
+ | **ASI01** Agent Goal Hijack | High | Orchestrator skill performs multi-step decomposition and delegation by design | Use this skill only when multi-agent orchestration is desired; for simple requests the scope guard responds directly without decomposing |
771
771
  | **ASI03** Identity and Privilege Abuse (advisory tokens) | Medium | Grant tokens are advisory scoring outputs only — caller-supplied `--agent` identity is not cryptographically verified; skill explicitly warns tokens must not be used as real authorization for PAYMENTS, DATABASE, or FILE_EXPORT | Tokens are explicitly marked advisory in SKILL.md and source; require separate platform auth and human approval before any real database, payment, email, or export action |
772
772
  | **ASI03** Identity and Privilege Abuse (local grant state) | Low | The permission system creates persistent local state (`active_grants.json`, `audit_log.jsonl`, `.signing_key`) — security-relevant files that are purpose-aligned but accessible to anyone with `data/` access | Keep the skill directory private; back up or delete local grant state when no longer needed; do not share `data/` casually; restrict OS-level permissions on `data/` on shared machines |
773
773
  | **ASI03** Identity and Privilege Abuse (token integrity) | ~~High~~ Resolved | Token payload had no integrity protection — active_grants.json could be edited to forge elevated grants | Fixed in v5.5.2 — `check_permission.py` HMAC-SHA256 signs each grant (`_sig` field, stdlib `hmac`+`hashlib`, key at `data/.signing_key`); `validate_token.py` verifies before accepting; tampered tokens rejected with `"Token signature invalid"` |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "network-ai",
3
- "version": "5.8.9",
3
+ "version": "5.9.0",
4
4
  "description": "AI agent orchestration framework for TypeScript/Node.js - 29 adapters (LangChain, AutoGen, CrewAI, OpenAI Assistants, LlamaIndex, Semantic Kernel, Haystack, DSPy, Agno, MCP, OpenClaw, A2A, Codex, MiniMax, NemoClaw, APS, Copilot, LangGraph, Anthropic Computer Use, OpenAI Agents SDK, Vertex AI, Pydantic AI, Browser Agent, Hermes, Orchestrator, RLM + streaming variants). Built-in CLI, security, swarm intelligence, real-time streaming, and agentic workflow patterns.",
5
5
  "homepage": "https://network-ai.org",
6
6
  "main": "dist/index.js",
@@ -620,7 +620,10 @@ def audit_summary(last_n: int = 20, as_json: bool = False) -> int:
620
620
  Summarize recent permission requests, grants, and denials.
621
621
 
622
622
  Parses data/audit_log.jsonl and produces per-agent and per-resource
623
- breakdowns plus recent activity.
623
+ breakdowns plus recent activity. Denial counts are read directly from
624
+ ``permission_denied`` log entries — they are NOT inferred as
625
+ requests minus grants. This preserves accuracy when log lines are
626
+ missing, replayed, or arrive out of order.
624
627
  """
625
628
  if not AUDIT_LOG.exists():
626
629
  if as_json:
@@ -656,29 +659,34 @@ def audit_summary(last_n: int = 20, as_json: bool = False) -> int:
656
659
  # Aggregate stats
657
660
  total_requests = 0
658
661
  total_grants = 0
662
+ total_denials = 0
659
663
  by_agent: dict[str, dict[str, int]] = {}
660
664
  by_resource: dict[str, dict[str, int]] = {}
661
665
 
662
666
  for entry in entries:
663
667
  action = entry.get("action", "")
664
668
  details = entry.get("details", {})
665
- agent_id = details.get("agent_id", "unknown")
666
- resource_type = details.get("resource_type", "unknown")
669
+ agent_id = details.get("agent_id", details.get("agentId", "unknown"))
670
+ resource_type = details.get("resource_type", details.get("resourceType", "unknown"))
667
671
 
668
672
  if action == "permission_request":
669
673
  total_requests += 1
670
- by_agent.setdefault(agent_id, {"requests": 0, "grants": 0})
674
+ by_agent.setdefault(agent_id, {"requests": 0, "grants": 0, "denials": 0})
671
675
  by_agent[agent_id]["requests"] += 1
672
- by_resource.setdefault(resource_type, {"requests": 0, "grants": 0})
676
+ by_resource.setdefault(resource_type, {"requests": 0, "grants": 0, "denials": 0})
673
677
  by_resource[resource_type]["requests"] += 1
674
678
  elif action == "permission_granted":
675
679
  total_grants += 1
676
- by_agent.setdefault(agent_id, {"requests": 0, "grants": 0})
680
+ by_agent.setdefault(agent_id, {"requests": 0, "grants": 0, "denials": 0})
677
681
  by_agent[agent_id]["grants"] += 1
678
- by_resource.setdefault(resource_type, {"requests": 0, "grants": 0})
682
+ by_resource.setdefault(resource_type, {"requests": 0, "grants": 0, "denials": 0})
679
683
  by_resource[resource_type]["grants"] += 1
680
-
681
- total_denials = total_requests - total_grants
684
+ elif action == "permission_denied":
685
+ total_denials += 1
686
+ by_agent.setdefault(agent_id, {"requests": 0, "grants": 0, "denials": 0})
687
+ by_agent[agent_id]["denials"] += 1
688
+ by_resource.setdefault(resource_type, {"requests": 0, "grants": 0, "denials": 0})
689
+ by_resource[resource_type]["denials"] += 1
682
690
 
683
691
  # Recent entries (last N)
684
692
  recent = entries[-last_n:]
@@ -700,6 +708,7 @@ def audit_summary(last_n: int = 20, as_json: bool = False) -> int:
700
708
  "total_requests": total_requests,
701
709
  "total_grants": total_grants,
702
710
  "total_denials": total_denials,
711
+ "denial_source": "explicit_permission_denied_events",
703
712
  "time_range": {"first": first_ts, "last": last_ts},
704
713
  "by_agent": by_agent,
705
714
  "by_resource": by_resource,
@@ -725,7 +734,7 @@ def audit_summary(last_n: int = 20, as_json: bool = False) -> int:
725
734
  print(f" {'Agent':<20} {'Requests':>10} {'Grants':>10} {'Denials':>10}")
726
735
  print(f" {'-'*50}")
727
736
  for agent_id, stats in sorted(by_agent.items()):
728
- denials = stats["requests"] - stats["grants"]
737
+ denials = stats["denials"]
729
738
  print(f" {agent_id:<20} {stats['requests']:>10} {stats['grants']:>10} {denials:>10}")
730
739
 
731
740
  if by_resource:
@@ -734,7 +743,7 @@ def audit_summary(last_n: int = 20, as_json: bool = False) -> int:
734
743
  print(f" {'Resource':<20} {'Requests':>10} {'Grants':>10} {'Denials':>10}")
735
744
  print(f" {'-'*50}")
736
745
  for resource_type, stats in sorted(by_resource.items()):
737
- denials = stats["requests"] - stats["grants"]
746
+ denials = stats["denials"]
738
747
  print(f" {resource_type:<20} {stats['requests']:>10} {stats['grants']:>10} {denials:>10}")
739
748
 
740
749
  print(f"\n Recent Activity (last {min(last_n, len(recent))}):")