diff --git a/AGENTS.md b/AGENTS.md index 5ba13e38..b66405a2 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -18,7 +18,8 @@ The shell is supported on Linux, Windows and macOS. ## Code Style -- **All Go files must be formatted with `gofmt` before committing.** Run `gofmt -w .` from the repo root and verify with `gofmt -l .` (no output means clean). CI enforces this and will fail if any file is not properly formatted. +- **IMPORTANT: Always run `make fmt` after making any edits.** This is a mandatory step — no exceptions. CI will reject unformatted code. Run it after every change, before committing, and before running tests. Do not skip this step. +- All Go files must be formatted with `gofmt` before committing. `make fmt` handles this automatically. You can verify with `gofmt -l .` (no output means clean). ## Pull Requests diff --git a/Makefile b/Makefile index bd56f052..f3a15812 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,11 @@ -.PHONY: build test test_all test_against_bash compliance +.PHONY: build fmt test test_all test_against_bash compliance build: go build -o rshell ./cmd/rshell +fmt: + go fmt ./... + test: go test -v -race ./... diff --git a/allowedsymbols/symbols_internal.go b/allowedsymbols/symbols_internal.go index 3a038475..cbef7a74 100644 --- a/allowedsymbols/symbols_internal.go +++ b/allowedsymbols/symbols_internal.go @@ -14,41 +14,41 @@ var internalPerPackageSymbols = map[string][]string{ }, "procinfo": { "bufio.NewScanner", // line-by-line reading of /proc files; no write capability. - "bytes.NewReader", // wraps a byte slice as an in-memory io.Reader; no I/O side effects. - "context.Context", // deadline/cancellation interface; no side effects. - "errors.New", // creates a sentinel error (unsupported-platform stub); pure function, no I/O. - "fmt.Errorf", // error formatting; pure function, no I/O. - "fmt.Sprintf", // string formatting; pure function, no I/O. - "os.Getpid", // returns the current process ID; read-only, no side effects. - "os.Open", // opens a file read-only; needed to stream /proc/stat line-by-line. - "os.ReadDir", // reads a directory listing; needed to enumerate /proc entries. - "os.ReadFile", // reads a whole file; needed to read /proc/[pid]/{stat,cmdline,status}. - "strconv.Atoi", // string-to-int conversion; pure function, no I/O. - "strconv.ParseInt", // string to int64 with base/bit-size; pure function, no I/O. - "strings.Fields", // splits a string on whitespace; pure function, no I/O. - "strings.HasPrefix", // checks string prefix; pure function, no I/O. - "strings.Index", // finds first occurrence of a substring; pure function, no I/O. - "strings.LastIndex", // finds last occurrence of a substring; pure function, no I/O. - "strings.TrimRight", // trims trailing characters; pure function, no I/O. - "strings.TrimSpace", // removes leading/trailing whitespace; pure function, no I/O. - "syscall.Getsid", // returns the session ID of a process; read-only syscall, no write/exec. - "time.Now", // returns the current wall-clock time; read-only, no side effects. - "time.Unix", // constructs a Time from Unix seconds; pure function, no I/O. - "golang.org/x/sys/unix.KinfoProc", // (darwin) struct type carrying per-process kinfo_proc data from sysctl; read-only data, no exec capability. - "golang.org/x/sys/unix.SysctlKinfoProc", // (darwin) reads a single process's kinfo_proc via kern.proc.pid sysctl; read-only, no exec or write capability. - "golang.org/x/sys/unix.SysctlKinfoProcSlice", // (darwin) reads all processes' kinfo_proc via kern.proc.all sysctl; read-only, no exec or write capability. - "golang.org/x/sys/unix.SysctlRaw", // (darwin) reads raw kern.procargs2 sysctl buffer per-PID to obtain argv; read-only, no exec capability. - "golang.org/x/sys/windows.CloseHandle", // (windows) closes a process-snapshot handle after enumeration; no data read or exec capability. + "bytes.NewReader", // wraps a byte slice as an in-memory io.Reader; no I/O side effects. + "context.Context", // deadline/cancellation interface; no side effects. + "errors.New", // creates a sentinel error (unsupported-platform stub); pure function, no I/O. + "fmt.Errorf", // error formatting; pure function, no I/O. + "fmt.Sprintf", // string formatting; pure function, no I/O. + "os.Getpid", // returns the current process ID; read-only, no side effects. + "os.Open", // opens a file read-only; needed to stream /proc/stat line-by-line. + "os.ReadDir", // reads a directory listing; needed to enumerate /proc entries. + "os.ReadFile", // reads a whole file; needed to read /proc/[pid]/{stat,cmdline,status}. + "strconv.Atoi", // string-to-int conversion; pure function, no I/O. + "strconv.ParseInt", // string to int64 with base/bit-size; pure function, no I/O. + "strings.Fields", // splits a string on whitespace; pure function, no I/O. + "strings.HasPrefix", // checks string prefix; pure function, no I/O. + "strings.Index", // finds first occurrence of a substring; pure function, no I/O. + "strings.LastIndex", // finds last occurrence of a substring; pure function, no I/O. + "strings.TrimRight", // trims trailing characters; pure function, no I/O. + "strings.TrimSpace", // removes leading/trailing whitespace; pure function, no I/O. + "syscall.Getsid", // returns the session ID of a process; read-only syscall, no write/exec. + "time.Now", // returns the current wall-clock time; read-only, no side effects. + "time.Unix", // constructs a Time from Unix seconds; pure function, no I/O. + "golang.org/x/sys/unix.KinfoProc", // (darwin) struct type carrying per-process kinfo_proc data from sysctl; read-only data, no exec capability. + "golang.org/x/sys/unix.SysctlKinfoProc", // (darwin) reads a single process's kinfo_proc via kern.proc.pid sysctl; read-only, no exec or write capability. + "golang.org/x/sys/unix.SysctlKinfoProcSlice", // (darwin) reads all processes' kinfo_proc via kern.proc.all sysctl; read-only, no exec or write capability. + "golang.org/x/sys/unix.SysctlRaw", // (darwin) reads raw kern.procargs2 sysctl buffer per-PID to obtain argv; read-only, no exec capability. + "golang.org/x/sys/windows.CloseHandle", // (windows) closes a process-snapshot handle after enumeration; no data read or exec capability. "golang.org/x/sys/windows.CreateToolhelp32Snapshot", // (windows) creates a read-only snapshot of the process table; no exec or write capability. - "golang.org/x/sys/windows.ERROR_NO_MORE_FILES", // (windows) sentinel error indicating end of process enumeration; pure constant. - "golang.org/x/sys/windows.Process32First", // (windows) reads the first entry from a process snapshot; read-only, no exec capability. - "golang.org/x/sys/windows.Process32Next", // (windows) advances to the next entry in a process snapshot; read-only, no exec capability. - "golang.org/x/sys/windows.ProcessEntry32", // (windows) struct type holding process snapshot entry data; pure data type, no I/O. - "golang.org/x/sys/windows.TH32CS_SNAPPROCESS", // (windows) flag constant selecting process entries for CreateToolhelp32Snapshot; pure constant. - "golang.org/x/sys/windows.UTF16ToString", // (windows) converts a null-terminated UTF-16 slice to a Go string; pure function, no I/O. + "golang.org/x/sys/windows.ERROR_NO_MORE_FILES", // (windows) sentinel error indicating end of process enumeration; pure constant. + "golang.org/x/sys/windows.Process32First", // (windows) reads the first entry from a process snapshot; read-only, no exec capability. + "golang.org/x/sys/windows.Process32Next", // (windows) advances to the next entry in a process snapshot; read-only, no exec capability. + "golang.org/x/sys/windows.ProcessEntry32", // (windows) struct type holding process snapshot entry data; pure data type, no I/O. + "golang.org/x/sys/windows.TH32CS_SNAPPROCESS", // (windows) flag constant selecting process entries for CreateToolhelp32Snapshot; pure constant. + "golang.org/x/sys/windows.UTF16ToString", // (windows) converts a null-terminated UTF-16 slice to a Go string; pure function, no I/O. }, "winnet": { - "encoding/binary.BigEndian", // reads big-endian IPv6 group values from DLL buffer; pure value, no I/O. + "encoding/binary.BigEndian", // reads big-endian IPv6 group values from DLL buffer; pure value, no I/O. "encoding/binary.LittleEndian", // reads little-endian DWORD fields from DLL buffer; pure value, no I/O. "errors.New", // creates a sentinel error (non-Windows stub); pure function, no I/O. "fmt.Errorf", // error formatting; pure function, no I/O. diff --git a/hooks/pre-push b/hooks/pre-push new file mode 100755 index 00000000..9948c6e5 --- /dev/null +++ b/hooks/pre-push @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -euo pipefail + +# Check that all Go files are properly formatted. +# Runs on pre-push to prevent unformatted code from reaching the remote. + +echo "Checking for unformatted Go files..." +unformatted=$(gofmt -l . 2>/dev/null) + +if [[ -n "$unformatted" ]]; then + echo "❌ The following files are not formatted:" >&2 + echo "$unformatted" >&2 + echo "" >&2 + echo "Run 'make fmt' to fix formatting, then commit and push again." >&2 + exit 1 +fi