@@ -10,49 +10,68 @@ import os from 'os';
10
10
*/
11
11
export async function setupSshCredentials ( ) : Promise < void > {
12
12
const homeDir = os . homedir ( ) ;
13
- const sshDir = `${ homeDir } /.ssh/` ;
14
- const sshConfigDir = `/opt/atlassian/pipelines/agent/ssh` ;
13
+ const sshDir = `${ homeDir } /.ssh` ;
14
+
15
+ // Bitbucket injects the SSH config into the container at these paths...
16
+ const sshConfigDir = '/opt/atlassian/pipelines/agent/ssh' ;
15
17
const identityFile = `${ sshConfigDir } /id_rsa_tmp` ;
16
18
const knownHostsFile = `${ sshConfigDir } /known_hosts` ;
17
19
18
- // Ensure the SSH directory exists, when `stat` throws an error, we know the directory doesn't exist
19
- const sshDirExists = await fs . promises
20
- . stat ( sshDir )
21
- . then ( ( stat ) => stat . isDirectory ( ) )
22
- . catch ( ( err ) => false ) ;
23
- if ( ! sshDirExists ) {
20
+ // ...and we copy them to the user's .ssh directory
21
+ const hostsFile = `${ sshDir } /known_hosts` ;
22
+ const pipelinesIdFile = `${ sshDir } /pipelines_id` ;
23
+ const configFile = `${ sshDir } /config` ;
24
+
25
+ // Ensure the SSH directory exists, we're OK to create it if it doesn't exist
26
+ if ( ! ( await pathExists ( sshDir ) ) ) {
24
27
await fs . promises . mkdir ( sshDir , { recursive : true } ) ;
25
28
}
26
29
27
- // Copy over the SSH identity file that Bitbucket has generated, if this fails then we should fail the whole pipeline
30
+ // Ensure all the required directories and files exist
31
+ // If these don't exist, we can't continue
32
+ const pathsToCheck = [
33
+ sshConfigDir ,
34
+ identityFile ,
35
+ knownHostsFile ,
36
+ configFile ,
37
+ ] ;
38
+ for ( const path of pathsToCheck ) {
39
+ if ( ! ( await pathExists ( path ) ) ) {
40
+ console . error (
41
+ `${ path } not found. Check that the SSH configuration is valid.`
42
+ ) ;
43
+ return ;
44
+ }
45
+ }
46
+
47
+ // Copy the Bitbucket injected identity file to the local .ssh directory
28
48
try {
29
49
console . log ( 'Attempting to copy SSH identity file...' ) ;
30
50
31
- const pipelinesIdFile = `${ sshDir } /pipelines_id` ;
32
51
await fs . promises . copyFile ( identityFile , pipelinesIdFile ) ;
33
52
34
53
console . log ( `Copied to ${ pipelinesIdFile } ` ) ;
35
54
console . log ( `Adding identity file config to config file` ) ;
36
55
37
- const configFile = `${ sshDir } /config` ;
38
56
await fs . promises . appendFile (
39
57
configFile ,
40
- `IdentityFile ${ pipelinesIdFile } `
58
+ `\nIdentityFile ${ pipelinesIdFile } \n `
41
59
) ;
42
60
} catch ( e ) {
43
61
console . error (
44
- 'Failed to update SSH configuration, check that SSH key configuration in Pipelines is valid. \n Check Pipelines -> SSH Keys.'
62
+ `Failed to update SSH configuration, check that SSH key configuration in Pipelines is valid. \n Check Pipelines -> SSH Keys.\n\n ${
63
+ ( e as Error ) . message
64
+ } `
45
65
) ;
46
66
return ;
47
67
}
48
68
49
- // Copy over the known_hosts file that Bitbucket generated
69
+ // Copy the Bitbucket injected known hosts file to the local .ssh directory
50
70
try {
51
71
console . log ( 'Piping known hosts into runtime ssh config' ) ;
52
72
const knownHosts = await fs . promises
53
73
. readFile ( knownHostsFile )
54
- . then ( ( buf ) => buf . toString ( ) ) ;
55
- const hostsFile = `${ sshDir } /known_hosts` ;
74
+ . then ( ( buf ) => `\n${ buf . toString ( ) } \n` ) ;
56
75
await fs . promises . appendFile ( hostsFile , knownHosts ) ;
57
76
} catch ( e ) {
58
77
console . error (
@@ -89,3 +108,14 @@ async function chmodRecursive(path: fs.PathLike, mode: fs.Mode): Promise<void> {
89
108
}
90
109
}
91
110
}
111
+
112
+ async function pathExists ( path : fs . PathLike ) : Promise < boolean > {
113
+ console . log ( `Checking if ${ path } exists` ) ;
114
+ // An error _typically_ means the object at `path` doesn't exist
115
+ // Though we may want to check whether the error is a permission error
116
+ // or a file not found error (the latter is OK)
117
+ return fs . promises
118
+ . stat ( path )
119
+ . then ( ( _ ) => true )
120
+ . catch ( ( _ ) => false ) ;
121
+ }
0 commit comments