Thank you for your interest in contributing to DotSecrets! This document provides guidelines and instructions for contributing to the project, particularly for those interested in implementing new secrets providers.
- Contributing to DotSecrets
Please help us keep DotSecrets open and inclusive. By participating, you are expected to uphold this code. Please report unacceptable behavior to the project maintainers.
- Fork the repository on GitHub
- Clone your fork locally
- Install dependencies with
npm install - Create a feature branch for your changes
- Make sure you have the latest changes from the upstream repository
- Run tests to ensure everything is working properly
- Make your changes, following the code style guidelines
- Add tests for your changes
- Run the test suite to make sure everything passes
- Commit your changes with clear, descriptive commit messages
- Push your changes to your fork
- Submit a pull request to the main repository
DotSecrets is designed to be extensible with new secrets providers. Here's how to implement a new provider:
All secrets providers must implement the ISecretsPlugin interface. The primary methods that must be implemented are:
getSecret(secretKey: string): Promise<string | undefined>- Retrieves a secret asynchronouslygetSecretSync(secretKey: string): string | undefined(optional) - Retrieves a secret synchronously if supportedpushSecrets(secrets: Record<string, string>): Promise<boolean | undefined>- Pushes multiple secrets to the providersetup(): Promise<boolean | undefined>- Interactive setup method for the provider
Create a new file in the src/plugins directory named after your provider (e.g., MyProviderPlugin.ts):
import { ISecretsPlugin } from "./ISecretsPlugin.js";
import { BaseSecretsPlugin } from "./BaseSecretsPlugin.js";
import { ConsoleUtils } from "../utils/console.js";
// Import any other necessary dependencies
export class MyProviderPlugin extends BaseSecretsPlugin implements ISecretsPlugin {
pluginName = "My Provider";
private client?: any;
private initialized?: Promise<void>;
constructor(_: Record<string, unknown> = {}, skip = false) {
super();
if (!skip) this.initialized = this.initializeClient();
}
private async initializeClient(): Promise<void> {
try {
// Initialize the client for your provider
// Check for required environment variables or configuration
this.client = /* your client initialization */;
ConsoleUtils.debug("My Provider plugin initialized successfully.");
} catch (error) {
ConsoleUtils.error(`Failed to initialize My Provider client: ${error}`);
throw error;
}
}
async getSecret(key: string): Promise<string | undefined> {
await this.initialized;
key = this.parseSecretName(key);
try {
// Implement secret retrieval logic
return /* retrieved secret */;
} catch (error) {
ConsoleUtils.warn(`Secret "${key}" not found or error retrieving: ${error}`);
return undefined;
}
}
getSecretSync(key: string): string | undefined {
// Implement synchronous retrieval if supported, or:
ConsoleUtils.error("My Provider does not support synchronous retrieval.");
return undefined;
}
async pushSecrets(secrets: Record<string, string>): Promise<boolean | undefined> {
// Implement logic to push multiple secrets to your provider
// Include validation, error handling, and progress reporting
return true; // Return true if successful
}
async setup(): Promise<boolean | undefined> {
// Implement interactive setup for your provider
// Guide the user through configuration, collect necessary credentials
return true; // Return true if setup was successful
}
}For each method, implement the provider-specific logic:
- initializeClient: Initialize your provider's client, check for required environment variables.
- getSecret: Fetch a secret from your provider using the provider's API.
- getSecretSync: If your provider supports it, implement synchronous secret retrieval.
- pushSecrets: Implement pushing secrets to your provider, with proper error handling and progress reporting.
- setup: Create an interactive setup process to guide users through configuration.
- Error Handling: Properly handle errors from your provider's API and give meaningful error messages.
- Caching: Consider implementing caching to improve performance.
- Authentication: Securely handle authentication credentials for your provider.
- Rate Limiting: Implement rate limiting if your provider has API restrictions.
- Progress Reporting: For operations that might take time, provide progress feedback to users.
Update the README.md file to include documentation for your provider:
- Add it to the provider table in the "Available Providers" section
- Create a new section under "Provider Configuration" with detailed setup instructions
- Document all required environment variables
- Ensure your code follows the style guidelines
- Update the README.md with details of your provider
- Include tests for your provider
- Ensure all tests pass
- Submit your PR with a clear description of the changes and the value they add
- Use TypeScript for all new code
- Follow the existing code style and patterns
- Use meaningful variable and function names
- Include JSDoc comments for public APIs
- Keep functions small and focused on a single responsibility
When implementing a new provider:
- Create unit tests for your provider in the
testdirectory - Mock external API calls in tests
- Test both success and failure cases
- Test configuration validation
- Run tests with
npm testto make sure everything passes
Thank you for contributing to DotSecrets and helping make it better for everyone!