Files
claude-code-conduit/bin/ccc-keygen.mjs
mikael-lovqvists-claude-agent 81ad722e84 Add ccc-keygen for secrets file generation
--create <names>  generates secrets.json with random 32-byte hex secrets
--filter <names>  extracts a subset of users into filtered-secrets.json
--input/--output  override default file paths

Removes hardcoded user/agent assumptions from secrets.example.json.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-07 20:59:25 +00:00

86 lines
2.4 KiB
JavaScript
Executable File

#!/usr/bin/env node
import { randomBytes } from 'crypto';
import { readFileSync, writeFileSync, existsSync } from 'fs';
function get_arg(argv, flag) {
const i = argv.indexOf(flag);
return i !== -1 ? argv[i + 1] : null;
}
function has_flag(argv, flag) {
return argv.includes(flag);
}
function parse_names(value, flag) {
if (!value) {
console.error(`${flag} requires a comma-separated list of usernames`);
process.exit(1);
}
return value.split(',').map(s => s.trim()).filter(Boolean);
}
function generate_secret() {
return randomBytes(32).toString('hex');
}
function read_secrets_file(input_path) {
if (!existsSync(input_path)) {
console.error(`Secrets file not found: ${input_path}`);
process.exit(1);
}
try {
return JSON.parse(readFileSync(input_path, 'utf8'));
} catch (err) {
console.error(`Cannot read secrets file: ${err.message}`);
process.exit(1);
}
}
function write_secrets_file(output_path, data) {
writeFileSync(output_path, JSON.stringify(data, null, '\t') + '\n', 'utf8');
console.log(`Written: ${output_path}`);
}
const argv = process.argv;
const create_arg = get_arg(argv, '--create');
const filter_arg = get_arg(argv, '--filter');
const input_arg = get_arg(argv, '--input') || 'secrets.json';
const output_arg = get_arg(argv, '--output');
if (!create_arg && !filter_arg) {
console.error(
'Usage:\n' +
' ccc-keygen --create <names> [--output secrets.json]\n' +
' ccc-keygen --filter <names> [--input secrets.json] [--output filtered-secrets.json]'
);
process.exit(1);
}
if (create_arg) {
const names = parse_names(create_arg, '--create');
const output_path = output_arg || 'secrets.json';
const users = {};
for (const name of names) {
users[name] = { secret: generate_secret(), canApprove: [] };
}
write_secrets_file(output_path, { users });
console.log(`Created users: ${names.join(', ')}`);
console.log('Edit canApprove lists to configure approval permissions.');
}
if (filter_arg) {
const names = parse_names(filter_arg, '--filter');
const output_path = output_arg || 'filtered-secrets.json';
const source = read_secrets_file(input_arg);
const users = {};
for (const name of names) {
if (!source.users?.[name]) {
console.error(`User '${name}' not found in ${input_arg}`);
process.exit(1);
}
users[name] = source.users[name];
}
write_secrets_file(output_path, { users });
console.log(`Filtered users: ${names.join(', ')}`);
}