Files
gitea.efforting.tech/ci/experiments/01-rsync-publish/steps/01-generate-key.mjs

77 lines
2.4 KiB
JavaScript

/**
* Step 01 — Generate a named SSH key pair
*
* Generates an ed25519 key pair and stores it in the secrets directory:
*
* <secrets_base>/git-ssh/<user>/public/<key_name>
* <secrets_base>/git-ssh/<user>/private/<key_name>
*
* The private key is written with mode 0600.
* The public key can be registered as a read-only deploy key in Gitea.
*/
import { execFile as exec_file } from 'node:child_process'
import { mkdirSync, mkdtempSync, chmodSync, existsSync, readFileSync, renameSync, rmSync } from 'node:fs'
import * as path from 'node:path'
import * as os from 'node:os'
import { promisify } from 'node:util'
import { fileURLToPath } from 'node:url'
import yaml from 'js-yaml'
const exec = promisify(exec_file)
const HERE = path.dirname(fileURLToPath(import.meta.url))
const CONFIG = yaml.load(readFileSync(path.join(HERE, '..', 'config.yml'), 'utf8'))
async function run(cmd, args = []) {
console.log(`$ ${cmd} ${args.join(' ')}`)
const { stdout, stderr } = await exec(cmd, args)
if (stdout) { process.stdout.write(stdout) }
if (stderr) { process.stderr.write(stderr) }
return stdout.trim()
}
async function main() {
const { secrets_base, user, key_name } = CONFIG
const public_dir = path.join(secrets_base, 'git-ssh', user, 'public')
const private_dir = path.join(secrets_base, 'git-ssh', user, 'private')
const public_path = path.join(public_dir, key_name)
const private_path = path.join(private_dir, key_name)
if (existsSync(private_path) || existsSync(public_path)) {
console.error(`Key "${key_name}" already exists for user "${user}". Aborting.`)
process.exit(1)
}
mkdirSync(public_dir, { recursive: true })
mkdirSync(private_dir, { recursive: true, mode: 0o700 })
// Generate into a secure temp directory, then move into place
const tmp_dir = mkdtempSync(path.join(os.tmpdir(), 'ci-keygen-'))
const tmp_path = path.join(tmp_dir, 'key')
try {
await run('ssh-keygen', [
'-t', 'ed25519',
'-N', '', // no passphrase
'-C', `ci/${user}/${key_name}`,
'-f', tmp_path,
])
renameSync(`${tmp_path}.pub`, public_path)
renameSync(tmp_path, private_path)
chmodSync(private_path, 0o600)
} finally {
rmSync(tmp_dir, { recursive: true, force: true })
}
console.log(`\nKey "${key_name}" generated for user "${user}".`)
console.log(`\nPublic key (add as read-only deploy key in Gitea):\n`)
console.log(readFileSync(public_path, 'utf8'))
}
main().catch(err => {
console.error(err)
process.exit(1)
})