🔐 Secure credential management for GitHub and GitLab projects
🔄 Build and upload workflow for secrets, variables, and files
📁 File-based credentials with custom handlers and formats
🔗 Webhook support for GitLab projects
🔍 Recursive mode for processing multiple projects
🔒 Encrypted secrets using GitHub's public key encryption
🎯 TypeScript-first with full type definitions
⚙️ Flexible configuration with JavaScript config files
🛡️ Force mode for overwriting existing credentials
Using npm:
npm install creddUsing yarn:
yarn add creddUsing pnpm:
pnpm add creddUsing bun:
bun add creddInstall globally:
npm i -g creddThen use the command:
# Build credentials (default)
credd <dir>
# Upload credentials
credd <dir> --upload
# Build and upload
credd <dir> --build --upload
# Force mode (overwrite existing)
credd <dir> --force
# Recursive mode (process subdirectories)
credd <dir> --recursiveOr use with npx (without installation):
# Build credentials (default)
npx credd <dir>
# Upload credentials
npx credd <dir> --upload
# Build and upload
npx credd <dir> --build --uploadimport { build, upload, buildDeep, uploadDeep } from 'credd';
// Build credentials for a single directory
await build('./configs/project1', {
buildDir: './build',
force: false,
});
// Upload credentials for a single directory
await upload('./configs/project1', {
buildDir: './build',
force: false,
});
// Build credentials recursively
await buildDeep('./configs', {
force: false,
});
// Upload credentials recursively
await uploadDeep('./configs', {
force: false,
});The credd package provides a CLI command for managing credentials in GitHub and GitLab projects:
Using global installation:
# Build credentials (default)
credd <dir>
# Upload credentials
credd <dir> --upload
# Build and upload
credd <dir> --build --upload
# Force mode (overwrite existing)
credd <dir> --force
# Recursive mode (process subdirectories)
credd <dir> --recursiveUsing npx (no installation needed):
npx credd <dir>
npx credd <dir> --upload
npx credd <dir> --build --upload
npx credd <dir> --force
npx credd <dir> --recursiveBuild credentials from source files into the build directory:
# Build credentials for current directory
credd .
# Build credentials for specific directory
credd ./configs/project1
# Build with force mode
credd . --force
# Build recursively
credd . --recursiveThe build process:
- Reads configuration from
config.jsin the target directory - Processes files using their handlers
- Generates output files in the
builddirectory - Adds metadata comments to generated files
Upload credentials to GitHub or GitLab:
# Upload credentials
credd . --upload
# Upload with force mode
credd . --upload --force
# Upload recursively
credd . --upload --recursiveThe upload process:
- Reads built files from the
builddirectory - Uploads secrets to the repository
- Uploads variables to the repository
- Uploads files as secrets or variables
- Manages webhooks (GitLab only)
Process multiple credential configurations in subdirectories:
# Build all credential configs recursively
credd . --recursive --build
# Upload all credential configs recursively
credd . --recursive --upload
# Build and upload all recursively
credd . --recursive --build --uploadRecursive mode finds all subdirectories containing index.js files and processes them.
The package exports functions for programmatic use:
import { build, upload, buildDeep, uploadDeep } from 'credd';
// Build credentials for a single directory
await build(serviceDirname, {
buildDir?: string;
log?: ILogger;
force?: boolean;
});
// Upload credentials for a single directory
await upload(serviceDirname, {
buildDir?: string;
log?: ILogger;
force?: boolean;
});
// Build credentials recursively
await buildDeep(dirname, {
buildDir?: string;
log?: ILogger;
force?: boolean;
});
// Upload credentials recursively
await uploadDeep(dirname, {
buildDir?: string;
log?: ILogger;
force?: boolean;
});import { createService } from 'credd';
// Create a service instance
const service = await createService(serviceDirname, {
force?: boolean;
});// Service configuration
type CredsService = {
projectId?: string;
projectName?: string;
projectPath?: string;
projectCredsUrl?: string;
token: string;
server: string;
force: boolean;
};
// Credential file configuration
type CredsFile = {
name: string;
filename: string;
credType?: 'secret' | 'variable' | 'skip';
content?: string;
handler: (fileOptions: any, config: any) => Record<string, any>;
type?: string;
format?: string;
};
// Variable configuration
type CredsVariable = string | {
value: string;
type?: 'env_var' | 'file';
protected?: boolean;
description?: string;
masked?: boolean;
};
// Main configuration
type CredsConfig = {
service: {
serviceName: 'github' | 'gitlab';
token: string;
projectPath: string;
projectName?: string;
projectId?: string; // Required for GitLab
server?: string; // Required for GitLab
projectCredsUrl?: string;
projectCredsOwner?: string;
};
secrets?: Record<string, CredsVariable>;
variables?: Record<string, CredsVariable>;
files?: Array<CredsFile> | Record<string, CredsFile>;
hooks?: Array<any>;
};Create a config.js file in your credentials directory:
module.exports = {
service: {
serviceName: 'github', // or 'gitlab'
token: 'YOUR_TOKEN',
projectPath: 'owner/repo',
// ... other service options
},
secrets: {
// Secret credentials
},
variables: {
// Environment variables
},
files: [
// File-based credentials
],
hooks: [
// Webhooks (GitLab only)
],
};For GitHub projects:
module.exports = {
service: {
serviceName: 'github',
token: process.env.GITHUB_TOKEN,
projectPath: 'owner/repo',
projectName: 'My Project',
projectCredsUrl: 'https://github.com/owner/repo',
projectCredsOwner: '@owner',
server: 'api.github.com', // Optional, defaults to api.github.com
},
// ... rest of config
};Required fields:
serviceName: Must be'github'token: GitHub personal access token withrepoandactions:writepermissionsprojectPath: Repository path in formatowner/repoprojectName: Project nameprojectCredsUrl: URL to the repositoryprojectCredsOwner: Owner username or organization
For GitLab projects:
module.exports = {
service: {
serviceName: 'gitlab',
token: process.env.GITLAB_TOKEN,
projectId: '123', // Project ID (required)
projectPath: 'group/project',
projectName: 'My Project',
projectCredsUrl: 'https://gitlab.com/group/project',
projectCredsOwner: '@group',
server: 'gitlab.com', // GitLab instance URL
},
// ... rest of config
};Required fields:
serviceName: Must be'gitlab'token: GitLab personal access token withapiscopeprojectId: GitLab project ID (numeric or string)projectPath: Project path in formatgroup/projectserver: GitLab instance URL (e.g.,gitlab.com,gitlab.example.com)projectName: Project nameprojectCredsUrl: URL to the repositoryprojectCredsOwner: Owner username or group
module.exports = {
secrets: {
DATABASE_PASSWORD: 'my-secret-password',
API_KEY: 'secret-api-key',
},
};module.exports = {
secrets: {
DATABASE_PASSWORD: {
value: 'my-secret-password',
protected: true, // Protected branch only (GitLab)
description: 'Database password',
masked: true, // Mask in logs (GitLab)
},
},
};module.exports = {
variables: {
NODE_ENV: 'production',
API_URL: {
value: 'https://api.example.com',
type: 'env_var', // or 'file' for GitLab
protected: false,
},
},
};Files allow you to generate credentials from source files:
const path = require('path');
module.exports = {
files: [
{
name: 'service-account',
filename: 'service-account.json',
credType: 'secret', // 'secret', 'variable', or 'skip'
type: 'json', // Output format
handler: async (fileOptions, config) => {
// Load and process your source file
const sourceData = require(path.join(__dirname, 'source.json'));
return {
// Transform data
...sourceData,
// Add computed values
};
},
},
{
name: 'config',
filename: 'config.js',
credType: 'variable',
type: 'js',
handler: (fileOptions, config) => ({
apiUrl: 'https://api.example.com',
environment: 'production',
}),
},
],
};File options:
name: Name of the credential (used as key)filename: Output filename inbuilddirectorycredType: How to upload ('secret','variable', or'skip')type: Output format ('json','js','yaml', etc.)handler: Function that processes the file and returns data
Webhooks are supported for GitLab only:
module.exports = {
hooks: [
{
url: 'https://example.com/webhook',
push_events: true,
tag_push_events: true,
merge_requests_events: true,
pipeline_events: true,
job_events: true,
enable_ssl_verification: true,
},
],
};You can use environment variables in your configuration:
# Set token via environment
GITHUB_TOKEN=your_token credd . --upload
GITLAB_TOKEN=your_token credd . --upload
# Or with npx
GITHUB_TOKEN=your_token npx credd . --upload
GITLAB_TOKEN=your_token npx credd . --upload// config.js
module.exports = {
service: {
serviceName: 'github',
token: process.env.GITHUB_TOKEN,
projectPath: 'myorg/myproject',
projectName: 'My Project',
projectCredsUrl: 'https://github.com/myorg/myproject',
projectCredsOwner: '@myorg',
},
secrets: {
DATABASE_URL: process.env.DATABASE_URL,
API_KEY: {
value: process.env.API_KEY,
},
},
variables: {
NODE_ENV: 'production',
API_URL: 'https://api.example.com',
},
files: [
{
name: 'service-account',
filename: 'service-account.json',
credType: 'secret',
type: 'json',
handler: async () => ({
type: 'service_account',
project_id: 'my-project',
private_key: process.env.SERVICE_ACCOUNT_KEY,
}),
},
],
};// config.js
module.exports = {
service: {
serviceName: 'gitlab',
token: process.env.GITLAB_TOKEN,
projectId: '12345',
projectPath: 'mygroup/myproject',
projectName: 'My Project',
projectCredsUrl: 'https://gitlab.com/mygroup/myproject',
projectCredsOwner: '@mygroup',
server: 'gitlab.com',
},
secrets: {
DATABASE_PASSWORD: {
value: process.env.DATABASE_PASSWORD,
protected: true,
masked: true,
},
},
variables: {
NODE_ENV: {
value: 'production',
type: 'env_var',
protected: false,
},
},
files: [
{
name: 'config',
filename: 'config.yaml',
credType: 'variable',
type: 'yaml',
handler: () => ({
api: {
url: 'https://api.example.com',
timeout: 5000,
},
}),
},
],
hooks: [
{
url: 'https://example.com/webhook',
push_events: true,
pipeline_events: true,
enable_ssl_verification: true,
},
],
};Credd includes comprehensive TypeScript definitions:
// All functions are properly typed for intellisense and type safety
import { build, upload, CredsConfig, CredsService } from 'credd';
const config: CredsConfig = {
service: {
serviceName: 'github',
// ... type-safe configuration
},
};The package requires:
@ycmd/run- Command execution utilities@ycmd/utils- Utility functions@lsk4/log- Logging utilities@lsk4/err- Error handling@lsk4/stringify- String formattingaxios- HTTP client for API requestslibsodium-wrappers- Encryption for GitHub secretsfishbird- Async utilitiesyargs- CLI argument parsing
We welcome contributions! Please follow these steps:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests
- Ensure all tests pass (
npm test) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT © Igor Suvorov
credd - Secure credential management 🔐
