2
0

Test that stdin gets forwarded correctly

Co-Authored-By: Sergio Padrino <1083228+sergiou87@users.noreply.github.com>
This commit is contained in:
Markus Olsson
2024-06-03 11:47:33 +02:00
parent f99853f6f5
commit 6052251d32
3 changed files with 89 additions and 21 deletions

3
index.d.ts vendored
View File

@@ -1,5 +1,8 @@
export function getDesktopAskpassTrampolinePath(): string
export function getDesktopAskpassTrampolineFilename(): string
export function getDesktopCredentialHelperTrampolinePath(): string
export function getDesktopCredentialHelperTrampolineFilename(): string
export function getSSHWrapperPath(): string
export function getSSHWrapperFilename(): string

View File

@@ -15,6 +15,21 @@ function getDesktopAskpassTrampolineFilename() {
: 'desktop-askpass-trampoline'
}
function getDesktopCredentialHelperTrampolinePath() {
return Path.join(
__dirname,
'build',
'Release',
getDesktopCredentialHelperTrampolineFilename()
)
}
function getDesktopCredentialHelperTrampolineFilename() {
return process.platform === 'win32'
? 'desktop-credential-helper-trampoline.exe'
: 'desktop-credential-helper-trampoline'
}
function getSSHWrapperPath() {
return Path.join(__dirname, 'build', 'Release', getSSHWrapperFilename())
}
@@ -26,6 +41,8 @@ function getSSHWrapperFilename() {
module.exports = {
getDesktopAskpassTrampolinePath,
getDesktopAskpassTrampolineFilename,
getDesktopCredentialHelperTrampolinePath,
getDesktopCredentialHelperTrampolineFilename,
getSSHWrapperPath,
getSSHWrapperFilename,
}

View File

@@ -2,46 +2,67 @@ const { stat, access } = require('fs').promises
const { constants } = require('fs')
const { execFile } = require('child_process')
const { promisify } = require('util')
const { getDesktopAskpassTrampolinePath } = require('../index')
const { getDesktopAskpassTrampolinePath, getDesktopCredentialHelperTrampolinePath } = require('../index')
const split2 = require('split2')
const { createServer } = require('net')
const trampolinePath = getDesktopAskpassTrampolinePath()
const askPassTrampolinePath = getDesktopAskpassTrampolinePath()
const helperTrampolinePath = getDesktopCredentialHelperTrampolinePath()
const run = promisify(execFile)
describe('desktop-trampoline', () => {
it('exists and is a regular file', async () =>
expect((await stat(trampolinePath)).isFile()).toBe(true))
expect((await stat(askPassTrampolinePath)).isFile()).toBe(true))
it('can be executed by current process', () =>
access(trampolinePath, constants.X_OK))
access(askPassTrampolinePath, constants.X_OK))
it('fails when required environment variables are missing', () =>
expect(run(trampolinePath, ['Username'])).rejects.toThrow())
expect(run(askPassTrampolinePath, ['Username'])).rejects.toThrow())
it('forwards arguments and valid environment variables correctly', async () => {
const captureSession = () => {
const output = []
let resolveOutput = null
const outputPromise = new Promise(resolve => {
resolveOutput = resolve
})
const server = createServer(socket => {
let timeoutId = null
socket.pipe(split2(/\0/)).on('data', data => {
output.push(data.toString('utf8'))
})
// Don't send anything and just close the socket after the trampoline is
// done forwarding data.
socket.end()
// Hack: consider the session finished after 100ms of inactivity.
// In a real-world scenario, you'd have to parse the data to know when
// the session is finished.
if (timeoutId !== null) {
clearTimeout(timeoutId)
timeoutId = null
}
timeoutId = setTimeout(() => {
resolveOutput(output)
socket.end()
server.close()
}, 100)
})
})
server.unref()
const startTrampolineServer = async () => {
return new Promise((resolve, reject) => {
server.on('error', e => reject(e))
server.listen(0, '127.0.0.1', () => {
resolve(server.address().port)
})
const serverPortPromise = new Promise((resolve, reject) => {
server.on('error', e => reject(e))
server.listen(0, '127.0.0.1', () => {
resolve(server.address().port)
})
}
})
return [serverPortPromise, outputPromise]
}
it('forwards arguments and valid environment variables correctly', async () => {
const [portPromise, outputPromise] = captureSession()
const port = await portPromise
const port = await startTrampolineServer()
const env = {
DESKTOP_TRAMPOLINE_TOKEN: '123456',
DESKTOP_PORT: port,
@@ -49,8 +70,9 @@ describe('desktop-trampoline', () => {
}
const opts = { env }
await run(trampolinePath, ['baz'], opts)
await run(askPassTrampolinePath, ['baz'], opts)
const output = await outputPromise
const outputArguments = output.slice(1, 2)
expect(outputArguments).toStrictEqual(['baz'])
// output[2] is the number of env variables
@@ -58,7 +80,33 @@ describe('desktop-trampoline', () => {
const outputEnv = output.slice(3, 3 + envc)
expect(outputEnv).toHaveLength(1)
expect(outputEnv).toContain('DESKTOP_TRAMPOLINE_TOKEN=123456')
})
server.close()
it('forwards stdin when running in credential-helper mode', async () => {
const [portPromise, outputPromise] = captureSession()
const port = await portPromise
const cp = run(helperTrampolinePath, ['get'], { env: { DESKTOP_PORT: port } })
cp.child.stdin.end('oh hai\n')
await cp
const output = await outputPromise
expect(output.at(-1)).toBe('oh hai\n')
})
it('doesn\'t forward stdin when running in askpass mode', async () => {
const [portPromise, outputPromise] = captureSession()
const port = await portPromise
const cp = run(askPassTrampolinePath, ['get'], { env: { DESKTOP_PORT: port } })
cp.child.stdin.end('oh hai\n')
await cp
const output = await outputPromise
expect(output.at(-1)).toBe('')
})
})