UNPKG

remcode

Version:

Turn your AI assistant into a codebase expert. Intelligent code analysis, semantic search, and software engineering guidance through MCP integration.

274 lines (273 loc) 10.6 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.SecretsManager = void 0; const sodium = __importStar(require("libsodium-wrappers")); // Use proper import syntax for Octokit with types const rest_1 = require("@octokit/rest"); const logger_1 = require("../utils/logger"); const logger = (0, logger_1.getLogger)('SecretsManager'); /** * Class to manage GitHub repository secrets for Remcode */ class SecretsManager { /** * Constructor * @param githubToken GitHub API token */ constructor(githubToken) { this.octokit = null; this.token = null; this.token = githubToken || process.env.GITHUB_TOKEN || null; if (this.token) { this.octokit = new rest_1.Octokit({ auth: this.token }); logger.debug('GitHub API client initialized'); } else { logger.warn('No GitHub token provided, API operations will be simulated'); } } /** * Configure required repository secrets * @param owner Repository owner * @param repo Repository name * @returns Summary of secret operations */ async configureRepositorySecrets(owner, repo) { logger.info(`Configuring repository secrets for ${owner}/${repo}`); const secrets = this.getRequiredSecrets(); const results = []; for (const secret of secrets) { try { const result = await this.setRepositorySecret(owner, repo, secret); results.push(result); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to set secret ${secret.name}: ${errorMessage}`); results.push({ success: false, secretName: secret.name, error: errorMessage }); // If this is a required secret, we should abort if (secret.required) { throw new Error(`Failed to set required secret ${secret.name}: ${errorMessage}`); } } } // Calculate summary const successful = results.filter(r => r.success).length; const summary = { total: secrets.length, successful, failed: secrets.length - successful, results }; logger.info(`Secret configuration complete: ${successful}/${secrets.length} secrets configured`); return summary; } /** * Get required secrets for Remcode * @returns List of required secrets */ getRequiredSecrets() { return [ { name: 'PINECONE_API_KEY', value: process.env.PINECONE_API_KEY || '', description: 'Pinecone API key for vector storage', required: true }, { name: 'HUGGINGFACE_TOKEN', value: process.env.HUGGINGFACE_TOKEN || '', description: 'HuggingFace token for embeddings', required: true }, { name: 'OPENAI_API_KEY', value: process.env.OPENAI_API_KEY || '', description: 'OpenAI API key for advanced text processing', required: false }, { name: 'SLACK_WEBHOOK_URL', value: process.env.SLACK_WEBHOOK_URL || '', description: 'Slack webhook URL for notifications', required: false } ]; } /** * Set a repository secret in GitHub * @param owner Repository owner * @param repo Repository name * @param secret Secret configuration * @returns Secret operation result */ async setRepositorySecret(owner, repo, secret) { logger.info(`Setting repository secret: ${secret.name}`); // Validate secret value if (!secret.value) { if (secret.required) { throw new Error(`Missing value for required secret: ${secret.name}`); } else { logger.warn(`Missing value for optional secret: ${secret.name}, skipping`); return { success: false, secretName: secret.name, error: 'Missing value for optional secret' }; } } try { if (!this.octokit) { // Simulate API call if no GitHub token is available logger.info(`[SIMULATED] Secret ${secret.name} would be set for ${owner}/${repo}`); return { success: true, secretName: secret.name }; } // Get the repository's public key for secret encryption const { data: publicKeyData } = await this.octokit.actions.getRepoPublicKey({ owner, repo }); // Encrypt the secret value with the repository's public key const encryptedValue = await this.encryptSecret(publicKeyData.key, secret.value); // Create or update the secret await this.octokit.actions.createOrUpdateRepoSecret({ owner, repo, secret_name: secret.name, encrypted_value: encryptedValue, key_id: publicKeyData.key_id }); logger.info(`Secret ${secret.name} successfully set for ${owner}/${repo}`); return { success: true, secretName: secret.name }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to set secret ${secret.name}: ${errorMessage}`); return { success: false, secretName: secret.name, error: errorMessage }; } } /** * Encrypt a secret value using sodium for GitHub * @param publicKey Base64-encoded public key * @param secretValue Secret value to encrypt * @returns Base64-encoded encrypted secret */ async encryptSecret(publicKey, secretValue) { // Wait for sodium to initialize await sodium.ready; // Convert the public key to a Uint8Array const publicKeyBytes = sodium.from_base64(publicKey, sodium.base64_variants.ORIGINAL); // Convert the secret to a Uint8Array const secretBytes = sodium.from_string(secretValue); // Encrypt the secret using libsodium const encryptedBytes = sodium.crypto_box_seal(secretBytes, publicKeyBytes); // Convert the encrypted secret to Base64 return sodium.to_base64(encryptedBytes, sodium.base64_variants.ORIGINAL); } /** * Check if a repository has a specific secret * @param owner Repository owner * @param repo Repository name * @param secretName Secret name to check * @returns True if the secret exists */ async hasRepositorySecret(owner, repo, secretName) { try { if (!this.octokit) { // Simulate API call if no GitHub token is available logger.info(`[SIMULATED] Checking if secret ${secretName} exists for ${owner}/${repo}`); return false; } // Get the list of repository secrets const { data } = await this.octokit.actions.listRepoSecrets({ owner, repo }); // Check if the secret exists return data.secrets.some((s) => s.name === secretName); } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to check if secret ${secretName} exists: ${errorMessage}`); return false; } } /** * Delete a repository secret * @param owner Repository owner * @param repo Repository name * @param secretName Secret name to delete * @returns True if the secret was deleted */ async deleteRepositorySecret(owner, repo, secretName) { try { if (!this.octokit) { // Simulate API call if no GitHub token is available logger.info(`[SIMULATED] Deleting secret ${secretName} from ${owner}/${repo}`); return true; } // Delete the secret await this.octokit.actions.deleteRepoSecret({ owner, repo, secret_name: secretName }); logger.info(`Secret ${secretName} successfully deleted from ${owner}/${repo}`); return true; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); logger.error(`Failed to delete secret ${secretName}: ${errorMessage}`); return false; } } } exports.SecretsManager = SecretsManager;