with one click
juicebox-ci-integration
// Configure Juicebox CI/CD. Trigger: "juicebox ci", "juicebox pipeline".
// Configure Juicebox CI/CD. Trigger: "juicebox ci", "juicebox pipeline".
Scan a source tree for command-injection vulnerable patterns: shell=True calls in Python subprocess, os.system / os.popen with interpolated strings, Node child_process.exec with template literals, Ruby backticks / Kernel#system / Kernel#exec with interpolation, Go exec.Command with shell wrapping, PHP system / passthru / shell_exec / backticks with $-interpolation, Java Runtime.exec with concatenated args. Use when: pre-commit gate on code that calls out to shell utilities, audit of file-processing / archive-handling / image-conversion code, post-bug-report investigation for "we shell out to a tool." Threshold: any shell-invocation API called with a string that contains a variable interpolation, OR shell=True with anything other than a fixed literal. Trigger with: "scan command injection", "shell=True audit", "find exec calls", "check os.system".
Scan a source tree for dynamic-code-execution APIs that an attacker can hijack: Python eval / exec / compile, JavaScript eval / Function() / setTimeout(string), Ruby eval / instance_eval / class_eval, Java ScriptEngine, PHP eval / assert($str), .NET Activator.CreateInstance / Reflection.Emit with dynamic input. Use when: pre-commit gate on any application that parses user-uploaded code (rule engines, formula evaluators, plugin systems), or post-bug-report when "we run user-supplied expressions." Threshold: any call to eval / exec / Function / similar where the argument is not a string literal. Trigger with: "scan eval", "find dynamic exec", "audit eval calls", "code injection patterns".
Scan a source tree for unsafe-by-default deserialization APIs: Python pickle.loads / cPickle / shelve / dill, Ruby Marshal.load / YAML.load (pre-3.1 default), Java ObjectInputStream.readObject, PHP unserialize, .NET BinaryFormatter / NetDataContractSerializer, Node.js node-serialize, JavaScript JSON.parse with reviver containing eval. Use when: pre-commit gate on services that accept binary blobs, audit of legacy job-queue code (workers deserializing tasks), post-bug-report when "we accept user-uploaded archives." Threshold: any call to a known-unsafe deserialization API on data that originates from user input, network, file upload, or untrusted storage. Trigger with: "scan deserialization", "pickle audit", "java readObject scan", "yaml.load check".
Scan a source tree for SQL-injection vulnerable patterns: string concatenation into queries, f-string interpolation in SQL, string-format substitution into raw queries, deprecated cursor methods (cursor.execute with % formatting), Knex / Sequelize raw() with template interpolation, sequelize.query with replacements. Use when: pre-commit code review, post-feature SQL-touching release, inheriting a legacy codebase that predates ORMs, or post-bug-report investigation. Threshold: any source line where SQL keywords (SELECT / INSERT / UPDATE / DELETE / FROM / WHERE) appear in a string that's being built via concatenation, f-string, %-format, or .format() with variable input. Trigger with: "scan for sqli", "sql injection patterns", "check raw queries", "audit cursor.execute".
Scan a source tree for weak cryptographic primitives: MD5 / SHA-1 used for security purposes, DES / 3DES / RC4 ciphers, ECB block mode, custom-built crypto (XOR loops, hand-rolled HMAC), hardcoded IVs, predictable random (Math.random / java.util.Random for crypto seeds), missing certificate verification (verify=False, rejectUnauthorized: false). Use when: pre-merge gate on crypto-touching code, audit before SOC2 / PCI assessment, post-incident review when "we found a weakness in our token signing." Threshold: any call to a known-weak algorithm with non-test context, OR cert verification explicitly disabled, OR a custom crypto loop pattern. Trigger with: "scan weak crypto", "find MD5 usage", "check ECB mode", "audit ssl verify", "weak random".
Scan a source-code tree for hardcoded credentials embedded in source files: AWS access keys, GitHub tokens, Stripe keys, Slack tokens, Anthropic API keys, OpenAI keys, JWT signing secrets, generic base64-encoded passwords, RSA / SSH private keys, and high-entropy string literals that pattern-match common credential shapes. Use when: pre-commit gate before pushing a feature branch, audit before SOC2, post-incident scan after a leak, or inheriting a codebase you didn't write. Threshold: any source file contains a string that matches a canonical credential regex (AWS AKIA prefix, GitHub ghp_ prefix, etc.) OR a string with Shannon entropy above 4.5 in a field context (key=, token:, secret=). Trigger with: "scan secrets", "credential scan", "find hardcoded keys", "leak check".
| name | juicebox-ci-integration |
| description | Configure Juicebox CI/CD. Trigger: "juicebox ci", "juicebox pipeline". |
| allowed-tools | Read, Write, Edit, Bash(npm:*), Grep |
| version | 1.0.0 |
| license | MIT |
| author | Jeremy Longshore <jeremy@intentsolutions.io> |
| tags | ["saas","recruiting","juicebox"] |
| compatibility | Designed for Claude Code |
Set up CI/CD for Juicebox AI data analysis integrations: run unit tests with mocked dataset and analysis responses on every PR, validate live API connectivity for data queries on merge to main. Juicebox provides AI-powered data exploration and visualization, so CI pipelines verify dataset upload logic, analysis execution, and result parsing workflows.
# .github/workflows/juicebox-ci.yml
name: Juicebox CI
on:
pull_request:
paths: ['src/juicebox/**', 'tests/**']
push:
branches: [main]
jobs:
unit-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm test -- --reporter=verbose
integration-tests:
if: github.ref == 'refs/heads/main'
needs: unit-tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run test:integration
env:
JUICEBOX_API_KEY: ${{ secrets.JUICEBOX_API_KEY }}
// tests/juicebox-service.test.ts
import { describe, it, expect, vi } from 'vitest';
import { analyzeDataset, getAnalysisResults } from '../src/juicebox-service';
vi.mock('../src/juicebox-client', () => ({
JuiceboxClient: vi.fn().mockImplementation(() => ({
createAnalysis: vi.fn().mockResolvedValue({
analysisId: 'ana_abc123',
status: 'processing',
datasetId: 'ds_xyz',
}),
getAnalysis: vi.fn().mockResolvedValue({
analysisId: 'ana_abc123',
status: 'completed',
results: {
summary: 'Revenue increased 15% QoQ',
charts: [{ type: 'bar', title: 'Revenue by Quarter' }],
insights: ['Q4 drove majority of growth', 'APAC region outperformed'],
},
}),
listDatasets: vi.fn().mockResolvedValue({
datasets: [{ id: 'ds_xyz', name: 'Sales Data', rowCount: 50000 }],
}),
})),
}));
describe('Juicebox Service', () => {
it('creates an analysis from dataset', async () => {
const result = await analyzeDataset('ds_xyz', 'What drove revenue growth?');
expect(result.analysisId).toBe('ana_abc123');
expect(result.status).toBe('processing');
});
it('retrieves completed analysis with insights', async () => {
const results = await getAnalysisResults('ana_abc123');
expect(results.status).toBe('completed');
expect(results.results.insights).toHaveLength(2);
});
});
// tests/integration/juicebox.integration.test.ts
import { describe, it, expect } from 'vitest';
const hasKey = !!process.env.JUICEBOX_API_KEY;
describe.skipIf(!hasKey)('Juicebox Live API', () => {
it('lists available datasets', async () => {
const res = await fetch('https://api.juicebox.ai/v1/datasets', {
headers: { Authorization: `Bearer ${process.env.JUICEBOX_API_KEY}` },
});
expect(res.status).toBe(200);
const body = await res.json();
expect(body).toHaveProperty('datasets');
});
});
| CI Issue | Cause | Fix |
|---|---|---|
401 Unauthorized | Invalid API key | Regenerate at juicebox.ai account settings |
Analysis stuck on processing | Large dataset or complex query | Increase polling timeout to 120s |
| Dataset not found (404) | Dataset ID changed or deleted | Use listDatasets to get a valid ID dynamically |
| Rate limit (429) | Too many concurrent analyses | Queue analyses and limit to 2 parallel runs |
| Empty insights array | Insufficient data for AI analysis | Ensure test dataset has 100+ rows with varied data |
See juicebox-deploy-integration.