From 9b8395ba0ee8d3530174f853980c3cfd43e1f253 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Thu, 7 Aug 2025 19:57:31 +0800 Subject: [PATCH 1/5] chore(ci): add go linter --- .github/workflows/go-lint.yml | 27 +++ .golangci.yml | 3 + Makefile | 6 + f3-sidecar/ffi_impl.go | 3 +- interop-tests/src/tests/go_app/.gitignore | 1 - interop-tests/src/tests/go_app/common.go | 3 +- interop-tests/src/tests/go_app/gen.go | 237 ++++++++++++++++++++++ 7 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/go-lint.yml create mode 100644 .golangci.yml delete mode 100644 interop-tests/src/tests/go_app/.gitignore create mode 100644 interop-tests/src/tests/go_app/gen.go diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml new file mode 100644 index 000000000000..f450c4683359 --- /dev/null +++ b/.github/workflows/go-lint.yml @@ -0,0 +1,27 @@ +name: Go code linters + +# Cancel workflow if there is a new change to the branch. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} + +on: + workflow_dispatch: + merge_group: + pull_request: + branches: + - main + push: + branches: + - main + +jobs: + lint-go: + name: Go lint checks + runs-on: ubuntu-24.04-arm + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.work" + - run: make lint-go diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 000000000000..4bbb013f4e47 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,3 @@ +version: "2" +linters: + default: standard diff --git a/Makefile b/Makefile index 39b9dc0f671d..04a7669b317c 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +GOLANGCI_LINT_VERSION=v2.3.1 + install: cargo install --locked --path . --force @@ -77,6 +79,10 @@ DOCKERFILES=$(wildcard Dockerfile*) lint-docker: $(DOCKERFILES) docker run --rm -i hadolint/hadolint < $< +lint-go: + go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) + go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run --timeout 10m --concurrency 4 ./f3-sidecar ./interop-tests/src/tests/go_app + # Formats Rust, TOML and Markdown files. fmt: cargo fmt --all diff --git a/f3-sidecar/ffi_impl.go b/f3-sidecar/ffi_impl.go index e58a1c173d98..ca4356449a01 100644 --- a/f3-sidecar/ffi_impl.go +++ b/f3-sidecar/ffi_impl.go @@ -57,5 +57,6 @@ func checkError(err error) { // To avoid potential panics // See func setGoDebugEnv() { - os.Setenv("GODEBUG", "invalidptr=0,cgocheck=0") + err := os.Setenv("GODEBUG", "invalidptr=0,cgocheck=0") + checkError(err) } diff --git a/interop-tests/src/tests/go_app/.gitignore b/interop-tests/src/tests/go_app/.gitignore deleted file mode 100644 index 40781048e6eb..000000000000 --- a/interop-tests/src/tests/go_app/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gen.go diff --git a/interop-tests/src/tests/go_app/common.go b/interop-tests/src/tests/go_app/common.go index 045c3cf3d1c1..c06bb3bdfd29 100644 --- a/interop-tests/src/tests/go_app/common.go +++ b/interop-tests/src/tests/go_app/common.go @@ -13,5 +13,6 @@ func checkError(err error) { // To avoid potential panics // See func setGoDebugEnv() { - os.Setenv("GODEBUG", "invalidptr=0,cgocheck=0") + err := os.Setenv("GODEBUG", "invalidptr=0,cgocheck=0") + checkError(err) } diff --git a/interop-tests/src/tests/go_app/gen.go b/interop-tests/src/tests/go_app/gen.go new file mode 100644 index 000000000000..c9bce1458eca --- /dev/null +++ b/interop-tests/src/tests/go_app/gen.go @@ -0,0 +1,237 @@ +package main + +/* +// Generated by rust2go. Please DO NOT edit this C part manually. + +#include +#include +#include +#include + +typedef struct ListRef { + const void *ptr; + uintptr_t len; +} ListRef; + +typedef struct StringRef { + const uint8_t *ptr; + uintptr_t len; +} StringRef; +*/ +import "C" +import ( + "runtime" + "unsafe" + + "github.com/ihciah/rust2go/asmcall" +) + +var GoKadNodeImpl GoKadNode + +type GoKadNode interface { + run() + connect(multiaddr *string) + get_n_connected() uint +} + +//export CGoKadNode_run +func CGoKadNode_run() { + GoKadNodeImpl.run() +} + +//export CGoKadNode_connect +func CGoKadNode_connect(multiaddr C.StringRef) { + _new_multiaddr := newString(multiaddr) + GoKadNodeImpl.connect(&_new_multiaddr) +} + +//export CGoKadNode_get_n_connected +func CGoKadNode_get_n_connected(slot *C.void, cb *C.void) { + resp := GoKadNodeImpl.get_n_connected() + resp_ref, buffer := cvt_ref(cntC_uintptr_t, refC_uintptr_t)(&resp) + asmcall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot)) + runtime.KeepAlive(resp_ref) + runtime.KeepAlive(resp) + runtime.KeepAlive(buffer) +} + +var GoBitswapNodeImpl GoBitswapNode + +type GoBitswapNode interface { + run() + connect(multiaddr *string) + get_block(cid *string) bool +} + +//export CGoBitswapNode_run +func CGoBitswapNode_run() { + GoBitswapNodeImpl.run() +} + +//export CGoBitswapNode_connect +func CGoBitswapNode_connect(multiaddr C.StringRef) { + _new_multiaddr := newString(multiaddr) + GoBitswapNodeImpl.connect(&_new_multiaddr) +} + +//export CGoBitswapNode_get_block +func CGoBitswapNode_get_block(cid C.StringRef, slot *C.void, cb *C.void) { + _new_cid := newString(cid) + resp := GoBitswapNodeImpl.get_block(&_new_cid) + resp_ref, buffer := cvt_ref(cntC_bool, refC_bool)(&resp) + asmcall.CallFuncG0P2(unsafe.Pointer(cb), unsafe.Pointer(&resp_ref), unsafe.Pointer(slot)) + runtime.KeepAlive(resp_ref) + runtime.KeepAlive(resp) + runtime.KeepAlive(buffer) +} + +func newString(s_ref C.StringRef) string { + return unsafe.String((*byte)(unsafe.Pointer(s_ref.ptr)), s_ref.len) +} +func refString(s *string, _ *[]byte) C.StringRef { + return C.StringRef{ + ptr: (*C.uint8_t)(unsafe.StringData(*s)), + len: C.uintptr_t(len(*s)), + } +} + +func ownString(s_ref C.StringRef) string { + return string(unsafe.Slice((*byte)(unsafe.Pointer(s_ref.ptr)), int(s_ref.len))) +} +func cntString(_ *string, _ *uint) [0]C.StringRef { return [0]C.StringRef{} } +func new_list_mapper[T1, T2 any](f func(T1) T2) func(C.ListRef) []T2 { + return func(x C.ListRef) []T2 { + input := unsafe.Slice((*T1)(unsafe.Pointer(x.ptr)), x.len) + output := make([]T2, len(input)) + for i, v := range input { + output[i] = f(v) + } + return output + } +} +func new_list_mapper_primitive[T1, T2 any](_ func(T1) T2) func(C.ListRef) []T2 { + return func(x C.ListRef) []T2 { + return unsafe.Slice((*T2)(unsafe.Pointer(x.ptr)), x.len) + } +} + +// only handle non-primitive type T +func cnt_list_mapper[T, R any](f func(s *T, cnt *uint) [0]R) func(s *[]T, cnt *uint) [0]C.ListRef { + return func(s *[]T, cnt *uint) [0]C.ListRef { + for _, v := range *s { + f(&v, cnt) + } + *cnt += uint(len(*s)) * size_of[R]() + return [0]C.ListRef{} + } +} + +// only handle primitive type T +func cnt_list_mapper_primitive[T, R any](_ func(s *T, cnt *uint) [0]R) func(s *[]T, cnt *uint) [0]C.ListRef { + return func(s *[]T, cnt *uint) [0]C.ListRef { return [0]C.ListRef{} } +} + +// only handle non-primitive type T +func ref_list_mapper[T, R any](f func(s *T, buffer *[]byte) R) func(s *[]T, buffer *[]byte) C.ListRef { + return func(s *[]T, buffer *[]byte) C.ListRef { + if len(*buffer) == 0 { + return C.ListRef{ + ptr: unsafe.Pointer(nil), + len: C.uintptr_t(len(*s)), + } + } + ret := C.ListRef{ + ptr: unsafe.Pointer(&(*buffer)[0]), + len: C.uintptr_t(len(*s)), + } + children_bytes := int(size_of[R]()) * len(*s) + children := (*buffer)[:children_bytes] + *buffer = (*buffer)[children_bytes:] + for _, v := range *s { + child := f(&v, buffer) + len := unsafe.Sizeof(child) + copy(children, unsafe.Slice((*byte)(unsafe.Pointer(&child)), len)) + children = children[len:] + } + return ret + } +} + +// only handle primitive type T +func ref_list_mapper_primitive[T, R any](_ func(s *T, buffer *[]byte) R) func(s *[]T, buffer *[]byte) C.ListRef { + return func(s *[]T, buffer *[]byte) C.ListRef { + if len(*s) == 0 { + return C.ListRef{ + ptr: unsafe.Pointer(nil), + len: C.uintptr_t(0), + } + } + return C.ListRef{ + ptr: unsafe.Pointer(&(*s)[0]), + len: C.uintptr_t(len(*s)), + } + } +} +func size_of[T any]() uint { + var t T + return uint(unsafe.Sizeof(t)) +} +func cvt_ref[R, CR any](cnt_f func(s *R, cnt *uint) [0]CR, ref_f func(p *R, buffer *[]byte) CR) func(p *R) (CR, []byte) { + return func(p *R) (CR, []byte) { + var cnt uint + cnt_f(p, &cnt) + buffer := make([]byte, cnt) + return ref_f(p, &buffer), buffer + } +} +func cvt_ref_cap[R, CR any](cnt_f func(s *R, cnt *uint) [0]CR, ref_f func(p *R, buffer *[]byte) CR, add_cap uint) func(p *R) (CR, []byte) { + return func(p *R) (CR, []byte) { + var cnt uint + cnt_f(p, &cnt) + buffer := make([]byte, cnt, cnt+add_cap) + return ref_f(p, &buffer), buffer + } +} + +func newC_uint8_t(n C.uint8_t) uint8 { return uint8(n) } +func newC_uint16_t(n C.uint16_t) uint16 { return uint16(n) } +func newC_uint32_t(n C.uint32_t) uint32 { return uint32(n) } +func newC_uint64_t(n C.uint64_t) uint64 { return uint64(n) } +func newC_int8_t(n C.int8_t) int8 { return int8(n) } +func newC_int16_t(n C.int16_t) int16 { return int16(n) } +func newC_int32_t(n C.int32_t) int32 { return int32(n) } +func newC_int64_t(n C.int64_t) int64 { return int64(n) } +func newC_bool(n C.bool) bool { return bool(n) } +func newC_uintptr_t(n C.uintptr_t) uint { return uint(n) } +func newC_intptr_t(n C.intptr_t) int { return int(n) } +func newC_float(n C.float) float32 { return float32(n) } +func newC_double(n C.double) float64 { return float64(n) } + +func cntC_uint8_t(_ *uint8, _ *uint) [0]C.uint8_t { return [0]C.uint8_t{} } +func cntC_uint16_t(_ *uint16, _ *uint) [0]C.uint16_t { return [0]C.uint16_t{} } +func cntC_uint32_t(_ *uint32, _ *uint) [0]C.uint32_t { return [0]C.uint32_t{} } +func cntC_uint64_t(_ *uint64, _ *uint) [0]C.uint64_t { return [0]C.uint64_t{} } +func cntC_int8_t(_ *int8, _ *uint) [0]C.int8_t { return [0]C.int8_t{} } +func cntC_int16_t(_ *int16, _ *uint) [0]C.int16_t { return [0]C.int16_t{} } +func cntC_int32_t(_ *int32, _ *uint) [0]C.int32_t { return [0]C.int32_t{} } +func cntC_int64_t(_ *int64, _ *uint) [0]C.int64_t { return [0]C.int64_t{} } +func cntC_bool(_ *bool, _ *uint) [0]C.bool { return [0]C.bool{} } +func cntC_uintptr_t(_ *uint, _ *uint) [0]C.uintptr_t { return [0]C.uintptr_t{} } +func cntC_intptr_t(_ *int, _ *uint) [0]C.intptr_t { return [0]C.intptr_t{} } +func cntC_float(_ *float32, _ *uint) [0]C.float { return [0]C.float{} } +func cntC_double(_ *float64, _ *uint) [0]C.double { return [0]C.double{} } + +func refC_uint8_t(p *uint8, _ *[]byte) C.uint8_t { return C.uint8_t(*p) } +func refC_uint16_t(p *uint16, _ *[]byte) C.uint16_t { return C.uint16_t(*p) } +func refC_uint32_t(p *uint32, _ *[]byte) C.uint32_t { return C.uint32_t(*p) } +func refC_uint64_t(p *uint64, _ *[]byte) C.uint64_t { return C.uint64_t(*p) } +func refC_int8_t(p *int8, _ *[]byte) C.int8_t { return C.int8_t(*p) } +func refC_int16_t(p *int16, _ *[]byte) C.int16_t { return C.int16_t(*p) } +func refC_int32_t(p *int32, _ *[]byte) C.int32_t { return C.int32_t(*p) } +func refC_int64_t(p *int64, _ *[]byte) C.int64_t { return C.int64_t(*p) } +func refC_bool(p *bool, _ *[]byte) C.bool { return C.bool(*p) } +func refC_uintptr_t(p *uint, _ *[]byte) C.uintptr_t { return C.uintptr_t(*p) } +func refC_intptr_t(p *int, _ *[]byte) C.intptr_t { return C.intptr_t(*p) } +func refC_float(p *float32, _ *[]byte) C.float { return C.float(*p) } +func refC_double(p *float64, _ *[]byte) C.double { return C.double(*p) } +func main() {} From 379633de9d2b4dd0cd828ccac62a2d4d26b56cd8 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Thu, 7 Aug 2025 20:09:41 +0800 Subject: [PATCH 2/5] Potential fix for code scanning alert no. 63: Workflow does not contain permissions Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- .github/workflows/go-lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index f450c4683359..570be5550ef3 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -1,4 +1,6 @@ name: Go code linters +permissions: + contents: read # Cancel workflow if there is a new change to the branch. concurrency: From 302ab0957886b23a481cf4f6534ff7c17f774760 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Thu, 7 Aug 2025 20:30:07 +0800 Subject: [PATCH 3/5] path filter --- .github/workflows/go-lint.yml | 12 ++++++++++++ Makefile | 1 - 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/go-lint.yml b/.github/workflows/go-lint.yml index 570be5550ef3..dba6cf59cb49 100644 --- a/.github/workflows/go-lint.yml +++ b/.github/workflows/go-lint.yml @@ -13,9 +13,21 @@ on: pull_request: branches: - main + paths: + - ".github/workflows/go-lint.yml" + - "Makefile" + - "go.work" + - "f3-sidecar/**" + - "interop-tests/src/tests/**" push: branches: - main + paths: + - ".github/workflows/go-lint.yml" + - "Makefile" + - "go.work" + - "f3-sidecar/**" + - "interop-tests/src/tests/**" jobs: lint-go: diff --git a/Makefile b/Makefile index 04a7669b317c..5744219ca09a 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,6 @@ lint-docker: $(DOCKERFILES) docker run --rm -i hadolint/hadolint < $< lint-go: - go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run --timeout 10m --concurrency 4 ./f3-sidecar ./interop-tests/src/tests/go_app # Formats Rust, TOML and Markdown files. From 48b213d5f7564eecd41d55a5c55ec1311dc23cd8 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Fri, 8 Aug 2025 16:16:34 +0800 Subject: [PATCH 4/5] remove GOLANGCI_LINT_VERSION from Makefile --- Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 5744219ca09a..ddfbcbecf669 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,3 @@ -GOLANGCI_LINT_VERSION=v2.3.1 - install: cargo install --locked --path . --force @@ -80,7 +78,7 @@ lint-docker: $(DOCKERFILES) docker run --rm -i hadolint/hadolint < $< lint-go: - go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION) run --timeout 10m --concurrency 4 ./f3-sidecar ./interop-tests/src/tests/go_app + go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.3.1 run --timeout 10m --concurrency 4 ./f3-sidecar ./interop-tests/src/tests/go_app # Formats Rust, TOML and Markdown files. fmt: From 26b7ac078e2547446d857622e31bb8643ad94e47 Mon Sep 17 00:00:00 2001 From: hanabi1224 Date: Fri, 8 Aug 2025 19:30:06 +0800 Subject: [PATCH 5/5] exclude generated code --- .golangci.yml | 7 +++++++ Makefile | 2 +- interop-tests/build.rs | 2 +- interop-tests/src/tests/go_app/{gen.go => ffi_gen.go} | 0 4 files changed, 9 insertions(+), 2 deletions(-) rename interop-tests/src/tests/go_app/{gen.go => ffi_gen.go} (100%) diff --git a/.golangci.yml b/.golangci.yml index 4bbb013f4e47..e278a9fb0ae6 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,3 +1,10 @@ version: "2" linters: default: standard + exclusions: + generated: lax +severity: + default: warn +run: + timeout: 5m + relative-path-mode: gomod diff --git a/Makefile b/Makefile index ddfbcbecf669..f34d7a080b2d 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ lint-docker: $(DOCKERFILES) docker run --rm -i hadolint/hadolint < $< lint-go: - go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.3.1 run --timeout 10m --concurrency 4 ./f3-sidecar ./interop-tests/src/tests/go_app + go run github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.3.1 run ./f3-sidecar ./interop-tests/src/tests/go_app # Formats Rust, TOML and Markdown files. fmt: diff --git a/interop-tests/build.rs b/interop-tests/build.rs index 35f908ca791f..a523c02d87e1 100644 --- a/interop-tests/build.rs +++ b/interop-tests/build.rs @@ -11,7 +11,7 @@ fn main() { .with_go_src("./src/tests/go_app") .with_regen_arg(rust2go::RegenArgs { src: "./src/tests/go_ffi.rs".into(), - dst: "./src/tests/go_app/gen.go".into(), + dst: "./src/tests/go_app/ffi_gen.go".into(), ..Default::default() }) .build(); diff --git a/interop-tests/src/tests/go_app/gen.go b/interop-tests/src/tests/go_app/ffi_gen.go similarity index 100% rename from interop-tests/src/tests/go_app/gen.go rename to interop-tests/src/tests/go_app/ffi_gen.go