How to Integrate SkillSpector into CI/CD Pipelines Using Exit Codes
SkillSpector provides deterministic exit codes (0, 1, and 2) that allow CI/CD systems to automatically gate AI-agent skill packages based on risk scores, with machine-readable JSON output for detailed automation.
The NVIDIA/SkillSpector repository offers a purpose-built CLI for scanning AI-agent skill packages to detect security risks. By leveraging the exit code contract implemented in src/skillspector/cli.py and the JSON serialization from src/skillspector/models.py, you can create robust CI/CD gates that block high-risk deployments without manual intervention.
Understanding SkillSpector Exit Codes
SkillSpector implements a three-state exit code system designed for automation, as documented in the repository's exit codes section. According to the NVIDIA/SkillSpector source code, the CLI returns specific codes to indicate scan success and risk thresholds:
| Exit Code | Condition | Risk Score | Recommendation |
|---|---|---|---|
| 0 | Scan succeeded | ≤ 50 | SAFE or CAUTION |
| 1 | Scan succeeded | > 50 | DO_NOT_INSTALL |
| 2 | Scan failed | N/A | Invalid input or internal error |
Exit Code 0 (Pass)
When skillspector scan exits with code 0, the skill passed all security checks with an acceptable risk profile. This occurs when the risk assessment score is 50 or below, yielding either SAFE or CAUTION recommendations.
Exit Code 1 (High Risk)
Exit code 1 indicates the scan completed successfully but detected critical security concerns. According to the exit code logic in src/skillspector/cli.py, this triggers when the risk score exceeds 50 and the recommendation becomes DO_NOT_INSTALL, signaling that the skill should not be deployed.
Exit Code 2 (Scan Failure)
Code 2 represents a scan failure unrelated to risk assessment. This covers invalid input paths, unreadable source files, or internal execution errors in the scanning engine, requiring immediate pipeline troubleshooting.
Capturing Machine-Readable JSON Output
For detailed automation beyond simple pass/fail gates, SkillSpector supports structured output via the --format json flag. As implemented in src/skillspector/models.py, the Finding.to_dict() method serializes scan results into a predictable schema:
{
"skill": { "name": "...", "source": "...", "scanned_at": "<ISO‑8601>" },
"risk_assessment": { "score": 0, "severity": "LOW", "recommendation": "SAFE" },
"components": [],
"issues": [],
"metadata": {
"has_executable_scripts": false,
"skillspector_version": "...",
"llm_requested": true,
"llm_available": true
}
}
You can write this output to a file using -o or --output for artifact collection and downstream parsing.
Implementing CI/CD Integration
Installation
Install the SkillSpector CLI as a step in your pipeline configuration using uv for fast, isolated tool installation:
uv tool install git+https://github.com/NVIDIA/SkillSpector.git
For MCP server capabilities, include the optional dependency:
uv tool install 'skillspector[mcp] @ git+https://github.com/NVIDIA/SkillSpector.git'
Basic Gate Implementation
Use the exit code directly with shell error handling to create a simple security gate. This pattern leverages set -e behavior common in CI environments:
if ! skillspector scan ./my-skill/ --format json -o skill_report.json; then
echo "⚠️ Skill rejected – see skill_report.json"
exit 1 # abort the pipeline
fi
echo "✅ Skill passed (score ≤ 50)"
Fine-Grained Risk Handling
Parse the JSON output to differentiate between SAFE and CAUTION recommendations, allowing conditional pipeline behavior:
RECOMMENDATION=$(jq -r '.risk_assessment.recommendation' skill_report.json)
case "$RECOMMENDATION" in
SAFE) echo "✅ Safe – continue";;
CAUTION) echo "⚠️ Caution – may require manual review";;
DO_NOT_INSTALL) echo "❌ Do not install – failing build"; exit 1;;
esac
Complete GitHub Actions Example
This workflow demonstrates production-grade integration with artifact upload, exit code evaluation, and conditional alerting:
name: CI – Skill Safety Check
on: [push, pull_request]
jobs:
skillspector:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install uv (optional)
run: curl -LsSf https://github.com/astral-sh/uv/releases/latest/download/uv-installer.sh | sh
- name: Install SkillSpector CLI
run: uv tool install git+https://github.com/NVIDIA/SkillSpector.git
- name: Run SkillSpector scan
id: scan
run: |
skillspector scan ./my-skill/ \
--format json \
--output skill_report.json
continue-on-error: true # we want to inspect the report even on failure
- name: Upload report artifact
uses: actions/upload-artifact@v4
with:
name: skill-report
path: skill_report.json
- name: Enforce gate based on exit code
if: steps.scan.outcome != 'success'
run: |
echo "❌ SkillSpector detected high‑risk issues – see artifact"
exit 1
- name: Optional CAUTION handling
run: |
RECOMMEND=$(jq -r '.risk_assessment.recommendation' skill_report.json)
if [ "$RECOMMEND" = "CAUTION" ]; then
echo "⚠️ CAUTION – flagging for manual review"
# e.g., comment on PR, create a ticket, etc.
fi
Key Source Files
Understanding these implementation files helps when debugging CI integration issues:
src/skillspector/cli.py: Contains the CLI entry point, argument parsing for--formatand--output, and the exit code logic that returns 0, 1, or 2 based on risk scores.src/skillspector/models.py: Defines the data models andFinding.to_dict()method that generates the JSON schema consumed by your CI pipelines.docs/SUPPRESSION.md: Provides baseline configuration options for handling false positives, essential for keeping CI reports stable across runs.pyproject.toml: Declares theskillspector[mcp]optional extras and version metadata.
Summary
- Exit code 0 indicates successful scans with risk scores ≤ 50 (SAFE/CAUTION), while exit code 1 signals high-risk skills (DO_NOT_INSTALL) and exit code 2 indicates scan failures.
- Use
--format jsonand--outputto capture machine-readable reports for artifact storage and programmatic parsing. - Implement gates using shell conditionals on exit codes, or parse JSON fields like
.risk_assessment.recommendationfor granular control. - Reference
src/skillspector/cli.pyfor exit code logic andsrc/skillspector/models.pyfor JSON schema details when building custom integrations.
Frequently Asked Questions
What do the SkillSpector exit codes mean in CI/CD contexts?
Exit code 0 means the skill passed security checks with a low risk score (≤ 50), exit code 1 means the scan succeeded but detected high-risk issues requiring blocking (score > 50, DO_NOT_INSTALL), and exit code 2 indicates the scan failed due to invalid inputs or internal errors. According to the NVIDIA/SkillSpector source code, these codes are generated in src/skillspector/cli.py to provide deterministic gating behavior.
How do I parse SkillSpector JSON output in a CI pipeline?
Use standard JSON parsing tools like jq to extract specific fields from the report generated with --format json. Common patterns include reading .risk_assessment.recommendation to distinguish between SAFE and CAUTION states, or checking .risk_assessment.score for numeric thresholds. The JSON structure is defined by the Finding.to_dict() method in src/skillspector/models.py.
Can I suppress false positives in CI runs?
Yes, SkillSpector supports baseline and suppression configurations documented in docs/SUPPRESSION.md. You can create a suppression file to exclude known acceptable patterns from risk scoring, ensuring that CI pipelines only flag new or unhandled security concerns rather than failing on approved components.
Where is the exit code logic implemented in SkillSpector?
The exit code mapping is implemented in src/skillspector/cli.py, which evaluates the risk score after scan completion and returns 0 for acceptable risk (≤ 50), 1 for high risk (> 50), or 2 for execution failures. This deterministic contract allows CI systems to rely on standard shell exit status checking without parsing output text.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →