@milaboratories/pl-deployments 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -44
- package/dist/index.mjs.map +1 -1
- package/dist/ssh/__tests__/common-utils.d.ts.map +1 -1
- package/dist/ssh/ssh.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/local/pl.test.ts +1 -1
- package/src/ssh/__tests__/common-utils.ts +10 -9
- package/src/ssh/__tests__/pl-docker.test.ts +1 -1
- package/src/ssh/__tests__/ssh-docker.test.ts +55 -2
- package/src/ssh/ssh.ts +13 -4
- package/src/ssh/Dockerfile +0 -29
- package/src/ssh/test-assets/simple-server.js +0 -10
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StartedTestContainer } from 'testcontainers';
|
|
1
2
|
import { describe, it, beforeAll, afterAll, expect } from 'vitest';
|
|
2
3
|
import { writeFileSync, readFileSync } from 'fs';
|
|
3
4
|
import { SshClient } from '../ssh';
|
|
@@ -6,9 +7,10 @@ import { downloadsFolder, cleanUp, getConnectionForSsh, getContainerHostAndPort,
|
|
|
6
7
|
import { ConsoleLoggerAdapter } from '@milaboratories/ts-helpers';
|
|
7
8
|
|
|
8
9
|
let client: SshClient;
|
|
9
|
-
|
|
10
|
+
let testContainer: StartedTestContainer;
|
|
10
11
|
|
|
11
12
|
beforeAll(async () => {
|
|
13
|
+
testContainer = await initContainer('ssh');
|
|
12
14
|
client = await SshClient.init(new ConsoleLoggerAdapter(), getConnectionForSsh(testContainer));
|
|
13
15
|
});
|
|
14
16
|
|
|
@@ -143,7 +145,58 @@ describe('sshConnect', () => {
|
|
|
143
145
|
});
|
|
144
146
|
|
|
145
147
|
it('should fail with invalid credentials', async () => {
|
|
146
|
-
await expect(SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer),
|
|
148
|
+
await expect(SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer), username: 'dfasdfa' })).rejects.toThrow();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should fail with invalid passphrase', async () => {
|
|
152
|
+
let catched = false;
|
|
153
|
+
try {
|
|
154
|
+
await SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer), passphrase: 'dfasdfa' });
|
|
155
|
+
} catch (e) {
|
|
156
|
+
console.log(e);
|
|
157
|
+
expect((e as Error).message.includes('Cannot parse privateKey: OpenSSH key integrity check failed')).toBe(true);
|
|
158
|
+
catched = true;
|
|
159
|
+
}
|
|
160
|
+
expect(catched).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it('should fail with invalid username', async () => {
|
|
164
|
+
let catched = false;
|
|
165
|
+
try {
|
|
166
|
+
await SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer), username: 'dfasdfa' });
|
|
167
|
+
} catch (e) {
|
|
168
|
+
console.log(e);
|
|
169
|
+
expect((e as Error).message.includes('All configured authentication methods failed')).toBe(true);
|
|
170
|
+
catched = true;
|
|
171
|
+
}
|
|
172
|
+
expect(catched).toBe(true);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should fail with invalid host', async () => {
|
|
176
|
+
let catched = false;
|
|
177
|
+
try {
|
|
178
|
+
await SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer), host: '192.100.100.100' });
|
|
179
|
+
} catch (e) {
|
|
180
|
+
console.log(e);
|
|
181
|
+
expect((e as Error).message.includes('Timed out while waiting for handshake')).toBe(true);
|
|
182
|
+
catched = true;
|
|
183
|
+
}
|
|
184
|
+
expect(catched).toBe(true);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should fail with invalid private key', async () => {
|
|
188
|
+
let catched = false;
|
|
189
|
+
|
|
190
|
+
const invalidPk = ssh.utils.generateKeyPairSync('ecdsa', { bits: 256, comment: 'node.js rules!', passphrase: 'password', cipher: 'aes256-cbc' });
|
|
191
|
+
|
|
192
|
+
try {
|
|
193
|
+
await SshClient.init(new ConsoleLoggerAdapter(), { ...getConnectionForSsh(testContainer), privateKey: invalidPk.private, passphrase: 'password' });
|
|
194
|
+
} catch (e) {
|
|
195
|
+
console.log(e);
|
|
196
|
+
expect((e as Error).message.includes('All configured authentication methods failed')).toBe(true);
|
|
197
|
+
catched = true;
|
|
198
|
+
}
|
|
199
|
+
expect(catched).toBe(true);
|
|
147
200
|
});
|
|
148
201
|
|
|
149
202
|
it('should timeout if the server is unreachable', async () => {
|
package/src/ssh/ssh.ts
CHANGED
|
@@ -6,7 +6,11 @@ import fs from 'fs';
|
|
|
6
6
|
import { readFile } from 'fs/promises';
|
|
7
7
|
import upath from 'upath';
|
|
8
8
|
import type { MiLogger } from '@milaboratories/ts-helpers';
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
const defaultConfig: ConnectConfig = {
|
|
11
|
+
keepaliveInterval: 60000,
|
|
12
|
+
keepaliveCountMax: 10,
|
|
13
|
+
}
|
|
10
14
|
|
|
11
15
|
export type SshAuthMethods = 'publickey' | 'password';
|
|
12
16
|
export type SshAuthMethodsResult = SshAuthMethods[];
|
|
@@ -26,8 +30,13 @@ export class SshClient {
|
|
|
26
30
|
* @returns A new instance of SshClient with an active connection.
|
|
27
31
|
*/
|
|
28
32
|
public static async init(logger: MiLogger, config: ConnectConfig): Promise<SshClient> {
|
|
33
|
+
const withDefaults = {
|
|
34
|
+
...defaultConfig,
|
|
35
|
+
...config
|
|
36
|
+
};
|
|
37
|
+
|
|
29
38
|
const client = new SshClient(logger, new Client());
|
|
30
|
-
await client.connect(
|
|
39
|
+
await client.connect(withDefaults);
|
|
31
40
|
|
|
32
41
|
return client;
|
|
33
42
|
}
|
|
@@ -178,13 +187,13 @@ export class SshClient {
|
|
|
178
187
|
});
|
|
179
188
|
|
|
180
189
|
conn.on('error', (err) => {
|
|
181
|
-
|
|
190
|
+
this.logger.error(`[SSH] SSH connection error, ports: ${JSON.stringify(ports)}, err: ${err.message}`);
|
|
182
191
|
server?.close();
|
|
183
192
|
reject(`ssh.forwardPort: conn.err: ${err}`);
|
|
184
193
|
});
|
|
185
194
|
|
|
186
195
|
conn.on('close', () => {
|
|
187
|
-
this.logger.info(`[SSH] Connection closed, ports: ${ports}`);
|
|
196
|
+
this.logger.info(`[SSH] Connection closed, ports: ${JSON.stringify(ports)}`);
|
|
188
197
|
});
|
|
189
198
|
|
|
190
199
|
conn.connect(config);
|
package/src/ssh/Dockerfile
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
FROM node:20
|
|
2
|
-
|
|
3
|
-
RUN apt-get update && \
|
|
4
|
-
apt-get install -y openssh-server && \
|
|
5
|
-
mkdir /var/run/sshd
|
|
6
|
-
|
|
7
|
-
# RUN echo 'root:rootpassword' | chpasswd
|
|
8
|
-
|
|
9
|
-
RUN useradd 'pl-doctor'
|
|
10
|
-
RUN echo 'pl-doctor:pl-doctor-password' | chpasswd
|
|
11
|
-
|
|
12
|
-
RUN sed -i 's/^#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config && \
|
|
13
|
-
sed -i 's/^#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
|
|
14
|
-
|
|
15
|
-
RUN apt-get install -y locales && \
|
|
16
|
-
locale-gen en_US.UTF-8
|
|
17
|
-
ENV LANG en_US.UTF-8
|
|
18
|
-
|
|
19
|
-
EXPOSE 22 3001
|
|
20
|
-
|
|
21
|
-
COPY ./test-assets/pub-key.pub /home/pl-doctor/.ssh/authorized_keys
|
|
22
|
-
COPY ./test-assets/simple-server.js /home/pl-doctor/simple-server.js
|
|
23
|
-
|
|
24
|
-
RUN chmod 755 /home/pl-doctor
|
|
25
|
-
RUN chown pl-doctor:pl-doctor /home/pl-doctor
|
|
26
|
-
|
|
27
|
-
RUN chmod +x /home/pl-doctor/simple-server.js
|
|
28
|
-
|
|
29
|
-
CMD ["/bin/bash", "-c", "/usr/sbin/sshd -D & node /home/pl-doctor/simple-server.js"]
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
const http = require('http');
|
|
2
|
-
const PORT = 3001;
|
|
3
|
-
const MESSAGE = "Hello, this is a simple Node.js server!";
|
|
4
|
-
const server = http.createServer((req, res) => {
|
|
5
|
-
res.writeHead(200, { 'Content-Type': 'text/plain' });
|
|
6
|
-
res.end(MESSAGE);
|
|
7
|
-
});
|
|
8
|
-
server.listen(PORT, () => {
|
|
9
|
-
console.log(`Server is running on port ${PORT}`);
|
|
10
|
-
});
|