Skip to content

feat: add SWIG support for generating multi-language bindings#53

Open
Copilot wants to merge 12 commits intomainfrom
copilot/add-swig-support
Open

feat: add SWIG support for generating multi-language bindings#53
Copilot wants to merge 12 commits intomainfrom
copilot/add-swig-support

Conversation

Copy link
Contributor

Copilot AI commented Feb 27, 2026

libcoraza needs SWIG compatibility to enable connector authors to generate bindings for Python, Ruby, Java, PHP, Perl, and other languages from the existing C API.

Changes

  • coraza.i — SWIG interface file:

    • Types declared independently to avoid exposing CGO-generated Go runtime boilerplate (_GoString_, GoInt, etc.) to SWIG
    • char **er output parameters hidden from target language via typemaps; raises a runtime exception with the actual error message on failure (language-specific: SWIG_JavaThrowException for Java, SWIG_Error + free + SWIG_fail for others) — C error string is freed after capture to prevent memory leaks
    • %newobject on coraza_matched_rule_get_error_log so target language runtime owns and frees the returned string
    • coraza_add_debug_log_callback / coraza_add_error_callback excluded via %ignore — function pointer handling is inherently language-specific and must be addressed per-binding
    • Python bytes/bytearray typemap: collapses (const unsigned char *data, int length) into a single native bytes argument
    • Java byte[] typemap: same pair mapped to a single byte[] argument
    • Java JNI library-load pragma: System.loadLibrary("coraza_jni") automatically embedded in the generated corazaJNI class
    • Source-of-truth comment cross-referencing libcoraza/coraza.go and make check-swig-sync
  • libcoraza/coraza.go — Sync warning comment added before the first //export annotation, directing developers to update coraza.i and run make check-swig-sync when adding, removing, or changing exported functions

  • configure.ac — Optional SWIG detection via AC_PATH_PROG + AM_CONDITIONAL([HAVE_SWIG]); shown in configure summary

  • Makefile.am — Conditional swig target (present only when SWIG is found); target language and output directory configurable via SWIG_LANG (default: python) and SWIG_OUTDIR (default: .):

    make swig                                          # generates Python bindings
    make swig SWIG_LANG=ruby                           # generates Ruby bindings
    make swig SWIG_LANG=java SWIG_OUTDIR=examples/java/gen  # generates Java bindings

    New check-swig-sync target verifies every //export function in libcoraza/coraza.go is accounted for in coraza.i (as an extern declaration or %ignore); exits non-zero if any are missing — safe to run in CI.

  • examples/python/ — Self-contained Python SWIG example directory:

    • simple_get.py — covers all exported functions testable without a native callback, including coraza_append_request_body / coraza_append_response_body via the native bytes typemap
    • Makefilemake builds the SWIG extension; make run executes the example; make clean removes generated files
    • README.md — prerequisites, build/run instructions, and function coverage table
  • examples/java/ — Self-contained Java SWIG example directory:

    • SimpleGet.java — covers all exported functions testable without a native callback using byte[] for body functions
    • Makefilemake generates the JNI library and compiles Java classes; make run executes the example; make clean removes generated artifacts
    • README.md — prerequisites, build/run instructions, and function coverage table
  • .github/workflows/swig.yml — CI workflow with two jobs (swig-python, swig-java), each tested against Go 1.24.x and 1.25.x on Ubuntu: installs dependencies, builds libcoraza, then delegates to make -C examples/python run / make -C examples/java run; all actions pinned to latest release SHA

  • .github/workflows/make-install.yml — Updated to pin all actions to latest release SHA

  • README.md — Documents SWIG prerequisites, build steps, and a complete Python compilation example; also fixes pre-existing $LID_LIBRARY_PATH typo

  • .gitignore — Excludes generated SWIG wrapper sources, language modules, examples/java/gen/, and other per-directory build artifacts; tracks examples/python/Makefile and examples/java/Makefile via negation rules

All GitHub Actions across all workflows are pinned by full commit SHA alongside a version comment (e.g. actions/setup-go@<sha> # v6.3.0, actions/checkout@<sha> # v6.0.2) for supply-chain security.

Original prompt

This section details on the original issue you should resolve

<issue_title>Add SWIG support</issue_title>
<issue_description>Many connectors will be born once this project is production-ready. We must keep in focus SWIG compatibility for the final v1 release.

SWIG is a software development tool that connects programs written in C and C++ with a variety of high-level programming languages. SWIG is used with different types of target languages including common scripting languages such as Javascript, Perl, PHP, Python, Tcl and Ruby.

  • Add some macros for compatibility
  • Make documentation compatible
  • Document the building process
  • Add it to the Makefile</issue_description>

Comments on the Issue (you are @copilot in this section)


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Copilot AI changed the title [WIP] Add SWIG support for project compatibility Add SWIG support for generating multi-language bindings Feb 27, 2026
@jptosso
Copy link
Member

jptosso commented Feb 27, 2026

@copilot add GitHub action tests for Java and python wrappers, add the examples to examples directory and keep tests consistent and covering all exported functions.

Copy link
Contributor Author

Copilot AI commented Feb 27, 2026

@copilot add GitHub action tests for Java and python wrappers, add the examples to examples directory and keep tests consistent and covering all exported functions.

Done in commit 2a8ac8c:

  • examples/python/simple_get.py and examples/java/SimpleGet.java — examples in the examples/ directory covering all exported functions testable without a native callback (test_lifecycle, test_request_body_from_file, test_rules_merge).
  • .github/workflows/swig.yml — CI jobs swig-python and swig-java, each run against Go 1.24.x and 1.25.x, that build the library, generate the SWIG wrapper, compile it, and run the example.
  • coraza.i — added Python bytes/bytearray and Java byte[] typemaps for the (const unsigned char *data, int length) parameter pair (so coraza_append_request_body / coraza_append_response_body accept native byte arrays), plus a Java JNI library-load pragma and language-specific exception handling for the char **er output parameter.

Functions not covered by the SWIG examples are coraza_matched_rule_get_severity and coraza_matched_rule_get_error_log, which require a matched-rule handle that is only obtainable via coraza_add_error_callback — excluded from the default SWIG wrapper since function-pointer callbacks are language-specific.

@jptosso
Copy link
Member

jptosso commented Feb 27, 2026

@copilot add GitHub action tests for Java and python wrappers, add the examples to examples directory and keep tests consistent and covering all exported functions.

Done in commit 2a8ac8c:

  • examples/python/simple_get.py and examples/java/SimpleGet.java — examples in the examples/ directory covering all exported functions testable without a native callback (test_lifecycle, test_request_body_from_file, test_rules_merge).
  • .github/workflows/swig.yml — CI jobs swig-python and swig-java, each run against Go 1.24.x and 1.25.x, that build the library, generate the SWIG wrapper, compile it, and run the example.
  • coraza.i — added Python bytes/bytearray and Java byte[] typemaps for the (const unsigned char *data, int length) parameter pair (so coraza_append_request_body / coraza_append_response_body accept native byte arrays), plus a Java JNI library-load pragma and language-specific exception handling for the char **er output parameter.

Functions not covered by the SWIG examples are coraza_matched_rule_get_severity and coraza_matched_rule_get_error_log, which require a matched-rule handle that is only obtainable via coraza_add_error_callback — excluded from the default SWIG wrapper since function-pointer callbacks are language-specific.

@copilot add the language specific examples, we need a directory for Java and a directory for python following a similar example

Copy link
Contributor Author

Copilot AI commented Feb 27, 2026

@copilot add GitHub action tests for Java and python wrappers, add the examples to examples directory and keep tests consistent and covering all exported functions.
...

Done in commit 0c80cc1. Each language directory is now self-contained:

examples/python/

  • Makefilemake builds the SWIG extension; make run runs the example; make clean removes generated files
  • README.md — prerequisites, build/run instructions, full function coverage table

examples/java/

  • Makefilemake generates the JNI library and compiles the Java classes; make run executes the example; make clean removes generated artifacts
  • README.md — prerequisites, build/run instructions, full function coverage table

The CI workflow now delegates to these Makefiles (make -C examples/python run / make -C examples/java run) rather than repeating the build commands inline.

@fzipi
Copy link
Member

fzipi commented Feb 28, 2026

@copilot update the gha version releases for all actions to latest, and include always the sha of the release.

Copy link
Contributor Author

Copilot AI commented Feb 28, 2026

@copilot update the gha version releases for all actions to latest, and include always the sha of the release.

Done in commit 2aa4462. All actions in both swig.yml and make-install.yml are now pinned to their latest release SHA:

  • actions/setup-go@4b73464bb391d4059bd26b0524d20df3927bd417 # v6.3.0
  • actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class SWIG support to libcoraza so connector authors can generate multi-language bindings from the existing C API, along with CI-verified Python and Java example bindings.

Changes:

  • Introduces coraza.i SWIG interface with language-specific typemaps (errors, byte buffers) and exclusions for callback APIs.
  • Adds optional SWIG detection + a conditional make swig target in the autotools build.
  • Adds Python/Java SWIG example projects and a CI workflow that builds/runs them.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
coraza.i Defines the SWIG module, mirrors C API types, and adds typemaps for error handling + byte buffers.
configure.ac Detects SWIG optionally and reports it in the configure summary.
Makefile.am Adds a conditional swig make target controlled by HAVE_SWIG.
README.md Documents SWIG prerequisites/build steps and fixes an LD_LIBRARY_PATH typo.
examples/python/simple_get.py Python smoke-test script exercising SWIG-exported APIs (no callbacks).
examples/python/README.md Python example build/run docs and function coverage table.
examples/python/Makefile Builds the Python SWIG wrapper/extension against libcoraza.
examples/java/SimpleGet.java Java smoke-test exercising SWIG-exported APIs (no callbacks).
examples/java/README.md Java example build/run docs and function coverage table.
examples/java/Makefile Builds the Java SWIG wrapper + JNI library and runs the example.
.github/workflows/swig.yml CI jobs to generate/build/run Python and Java SWIG examples.
.gitignore Ignores generated SWIG artifacts and un-ignores the example Makefiles.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@fzipi
Copy link
Member

fzipi commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

Copy link
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot apply changes based on the comments in this thread

Done in commit ca2033c:

  • coraza.i: Fixed memory leak in the char **er typemap — the C string allocated by libcoraza is now freed after it's captured. For non-Java: replaced SWIG_exception_fail with SWIG_Error + free + SWIG_fail (since SWIG_Error copies the message before returning, freeing the original is safe). Added #include <stdlib.h> for free(). For Java: free() added after SWIG_JavaThrowException.
  • examples/python/simple_get.py: Simplified docstring build commands to make -C examples/python / make -C examples/python run.
  • examples/java/SimpleGet.java: Updated build/run instructions to make -C examples/java and LD_LIBRARY_PATH=examples/java java -cp examples/java/gen/ -Djava.library.path=examples/java SimpleGet.

Copilot finished work on behalf of fzipi March 1, 2026 15:28
@fzipi fzipi marked this pull request as ready for review March 1, 2026 15:29
@fzipi
Copy link
Member

fzipi commented Mar 1, 2026

@copilot Looks like functions defined in the Go code can lose sync with the defined in the coraza.i file. Can this be solved automatically. E.g. adding something into the Makefile for autogeneration? If not, then add clear warnings in the origin Golang file to update the dependent swig interface file.

Copy link
Contributor Author

Copilot AI commented Mar 1, 2026

@copilot Looks like functions defined in the Go code can lose sync with the defined in the coraza.i file. Can this be solved automatically. E.g. adding something into the Makefile fo...

Full auto-generation of coraza.i isn't feasible because it contains hand-written typemaps, %ignore directives, and %newobject annotations that can't be derived from the C header alone. Done in commit a7e192e with a lighter-weight approach:

  • make check-swig-sync (new Makefile.am target) — greps every //export function name from libcoraza/coraza.go and verifies it appears in coraza.i as either an extern declaration or a %ignore directive; exits non-zero if anything is missing.
  • Warning comment in libcoraza/coraza.go — placed just before the first //export, directing developers to update coraza.i and run make check-swig-sync.
  • Source-of-truth comment in coraza.i — cross-references libcoraza/coraza.go and the sync target.

This can also be wired into CI by adding a make check-swig-sync step to the workflow if desired.

Copilot finished work on behalf of fzipi March 1, 2026 18:12
Copy link
Member

@fzipi fzipi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now.

@fzipi fzipi changed the title Add SWIG support for generating multi-language bindings feat: add SWIG support for generating multi-language bindings Mar 1, 2026
@fzipi
Copy link
Member

fzipi commented Mar 1, 2026

@jptosso Can you review this one?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add SWIG support

4 participants