vaultace-cli
Version:
AI-powered security scanner that detects vulnerabilities in AI-generated code. Proactive scanning, autonomous fixing, and emergency response for modern development teams.
205 lines (167 loc) • 4.87 kB
JavaScript
/**
* Configuration Manager
* Handles CLI configuration storage and retrieval
*/
const fs = require('fs-extra')
const path = require('path')
const os = require('os')
class ConfigManager {
static getConfigPath() {
// Use XDG config directory or fallback to home
const configDir = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config')
return path.join(configDir, 'vaultace', 'config.json')
}
static getConfig() {
try {
const configPath = this.getConfigPath()
if (!fs.existsSync(configPath)) {
return this.getDefaultConfig()
}
const config = fs.readJsonSync(configPath)
// Merge with defaults to ensure all keys exist
return {
...this.getDefaultConfig(),
...config
}
} catch (error) {
console.warn(`Config read error: ${error.message}`)
return this.getDefaultConfig()
}
}
static getDefaultConfig() {
return {
apiUrl: 'https://api.vaultace.co',
auth: {
accessToken: null,
refreshToken: null,
expiresAt: null
},
defaults: {
severity: 'medium',
format: 'table',
aiPatterns: true,
respectGitignore: true
},
preferences: {
autoUpdate: true,
verbose: false,
colorOutput: true
}
}
}
static saveConfig(config) {
try {
const configPath = this.getConfigPath()
// Ensure config directory exists
fs.ensureDirSync(path.dirname(configPath))
// Write config with proper permissions
fs.writeJsonSync(configPath, config, { spaces: 2, mode: 0o600 })
} catch (error) {
throw new Error(`Failed to save config: ${error.message}`)
}
}
static set(key, value) {
const config = this.getConfig()
// Handle nested keys (e.g., "defaults.severity")
const keys = key.split('.')
let current = config
for (let i = 0; i < keys.length - 1; i++) {
const k = keys[i]
if (!current[k] || typeof current[k] !== 'object') {
current[k] = {}
}
current = current[k]
}
current[keys[keys.length - 1]] = value
this.saveConfig(config)
}
static get(key) {
const config = this.getConfig()
// Handle nested keys
const keys = key.split('.')
let current = config
for (const k of keys) {
if (current && typeof current === 'object' && k in current) {
current = current[k]
} else {
return undefined
}
}
return current
}
static setAuth(authData) {
const config = this.getConfig()
config.auth = {
...config.auth,
...authData
}
this.saveConfig(config)
}
static clearAuth() {
const config = this.getConfig()
config.auth = {
accessToken: null,
refreshToken: null,
expiresAt: null
}
this.saveConfig(config)
}
static isAuthenticated() {
const config = this.getConfig()
return !!(config.auth?.accessToken && config.auth?.refreshToken)
}
static isTokenExpired() {
const config = this.getConfig()
if (!config.auth?.expiresAt) {
return true
}
// Add 5 minute buffer for token refresh
return Date.now() > (config.auth.expiresAt - 300000)
}
static reset() {
const defaultConfig = this.getDefaultConfig()
this.saveConfig(defaultConfig)
}
static validateConfig(config = null) {
const cfg = config || this.getConfig()
// Validate API URL
if (cfg.apiUrl) {
try {
new URL(cfg.apiUrl)
} catch {
throw new Error('Invalid API URL format')
}
}
// Validate severity levels
const validSeverities = ['low', 'medium', 'high', 'critical']
if (cfg.defaults?.severity && !validSeverities.includes(cfg.defaults.severity)) {
throw new Error(`Invalid severity level. Must be one of: ${validSeverities.join(', ')}`)
}
// Validate output formats
const validFormats = ['table', 'json', 'csv', 'sarif']
if (cfg.defaults?.format && !validFormats.includes(cfg.defaults.format)) {
throw new Error(`Invalid output format. Must be one of: ${validFormats.join(', ')}`)
}
return true
}
// Migration helpers
static migrate() {
try {
const config = this.getConfig()
let migrated = false
// Example migration: rename old keys
if (config.api_url) {
config.apiUrl = config.api_url
delete config.api_url
migrated = true
}
if (migrated) {
this.saveConfig(config)
console.log(chalk.blue('ℹ️ Configuration migrated to latest format'))
}
} catch (error) {
console.warn(`Config migration warning: ${error.message}`)
}
}
}
module.exports = ConfigManager