8 Commits

Author SHA1 Message Date
Matthias Pigulla
cb8b21017a Update version numbers in README for the next bugfix release 2021-04-07 12:30:27 +02:00
Matthias Pigulla
aed5400f20 Log when a key is _not_ used as a deploy key
Resolves #69.

Co-authored-by: Sean Killeen <SeanKilleen@gmail.com>
2021-03-17 18:50:49 +00:00
Matthias Pigulla
4681241867 Use case-insensitive regex matching when scanning key comments
Resolves #68, closes #70, closes #71.

Co-authored-by: Sean Killeen <SeanKilleen@gmail.com>
2021-03-17 18:27:52 +00:00
Matthias Pigulla
4b6f4eb000 Windows virtual environment: Use SSH binaries from the Git suite (#63)
* Use SSH binaries from the Git suite

* Try to kill the ssh-agent upon action termination on Windows as well
2021-03-10 08:19:17 +01:00
Matthias Pigulla
795485730f Prepare 0.5.1 release 2021-03-10 08:17:18 +01:00
Matthias Pigulla
598c7ea894 Handle ENOENT exceptions with a graceful message 2021-03-05 20:17:14 +00:00
Shashank Patidar
65d1ea3d90 Mention that container-based workflows need to have ssh packages installed
Co-authored-by: Shashank Patidar <74622220+shashank11p@users.noreply.github.com>
2021-03-05 20:11:48 +00:00
Cecile Tonglet
5f95203cea Add note about using cargo with private dependencies (#64)
* Add note about using cargo with private dependencies

* Update doc to mention Windows only

* Add alternative workaround

* Create extra main section for tips and information regarding different languages/tools

Co-authored-by: Matthias Pigulla <mp@webfactory.de>
2021-03-04 12:49:35 +01:00
9 changed files with 266 additions and 255 deletions

View File

@@ -1,45 +1,46 @@
on: [push, pull_request]
on: [ push, pull_request ]
jobs:
deployment_keys_demo:
env:
GIT_SSH_COMMAND: ssh -v
strategy:
fail-fast: false
matrix:
os: [windows-latest]
os: [ ubuntu-latest, macOS-latest, windows-latest ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
# - name: Setup key
# uses: ./
# with:
# ssh-private-key: |
# ${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }}
# ${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}
# - run: |
# cat ~/.ssh/config
# ssh-add -l
# C:/Windows/System32/OpenSSH/ssh.exe -v git@key-2 'echo octocat'
- name: Start SSH session
uses: luchihoratiu/debug-via-ssh@main
with:
NGROK_AUTH_TOKEN: ${{ secrets.NGROK_AUTH_TOKEN }}
SSH_PASS: ${{ secrets.SSH_PASS }}
# git clone git@github.com:mpdude/test-2.git test-2-git
# ls -alh ~/.ssh
# git clone https://github.com/mpdude/test-1.git test-1-http
# git clone git@github.com:mpdude/test-1.git test-1-git
# git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh
# git clone https://github.com/mpdude/test-2.git test-2-http
- uses: actions/checkout@v2
- name: Setup key
uses: ./
with:
ssh-private-key: |
${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }}
${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}
- run: |
git clone https://github.com/mpdude/test-1.git test-1-http
git clone git@github.com:mpdude/test-1.git test-1-git
git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh
git clone https://github.com/mpdude/test-2.git test-2-http
git clone git@github.com:mpdude/test-2.git test-2-git
git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh
docker_demo:
runs-on: ubuntu-latest
container:
image: ubuntu:latest
steps:
- uses: actions/checkout@v2
- run: apt update && apt install -y openssh-client git
- name: Setup key
uses: ./
with:
ssh-private-key: |
${{ secrets.MPDUDE_TEST_1_DEPLOY_KEY }}
${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}
- run: |
git clone https://github.com/mpdude/test-1.git test-1-http
git clone git@github.com:mpdude/test-1.git test-1-git
git clone ssh://git@github.com/mpdude/test-1.git test-1-git-ssh
git clone https://github.com/mpdude/test-2.git test-2-http
git clone git@github.com:mpdude/test-2.git test-2-git
git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh
# git clone ssh://git@github.com/mpdude/test-2.git test-2-git-ssh
# cat > ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9 <<< "${{ secrets.MPDUDE_TEST_2_DEPLOY_KEY }}"
# ssh-keygen -p -f ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9 -N secret-passphrase
# eval `ssh-agent`
# echo "secret-passphrase" | ssh-add ~/.ssh/5965bf89ab6e2900262e3f6802dfb4d65cb0de539d0fbb97d381e7130a4ba7e9
# ssh-add -L
# git clone git@github.com:mpdude/test-2.git test-2-git
# shell: bash

View File

@@ -33,9 +33,9 @@ jobs:
...
steps:
- actions/checkout@v2
# Make sure the @v0.5.0 matches the current version of the
# Make sure the @v0.5.2 matches the current version of the
# action
- uses: webfactory/ssh-agent@v0.5.0
- uses: webfactory/ssh-agent@v0.5.2
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- ... other steps
@@ -50,7 +50,7 @@ You can set up different keys as different secrets and pass them all to the acti
```yaml
# ... contens as before
- uses: webfactory/ssh-agent@v0.5.0
- uses: webfactory/ssh-agent@v0.5.2
with:
ssh-private-key: |
${{ secrets.FIRST_KEY }}
@@ -90,6 +90,42 @@ If the private key is not in the `PEM` format, you will see an `Error loading ke
Use `ssh-keygen -p -f path/to/your/key -m pem` to convert your key file to `PEM`, but be sure to make a backup of the file first 😉.
## Additional Information for Particular Tools or Platforms
If you know that your favorite tool or platform of choice requires extra tweaks or has some caveats when running with SSH, feel free to open a PR to amend this section here.
### Container-based Workflows
If you are using this action on container-based workflows, make sure the container has the necessary SSH binaries or package(s) installed.
### Cargo's (Rust) Private Dependencies on Windows
If you are using private repositories in your dependencies like this:
```
stuff = { git = "ssh://git@github.com/myorg/stuff.git", branch = "main" }
```
... you will need to change a configuration in the workflow for Windows machines in order to make cargo able to clone private repositories.
There are 2 ways you can achieve this:
1. Add this step once in your job **before** any cargo command:
```
- name: Update cargo config to use Git CLI
run: Set-Content -Path $env:USERPROFILE\.cargo\config.toml "[net]`ngit-fetch-with-cli = true"
```
This will configure Cargo to use the Git CLI as explained in the [Cargo's documentation](https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli).
2. Alternatively you can set it to the environment variables for the entire workflow:
```
env:
CARGO_NET_GIT_FETCH_WITH_CLI: true
```
## What this Action *cannot* do for you
The following items are not issues, but beyond what this Action is supposed to do.

View File

@@ -1,24 +0,0 @@
/*
ssh-add on Windows (probably part of the source at https://github.com/PowerShell/openssh-portable)
does not/can not read the passphrase from stdin.
However, when the DISPLAY env var is set and ssh-add is not run from a terminal (however it tests
that), it will run the executable pointed to by SSH_ASKPASS in a subprocess and read the passphrase
from that subprocess' stdout.
This program can be used as the SSH_ASKPASS implementation. It will return the passphrase set
in the SSH_PASS env variable.
To cross-compile from Ubuntu, I installed the `mingw-w64` package and ran
$ x86_64-w64-mingw32-gcc askpass.c -static -o askpass.exe
*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv)
{
printf("%s\n", getenv("SSH_PASS"));
return 0;
}

Binary file not shown.

View File

@@ -1,10 +1,12 @@
const core = require('@actions/core')
const { execSync } = require('child_process')
const core = require('@actions/core');
const { execSync } = require('child_process');
const { sshAgent } = require('./paths.js');
try {
// Kill the started SSH agent
console.log('Stopping SSH agent')
execSync('kill ${SSH_AGENT_PID}', { stdio: 'inherit' })
console.log('Stopping SSH agent');
execSync(sshAgent, ['-k'], { stdio: 'inherit' });
} catch (error) {
console.log(error.message);
console.log('Error stopping the SSH agent, proceeding anyway');

35
dist/cleanup.js vendored
View File

@@ -122,13 +122,15 @@ module.exports = require("child_process");
/***/ 175:
/***/ (function(__unusedmodule, __unusedexports, __webpack_require__) {
const core = __webpack_require__(470)
const { execSync } = __webpack_require__(129)
const core = __webpack_require__(470);
const { execSync } = __webpack_require__(129);
const { sshAgent } = __webpack_require__(972);
try {
// Kill the started SSH agent
console.log('Stopping SSH agent')
execSync('kill ${SSH_AGENT_PID}', { stdio: 'inherit' })
console.log('Stopping SSH agent');
execSync(sshAgent, ['-k'], { stdio: 'inherit' });
} catch (error) {
console.log(error.message);
console.log('Error stopping the SSH agent, proceeding anyway');
@@ -480,6 +482,31 @@ module.exports = require("path");
module.exports = require("fs");
/***/ }),
/***/ 972:
/***/ (function(module, __unusedexports, __webpack_require__) {
const os = __webpack_require__(87);
module.exports = (process.env['OS'] != 'Windows_NT') ? {
// 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
home: os.userInfo().homedir,
sshAgent: 'ssh-agent',
sshAdd: 'ssh-add'
} : {
home: os.homedir(),
sshAgent: 'c://progra~1//git//usr//bin//ssh-agent.exe',
sshAdd: 'c://progra~1//git//usr//bin//ssh-add.exe'
};
/***/ })
/******/ });

172
dist/index.js vendored
View File

@@ -118,9 +118,8 @@ exports.issueCommand = issueCommand;
const core = __webpack_require__(470);
const child_process = __webpack_require__(129);
const fs = __webpack_require__(747);
const os = __webpack_require__(87);
const token = __webpack_require__(417).randomBytes(64).toString('hex');
const isWindows = (process.env['OS'] == 'Windows_NT');
const crypto = __webpack_require__(417);
const { home, sshAgent, sshAdd } = __webpack_require__(972);
try {
const privateKey = core.getInput('ssh-private-key');
@@ -131,113 +130,77 @@ try {
return;
}
var home;
if (isWindows) {
console.log('Preparing ssh-agent service on Windows');
child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' });
// Work around https://github.com/PowerShell/openssh-portable/pull/447 by creating a \dev\tty file
/*fs.mkdirSync('c:\\dev');
fs.closeSync(fs.openSync('c:\\dev\\tty', 'a'));
fs.mkdirSync('d:\\dev');
fs.closeSync(fs.openSync('d:\\dev\\tty', 'a'));*/
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';
console.log(`Adding GitHub.com keys to ${homeSsh}/known_hosts`);
fs.mkdirSync(homeSsh, { recursive: true });
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');
console.log("Starting ssh-agent");
const authSock = core.getInput('ssh-auth-sock');
let sshAgentOutput = ''
if (authSock && authSock.length > 0) {
sshAgentOutput = child_process.execFileSync('ssh-agent', ['-a', authSock]);
} else {
sshAgentOutput = child_process.execFileSync('ssh-agent')
}
const sshAgentArgs = (authSock && authSock.length > 0) ? ['-a', authSock] : [];
// 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])
child_process.execFileSync(sshAgent, sshAgentArgs).toString().split("\n").forEach(function(line) {
const matches = /^(SSH_AUTH_SOCK|SSH_AGENT_PID)=(.*); export \1/.exec(line);
if (matches && matches.length > 0) {
// This will also set process.env accordingly, so changes take effect for this script
core.exportVariable(matches[1], matches[2])
console.log(`${matches[1]}=${matches[2]}`);
}
}
console.log("Adding private keys to agent");
var keyNumber = 0;
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}`);
output = child_process.execFileSync('ssh-keygen', ['-p', '-f', keyFile, '-N', token]);
} catch (exception) {
fs.unlinkSync(keyFile);
throw exception;
}
// Load key into agent
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 {
child_process.execFileSync('ssh-add', [keyFile], { env: process.env, input: token });
}
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|\')/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
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}"`);
// 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)
//let identitiesOnly = isWindows ? 'no' : 'yes';
let sshConfig = `\nHost key-${keyNumber}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentitiesOnly yes\n`
+ ` AddKeysToAgent yes\n`
+ ` IdentityFile ${keyFile}\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key #${keyNumber} for GitHub repository ${ownerAndRepo}`);
});
});
console.log("Keys added:");
child_process.execSync('ssh-add -l', { stdio: 'inherit' });
console.log("Adding private key(s) to agent");
privateKey.split(/(?=-----BEGIN)/).forEach(function(key) {
child_process.execFileSync(sshAdd, ['-'], { input: key.trim() + "\n" });
});
console.log("Key(s) added:");
child_process.execFileSync(sshAdd, ['-l'], { stdio: 'inherit' });
console.log('Configuring deployment key(s)');
child_process.execFileSync(sshAdd, ['-L']).toString().split(/\r?\n/).forEach(function(key) {
const parts = key.match(/\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+)/i);
if (!parts) {
console.log(`Comment for key '${key}' does not match GitHub URL pattern. Not treating it as a GitHub deploy key.`);
return;
}
const sha256 = crypto.createHash('sha256').update(key).digest('hex');
const ownerAndRepo = parts[1].replace(/\.git$/, '');
fs.writeFileSync(`${homeSsh}/key-${sha256}`, key + "\n", { mode: '600' });
child_process.execSync(`git config --global --replace-all url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
const sshConfig = `\nHost key-${sha256}.github.com\n`
+ ` HostName github.com\n`
+ ` IdentityFile ${homeSsh}/key-${sha256}\n`
+ ` IdentitiesOnly yes\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use identity '${homeSsh}/key-${sha256}' for GitHub repository ${ownerAndRepo}`);
});
} catch (error) {
if (error.code == 'ENOENT') {
console.log(`The '${error.path}' executable could not be found. Please make sure it is on your PATH and/or the necessary packages are installed.`);
console.log(`PATH is set to: ${process.env.PATH}`);
}
core.setFailed(error.message);
}
@@ -601,6 +564,31 @@ module.exports = require("path");
module.exports = require("fs");
/***/ }),
/***/ 972:
/***/ (function(module, __unusedexports, __webpack_require__) {
const os = __webpack_require__(87);
module.exports = (process.env['OS'] != 'Windows_NT') ? {
// 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
home: os.userInfo().homedir,
sshAgent: 'ssh-agent',
sshAdd: 'ssh-add'
} : {
home: os.homedir(),
sshAgent: 'c://progra~1//git//usr//bin//ssh-agent.exe',
sshAdd: 'c://progra~1//git//usr//bin//ssh-add.exe'
};
/***/ })
/******/ });

147
index.js
View File

@@ -1,9 +1,8 @@
const core = require('@actions/core');
const child_process = require('child_process');
const fs = require('fs');
const os = require('os');
const token = require('crypto').randomBytes(64).toString('hex');
const isWindows = (process.env['OS'] == 'Windows_NT');
const crypto = require('crypto');
const { home, sshAgent, sshAdd } = require('./paths.js');
try {
const privateKey = core.getInput('ssh-private-key');
@@ -14,112 +13,76 @@ try {
return;
}
var home;
if (isWindows) {
console.log('Preparing ssh-agent service on Windows');
child_process.execSync('sc config ssh-agent start=demand', { stdio: 'inherit' });
// Work around https://github.com/PowerShell/openssh-portable/pull/447 by creating a \dev\tty file
/*fs.mkdirSync('c:\\dev');
fs.closeSync(fs.openSync('c:\\dev\\tty', 'a'));
fs.mkdirSync('d:\\dev');
fs.closeSync(fs.openSync('d:\\dev\\tty', 'a'));*/
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';
console.log(`Adding GitHub.com keys to ${homeSsh}/known_hosts`);
fs.mkdirSync(homeSsh, { recursive: true });
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');
console.log("Starting ssh-agent");
const authSock = core.getInput('ssh-auth-sock');
let sshAgentOutput = ''
if (authSock && authSock.length > 0) {
sshAgentOutput = child_process.execFileSync('ssh-agent', ['-a', authSock]);
} else {
sshAgentOutput = child_process.execFileSync('ssh-agent')
}
const sshAgentArgs = (authSock && authSock.length > 0) ? ['-a', authSock] : [];
// 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])
child_process.execFileSync(sshAgent, sshAgentArgs).toString().split("\n").forEach(function(line) {
const matches = /^(SSH_AUTH_SOCK|SSH_AGENT_PID)=(.*); export \1/.exec(line);
if (matches && matches.length > 0) {
// This will also set process.env accordingly, so changes take effect for this script
core.exportVariable(matches[1], matches[2])
console.log(`${matches[1]}=${matches[2]}`);
}
}
console.log("Adding private keys to agent");
var keyNumber = 0;
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}`);
output = child_process.execFileSync('ssh-keygen', ['-p', '-f', keyFile, '-N', token]);
} catch (exception) {
fs.unlinkSync(keyFile);
throw exception;
}
// Load key into agent
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 {
child_process.execFileSync('ssh-add', [keyFile], { env: process.env, input: token });
}
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|\')/);
if (parts == null) {
return;
}
let ownerAndRepo = parts[1];
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}"`);
// 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)
//let identitiesOnly = isWindows ? 'no' : 'yes';
let sshConfig = `\nHost key-${keyNumber}\n`
+ ` HostName github.com\n`
+ ` User git\n`
+ ` IdentitiesOnly yes\n`
+ ` AddKeysToAgent yes\n`
+ ` IdentityFile ${keyFile}\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use key #${keyNumber} for GitHub repository ${ownerAndRepo}`);
});
});
console.log("Keys added:");
child_process.execSync('ssh-add -l', { stdio: 'inherit' });
console.log("Adding private key(s) to agent");
privateKey.split(/(?=-----BEGIN)/).forEach(function(key) {
child_process.execFileSync(sshAdd, ['-'], { input: key.trim() + "\n" });
});
console.log("Key(s) added:");
child_process.execFileSync(sshAdd, ['-l'], { stdio: 'inherit' });
console.log('Configuring deployment key(s)');
child_process.execFileSync(sshAdd, ['-L']).toString().split(/\r?\n/).forEach(function(key) {
const parts = key.match(/\bgithub\.com[:/]([_.a-z0-9-]+\/[_.a-z0-9-]+)/i);
if (!parts) {
console.log(`Comment for key '${key}' does not match GitHub URL pattern. Not treating it as a GitHub deploy key.`);
return;
}
const sha256 = crypto.createHash('sha256').update(key).digest('hex');
const ownerAndRepo = parts[1].replace(/\.git$/, '');
fs.writeFileSync(`${homeSsh}/key-${sha256}`, key + "\n", { mode: '600' });
child_process.execSync(`git config --global --replace-all url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "https://github.com/${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "git@github.com:${ownerAndRepo}"`);
child_process.execSync(`git config --global --add url."git@key-${sha256}.github.com:${ownerAndRepo}".insteadOf "ssh://git@github.com/${ownerAndRepo}"`);
const sshConfig = `\nHost key-${sha256}.github.com\n`
+ ` HostName github.com\n`
+ ` IdentityFile ${homeSsh}/key-${sha256}\n`
+ ` IdentitiesOnly yes\n`;
fs.appendFileSync(`${homeSsh}/config`, sshConfig);
console.log(`Added deploy-key mapping: Use identity '${homeSsh}/key-${sha256}' for GitHub repository ${ownerAndRepo}`);
});
} catch (error) {
if (error.code == 'ENOENT') {
console.log(`The '${error.path}' executable could not be found. Please make sure it is on your PATH and/or the necessary packages are installed.`);
console.log(`PATH is set to: ${process.env.PATH}`);
}
core.setFailed(error.message);
}

18
paths.js Normal file
View File

@@ -0,0 +1,18 @@
const os = require('os');
module.exports = (process.env['OS'] != 'Windows_NT') ? {
// 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
home: os.userInfo().homedir,
sshAgent: 'ssh-agent',
sshAdd: 'ssh-add'
} : {
home: os.homedir(),
sshAgent: 'c://progra~1//git//usr//bin//ssh-agent.exe',
sshAdd: 'c://progra~1//git//usr//bin//ssh-add.exe'
};