2019-09-14 18:28:16 -04:00
const core = require ( '@actions/core' ) ;
const child _process = require ( 'child_process' ) ;
const fs = require ( 'fs' ) ;
2021-02-13 15:02:34 -05:00
const os = require ( 'os' ) ;
2021-03-01 04:24:06 -05:00
const token = require ( 'crypto' ) . randomBytes ( 64 ) . toString ( 'hex' ) ;
2021-03-01 04:41:11 -05:00
const isWindows = ( process . env [ 'OS' ] == 'Windows_NT' ) ;
2019-09-14 18:28:16 -04:00
try {
2020-02-06 13:09:44 -05:00
const privateKey = core . getInput ( 'ssh-private-key' ) ;
2020-01-14 04:29:16 -05:00
if ( ! privateKey ) {
core . setFailed ( "The ssh-private-key argument is empty. Maybe the secret has not been configured, or you are using a wrong secret name in your workflow file." ) ;
return ;
}
2021-02-13 15:02:34 -05:00
var home ;
2021-03-01 04:41:11 -05:00
if ( isWindows ) {
2021-02-13 15:02:34 -05:00
console . log ( 'Preparing ssh-agent service on Windows' ) ;
child _process . execSync ( 'sc config ssh-agent start=demand' , { stdio : 'inherit' } ) ;
2021-03-02 10:29:19 -05:00
// Work around https://github.com/PowerShell/openssh-portable/pull/447 by creating a \dev\tty file
2021-03-02 13:27:44 -05:00
/ * f s . m k d i r S y n c ( ' c : \ \ d e v ' ) ;
2021-03-02 10:40:01 -05:00
fs . closeSync ( fs . openSync ( 'c:\\dev\\tty' , 'a' ) ) ;
2021-03-02 10:55:31 -05:00
fs . mkdirSync ( 'd:\\dev' ) ;
2021-03-02 13:27:44 -05:00
fs . closeSync ( fs . openSync ( 'd:\\dev\\tty' , 'a' ) ) ; * /
2021-03-02 10:29:19 -05:00
2021-02-13 15:02:34 -05:00
home = os . homedir ( ) ;
} else {
// Use getent() system call, since this is what ssh does; makes a difference in Docker-based
// Action runs, where $HOME is different from the pwent
var { homedir : home } = os . userInfo ( ) ;
}
const homeSsh = home + '/.ssh' ;
2019-09-15 03:32:43 -04:00
console . log ( ` Adding GitHub.com keys to ${ homeSsh } /known_hosts ` ) ;
2020-03-02 19:41:12 -05:00
fs . mkdirSync ( homeSsh , { recursive : true } ) ;
2019-09-15 03:32:43 -04:00
fs . appendFileSync ( ` ${ homeSsh } /known_hosts ` , '\ngithub.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==\n' ) ;
fs . appendFileSync ( ` ${ homeSsh } /known_hosts ` , '\ngithub.com ssh-dss AAAAB3NzaC1kc3MAAACBANGFW2P9xlGU3zWrymJgI/lKo//ZW2WfVtmbsUZJ5uyKArtlQOT2+WRhcg4979aFxgKdcsqAYW3/LS1T2km3jYW/vr4Uzn+dXWODVk5VlUiZ1HFOHf6s6ITcZvjvdbp6ZbpM+DuJT7Bw+h5Fx8Qt8I16oCZYmAPJRtu46o9C2zk1AAAAFQC4gdFGcSbp5Gr0Wd5Ay/jtcldMewAAAIATTgn4sY4Nem/FQE+XJlyUQptPWMem5fwOcWtSXiTKaaN0lkk2p2snz+EJvAGXGq9dTSWHyLJSM2W6ZdQDqWJ1k+cL8CARAqL+UMwF84CR0m3hj+wtVGD/J4G5kW2DBAf4/bqzP4469lT+dF2FRQ2L9JKXrCWcnhMtJUvua8dvnwAAAIB6C4nQfAA7x8oLta6tT+oCk2WQcydNsyugE8vLrHlogoWEicla6cWPk7oXSspbzUcfkjN3Qa6e74PhRkc7JdSdAlFzU3m7LMkXo1MHgkqNX8glxWNVqBSc0YRdbFdTkL0C6gtpklilhvuHQCdbgB3LBAikcRkDp+FCVkUgPC/7Rw==\n' ) ;
2019-09-14 18:28:16 -04:00
console . log ( "Starting ssh-agent" ) ;
const authSock = core . getInput ( 'ssh-auth-sock' ) ;
2020-05-18 03:08:29 -04:00
let sshAgentOutput = ''
if ( authSock && authSock . length > 0 ) {
sshAgentOutput = child _process . execFileSync ( 'ssh-agent' , [ '-a' , authSock ] ) ;
} else {
sshAgentOutput = child _process . execFileSync ( 'ssh-agent' )
}
// Extract auth socket path and agent pid and set them as job variables
const lines = sshAgentOutput . toString ( ) . split ( "\n" )
for ( const lineNumber in lines ) {
const matches = /^(SSH_AUTH_SOCK|SSH_AGENT_PID)=(.*); export \1/ . exec ( lines [ lineNumber ] )
if ( matches && matches . length > 0 ) {
core . exportVariable ( matches [ 1 ] , matches [ 2 ] )
}
}
2019-09-14 18:28:16 -04:00
2021-02-27 15:47:41 -05:00
console . log ( "Adding private keys to agent" ) ;
var keyNumber = 0 ;
2020-01-14 04:29:16 -05:00
2021-02-27 15:47:41 -05:00
privateKey . split ( /(?=-----BEGIN)/ ) . forEach ( function ( key ) {
++ keyNumber ;
let keyFile = ` ${ homeSsh } /key_ ${ keyNumber } ` ;
// Write private key (unencrypted!) to file
console . log ( ` Write file ${ keyFile } ` ) ;
fs . writeFileSync ( keyFile , key . replace ( "\r\n" , "\n" ) . trim ( ) + "\n" , { mode : '600' } ) ;
// Set private key passphrase
let output = '' ;
try {
console . log ( ` Set passphrase on ${ keyFile } ` ) ;
2021-03-01 05:50:07 -05:00
output = child _process . execFileSync ( 'ssh-keygen' , [ '-p' , '-f' , keyFile , '-N' , token ] ) ;
2021-02-27 15:47:41 -05:00
} catch ( exception ) {
fs . unlinkSync ( keyFile ) ;
throw exception ;
}
2020-01-14 04:29:16 -05:00
2021-02-27 15:47:41 -05:00
// Load key into agent
2021-03-01 04:41:11 -05:00
if ( isWindows ) {
child _process . execFileSync ( 'ssh-add' , [ keyFile ] , { env : { ... process . env , ... { 'DISPLAY' : 'fake' , 'SSH_PASS' : token , 'SSH_ASKPASS' : 'D:\\a\\ssh-agent\\ssh-agent\\askpass.exe' } } } ) ;
} else {
2021-03-01 05:59:34 -05:00
child _process . execFileSync ( 'ssh-add' , [ keyFile ] , { env : process . env , input : token } ) ;
2021-03-01 04:41:11 -05:00
}
2021-02-28 10:58:23 -05:00
2021-02-27 15:47:41 -05:00
output . toString ( ) . split ( /\r?\n/ ) . forEach ( function ( key ) {
let parts = key . match ( /^Key has comment '.*\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+?)(?=\.git|\s|\')/ ) ;
2021-02-19 08:37:34 -05:00
2021-02-27 15:47:41 -05:00
if ( parts == null ) {
return ;
}
2021-02-19 08:37:34 -05:00
2021-02-27 15:47:41 -05:00
let ownerAndRepo = parts [ 1 ] ;
2021-02-19 08:37:34 -05:00
2021-02-27 15:47:41 -05:00
child _process . execSync ( ` git config --global --replace-all url."git@key- ${ keyNumber } : ${ ownerAndRepo } ".insteadOf "https://github.com/ ${ ownerAndRepo } " ` ) ;
child _process . execSync ( ` git config --global --add url."git@key- ${ keyNumber } : ${ ownerAndRepo } ".insteadOf "git@github.com: ${ ownerAndRepo } " ` ) ;
child _process . execSync ( ` git config --global --add url."git@key- ${ keyNumber } : ${ ownerAndRepo } ".insteadOf "ssh://git@github.com/ ${ ownerAndRepo } " ` ) ;
2021-02-19 08:37:34 -05:00
2021-03-02 10:40:01 -05:00
// On Linux and OS X, IdentitiesOnly=no will send all keys from agent before the explicit key, so use "yes".
// On Windows, IdentitiesOnly=yes will ignore keys from the agent, but send explicit keys first; so use "no" (https://github.com/PowerShell/Win32-OpenSSH/issues/1550)
2021-03-02 13:27:44 -05:00
let identitiesOnly = isWindows ? 'no' : 'yes' ;
2021-03-02 10:40:01 -05:00
2021-02-27 15:47:41 -05:00
let sshConfig = ` \n Host key- ${ keyNumber } \n `
+ ` HostName github.com \n `
+ ` User git \n `
2021-03-02 10:40:01 -05:00
+ ` IdentitiesOnly ${ identitiesOnly } \n `
2021-03-02 11:11:15 -05:00
+ ` AddKeysToAgent yes \n `
2021-02-27 15:47:41 -05:00
+ ` IdentityFile ${ keyFile } \n ` ;
2021-02-19 08:37:34 -05:00
2021-02-27 15:47:41 -05:00
fs . appendFileSync ( ` ${ homeSsh } /config ` , sshConfig ) ;
2021-02-19 08:37:34 -05:00
2021-02-27 15:47:41 -05:00
console . log ( ` Added deploy-key mapping: Use key # ${ keyNumber } for GitHub repository ${ ownerAndRepo } ` ) ;
} ) ;
2021-02-19 08:37:34 -05:00
} ) ;
2021-02-27 15:47:41 -05:00
console . log ( "Keys added:" ) ;
child _process . execSync ( 'ssh-add -l' , { stdio : 'inherit' } ) ;
2019-09-14 18:28:16 -04:00
} catch ( error ) {
core . setFailed ( error . message ) ;
}