From 1a0e4b27a69f68d1e0139752cae6b00083c3f6e3 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 2 Apr 2026 23:27:10 +0200 Subject: [PATCH 1/8] ci: zizmor auto-fixes Signed-off-by: Sebastiaan van Stijn --- .github/workflows/test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e0cc879..3ff84fd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -29,6 +29,8 @@ jobs: go-version: ${{ matrix.go }} - name: Checkout code uses: actions/checkout@v6 + with: + persist-credentials: false - name: Test run: go test -v ./... lint: @@ -36,6 +38,8 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v6 + with: + persist-credentials: false - name: go mod tidy run: | go mod tidy From 125a9cebff13ffa7a420ee6d001d23e1aaf321e2 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 2 Apr 2026 23:56:54 +0200 Subject: [PATCH 2/8] fix linting (unused) Signed-off-by: Sebastiaan van Stijn --- term.go | 5 ++--- term_windows.go | 2 +- windows/ansi_reader.go | 27 +++++++++++++-------------- windows/ansi_writer.go | 1 - 4 files changed, 16 insertions(+), 19 deletions(-) diff --git a/term.go b/term.go index f9d8988..d083c98 100644 --- a/term.go +++ b/term.go @@ -10,9 +10,8 @@ type Winsize struct { Height uint16 Width uint16 - // Only used on Unix - x uint16 - y uint16 + x uint16 //nolint:unused // only used on Unix + y uint16 //nolint:unused // only used on Unix } // StdStreams returns the standard streams (stdin, stdout, stderr). diff --git a/term_windows.go b/term_windows.go index ab5bd85..d8e21c3 100644 --- a/term_windows.go +++ b/term_windows.go @@ -100,7 +100,7 @@ func getWinsize(fd uintptr) (*Winsize, error) { }, nil } -func setWinsize(fd uintptr, ws *Winsize) error { +func setWinsize(uintptr, *Winsize) error { return errors.New("not implemented on Windows") } diff --git a/windows/ansi_reader.go b/windows/ansi_reader.go index fb34c54..831a8bf 100644 --- a/windows/ansi_reader.go +++ b/windows/ansi_reader.go @@ -22,11 +22,10 @@ const ( // ansiReader wraps a standard input file (e.g., os.Stdin) providing ANSI sequence translation. type ansiReader struct { - file *os.File - fd uintptr - buffer []byte - cbBuffer int - command []byte + file *os.File + fd uintptr + buffer []byte + command []byte } // NewAnsiReader returns an io.ReadCloser that provides VT100 terminal emulation on top of a @@ -181,9 +180,10 @@ func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) stri if keyEvent.UnicodeChar == 0 { return formatVirtualKey(keyEvent.VirtualKeyCode, keyEvent.ControlKeyState, escapeSequence) } - + key := string(rune(keyEvent.UnicodeChar)) _, alt, control := getControlKeys(keyEvent.ControlKeyState) - if control { + switch { + case control && !alt: // TODO(azlinux): Implement following control sequences // -D Signals the end of input from the keyboard; also exits current shell. // -H Deletes the first character to the left of the cursor. Also called the ERASE key. @@ -191,14 +191,13 @@ func keyToString(keyEvent *winterm.KEY_EVENT_RECORD, escapeSequence []byte) stri // -S Suspends printing on the screen (does not stop the program). // -U Deletes all characters on the current line. Also called the KILL key. // -E Quits current command and creates a core + return key + case !control && alt: + // +Key generates ESC N Key + return ansiterm.KEY_ESC_N + strings.ToLower(key) + default: + return key } - - // +Key generates ESC N Key - if !control && alt { - return ansiterm.KEY_ESC_N + strings.ToLower(string(rune(keyEvent.UnicodeChar))) - } - - return string(rune(keyEvent.UnicodeChar)) } // formatVirtualKey converts a virtual key (e.g., up arrow) into the appropriate ANSI string. diff --git a/windows/ansi_writer.go b/windows/ansi_writer.go index 4243307..6ccc38f 100644 --- a/windows/ansi_writer.go +++ b/windows/ansi_writer.go @@ -18,7 +18,6 @@ type ansiWriter struct { infoReset *winterm.CONSOLE_SCREEN_BUFFER_INFO command []byte escapeSequence []byte - inAnsiSequence bool parser *ansiterm.AnsiParser } From 1f5087c25ec94367aadd4a38bd2f58b87fcad0aa Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 2 Apr 2026 23:58:39 +0200 Subject: [PATCH 3/8] fix S1005: unnecessary assignment to the blank identifier (staticcheck) Signed-off-by: Sebastiaan van Stijn --- term_windows.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/term_windows.go b/term_windows.go index d8e21c3..7d22952 100644 --- a/term_windows.go +++ b/term_windows.go @@ -167,7 +167,7 @@ func restoreAtInterrupt(fd uintptr, state *State) { signal.Notify(sigchan, os.Interrupt) go func() { - _ = <-sigchan + <-sigchan _ = RestoreTerminal(fd, state) os.Exit(0) }() From af14034da41951b0c1fdc4d70b835e35e7b7988d Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 3 Apr 2026 00:01:59 +0200 Subject: [PATCH 4/8] fix ST1017: don't use Yoda conditions (staticcheck) Signed-off-by: Sebastiaan van Stijn --- windows/ansi_reader.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/windows/ansi_reader.go b/windows/ansi_reader.go index 831a8bf..dca5a4e 100644 --- a/windows/ansi_reader.go +++ b/windows/ansi_reader.go @@ -218,9 +218,9 @@ func formatVirtualKey(key uint16, controlState uint32, escapeSequence []byte) st // getControlKeys extracts the shift, alt, and ctrl key states. func getControlKeys(controlState uint32) (shift, alt, control bool) { - shift = 0 != (controlState & winterm.SHIFT_PRESSED) - alt = 0 != (controlState & (winterm.LEFT_ALT_PRESSED | winterm.RIGHT_ALT_PRESSED)) - control = 0 != (controlState & (winterm.LEFT_CTRL_PRESSED | winterm.RIGHT_CTRL_PRESSED)) + shift = controlState&winterm.SHIFT_PRESSED != 0 + alt = controlState&(winterm.LEFT_ALT_PRESSED|winterm.RIGHT_ALT_PRESSED) != 0 + control = controlState&(winterm.LEFT_CTRL_PRESSED|winterm.RIGHT_CTRL_PRESSED) != 0 return shift, alt, control } From e44d23ccea68763367209060b1597238d6f07f2e Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 3 Apr 2026 00:16:25 +0200 Subject: [PATCH 5/8] fix G601: Implicit memory aliasing in for loop. (gosec) windows/ansi_reader.go:171:35: G601: Implicit memory aliasing in for loop. (gosec) buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence)) ^ Signed-off-by: Sebastiaan van Stijn --- windows/ansi_reader.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/windows/ansi_reader.go b/windows/ansi_reader.go index dca5a4e..a0aa71c 100644 --- a/windows/ansi_reader.go +++ b/windows/ansi_reader.go @@ -166,9 +166,10 @@ var keyMapPrefix = map[uint16]string{ // translateKeyEvents converts the input events into the appropriate ANSI string. func translateKeyEvents(events []winterm.INPUT_RECORD, escapeSequence []byte) []byte { var buffer bytes.Buffer - for _, event := range events { + for i := range events { + event := events[i] if event.EventType == winterm.KEY_EVENT && event.KeyEvent.KeyDown != 0 { - buffer.WriteString(keyToString(&event.KeyEvent, escapeSequence)) + buffer.WriteString(keyToString(&events[i].KeyEvent, escapeSequence)) } } From d0d1b3416b226dcd128959776ece9a1ea59212f4 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Thu, 2 Apr 2026 23:55:57 +0200 Subject: [PATCH 6/8] fix G115: integer overflow conversion (gosec) Signed-off-by: Sebastiaan van Stijn --- term_unix.go | 13 +++++++++++++ term_windows.go | 11 +++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/term_unix.go b/term_unix.go index f184bb8..093d1f3 100644 --- a/term_unix.go +++ b/term_unix.go @@ -6,6 +6,7 @@ package term import ( "errors" "io" + "math" "os" "golang.org/x/sys/unix" @@ -31,12 +32,18 @@ func getFdInfo(in interface{}) (uintptr, bool) { } func getWinsize(fd uintptr) (*Winsize, error) { + if fd > math.MaxInt { + return nil, errors.New("invalid file descriptor") + } uws, err := unix.IoctlGetWinsize(int(fd), unix.TIOCGWINSZ) ws := &Winsize{Height: uws.Row, Width: uws.Col, x: uws.Xpixel, y: uws.Ypixel} return ws, err } func setWinsize(fd uintptr, ws *Winsize) error { + if fd > math.MaxInt { + return errors.New("invalid file descriptor") + } return unix.IoctlSetWinsize(int(fd), unix.TIOCSWINSZ, &unix.Winsize{ Row: ws.Height, Col: ws.Width, @@ -81,6 +88,9 @@ func setRawTerminalOutput(uintptr) (*State, error) { } func tcget(fd uintptr) (*unix.Termios, error) { + if fd > math.MaxInt { + return nil, errors.New("invalid file descriptor") + } p, err := unix.IoctlGetTermios(int(fd), getTermios) if err != nil { return nil, err @@ -89,5 +99,8 @@ func tcget(fd uintptr) (*unix.Termios, error) { } func tcset(fd uintptr, p *unix.Termios) error { + if fd > math.MaxInt { + return errors.New("invalid file descriptor") + } return unix.IoctlSetTermios(int(fd), setTermios, p) } diff --git a/term_windows.go b/term_windows.go index 7d22952..4506319 100644 --- a/term_windows.go +++ b/term_windows.go @@ -3,6 +3,7 @@ package term import ( "errors" "io" + "math" "os" "os/signal" @@ -94,9 +95,15 @@ func getWinsize(fd uintptr) (*Winsize, error) { return nil, err } + w := int32(info.Window.Right) - int32(info.Window.Left) + 1 + h := int32(info.Window.Bottom) - int32(info.Window.Top) + 1 + if w < 0 || w > math.MaxUint16 || h < 0 || h > math.MaxUint16 { + return nil, errors.New("invalid console window size") + } + return &Winsize{ - Width: uint16(info.Window.Right - info.Window.Left + 1), - Height: uint16(info.Window.Bottom - info.Window.Top + 1), + Width: uint16(w), + Height: uint16(h), }, nil } From 9ecb311df7fb918caca44d6ac72078e64a73baa1 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 3 Apr 2026 00:25:09 +0200 Subject: [PATCH 7/8] fix G103: Use of unsafe calls should be audited (gosec) windows/ansi_reader.go:105:60: G103: Use of unsafe calls should be audited (gosec) recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes))))) ^ Signed-off-by: Sebastiaan van Stijn --- windows/ansi_reader.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/windows/ansi_reader.go b/windows/ansi_reader.go index a0aa71c..c236069 100644 --- a/windows/ansi_reader.go +++ b/windows/ansi_reader.go @@ -98,11 +98,8 @@ func (ar *ansiReader) Read(p []byte) (int, error) { // readInputEvents polls until at least one event is available. func readInputEvents(ar *ansiReader, maxBytes int) ([]winterm.INPUT_RECORD, error) { - // Determine the maximum number of records to retrieve - // -- Cast around the type system to obtain the size of a single INPUT_RECORD. - // unsafe.Sizeof requires an expression vs. a type-reference; the casting - // tricks the type system into believing it has such an expression. - recordSize := int(unsafe.Sizeof(*((*winterm.INPUT_RECORD)(unsafe.Pointer(&maxBytes))))) + // Determine the size of a single INPUT_RECORD. + recordSize := int(unsafe.Sizeof(winterm.INPUT_RECORD{})) countRecords := maxBytes / recordSize if countRecords > ansiterm.MAX_INPUT_EVENTS { countRecords = ansiterm.MAX_INPUT_EVENTS From 13d2eed26b6a6c014a523e8c79dc8c765cbe50b8 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 3 Apr 2026 00:50:10 +0200 Subject: [PATCH 8/8] ci: update golangci-lint to v2.11 Signed-off-by: Sebastiaan van Stijn --- .github/workflows/test.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3ff84fd..5cd634d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,5 +46,7 @@ jobs: git diff --exit-code - name: Lint run: | - docker run --rm -v ./:/go/src/github.com/moby/term -w /go/src/github.com/moby/term \ - golangci/golangci-lint:v2.8-alpine golangci-lint run -v + docker run --rm \ + -v ./:/go/src/github.com/moby/term \ + -w /go/src/github.com/moby/term \ + golangci/golangci-lint:v2.11-alpine golangci-lint run -v