Skip to content

Commit bf9f18e

Browse files
authored
Merge pull request #105 from vadz/fix-option-validity-check
Fix checking validity of tmate-server-xxx parameters
2 parents f309efd + dc9bdec commit bf9f18e

5 files changed

Lines changed: 93 additions & 19 deletions

File tree

action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ inputs:
2020
required: false
2121
default: 'false'
2222
tmate-server-host:
23-
description: 'The hostname for your tmate server'
23+
description: 'The hostname for your tmate server (e.g. ssh.example.org)'
2424
required: false
2525
default: ''
2626
tmate-server-port:
27-
description: 'The port for your tmate server'
27+
description: 'The port for your tmate server (e.g. 2222)'
2828
required: false
2929
default: ''
3030
tmate-server-rsa-fingerprint:

lib/index.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10282,11 +10282,12 @@ const execShellCommand = (cmd) => {
1028210282

1028310283
/**
1028410284
* @param {string} key
10285-
* @return {string}
10285+
* @param {regex} re regex to use for validation
10286+
* @return {string}, {undefined} or throws an error if input doesn't match regex
1028610287
*/
10287-
const getValidatedInput = (key) => {
10288+
const getValidatedInput = (key, re) => {
1028810289
const value = core.getInput(key);
10289-
if (/^[-.+A-Za-z0-9]*$/.test(value)) {
10290+
if (value !== undefined && !re.test(value)) {
1029010291
throw new Error(`Invalid value for '${key}': '${value}'`);
1029110292
}
1029210293
return value;
@@ -10406,11 +10407,21 @@ async function run() {
1040610407
await execShellCommand(`echo 'set +e' >/tmp/tmate.bashrc`);
1040710408
let setDefaultCommand = `set-option -g default-command "bash --rcfile /tmp/tmate.bashrc" \\;`;
1040810409

10409-
if (core.getInput("tmate-server-host") !== "") {
10410-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-host "${getValidatedInput("tmate-server-host")}" \\;`;
10411-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-port "${getValidatedInput("tmate-server-port")}" \\;`;
10412-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-rsa-fingerprint "${getValidatedInput("tmate-server-rsa-fingerprint")}" \\;`;
10413-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-ed25519-fingerprint "${getValidatedInput("tmate-server-ed25519-fingerprint")}" \\;`;
10410+
// The regexes used here for validation are lenient, i.e. may accept
10411+
// values that are not, strictly speaking, valid, but should be good
10412+
// enough for detecting obvious errors, which is all we want here.
10413+
const options = {
10414+
"tmate-server-host": /^[a-z\d\-]+(\.[a-z\d\-]+)*$/i,
10415+
"tmate-server-port": /^\d{1,5}$/,
10416+
"tmate-server-rsa-fingerprint": /./,
10417+
"tmate-server-ed25519-fingerprint": /./,
10418+
}
10419+
10420+
for (const opt in options) {
10421+
const value = getValidatedInput(opt, options[opt]);
10422+
if (value !== undefined) {
10423+
setDefaultCommand = `${setDefaultCommand} set-option -g ${opt} "${value}" \\;`;
10424+
}
1041410425
}
1041510426

1041610427
core.debug("Creating new session")

src/helpers.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,12 @@ export const execShellCommand = (cmd) => {
4141

4242
/**
4343
* @param {string} key
44-
* @return {string}
44+
* @param {regex} re regex to use for validation
45+
* @return {string}, {undefined} or throws an error if input doesn't match regex
4546
*/
46-
export const getValidatedInput = (key) => {
47+
export const getValidatedInput = (key, re) => {
4748
const value = core.getInput(key);
48-
if (/^[-.+A-Za-z0-9]*$/.test(value)) {
49+
if (value !== undefined && !re.test(value)) {
4950
throw new Error(`Invalid value for '${key}': '${value}'`);
5051
}
5152
return value;

src/index.js

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -97,11 +97,21 @@ export async function run() {
9797
await execShellCommand(`echo 'set +e' >/tmp/tmate.bashrc`);
9898
let setDefaultCommand = `set-option -g default-command "bash --rcfile /tmp/tmate.bashrc" \\;`;
9999

100-
if (core.getInput("tmate-server-host") !== "") {
101-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-host "${getValidatedInput("tmate-server-host")}" \\;`;
102-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-port "${getValidatedInput("tmate-server-port")}" \\;`;
103-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-rsa-fingerprint "${getValidatedInput("tmate-server-rsa-fingerprint")}" \\;`;
104-
setDefaultCommand = `${setDefaultCommand} set-option -g tmate-server-ed25519-fingerprint "${getValidatedInput("tmate-server-ed25519-fingerprint")}" \\;`;
100+
// The regexes used here for validation are lenient, i.e. may accept
101+
// values that are not, strictly speaking, valid, but should be good
102+
// enough for detecting obvious errors, which is all we want here.
103+
const options = {
104+
"tmate-server-host": /^[a-z\d\-]+(\.[a-z\d\-]+)*$/i,
105+
"tmate-server-port": /^\d{1,5}$/,
106+
"tmate-server-rsa-fingerprint": /./,
107+
"tmate-server-ed25519-fingerprint": /./,
108+
}
109+
110+
for (const opt in options) {
111+
const value = getValidatedInput(opt, options[opt]);
112+
if (value !== undefined) {
113+
setDefaultCommand = `${setDefaultCommand} set-option -g ${opt} "${value}" \\;`;
114+
}
105115
}
106116

107117
core.debug("Creating new session")

src/index.test.js

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,14 @@ jest.mock("fs", () => ({
1111
unlinkSync: () => true,
1212
writeFileSync: () => true
1313
}));
14-
jest.mock('./helpers');
14+
jest.mock('./helpers', () => {
15+
const originalModule = jest.requireActual('./helpers');
16+
return {
17+
__esModule: true,
18+
...originalModule,
19+
execShellCommand: jest.fn(() => 'mocked execShellCommand'),
20+
};
21+
});
1522
import { execShellCommand } from "./helpers"
1623
import { run } from "."
1724

@@ -106,4 +113,49 @@ describe('Tmate GitHub integration', () => {
106113
await run()
107114
expect(execShellCommand).not.toHaveBeenNthCalledWith(1, "brew install tmate")
108115
});
116+
it('should validate correct tmate options', async () => {
117+
// Check for the happy path first.
118+
core.getInput.mockImplementation(function(opt) {
119+
switch (opt) {
120+
case "tmate-server-host": return "ssh.tmate.io";
121+
case "tmate-server-port": return "22";
122+
case "tmate-server-rsa-fingerprint": return "SHA256:Hthk2T/M/Ivqfk1YYUn5ijC2Att3+UPzD7Rn72P5VWs";
123+
case "tmate-server-ed25519-fingerprint": return "SHA256:jfttvoypkHiQYUqUCwKeqd9d1fJj/ZiQlFOHVl6E9sI";
124+
default: return undefined;
125+
}
126+
})
127+
128+
await run()
129+
130+
// Find the command launching tmate with its various options.
131+
let tmateCmd;
132+
for (const call of execShellCommand.mock.calls) {
133+
const cmd = call[0]
134+
if (cmd.includes("set-option -g")) {
135+
tmateCmd = cmd
136+
break
137+
}
138+
}
139+
140+
expect(tmateCmd).toBeDefined();
141+
142+
const re = /set-option -g tmate-server-host "([^"]+)"/;
143+
const match = re.exec(tmateCmd);
144+
expect(match).toBeTruthy();
145+
expect(match[1]).toEqual("ssh.tmate.io");
146+
});
147+
it('should fail to validate wrong tmate options', async () => {
148+
core.getInput.mockImplementation(function(opt) {
149+
switch (opt) {
150+
case "tmate-server-host": return "not/a/valid/hostname";
151+
default: return undefined;
152+
}
153+
})
154+
155+
await run()
156+
157+
expect(core.setFailed).toHaveBeenCalledWith(
158+
Error("Invalid value for 'tmate-server-host': 'not/a/valid/hostname'")
159+
)
160+
});
109161
});

0 commit comments

Comments
 (0)