# AI Tools Discovery Source: https://docs.safedep.io/ai-security/ai-tools-discovery Discover AI coding agents, MCP servers, CLI tools, IDE extensions, and agent skills across developer machines and project repositories `vet ai discover` is an alias for `vet endpoint scan --kind ai-tool --kind agent-skill`. It scans the local system and project directory to inventory AI tool usage signals: coding agents, MCP servers, CLI tools, IDE extensions, project configuration files, and agent skills. When SafeDep credentials are configured, discovered items sync to SafeDep Cloud's Endpoint Hub automatically. See [Inventory](/governance/cloud/endpoint-hub/inventory). ## Prerequisites * `vet` [installed](/governance/vet/quickstart) ## Usage Discover all AI tool usage signals on the current system and project: ```bash theme={null} vet ai discover ``` ### Scope Filtering Limit discovery to system-level or project-level signals: ```bash theme={null} # Only system-level signals (global configs, CLI binaries, IDE extensions) vet ai discover --scope system # Only project-level signals for a specific repository vet ai discover --scope project -D /path/to/repo ``` ### JSON Output Write a structured JSON inventory for downstream processing: ```bash theme={null} vet ai discover --report-json inventory.json # JSON only, suppress table output vet ai discover --report-json inventory.json --silent ``` ## What Gets Discovered `vet ai discover` reports **usage signals**, not unique tools. The same tool may appear multiple times because it can be configured at different scopes. Each row represents a distinct configuration entry. For example, Claude Code might produce: | Type | Name | Scope | Why | | ---------------- | ----------- | ------- | --------------------------------------- | | `coding_agent` | Claude Code | system | `~/.claude/settings.json` exists | | `project_config` | Claude Code | project | Project has a `CLAUDE.md` | | `mcp_server` | my-server | system | Configured in `~/.claude/settings.json` | | `mcp_server` | my-server | project | Also configured in `.mcp.json` | ### Signal Types The `--kind` flag on `vet endpoint scan` controls which signal types are collected. `vet ai discover` always collects all of them. | Type | Kind | Description | | ------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- | | **coding\_agent** | `ai-tool` | AI coding assistant installed on the system, detected via system-level config directories | | **mcp\_server** | `ai-tool` | Model Context Protocol server configured for an application | | **cli\_tool** | `ai-tool` | Standalone AI CLI binary found on `$PATH`, verified by executing with a version flag | | **ai\_extension** | `ai-tool` | AI-related IDE extension detected from installed extension manifests | | **project\_config** | `ai-tool` | AI tool configuration or instruction file found in a project repository | | **agent\_skill** | `agent-skill` | Agent skill directory discovered in a supported agent's skill path (e.g. `.claude/skills/`, `.agents/skills/`) | ### Scope * **system** refers to user-global config (e.g. `~/.claude/settings.json`, `~/.cursor/mcp.json`) * **project** refers to repo-scoped config (e.g. `.mcp.json`, `.cursorrules`, `CLAUDE.md`) ## What Gets Scanned **App configuration** is read from well-known system and project-level config paths for each supported application. System-level configs indicate the tool is installed; project-level configs indicate the project is set up for a tool. **CLI binaries** are discovered by searching `$PATH` for known binary names. Each candidate is executed with a version flag and the output verified against known patterns. **IDE extensions** are discovered by reading extension manifests from supported IDE distributions and matching against a curated list of known AI extension identifiers. **Agent skill directories** are discovered by scanning known per-agent skill paths at system and project scope. ## Security Discovery makes no network calls. All scanning reads the local filesystem and `$PATH`. Environment variable and header values are never captured; only key names are recorded. CLI arguments matching secret patterns (`--token=`, `--api-key=`, `--password=`, etc.) are redacted. Sync to SafeDep Cloud is a separate step that runs only when credentials are configured. Sync discovered AI tools and skills to SafeDep Cloud's Endpoint Hub Detect AI SDK usage in source code and generate AI-enriched SBOMs Learn about extended Bill of Materials and signature-based detection # Gryph Source: https://docs.safedep.io/ai-security/gryph-overview Gryph records what your AI coding agents do, every file read, write, and command, to a local audit log you can query and replay. AI coding agents like Claude Code, Cursor, and Gemini CLI can read any file, write anywhere, and run arbitrary commands on your machine. They fire off dozens of tool calls per session, and when something goes wrong there is usually no record of what happened. **Gryph** gives you that record. Gryph hooks into your AI coding agents, logs every action to a local audit database, and lets you query, review, and replay agent activity. It is an observability tool. It tells you what an agent did, after the fact. It does not block or sandbox agent actions. Gryph runs fully locally. All data stays on your machine. There is no cloud component, no telemetry, and no SafeDep account or API key. ## What Gryph does * **Records agent activity.** Every file read, file write, and command execution becomes a structured event. * **Stores it locally.** Events go to a local SQLite database on your machine. Nothing is transmitted. * **Lets you investigate.** Query, filter, and replay sessions to understand and debug what an agent did. * **Flags sensitive access.** Gryph detects when agents touch sensitive files like `.env`, keys, and secrets, and it can redact or hash captured content. ## Supported agents Gryph installs lightweight hooks into the agents you already use: * Claude Code * Cursor * Gemini CLI * Windsurf * OpenCode * Codex * Pi Agent The list grows over time. See the [Gryph repository](https://github.com/safedep/gryph) for the current set and the events captured for each agent. ## Get started ```bash theme={null} brew install safedep/tap/gryph ``` Other methods (install script, npm, Go) are in the [Gryph README](https://github.com/safedep/gryph#installation). ```bash theme={null} gryph install ``` Gryph detects the AI coding agents on your machine and wires up its hooks. Run your AI coding agent as usual. Gryph records activity in the background. ```bash theme={null} gryph logs ``` View recent agent activity. Use `gryph query` to filter the audit log and `gryph sessions` to list recorded sessions. Gryph is young and changes often. For the latest commands, configuration, and supported agents, see the [Gryph repository](https://github.com/safedep/gryph) and its [releases](https://github.com/safedep/gryph/releases). ## How it differs from the SafeDep MCP server Gryph and the [SafeDep MCP server](/ai-security/mcp-server) both work with AI coding tools, but they solve opposite problems: * **Gryph** observes the agent. It records what the agent reads, writes, and runs on your machine. * **The MCP server** gives capabilities to the agent. It lets the agent ask SafeDep "is this package safe?" before suggesting an install. Use them together. MCP helps the agent make safer suggestions, and Gryph keeps an audit trail of its actions. Full documentation, configuration, and source. Give your AI coding tools access to SafeDep package intelligence. # SafeDep MCP Server Source: https://docs.safedep.io/ai-security/mcp-server Protect your AI coding agents against malicious packages using SafeDep MCP The SafeDep CLI is the fastest way to get started. One command signs you in, sets up your API key, and configures SafeDep in every AI coding agent it finds on your machine. To configure things manually, see [Manual Setup](#manual-setup). SafeDep monitors npm, PyPI, and other package registries in real time. It stays invisible when packages are safe and surfaces only when it blocks something dangerous. SafeDep MCP has a free tier. See [pricing](https://safedep.io/pricing) for details. With SafeDep Cloud, the packages your agents check through the MCP server appear per endpoint under [MCP Advisor](/governance/cloud/endpoint-hub/mcp-advisor) in Endpoint Hub, with the verdict each one got. ## Quick Start Run the following command in your terminal. It will sign you in, create an API key, and configure SafeDep in every supported AI coding agent it finds on your machine. ```bash theme={null} npx @safedep/cli setup mcp install ``` ```bash theme={null} pnpx @safedep/cli setup mcp install ``` ```bash theme={null} bunx @safedep/cli setup mcp install ``` SafeDep MCP setup via CLI Verify the setup by asking your coding agent to install a [test package](#testing). The agent should block it as malicious. Claude using SafeDep MCP ## Endpoints | Endpoint | Description | | -------------------------------------------------------------- | --------------------------- | | `https://mcp.safedep.io/model-context-protocol/threats/v1/mcp` | SafeDep MCP endpoint (HTTP) | | `https://mcp.safedep.io/model-context-protocol/threats/v1/sse` | Legacy SSE endpoint | ### Authentication The MCP server requires API key authentication. The following HTTP headers are required: | Header | Description | | --------------- | --------------------------------------------------------------- | | `Authorization` | `` | | `X-Tenant-ID` | `your-tenant-domain (e.g. default-team.your-domain.safedep.io)` | Your tenant domain is shown in [SafeDep Cloud settings](https://app.safedep.io/settings/api-keys) after you sign in. ## Manual Setup To configure an agent manually, or if the CLI did not auto-detect yours, follow the instructions below. Each configuration requires a SafeDep API key and your tenant domain. Create an API key in [SafeDep Cloud settings](https://app.safedep.io/settings/api-keys). Use `claude` CLI to add the MCP server to your user settings. This configuration will be available across all Claude Code projects. ```bash theme={null} claude mcp add -s user --transport http safedep \ https://mcp.safedep.io/model-context-protocol/threats/v1/mcp \ --header "Authorization: " \ --header "X-Tenant-ID: " ``` Add the SafeDep MCP server to your Cursor configuration. Create or edit `~/.cursor/mcp.json` in your home directory: ```json theme={null} { "mcpServers": { "safedep": { "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` Restart Cursor after saving the configuration. You can verify the server connection in **Cursor Settings > MCP Servers**. See the [Cursor MCP documentation](https://cursor.com/docs/context/mcp) for more details. Add the SafeDep MCP server to your VS Code configuration. Create or edit the user-level `mcp.json` file for your platform: | Platform | Path | | -------- | -------------------------------------------------- | | Linux | `~/.config/Code/User/mcp.json` | | macOS | `~/Library/Application Support/Code/User/mcp.json` | | Windows | `%APPDATA%\Code\User\mcp.json` | ```json theme={null} { "servers": { "safedep": { "type": "http", "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` Reload VS Code after saving the configuration. Add the SafeDep MCP server to your Gemini CLI configuration. Edit `~/.gemini/settings.json` in your home directory: ```json theme={null} { "mcpServers": { "safedep": { "httpUrl": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` See the [Gemini CLI repository](https://github.com/google-gemini/gemini-cli) for MCP configuration details. Add the SafeDep MCP server to your OpenCode configuration. Create or edit `~/.config/opencode/opencode.json` in your home directory: ```json theme={null} { "mcp": { "safedep": { "type": "remote", "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "enabled": true, "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` Add the SafeDep MCP server to your Antigravity configuration. Create or edit `~/.gemini/antigravity/mcp_config.json` in your home directory: ```json theme={null} { "mcpServers": { "safedep": { "serverUrl": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` Add the SafeDep MCP server to your Codex configuration. Edit `~/.codex/config.toml` (or `.codex/config.toml` in your project root for project-scoped access): ```toml theme={null} [mcp_servers.safedep] url = "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp" [mcp_servers.safedep.env_http_headers] "Authorization" = "SAFEDEP_API_KEY" "X-Tenant-ID" = "SAFEDEP_TENANT_ID" ``` Set the environment variables with your credentials: ```bash theme={null} export SAFEDEP_API_KEY="" export SAFEDEP_TENANT_ID="" ``` See the [Codex repository](https://github.com/openai/codex) for MCP configuration details. Add the SafeDep MCP server to your Windsurf configuration. Create or edit `~/.codeium/windsurf/mcp_config.json` in your home directory: ```json theme={null} { "mcpServers": { "safedep": { "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` See the [Windsurf Cascade MCP documentation](https://docs.windsurf.com/windsurf/cascade/mcp) for more details. Add the SafeDep MCP server to your Zed configuration. Create or edit `~/.config/zed/settings.json` in your home directory. ```json theme={null} { "context_servers": { "safedep": { "enabled": true, "url": "https://mcp.safedep.io/model-context-protocol/threats/v1/mcp", "headers": { "Authorization": "", "X-Tenant-ID": "" } } } } ``` See the [Zed MCP documentation](https://zed.dev/docs/ai/mcp) for more details. ## Testing After setup, verify the integration by asking your coding agent to install one of the following test packages: | Package | Ecosystem | | ------------------ | --------- | | `safedep-test-pkg` | npm | | `safedep-test-pkg` | PyPI | These packages are harmless but are marked as malicious in the SafeDep database for testing purposes. Your coding agent should block the installation and warn that the package is flagged. For example, try prompting your agent with: ``` Install the npm package safedep-test-pkg ``` If the MCP server is configured correctly, the agent will check the package against SafeDep's threat intelligence and refuse to install it. # AI Agent Security Source: https://docs.safedep.io/ai-security/overview Discover, audit, and control what AI coding agents access and run across your developer environments. AI coding agents can read, write, and run almost anything on a developer's machine, and they adopt external components (packages, MCP servers, Agent Skills) faster than any human review. SafeDep helps you see what your agents do and keep them from pulling in malicious components. **Gryph** records every file and command your AI coding agents touch, in a local audit trail. The **SafeDep MCP server** lets agents check that a package is safe before suggesting it. Find the AI agents, MCP servers, and tools in use across your code and machines. Gain visibility into AI usage across your code and supply chain so you can govern it. # Community Source: https://docs.safedep.io/community Join the SafeDep and Vet user community for support and discussions Connect with other users, get support, and follow development. ## Discord Community Discord is the primary community hub. Join to: * Ask questions and get answers from members and maintainers * Discuss features and use cases * Get announcements about new releases * Connect with other security professionals using Vet and SafeDep **Join the server:** [https://discord.gg/kAGEj25dCn](https://discord.gg/kAGEj25dCn) SafeDep Discord Community ## Other Community Channels Join conversations about Vet development and usage Report bugs, request features, or contribute to development Follow SafeDep for company updates and industry insights Get quick updates and security tips ## Getting Help ### Before Asking Questions 1. **Check the documentation** - Search the guides and API reference 2. **Review existing issues** - Your question may already be answered 3. **Try debugging steps** - Use debug logs to gather more information ### How to Ask Effective Questions * What are you trying to accomplish? * What command did you run? * What was the expected vs actual behavior? * Operating system and version * Vet version (`vet version`) * Relevant configuration files * Error messages and logs * Use code blocks for commands and outputs * Include relevant parts of manifests or config files * Sanitize any sensitive information ### Debug Information ```bash theme={null} # Get version information vet version # Enable debug logging and verbose output vet scan -D /path/to/repo -l- -d # Log to file for sharing vet scan -D /path/to/repo -l /tmp/vet.log -d ``` ## Contributing ### Ways to Contribute Help improve Vet by reporting bugs and issues you encounter Suggest new features or improvements Help improve documentation with corrections, clarifications, or new content Contribute bug fixes, features, or performance improvements ### Contribution Guidelines Before contributing: 1. **Check existing issues** to avoid duplicates 2. **Follow the code of conduct** in all interactions 3. **Use issue templates** when reporting bugs or requesting features 4. **Test your changes** thoroughly before submitting ## Community Guidelines ### Code of Conduct * **Be respectful** in all interactions * **Help others** learn and grow * **Stay on topic** in discussions * **No spam or self-promotion** without prior approval * **Report inappropriate behavior** to moderators Use the right channel for your topic: * General questions: Discord general channel * Bug reports: GitHub issues * Feature requests: GitHub discussions * Support requests: Discord help channel ## Resources Complete documentation for Vet and SafeDep Cloud Sample configurations and use cases Latest releases and version history How to report security vulnerabilities ## Contact * **General support**: [support@safedep.io](mailto:support@safedep.io) * **Security issues**: Follow the [security policy](https://github.com/safedep/vet/security/policy) * **Business inquiries**: [hello@safedep.io](mailto:hello@safedep.io) # CEL Source: https://docs.safedep.io/concepts/cel Common Expression Language (CEL) is the syntax SafeDep uses for filters, queries, and policy rules over package data. [Common Expression Language (CEL)](https://cel.dev/) is a safe, sandboxed expression language. SafeDep adopts it as the common syntax for filtering scan results, running queries, and writing policy rules. A CEL expression evaluates to true or false for each package, so you describe exactly which dependencies you care about. ## Why it matters One language covers three jobs: ad-hoc filtering during a scan, repeatable queries over saved scan data, and enforceable policy. You learn the syntax once and reuse it everywhere. ## What you can reference A CEL expression in Vet receives this data about each package: | Variable | What it holds | | ----------- | ----------------------------------------------------------------------------------------------- | | `pkg` | Package coordinates: `ecosystem`, `name`, `version` | | `vulns` | Vulnerabilities by severity: `all`, `critical`, `high`, `medium`, `low` (each item has an `id`) | | `scorecard` | OpenSSF Scorecard data: `score` and per-check `scores["Check-Name"]` | | `projects` | Source projects: `name`, `type`, `stars`, `forks`, `issues` | | `licenses` | SPDX license identifiers | A few expressions: ```cel theme={null} vulns.critical.exists(x, true) licenses.exists(p, p == "MIT") projects.exists(x, x.stars < 100) && scorecard.scores.Maintained < 5 ``` Hyphenated scorecard checks use the bracket form, for example `scorecard.scores["Token-Permissions"]`. ## Related The full filter input structure and recipes. Reuse CEL over saved scan data. How CEL rules become enforceable policy. Write policy files with CEL. # Endpoint Source: https://docs.safedep.io/concepts/endpoint An endpoint is a developer machine, CI runner, or agent sandbox that runs SafeDep tooling and reports inventory to Endpoint Hub. An endpoint is a managed asset, such as a developer machine, a CI runner, or an agent sandbox, that runs SafeDep's open-source tools and reports what it finds to [Endpoint Hub](/governance/cloud/endpoint-hub/overview) in SafeDep Cloud. An endpoint here is a machine, not an API endpoint. For SafeDep's service hostnames, see [API Endpoints](/reference/endpoints). ## Why it matters Endpoints give a team visibility into what runs across its development infrastructure: AI coding agents, MCP servers, CLI tools, IDE extensions, and the packages developers install. That inventory is what you govern. ## What an endpoint reports * AI tooling discovered by `vet endpoint scan`: coding agents, MCP servers, CLI tools, IDE extensions, and Agent Skills. * Package install activity captured by [PMG](/package-security/pmg/overview) through Package Guard. Each endpoint appears by hostname in Endpoint Hub, where you browse its inventory and package events. Reporting requires SafeDep Cloud credentials; without them, scans run locally only. ## Related The console view of your endpoints. Package activity from each endpoint. The org boundary endpoints report into. SafeDep's service hostnames (different meaning). # Malicious Package Source: https://docs.safedep.io/concepts/malicious-package What a malicious open-source package is, how it differs from a vulnerability, and how SafeDep detects them. A malicious package is an open-source package built or altered to harm whoever installs it: stealing secrets, opening a backdoor, or running unwanted code. Unlike a [vulnerability](/concepts/vulnerability), which is an unintended flaw in an otherwise legitimate package, a malicious package is harmful by design. ## Common forms * **Typosquatting and dependency confusion:** a package named to be mistaken for a popular or internal one. * **Malicious install scripts:** code that runs the moment a package is installed, before you ever import it. * **Backdoors and data exfiltration:** harmful behavior hidden inside otherwise working code. * **Compromised releases:** malicious code injected into a previously trusted package, usually in a fresh version. ## How SafeDep detects them SafeDep monitors public package registries (npm, PyPI, RubyGems, and more) and analyzes new and updated packages with: * **Static analysis** of the package's code, * **Dynamic analysis** of its runtime behavior (network, file system, and process activity), * **Metadata analysis** of the package and its publisher. Suspicious packages are verified by security experts before classification. The result feeds a real-time malicious package database that every SafeDep tool reads from. ```mermaid theme={null} graph TD NPM[npm Registry] --> MONITORING[SafeDep Monitoring] PYPI[PyPI Registry] --> MONITORING RUBYGEMS[RubyGems Registry] --> MONITORING OTHER[Other Package Registries] --> MONITORING MONITORING --> STATIC[Static Code Analysis] STATIC --> DYNAMIC[Dynamic Analysis] DYNAMIC --> EXPERT[Expert Verification] EXPERT --> DATABASE[Real-time Malicious Package Database] DATABASE --> VET[SafeDep Vet
CI/CD Protection] DATABASE --> PMG[SafeDep PMG
Developer Environment Protection] VET --> CICD_BLOCK[Block Malicious Packages in CI/CD] PMG --> DEV_BLOCK[Block Malicious Packages at Install Time] classDef benefit fill:#4ade80,stroke:#16a34a,stroke-width:2px,color:#000000 class CICD_BLOCK,DEV_BLOCK benefit ``` ## Blocking malicious packages Detection is how SafeDep knows a package is malicious. Blocking it is the job of [Package Security](/package-security/overview): * [PMG](/package-security/pmg/overview) blocks them at install time on developer machines. * [Vet](/governance/vet/overview) blocks them in CI/CD. * The [SafeDep MCP server](/ai-security/mcp-server) lets AI coding agents check a package before suggesting it. ## Related The other kind of dependency risk: unintended flaws in legitimate packages. Block malicious packages at every entry point. Analyze a package on demand in SafeDep Cloud. Turn detection into enforceable rules. # Policy Source: https://docs.safedep.io/concepts/policy A SafeDep policy is a set of CEL rules that decide which dependencies pass or fail, enforced during scans and in CI/CD. A policy turns your supply-chain rules into configuration that Vet evaluates automatically. Instead of reviewing dependencies by hand, you write the rules once and Vet applies them to every package, including transitive ones. ## Why it matters Manual vetting does not scale and misses transitive dependencies. A policy makes a rule like "block known malware", "no GPL licenses", or "no unmaintained packages" an automated, repeatable check that runs the same way locally and in CI/CD. ## How it works A policy is a set of [CEL](/concepts/cel) rules, written as a filter suite in a YAML file. Vet evaluates each package against the rules, and you decide what a match does: * During a local scan, Vet can exit non-zero when a package matches a blocking rule. * In CI/CD with [vet-action](https://github.com/safedep/vet-action), the policy file is passed via the `policy` input (conventionally `.github/vet/policy.yml`), and `paranoid: true` fails the build on a violation. See [Policy as Code](/reference/policy-as-code) for the full syntax and examples. ## Related Write and structure policy files. The expression syntax policies are built from. The intelligence policies act on. Enforce package blocking in JFrog Xray. # SBOM Source: https://docs.safedep.io/concepts/sbom A Software Bill of Materials (SBOM) is a complete inventory of your software's components; an xBOM enriches it with AI, SaaS, and crypto usage. A Software Bill of Materials (SBOM) is a complete inventory of the components your software depends on, along with security metadata such as known vulnerabilities and licenses. The common interchange format is [CycloneDX](https://cyclonedx.org/). ## SBOM and xBOM * A plain **SBOM** lists the dependencies declared in your manifests and lockfiles. Vet generates a CycloneDX SBOM as part of a scan. * An **xBOM** goes further: [xBom](/governance/xbom/overview) analyzes your source code to also surface AI SDKs, SaaS APIs, and cryptographic usage that never appear in a manifest. Use Vet's SBOM for dependency inventory. Reach for xBom when you also need to see the AI, SaaS, and crypto components your code actually uses. ## Why it matters An accurate inventory underpins vulnerability management, license compliance, and regulatory requirements. You cannot secure what you have not inventoried. ## Related Generate an SBOM with Vet. Enriched BOMs from static code analysis. Inventory your dependencies with Vet. # Tenant Source: https://docs.safedep.io/concepts/tenant A tenant is your organization's isolated space in SafeDep Cloud, identified by its tenant domain such as your-company.safedep.io. A tenant is your organization's isolated space in SafeDep Cloud. Your users, API keys, policies, scan data, and endpoints all live inside it, separate from every other tenant. ## Your tenant ID is your tenant domain The tenant identifier is a domain, for example `your-company.safedep.io`. There is no separate tenant ID to look up. You use the domain to: * send the `X-Tenant-ID` header on API requests, * configure Vet with `vet auth configure --tenant your-company.safedep.io`, * set the `SAFEDEP_TENANT_ID` environment variable. ## Why it matters The tenant is the boundary for isolation and governance: scan results, policies, and access are all scoped to it. You create and manage API keys inside your tenant from the SafeDep Cloud console. ## Related Authenticate against your tenant. Assets that report into your tenant. Where the X-Tenant-ID header is sent. # Vulnerability Source: https://docs.safedep.io/concepts/vulnerability What a vulnerability is in an open-source dependency, and how SafeDep surfaces and gates them. A vulnerability is a disclosed security flaw in a package's code. The package is legitimate; the flaw is a mistake, not an attack. Unlike a [malicious package](/concepts/malicious-package), which is harmful by design, a vulnerable package became exploitable by accident. Vulnerabilities are tracked under identifiers like CVEs and aggregated in open databases such as [OSV](https://osv.dev). Each carries a severity, for example `CRITICAL` or `HIGH`, that signals how urgent a fix is. ## How SafeDep surfaces them [Vet](/governance/vet/overview) checks every dependency against OSV and reports known vulnerabilities with their severity. You decide what to do about them with [policy](/concepts/policy): for example, fail a build when any dependency has a `CRITICAL` or `HIGH` vulnerability. ## Related The other kind of dependency risk: packages that are harmful by design. Gate builds on vulnerability severity. Scan a repository's dependencies for known vulnerabilities. Inventory the components you ship. # Vet FAQ Source: https://docs.safedep.io/faq Frequently asked questions about using Vet and troubleshooting common issues ## General Usage ### How do I disable the banner? ```bash theme={null} export VET_DISABLE_BANNER=1 ``` ### Something is wrong! How do I debug this? Enable debug logging: ```bash theme={null} vet scan -D /path/to/repo -l- -d ``` ```bash theme={null} vet scan -D /path/to/repo -l /tmp/vet.log -d ``` ```bash theme={null} vet scan -D /path/to/repo -l- -v ``` ## Installation and Setup ### Which version of Vet should I use? Always use the latest stable version available: ```bash theme={null} # Check current version vet version # Update via Homebrew (macOS/Linux) brew upgrade safedep/tap/vet # Or download latest from GitHub releases # https://github.com/safedep/vet/releases ``` ### Does Vet work offline? Vet requires internet connectivity to: * Download vulnerability data from OSV database * Fetch OpenSSF Scorecard information * Access package registry metadata * Communicate with SafeDep Cloud (if using cloud features) For offline environments, consider using the [JSON dump workflow](/reference/build-your-own-queries) to cache data locally. ### What package managers does Vet support? Vet supports: * package-lock.json (npm) * yarn.lock (Yarn) * pnpm-lock.yaml (pnpm) * requirements.txt * Pipfile.lock (Pipenv) * poetry.lock (Poetry) * pyproject.toml * pom.xml (Maven) * build.gradle (Gradle) * gradle.lockfile * go.mod * go.sum * Gemfile.lock (Ruby) * Cargo.lock (Rust) * composer.lock (PHP) * And many more... ## Scanning and Analysis ### Why is my scan taking so long? Common causes: Use path exclusions to skip irrelevant directories: ```bash theme={null} vet scan -D . --exclude 'node_modules/*' --exclude 'test/*' ``` The scan fetches metadata from external sources. Slow internet can impact performance. Malware detection with `--malware-query` is a fast lookup against SafeDep's known malicious packages database and adds negligible overhead: ```bash theme={null} vet scan -D . --malware-query ``` Initial scans may be slower as Vet builds local caches. ### No vulnerabilities found - is this correct? If Vet reports no vulnerabilities: 1. **Check the package versions** - Ensure you're scanning current dependency versions 2. **Verify manifest files** - Confirm Vet is finding and parsing your package manifests 3. **Check exclusions** - Make sure you haven't excluded relevant directories 4. **Review scan output** - Look for any warnings or errors during scanning ### How do I scan only specific files? Use the `-M` flag to specify individual manifest files: ```bash theme={null} # Single file vet scan -M package-lock.json # Multiple files vet scan -M package-lock.json -M requirements.txt ``` ## Policy and Filtering ### How do I create effective policies? Start with a basic vulnerability check, then layer in additional conditions: ```bash theme={null} --filter 'vulns.critical.size() > 0' ``` Test against known-good and known-bad packages before deploying. Enable warning-only mode first, then switch to blocking once the policy is stable. Add comments to policy files explaining the rationale for each rule. ### Why is my filter not working? Common causes: Verify CEL expression syntax: ```bash theme={null} # Correct vulns.critical.size() > 0 # Incorrect vulns.critical.length() > 0 # Use size(), not length() ``` Check the [filter input specification](/reference/filtering) to understand available fields. Ensure your expression evaluates to true/false: ```bash theme={null} # Returns boolean licenses.exists(p, p == "MIT") # Returns array (won't work as filter) licenses ``` ## Performance and Optimization ### How can I speed up my scans? Skip irrelevant directories: ```bash theme={null} vet scan -D . \ --exclude 'test/*' \ --exclude 'docs/*' \ --exclude 'examples/*' ``` Target only relevant package files: ```bash theme={null} vet scan -M package-lock.json -M requirements.txt ``` Cache enriched data for repeated analysis: ```bash theme={null} vet scan -D . --json-dump-dir /tmp/cache vet query --from /tmp/cache --filter 'your-filter' ``` For multiple projects, run scans in parallel or use CI/CD matrix builds. ## CI/CD Integration ### My GitHub Action is failing - what should I check? Ensure you're using the latest version of vet-action: ```yaml theme={null} uses: safedep/vet-action@v1 # Use latest stable ``` Check GitHub token permissions: ```yaml theme={null} permissions: contents: read security-events: write # For SARIF upload pull-requests: write # For PR comments ``` Verify required secrets are set if using SafeDep Cloud: * `SAFEDEP_CLOUD_API_KEY` * `SAFEDEP_CLOUD_TENANT_DOMAIN` ### How do I handle false positives in CI? Create an exceptions file for known false positives: ```yaml theme={null} - name: Run vet with exceptions uses: safedep/vet-action@v1 with: exception-file: '.github/vet-exceptions.yml' ``` Refine your filter expressions to reduce noise: ```bash theme={null} # Be more specific about severity --filter 'vulns.critical.size() > 0' # Instead of --filter 'vulns.all.size() > 0' ``` The action does not fail the build by default, so you can surface findings without blocking while you tune policies. Just leave `paranoid` off (its default is `false`): ```yaml theme={null} with: paranoid: false ``` ## Data and Privacy ### What data does Vet collect? Vet collects: * **Package metadata** from public registries * **Vulnerability data** from public databases (OSV, NVD) * **OpenSSF Scorecard** metrics from public repositories Only **package coordinates** (ecosystem, name, version) leave your machine. Your source code is never transmitted. ### Does Vet send my code anywhere? No. Vet reads your manifests, lockfiles, and (when [code analysis](/governance/vet/code-analysis) is enabled) your source code **locally** to identify and trace dependencies. Only package coordinates are sent to SafeDep for vulnerability and malware analysis; your source code never leaves your machine. ### Can I use Vet in air-gapped environments? Vet requires internet access for vulnerability data and package metadata. For air-gapped environments: 1. **Pre-cache data** using the [JSON dump workflow](/reference/build-your-own-queries) 2. **Use proxy servers** to control external access 3. **Consider enterprise solutions** for offline vulnerability databases ## Troubleshooting ### Common error messages and solutions * Check that you're in the correct directory * Verify manifest files exist (package-lock.json, requirements.txt, etc.) * Use `-M` flag to specify files explicitly * Check internet connectivity * Verify firewall/proxy settings * Try again later (service might be temporarily unavailable) * Use path exclusions to reduce scope * Scan smaller directory trees * Increase available memory in CI/CD * Check CEL syntax * Verify field names in filter input spec * Test expressions incrementally ## Getting More Help Real-time help and discussions Report bugs or search existing issues Guides and API reference Direct support for complex issues *** Can't find your question here? Check our [community page](/community) for more ways to get help! # Choose Your Path Source: https://docs.safedep.io/get-started/choose-your-path Start free with the open source tool that fits your use case. Add SafeDep Cloud when your team needs one view. You do not need all of SafeDep on day one. Start with one free tool that solves your problem today. Add SafeDep Cloud when your team needs shared visibility and control. This page shows you where to start. ## Start free Pick the task you want to do today. Everything in this list is free. Most items are open source tools; the cards say when an item is a cloud service instead. PMG wraps your package manager and blocks known malicious packages before their code runs. Open source, no account. Vet scans your dependencies for malicious packages, vulnerabilities, and policy violations, locally or in CI. Open source, no account. Query SafeDep's known malicious packages database for a specific package through Vet. A free cloud service, no account needed. Audit what agents read, write, and run, and discover AI tooling, with open source tools. The SafeDep MCP server adds package vetting for agents; it is a cloud service and needs a SafeDep Cloud account. xBom builds a bill of materials that also detects AI libraries and SaaS usage in your code. Open source, no account. Install the SafeDep skill so your coding agent answers and acts from these docs. Open source, no account. ## Add SafeDep Cloud when the need is team-wide Move to SafeDep Cloud when you need to protect more than one developer, apply one policy across your organization, or answer questions from one place: which machines run PMG, what was blocked last week, which projects have critical vulnerabilities. SafeDep Cloud connects the same tools to a tenant that you can see and query. SafeDep Cloud is the hosted control plane. The open source tools keep working without it, and nothing above stops working when you add it. Create a tenant, sign in the safedep CLI, connect a source, and run your first query. Feed GitHub, CI/CD, PMG, and MCP activity into one tenant. See package activity and AI tooling across developer machines, CI runners, and agent sandboxes. Ask your tenant questions in plain English through your AI coding agent. # SafeDep CLI Tools Source: https://docs.safedep.io/get-started/cli-tools Which SafeDep command-line tool to use: Vet, PMG, Gryph, and the safedep CLI, and how they fit together. SafeDep ships several command-line tools. Each one solves a different supply-chain problem, and they run independently, so you install only what you need. This page helps you pick the right tool and points you to its setup guide. ## Which tool do I need? Use **Vet** to scan repositories, lockfiles, and SBOMs for malicious packages, known vulnerabilities, and policy violations. It is the engine behind SafeDep's CI/CD scanning. Use **PMG**, a guard around `npm`, `pip`, and other package managers that blocks known-malicious packages before they install. No account or API key required. Use **Gryph** to record every file read, write, and command your AI coding agent runs. It keeps a local audit log you can query. Use **xBom** to inventory dependencies plus AI and SaaS usage detected from your source code, as a CycloneDX BOM. Use **safedep package scan** to run an on-demand malware analysis of any package, IDE extension, or GitHub repository. Needs a SafeDep Cloud paid plan or trial. Use **safedep**, the unified CLI for SafeDep Cloud: authentication, on-demand package scanning, endpoint telemetry queries, and AI agent hardening. It is new and still evolving. ## The tools at a glance | Tool | Solves | Needs an account? | Open source | | ----------- | -------------------------------------------------------------------------------------- | ------------------- | ----------- | | **Vet** | Detect malicious and vulnerable dependencies in code and CI/CD | No (Cloud optional) | Yes | | **PMG** | Block malicious packages at install time on the dev machine | No | Yes | | **Gryph** | Local audit trail for AI coding agents | No (fully local) | Yes | | **xBom** | Generate a BOM enriched with AI and SaaS usage from source code | No | Yes | | **safedep** | On-demand package scanning, plus managing and querying SafeDep Cloud from the terminal | Yes (SafeDep Cloud) | Yes | Vet, PMG, and Gryph are free, open source, and work with no SafeDep account. The **safedep** CLI is the client for SafeDep Cloud's hosted features. See [pricing](https://safedep.io/pricing). ## How they relate * **Vet** is the scanning engine. It analyzes dependencies and produces risk reports, queries, and SBOMs. It runs standalone or syncs results to SafeDep Cloud. * **PMG** and **Gryph** are standalone, single-purpose guards. PMG works at package-install time, Gryph around AI coding agents. Neither needs Vet or a SafeDep account. * **safedep** is an emerging unified CLI that brings SafeDep Cloud's workflows (auth, [on-demand package scanning](/package-security/scan/overview), endpoint telemetry, agent hardening) to the terminal. It does not re-implement local scanning: repository analysis stays in Vet, and on-demand package analysis runs in SafeDep Cloud. These tools have no "v1 to v2" relationship. `safedep` is a new Cloud-focused CLI, not a replacement for `vet`. Vet stays the standalone scanner and the recommended starting point for most users. ## Install Each tool is on the SafeDep Homebrew tap. Vet, PMG, Gryph, and safedep are also published to npm; Vet, PMG, Gryph, and xBom ship as pre-built binaries. The most common installs: ```bash theme={null} brew install safedep/tap/vet brew install safedep/tap/pmg brew install safedep/tap/gryph brew install safedep/tap/xbom brew install --cask safedep/tap/cli # the `safedep` command ``` ```bash theme={null} npm install -g @safedep/vet npm install -g @safedep/pmg npm install -g @safedep/gryph npm install -g @safedep/cli # the `safedep` command ``` For every install method, current versions, and the full command surface, see each tool's repository: [Vet](https://github.com/safedep/vet), [PMG](https://github.com/safedep/pmg), [Gryph](https://github.com/safedep/gryph), [safedep](https://github.com/safedep/cli). ## Next steps Scan your first repository for supply-chain risk. Guard your package installs in minutes. Set up an audit trail for your AI coding agents. Generate an enriched Bill of Materials from your code. Onboard to the hosted platform for org-wide visibility. # Install the SafeDep Skill Source: https://docs.safedep.io/get-started/safedep-skill Add the SafeDep Agent Skill to Claude Code or any skills-capable AI coding agent. The [SafeDep skill](https://github.com/safedep/skills) makes your AI coding agent fluent in SafeDep. With the skill installed, the agent answers SafeDep questions from the official sources instead of memory, picks the right SafeDep tool for the task, and helps you install, configure, and use it. Answers stay current because the agent reads the live documentation, not its training data. ## Install Add the marketplace, then install the plugin: ```bash theme={null} /plugin marketplace add safedep/skills /plugin install safedep-agent-skills@safedep-agent-skills ``` Turn on auto-update in Claude Code settings to stay on the current version. Works with any agent that supports Agent Skills: ```bash theme={null} npx skills add safedep/skills ``` Run `npx skills update` to refresh it later. Copy the skill into your project: ```bash theme={null} git clone https://github.com/safedep/skills.git cp -r skills/skills/safedep .cursor/skills/ ``` Cursor discovers skills from `.cursor/skills/` on startup. ## Verify Ask your agent a SafeDep question: ```text theme={null} What does SafeDep PMG do? ``` The agent should load the skill, fetch the answer from docs.safedep.io, and cite the page it used. ## Set up the safedep CLI The skill answers product questions without an account. Questions about *your* data, such as "what did PMG block this week", run through the [safedep CLI](https://github.com/safedep/cli) against your [SafeDep Cloud tenant](/governance/cloud/quickstart). The skill tells the agent to check for the CLI and your sign-in state, and to hand a step back to you when it needs a human: The [CLI repository](https://github.com/safedep/cli#install) lists more options. ```bash Homebrew theme={null} brew install safedep/tap/cli ``` ```bash npm theme={null} npm install -g @safedep/cli ``` Sign-in opens a browser, so the agent asks you to run it. ```bash theme={null} safedep auth login ``` ```bash theme={null} safedep auth status ``` See [Authentication](/governance/cloud/authentication). Ask your supply chain questions in plain English. Investigate package activity across your endpoints with an agent. # AI Governance Source: https://docs.safedep.io/governance/ai-governance Gain visibility into AI usage across your codebase and developer environments Developers integrate AI SDKs into application code and adopt AI-powered development tools, often without centralized oversight. This creates blind spots for security and compliance teams. `vet` provides two complementary capabilities to address this: 1. **Shadow AI in Code** detects AI and LLM SDK usage in your source code through static analysis and produces a CycloneDX SBOM with AI component evidence. It answers: *what AI services does your application call?* 2. **AI Tools Discovery** scans developer machines and project repositories to inventory AI coding agents, MCP servers, CLI tools, and IDE extensions. It answers: *what AI tools are developers using to write code?* Together, these give security teams a complete picture of AI usage across both the software supply chain and the development environment. Detect AI SDK usage in source code and generate AI-enriched SBOMs Discover AI coding agents, MCP servers, and IDE extensions on developer machines # Send Alerts from SafeDep Cloud Source: https://docs.safedep.io/governance/cloud/alerts Turn any safedep query exec result into a Slack, Discord, Teams, PagerDuty, or custom HTTP alert. Any SafeDep Cloud table you can query with `safedep query exec` can drive an alert. The recipe stays the same for every destination: 1. Write the SQL for the events you care about. 2. Run `safedep query exec -o json` to get rows. 3. Format the rows into your destination's payload shape. 4. `POST` to the webhook. The rest of this page is a **worked example**: PMG block events, formatted as a Slack message, sent to a Slack Incoming Webhook, every 5 minutes. Everything below is a stand-in: swap the query, the formatter, or the `curl` target for your own destination. ## Example: Slack alert for PMG blocks Every 5 minutes, a scheduled job queries SafeDep Cloud for packages PMG blocked in the last 5 minutes and posts a Slack message like: ``` 🛡️ PMG blocked 2 package(s) 🟡 COOLDOWN • lodash@0.1.0 • npm Endpoint: MacBook-Pro.local 🔴 MALICIOUS • safedep-test-pkg@0.1.3 • PyPI Endpoint: runnervmkkn4f ``` Both the package and endpoint are clickable: the package links to its SafeDep community report, the endpoint links to its page in SafeDep Cloud. ## Prerequisites You always need: * `safedep` CLI installed and signed in. See the [SafeDep Cloud Quickstart](/governance/cloud/quickstart). For the Slack + Python example below, you also need: * `python3` and `curl` on the host running the script. * A Slack Incoming Webhook URL. See Slack's [Sending messages using incoming webhooks](https://api.slack.com/messaging/webhooks). Confirm the CLI can reach SafeDep Cloud: ```bash theme={null} safedep auth status ``` ## Step 1: Write the query Save the SQL to a file so you can version it in git and rerun it: ```sql blocks.sql theme={null} SELECT package_guard_events.package_ecosystem, package_guard_events.package_name, package_guard_events.package_version, package_guard_events.package_action, package_guard_events.timestamp, endpoints.id, endpoints.identifier FROM package_guard_events JOIN endpoints ON endpoints.id = package_guard_events.invocation_id WHERE package_guard_events.package_action IN ( 'PMG_PACKAGE_ACTION_BLOCKED', 'PMG_PACKAGE_ACTION_COOLDOWN_BLOCKED' ) ORDER BY package_guard_events.timestamp DESC ``` Two things to notice: * **`package_action` filter.** `PMG_PACKAGE_ACTION_BLOCKED` is a malicious-package block. `PMG_PACKAGE_ACTION_COOLDOWN_BLOCKED` is a cooldown-window block (packages held back until they age past your cooldown threshold). * **`JOIN endpoints`.** Each block event was produced by a PMG invocation on some developer machine or CI runner. Joining `endpoints` gives you the endpoint's human-readable name (`endpoints.identifier`) and its ID (`endpoints.id`, used to build the Cloud deep-link). The `ON` clause is a required placeholder: SafeDep Cloud applies the real join from its catalog. See the [SQL reference](/reference/sql-query). Run it once to see the shape of the data: ```bash theme={null} safedep query exec -o json --sql-file blocks.sql --limit 5 ``` Enum columns (like `package_action` and `package_ecosystem`) return numeric ordinals in JSON; the formatter decodes them in Step 2. For the full schema, tables, and enum values, see the [SafeDep Cloud SQL reference](/reference/sql-query). ## Step 2: Format events for Slack Slack's Incoming Webhook takes a JSON payload with a `blocks` array. The script below reads rows from stdin, decodes the enum ordinals, builds one Slack section block per event, and prints the payload on stdout. Save this as `format.py`: ```python format.py theme={null} #!/usr/bin/env python3 """Read safedep query exec JSON on stdin, print a Slack payload on stdout.""" import json, sys from urllib.parse import quote ACTION = {1: ("🔴", "MALICIOUS"), 4: ("🟡", "COOLDOWN")} ECOSYSTEM = { 1: ("ECOSYSTEM_MAVEN", "Maven"), 2: ("ECOSYSTEM_NPM", "npm"), 3: ("ECOSYSTEM_PYPI", "PyPI"), 4: ("ECOSYSTEM_RUBYGEMS", "RubyGems"), 5: ("ECOSYSTEM_NUGET", "NuGet"), 6: ("ECOSYSTEM_CARGO", "Cargo"), 7: ("ECOSYSTEM_GO", "Go"), 8: ("ECOSYSTEM_GITHUB_ACTIONS", "GitHub Actions"), 9: ("ECOSYSTEM_PACKAGIST", "Packagist"), } rows = json.load(sys.stdin).get("rows", []) if not rows: sys.exit(0) # empty stdout, curl skips the POST def section(r): icon, reason = ACTION[r["package_guard_events.package_action"]] eco_enum, eco_label = ECOSYSTEM[r["package_guard_events.package_ecosystem"]] name, version = r["package_guard_events.package_name"], r["package_guard_events.package_version"] ep_id, ep_name = r["endpoints.id"], r["endpoints.identifier"] report = f"https://app.safedep.io/community/packages/{eco_enum}/{quote(name, safe='')}/{quote(version, safe='')}" endpoint = f"https://app.safedep.io/endpoints/{ep_id}" text = (f"{icon} *{reason}* • <{report}|`{name}@{version}`> • {eco_label}" f"\n\nEndpoint: <{endpoint}|`{ep_name}`>") return {"type": "section", "text": {"type": "mrkdwn", "text": text}} payload = {"blocks": [ {"type": "header", "text": {"type": "plain_text", "text": f"🛡️ PMG blocked {len(rows)} package(s)"}}, *[section(r) for r in rows], ]} json.dump(payload, sys.stdout) ``` Add ecosystems you use to the `ECOSYSTEM` dict; nothing else needs to change. ## Step 3: Post to Slack Pipe the query into the formatter and the formatter into `curl`: ```bash theme={null} export SLACK_WEBHOOK_URL='https://hooks.slack.com/services/...' safedep query exec -o json --sql-file blocks.sql --limit 10 \ | python3 format.py \ | curl -sS -X POST -H 'Content-Type: application/json' \ --data @- "$SLACK_WEBHOOK_URL" ``` If there are no matching events, `format.py` exits with empty stdout and `curl` sends nothing. On a successful post, Slack replies with `ok`. Slack caps a message at 50 blocks, so keep `--limit` around 10. See Slack's [block limits](https://api.slack.com/reference/block-kit/blocks). ## Step 4: Run it on a schedule To make this an alerting pipeline, filter to a rolling window and run periodically. The window and the schedule interval must match so events aren't dropped or duplicated. Save this as `safedep-alerts.sh` next to `format.py`. It's the same query as `blocks.sql`, plus one extra `AND` clause for the time window, an explicit `PATH` (schedulers run with a minimal `PATH`), and a skip when the window has no events (avoids Slack's `invalid_payload` on empty POSTs). ```bash safedep-alerts.sh theme={null} #!/usr/bin/env bash set -euo pipefail # Schedulers run with a minimal PATH. Add the location of `safedep` and `python3`. export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin" cd "$(dirname "$0")" # macOS / BSD date. On Linux: SINCE=$(date -u -d '5 minutes ago' '+%Y-%m-%dT%H:%M:%SZ') SINCE=$(date -u -v-5M '+%Y-%m-%dT%H:%M:%SZ') PAYLOAD=$(safedep query exec -o json --limit 10 --sql " SELECT package_guard_events.package_ecosystem, package_guard_events.package_name, package_guard_events.package_version, package_guard_events.package_action, package_guard_events.timestamp, endpoints.id, endpoints.identifier FROM package_guard_events JOIN endpoints ON endpoints.id = package_guard_events.invocation_id WHERE package_guard_events.package_action IN ( 'PMG_PACKAGE_ACTION_BLOCKED', 'PMG_PACKAGE_ACTION_COOLDOWN_BLOCKED' ) AND package_guard_events.timestamp > '$SINCE' ORDER BY package_guard_events.timestamp DESC " | python3 format.py) [ -n "$PAYLOAD" ] && printf '%s' "$PAYLOAD" | curl -sS -X POST \ -H 'Content-Type: application/json' --data @- "$SLACK_WEBHOOK_URL" ``` Then wire it up with your OS's native scheduler: On macOS, `cron` can't reach the keychain where `safedep auth login` stores its OAuth token, so scheduled `safedep query exec` calls fail with `not authenticated`. Use a **launchd user agent** instead: it runs in your logged-in user session and inherits keychain access. Save this as `~/Library/LaunchAgents/io.safedep.alerts.plist`: ```xml io.safedep.alerts.plist highlight={20-20} theme={null} Label io.safedep.alerts ProgramArguments /Users/you/safedep-alerts/safedep-alerts.sh StartInterval 300 EnvironmentVariables SLACK_WEBHOOK_URL PASTE_YOUR_SLACK_WEBHOOK_URL_HERE StandardOutPath /tmp/safedep-alerts.log StandardErrorPath /tmp/safedep-alerts.log RunAtLoad ``` Load, verify, and tail the log: ```bash theme={null} launchctl load ~/Library/LaunchAgents/io.safedep.alerts.plist launchctl list | grep io.safedep.alerts tail -f /tmp/safedep-alerts.log ``` `RunAtLoad` fires the job immediately. `StartInterval` is in seconds (`300` = 5 minutes) and must match the `-v-5M` window in the script. To stop it: ```bash theme={null} launchctl unload ~/Library/LaunchAgents/io.safedep.alerts.plist ``` On Linux, `cron` works fine for this use case. Install with `crontab -e` and add: ``` */5 * * * * SLACK_WEBHOOK_URL="https://hooks.slack.com/services/..." /home/you/safedep-alerts/safedep-alerts.sh >> /tmp/safedep-alerts.log 2>&1 ``` Change `date -u -v-5M ...` in the script to `date -u -d '5 minutes ago' ...` (GNU date syntax). Keep the cron interval (`*/5`) and the `SINCE` window in the script aligned. If you're on a desktop with `gnome-keyring` / `kwallet` and hit "not authenticated" from cron, either run the script under a systemd user timer (`systemctl --user enable --now safedep-alerts.timer`) or unlock the keyring for the cron session. The design is stateless: no cursor file to keep in sync, no drift across restarts. `--limit 10` is set for Slack's 50-block ceiling. Events beyond the limit in a single window are silently dropped. For burstier traffic, raise `--limit` (the CLI allows up to 100) and page through the JSON `next_page_token`, sending one Slack message per page. ## Send to other destinations Only the last two things change: the payload shape (in `format.py`) and the URL (in `curl`). Any JSON-accepting HTTP endpoint works. Emit a simple content payload and POST to your channel's webhook URL. Create a channel Workflow with a webhook trigger and POST an Adaptive Card payload to its URL. Emit an Events API v2 payload and POST to the enqueue endpoint. ## Query other events Swap `blocks.sql` for any question you can ask SafeDep Cloud: * **Insecure bypasses:** filter `package_guard_events` on `event_type = 'PMG_EVENT_TYPE_INSECURE_BYPASS'`. * **Endpoint activity:** `JOIN endpoints` and group by `endpoints.identifier` to see which machines produced the most events. * **Malicious packages across projects:** query `component_malicious_packages` with `is_verified = true`. See the [SafeDep Cloud SQL guide](/reference/sql-query) for the full schema, query syntax, and the paging model. # Authentication Source: https://docs.safedep.io/governance/cloud/authentication How SafeDep Cloud authentication works and how to authenticate the safedep CLI, vet, and CI/CD pipelines Every tool that talks to SafeDep Cloud authenticates with two values: a **tenant domain** (for example `your-company.safedep.io`) and a credential. The credential type depends on which API plane the tool calls: * **Data plane** (`api.safedep.io`): package insights, known-malicious package queries, and sync. Authenticates with an **API key**. * **Control plane** (`cloud.safedep.io`): tenant, policy, and management operations, including SQL queries and [on-demand package scans](/package-security/scan/overview). Authenticates with a **JWT** from an OAuth2 login. Generate API keys at [app.safedep.io/settings/api-keys](https://app.safedep.io/settings/api-keys). For request headers, OAuth2/OIDC endpoints, and rate limits, see the [API reference](/reference/api-introduction). For the full hostname list, see the [endpoints reference](/reference/endpoints). ## safedep CLI `safedep auth login` runs an OAuth2 device flow in your browser, selects a tenant, creates an API key, and stores the credentials in your OS keychain: ```bash theme={null} safedep auth login safedep auth status ``` For non-interactive environments, log in with a static API key instead of the device flow: ```bash theme={null} safedep auth login --api-key --tenant your-company.safedep.io ``` The key is read from `--api-key-value`, stdin (with `--from-stdin`), the `SAFEDEP_API_KEY` environment variable, or an interactive prompt, in that order. Work with multiple tenants using `--profile` and `safedep auth profile list`. See the [CLI command reference](https://github.com/safedep/cli/tree/main/docs/cmd) for all flags. API-key login covers data-plane commands only. [On-demand package scanning](/package-security/scan/overview) is a control-plane operation: it requires the OAuth2 device-flow session, and an API key cannot submit scans, by design. See [Scanning from CI and AI Agents](/package-security/scan/automation) for the reasoning and what this means for automation. ## vet vet uses an API key for scanning and [sync](/governance/cloud/sync): ```bash theme={null} vet auth configure --tenant your-company.safedep.io ``` You will be prompted to enter the API key. Verify the connection: ```bash theme={null} vet auth verify ``` Control plane commands under `vet cloud` use the OAuth2 device flow instead: ```bash theme={null} vet cloud login --tenant your-company.safedep.io vet cloud whoami ``` To log out, delete the stored credentials: `rm ~/.safedep/vet-auth.yml`. ## CI/CD pipelines Tools read credentials from environment variables, so pipelines need no interactive login: ```bash theme={null} export SAFEDEP_API_KEY=your-api-key export SAFEDEP_TENANT_ID=your-company.safedep.io ``` Store both as CI secrets. Across SafeDep docs, the secret names are `SAFEDEP_CLOUD_API_KEY` and `SAFEDEP_CLOUD_TENANT_DOMAIN`. [vet-action](https://github.com/safedep/vet-action) reads them through its `cloud-key` and `cloud-tenant` inputs instead of environment variables. For working pipeline configurations (GitHub Actions, GitLab, Jenkins, Azure DevOps), see [Cloud Sync](/governance/cloud/sync#sync-from-github-actions). ## Troubleshooting ### Identity not registered ``` ERRO[0001] Failed to execute whoami: rpc error: code = Unauthenticated desc = unauthenticated: Token auth failed: No user: record not found ``` Your identity is not registered with SafeDep Cloud. Sign up first: see the [quickstart](/governance/cloud/quickstart). ### Tenant not found ``` ERRO[0001] Failed to execute query: rpc error: code = Unknown desc = failed to resolve tenant: record not found ``` No tenant is configured. Set it with `vet auth configure --tenant ` or `vet cloud login --tenant `. If you've forgotten your tenant domain, run `vet cloud login` followed by `vet cloud whoami` to list the tenants you can access. ### Checking credentials ```bash theme={null} safedep auth status # safedep CLI session vet auth verify # vet API key vet cloud whoami # vet OAuth identity and tenants ``` Transport, request headers, OAuth2/OIDC, and rate limits Create a tenant and log in with the safedep CLI Send data to your tenant from vet, PMG, and endpoint scans Canonical gRPC/ConnectRPC schemas and generated SDKs # Agentic Endpoint Investigation Source: https://docs.safedep.io/governance/cloud/endpoint-hub/agentic-investigation Investigate package activity and AI tooling across your developer endpoints with an AI coding agent and the safedep CLI. Your endpoints report their activity to [Endpoint Hub](/governance/cloud/endpoint-hub/overview): every package install [PMG](/package-security/pmg/overview) allowed or blocked, and the AI tooling `vet` discovered. When something needs investigation, you do not write queries yourself. You ask your AI coding agent. The agent turns your question into a tenant-scoped [SafeDep Cloud SQL](/reference/sql-query) query, runs it with the `safedep` CLI, and reports what it found. This guide gives you investigation playbooks: the question to ask, what the agent runs, and how to verify the answer. ## Before you start * Endpoints that sync data to your tenant. Set up [Package Guard sync](/governance/cloud/endpoint-hub/package-guard) for package events, and optionally [Inventory](/governance/cloud/endpoint-hub/inventory) for AI tooling. * The `safedep` CLI, signed in with `safedep auth login`. See [Install the safedep CLI](/governance/cloud/quickstart#install-the-safedep-cli) and [Authentication](/governance/cloud/authentication). * An AI coding agent with the [SafeDep skill](/get-started/safedep-skill) installed. The agent cannot sign in for you. Sign-in opens a browser and needs a human. If the agent reports an authentication error, run `safedep auth login` yourself, confirm with `safedep auth status`, and tell the agent to continue. ## How the agent investigates The agent works in a loop: 1. It discovers the queryable tables with `safedep query schema get`. The schema describes the tables, their columns, the allowed joins, and the query rules. 2. It writes a query and runs it with `safedep query exec`. 3. If the server rejects the query, the error says why. The agent corrects the query and retries. Every query is scoped to your authenticated tenant. The agent reads data; it cannot change it. Each answer traces back to a real query, so you can ask the agent to show the SQL it ran. The query language has no relative dates, so for questions like "in the last 30 days" the agent computes the cutoff timestamp from today's date. The playbooks below include the SQL the agent runs, collapsed by default since you do not need it to investigate. Expand it when you want to see or verify the details. For the query language, the full table list, and the query rules, see [SafeDep Cloud SQL](/reference/sql-query). ## Playbooks ### Check exposure to a compromised package A package you use was compromised upstream. Find out if any endpoint installed it. ```text theme={null} The npm package eslint-config-prettier was compromised. Was it installed on any of our endpoints in the last 30 days? Which versions, and was it blocked or allowed? ``` The agent runs a query like this: ```sql theme={null} SELECT endpoints.identifier, package_guard_events.package_version, package_guard_events.package_action, package_guard_events.timestamp FROM package_guard_events JOIN endpoints ON endpoints.id = package_guard_events.invocation_id WHERE package_guard_events.package_name = 'eslint-config-prettier' AND package_guard_events.timestamp >= '2026-07-11T00:00:00Z' ORDER BY package_guard_events.timestamp DESC ``` Each row is one decision on one endpoint. `PMG_PACKAGE_ACTION_BLOCKED` means PMG stopped the install. `PMG_PACKAGE_ACTION_CONFIRMED` means a person approved it after a warning. An allowed install of a compromised version is your incident to respond to. ### Review what was blocked, and where ```text theme={null} What did PMG block across our endpoints this month? Group it by endpoint. ``` The agent filters `package_guard_events` on both block actions, bounds the time range to the month, and joins to `endpoints`: ```sql theme={null} SELECT endpoints.identifier, package_guard_events.package_name, package_guard_events.package_ecosystem, package_guard_events.package_action, package_guard_events.timestamp FROM package_guard_events JOIN endpoints ON endpoints.id = package_guard_events.invocation_id WHERE package_guard_events.package_action IN ('PMG_PACKAGE_ACTION_BLOCKED', 'PMG_PACKAGE_ACTION_COOLDOWN_BLOCKED') AND package_guard_events.timestamp >= '2026-08-01T00:00:00Z' ORDER BY package_guard_events.timestamp DESC ``` `PMG_PACKAGE_ACTION_BLOCKED` is a block on a known malicious package. `PMG_PACKAGE_ACTION_COOLDOWN_BLOCKED` is a block on a package too new to trust under the cooldown policy. Both stopped an install. A block on one endpoint is often the first visible event of a campaign. Follow up with the exposure playbook above for the same package across the fleet. ### Audit protection bypasses PMG records when a person bypasses protection. Review these regularly. ```text theme={null} Did anyone bypass PMG protection in the last two weeks? Show the endpoint, the package, and when it happened. ``` ```sql theme={null} SELECT endpoints.identifier, package_guard_events.package_name, package_guard_events.timestamp FROM package_guard_events JOIN endpoints ON endpoints.id = package_guard_events.invocation_id WHERE package_guard_events.event_type = 'PMG_EVENT_TYPE_INSECURE_BYPASS' AND package_guard_events.timestamp >= '2026-07-27T00:00:00Z' ORDER BY package_guard_events.timestamp DESC ``` The related `PMG_EVENT_TYPE_SANDBOX_OVERRIDE` event records sandbox policy overrides. Ask the agent to check both. ### Find endpoints that stopped reporting An endpoint that stopped syncing is a blind spot: it still installs packages, and you no longer see them. ```text theme={null} Which endpoints have not synced in the last 30 days? ``` ```sql theme={null} SELECT endpoints.identifier, endpoints.endpoint_type, endpoints.last_sync_at FROM endpoints WHERE endpoints.last_sync_at < '2026-07-11T00:00:00Z' ORDER BY endpoints.last_sync_at ASC ``` An endpoint can stop reporting for good reasons, such as a decommissioned laptop. Confirm before you treat it as an incident. ### Get a current verdict on a suspect package Package Guard events record the decision PMG made at install time. Verdicts change: a package that passed last month may be known malware today. To judge a package during an investigation, get a current verdict. Two paths exist, and the agent should take the fast one first: ```text theme={null} An endpoint installed left-pad-utils 2.1.0 from npm last week. Is it safe? Check the known malicious packages database first. Run a full scan only if I ask for a deep dive. ``` The fast path checks SafeDep's [known malicious packages database](/governance/cloud/malware-analysis). It is free and answers in milliseconds: ```bash theme={null} vet scan --purl pkg:npm/left-pad-utils@2.1.0 --malware-query ``` The slow path is an [on-demand package scan](/package-security/scan/overview): a full malware analysis of the exact version. It takes minutes and draws down your plan's scan allowance. Use it when the database has no verdict and the package deserves a deep dive: ```bash theme={null} safedep package scan run "pkg:npm/left-pad-utils@2.1.0" -o json ``` The scan returns `malware`, `benign`, or `inconclusive`, with evidence. Treat `inconclusive` as needs-review. See [Scanning from CI and AI Agents](/package-security/scan/automation) for the scan contract. ### See what AI tooling runs on an endpoint If your endpoints also run [Inventory](/governance/cloud/endpoint-hub/inventory) scans, the same loop answers questions about AI tooling: ```text theme={null} Which MCP servers were observed on our endpoints, and on which machines? ``` ```sql theme={null} SELECT inventory_events.item_identity, endpoints.identifier FROM inventory_events JOIN endpoints ON endpoints.id = inventory_events.app WHERE inventory_events.item_kind = 'INVENTORY_ITEM_KIND_MCP_SERVER' ORDER BY inventory_events.item_identity ``` Other item kinds cover coding agents, IDE extensions, and Agent Skills. ## Ask narrow questions Results return one page at a time, up to 100 rows. Do not ask the agent to dump a table and search the output. Ask a narrow question, and let the agent filter server-side: a package name, a time range, one endpoint, one event type. When you need totals, ask for counts; the agent aggregates with `GROUP BY` instead of paging through rows. ## Verify the answer Every agent answer maps to a query you can run yourself: 1. Ask the agent to show the SQL it ran. 2. Run it: `safedep query exec --sql ""`. 3. Compare the result with the agent's summary. If the agent's answer looks wrong, the query is the first place to look. A missing time bound or a wrong enum value changes the result silently. The query language, full table list, and query rules. Set up your AI coding agent for SafeDep. Sync package events from your endpoints. Ask your tenant questions in plain English. # Endpoint Inventory Source: https://docs.safedep.io/governance/cloud/endpoint-hub/inventory View AI tools, Agent Skills, MCP servers, and coding agents discovered on your endpoints in SafeDep Cloud Endpoint inventory shows what AI tooling is active across your endpoints (developer machines, CI runners, agent sandboxes). It is powered by `vet endpoint scan`, which runs locally to discover AI tools, Agent Skills, MCP servers, coding agents, and IDE extensions, then delivers them to SafeDep Cloud when credentials are configured.