github/test: Run tests with address sanitizer
We have lots of cgo interaction here so better to check things fully. This also requires manually checking for leaks, so add support for this.
This commit is contained in:
parent
04ad7bdc73
commit
eac1f2d85d
|
@ -13,19 +13,38 @@ jobs:
|
|||
with:
|
||||
go-version: ${{ matrix.go-version }}
|
||||
- name: Install PAM
|
||||
run: sudo apt install -y libpam-dev
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt install -y libpam-dev
|
||||
- name: Install Debug symbols
|
||||
run: |
|
||||
sudo apt install -y ubuntu-dev-tools
|
||||
(cd /tmp && pull-lp-ddebs libpam0g $(lsb_release -c -s))
|
||||
(cd /tmp && pull-lp-ddebs libpam-modules $(lsb_release -c -s))
|
||||
sudo dpkg -i /tmp/libpam*-dbgsym_*.ddeb
|
||||
- name: Add a test user
|
||||
run: sudo useradd -d /tmp/test -p '$1$Qd8H95T5$RYSZQeoFbEB.gS19zS99A0' -s /bin/false test
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Test
|
||||
run: sudo go test -v -cover -coverprofile=coverage.out ./...
|
||||
- name: Test with Address Sanitizer
|
||||
env:
|
||||
GO_PAM_TEST_WITH_ASAN: true
|
||||
CGO_CFLAGS: "-O0 -g3 -fno-omit-frame-pointer"
|
||||
run: |
|
||||
# Do not run sudo-requiring go tests because as PAM has some leaks in 22.04
|
||||
go test -v -asan -cover -coverprofile=coverage-asan-tx.out -gcflags=all="-N -l"
|
||||
|
||||
# Run the rest of tests normally
|
||||
sudo go test -v -cover -coverprofile=coverage-asan-module.out -asan -gcflags=all="-N -l" -run Module
|
||||
sudo go test -C cmd -coverprofile=coverage-asan.out -v -asan -gcflags=all="-N -l" ./...
|
||||
- name: Generate example module
|
||||
run: |
|
||||
rm -f example-module/pam_go.so
|
||||
go generate -C example-module -v
|
||||
test -e example-module/pam_go.so
|
||||
git diff --exit-code example-module
|
||||
- name: Test
|
||||
run: sudo go test -v -cover -coverprofile=coverage.out ./...
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v3
|
||||
env:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
coverage.out
|
||||
coverage*.out
|
||||
example-module/*.so
|
||||
example-module/*.h
|
||||
cmd/pam-moduler/tests/*/*.so
|
||||
|
|
|
@ -23,6 +23,7 @@ func ensureNoError(t *testing.T, err error) {
|
|||
|
||||
func Test_NewNullModuleTransaction(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
mt := moduleTransaction{}
|
||||
|
||||
if mt.handle != nil {
|
||||
|
@ -137,6 +138,7 @@ func Test_NewNullModuleTransaction(t *testing.T) {
|
|||
tc := tc
|
||||
t.Run(name+"-error-check", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
data, err := tc.testFunc(t)
|
||||
|
||||
switch d := data.(type) {
|
||||
|
@ -202,6 +204,7 @@ func Test_NewNullModuleTransaction(t *testing.T) {
|
|||
|
||||
func Test_ModuleTransaction_InvokeHandler(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
mt := &moduleTransaction{}
|
||||
|
||||
err := mt.InvokeHandler(nil, 0, nil)
|
||||
|
@ -308,6 +311,7 @@ func Test_ModuleTransaction_InvokeHandler(t *testing.T) {
|
|||
func testMockModuleTransaction(t *testing.T, mt *moduleTransaction) {
|
||||
t.Helper()
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
|
||||
tests := map[string]struct {
|
||||
testFunc func(mock *mockModuleTransaction) (any, error)
|
||||
|
@ -898,6 +902,7 @@ func testMockModuleTransaction(t *testing.T, mt *moduleTransaction) {
|
|||
tc := tc
|
||||
t.Run(name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
mock := newMockModuleTransaction(&mockModuleTransaction{T: t,
|
||||
Expectations: tc.mockExpectations, RetData: tc.mockRetData,
|
||||
ConversationHandler: tc.conversationHandler})
|
||||
|
|
|
@ -39,6 +39,7 @@ func ensureTransactionEnds(t *testing.T, tx *Transaction) {
|
|||
}
|
||||
|
||||
func TestPAM_001(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -67,6 +68,7 @@ func TestPAM_001(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_002(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -107,6 +109,7 @@ func (c Credentials) RespondPAM(s Style, msg string) (string, error) {
|
|||
}
|
||||
|
||||
func TestPAM_003(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -128,6 +131,7 @@ func TestPAM_003(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_004(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -148,10 +152,14 @@ func TestPAM_004(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_005(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
}
|
||||
if _, found := os.LookupEnv("GO_PAM_TEST_WITH_ASAN"); found {
|
||||
t.Skip("test fails under ASAN")
|
||||
}
|
||||
tx, err := StartFunc("passwd", "test", func(s Style, msg string) (string, error) {
|
||||
return "secret", nil
|
||||
})
|
||||
|
@ -174,6 +182,7 @@ func TestPAM_005(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_006(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -197,6 +206,7 @@ func TestPAM_006(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_007(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
if u.Uid != "0" {
|
||||
t.Skip("run this test as root")
|
||||
|
@ -223,6 +233,7 @@ func TestPAM_007(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
c := Credentials{
|
||||
// the custom service always permits even with wrong password.
|
||||
|
@ -258,6 +269,7 @@ func TestPAM_ConfDir(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir_FailNoServiceOrUnsupported(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
if !CheckPamHasStartConfdir() {
|
||||
t.Skip("this requires PAM with Conf dir support")
|
||||
}
|
||||
|
@ -286,6 +298,7 @@ func TestPAM_ConfDir_FailNoServiceOrUnsupported(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir_InfoMessage(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
u, _ := user.Current()
|
||||
var infoText string
|
||||
tx, err := StartConfDir("echo-service", u.Username,
|
||||
|
@ -319,6 +332,7 @@ func TestPAM_ConfDir_InfoMessage(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir_Deny(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
if !CheckPamHasStartConfdir() {
|
||||
t.Skip("this requires PAM with Conf dir support")
|
||||
}
|
||||
|
@ -350,6 +364,7 @@ func TestPAM_ConfDir_Deny(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir_PromptForUserName(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
c := Credentials{
|
||||
User: "testuser",
|
||||
// the custom service only cares about correct user name.
|
||||
|
@ -375,6 +390,7 @@ func TestPAM_ConfDir_PromptForUserName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPAM_ConfDir_WrongUserName(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
c := Credentials{
|
||||
User: "wronguser",
|
||||
Password: "wrongsecret",
|
||||
|
@ -403,6 +419,7 @@ func TestPAM_ConfDir_WrongUserName(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestItem(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx, err := StartFunc("passwd", "test", func(s Style, msg string) (string, error) {
|
||||
return "", nil
|
||||
})
|
||||
|
@ -442,6 +459,7 @@ func TestItem(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx, err := StartFunc("", "", func(s Style, msg string) (string, error) {
|
||||
return "", nil
|
||||
})
|
||||
|
@ -511,6 +529,7 @@ func TestEnv(t *testing.T) {
|
|||
|
||||
func Test_Error(t *testing.T) {
|
||||
t.Parallel()
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
if !CheckPamHasStartConfdir() {
|
||||
t.Skip("this requires PAM with Conf dir support")
|
||||
}
|
||||
|
@ -624,6 +643,7 @@ func Test_Error(t *testing.T) {
|
|||
}
|
||||
|
||||
func Test_Finalizer(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
if !CheckPamHasStartConfdir() {
|
||||
t.Skip("this requires PAM with Conf dir support")
|
||||
}
|
||||
|
@ -643,6 +663,7 @@ func Test_Finalizer(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_001(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
_, err := tx.GetEnvList()
|
||||
if err == nil {
|
||||
|
@ -651,6 +672,7 @@ func TestFailure_001(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_002(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.PutEnv("")
|
||||
if err == nil {
|
||||
|
@ -659,6 +681,7 @@ func TestFailure_002(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_003(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.CloseSession(0)
|
||||
if err == nil {
|
||||
|
@ -667,6 +690,7 @@ func TestFailure_003(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_004(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.OpenSession(0)
|
||||
if err == nil {
|
||||
|
@ -675,6 +699,7 @@ func TestFailure_004(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_005(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.ChangeAuthTok(0)
|
||||
if err == nil {
|
||||
|
@ -683,6 +708,7 @@ func TestFailure_005(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_006(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.AcctMgmt(0)
|
||||
if err == nil {
|
||||
|
@ -691,6 +717,7 @@ func TestFailure_006(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_007(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.SetCred(0)
|
||||
if err == nil {
|
||||
|
@ -699,6 +726,7 @@ func TestFailure_007(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_008(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.SetItem(User, "test")
|
||||
if err == nil {
|
||||
|
@ -707,6 +735,7 @@ func TestFailure_008(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_009(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
_, err := tx.GetItem(User)
|
||||
if err == nil {
|
||||
|
@ -715,6 +744,7 @@ func TestFailure_009(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestFailure_010(t *testing.T) {
|
||||
t.Cleanup(maybeDoLeakCheck)
|
||||
tx := Transaction{}
|
||||
err := tx.End()
|
||||
if err != nil {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Package pam provides a wrapper for the PAM application API.
|
||||
package pam
|
||||
|
||||
/*
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
#include <sanitizer/lsan_interface.h>
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
maybe_do_leak_check (void)
|
||||
{
|
||||
#ifdef __SANITIZE_ADDRESS__
|
||||
__lsan_do_leak_check();
|
||||
#endif
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
func maybeDoLeakCheck() {
|
||||
runtime.GC()
|
||||
time.Sleep(time.Millisecond * 20)
|
||||
if os.Getenv("GO_PAM_SKIP_LEAK_CHECK") == "" {
|
||||
C.maybe_do_leak_check()
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue