picosentry 2.0.2__tar.gz → 2.0.7__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.
- picosentry-2.0.7/PKG-INFO +320 -0
- picosentry-2.0.7/README.md +243 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/__init__.py +1 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/__init__.py +1 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/logging.py +1 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/tracing.py +13 -4
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/__init__.py +1 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/_base.py +4 -5
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus_governance.py +7 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/engine.py +12 -14
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/validation.py +4 -4
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/version.py +1 -1
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/database/manager.py +12 -3
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/correlation.py +2 -2
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/observability.py +36 -19
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/__init__.py +1 -1
- picosentry-2.0.7/picosentry.egg-info/PKG-INFO +320 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/pyproject.toml +1 -1
- picosentry-2.0.2/PKG-INFO +0 -343
- picosentry-2.0.2/README.md +0 -266
- picosentry-2.0.2/picosentry.egg-info/PKG-INFO +0 -343
- {picosentry-2.0.2 → picosentry-2.0.7}/COMMERCIAL-LICENSE.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/LICENSE +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/LICENSE-SUMMARY.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/__main__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/audit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/guards.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/policy.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/_core/py.typed +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/cli.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/experimental.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/__main__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/admission/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/admission/scanner.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/admission/validator.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/api_versioning.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/logger.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/sinks/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/sinks/base.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/sinks/file_sink.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/sinks/syslog_sink.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/audit/sinks/webhook_sink.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/auth.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/baseline_hardening.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/cli.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/cluster/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/cluster/manager.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/daemon/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/daemon/redis_store.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/daemon/server.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/daemon/sqlite_store.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/daemon/store.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SECCOMP-KILL.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-002.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-003.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-004.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-005.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-006.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-007.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-008.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-009.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-SUS-010.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/L3-TIMEOUT-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/docs/rules/README.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/errors.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/cyclonedx.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/github.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/json_fmt.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/ml_context.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/sarif.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/formatters/table.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/grpc_transport/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/grpc_transport/_servicer.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/grpc_transport/client.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/grpc_transport/server.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/guards.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/health.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/backends/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/backends/base.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/backends/seatbelt_backend.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/backends/seccomp_backend.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/backends/subprocess_backend.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/engine.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/policy.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l3/policy_hash.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/baseline.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/differ.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/engine.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/profiler.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/redis_baseline.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/baseline_drift.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/container_escape.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/crypto_mining.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/dependency_confusion.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/entropy.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/env_leak.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/exfil.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/filesystem.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/honeypot.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/network.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/persistence.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/privilege_escalation.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/process_anomaly.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/supply_chain.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/l4/rules/timing.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/license.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/mtls/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/mtls/context.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/notary/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/notary/rekor.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/policy_versioned/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/policy_versioned/signing.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/policy_versioned/store.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/py.typed +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/ratelimit/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/ratelimit/limiter.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/ratelimit/queue.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/ratelimit/redis_limiter.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/redis_health.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/reproducible.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/retention/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/retention/manager.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/slo.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/tenant/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/tenant/store.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/webhooks.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/sandbox/workspace.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/__main__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/_network.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/advisory.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/audit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/auth.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/cache.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/axios_poisoning/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/axios_poisoning/detector.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/node_ipc_compromise/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/node_ipc_compromise/detector.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/shai_hulud/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/shai_hulud/detector.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/trapdoor/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/campaigns/trapdoor/detector.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/cli.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/advisories/npm-critical-advisories.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/cargo_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/generate_npm_top.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/go_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/colors_js.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/crossenv.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/event_stream_3.3.6.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/left_pad.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/nx_typosquat.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/shai_hulud.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/ioc/ua_parser_js.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/maven_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/npm_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/nuget_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/pypi_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus/rubygems_top_packages.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/corpus_share.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/crypto.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/daemon.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/detection_quality.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-BUND-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-CARGO-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-CARGO-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-CARGO-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-CRED-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-ENGIN-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-FORK-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-GO-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-GO-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-GO-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-IOC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-LICENSE-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-LOCK-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MAINT-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MANI-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MANI-002.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MAVEN-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MAVEN-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-MAVEN-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-NETEX-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-NUGET-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-NUGET-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-NUGET-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-OBFS-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-OBFS-002.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-OBFS-003.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-OBFS-004.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PNPM-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-POST-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PROV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-002.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-003.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-004.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-005.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-006.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-OBFS-007.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-POST-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-PYPI-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-RUBYGEMS-ADV-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-RUBYGEMS-DEPC-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-RUBYGEMS-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-SIDELOAD-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-TYPO-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/L2-WORM-001.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/docs/rules/README.md +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/enterprise.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/fleet.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/cyclonedx.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/github.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/json_fmt.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/ml_context.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/sarif.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/formatters/table.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/guards.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/ioc_registry.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/logging.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/management.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/metrics.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/policy.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/policy_lifecycle.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/py.typed +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/advisory_check.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/bundled_shadow.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/cargo_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/cargo_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/credential_read.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/dep_confusion.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/engine.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/fork_drift.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/go_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/go_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/ioc_detection.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/license.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/lockfile_drift.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/maintainer_change.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/manifest.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/maven_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/maven_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/network_exfil.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/nuget_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/nuget_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/obfuscation.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pnpm_config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pnpm_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/post_install.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/provenance.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pypi_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pypi_obfuscation.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pypi_post_install.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/pypi_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/rubygems_lock_parser.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/rubygems_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/sideloading.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/typosquat.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/typosquat_utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/utils.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/rules/worm_propagation.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/tenant.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/scan/workspace.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/deps.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/models.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/admin.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/anomaly.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/auth.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/correlation.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/dashboard.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/health.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/metrics.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/orgs.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/plugins.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/projects.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/scans.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/scheduler.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/webhooks.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/routers/ws.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/api/server.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/anomaly_rules.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/logging_config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/project_registry.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/protocols.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/config/settings.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/database/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/database/pools.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/front/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/front/index.html +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/audit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/cors_hardening.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/ddos_shield.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/docs_restriction.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/https_enforcement.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/rate_limit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/request_id.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/request_size_limit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/request_timeout.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/middleware/security_headers.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/plugins/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/plugins/test_discord_notifier/notifier.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/plugins/test_discord_notifier/plugin.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/plugins/test_plugin/plugin.json +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/plugins/test_plugin/test_handler.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/alert_hub.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/anomaly_detector.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/audit_cleanup.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/auth.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/backup.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/event_bus.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/intelligence.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/log_manager.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/metrics.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/orchestrator.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/orgs.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/plugin_manager.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/rbac.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/scheduler.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/webhooks.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/serve/services/websocket_manager.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/__main__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/cli.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/config.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/engine/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/engine/normalizer.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/engine/rule_engine.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/health.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/middleware/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/middleware/rate_limiter.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/output_guard/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/picoshogun/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/prompt_guard/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/prompt_guard/normalize.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/prompt_guard/rules.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/prompt_guard/scorer.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/py.typed +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/ratelimit.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/output_policy/exfiltration.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/output_policy/format_violation.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/output_policy/harmful_content.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/output_policy/pii_leak.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/context_injection.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/encoding_attack.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/extraction_attempt.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/instruction_override.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/multi_turn_trap.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/rules/prompt_injection/role_manipulation.yaml +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/server.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/telemetry/__init__.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/telemetry/metrics.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/telemetry/otel.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/telemetry/sink.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry/watch/types.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry.egg-info/SOURCES.txt +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry.egg-info/dependency_links.txt +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry.egg-info/entry_points.txt +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry.egg-info/requires.txt +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/picosentry.egg-info/top_level.txt +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/setup.cfg +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/tests/test_auth.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/tests/test_errors.py +0 -0
- {picosentry-2.0.2 → picosentry-2.0.7}/tests/test_slo.py +0 -0
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: picosentry
|
|
3
|
+
Version: 2.0.7
|
|
4
|
+
Summary: Unified supply-chain security suite — scanner, sandbox, LLM defense, and orchestration
|
|
5
|
+
Author-email: Henrik Kirk <kirk@kirkforge.dev>
|
|
6
|
+
Maintainer-email: KirkForge <kirk@kirkforge.dev>
|
|
7
|
+
License-Expression: BUSL-1.1
|
|
8
|
+
Project-URL: Homepage, https://github.com/KirkForge/PicoSentry
|
|
9
|
+
Project-URL: Documentation, https://github.com/KirkForge/PicoSentry#readme
|
|
10
|
+
Project-URL: Repository, https://github.com/KirkForge/PicoSentry
|
|
11
|
+
Project-URL: Issues, https://github.com/KirkForge/PicoSentry/issues
|
|
12
|
+
Project-URL: Changelog, https://github.com/KirkForge/PicoSentry/blob/main/CHANGELOG.md
|
|
13
|
+
Project-URL: Release Notes, https://github.com/KirkForge/PicoSentry/releases
|
|
14
|
+
Project-URL: Source Code, https://github.com/KirkForge/PicoSentry
|
|
15
|
+
Project-URL: Bug Tracker, https://github.com/KirkForge/PicoSentry/issues
|
|
16
|
+
Project-URL: Commercial, https://github.com/KirkForge/PicoShogun
|
|
17
|
+
Keywords: security,supply-chain,sandbox,llm-defense,prompt-injection,scanner,npm,pnpm,deterministic,audit,orchestration,devsecops,ci-cd
|
|
18
|
+
Classifier: Development Status :: 4 - Beta
|
|
19
|
+
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Intended Audience :: System Administrators
|
|
21
|
+
Classifier: Intended Audience :: Information Technology
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Programming Language :: Python :: 3
|
|
24
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
28
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
29
|
+
Classifier: Topic :: Security
|
|
30
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
31
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
32
|
+
Classifier: Topic :: System :: Monitoring
|
|
33
|
+
Classifier: Environment :: Console
|
|
34
|
+
Classifier: Framework :: FastAPI
|
|
35
|
+
Classifier: Framework :: Pytest
|
|
36
|
+
Classifier: Typing :: Typed
|
|
37
|
+
Requires-Python: >=3.10
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
License-File: LICENSE
|
|
40
|
+
License-File: LICENSE-SUMMARY.md
|
|
41
|
+
License-File: COMMERCIAL-LICENSE.md
|
|
42
|
+
Requires-Dist: pyyaml>=6.0
|
|
43
|
+
Provides-Extra: scan
|
|
44
|
+
Requires-Dist: requests>=2.31.0; extra == "scan"
|
|
45
|
+
Provides-Extra: watch-server
|
|
46
|
+
Requires-Dist: fastapi>=0.100; extra == "watch-server"
|
|
47
|
+
Requires-Dist: uvicorn>=0.23; extra == "watch-server"
|
|
48
|
+
Provides-Extra: serve
|
|
49
|
+
Requires-Dist: fastapi>=0.104.0; extra == "serve"
|
|
50
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "serve"
|
|
51
|
+
Requires-Dist: pydantic>=2.0.0; extra == "serve"
|
|
52
|
+
Requires-Dist: PyJWT>=2.8.0; extra == "serve"
|
|
53
|
+
Requires-Dist: passlib[bcrypt]>=1.7.4; extra == "serve"
|
|
54
|
+
Requires-Dist: python-multipart>=0.0.6; extra == "serve"
|
|
55
|
+
Requires-Dist: croniter>=1.0.0; extra == "serve"
|
|
56
|
+
Provides-Extra: otel
|
|
57
|
+
Requires-Dist: opentelemetry-api>=1.20; extra == "otel"
|
|
58
|
+
Requires-Dist: opentelemetry-sdk>=1.20; extra == "otel"
|
|
59
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20; extra == "otel"
|
|
60
|
+
Provides-Extra: sigstore
|
|
61
|
+
Requires-Dist: sigstore>=3.0; extra == "sigstore"
|
|
62
|
+
Provides-Extra: all
|
|
63
|
+
Requires-Dist: picosentry[otel,scan,serve,sigstore,watch-server]; extra == "all"
|
|
64
|
+
Provides-Extra: dev
|
|
65
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
66
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
67
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
|
|
68
|
+
Requires-Dist: pytest-timeout>=2.0; extra == "dev"
|
|
69
|
+
Requires-Dist: httpx>=0.24; extra == "dev"
|
|
70
|
+
Requires-Dist: ruff>=0.8; extra == "dev"
|
|
71
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
72
|
+
Requires-Dist: build>=1.0; extra == "dev"
|
|
73
|
+
Requires-Dist: twine>=5.0; extra == "dev"
|
|
74
|
+
Requires-Dist: jsonschema>=4.0; extra == "dev"
|
|
75
|
+
Requires-Dist: types-PyYAML; extra == "dev"
|
|
76
|
+
Dynamic: license-file
|
|
77
|
+
|
|
78
|
+
# PicoSentry 🦞
|
|
79
|
+
|
|
80
|
+

|
|
81
|
+
|
|
82
|
+
**Local supply-chain scanner with offline, deterministic detection across npm, PyPI, Go, Cargo, Maven, RubyGems, and NuGet. Kernel-sandbox enforcement is included as a beta capability for runtime containment.**
|
|
83
|
+
|
|
84
|
+
> PicoSentry scans a candidate package for malicious-behavior patterns — obfuscation,
|
|
85
|
+
> typosquatting, dependency confusion, post-install exfiltration, known IOCs, and CVEs —
|
|
86
|
+
> using a fully offline rule catalog. A kernel-sandbox (`seccomp-bpf` + `landlock`) is
|
|
87
|
+
> available to enforce syscalls at install time; full per-syscall tracing from the kernel
|
|
88
|
+
> is tracked as future work.
|
|
89
|
+
|
|
90
|
+
[](https://pypi.org/project/picosentry/)
|
|
91
|
+
[](https://pypi.org/project/picosentry/)
|
|
92
|
+
[](LICENSE)
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Status
|
|
97
|
+
|
|
98
|
+
Source of truth: [`picosentry/experimental.py`](picosentry/experimental.py).
|
|
99
|
+
|
|
100
|
+
| Component | Status | Notes |
|
|
101
|
+
|-----------|--------|-------|
|
|
102
|
+
| `picosentry scan` | **Stable** | Core scanner; 7 ecosystems; deterministic, offline |
|
|
103
|
+
| `picosentry sandbox` | **Beta** | seccomp-bpf enforces; gRPC transport experimental |
|
|
104
|
+
| `picosentry watch` | **Beta** | Prompt-injection detection works; HTTP server experimental |
|
|
105
|
+
| `picosentry serve` | **Experimental** | API server + dashboard in active development |
|
|
106
|
+
| Cross-layer correlation | **Experimental** | Links findings across layers |
|
|
107
|
+
| Plugin system | **Beta** | Loads and dispatches; signature verify works |
|
|
108
|
+
| Postgres backend | **Stub** | SQLite only; migration not started |
|
|
109
|
+
| Cluster mode | **Experimental** | Single-node verified; multi-node gossip untested |
|
|
110
|
+
| Detection benchmarks | **Stub** | Framework defined, no real data yet |
|
|
111
|
+
| Corpus marketplace | **Stub** | Export/import CLI commands not wired |
|
|
112
|
+
|
|
113
|
+
The scanner is the stable product. The kernel sandbox is beta enforcement-only today;
|
|
114
|
+
it kills disallowed syscalls but does not yet emit a per-syscall trace (see "What it
|
|
115
|
+
does NOT do" below).
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
## What it does NOT do (today)
|
|
120
|
+
|
|
121
|
+
- **Does not record per-syscall traces from the kernel sandbox.** The seccomp-bpf
|
|
122
|
+
backend enforces (kills on disallowed syscalls) and emits meta-events (verdict,
|
|
123
|
+
timeout, violation, degradation) — not a syscall stream. L4 behavioral observers
|
|
124
|
+
read subprocess stdout, not the kernel.
|
|
125
|
+
- **Does not scan LLM model weights.** It guards prompts and outputs in deployed
|
|
126
|
+
apps, not the model itself.
|
|
127
|
+
- **Does not run cluster mode in production.** Single-node only; multi-node gossip
|
|
128
|
+
is untested.
|
|
129
|
+
- **Does not have a real Postgres backend.** SQLite only.
|
|
130
|
+
- **Does not have detection-benchmark data.** The validation harness exists
|
|
131
|
+
(`picosentry scan --validate`); the rule-level precision/recall numbers have not
|
|
132
|
+
been run against a real dataset.
|
|
133
|
+
- **Does not advertise a CVE database on its own.** CVE matching uses the OSV
|
|
134
|
+
corpus (`[scan]` extra); offline-only operation pulls from the local corpus
|
|
135
|
+
snapshot.
|
|
136
|
+
|
|
137
|
+
If a feature is in `experimental.py` as Stub or Experimental, treat it as not
|
|
138
|
+
shipped.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## 30-second demo (no clone)
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
pip install picosentry
|
|
146
|
+
picosentry scan ./your-project # any project on disk
|
|
147
|
+
picosentry scan ./package.json # or a single manifest
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
If you prefer a reproducible example, the repo ships a malicious PyPI fixture:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
git clone https://github.com/KirkForge/PicoSentry.git
|
|
154
|
+
cd PicoSentry
|
|
155
|
+
picosentry scan examples/pypi-obfuscated-setup/
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Real CLI output
|
|
159
|
+
|
|
160
|
+
```text
|
|
161
|
+
$ picosentry scan examples/pypi-obfuscated-setup/
|
|
162
|
+
PICOSENTRY_CACHE_HMAC_KEY not set — cache entries will be invalidated on process restart. Set it for persistent cache integrity.
|
|
163
|
+
🦞 PicoSentry
|
|
164
|
+
Target: /home/kirk/Madlab/Clean-Live/PicoSeries/picosentry/examples/pypi-obfuscated-setup
|
|
165
|
+
Engine: v2.0.5 | Corpus: vef6b3b3115bb
|
|
166
|
+
Scan ID: 08057439b4ba08d8
|
|
167
|
+
|
|
168
|
+
Packages scanned: 0
|
|
169
|
+
Files scanned: 2
|
|
170
|
+
Duration: 20ms
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The scan above fires 5+ findings across the obfuscation, post-install, and
|
|
174
|
+
exfiltration rules. Re-run with the same inputs and the `Scan ID` and `Corpus`
|
|
175
|
+
digest will match exactly — that's the determinism guarantee.
|
|
176
|
+
|
|
177
|
+
> A complete sample output (with rule IDs and severities) for the same example is
|
|
178
|
+
> checked into the repo. The example is the reproducible fixture we use in CI.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## What it detects (a subset)
|
|
183
|
+
|
|
184
|
+
| Rule | What it catches | Example |
|
|
185
|
+
|------|----------------|---------|
|
|
186
|
+
| L2-TYPO-001 | Typosquatted package names | `reqursts` instead of `requests` |
|
|
187
|
+
| L2-DEPC-001 | Dependency confusion (private → public) | `internal-pkg` not on registry |
|
|
188
|
+
| L2-PYPI-OBFS-001 | Dynamic execution in setup.py | `exec()` / `eval()` in install scripts |
|
|
189
|
+
| L2-PYPI-OBFS-002 | Base64-decoded payloads in source | `base64.b64decode(...)` + dynamic use |
|
|
190
|
+
| L2-PYPI-OBFS-007 | Base64 decode + exec/eval combo | Decode-then-execute obfuscation chain |
|
|
191
|
+
| L2-PYPI-POST-001 | Post-install code execution | `setup.py` runs code at install time |
|
|
192
|
+
| L2-NETEX-001 | Network calls during install | `urllib.request`, `curl`, `wget` at install |
|
|
193
|
+
| L2-IOC-001 | Known IOC behavior patterns | Hardcoded C2 host, exfil URL patterns |
|
|
194
|
+
| L2-CVE-001 | Known CVEs in dependency tree | OSV-matched vulnerabilities |
|
|
195
|
+
| L2-DEP-001 | Deprecated / insecure dependency | End-of-life library versions |
|
|
196
|
+
| L2-SBOM-001 | SBOM generation | CycloneDX-compatible output |
|
|
197
|
+
| L2-LICENSE-001 | License compliance | Copyleft, unknown, deprecated licenses |
|
|
198
|
+
|
|
199
|
+
Full rule catalog: [`picosentry/scan/docs/rules/`](picosentry/scan/docs/rules/) (50 rules
|
|
200
|
+
across the supported ecosystems).
|
|
201
|
+
|
|
202
|
+
---
|
|
203
|
+
|
|
204
|
+
## Feature matrix
|
|
205
|
+
|
|
206
|
+
| Feature | PicoSentry | pip-audit | osv-scanner | Trivy | Socket |
|
|
207
|
+
|---------|:---------:|:---------:|:-----------:|:-----:|:------:|
|
|
208
|
+
| Offline operation | yes | partial | partial | partial | no |
|
|
209
|
+
| Deterministic output (bit-identical runs) | yes | no | no | no | no |
|
|
210
|
+
| Malicious-behavior detection (not just CVEs) | yes | no | no | partial | partial |
|
|
211
|
+
| Multi-ecosystem (npm, PyPI, Go, Cargo, Maven, RubyGems, NuGet) | yes | partial | yes | yes | partial |
|
|
212
|
+
| Runtime sandbox enforcement (kernel-level) | beta | no | no | no | no |
|
|
213
|
+
| Runtime syscall observation from kernel | no | no | no | no | no |
|
|
214
|
+
| FOSS source available | yes (BUSL-1.1) | yes (Apache-2.0) | yes (Apache-2.0) | yes (Apache-2.0) | no |
|
|
215
|
+
|
|
216
|
+
Where PicoSentry is weaker: pip-audit and osv-scanner have wider and more frequently
|
|
217
|
+
refreshed CVE coverage via OSV. Trivy has broader container and IaC scanning. Socket
|
|
218
|
+
has hosted workflow integrations PicoSentry doesn't ship. The differentiator is the
|
|
219
|
+
combination of offline + deterministic + malicious-behavior rules in a single offline
|
|
220
|
+
binary — not raw CVE breadth.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Install
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Core scanner — works offline, no HTTP deps (only `pyyaml` installed)
|
|
228
|
+
pip install picosentry
|
|
229
|
+
|
|
230
|
+
# Extras
|
|
231
|
+
pip install picosentry[scan] # + online corpus management
|
|
232
|
+
pip install picosentry[serve] # + API server + dashboard
|
|
233
|
+
pip install picosentry[all] # Everything
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The default `pip install picosentry` is deliberately lightweight — it pulls in
|
|
237
|
+
only `pyyaml`, which is enough to run `picosentry scan` against any project.
|
|
238
|
+
To use the API server, dashboard, or HTTP corpus refresh, install the matching
|
|
239
|
+
extras (see [install options](#install-options) below).
|
|
240
|
+
|
|
241
|
+
### Install options
|
|
242
|
+
|
|
243
|
+
| Command | What you get |
|
|
244
|
+
|---------|-------------|
|
|
245
|
+
| `pip install picosentry` | Core: scanner, sandbox, watch (lightweight) |
|
|
246
|
+
| `pip install picosentry[scan]` | + requests for online corpus management |
|
|
247
|
+
| `pip install picosentry[serve]` | + FastAPI server, dashboard, auth, scheduler |
|
|
248
|
+
| `pip install picosentry[watch-server]` | + FastAPI + uvicorn for watch HTTP daemon |
|
|
249
|
+
| `pip install picosentry[otel]` | + OpenTelemetry tracing |
|
|
250
|
+
| `pip install picosentry[sigstore]` | + Sigstore signing support |
|
|
251
|
+
| `pip install picosentry[all]` | Everything |
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Usage
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
picosentry scan ./my-project
|
|
259
|
+
picosentry scan ./package.json # single file
|
|
260
|
+
picosentry scan --format json ./project # JSON output
|
|
261
|
+
picosentry scan --format sarif ./project # SARIF output
|
|
262
|
+
picosentry scan --format cyclonedx ./project # CycloneDX SBOM
|
|
263
|
+
picosentry scan --verify-determinism ./project # assert SHA-256 stability
|
|
264
|
+
picosentry scan --diff scan-a.json scan-b.json # compare two scans
|
|
265
|
+
picosentry scan --fail-on high ./project # exit non-zero on HIGH+
|
|
266
|
+
picosentry sandbox echo "hello" # beta — kernel-level enforcement
|
|
267
|
+
picosentry watch scan-prompt --text "..." # beta — LLM prompt guard
|
|
268
|
+
picosentry serve --port 8765 # experimental — API + dashboard
|
|
269
|
+
picosentry health
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Design principles
|
|
275
|
+
|
|
276
|
+
- **Deterministic**: same inputs + same policy = same SHA-256 output. No randomness,
|
|
277
|
+
no probabilistic scoring, no network dependence. Asserted by `--verify-determinism`.
|
|
278
|
+
- **Offline by default**: no phone-home, no remote API calls at scan time. Works in
|
|
279
|
+
air-gapped environments. Online corpus refresh is opt-in via the `[scan]` extra.
|
|
280
|
+
- **Typed**: full Python type annotations, `py.typed` shipped.
|
|
281
|
+
- **Lightweight core**: the default install pulls only `pyyaml`. Heavy deps are
|
|
282
|
+
gated behind extras.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Repository structure
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
picosentry/
|
|
290
|
+
_core/ shared primitives
|
|
291
|
+
scan/ supply-chain scanner (CLI: `picosentry scan`)
|
|
292
|
+
sandbox/ runtime kernel-sandbox (CLI: `picosentry sandbox`, beta)
|
|
293
|
+
watch/ LLM prompt/output guard (CLI: `picosentry watch`, beta)
|
|
294
|
+
serve/ API server + dashboard (CLI: `picosentry serve`, experimental)
|
|
295
|
+
experimental.py feature-maturity tracking
|
|
296
|
+
examples/
|
|
297
|
+
pypi-obfuscated-setup/ reproducible malicious PyPI fixture
|
|
298
|
+
npm-postinstall-exfil/ reproducible npm post-install fixture
|
|
299
|
+
prompt-injection/ reproducible prompt-injection fixture
|
|
300
|
+
docs/
|
|
301
|
+
rules/ per-rule documentation (see picosentry/scan/docs/rules/)
|
|
302
|
+
strategic/ design docs and architecture
|
|
303
|
+
tests/ test suite
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
---
|
|
307
|
+
|
|
308
|
+
## Where to get help
|
|
309
|
+
|
|
310
|
+
- **Bug reports / feature requests**: [GitHub Issues](https://github.com/KirkForge/PicoSentry/issues)
|
|
311
|
+
- **Security issues** (do **not** file a public issue): see [SECURITY.md](SECURITY.md) —
|
|
312
|
+
email `security@kirkforge.dev` or open a [private vulnerability report](https://github.com/KirkForge/PicoSentry/security/advisories/new).
|
|
313
|
+
- **Questions / discussion**: [GitHub Discussions](https://github.com/KirkForge/PicoSentry/discussions)
|
|
314
|
+
- **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
315
|
+
|
|
316
|
+
---
|
|
317
|
+
|
|
318
|
+
## License
|
|
319
|
+
|
|
320
|
+
BUSL-1.1 — see [LICENSE](LICENSE) and [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md).
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# PicoSentry 🦞
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
**Local supply-chain scanner with offline, deterministic detection across npm, PyPI, Go, Cargo, Maven, RubyGems, and NuGet. Kernel-sandbox enforcement is included as a beta capability for runtime containment.**
|
|
6
|
+
|
|
7
|
+
> PicoSentry scans a candidate package for malicious-behavior patterns — obfuscation,
|
|
8
|
+
> typosquatting, dependency confusion, post-install exfiltration, known IOCs, and CVEs —
|
|
9
|
+
> using a fully offline rule catalog. A kernel-sandbox (`seccomp-bpf` + `landlock`) is
|
|
10
|
+
> available to enforce syscalls at install time; full per-syscall tracing from the kernel
|
|
11
|
+
> is tracked as future work.
|
|
12
|
+
|
|
13
|
+
[](https://pypi.org/project/picosentry/)
|
|
14
|
+
[](https://pypi.org/project/picosentry/)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Status
|
|
20
|
+
|
|
21
|
+
Source of truth: [`picosentry/experimental.py`](picosentry/experimental.py).
|
|
22
|
+
|
|
23
|
+
| Component | Status | Notes |
|
|
24
|
+
|-----------|--------|-------|
|
|
25
|
+
| `picosentry scan` | **Stable** | Core scanner; 7 ecosystems; deterministic, offline |
|
|
26
|
+
| `picosentry sandbox` | **Beta** | seccomp-bpf enforces; gRPC transport experimental |
|
|
27
|
+
| `picosentry watch` | **Beta** | Prompt-injection detection works; HTTP server experimental |
|
|
28
|
+
| `picosentry serve` | **Experimental** | API server + dashboard in active development |
|
|
29
|
+
| Cross-layer correlation | **Experimental** | Links findings across layers |
|
|
30
|
+
| Plugin system | **Beta** | Loads and dispatches; signature verify works |
|
|
31
|
+
| Postgres backend | **Stub** | SQLite only; migration not started |
|
|
32
|
+
| Cluster mode | **Experimental** | Single-node verified; multi-node gossip untested |
|
|
33
|
+
| Detection benchmarks | **Stub** | Framework defined, no real data yet |
|
|
34
|
+
| Corpus marketplace | **Stub** | Export/import CLI commands not wired |
|
|
35
|
+
|
|
36
|
+
The scanner is the stable product. The kernel sandbox is beta enforcement-only today;
|
|
37
|
+
it kills disallowed syscalls but does not yet emit a per-syscall trace (see "What it
|
|
38
|
+
does NOT do" below).
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## What it does NOT do (today)
|
|
43
|
+
|
|
44
|
+
- **Does not record per-syscall traces from the kernel sandbox.** The seccomp-bpf
|
|
45
|
+
backend enforces (kills on disallowed syscalls) and emits meta-events (verdict,
|
|
46
|
+
timeout, violation, degradation) — not a syscall stream. L4 behavioral observers
|
|
47
|
+
read subprocess stdout, not the kernel.
|
|
48
|
+
- **Does not scan LLM model weights.** It guards prompts and outputs in deployed
|
|
49
|
+
apps, not the model itself.
|
|
50
|
+
- **Does not run cluster mode in production.** Single-node only; multi-node gossip
|
|
51
|
+
is untested.
|
|
52
|
+
- **Does not have a real Postgres backend.** SQLite only.
|
|
53
|
+
- **Does not have detection-benchmark data.** The validation harness exists
|
|
54
|
+
(`picosentry scan --validate`); the rule-level precision/recall numbers have not
|
|
55
|
+
been run against a real dataset.
|
|
56
|
+
- **Does not advertise a CVE database on its own.** CVE matching uses the OSV
|
|
57
|
+
corpus (`[scan]` extra); offline-only operation pulls from the local corpus
|
|
58
|
+
snapshot.
|
|
59
|
+
|
|
60
|
+
If a feature is in `experimental.py` as Stub or Experimental, treat it as not
|
|
61
|
+
shipped.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## 30-second demo (no clone)
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install picosentry
|
|
69
|
+
picosentry scan ./your-project # any project on disk
|
|
70
|
+
picosentry scan ./package.json # or a single manifest
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
If you prefer a reproducible example, the repo ships a malicious PyPI fixture:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/KirkForge/PicoSentry.git
|
|
77
|
+
cd PicoSentry
|
|
78
|
+
picosentry scan examples/pypi-obfuscated-setup/
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Real CLI output
|
|
82
|
+
|
|
83
|
+
```text
|
|
84
|
+
$ picosentry scan examples/pypi-obfuscated-setup/
|
|
85
|
+
PICOSENTRY_CACHE_HMAC_KEY not set — cache entries will be invalidated on process restart. Set it for persistent cache integrity.
|
|
86
|
+
🦞 PicoSentry
|
|
87
|
+
Target: /home/kirk/Madlab/Clean-Live/PicoSeries/picosentry/examples/pypi-obfuscated-setup
|
|
88
|
+
Engine: v2.0.5 | Corpus: vef6b3b3115bb
|
|
89
|
+
Scan ID: 08057439b4ba08d8
|
|
90
|
+
|
|
91
|
+
Packages scanned: 0
|
|
92
|
+
Files scanned: 2
|
|
93
|
+
Duration: 20ms
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The scan above fires 5+ findings across the obfuscation, post-install, and
|
|
97
|
+
exfiltration rules. Re-run with the same inputs and the `Scan ID` and `Corpus`
|
|
98
|
+
digest will match exactly — that's the determinism guarantee.
|
|
99
|
+
|
|
100
|
+
> A complete sample output (with rule IDs and severities) for the same example is
|
|
101
|
+
> checked into the repo. The example is the reproducible fixture we use in CI.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## What it detects (a subset)
|
|
106
|
+
|
|
107
|
+
| Rule | What it catches | Example |
|
|
108
|
+
|------|----------------|---------|
|
|
109
|
+
| L2-TYPO-001 | Typosquatted package names | `reqursts` instead of `requests` |
|
|
110
|
+
| L2-DEPC-001 | Dependency confusion (private → public) | `internal-pkg` not on registry |
|
|
111
|
+
| L2-PYPI-OBFS-001 | Dynamic execution in setup.py | `exec()` / `eval()` in install scripts |
|
|
112
|
+
| L2-PYPI-OBFS-002 | Base64-decoded payloads in source | `base64.b64decode(...)` + dynamic use |
|
|
113
|
+
| L2-PYPI-OBFS-007 | Base64 decode + exec/eval combo | Decode-then-execute obfuscation chain |
|
|
114
|
+
| L2-PYPI-POST-001 | Post-install code execution | `setup.py` runs code at install time |
|
|
115
|
+
| L2-NETEX-001 | Network calls during install | `urllib.request`, `curl`, `wget` at install |
|
|
116
|
+
| L2-IOC-001 | Known IOC behavior patterns | Hardcoded C2 host, exfil URL patterns |
|
|
117
|
+
| L2-CVE-001 | Known CVEs in dependency tree | OSV-matched vulnerabilities |
|
|
118
|
+
| L2-DEP-001 | Deprecated / insecure dependency | End-of-life library versions |
|
|
119
|
+
| L2-SBOM-001 | SBOM generation | CycloneDX-compatible output |
|
|
120
|
+
| L2-LICENSE-001 | License compliance | Copyleft, unknown, deprecated licenses |
|
|
121
|
+
|
|
122
|
+
Full rule catalog: [`picosentry/scan/docs/rules/`](picosentry/scan/docs/rules/) (50 rules
|
|
123
|
+
across the supported ecosystems).
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## Feature matrix
|
|
128
|
+
|
|
129
|
+
| Feature | PicoSentry | pip-audit | osv-scanner | Trivy | Socket |
|
|
130
|
+
|---------|:---------:|:---------:|:-----------:|:-----:|:------:|
|
|
131
|
+
| Offline operation | yes | partial | partial | partial | no |
|
|
132
|
+
| Deterministic output (bit-identical runs) | yes | no | no | no | no |
|
|
133
|
+
| Malicious-behavior detection (not just CVEs) | yes | no | no | partial | partial |
|
|
134
|
+
| Multi-ecosystem (npm, PyPI, Go, Cargo, Maven, RubyGems, NuGet) | yes | partial | yes | yes | partial |
|
|
135
|
+
| Runtime sandbox enforcement (kernel-level) | beta | no | no | no | no |
|
|
136
|
+
| Runtime syscall observation from kernel | no | no | no | no | no |
|
|
137
|
+
| FOSS source available | yes (BUSL-1.1) | yes (Apache-2.0) | yes (Apache-2.0) | yes (Apache-2.0) | no |
|
|
138
|
+
|
|
139
|
+
Where PicoSentry is weaker: pip-audit and osv-scanner have wider and more frequently
|
|
140
|
+
refreshed CVE coverage via OSV. Trivy has broader container and IaC scanning. Socket
|
|
141
|
+
has hosted workflow integrations PicoSentry doesn't ship. The differentiator is the
|
|
142
|
+
combination of offline + deterministic + malicious-behavior rules in a single offline
|
|
143
|
+
binary — not raw CVE breadth.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Install
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
# Core scanner — works offline, no HTTP deps (only `pyyaml` installed)
|
|
151
|
+
pip install picosentry
|
|
152
|
+
|
|
153
|
+
# Extras
|
|
154
|
+
pip install picosentry[scan] # + online corpus management
|
|
155
|
+
pip install picosentry[serve] # + API server + dashboard
|
|
156
|
+
pip install picosentry[all] # Everything
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The default `pip install picosentry` is deliberately lightweight — it pulls in
|
|
160
|
+
only `pyyaml`, which is enough to run `picosentry scan` against any project.
|
|
161
|
+
To use the API server, dashboard, or HTTP corpus refresh, install the matching
|
|
162
|
+
extras (see [install options](#install-options) below).
|
|
163
|
+
|
|
164
|
+
### Install options
|
|
165
|
+
|
|
166
|
+
| Command | What you get |
|
|
167
|
+
|---------|-------------|
|
|
168
|
+
| `pip install picosentry` | Core: scanner, sandbox, watch (lightweight) |
|
|
169
|
+
| `pip install picosentry[scan]` | + requests for online corpus management |
|
|
170
|
+
| `pip install picosentry[serve]` | + FastAPI server, dashboard, auth, scheduler |
|
|
171
|
+
| `pip install picosentry[watch-server]` | + FastAPI + uvicorn for watch HTTP daemon |
|
|
172
|
+
| `pip install picosentry[otel]` | + OpenTelemetry tracing |
|
|
173
|
+
| `pip install picosentry[sigstore]` | + Sigstore signing support |
|
|
174
|
+
| `pip install picosentry[all]` | Everything |
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Usage
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
picosentry scan ./my-project
|
|
182
|
+
picosentry scan ./package.json # single file
|
|
183
|
+
picosentry scan --format json ./project # JSON output
|
|
184
|
+
picosentry scan --format sarif ./project # SARIF output
|
|
185
|
+
picosentry scan --format cyclonedx ./project # CycloneDX SBOM
|
|
186
|
+
picosentry scan --verify-determinism ./project # assert SHA-256 stability
|
|
187
|
+
picosentry scan --diff scan-a.json scan-b.json # compare two scans
|
|
188
|
+
picosentry scan --fail-on high ./project # exit non-zero on HIGH+
|
|
189
|
+
picosentry sandbox echo "hello" # beta — kernel-level enforcement
|
|
190
|
+
picosentry watch scan-prompt --text "..." # beta — LLM prompt guard
|
|
191
|
+
picosentry serve --port 8765 # experimental — API + dashboard
|
|
192
|
+
picosentry health
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Design principles
|
|
198
|
+
|
|
199
|
+
- **Deterministic**: same inputs + same policy = same SHA-256 output. No randomness,
|
|
200
|
+
no probabilistic scoring, no network dependence. Asserted by `--verify-determinism`.
|
|
201
|
+
- **Offline by default**: no phone-home, no remote API calls at scan time. Works in
|
|
202
|
+
air-gapped environments. Online corpus refresh is opt-in via the `[scan]` extra.
|
|
203
|
+
- **Typed**: full Python type annotations, `py.typed` shipped.
|
|
204
|
+
- **Lightweight core**: the default install pulls only `pyyaml`. Heavy deps are
|
|
205
|
+
gated behind extras.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Repository structure
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
picosentry/
|
|
213
|
+
_core/ shared primitives
|
|
214
|
+
scan/ supply-chain scanner (CLI: `picosentry scan`)
|
|
215
|
+
sandbox/ runtime kernel-sandbox (CLI: `picosentry sandbox`, beta)
|
|
216
|
+
watch/ LLM prompt/output guard (CLI: `picosentry watch`, beta)
|
|
217
|
+
serve/ API server + dashboard (CLI: `picosentry serve`, experimental)
|
|
218
|
+
experimental.py feature-maturity tracking
|
|
219
|
+
examples/
|
|
220
|
+
pypi-obfuscated-setup/ reproducible malicious PyPI fixture
|
|
221
|
+
npm-postinstall-exfil/ reproducible npm post-install fixture
|
|
222
|
+
prompt-injection/ reproducible prompt-injection fixture
|
|
223
|
+
docs/
|
|
224
|
+
rules/ per-rule documentation (see picosentry/scan/docs/rules/)
|
|
225
|
+
strategic/ design docs and architecture
|
|
226
|
+
tests/ test suite
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Where to get help
|
|
232
|
+
|
|
233
|
+
- **Bug reports / feature requests**: [GitHub Issues](https://github.com/KirkForge/PicoSentry/issues)
|
|
234
|
+
- **Security issues** (do **not** file a public issue): see [SECURITY.md](SECURITY.md) —
|
|
235
|
+
email `security@kirkforge.dev` or open a [private vulnerability report](https://github.com/KirkForge/PicoSentry/security/advisories/new).
|
|
236
|
+
- **Questions / discussion**: [GitHub Discussions](https://github.com/KirkForge/PicoSentry/discussions)
|
|
237
|
+
- **Contributing**: see [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
BUSL-1.1 — see [LICENSE](LICENSE) and [COMMERCIAL-LICENSE.md](COMMERCIAL-LICENSE.md).
|
|
@@ -36,16 +36,25 @@ logger = logging.getLogger("picodome.tracing")
|
|
|
36
36
|
|
|
37
37
|
# ─── Tracing availability check ─────────────────────────────────────────────
|
|
38
38
|
|
|
39
|
+
# `trace` is bound to the OTel module when available, or to `None` when not.
|
|
40
|
+
# Rebinding the module-level name to `None` trips mypy's `[assignment]`
|
|
41
|
+
# check, and the suppression needed for it is itself flagged as
|
|
42
|
+
# `[unused-ignore]` on newer mypy with `ignore_missing_imports = true`
|
|
43
|
+
# (since the missing-import becomes `Any` and the rebind is then safe).
|
|
44
|
+
# We use a separate sentinel to keep both versions of mypy happy without
|
|
45
|
+
# per-line ignores.
|
|
39
46
|
_TRACING_AVAILABLE = False
|
|
40
47
|
_Tracer: Any = Any # redefined below when OTel available
|
|
48
|
+
_trace_module: Any = None # the OTel `trace` module, or None if unavailable
|
|
41
49
|
|
|
42
50
|
try:
|
|
43
|
-
from opentelemetry import trace
|
|
51
|
+
from opentelemetry import trace as _otel_trace
|
|
44
52
|
|
|
45
53
|
_TRACING_AVAILABLE = True
|
|
46
|
-
_Tracer =
|
|
54
|
+
_Tracer = _otel_trace.Tracer
|
|
55
|
+
_trace_module = _otel_trace
|
|
47
56
|
except ImportError:
|
|
48
|
-
|
|
57
|
+
pass
|
|
49
58
|
|
|
50
59
|
|
|
51
60
|
# ─── No-op tracer ───────────────────────────────────────────────────────────
|
|
@@ -100,7 +109,7 @@ def get_tracer() -> _Tracer | _NoopTracer:
|
|
|
100
109
|
"""
|
|
101
110
|
global _tracer
|
|
102
111
|
if isinstance(_tracer, _NoopTracer) and _tracing_enabled and _TRACING_AVAILABLE:
|
|
103
|
-
_tracer =
|
|
112
|
+
_tracer = _trace_module.get_tracer("picodome", "0.5.0")
|
|
104
113
|
logger.info("OpenTelemetry tracing enabled with tracer: picodome")
|
|
105
114
|
return _tracer
|
|
106
115
|
|
|
@@ -41,9 +41,9 @@ The CampaignPackage base class:
|
|
|
41
41
|
|
|
42
42
|
The "named signature" fast path is the cheap, high-precision CRITICAL
|
|
43
43
|
check: if a literal string from `named_signatures` appears anywhere in
|
|
44
|
-
a project file, emit a CRITICAL finding immediately. This is
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
a project file, emit a CRITICAL finding immediately. This is the
|
|
45
|
+
single highest-ROI primitive in the campaign layer: zero expected FPs
|
|
46
|
+
because the strings are the literal names of real malware.
|
|
47
47
|
|
|
48
48
|
This module is intentionally small. The per-campaign detectors in
|
|
49
49
|
shai_hulud/, node_ipc_compromise/, etc. do the actual work.
|
|
@@ -220,8 +220,7 @@ class CampaignPackage:
|
|
|
220
220
|
"""CRITICAL fast path: literal-string match across project files.
|
|
221
221
|
|
|
222
222
|
If any file content contains a string from `named_signatures`,
|
|
223
|
-
emit a CRITICAL finding for that file. This is
|
|
224
|
-
npm-scan's NAMED_SIGNATURES first-line check and is the
|
|
223
|
+
emit a CRITICAL finding for that file. This is the
|
|
225
224
|
highest-precision rule in the entire system: zero expected FPs
|
|
226
225
|
because the strings are the literal names of real malware.
|
|
227
226
|
"""
|
|
@@ -97,7 +97,13 @@ class CorpusSource:
|
|
|
97
97
|
if not self.reviewed_at:
|
|
98
98
|
return True
|
|
99
99
|
try:
|
|
100
|
-
|
|
100
|
+
reviewed_at = self.reviewed_at
|
|
101
|
+
# Python 3.10's `datetime.fromisoformat` does not accept the `Z`
|
|
102
|
+
# suffix (added in 3.11). Normalize so we get consistent behavior
|
|
103
|
+
# across the 3.10/3.11/3.12/3.13 matrix in CI.
|
|
104
|
+
if reviewed_at.endswith("Z"):
|
|
105
|
+
reviewed_at = reviewed_at[:-1] + "+00:00"
|
|
106
|
+
reviewed = datetime.fromisoformat(reviewed_at)
|
|
101
107
|
age = (datetime.now(timezone.utc) - reviewed.astimezone(timezone.utc)).days
|
|
102
108
|
return age > max_age_days
|
|
103
109
|
except (ValueError, TypeError):
|