Static analysis for AI agent security posture and policy audit — with source-linked evidence.
Pulse inspects an AI agent repository without executing it and reports which capabilities the agent has (shell exec, network egress, secret reads, file writes), which source lines prove that, and which controls gate those capabilities. It understands the semantics of agent frameworks (LangGraph, AutoGen, CrewAI, OpenAI Agents SDK, etc.) rather than pattern-matching on imports.
Status:
v0.2.0-dev— SaaS pipeline functional; hard-gate scanner 3 of 4 gaps closed.The scanner, multi-tenant authorization, external auth, PostgreSQL + S3 deployment topology, and CI integration are functional for self-hosted deployments. The hard-gate scanner's eight priority rules were measured on holdout v3 (frozen, retired): original measurement reported precision 80%, recall 44.44% with 4 documented gaps. v0.2.0 closes 3 of 4 gaps (PULSE-003, PULSE-005, PULSE-012, and the PULSE-021 false-positive class); 1 partial gap remains (MCP-SERVERS-01 PULSE-021 FN —
match/casedispatch not yet recognized, but PULSE-002 fires for the same tool). See measurement-result-v0.2.0.md for the re-measurement. A new unseen holdout v4 is required for any future precision/recall claim.The Evidence-Semantic Verifier is a shadow/observation layer and does not change production findings.
The product source lives under huqan-pulse/.
AI agents behave differently from traditional applications: they invoke tools dynamically at runtime, make decisions, and interact with external systems. Static analysis tools built for traditional code cannot tell whether a subprocess.run call is a utility helper or a user-driven shell execution path.
Pulse addresses this gap:
- Capability-aware: Classifies what an agent can do separately from what it calls — canonical capability IDs like
shell.execute,network.http.request,secret.read,database.mutate,agent.task.delegate. - Evidence-semantic: Every finding is backed by source-linked evidence — which token, which function, which dispatch path proves the capability claim.
- Framework-aware: 60+ framework adapters recognize tool dispatch patterns for LangGraph, AutoGen, CrewAI, OpenAI Agents SDK, Pydantic AI, Semantic Kernel, Microsoft Agent Framework, AGNO, Langroid, Google ADK, ChatDev, smolagents, Browser-use, MCP, and more.
- Reachability-aware: Builds an enforcement graph proving whether a capability is reachable from source to sink, and which gates (approval, sandbox, policy engine) sit on the path.
- Drift-aware: Reports deltas between two scans — new capabilities added, controls removed.
- CI-friendly: SARIF output, baseline diffing,
--fail-onpolicies for GitHub Actions / GitLab CI. - Zero-execution: Customer code is never executed. Python is parsed via
python3 -I -S(stdlibastonly); JS/TS via the TypeScript parser.
docker pull ghcr.io/ali-ulu/pulse:v0.1.0
docker run --rm -v "$PWD:/repo" ghcr.io/ali-ulu/pulse:v0.1.0 \
node huqan-pulse/portable-scanner/scan.mjs /repo /tmp/report.json local/repo HEAD 0.1.0 productiongit clone https://github.com/ali-ulu/Pulse.git
cd Pulse/huqan-pulse
npm ci
# Scan the sample agent
node portable-scanner/verify.mjs
# Scan your own repo
node portable-scanner/scan.mjs \
/path/to/your/agent/repo \
pulse-report.json \
your-org/your-repo \
$(git rev-parse --short HEAD) \
0.1.0 \
production- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm ci
- name: Scan with Pulse
run: |
node portable-scanner/scan.mjs . pulse-report.sarif \
${{ github.repository }} ${{ github.sha }} 0.1.0 production \
--sarif --fail-on validated-hard-gate
- uses: github/codeql-action/upload-sarif@v3
if: always()
with: { sarif_file: pulse-report.sarif }| Framework | Adapter | Recognized patterns |
|---|---|---|
| LangGraph | yes | create_react_agent, StateGraph, ToolNode, conditional edges |
| AutoGen | yes | ConversableAgent, register_function, GroupChat, UserProxyAgent |
| CrewAI | yes | Crew, Agent, Task, @tool decorator, YAML config |
| OpenAI Agents SDK | yes | Runner.run, Agent, function_tool, handoff |
| Pydantic AI | yes | Agent, tool, RunContext |
| Semantic Kernel | yes | KernelFunction, kernel_function decorator |
| Microsoft Agent Framework | yes | AgentThread, tool registration |
| Google ADK | yes | Agent, Tool, Runner |
| AGNO | yes | Assistant, tool registration |
| Langroid | yes | ChatAgent, ToolMessage |
| ChatDev | yes | RolePlaying, YAML phase config |
| smolagents | yes | Tool, HfApiModel, CodeAgent |
| Browser-use | yes | Controller, @action decorator |
| MCP (Model Context Protocol) | yes | @mcp.tool(), server manifest, tool annotations |
| OpenAI function calling | yes | tools array, function schema |
Full list: capability registry.
Pulse maps each tool to one of these capability domains:
| Domain | Capability IDs | Example |
|---|---|---|
| Agent Core | agent.plan, agent.task.track, agent.task.delegate |
Planning, task tracking, sub-agent delegation |
| System Access | shell.execute, filesystem.write, filesystem.delete |
Shell command, file write/delete |
| External Egress | network.http.request, scm.repository.push, network.websocket |
HTTP request, git push, WebSocket |
| Sensitive Data | secret.read, database.mutate, persistent_memory |
Secret read, DB mutation, persistent memory |
Each capability produces a policy bundle entry with an allow / review / block / dry_run_only decision.
| Property | Status |
|---|---|
| Customer code never executed | yes — Python via python3 -I -S AST, JS/TS via TypeScript parser |
| Tenant isolation server-side | yes — cross-tenant reads return 403, not 404 |
| Source archive transient | yes — deleted after terminal scan transition, sha256 re-verified on each fetch |
| Dev auth rejected in production | yes — AUTH_MODE=dev + NODE_ENV=production rejected |
| Deterministic output | yes — same input produces byte-identical output, PYTHONHASHSEED=0 |
| Fail-closed partial assessment | yes — budget breach or parse error never produces a clean result |
| Ed25519-signed receipts | yes — keyId confusion bypass closed |
| HMAC-signed export cursors | yes — key rotation (active + verifier set) |
| ZIP bomb / path traversal guard | yes — two-pass bomb-safe filter, assertSafeName |
| Rate limit + CSP + HSTS + helmet defaults | yes — on all authenticated routes |
| Format | Use case |
|---|---|
| JSON | Full report, programmatic access |
| SARIF | GitHub Code Scanning, Azure DevOps |
| HTML | Human-readable x-ray view, source-linked |
| NDJSON | Streaming, large reports |
| policy_bundle | HUQAN runtime integration (Ed25519-signed) |
cd huqan-pulse
npm ci
npm run release:verifyrelease:verify runs (all must pass):
tsc --noEmit(typecheck)vitest run(250 tests) +node --test(10 runtime-integration tests) + evidence-semantic-verifier (248 checks)tsc -b && vite build(production build)npm run calibrate(HAGB calibration corpus)npm run test:portable-scanner-parity(root vs huqan-pulse portable-scanner sync)npm run verify:product-source-manifest(SHA-256 file manifest, 843 files)npm run verify:claim-guardrail(marketing claim guardrail)npm audit --audit-level=high(0 vulnerabilities)
Total: 513 checks (250 unit + 5 dashboard + 10 runtime + 248 evidence-semantic) — all green.
The product runs as a web API + dashboard + separate scan worker + PostgreSQL + S3-compatible source storage:
┌─────────────┐
│ Dashboard │ (Vite + React, dashboard app)
└──────┬──────┘
│
┌──────▼──────┐
│ Web API │ (Fastify, multi-tenant auth)
└──────┬──────┘
│
┌────────────┼────────────┐
│ │ │
┌──────▼──────┐ ┌───▼────┐ ┌─────▼─────┐
│ PostgreSQL │ │ S3 │ │ Worker │
│ (tenancy, │ │ (source│ │ (scan │
│ scans, │ │ archive│ │ pipeline)│
│ reports) │ │ transient)│ │
└─────────────┘ └────────┘ └───────────┘
Production startup is fail-closed. The service refuses to start if any of these are missing:
- PostgreSQL (
DATABASE_URL) - JWT/OIDC or WorkOS authentication settings
- S3-compatible source store
- Export resume cursor HMAC keyring (
EXPORT_CURSOR_HMAC_KEYS,EXPORT_CURSOR_HMAC_ACTIVE_KEY_ID)
Pre-deploy verification:
cd huqan-pulse
npm run predeploy:verify # staging:verify + storage:verify + auth:verify
npm run migrate # PostgreSQL schema migrationsLocal predeploy topology example: huqan-pulse/deploy/compose.predeploy.yml (PostgreSQL + MinIO + web + worker). Do not commit real secrets to the repo.
- Pull the immutable image:
docker pull ghcr.io/ali-ulu/pulse:v0.1.0 - Run the migration job as a one-shot release job.
- Deploy the worker.
- Deploy the web API.
- Verify readiness via
/healthzand/readyz. - Run an authenticated smoke test (WorkOS sign-in →
/me→ org create → scan upload → report read).
Full operations guide: huqan-pulse/docs/OPERATIONS_RUNBOOK.md
CI uses three independent gates:
verifyjob —release:verify+ calibration evidence clean checkhagb-regressionjob — HAGB benchmark, holdout v2/v3 freeze, blinded review packets, schema validationcontainerjob — production Docker image build + predeploy smoke test
The container job does not build unless verify and hagb-regression pass. Portable runtime parity and the product-source SHA-256 manifest are locked against drift.
Tag pushes (v*.*.*) additionally trigger the release workflow: verify → GHCR image push + GitHub Release (CHANGELOG notes + portable-scanner tarball).
The Evidence-Semantic Verifier is not a production gate. It produced useful signal in HAGB development/holdout work, but on a real MCP repository outside calibration it reached the same conclusion as the deterministic scanner on only 1 of 7 findings. It is kept in shadow/observation mode and does not suppress or elevate live findings.
Production decisions are made by the deterministic scanner, source evidence, the enforcement graph, and the documented finding rules.
Pulse does not claim to fully certify every security property or runtime behavior of a repository. Statically unsupported or insufficiently evidenced areas are reported as coverage gap, review required, or partial assessment — never hidden as clean.
The hard-gate scanner's eight priority rules had measured gaps (PULSE-003/005/021 false negatives, PULSE-012 false positive) documented in the holdout v3 measurement. v0.2.0 closes 3 of 4 gaps (see re-measurement); 1 partial gap remains (MCP-SERVERS-01 PULSE-021 FN — match/case dispatch). Until an unseen holdout v4 confirms the fixes generalize, the eight rules should still not be used as a blocking CI gate. Use --fail-on any-new-finding for drift detection.
- AI agent security review: Capability audit before integrating a third-party agent framework.
- CI/CD gate: Check agent capability drift on every PR; block new critical capabilities.
- Compliance: Agent capability inventory and evidence chain for SOC2 / ISO 27001 audits.
- Vendor risk: Verify a SaaS AI agent provider's claimed capability boundaries.
- Internal platform: Runtime policy enforcement for self-hosted AI agent platforms (via HUQAN runtime integration).
- Changelog
- Contributing
- Deployment readiness
- Operations runbook
- Security policy
- Engine boundary
- CI integration
- Worker budgets
- Bounded report persistence
- Export receipts and cancellation
- Real repo precision
- Industry standard calibration
- Portable scanner README
- Working lock (honest scope)
- Issue tracker — bug reports, feature requests, security disclosures
- Pull requests — see CONTRIBUTING.md
- Releases — version history and portable-scanner tarballs
- Container registry — Docker images
GNU Affero General Public License v3.0. AGPL-3.0 is a copyleft license that also covers network-served use — anyone who runs a modified Pulse as a web service must offer the source to all users of that service (section 13). Contributions are welcome under the same license; see CONTRIBUTING.md. For a commercial license not bound by AGPL, contact the maintainer.