Initial commit: breakpilot-compliance - Compliance SDK Platform
Services: Admin-Compliance, Backend-Compliance, AI-Compliance-SDK, Consent-SDK, Developer-Portal, PCA-Platform, DSMS Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
35
breakpilot-compliance-sdk/packages/cli/src/cli.ts
Normal file
35
breakpilot-compliance-sdk/packages/cli/src/cli.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* BreakPilot Compliance SDK CLI
|
||||
*
|
||||
* Commands:
|
||||
* - init: Initialize a new compliance project
|
||||
* - deploy: Deploy to hardware (Mac Mini/Mac Studio)
|
||||
* - scan: Run security scans
|
||||
* - export: Export compliance reports
|
||||
* - status: Check compliance status
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
import { initCommand } from './commands/init'
|
||||
import { deployCommand } from './commands/deploy'
|
||||
import { scanCommand } from './commands/scan'
|
||||
import { exportCommand } from './commands/export'
|
||||
import { statusCommand } from './commands/status'
|
||||
|
||||
const program = new Command()
|
||||
|
||||
program
|
||||
.name('breakpilot')
|
||||
.description('BreakPilot Compliance SDK CLI')
|
||||
.version('0.0.1')
|
||||
|
||||
// Register commands
|
||||
program.addCommand(initCommand)
|
||||
program.addCommand(deployCommand)
|
||||
program.addCommand(scanCommand)
|
||||
program.addCommand(exportCommand)
|
||||
program.addCommand(statusCommand)
|
||||
|
||||
program.parse()
|
||||
217
breakpilot-compliance-sdk/packages/cli/src/commands/deploy.ts
Normal file
217
breakpilot-compliance-sdk/packages/cli/src/commands/deploy.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
/**
|
||||
* Deploy command - Deploy to hardware (Mac Mini/Mac Studio)
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
interface DeployOptions {
|
||||
target?: string
|
||||
config?: string
|
||||
dryRun?: boolean
|
||||
}
|
||||
|
||||
export const deployCommand = new Command('deploy')
|
||||
.description('Deploy compliance services to hardware')
|
||||
.option('-t, --target <target>', 'Deployment target (mac-mini, mac-studio, cloud)', 'mac-mini')
|
||||
.option('-c, --config <path>', 'Path to config file', './breakpilot.config.json')
|
||||
.option('--dry-run', 'Show what would be deployed without actually deploying', false)
|
||||
.action(async (options: DeployOptions) => {
|
||||
const chalk = (await import('chalk')).default
|
||||
const ora = (await import('ora')).default
|
||||
const inquirer = (await import('inquirer')).default
|
||||
|
||||
console.log(chalk.bold.blue('\n🚀 BreakPilot Compliance SDK - Deployment\n'))
|
||||
|
||||
// Check for config file
|
||||
const configPath = path.resolve(options.config || './breakpilot.config.json')
|
||||
if (!fs.existsSync(configPath)) {
|
||||
console.log(chalk.yellow('⚠️ No config file found. Run `breakpilot init` first.'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
|
||||
|
||||
// Prompt for deployment details
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'target',
|
||||
message: 'Select deployment target:',
|
||||
choices: [
|
||||
{ name: 'Mac Mini M4 Pro (64GB RAM, Qwen 2.5 32B)', value: 'mac-mini' },
|
||||
{ name: 'Mac Studio M2 Ultra (512GB RAM, Qwen 2.5 40B)', value: 'mac-studio' },
|
||||
{ name: 'Cloud (BreakPilot Servers)', value: 'cloud' },
|
||||
],
|
||||
default: options.target,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'hostname',
|
||||
message: 'Target hostname/IP:',
|
||||
when: (answers) => answers.target !== 'cloud',
|
||||
default: 'localhost',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'sshUser',
|
||||
message: 'SSH username:',
|
||||
when: (answers) => answers.target !== 'cloud',
|
||||
default: process.env.USER || 'admin',
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'installLLM',
|
||||
message: 'Install/update LLM model?',
|
||||
when: (answers) => answers.target !== 'cloud',
|
||||
default: true,
|
||||
},
|
||||
])
|
||||
|
||||
if (options.dryRun) {
|
||||
console.log(chalk.yellow('\n📋 Dry run - no changes will be made\n'))
|
||||
}
|
||||
|
||||
const spinner = ora('Preparing deployment...').start()
|
||||
|
||||
try {
|
||||
// Generate docker-compose.yml
|
||||
const dockerCompose = generateDockerCompose(answers.target, config)
|
||||
|
||||
if (options.dryRun) {
|
||||
spinner.info('Would generate docker-compose.yml:')
|
||||
console.log(chalk.gray(dockerCompose))
|
||||
return
|
||||
}
|
||||
|
||||
// For actual deployment, we'd:
|
||||
// 1. SSH to target machine
|
||||
// 2. Copy docker-compose.yml
|
||||
// 3. Run docker-compose up -d
|
||||
// 4. Install LLM if requested
|
||||
|
||||
spinner.text = 'Connecting to target...'
|
||||
await sleep(1000) // Simulated
|
||||
|
||||
spinner.text = 'Deploying services...'
|
||||
await sleep(2000) // Simulated
|
||||
|
||||
if (answers.installLLM) {
|
||||
spinner.text = 'Installing LLM model (this may take a while)...'
|
||||
await sleep(2000) // Simulated
|
||||
}
|
||||
|
||||
spinner.succeed('Deployment complete!')
|
||||
|
||||
console.log(chalk.green('\n✅ Services deployed successfully'))
|
||||
console.log(chalk.gray('\nDeployed services:'))
|
||||
console.log(chalk.gray(' - API Gateway (port 443)'))
|
||||
console.log(chalk.gray(' - Compliance Engine'))
|
||||
console.log(chalk.gray(' - RAG Service'))
|
||||
console.log(chalk.gray(' - Security Scanner'))
|
||||
console.log(chalk.gray(' - PostgreSQL'))
|
||||
console.log(chalk.gray(' - Qdrant'))
|
||||
console.log(chalk.gray(' - MinIO'))
|
||||
if (answers.installLLM) {
|
||||
const model = answers.target === 'mac-studio' ? 'qwen2.5:40b' : 'qwen2.5:32b'
|
||||
console.log(chalk.gray(` - Ollama (${model})`))
|
||||
}
|
||||
|
||||
console.log(chalk.blue('\n🔗 Access your services at:'))
|
||||
console.log(chalk.white(` https://${answers.hostname || 'localhost'}/api/v1`))
|
||||
} catch (error) {
|
||||
spinner.fail('Deployment failed')
|
||||
console.error(chalk.red('Error:'), error)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
function generateDockerCompose(target: string, config: Record<string, unknown>): string {
|
||||
const llmModel = target === 'mac-studio' ? 'qwen2.5:40b' : 'qwen2.5:32b'
|
||||
|
||||
return `# Generated by BreakPilot CLI
|
||||
# Target: ${target}
|
||||
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
api-gateway:
|
||||
image: ghcr.io/breakpilot/compliance-sdk-gateway:latest
|
||||
ports:
|
||||
- "443:443"
|
||||
- "80:80"
|
||||
environment:
|
||||
- DATABASE_URL=postgres://breakpilot:breakpilot@postgres:5432/compliance
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- OLLAMA_URL=http://host.docker.internal:11434
|
||||
- MINIO_URL=http://minio:9000
|
||||
depends_on:
|
||||
- postgres
|
||||
- qdrant
|
||||
- minio
|
||||
restart: unless-stopped
|
||||
|
||||
compliance-engine:
|
||||
image: ghcr.io/breakpilot/compliance-engine:latest
|
||||
environment:
|
||||
- DATABASE_URL=postgres://breakpilot:breakpilot@postgres:5432/compliance
|
||||
depends_on:
|
||||
- postgres
|
||||
restart: unless-stopped
|
||||
|
||||
rag-service:
|
||||
image: ghcr.io/breakpilot/rag-service:latest
|
||||
environment:
|
||||
- QDRANT_URL=http://qdrant:6333
|
||||
- OLLAMA_URL=http://host.docker.internal:11434
|
||||
- EMBEDDING_MODEL=bge-m3
|
||||
depends_on:
|
||||
- qdrant
|
||||
restart: unless-stopped
|
||||
|
||||
security-scanner:
|
||||
image: ghcr.io/breakpilot/security-scanner:latest
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
restart: unless-stopped
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
- POSTGRES_USER=breakpilot
|
||||
- POSTGRES_PASSWORD=breakpilot
|
||||
- POSTGRES_DB=compliance
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
qdrant:
|
||||
image: qdrant/qdrant:v1.12.1
|
||||
volumes:
|
||||
- qdrant_data:/qdrant/storage
|
||||
restart: unless-stopped
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
- MINIO_ROOT_USER=breakpilot
|
||||
- MINIO_ROOT_PASSWORD=breakpilot123
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
qdrant_data:
|
||||
minio_data:
|
||||
|
||||
# Note: Ollama runs on the host system
|
||||
# Install with: ollama pull ${llmModel}
|
||||
`
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
222
breakpilot-compliance-sdk/packages/cli/src/commands/export.ts
Normal file
222
breakpilot-compliance-sdk/packages/cli/src/commands/export.ts
Normal file
@@ -0,0 +1,222 @@
|
||||
/**
|
||||
* Export command - Export compliance reports
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
interface ExportOptions {
|
||||
format?: string
|
||||
output?: string
|
||||
type?: string
|
||||
}
|
||||
|
||||
export const exportCommand = new Command('export')
|
||||
.description('Export compliance reports and documentation')
|
||||
.option('-f, --format <format>', 'Export format (pdf, docx, json, csv)', 'pdf')
|
||||
.option('-o, --output <path>', 'Output file path')
|
||||
.option('-t, --type <type>', 'Report type (full, summary, vvt, tom, dsfa, controls, risks)', 'summary')
|
||||
.action(async (options: ExportOptions) => {
|
||||
const chalk = (await import('chalk')).default
|
||||
const ora = (await import('ora')).default
|
||||
const inquirer = (await import('inquirer')).default
|
||||
|
||||
console.log(chalk.bold.blue('\n📄 BreakPilot Compliance Export\n'))
|
||||
|
||||
// Prompt for export details
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: 'Select report type:',
|
||||
choices: [
|
||||
{ name: 'Full Compliance Report', value: 'full' },
|
||||
{ name: 'Executive Summary', value: 'summary' },
|
||||
{ name: 'Verarbeitungsverzeichnis (VVT)', value: 'vvt' },
|
||||
{ name: 'Technische & Organisatorische Maßnahmen (TOM)', value: 'tom' },
|
||||
{ name: 'Datenschutz-Folgenabschätzung (DSFA)', value: 'dsfa' },
|
||||
{ name: 'Controls Overview', value: 'controls' },
|
||||
{ name: 'Risk Register', value: 'risks' },
|
||||
{ name: 'SBOM (Software Bill of Materials)', value: 'sbom' },
|
||||
],
|
||||
default: options.type,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'format',
|
||||
message: 'Select export format:',
|
||||
choices: [
|
||||
{ name: 'PDF', value: 'pdf' },
|
||||
{ name: 'Word Document (DOCX)', value: 'docx' },
|
||||
{ name: 'JSON', value: 'json' },
|
||||
{ name: 'CSV', value: 'csv' },
|
||||
{ name: 'CycloneDX (SBOM only)', value: 'cyclonedx' },
|
||||
{ name: 'SPDX (SBOM only)', value: 'spdx' },
|
||||
],
|
||||
default: options.format,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'output',
|
||||
message: 'Output file path:',
|
||||
default: (answers: { type: string; format: string }) =>
|
||||
`compliance-${answers.type}-${new Date().toISOString().split('T')[0]}.${answers.format}`,
|
||||
},
|
||||
])
|
||||
|
||||
const spinner = ora('Generating report...').start()
|
||||
|
||||
try {
|
||||
// In a real implementation, this would:
|
||||
// 1. Connect to the compliance API
|
||||
// 2. Fetch all relevant data
|
||||
// 3. Generate the report in the requested format
|
||||
|
||||
spinner.text = 'Fetching compliance data...'
|
||||
await sleep(1000)
|
||||
|
||||
spinner.text = 'Generating document...'
|
||||
await sleep(1500)
|
||||
|
||||
const outputPath = path.resolve(answers.output)
|
||||
|
||||
// Generate mock output
|
||||
const content = generateMockReport(answers.type, answers.format)
|
||||
fs.writeFileSync(outputPath, content)
|
||||
|
||||
spinner.succeed('Report generated successfully!')
|
||||
|
||||
console.log(chalk.green('\n✅ Export complete'))
|
||||
console.log(chalk.gray(` File: ${outputPath}`))
|
||||
console.log(chalk.gray(` Type: ${answers.type}`))
|
||||
console.log(chalk.gray(` Format: ${answers.format}`))
|
||||
|
||||
// Show report preview for JSON
|
||||
if (answers.format === 'json') {
|
||||
console.log(chalk.bold('\n📋 Preview:\n'))
|
||||
const preview = JSON.parse(content)
|
||||
console.log(chalk.gray(JSON.stringify(preview, null, 2).substring(0, 500) + '...'))
|
||||
}
|
||||
} catch (error) {
|
||||
spinner.fail('Export failed')
|
||||
console.error(chalk.red('Error:'), error)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
function generateMockReport(type: string, format: string): string {
|
||||
const reportData = {
|
||||
generatedAt: new Date().toISOString(),
|
||||
reportType: type,
|
||||
format: format,
|
||||
organization: 'Example Organization',
|
||||
complianceScore: 78,
|
||||
summary: {
|
||||
totalControls: 44,
|
||||
implementedControls: 35,
|
||||
partialControls: 6,
|
||||
openControls: 3,
|
||||
totalRisks: 12,
|
||||
criticalRisks: 1,
|
||||
highRisks: 2,
|
||||
regulations: ['DSGVO', 'NIS2', 'AI Act'],
|
||||
},
|
||||
sections: getSectionsForType(type),
|
||||
}
|
||||
|
||||
if (format === 'json' || format === 'cyclonedx' || format === 'spdx') {
|
||||
return JSON.stringify(reportData, null, 2)
|
||||
}
|
||||
|
||||
// For PDF/DOCX, we'd use a proper document generation library
|
||||
// For now, return a placeholder
|
||||
return `[${format.toUpperCase()} Report - ${type}]\n\n${JSON.stringify(reportData, null, 2)}`
|
||||
}
|
||||
|
||||
function getSectionsForType(type: string): Record<string, unknown>[] {
|
||||
switch (type) {
|
||||
case 'vvt':
|
||||
return [
|
||||
{
|
||||
id: 'vvt-1',
|
||||
name: 'Kundenmanagement',
|
||||
purpose: 'Verwaltung von Kundenbeziehungen',
|
||||
legalBasis: 'Art. 6 Abs. 1 lit. b DSGVO',
|
||||
dataCategories: ['Kontaktdaten', 'Vertragsdetails', 'Kommunikationshistorie'],
|
||||
retentionPeriod: '10 Jahre nach Vertragsende',
|
||||
},
|
||||
{
|
||||
id: 'vvt-2',
|
||||
name: 'Personalverwaltung',
|
||||
purpose: 'Verwaltung von Mitarbeiterdaten',
|
||||
legalBasis: 'Art. 6 Abs. 1 lit. b, c DSGVO',
|
||||
dataCategories: ['Personaldaten', 'Gehaltsdaten', 'Leistungsdaten'],
|
||||
retentionPeriod: '10 Jahre nach Beendigung',
|
||||
},
|
||||
]
|
||||
case 'tom':
|
||||
return [
|
||||
{
|
||||
category: 'Zutrittskontrolle',
|
||||
measures: [
|
||||
'Zutrittskontrollsystem mit Chipkarten',
|
||||
'Videoüberwachung der Eingänge',
|
||||
'Besucherregistrierung',
|
||||
],
|
||||
},
|
||||
{
|
||||
category: 'Zugangskontrolle',
|
||||
measures: [
|
||||
'Passwort-Policy (min. 12 Zeichen)',
|
||||
'Multi-Faktor-Authentifizierung',
|
||||
'Automatische Sperrung nach 5 Fehlversuchen',
|
||||
],
|
||||
},
|
||||
]
|
||||
case 'controls':
|
||||
return [
|
||||
{
|
||||
id: 'ctrl-1',
|
||||
domain: 'ACCESS_CONTROL',
|
||||
title: 'Benutzerauthentifizierung',
|
||||
status: 'IMPLEMENTED',
|
||||
evidence: ['auth-policy.pdf', 'mfa-config.png'],
|
||||
},
|
||||
{
|
||||
id: 'ctrl-2',
|
||||
domain: 'DATA_PROTECTION',
|
||||
title: 'Datenverschlüsselung',
|
||||
status: 'IMPLEMENTED',
|
||||
evidence: ['encryption-certificate.pdf'],
|
||||
},
|
||||
]
|
||||
case 'risks':
|
||||
return [
|
||||
{
|
||||
id: 'risk-1',
|
||||
title: 'Datenverlust durch Cyberangriff',
|
||||
likelihood: 3,
|
||||
impact: 5,
|
||||
severity: 'HIGH',
|
||||
mitigation: 'Backup-Strategie, Incident Response Plan',
|
||||
status: 'MITIGATED',
|
||||
},
|
||||
{
|
||||
id: 'risk-2',
|
||||
title: 'DSGVO-Bußgeld wegen unzureichender Dokumentation',
|
||||
likelihood: 2,
|
||||
impact: 4,
|
||||
severity: 'MEDIUM',
|
||||
mitigation: 'Regelmäßige Dokumentationsaudits',
|
||||
status: 'MONITORING',
|
||||
},
|
||||
]
|
||||
default:
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
221
breakpilot-compliance-sdk/packages/cli/src/commands/init.ts
Normal file
221
breakpilot-compliance-sdk/packages/cli/src/commands/init.ts
Normal file
@@ -0,0 +1,221 @@
|
||||
/**
|
||||
* Init command - Initialize a new compliance project
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
|
||||
interface InitOptions {
|
||||
template?: string
|
||||
force?: boolean
|
||||
}
|
||||
|
||||
export const initCommand = new Command('init')
|
||||
.description('Initialize a new compliance project')
|
||||
.argument('[directory]', 'Directory to initialize', '.')
|
||||
.option('-t, --template <template>', 'Project template (react, vue, vanilla)', 'react')
|
||||
.option('-f, --force', 'Overwrite existing files', false)
|
||||
.action(async (directory: string, options: InitOptions) => {
|
||||
const chalk = (await import('chalk')).default
|
||||
const ora = (await import('ora')).default
|
||||
const inquirer = (await import('inquirer')).default
|
||||
|
||||
console.log(chalk.bold.blue('\n🚀 BreakPilot Compliance SDK - Project Setup\n'))
|
||||
|
||||
// Prompt for configuration
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'projectName',
|
||||
message: 'Project name:',
|
||||
default: path.basename(path.resolve(directory)),
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'template',
|
||||
message: 'Select a template:',
|
||||
choices: [
|
||||
{ name: 'React (Recommended)', value: 'react' },
|
||||
{ name: 'Vue 3', value: 'vue' },
|
||||
{ name: 'Vanilla JS', value: 'vanilla' },
|
||||
],
|
||||
default: options.template,
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'apiEndpoint',
|
||||
message: 'API Endpoint:',
|
||||
default: 'https://compliance.breakpilot.app/api/v1',
|
||||
},
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'includeComponents',
|
||||
message: 'Include pre-built UI components?',
|
||||
default: true,
|
||||
},
|
||||
])
|
||||
|
||||
const spinner = ora('Setting up project...').start()
|
||||
|
||||
try {
|
||||
const targetDir = path.resolve(directory)
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!fs.existsSync(targetDir)) {
|
||||
fs.mkdirSync(targetDir, { recursive: true })
|
||||
}
|
||||
|
||||
// Create config file
|
||||
const configPath = path.join(targetDir, 'breakpilot.config.json')
|
||||
const config = {
|
||||
projectName: answers.projectName,
|
||||
template: answers.template,
|
||||
apiEndpoint: answers.apiEndpoint,
|
||||
version: '0.0.1',
|
||||
features: {
|
||||
dsgvo: true,
|
||||
compliance: true,
|
||||
rag: true,
|
||||
security: true,
|
||||
},
|
||||
}
|
||||
|
||||
fs.writeFileSync(configPath, JSON.stringify(config, null, 2))
|
||||
|
||||
// Create .env.example
|
||||
const envExamplePath = path.join(targetDir, '.env.example')
|
||||
const envContent = `# BreakPilot Compliance SDK Configuration
|
||||
BREAKPILOT_API_ENDPOINT=${answers.apiEndpoint}
|
||||
BREAKPILOT_API_KEY=pk_live_xxx
|
||||
BREAKPILOT_TENANT_ID=your_tenant_id
|
||||
`
|
||||
fs.writeFileSync(envExamplePath, envContent)
|
||||
|
||||
// Create example usage file based on template
|
||||
const examplePath = path.join(targetDir, `compliance-example.${getExtension(answers.template)}`)
|
||||
fs.writeFileSync(examplePath, getExampleCode(answers.template, answers.apiEndpoint))
|
||||
|
||||
spinner.succeed('Project initialized successfully!')
|
||||
|
||||
console.log(chalk.green('\n✅ Project created at:'), chalk.white(targetDir))
|
||||
console.log(chalk.gray('\nNext steps:'))
|
||||
console.log(chalk.gray(' 1. Copy .env.example to .env and fill in your API key'))
|
||||
console.log(chalk.gray(` 2. Install the SDK: npm install @breakpilot/compliance-sdk-${answers.template}`))
|
||||
console.log(chalk.gray(' 3. Import and use the SDK in your application'))
|
||||
console.log(chalk.gray('\nDocumentation: https://docs.breakpilot.app/sdk'))
|
||||
} catch (error) {
|
||||
spinner.fail('Failed to initialize project')
|
||||
console.error(chalk.red('Error:'), error)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
function getExtension(template: string): string {
|
||||
switch (template) {
|
||||
case 'react':
|
||||
return 'tsx'
|
||||
case 'vue':
|
||||
return 'vue'
|
||||
default:
|
||||
return 'js'
|
||||
}
|
||||
}
|
||||
|
||||
function getExampleCode(template: string, apiEndpoint: string): string {
|
||||
switch (template) {
|
||||
case 'react':
|
||||
return `// Example React integration
|
||||
import {
|
||||
ComplianceProvider,
|
||||
ConsentBanner,
|
||||
DSRPortal,
|
||||
useCompliance
|
||||
} from '@breakpilot/compliance-sdk-react';
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<ComplianceProvider
|
||||
apiEndpoint="${apiEndpoint}"
|
||||
apiKey={process.env.BREAKPILOT_API_KEY}
|
||||
tenantId={process.env.BREAKPILOT_TENANT_ID}
|
||||
>
|
||||
<ConsentBanner position="BOTTOM" theme="LIGHT" />
|
||||
<MyApp />
|
||||
</ComplianceProvider>
|
||||
);
|
||||
}
|
||||
|
||||
function MyApp() {
|
||||
const { state, compliance, rag } = useCompliance();
|
||||
|
||||
const askQuestion = async () => {
|
||||
const answer = await rag.ask('Was ist bei Art. 9 DSGVO zu beachten?');
|
||||
console.log(answer);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Compliance Score: {compliance.calculateComplianceScore().overall}%</h1>
|
||||
<button onClick={askQuestion}>Frage stellen</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
`
|
||||
case 'vue':
|
||||
return `<!-- Example Vue 3 integration -->
|
||||
<script setup lang="ts">
|
||||
import { useCompliance, useRAG } from '@breakpilot/compliance-sdk-vue';
|
||||
|
||||
const { state, complianceScore } = useCompliance();
|
||||
const { ask, chatHistory, isLoading } = useRAG();
|
||||
|
||||
const askQuestion = async () => {
|
||||
await ask('Was ist bei Art. 9 DSGVO zu beachten?');
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Compliance Score: {{ complianceScore }}%</h1>
|
||||
<button @click="askQuestion" :disabled="isLoading">
|
||||
{{ isLoading ? 'Lädt...' : 'Frage stellen' }}
|
||||
</button>
|
||||
<div v-for="msg in chatHistory" :key="msg.id">
|
||||
<strong>{{ msg.role }}:</strong> {{ msg.content }}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
`
|
||||
default:
|
||||
return `// Example Vanilla JS integration
|
||||
import { BreakPilotSDK } from '@breakpilot/compliance-sdk-vanilla';
|
||||
|
||||
BreakPilotSDK.init({
|
||||
apiEndpoint: '${apiEndpoint}',
|
||||
apiKey: 'pk_live_xxx',
|
||||
autoInjectBanner: true,
|
||||
bannerConfig: {
|
||||
position: 'BOTTOM',
|
||||
theme: 'LIGHT',
|
||||
language: 'de'
|
||||
},
|
||||
onConsentChange: (consents) => {
|
||||
console.log('Consents updated:', consents);
|
||||
if (consents.ANALYTICS) {
|
||||
// Load analytics
|
||||
}
|
||||
},
|
||||
onReady: () => {
|
||||
console.log('SDK ready!');
|
||||
}
|
||||
});
|
||||
|
||||
// Or use Web Components:
|
||||
// <breakpilot-consent-banner api-key="pk_live_xxx" theme="light" position="bottom">
|
||||
// </breakpilot-consent-banner>
|
||||
`
|
||||
}
|
||||
}
|
||||
228
breakpilot-compliance-sdk/packages/cli/src/commands/scan.ts
Normal file
228
breakpilot-compliance-sdk/packages/cli/src/commands/scan.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
/**
|
||||
* Scan command - Run security scans
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
import * as path from 'path'
|
||||
|
||||
interface ScanOptions {
|
||||
tools?: string
|
||||
output?: string
|
||||
format?: string
|
||||
severity?: string
|
||||
}
|
||||
|
||||
export const scanCommand = new Command('scan')
|
||||
.description('Run security scans on your codebase')
|
||||
.argument('[path]', 'Path to scan', '.')
|
||||
.option('-t, --tools <tools>', 'Comma-separated list of tools (gitleaks,semgrep,bandit,trivy,grype,syft)', 'all')
|
||||
.option('-o, --output <path>', 'Output file path')
|
||||
.option('-f, --format <format>', 'Output format (json, sarif, table)', 'table')
|
||||
.option('-s, --severity <level>', 'Minimum severity to report (low, medium, high, critical)', 'low')
|
||||
.action(async (scanPath: string, options: ScanOptions) => {
|
||||
const chalk = (await import('chalk')).default
|
||||
const ora = (await import('ora')).default
|
||||
|
||||
console.log(chalk.bold.blue('\n🔒 BreakPilot Security Scanner\n'))
|
||||
|
||||
const targetPath = path.resolve(scanPath)
|
||||
console.log(chalk.gray(`Scanning: ${targetPath}\n`))
|
||||
|
||||
const tools = options.tools === 'all'
|
||||
? ['gitleaks', 'semgrep', 'bandit', 'trivy', 'grype', 'syft']
|
||||
: options.tools!.split(',').map(t => t.trim())
|
||||
|
||||
const results: ScanResult[] = []
|
||||
|
||||
for (const tool of tools) {
|
||||
const spinner = ora(`Running ${tool}...`).start()
|
||||
|
||||
try {
|
||||
// Simulate running the tool
|
||||
await sleep(1500)
|
||||
|
||||
const toolResult = simulateToolResult(tool)
|
||||
results.push(toolResult)
|
||||
|
||||
if (toolResult.findings.length > 0) {
|
||||
spinner.warn(`${tool}: ${toolResult.findings.length} findings`)
|
||||
} else {
|
||||
spinner.succeed(`${tool}: No issues found`)
|
||||
}
|
||||
} catch (error) {
|
||||
spinner.fail(`${tool}: Failed`)
|
||||
}
|
||||
}
|
||||
|
||||
// Summary
|
||||
console.log(chalk.bold('\n📊 Scan Summary\n'))
|
||||
|
||||
const allFindings = results.flatMap(r => r.findings)
|
||||
const bySeverity = {
|
||||
critical: allFindings.filter(f => f.severity === 'CRITICAL'),
|
||||
high: allFindings.filter(f => f.severity === 'HIGH'),
|
||||
medium: allFindings.filter(f => f.severity === 'MEDIUM'),
|
||||
low: allFindings.filter(f => f.severity === 'LOW'),
|
||||
}
|
||||
|
||||
if (bySeverity.critical.length > 0) {
|
||||
console.log(chalk.red(` 🔴 Critical: ${bySeverity.critical.length}`))
|
||||
}
|
||||
if (bySeverity.high.length > 0) {
|
||||
console.log(chalk.red(` 🟠 High: ${bySeverity.high.length}`))
|
||||
}
|
||||
if (bySeverity.medium.length > 0) {
|
||||
console.log(chalk.yellow(` 🟡 Medium: ${bySeverity.medium.length}`))
|
||||
}
|
||||
if (bySeverity.low.length > 0) {
|
||||
console.log(chalk.gray(` 🟢 Low: ${bySeverity.low.length}`))
|
||||
}
|
||||
|
||||
if (allFindings.length === 0) {
|
||||
console.log(chalk.green(' ✅ No security issues found!'))
|
||||
} else {
|
||||
console.log(chalk.gray(`\n Total: ${allFindings.length} findings`))
|
||||
|
||||
// Show top findings
|
||||
if (options.format === 'table') {
|
||||
console.log(chalk.bold('\n📋 Top Findings\n'))
|
||||
|
||||
const topFindings = allFindings
|
||||
.sort((a, b) => severityOrder(b.severity) - severityOrder(a.severity))
|
||||
.slice(0, 10)
|
||||
|
||||
for (const finding of topFindings) {
|
||||
const severityColor = getSeverityColor(finding.severity)
|
||||
console.log(
|
||||
` ${severityColor(finding.severity.padEnd(8))} ` +
|
||||
`${chalk.gray(finding.tool.padEnd(10))} ` +
|
||||
`${finding.title}`
|
||||
)
|
||||
if (finding.file) {
|
||||
console.log(chalk.gray(` └─ ${finding.file}:${finding.line || '?'}`))
|
||||
}
|
||||
}
|
||||
|
||||
if (allFindings.length > 10) {
|
||||
console.log(chalk.gray(`\n ... and ${allFindings.length - 10} more findings`))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write output if requested
|
||||
if (options.output) {
|
||||
const fs = await import('fs')
|
||||
const output = {
|
||||
scanDate: new Date().toISOString(),
|
||||
targetPath,
|
||||
tools,
|
||||
summary: {
|
||||
total: allFindings.length,
|
||||
critical: bySeverity.critical.length,
|
||||
high: bySeverity.high.length,
|
||||
medium: bySeverity.medium.length,
|
||||
low: bySeverity.low.length,
|
||||
},
|
||||
findings: allFindings,
|
||||
}
|
||||
|
||||
fs.writeFileSync(options.output, JSON.stringify(output, null, 2))
|
||||
console.log(chalk.gray(`\nResults written to: ${options.output}`))
|
||||
}
|
||||
|
||||
// Exit with error if critical findings
|
||||
if (bySeverity.critical.length > 0 || bySeverity.high.length > 0) {
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
interface Finding {
|
||||
id: string
|
||||
tool: string
|
||||
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'LOW'
|
||||
title: string
|
||||
description?: string
|
||||
file?: string
|
||||
line?: number
|
||||
recommendation?: string
|
||||
}
|
||||
|
||||
interface ScanResult {
|
||||
tool: string
|
||||
findings: Finding[]
|
||||
}
|
||||
|
||||
function simulateToolResult(tool: string): ScanResult {
|
||||
// Simulate some findings for demonstration
|
||||
const findings: Finding[] = []
|
||||
|
||||
switch (tool) {
|
||||
case 'gitleaks':
|
||||
// Secrets detection - usually finds nothing in clean repos
|
||||
break
|
||||
case 'semgrep':
|
||||
findings.push({
|
||||
id: 'semgrep-1',
|
||||
tool: 'semgrep',
|
||||
severity: 'MEDIUM',
|
||||
title: 'Potential SQL injection',
|
||||
description: 'User input used in SQL query without parameterization',
|
||||
file: 'src/db/queries.ts',
|
||||
line: 42,
|
||||
recommendation: 'Use parameterized queries instead of string concatenation',
|
||||
})
|
||||
break
|
||||
case 'bandit':
|
||||
// Python security - skip if not a Python project
|
||||
break
|
||||
case 'trivy':
|
||||
findings.push({
|
||||
id: 'trivy-1',
|
||||
tool: 'trivy',
|
||||
severity: 'HIGH',
|
||||
title: 'CVE-2024-1234 in lodash@4.17.20',
|
||||
description: 'Prototype pollution vulnerability',
|
||||
recommendation: 'Upgrade to lodash@4.17.21 or higher',
|
||||
})
|
||||
break
|
||||
case 'grype':
|
||||
findings.push({
|
||||
id: 'grype-1',
|
||||
tool: 'grype',
|
||||
severity: 'LOW',
|
||||
title: 'Outdated dependency: axios@0.21.0',
|
||||
recommendation: 'Update to latest version',
|
||||
})
|
||||
break
|
||||
case 'syft':
|
||||
// SBOM generation - no findings, just metadata
|
||||
break
|
||||
}
|
||||
|
||||
return { tool, findings }
|
||||
}
|
||||
|
||||
function severityOrder(severity: string): number {
|
||||
switch (severity) {
|
||||
case 'CRITICAL': return 4
|
||||
case 'HIGH': return 3
|
||||
case 'MEDIUM': return 2
|
||||
case 'LOW': return 1
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
|
||||
function getSeverityColor(severity: string): (text: string) => string {
|
||||
const chalk = require('chalk')
|
||||
switch (severity) {
|
||||
case 'CRITICAL': return chalk.red.bold
|
||||
case 'HIGH': return chalk.red
|
||||
case 'MEDIUM': return chalk.yellow
|
||||
case 'LOW': return chalk.gray
|
||||
default: return chalk.white
|
||||
}
|
||||
}
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
161
breakpilot-compliance-sdk/packages/cli/src/commands/status.ts
Normal file
161
breakpilot-compliance-sdk/packages/cli/src/commands/status.ts
Normal file
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* Status command - Check compliance status
|
||||
*/
|
||||
|
||||
import { Command } from 'commander'
|
||||
|
||||
interface StatusOptions {
|
||||
json?: boolean
|
||||
verbose?: boolean
|
||||
}
|
||||
|
||||
export const statusCommand = new Command('status')
|
||||
.description('Check current compliance status')
|
||||
.option('-j, --json', 'Output as JSON', false)
|
||||
.option('-v, --verbose', 'Show detailed status', false)
|
||||
.action(async (options: StatusOptions) => {
|
||||
const chalk = (await import('chalk')).default
|
||||
const ora = (await import('ora')).default
|
||||
|
||||
if (!options.json) {
|
||||
console.log(chalk.bold.blue('\n📊 BreakPilot Compliance Status\n'))
|
||||
}
|
||||
|
||||
const spinner = options.json ? null : ora('Fetching status...').start()
|
||||
|
||||
try {
|
||||
// Simulate fetching status from API
|
||||
await sleep(1000)
|
||||
|
||||
const status = {
|
||||
lastUpdated: new Date().toISOString(),
|
||||
overallScore: 78,
|
||||
trend: 'UP',
|
||||
regulations: {
|
||||
DSGVO: { score: 85, status: 'COMPLIANT' },
|
||||
NIS2: { score: 72, status: 'PARTIAL' },
|
||||
'AI Act': { score: 65, status: 'IN_PROGRESS' },
|
||||
},
|
||||
controls: {
|
||||
total: 44,
|
||||
implemented: 35,
|
||||
partial: 6,
|
||||
notImplemented: 3,
|
||||
},
|
||||
risks: {
|
||||
total: 12,
|
||||
critical: 1,
|
||||
high: 2,
|
||||
medium: 5,
|
||||
low: 4,
|
||||
},
|
||||
evidence: {
|
||||
total: 28,
|
||||
valid: 24,
|
||||
expiring: 3,
|
||||
expired: 1,
|
||||
},
|
||||
dsrRequests: {
|
||||
pending: 2,
|
||||
inProgress: 1,
|
||||
completed: 15,
|
||||
},
|
||||
nextActions: [
|
||||
{
|
||||
priority: 'HIGH',
|
||||
action: 'Address critical risk: Data breach potential',
|
||||
dueDate: '2024-02-15',
|
||||
},
|
||||
{
|
||||
priority: 'MEDIUM',
|
||||
action: 'Update expired evidence: Security audit report',
|
||||
dueDate: '2024-02-20',
|
||||
},
|
||||
{
|
||||
priority: 'MEDIUM',
|
||||
action: 'Complete NIS2 gap assessment',
|
||||
dueDate: '2024-03-01',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
if (options.json) {
|
||||
console.log(JSON.stringify(status, null, 2))
|
||||
return
|
||||
}
|
||||
|
||||
spinner?.succeed('Status retrieved')
|
||||
|
||||
// Overall Score
|
||||
const scoreColor = status.overallScore >= 80 ? chalk.green :
|
||||
status.overallScore >= 60 ? chalk.yellow : chalk.red
|
||||
const trendIcon = status.trend === 'UP' ? '↑' :
|
||||
status.trend === 'DOWN' ? '↓' : '→'
|
||||
|
||||
console.log(chalk.bold('\n🎯 Overall Compliance Score'))
|
||||
console.log(` ${scoreColor.bold(status.overallScore + '%')} ${chalk.gray(trendIcon)}`)
|
||||
|
||||
// Regulations
|
||||
console.log(chalk.bold('\n📜 Regulations'))
|
||||
Object.entries(status.regulations).forEach(([reg, data]) => {
|
||||
const color = data.score >= 80 ? chalk.green :
|
||||
data.score >= 60 ? chalk.yellow : chalk.red
|
||||
const statusIcon = data.status === 'COMPLIANT' ? '✓' :
|
||||
data.status === 'PARTIAL' ? '◐' : '○'
|
||||
console.log(` ${statusIcon} ${reg.padEnd(12)} ${color(data.score + '%')} ${chalk.gray(data.status)}`)
|
||||
})
|
||||
|
||||
// Controls
|
||||
console.log(chalk.bold('\n🔧 Controls'))
|
||||
console.log(` ${chalk.green('●')} Implemented: ${status.controls.implemented}`)
|
||||
console.log(` ${chalk.yellow('●')} Partial: ${status.controls.partial}`)
|
||||
console.log(` ${chalk.red('●')} Not Implemented: ${status.controls.notImplemented}`)
|
||||
console.log(chalk.gray(` Total: ${status.controls.total}`))
|
||||
|
||||
// Risks
|
||||
console.log(chalk.bold('\n⚠️ Risks'))
|
||||
if (status.risks.critical > 0) {
|
||||
console.log(` ${chalk.red.bold('🔴')} Critical: ${status.risks.critical}`)
|
||||
}
|
||||
if (status.risks.high > 0) {
|
||||
console.log(` ${chalk.red('🟠')} High: ${status.risks.high}`)
|
||||
}
|
||||
console.log(` ${chalk.yellow('🟡')} Medium: ${status.risks.medium}`)
|
||||
console.log(` ${chalk.gray('🟢')} Low: ${status.risks.low}`)
|
||||
|
||||
// Evidence
|
||||
if (options.verbose) {
|
||||
console.log(chalk.bold('\n📎 Evidence'))
|
||||
console.log(` ${chalk.green('●')} Valid: ${status.evidence.valid}`)
|
||||
console.log(` ${chalk.yellow('●')} Expiring: ${status.evidence.expiring}`)
|
||||
console.log(` ${chalk.red('●')} Expired: ${status.evidence.expired}`)
|
||||
}
|
||||
|
||||
// DSR Requests
|
||||
if (options.verbose) {
|
||||
console.log(chalk.bold('\n📬 DSR Requests'))
|
||||
console.log(` Pending: ${status.dsrRequests.pending}`)
|
||||
console.log(` In Progress: ${status.dsrRequests.inProgress}`)
|
||||
console.log(` Completed: ${status.dsrRequests.completed}`)
|
||||
}
|
||||
|
||||
// Next Actions
|
||||
console.log(chalk.bold('\n📋 Next Actions'))
|
||||
status.nextActions.forEach(action => {
|
||||
const priorityColor = action.priority === 'HIGH' ? chalk.red :
|
||||
action.priority === 'MEDIUM' ? chalk.yellow : chalk.gray
|
||||
console.log(` ${priorityColor('●')} ${action.action}`)
|
||||
console.log(chalk.gray(` Due: ${action.dueDate}`))
|
||||
})
|
||||
|
||||
console.log('')
|
||||
} catch (error) {
|
||||
spinner?.fail('Failed to fetch status')
|
||||
console.error(chalk.red('Error:'), error)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
function sleep(ms: number): Promise<void> {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
18
breakpilot-compliance-sdk/packages/cli/src/index.ts
Normal file
18
breakpilot-compliance-sdk/packages/cli/src/index.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* @breakpilot/compliance-sdk-cli
|
||||
*
|
||||
* CLI tool for BreakPilot Compliance SDK
|
||||
*
|
||||
* Commands:
|
||||
* - init: Initialize a new compliance project
|
||||
* - deploy: Deploy to hardware (Mac Mini/Mac Studio)
|
||||
* - scan: Run security scans
|
||||
* - export: Export compliance reports
|
||||
* - status: Check compliance status
|
||||
*/
|
||||
|
||||
export { initCommand } from './commands/init'
|
||||
export { deployCommand } from './commands/deploy'
|
||||
export { scanCommand } from './commands/scan'
|
||||
export { exportCommand } from './commands/export'
|
||||
export { statusCommand } from './commands/status'
|
||||
Reference in New Issue
Block a user