Skip to content

Commit d044f12

Browse files
authored
Version 0.7.1 (#155)
1 parent b4f6aef commit d044f12

File tree

22 files changed

+961
-141
lines changed

22 files changed

+961
-141
lines changed

.github/workflows/demo-test.yaml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ jobs:
1313
runs-on: ubuntu-latest
1414

1515
steps:
16-
- uses: actions/checkout@v4
16+
- uses: actions/checkout@v5
1717

18-
- name: Set up Go 1.22
19-
uses: actions/setup-go@v5
18+
- name: Set up Go
19+
uses: actions/setup-go@v6
2020
with:
21-
go-version: "1.22"
21+
go-version-file: go.mod
22+
cache: false
2223

2324
- name: Run demo e2e test
2425
env:

.github/workflows/release.yaml

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,13 @@ jobs:
3737
runs-on: ${{ matrix.os }}
3838

3939
steps:
40-
- uses: actions/checkout@v4
40+
- uses: actions/checkout@v5
4141

42-
- name: Set up Go 1.22
43-
uses: actions/setup-go@v5
42+
- name: Set up Go
43+
uses: actions/setup-go@v6
4444
with:
45-
go-version: "1.22"
45+
go-version-file: go.mod
46+
cache: false
4647

4748
- name: Get version
4849
id: package_version
@@ -225,7 +226,7 @@ jobs:
225226
done
226227
227228
- name: Upload artifacts
228-
uses: actions/upload-artifact@v4
229+
uses: actions/upload-artifact@v6
229230
with:
230231
name: release-${{ matrix.goos }}-${{ matrix.goarch }}
231232
path: dist/packages/*
@@ -240,12 +241,13 @@ jobs:
240241
version: ${{ steps.package_version.outputs.version }}
241242

242243
steps:
243-
- uses: actions/checkout@v4
244+
- uses: actions/checkout@v5
244245

245-
- name: Set up Go 1.22
246-
uses: actions/setup-go@v5
246+
- name: Set up Go
247+
uses: actions/setup-go@v6
247248
with:
248-
go-version: "1.22"
249+
go-version-file: go.mod
250+
cache: false
249251

250252
- name: Get version
251253
id: package_version
@@ -256,14 +258,15 @@ jobs:
256258
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
257259
258260
- name: Create release
259-
uses: actions/create-release@v1
261+
shell: bash
260262
env:
261263
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
262-
with:
263-
tag_name: v${{ steps.package_version.outputs.version }}
264-
release_name: Version ${{ steps.package_version.outputs.version }}
265-
draft: true
266-
prerelease: false
264+
run: |
265+
set -euo pipefail
266+
gh release create "v${{ steps.package_version.outputs.version }}" \
267+
--repo "${{ github.repository }}" \
268+
--title "Version ${{ steps.package_version.outputs.version }}" \
269+
--draft
267270
268271
upload-release:
269272
needs:
@@ -272,7 +275,7 @@ jobs:
272275
runs-on: ubuntu-latest
273276

274277
steps:
275-
- uses: actions/download-artifact@v4
278+
- uses: actions/download-artifact@v7
276279
with:
277280
pattern: release-*
278281
path: dist/packages

.github/workflows/test.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,16 @@ jobs:
2121
runs-on: ${{ matrix.os }}
2222

2323
steps:
24-
- uses: actions/checkout@v4
24+
- uses: actions/checkout@v5
2525

2626
- name: Set up mise
27-
uses: jdx/mise-action@v2
27+
uses: jdx/mise-action@v4
2828

29-
- name: Set up Go 1.22
30-
uses: actions/setup-go@v5
29+
- name: Set up Go
30+
uses: actions/setup-go@v6
3131
with:
32-
go-version: "1.22"
32+
go-version-file: go.mod
33+
cache: false
3334

3435
- name: Run full test
3536
run: mise run full_test

demo/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ backend: 172.31.1.33"]
5858
5959
client --> password_ssh
6060
client --> key_ssh
61-
client -. via proxy .-> ssh_proxy
61+
client --> ssh_proxy
6262
client -. via proxy .-> http_proxy
6363
client -. via proxy .-> socks_proxy
6464

demo/client/home/.lssh.d/servers_proxy.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,21 @@ proxy = "ssh_proxy"
1111
control_master = false
1212
note = "private ssh server over ssh proxy"
1313

14+
[server.ssh_proxy_cm]
15+
addr = "172.31.0.31"
16+
key = "~/.ssh/demo_lssh_ed25519"
17+
control_master = true
18+
control_persist = "30s"
19+
note = "ssh proxy hop server with ControlMaster"
20+
21+
[server.OverSshProxyCM]
22+
addr = "172.31.1.41"
23+
key = "~/.ssh/demo_lssh_ed25519"
24+
proxy = "ssh_proxy_cm"
25+
control_master = true
26+
control_persist = "30s"
27+
note = "private ssh server over ssh proxy with ControlMaster"
28+
1429
[server.OverHttpProxy]
1530
addr = "172.31.1.41"
1631
key = "~/.ssh/demo_lssh_ed25519"

demo/e2e_test.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,57 @@ func TestDemoDockerComposeE2E(t *testing.T) {
8787
assertClientCommandContains(t, demoDir, "lssh --host OverSocksProxy hostname", "over-proxy-ssh")
8888
})
8989

90+
t.Run("control master local forward works", func(t *testing.T) {
91+
pidFile := "/tmp/lssh-demo-local-forward.pid"
92+
t.Cleanup(func() {
93+
stopClientForward(t, demoDir, pidFile)
94+
})
95+
96+
startClientForward(t, demoDir, pidFile,
97+
"lssh --host OverSshProxyCM -N -L 10081:localhost:22",
98+
"127.0.0.1:10081",
99+
)
100+
101+
assertClientCommandContains(t, demoDir,
102+
`banner=$(nc -w 5 127.0.0.1 10081 | head -c 8); printf '%s' "$banner"`,
103+
"SSH-2.0-",
104+
)
105+
})
106+
107+
t.Run("control master dynamic forward works", func(t *testing.T) {
108+
pidFile := "/tmp/lssh-demo-dynamic-forward.pid"
109+
t.Cleanup(func() {
110+
stopClientForward(t, demoDir, pidFile)
111+
})
112+
113+
startClientForward(t, demoDir, pidFile,
114+
"lssh --host OverSshProxyCM -N -D 10080",
115+
"127.0.0.1:10080",
116+
)
117+
118+
assertClientCommandContains(t, demoDir,
119+
`banner=$(nc -X 5 -x 127.0.0.1:10080 -w 5 172.31.1.41 22 | head -c 8); printf '%s' "$banner"`,
120+
"SSH-2.0-",
121+
)
122+
})
123+
124+
t.Run("control master remote forward works", func(t *testing.T) {
125+
pidFile := "/tmp/lssh-demo-remote-forward.pid"
126+
t.Cleanup(func() {
127+
stopClientForward(t, demoDir, pidFile)
128+
})
129+
130+
startClientForward(t, demoDir, pidFile,
131+
"lssh --host OverSshProxyCM -N -R 172.31.0.10:2222:10082",
132+
"",
133+
)
134+
135+
waitForComposeExecContains(t, demoDir, "over_proxy_ssh",
136+
`banner=$(bash -lc 'exec 3<>/dev/tcp/127.0.0.1/10082; head -c 8 <&3' 2>/dev/null || true); printf '%s' "$banner"`,
137+
"SSH-2.0-",
138+
)
139+
})
140+
90141
t.Run("local rc is available on remote shell", func(t *testing.T) {
91142
assertClientCommandContains(t, demoDir,
92143
`lssh --host LocalRcKeyAuth 'type lvim >/dev/null && type ltmux >/dev/null && echo local_rc_ok'`,
@@ -227,3 +278,72 @@ func mustRunComposeCommand(t *testing.T, demoDir string, args ...string) string
227278

228279
return string(output)
229280
}
281+
282+
func startClientForward(t *testing.T, demoDir, pidFile, forwardCommand, waitAddr string) {
283+
t.Helper()
284+
285+
stopClientForward(t, demoDir, pidFile)
286+
287+
startCmd := fmt.Sprintf(
288+
`rm -f %[1]s; nohup %[2]s >/tmp/$(basename %[1]s).log 2>&1 & echo $! > %[1]s`,
289+
pidFile,
290+
forwardCommand,
291+
)
292+
293+
if output, err := runClientCommand(demoDir, startCmd); err != nil {
294+
t.Fatalf("failed to start forward: %s\nerror: %v\noutput:\n%s", forwardCommand, err, output)
295+
}
296+
297+
if waitAddr == "" {
298+
time.Sleep(2 * time.Second)
299+
return
300+
}
301+
302+
deadline := time.Now().Add(10 * time.Second)
303+
checkCmd := fmt.Sprintf("nc -z -w 2 %s %s", strings.Split(waitAddr, ":")[0], strings.Split(waitAddr, ":")[1])
304+
for time.Now().Before(deadline) {
305+
if _, err := runClientCommand(demoDir, checkCmd); err == nil {
306+
return
307+
}
308+
time.Sleep(200 * time.Millisecond)
309+
}
310+
311+
logOutput, _ := runClientCommand(demoDir, fmt.Sprintf("cat /tmp/$(basename %s).log || true", pidFile))
312+
t.Fatalf("forward did not become ready: %s\nlog:\n%s", forwardCommand, logOutput)
313+
}
314+
315+
func stopClientForward(t *testing.T, demoDir, pidFile string) {
316+
t.Helper()
317+
318+
_, _ = runClientCommand(demoDir,
319+
fmt.Sprintf(`if [ -f %[1]s ]; then kill $(cat %[1]s) >/dev/null 2>&1 || true; rm -f %[1]s; fi`, pidFile),
320+
)
321+
}
322+
323+
func waitForComposeExecContains(t *testing.T, demoDir, service, command, want string) {
324+
t.Helper()
325+
326+
deadline := time.Now().Add(10 * time.Second)
327+
var lastOutput string
328+
329+
for time.Now().Before(deadline) {
330+
output, err := runComposeServiceCommand(demoDir, service, command)
331+
lastOutput = output
332+
if err == nil && strings.Contains(output, want) {
333+
return
334+
}
335+
time.Sleep(200 * time.Millisecond)
336+
}
337+
338+
t.Fatalf("output missing %q for service %s command %s\nlast output:\n%s", want, service, command, lastOutput)
339+
}
340+
341+
func runComposeServiceCommand(demoDir, service, command string) (string, error) {
342+
cmd := exec.Command("docker", "compose", "exec", "-T", service, "bash", "-lc", command)
343+
cmd.Dir = demoDir
344+
output, err := cmd.CombinedOutput()
345+
if err != nil {
346+
return string(output), fmt.Errorf("%w", err)
347+
}
348+
return string(output), nil
349+
}

demo/images/sshd/Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ RUN apt-get update && \
55
bash \
66
ca-certificates \
77
gzip \
8+
netcat-openbsd \
89
openssh-server \
910
procps \
1011
tmux \

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
1212
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 // indirect
1313
github.com/blacknon/crypto11 v1.6.2-0.20260315101107-fd111b1d25ce // indirect
14-
github.com/blacknon/go-sshlib v0.1.24
14+
github.com/blacknon/go-sshlib v0.1.26
1515
github.com/blacknon/go-x11auth v0.1.0 // indirect
1616
github.com/c-bata/go-prompt v0.2.6
1717
github.com/davecgh/go-spew v1.1.1 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ github.com/blacknon/crypto11 v1.6.2-0.20260315101107-fd111b1d25ce h1:e/O1bXnYwEq
1717
github.com/blacknon/crypto11 v1.6.2-0.20260315101107-fd111b1d25ce/go.mod h1:DK0nQEQvNRRg4/vN5CfNhvvUNTPbOQ2xAQ83qQFK20s=
1818
github.com/blacknon/go-prompt v0.2.7 h1:dVdTqVplKvpT/k4bB9BlbcBYl/k6amYX5tvjYBmuKkI=
1919
github.com/blacknon/go-prompt v0.2.7/go.mod h1:zNBmC/BPAyr+3ey1oRhPxuXJS9zz1lEmJpwaoQroe3w=
20-
github.com/blacknon/go-sshlib v0.1.24 h1:YQ5yzThK3+bv4gY4kH1C7z3sFzUDt9wFV0fMWGhz5Dc=
21-
github.com/blacknon/go-sshlib v0.1.24/go.mod h1:h0156rkS41AR81QU8/VbrWRe56N4qrsZgN+I1N6wuxc=
20+
github.com/blacknon/go-sshlib v0.1.26 h1:Myil2trS0s5d7Y28A2lZfvbIOQlFETgAsaFEBpQjWOk=
21+
github.com/blacknon/go-sshlib v0.1.26/go.mod h1:JrNchFWRLqiIAaGd+1rBCs0mbZTfxuyaZ2E9ureS9mw=
2222
github.com/blacknon/go-sshproc v0.1.1 h1:Zhhm/lyC+lotbN8vqXD3fnxVbJP4ILMCu086PuTLXFo=
2323
github.com/blacknon/go-sshproc v0.1.1/go.mod h1:FoW0cVjAxqtJVrhgzif6SOBsZ27EiMF/i2iCqiUPwBY=
2424
github.com/blacknon/go-x11auth v0.1.0 h1:SnljCPWcvglWeGAlKc1RAPMHnOfMpM9+GrTGEUQ1lqQ=

internal/common/common.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -548,12 +548,15 @@ func StringCompression(mode int, data []byte) (result []byte, err error) {
548548
switch mode {
549549
case ARCHIVE_GZIP:
550550
zw := gzip.NewWriter(buf)
551-
defer zw.Close()
552-
553551
r := bytes.NewReader(data)
554552

555553
_, err = io.Copy(zw, r)
556-
zw.Flush()
554+
if err != nil {
555+
return nil, err
556+
}
557+
if err = zw.Close(); err != nil {
558+
return nil, err
559+
}
557560
}
558561

559562
result = buf.Bytes()

0 commit comments

Comments
 (0)