8000 Native SSH Key Support (#569) · lyrl/github-pages-deploy-action@64eb711 · GitHub
[go: up one dir, main page]

Skip to content 8000

Commit 64eb711

Browse files
JamesIvesPike
andauthored
Native SSH Key Support (JamesIves#569)
* SSH Key Support 🔑 * Update ssh.ts * Update src/ssh.ts Co-authored-by: Axel Hecht <axel@pike.org> * README fixes/etc * Unit Tests & README * ssh key * Update README.md * Update ssh.test.ts * Update ssh.test.ts * Update ssh.test.ts * Update ssh.test.ts * Update ssh.test.ts * Update ssh.test.ts * Update integration.yml Co-authored-by: Axel Hecht <axel@pike.org>
1 parent e00d6bf commit 64eb711

File tree

10 files changed

+224
-47
lines changed

10 files changed

+224
-47
lines changed

.github/workflows/integration.yml

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,30 @@ jobs:
9090

9191
# Deploys using an SSH key.
9292
integration-ssh:
93+
needs: integration-container
94+
runs-on: ubuntu-latest
95+
steps:
96+
- name: Checkout
97+
uses: actions/checkout@v2
98+
with:
99+
persist-credentials: false
100+
101+
- name: Build and Deploy
102+
uses: JamesIves/github-pages-deploy-action@releases/v4
103+
with:
104+
ssh-key: ${{ secrets.DEPLOY_KEY }}
105+
branch: gh-pages
106+
folder: integration
107+
target-folder: cat/montezuma3
108+
109+
- name: Cleanup Generated Branch
110+
uses: dawidd6/action-delete-branch@v2.0.1
111+
with:
112+
github_token: ${{ secrets.GITHUB_TOKEN }}
113+
branches: gh-pages
114+
115+
# Deploys using an SSH key.
116+
integration-ssh-third-party-client:
93117
needs: integration-container
94118
runs-on: ubuntu-latest
95119
steps:
@@ -109,7 +133,7 @@ jobs:
109133
ssh: true
110134
branch: gh-pages
111135
folder: integration
112-
target-folder: cat/montezuma3
136+
target-folder: cat/montezuma4
113137

114138
- name: Cleanup Generated Branch
115139
uses: dawidd6/action-delete-branch@v2.0.1
@@ -131,15 +155,10 @@ jobs:
131155
with:
132156
persist-credentials: false
133157

134-
- name: Install SSH Client
135-
uses: webfactory/ssh-agent@v0.4.1
136-
with:
137-
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
138-
139158
- name: Build and Deploy
140159
uses: JamesIves/github-pages-deploy-action@releases/v4
141160
with:
142-
ssh: true
161+
ssh-key: ${{ secrets.DEPLOY_KEY }}
143162
branch: gh-pages
144163
folder: integration
145164
target-folder: cat/montezuma4

README.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ By default the action does not need any token configuration and uses the provide
132132
| Key | Value Information | Type | Required |
133133
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | -------- |
134134
| `token` | This option defaults to the repository scoped GitHub Token. However if you need more permissions for things such as deploying to another repository, you can add a Personal Access Token (PAT) here. This should be stored in the `secrets / with` menu **as a secret**. We reccomend using a service account with the least permissions neccersary and recommend when generating a new PAT that you select the least permission scopes neccersary. [Learn more about creating and using encrypted secrets here.](https://help.github.com/en/actions/automating-your-workflow-with-github-actions/creating-and-using-encrypted-secrets) | **No** |
135-
| `ssh` | You can configure the action to deploy using SSH by setting this option to `true`. For more information on how to add your ssh key pair please refer to the [Using a Deploy Key section of this README](https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key-). | `with` | **No** |
135+
| `ssh-key` | You can configure the action to deploy using SSH by setting this option to a private SSH key stored **as a secret**. It can also be set to `true` to use an existing SSH client configuration. For more detailed information on how to add your ssh key pair please refer to the [Using a Deploy Key section of this README](https://github.com/JamesIves/github-pages-deploy-action/tree/dev#using-an-ssh-deploy-key-). | `with` | **No** |
136136

137137
#### Optional Choices
138138

@@ -176,20 +176,15 @@ ssh-keygen -t rsa -m pem -b 4096 -C "youremailhere@example.com" -N ""
176176

177177
Once you've generated the key pair you must add the contents of the public key within your repository's [deploy keys menu](https://developer.github.com/v3/guides/managing-deploy-keys/). You can find this option by going to `Settings > Deploy Keys`, you can name the public key whatever you want, but you **do** need to give it write access. Afterwards add the contents of the private key to the `Settings > Secrets` menu as `DEPLOY_KEY`.
178178

179-
With this configured you must add the `ssh-agent` step to your workflow and set `ssh` to `true` within the deploy action. There are several SSH actions available on the [GitHub marketplace](https://github.com/marketplace?type=actions) for you to choose from.
179+
With this configured you can then set the `ssh-key` part of the action to your private key stored as a secret.
180180

181181
```yml
182-
- name: Install SSH Client 🔑
183-
uses: webfactory/ssh-agent@v0.4.1
184-
with:
185-
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
186-
187182
- name: Deploy 🚀
188183
uses: JamesIves/github-pages-deploy-action@3.7.1
189184
with:
190-
ssh: true
19118 8000 5
branch: gh-pages
192186
folder: site
187+
ssh-key: ${{ secrets.DEPLOY_KEY }}
193188
```
194189
195190
<details><summary>You can view a full example of this here.</summary>
@@ -215,11 +210,6 @@ jobs:
215210
npm install
216211
npm run build
217212
218-
- name: Install SSH Client 🔑
219-
uses: webfactory/ssh-agent@v0.4.1 # This step installs the ssh client into the workflow run. There's many options available for this on the action marketplace.
220-
with:
221-
ssh-private-key: ${{ secrets.DEPLOY_KEY }}
222-
223213
- name: Deploy 🚀
224214
uses: JamesIves/github-pages-deploy-action@3.7.1
225215
with:
@@ -229,12 +219,14 @@ jobs:
229219
clean-exclude: |
230220
special-file.txt
231221
some/*.txt
232-
ssh: true # SSH must be set to true so the deploy action knows which protocol to deploy with.
222+
ssh-key: ${{ secrets.DEPLOY_KEY }}
233223
```
234224
235225
</p>
236226
</details>
237227
228+
Alternatively if you've already configured the SSH client within a previous step you can set the `ssh-key` option to `true` to allow it to deploy using an existing SSH client. Instead of adjusting the client configuration it will simply switch to using GitHub's SSH endpoints.
229+
238230
---
239231

240232
### Operating System Support 💿

__tests__/main.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ describe('main', () => {
6060
folder: 'assets',
6161
branch: 'branch',
6262
token: '123',
63+
sshKey: true,
6364
pusher: {
6465
name: 'asd',
6566
email: 'as@cat'
@@ -77,7 +78,7 @@ describe('main', () => {
7778
folder: 'assets',
7879
branch: 'branch',
7980
token: null,
80-
ssh: null,
81+
sshKey: null,
8182
pusher: {
8283
name: 'asd',
8384
email: 'as@cat'

__tests__/ssh.test.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import {mkdirP} from '@actions/io'
2+
import {appendFileSync} from 'fs'
3+
import {action, TestFlag} from '../src/constants'
4+
import {execute} from '../src/execute'
5+
import {configureSSH} from '../src/ssh'
6+
7+
const originalAction = JSON.stringify(action)
8+
9+
jest.mock('fs', () => ({
10+
appendFileSync: jest.fn(),
11+
existsSync: jest.fn()
12+
}))
13+
14+
jest.mock('@actions/io', () => ({
15+
rmRF: jest.fn(),
16+
mkdirP: jest.fn()
17+
}))
18+
19+
jest.mock('@actions/core', () => ({
20+
setFailed: jest.fn(),
21+
getInput: jest.fn(),
22+
setOutput: jest.fn(),
23+
isDebug: jest.fn(),
24+
info: jest.fn()
25+
}))
26+
27+
jest.mock('../src/execute', () => ({
28+
// eslint-disable-next-line @typescript-eslint/naming-convention
29+
__esModule: true,
30+
execute: jest.fn()
31+
}))
32+
33+
describe('configureSSH', () => {
34+
afterEach(() => {
35+
Object.assign(action, JSON.parse(originalAction))
36+
})
37+
38+
it('should skip client configuration if sshKey is set to true', async () => {
39+
Object.assign(action, {
40+
silent: false,
41+
folder: 'assets',
42+
branch: 'branch',
43+
sshKey: true,
44+
pusher: {
45+
name: 'asd',
46+
email: 'as@cat'
47+
},
48+
isTest: TestFlag.HAS_CHANGED_FILES
49+
})
50+
51+
await configureSSH(action)
52+
53+
expect(execute).toBeCalledTimes(0)
54+
expect(mkdirP).toBeCalledTimes(0)
55+
expect(appendFileSync).toBeCalledTimes(0)
56+
})
57+
58+
it('should configure the ssh client if a key is defined', async () => {
59+
Object.assign(action, {
60+
silent: false,
61+
folder: 'assets',
62+
branch: 'branch',
63+
sshKey: '?=-----BEGIN 123 456\n 789',
64+
pusher: {
65+
name: 'asd',
66+
email: 'as@cat'
67+
},
68+
isTest: TestFlag.HAS_CHANGED_FILES
69+
})
70+
71+
await configureSSH(action)
72+
73+
expect(execute).toBeCalledTimes(4)
74+
expect(mkdirP).toBeCalledTimes(1)
75+
expect(appendFileSync).toBeCalledTimes(2)
76+
})
77+
78+
it('should throw if something errors', async () => {
79+
;(execute as jest.Mock).mockImplementationOnce(() => {
80+
throw new Error('Mocked throw')
81+
})
82+
83+
Object.assign(action, {
84+
silent: false,
85+
folder: 'assets',
86+
branch: 'branch',
87+
sshKey: 'real_key',
88+
pusher: {
89+
name: 'asd',
90+
email: 'as@cat'
91+
},
92+
isTest: TestFlag.HAS_CHANGED_FILES
93+
})
94+
95+
A3E7 try {
96+
await configureSSH(action)
97+
} catch (error) {
98+
expect(error.message).toBe(
99+
'The ssh client configuration encountered an error: Mocked throw ❌'
100+
)
101+
}
102+
})
103+
})

__tests__/util.test.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ describe('util', () => {
3838
workspace: 'src/',
3939
folder: 'build',
4040
token: null,
41-
ssh: true,
41+
sshKey: 'real_token',
4242
silent: false,
4343
isTest: TestFlag.NONE
4444
}
@@ -51,7 +51,7 @@ describe('util', () => {
5151
workspace: 'src/',
5252
folder: 'build',
5353
token: '123',
54-
ssh: null,
54+
sshKey: null,
5555
silent: false,
5656
isTest: TestFlag.NONE
5757
}
@@ -64,7 +64,7 @@ describe('util', () => {
6464
workspace: 'src/',
6565
folder: 'build',
6666
token: null,
67-
ssh: null,
67+
sshKey: null,
6868
silent: false,
6969
isTest: TestFlag.NONE
7070
}
@@ -80,7 +80,7 @@ describe('util', () => {
8080
workspace: 'src/',
8181
folder: 'build',
8282
token: null,
83-
ssh: true,
83+
sshKey: 'real_token',
8484
silent: false,
8585
isTest: TestFlag.NONE
8686
}
@@ -96,7 +96,7 @@ describe('util', () => {
9696
workspace: 'src/',
9797
folder: 'build',
9898
token: '123',
99-
ssh: null,
99+
sshKey: null,
100100
silent: false,
101101
isTest: TestFlag.NONE
102102
}
@@ -155,7 +155,7 @@ describe('util', () => {
155155
workspace: 'src/',
156156
folder: 'build',
157157
token: null,
158-
ssh: null,
158+
sshKey: null,
159159
silent: false,
160160
isTest: TestFlag.NONE
161161
}
@@ -168,7 +168,7 @@ describe('util', () => {
168168
workspace: 'src/',
169169
folder: '/home/user/repo/build',
170170
token: null,
171-
ssh: null,
171+
sshKey: null,
172172
silent: false,
173173
isTest: TestFlag.NONE
174174
}
@@ -181,7 +181,7 @@ describe('util', () => {
181181
workspace: 'src/',
182182
folder: './build',
183183
token: null,
184-
ssh: null,
184+
sshKey: null,
185185
silent: false,
186186
isTest: TestFlag.NONE
187187
}
@@ -194,7 +194,7 @@ describe('util', () => {
194194
workspace: 'src/',
195195
folder: '~/repo/build',
196196
token: null,
197-
ssh: null,
197+
sshKey: null,
198198
silent: false,
199199
isTest: TestFlag.NONE
200200
}

action.yml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,14 @@ branding:
88
icon: 'git-commit'
99
color: 'orange'
1010
inputs:
11-
ssh:
12-
description: 'You can configure the action to deploy using SSH by setting this option to true. More more information on how to add your ssh key pair please refer to the Using a Deploy Key section of this README.'
11+
ssh-key:
12+
description: >
13+
This option allows you to define a private SSH key to be used in conjunction with a repository deployment key to deploy using SSH.
14+
The private key should be stored in the `secrets / with` menu **as a secret**. The public should be stored in the repositories deployment
15+
keys menu and be given write access.
16+
17+
Alternatively you can set this field to `true` to enable SSH endpoints for deployment without configuring the ssh client. This can be useful if you've
18+
already setup the SSH client using another package or action in a previous step.
1319
required: false
1420

1521
token:

src/constants.ts

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ export interface ActionInterface {
4141
singleCommit?: boolean | null
4242
/** Determines if the action should run in silent mode or not. */
4343
silent: boolean
44-
/** Set to true if you're using an ssh client in your build step. */
45-
ssh?: boolean | null
44+
/** Defines an SSH private key that can be used during deployment. This can also be set to true to use SSH deployment endpoints if you've already configured the SSH client outside of this package. */
45+
sshKey?: string | boolean | null
4646
/** If you'd like to push the contents of the deployment folder into a specific directory on the deployment branch you can specify it here. */
4747
targetFolder?: string
4848
/** Deployment token. */
@@ -65,10 +65,11 @@ export interface NodeActionInterface {
6565
token?: string | null
6666
/** Determines if the action should run in silent mode or not. */
6767
silent: boolean
68-
/** Set to true if you're using an ssh client in your build step. */
69-
ssh?: boolean | null
68+
/** Defines an SSH private key that can be used during deployment. This can also be set to true to use SSH deployment endpoints if you've already configured the SSH client outside of this package. */
69+
sshKey?: string | boolean | null
7070
/** The folder where your deployment project lives. */
7171
workspace: string
72+
/** Determines test scenarios the action is running in. */
7273
isTest: TestFlag
7374
}
7475

@@ -113,17 +114,20 @@ export const action: ActionInterface = {
113114
silent: !isNullOrUndefined(getInput('silent'))
114115
? getInput('silent').toLowerCase() === 'true'
115116
: false,
116-
ssh: !isNullOrUndefined(getInput('ssh'))
117-
? getInput('ssh').toLowerCase() === 'true'
118-
: false,
117+
sshKey: isNullOrUndefined(getInput('ssh-key'))
118+
? false
119+
: !isNullOrUndefined(getInput('ssh-key')) &&
120+
getInput('ssh-key').toLowerCase() === 'true'
121+
? true
122+
: getInput('ssh-key'),
119123
targetFolder: getInput('target-folder'),
120124
workspace: process.env.GITHUB_WORKSPACE || ''
121125
}
122126

123127
/** Types for the required action parameters. */
124128
export type RequiredActionParameters = Pick<
125129
ActionInterface,
126-
'token' | 'ssh' | 'branch' | 'folder' | 'isTest'
130+
'token' | 'sshKey' | 'branch' | 'folder' | 'isTest'
127131
>
128132

129133
/** Status codes for the action. */

0 commit comments

Comments
 (0)
0