8 Commits
v2.6 ... main

Author SHA1 Message Date
2e774e9623 mod: update dependencies; do not automatically update dependencies in builds
All checks were successful
Go Project Action / Spell-check and test go project (push) Successful in 55s
Release Go Application / Release go project (release) Successful in 1m6s
2025-11-08 12:41:47 +01:00
a016b15508 feat: keyboard interactive login for unlimited access configurations
Some checks failed
Go Project Action / Spell-check and test go project (push) Failing after 54s
If users are limited they are only allowed to authenticate via their ssh
private-public key-pair, which the configuration holds for each accepted
user accordingly.
2025-11-08 12:36:06 +01:00
c6d270fc36 feat: accept arguments through ssh command arguments
Some checks failed
Go Project Action / Spell-check and test go project (push) Failing after 54s
Configured default arguments are replaced with provided arguments
through the `ssh` command. Without any arguments the default arguments
are used instead.
2025-11-08 12:04:17 +01:00
7dc1f9c53e mod: bump action dependencies
All checks were successful
Go Project Action / Spell-check and test go project (push) Successful in 59s
2025-11-05 22:49:14 +01:00
6d2ab00fa7 mod: revert changes
All checks were successful
Go Project Action / Spell-check and test go project (push) Successful in 50s
Release Go Application / Release go project (release) Successful in 50s
Logging will be done through `zlog` dependency for *zig* based
applications. `zlog` shall be configured such that it should not log to
*stderr* and should use the "log" file instead. This way the log file is
both used by `serve` and by the running application. Logging could also
happen in a different file and is independent of the logging of `serve`,
however for now I want the logging to also happen in the same file.
2025-11-01 00:21:37 +01:00
09e4a5d646 doc: increament version
All checks were successful
Go Project Action / Spell-check and test go project (push) Successful in 46s
Release Go Application / Release go project (release) Successful in 46s
2025-10-31 23:27:38 +01:00
904f585c4d mod: use log file as stderr for ssh command
Some checks failed
Go Project Action / Spell-check and test go project (push) Has been cancelled
2025-10-31 23:26:58 +01:00
f78e3092fb mod: copy stderr from ssh session to locally running processes stderr
All checks were successful
Go Project Action / Spell-check and test go project (push) Successful in 51s
Release Go Application / Release go project (release) Successful in 46s
Log the `serve` version in the beginning with a closing log message.
2025-10-31 23:03:30 +01:00
5 changed files with 35 additions and 34 deletions

View File

@@ -18,8 +18,14 @@ jobs:
uses: actions/setup-go@v5 uses: actions/setup-go@v5
with: with:
go-version: 1.24.x go-version: 1.24.x
- name: Spell checking
uses: crate-ci/typos@v1.39.0
with:
config: ./.typos-config
- name: Install dependencies - name: Install dependencies
run: go get -u . run: go get .
- name: Run tests
run: go test ./...
- name: Build - name: Build
run: CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -o ./bin/serve main.go run: CGO_ENABLED=0 GOOS=linux go build -ldflags "-s -w" -o ./bin/serve main.go
- name: Release build artifacts - name: Release build artifacts

View File

@@ -18,10 +18,10 @@ jobs:
with: with:
go-version: 1.24.x go-version: 1.24.x
- name: Spell checking - name: Spell checking
uses: crate-ci/typos@v1.25.0 uses: crate-ci/typos@v1.39.0
with: with:
config: ./.typos-config config: ./.typos-config
- name: Install dependencies - name: Install dependencies
run: go get -u . run: go get .
- name: Run tests - name: Run tests
run: go test ./... run: go test ./...

2
go.mod
View File

@@ -7,6 +7,7 @@ require (
github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309
github.com/charmbracelet/wish v1.4.7 github.com/charmbracelet/wish v1.4.7
github.com/spf13/viper v1.21.0 github.com/spf13/viper v1.21.0
golang.org/x/crypto v0.43.0
) )
require ( require (
@@ -45,7 +46,6 @@ require (
github.com/subosito/gotenv v1.6.0 // indirect github.com/subosito/gotenv v1.6.0 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect
golang.org/x/sys v0.37.0 // indirect golang.org/x/sys v0.37.0 // indirect
golang.org/x/text v0.30.0 // indirect golang.org/x/text v0.30.0 // indirect

View File

@@ -15,6 +15,7 @@ import (
"github.com/charmbracelet/wish" "github.com/charmbracelet/wish"
"github.com/charmbracelet/wish/activeterm" "github.com/charmbracelet/wish/activeterm"
"github.com/charmbracelet/wish/logging" "github.com/charmbracelet/wish/logging"
gossh "golang.org/x/crypto/ssh"
) )
// Setup default logger to append or create a new log file `log` in the current // Setup default logger to append or create a new log file `log` in the current
@@ -51,16 +52,24 @@ func setupSshServer(host string, port string, host_key_path string, users map[st
} }
return false return false
}), }),
wish.WithKeyboardInteractiveAuth(func(_ ssh.Context, _ gossh.KeyboardInteractiveChallenge) bool {
if len(users) == 0 {
// no users provided, meaning there is no user authentication, everyone is allowed to connect
return true
}
// NOTE interactive logins through keyboard challenges shall not be allowed; use
// ssh public-private key-pairs instead for limited access
return false
}),
ssh.AllocatePty(), ssh.AllocatePty(),
wish.WithMiddleware( wish.WithMiddleware(
func(next ssh.Handler) ssh.Handler { func(next ssh.Handler) ssh.Handler {
return func(s ssh.Session) { return func(s ssh.Session) {
cmd := wish.Command(s, name, args...) provided_args := s.Command()
file, err := os.OpenFile("log", os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600) if len(provided_args) > 0 {
if err != nil { args = provided_args
wish.Fatalln(s, err)
} }
cmd.SetStderr(file) cmd := wish.Command(s, name, args...)
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
wish.Fatalln(s, err) wish.Fatalln(s, err)
} }

36
main.go
View File

@@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"os"
"github.com/spf13/viper" "github.com/spf13/viper"
"yves-biener.de/wish-serve/internal/serve" "yves-biener.de/wish-serve/internal/serve"
@@ -15,12 +14,19 @@ func createDefaultConfig() {
viper.SetDefault("key.dir", ".ssh") viper.SetDefault("key.dir", ".ssh")
viper.SetDefault("key.name", "ssh_ed25519_key") viper.SetDefault("key.name", "ssh_ed25519_key")
viper.SetDefault("app.name", "echo") viper.SetDefault("app.name", "echo")
viper.SetDefault("app.args", []string{"Hello World"}) viper.SetDefault("app.args", []string{"Hello", "World"})
} }
// Load the configuration file from (`$HOME/.config/serve/config.yml` or // Load the configuration file from any of the following locations (loading the
// `./config.yml`) if it exists. Otherwise use the default values from // first one with an existing configuration):
// `createDefaultConfig()`. // - `$HOME/.config/serve/config.yml`
// - `./config.yml`
//
// If no configuration is found in any of the defined locations the default
// values of `createDefaultConfig` will remain unchanged.
//
// Invalid configuration files will cause a fatal error causing the application
// to panic.
func loadConfig() { func loadConfig() {
viper.SetConfigName("config") viper.SetConfigName("config")
viper.SetConfigType("yml") viper.SetConfigType("yml")
@@ -33,29 +39,9 @@ func loadConfig() {
} }
} }
// Overwrite (default) configuration value for the application to serve with
// given command line arguments.
//
// NOTE: This will also overwrite the configuration for the `app` entry from the
// configuration file.
func overwriteServeCommand() {
if len(os.Args) >= 2 {
name := os.Args[1]
viper.Set("app.name", name)
if len(os.Args) >= 3 {
args := os.Args[2:]
viper.Set("app.args", args)
} else {
// no arguments provided -> clear app arguments
viper.Set("app.args", []string{})
}
}
}
func main() { func main() {
createDefaultConfig() createDefaultConfig()
loadConfig() loadConfig()
overwriteServeCommand()
serve.Serve( serve.Serve(
viper.GetString("host"), viper.GetString("host"),