{"owner":"TykTechnologies","repo":"tyk","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":3392,"categories":["plugin-manifest","anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["ci/tests/python-plugins/extend-python/README.md","docs/plugins/go-development-flow.md"],"skills":{"ci/tests/python-plugins/extend-python/README.md":"### Tyk Gateway with Python Coprocess\n\nStarting from Tyk Gateway version `v5.3.0`, Python is no longer bundled with the official Docker images. \nHowever, Tyk Gateway continues to support Python plugins functionality. \n\nIf you wish to use Python plugins, you can extend the official Docker image by adding Python to it. \nThis directory contains a sample Dockerfile that demonstrates how to achieve this.","docs/plugins/go-development-flow.md":"---\ntitle: Custom Go plugin development flow\ntags:\n    - custom plugin\n    - golang\n    - go plugin\n    - middleware\n    - debugging go plugins\ndescription: Development flow working with Go Plugins\ndate: \"2024-10-11\"\n---\n\nWe recommend that you familiarize yourself with the following official Go documentation to help you work effectively with Go plugins:\n\n- [The official plugin package documentation - Warnings](https://pkg.go.dev/plugin)\n- [Tutorial: Getting started with multi-module workspaces](https://go.dev/doc/tutorial/workspaces)\n\n{{< note success >}} **Note**\n\nPlugins are currently supported only on Linux, FreeBSD, and macOS, making them unsuitable for applications intended to be portable. {{< /note >}}\n\nPlugins need to be compiled to native shared object code, which can then be loaded by Tyk Gateway. It's important to understand the need for plugins to be compiled using exactly the same environment and [build flags]({{< ref \"product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-development-flow#build-flags\" >}}) as the Gateway. To simplify this and minimise the risk of compatibility problems, we recommend the use of [Go workspaces](https://go.dev/blog/get-familiar-with-workspaces), to provide a consistent environment.\n\n## Setting up your environment\n\nTo develop plugins, you'll need:\n\n- Go (matching the version used in the Gateway, which you can determine using `go.mod`).\n- Git to check out Tyk Gateway source code.\n- A folder with the code that you want to build into plugins.\n\nWe recommend that you set up a *Go workspace*, which, at the end, is going to contain:\n\n- `/tyk-release-x.y.z` - the Tyk Gateway source code\n- `/plugins` - the plugins\n- `/go.work` - the *Go workspace* file\n- `/go.work.sum` - *Go workspace* package checksums\n\nUsing the *Go workspace* ensures build compatibility between the plugins and Gateway.\n\n### 1. Checking out Tyk Gateway source code\n\n```\ngit clone --branch release-5.3.6 https://github.com/TykTechnologies/tyk.git tyk-release-5.3.6 || true\n```\n\nThis example uses a particular `release-5.3.6` branch, to match Tyk Gateway release 5.3.6. With newer `git` versions, you may pass `--branch v5.3.6` and it would use the tag. In case you want to use the tag it's also possible to navigate into the folder and issue `git checkout tags/v5.3.6`.\n\n### 2. Preparing the Go workspace\n\nYour Go workspace can be very simple:\n\n1. Create a `.go` file containing the code for your plugin.\n2. Create a `go.mod` file for the plugin.\n3. Ensure the correct Go version is in use.\n\nAs an example, we can use the [CustomGoPlugin.go](https://github.com/TykTechnologies/custom-go-plugin/blob/master/go/src/CustomGoPlugin.go) sample as the source for our plugin as shown:\n\n```\nmkdir -p plugins\ncd plugins\ngo mod init testplugin\ngo mod edit -go $(go mod edit -json go.mod | jq -r .Go)\nwget -q https://raw.githubusercontent.com/TykTechnologies/custom-go-plugin/refs/heads/master/go/src/CustomGoPlugin.go\ncd -\n```\n\nThe following snippet provides you with a way to get the exact Go version used by Gateway from it's [go.mod](https://github.com/TykTechnologies/tyk/blob/release-5.3.6/go.mod#L3) file:\n\n- `go mod edit -json go.mod | jq -r .Go` (e.g. `1.22.7`)\n\nThis should be used to ensure the version matches between gateway and the plugin.\n\nTo summarize what was done:\n\n1. We created a plugins folder and initialzed a `go` project using `go mod` command.\n2. Set the Go version of `go.mod` to match the one set in the Gateway.\n3. Initialzied the project with sample plugin `go` code.\n\nAt this point, we don't have a *Go workspace* but we will create one next so that we can effectively share the Gateway dependency across Go modules.\n\n### 3. Creating the Go workspace\n\nTo set up the Go workspace, start in the directory that contains the Gateway and the Plugins folder. You'll first, create the `go.work` file to set up your Go workspace, and include the `tyk-release-5.3.6` and `plugins` folders. Then, navigate to the plugins folder to fetch the Gateway dependency at the exact commit hash and run `go mod tidy` to ensure dependencies are up to date.\n\nFollow these commands:\n\n```\ngo work init ./tyk-release-5.3.6\ngo work use ./plugins\ncommit_hash=$(cd tyk-release-5.3.6 && git rev-parse HEAD)\ncd plugins && go get github.com/TykTechnologies/tyk@${commit_hash} && go mod tidy && cd -\n```\n\nThe following snippet provides you to get the commit hash exactly, so it can be used with `go get`.\n\n- `git rev-parse HEAD`\n\nThe Go workspace file (`go.work`) should look like this:\n\n```\ngo 1.22.7\n\nuse (\n\t./plugins\n\t./tyk-release-5.3.6\n)\n```\n\n### 4. Building and validating the plugin\n\nNow that your *Go workspace* is ready, you can build your plugin as follows:\n\n```\ncd tyk-release-5.3.6 && go build -tags=goplugin -trimpath . && cd -\ncd plugins           && go build -trimpath -buildmode=plugin . && cd -\n```\n\nThese steps build both the Gateway and the plugin.\n\nYou can use the Gateway binary that you just built to test that your new plugin loads into the Gateway without having to configure and then make a request to an API using this command:\n\n```\n./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\n```\n\nYou should see an output similar to:\n\n```\ntime=\"Oct 14 13:39:55\" level=info msg=\"--- Go custom plugin init success! ---- \"\n[file=plugins/testplugin.so, symbol=AuthCheck] loaded ok, got 0x76e1aeb52140\n```\n\nThe log shows that the plugin has correctly loaded into the Gateway and that its `init` function has been successfully invoked.\n\n### 5. Summary\n\nIn the preceding steps we have put together an end-to-end build environment for both the Gateway and the plugin. Bear in mind that runtime environments may have additional restrictions beyond Go version and build flags to which the plugin developer must pay attention.\n\nCompatibility in general is a big concern when working with Go plugins: as the plugins are tightly coupled to the Gateway, consideration must always be made for the build restrictions enforced by environment and configuration options.\n\nContinue with [Loading Go Plugins into Tyk](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/loading-go-plugins/).\n\n## Debugging Golang Plugins\n\nPlugins are native Go code compiled to a binary shared object file. The code may depend on `cgo` and require libraries like `libc` provided by the runtime environment. The following are some debugging steps for diagnosing issues arising from using plugins.\n\n### Warnings\n\nThe [Plugin package - Warnings](https://pkg.go.dev/plugin#hdr-Warnings) section in the Go documentation outlines several requirements which can't be ignored when working with plugins. The most important restriction is the following:\n\n> Runtime crashes are likely to occur unless all parts of the program (the application and all its plugins) are compiled using exactly the same version of the toolchain, the same build tags, and the same values of certain flags and environment variables.\n\nWe provide the *Tyk Plugin Compiler* docker image, which we strongly recommend is used to build plugins compatible with the official Gateway releases. This tool provides the cross compilation toolchain, Go version used to build the release, and ensures that compatible flags are used when compiling plugins, like `-trimpath`, `CC`, `CGO_ENABLED`, `GOOS`, `GOARCH`.\n\nThe *Plugin Compiler* also works around known Go issues such as:\n\n- https://github.com/golang/go/issues/19004\n- https://www.reddit.com/r/golang/comments/qxghjv/plugin_already_loaded_when_a_plugin_is_loaded/\n\nSupplying the argument `build_id` to the *Plugin Compiler* ensures the same plugin can be rebuilt. The *Plugin Compiler* does this by replacing the plugin `go.mod` module path.\n\nContinue with [Tyk Plugin Compiler](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-plugin-compiler/).\n\n### Using Incorrect Build Flags\n\nWhen working with Go plugins, it's easy to miss the restriction that the plugin at the very least must be built with the same Go version, and the same flags (notably `-trimpath`) as the Tyk Gateway on which it is to be used.\n\nIf you miss an argument (for example `-trimpath`) when building the plugin, the Gateway will report an error when your API attempts to load the plugin, for example:\n\n```\ntask: [test] cd tyk-release-5.3.6 && go build -tags=goplugin -trimpath .\ntask: [test] cd plugins && go build -buildmode=plugin .\ntask: [test] ./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\ntyk: error: unexpected error: plugin.Open(\"plugins/testplugin\"): plugin was built with a different version of package internal/goarch, try --help\n```\n\nUsually when the error hints at a standard library package, the build flags between the Gateway and plugin binaries don't match.\n\nOther error messages may be reported, depending on what triggered the issue. For example, if you omitted `-race` in the plugin but the gateway was built with `-race`, the following error will be reported:\n\n```\nplugin was built with a different version of package runtime/internal/sys, try --help\n```\n\nStrictly speaking:\n\n- Build flags like `-trimpath`, `-race` need to match.\n- Go toolchain / build env needs to be exactly the same.\n- For cross compilation you must use the same `CC` value for the build (CGO).\n- `CGO_ENABLED=1`, `GOOS`, `GOARCH` must match with runtime.\n\nWhen something is off, you can check what is different by using the `go version -m` command for the Gateway (`go version -m tyk`) and plugin (`go version -m plugin.so`). Inspecting and comparing the output of `build` tokens usually yields the difference that caused the compatibility issue.\n\n### Plugin Compatibility Issues\n\nBelow are some common situations where dependencies might cause issues:\n\n- The `Gateway` has a dependency without a `go.mod` file, but the plugin needs to use it.\n- Both the `Gateway` and the plugin share a dependency. In this case, the plugin must use the exact same version as the `Gateway`.\n- The plugin requires a different version of a shared dependency.\n\nHere’s how to handle each case:\n\n**Case 1: Gateway dependency lacks `go.mod`**\n\n- The plugin depends on the `Gateway`, which uses dependency *A*.\n- *A* doesn’t have a `go.mod` file, so a pseudo version is generated during the build.\n- Result: The build completes, but the plugin fails to load due to a version mismatch.\n\n**Solution:** Update the code to remove dependency *A*, or use a version of *A* that includes a `go.mod` file.\n\n**Case 2: Shared dependency with version matching**\n\n- The plugin and `Gateway` share a dependency, and this dependency includes a `go.mod` file.\n- The version matches, and the dependency is promoted to *direct* in `go.mod`.\n- Outcome: You’ll need to keep this dependency version in sync with the `Gateway`.\n\n**Case 3: Plugin requires a different version of a shared dependency**\n\n- The plugin and `Gateway` share a dependency, but the plugin needs a different version.\n- If the other version is a major release (e.g., `/v4`), it’s treated as a separate package, allowing both versions to coexist.\n- If it’s just a minor/patch difference, the plugin will likely fail to load due to a version conflict.\n\n**Recommendation:** For best results, use Go package versions that follow the Go module versioning (metaversion). However, keep in mind that many `Gateway` dependencies use basic `v1` semantic versioning, which doesn’t always enforce strict versioned import paths.\n\n### List plugin symbols\n\nSometimes it's useful to list symbols from a plugin. For example, we can list the symbols as they are compiled into our testplugin:\n\n```\n# nm -gD testplugin.so | grep testplugin\n00000000014db4b0 R go:link.pkghashbytes.testplugin\n000000000170f7d0 D go:link.pkghash.testplugin\n000000000130f5e0 T testplugin.AddFooBarHeader\n000000000130f900 T testplugin.AddFooBarHeader.deferwrap1\n000000000130f980 T testplugin.AuthCheck\n0000000001310100 T testplugin.AuthCheck.deferwrap1\n000000000130f540 T testplugin.init\n0000000001310ce0 T testplugin.init.0\n0000000001ce9580 D testplugin..inittask\n0000000001310480 T testplugin.InjectConfigData\n0000000001310180 T testplugin.InjectMetadata\n0000000001d2a3e0 B testplugin.logger\n0000000001310cc0 T testplugin.main\n0000000001310820 T testplugin.MakeOutboundCall\n0000000001310c40 T testplugin.MakeOutboundCall.deferwrap1\n```\n\nThis command prints other symbols that are part of the binary. In the worst case, a build compatibility issue may cause a crash in the Gateway due to an unrecoverable error and this can be used to further debug the binaries produced.\n\nA very basic check to ensure Gateway/plugin compatibility is using the built in `go version -m <file>`:\n\n```\n[output truncated]\n\tbuild\t-buildmode=exe\n\tbuild\t-compiler=gc\n\tbuild\t-race=true\n\tbuild\t-tags=goplugin\n\tbuild\t-trimpath=true\n\tbuild\tCGO_ENABLED=1\n\tbuild\tGOARCH=amd64\n\tbuild\tGOOS=linux\n\tbuild\tGOAMD64=v1\n\tbuild\tvcs=git\n\tbuild\tvcs.revision=1db1935d899296c91a55ba528e7b653aec02883b\n\tbuild\tvcs.time=2024-09-24T12:54:26Z\n\tbuild\tvcs.modified=false\n```\n\nThese options should match between the Gateway binary and the plugin. You can use the command for both binaries and then compare the outputs.\n"},"files":{"ci/tests/python-plugins/extend-python/README.md":"### Tyk Gateway with Python Coprocess\n\nStarting from Tyk Gateway version `v5.3.0`, Python is no longer bundled with the official Docker images. \nHowever, Tyk Gateway continues to support Python plugins functionality. \n\nIf you wish to use Python plugins, you can extend the official Docker image by adding Python to it. \nThis directory contains a sample Dockerfile that demonstrates how to achieve this.","docs/plugins/go-development-flow.md":"---\ntitle: Custom Go plugin development flow\ntags:\n    - custom plugin\n    - golang\n    - go plugin\n    - middleware\n    - debugging go plugins\ndescription: Development flow working with Go Plugins\ndate: \"2024-10-11\"\n---\n\nWe recommend that you familiarize yourself with the following official Go documentation to help you work effectively with Go plugins:\n\n- [The official plugin package documentation - Warnings](https://pkg.go.dev/plugin)\n- [Tutorial: Getting started with multi-module workspaces](https://go.dev/doc/tutorial/workspaces)\n\n{{< note success >}} **Note**\n\nPlugins are currently supported only on Linux, FreeBSD, and macOS, making them unsuitable for applications intended to be portable. {{< /note >}}\n\nPlugins need to be compiled to native shared object code, which can then be loaded by Tyk Gateway. It's important to understand the need for plugins to be compiled using exactly the same environment and [build flags]({{< ref \"product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-development-flow#build-flags\" >}}) as the Gateway. To simplify this and minimise the risk of compatibility problems, we recommend the use of [Go workspaces](https://go.dev/blog/get-familiar-with-workspaces), to provide a consistent environment.\n\n## Setting up your environment\n\nTo develop plugins, you'll need:\n\n- Go (matching the version used in the Gateway, which you can determine using `go.mod`).\n- Git to check out Tyk Gateway source code.\n- A folder with the code that you want to build into plugins.\n\nWe recommend that you set up a *Go workspace*, which, at the end, is going to contain:\n\n- `/tyk-release-x.y.z` - the Tyk Gateway source code\n- `/plugins` - the plugins\n- `/go.work` - the *Go workspace* file\n- `/go.work.sum` - *Go workspace* package checksums\n\nUsing the *Go workspace* ensures build compatibility between the plugins and Gateway.\n\n### 1. Checking out Tyk Gateway source code\n\n```\ngit clone --branch release-5.3.6 https://github.com/TykTechnologies/tyk.git tyk-release-5.3.6 || true\n```\n\nThis example uses a particular `release-5.3.6` branch, to match Tyk Gateway release 5.3.6. With newer `git` versions, you may pass `--branch v5.3.6` and it would use the tag. In case you want to use the tag it's also possible to navigate into the folder and issue `git checkout tags/v5.3.6`.\n\n### 2. Preparing the Go workspace\n\nYour Go workspace can be very simple:\n\n1. Create a `.go` file containing the code for your plugin.\n2. Create a `go.mod` file for the plugin.\n3. Ensure the correct Go version is in use.\n\nAs an example, we can use the [CustomGoPlugin.go](https://github.com/TykTechnologies/custom-go-plugin/blob/master/go/src/CustomGoPlugin.go) sample as the source for our plugin as shown:\n\n```\nmkdir -p plugins\ncd plugins\ngo mod init testplugin\ngo mod edit -go $(go mod edit -json go.mod | jq -r .Go)\nwget -q https://raw.githubusercontent.com/TykTechnologies/custom-go-plugin/refs/heads/master/go/src/CustomGoPlugin.go\ncd -\n```\n\nThe following snippet provides you with a way to get the exact Go version used by Gateway from it's [go.mod](https://github.com/TykTechnologies/tyk/blob/release-5.3.6/go.mod#L3) file:\n\n- `go mod edit -json go.mod | jq -r .Go` (e.g. `1.22.7`)\n\nThis should be used to ensure the version matches between gateway and the plugin.\n\nTo summarize what was done:\n\n1. We created a plugins folder and initialzed a `go` project using `go mod` command.\n2. Set the Go version of `go.mod` to match the one set in the Gateway.\n3. Initialzied the project with sample plugin `go` code.\n\nAt this point, we don't have a *Go workspace* but we will create one next so that we can effectively share the Gateway dependency across Go modules.\n\n### 3. Creating the Go workspace\n\nTo set up the Go workspace, start in the directory that contains the Gateway and the Plugins folder. You'll first, create the `go.work` file to set up your Go workspace, and include the `tyk-release-5.3.6` and `plugins` folders. Then, navigate to the plugins folder to fetch the Gateway dependency at the exact commit hash and run `go mod tidy` to ensure dependencies are up to date.\n\nFollow these commands:\n\n```\ngo work init ./tyk-release-5.3.6\ngo work use ./plugins\ncommit_hash=$(cd tyk-release-5.3.6 && git rev-parse HEAD)\ncd plugins && go get github.com/TykTechnologies/tyk@${commit_hash} && go mod tidy && cd -\n```\n\nThe following snippet provides you to get the commit hash exactly, so it can be used with `go get`.\n\n- `git rev-parse HEAD`\n\nThe Go workspace file (`go.work`) should look like this:\n\n```\ngo 1.22.7\n\nuse (\n\t./plugins\n\t./tyk-release-5.3.6\n)\n```\n\n### 4. Building and validating the plugin\n\nNow that your *Go workspace* is ready, you can build your plugin as follows:\n\n```\ncd tyk-release-5.3.6 && go build -tags=goplugin -trimpath . && cd -\ncd plugins           && go build -trimpath -buildmode=plugin . && cd -\n```\n\nThese steps build both the Gateway and the plugin.\n\nYou can use the Gateway binary that you just built to test that your new plugin loads into the Gateway without having to configure and then make a request to an API using this command:\n\n```\n./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\n```\n\nYou should see an output similar to:\n\n```\ntime=\"Oct 14 13:39:55\" level=info msg=\"--- Go custom plugin init success! ---- \"\n[file=plugins/testplugin.so, symbol=AuthCheck] loaded ok, got 0x76e1aeb52140\n```\n\nThe log shows that the plugin has correctly loaded into the Gateway and that its `init` function has been successfully invoked.\n\n### 5. Summary\n\nIn the preceding steps we have put together an end-to-end build environment for both the Gateway and the plugin. Bear in mind that runtime environments may have additional restrictions beyond Go version and build flags to which the plugin developer must pay attention.\n\nCompatibility in general is a big concern when working with Go plugins: as the plugins are tightly coupled to the Gateway, consideration must always be made for the build restrictions enforced by environment and configuration options.\n\nContinue with [Loading Go Plugins into Tyk](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/loading-go-plugins/).\n\n## Debugging Golang Plugins\n\nPlugins are native Go code compiled to a binary shared object file. The code may depend on `cgo` and require libraries like `libc` provided by the runtime environment. The following are some debugging steps for diagnosing issues arising from using plugins.\n\n### Warnings\n\nThe [Plugin package - Warnings](https://pkg.go.dev/plugin#hdr-Warnings) section in the Go documentation outlines several requirements which can't be ignored when working with plugins. The most important restriction is the following:\n\n> Runtime crashes are likely to occur unless all parts of the program (the application and all its plugins) are compiled using exactly the same version of the toolchain, the same build tags, and the same values of certain flags and environment variables.\n\nWe provide the *Tyk Plugin Compiler* docker image, which we strongly recommend is used to build plugins compatible with the official Gateway releases. This tool provides the cross compilation toolchain, Go version used to build the release, and ensures that compatible flags are used when compiling plugins, like `-trimpath`, `CC`, `CGO_ENABLED`, `GOOS`, `GOARCH`.\n\nThe *Plugin Compiler* also works around known Go issues such as:\n\n- https://github.com/golang/go/issues/19004\n- https://www.reddit.com/r/golang/comments/qxghjv/plugin_already_loaded_when_a_plugin_is_loaded/\n\nSupplying the argument `build_id` to the *Plugin Compiler* ensures the same plugin can be rebuilt. The *Plugin Compiler* does this by replacing the plugin `go.mod` module path.\n\nContinue with [Tyk Plugin Compiler](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-plugin-compiler/).\n\n### Using Incorrect Build Flags\n\nWhen working with Go plugins, it's easy to miss the restriction that the plugin at the very least must be built with the same Go version, and the same flags (notably `-trimpath`) as the Tyk Gateway on which it is to be used.\n\nIf you miss an argument (for example `-trimpath`) when building the plugin, the Gateway will report an error when your API attempts to load the plugin, for example:\n\n```\ntask: [test] cd tyk-release-5.3.6 && go build -tags=goplugin -trimpath .\ntask: [test] cd plugins && go build -buildmode=plugin .\ntask: [test] ./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\ntyk: error: unexpected error: plugin.Open(\"plugins/testplugin\"): plugin was built with a different version of package internal/goarch, try --help\n```\n\nUsually when the error hints at a standard library package, the build flags between the Gateway and plugin binaries don't match.\n\nOther error messages may be reported, depending on what triggered the issue. For example, if you omitted `-race` in the plugin but the gateway was built with `-race`, the following error will be reported:\n\n```\nplugin was built with a different version of package runtime/internal/sys, try --help\n```\n\nStrictly speaking:\n\n- Build flags like `-trimpath`, `-race` need to match.\n- Go toolchain / build env needs to be exactly the same.\n- For cross compilation you must use the same `CC` value for the build (CGO).\n- `CGO_ENABLED=1`, `GOOS`, `GOARCH` must match with runtime.\n\nWhen something is off, you can check what is different by using the `go version -m` command for the Gateway (`go version -m tyk`) and plugin (`go version -m plugin.so`). Inspecting and comparing the output of `build` tokens usually yields the difference that caused the compatibility issue.\n\n### Plugin Compatibility Issues\n\nBelow are some common situations where dependencies might cause issues:\n\n- The `Gateway` has a dependency without a `go.mod` file, but the plugin needs to use it.\n- Both the `Gateway` and the plugin share a dependency. In this case, the plugin must use the exact same version as the `Gateway`.\n- The plugin requires a different version of a shared dependency.\n\nHere’s how to handle each case:\n\n**Case 1: Gateway dependency lacks `go.mod`**\n\n- The plugin depends on the `Gateway`, which uses dependency *A*.\n- *A* doesn’t have a `go.mod` file, so a pseudo version is generated during the build.\n- Result: The build completes, but the plugin fails to load due to a version mismatch.\n\n**Solution:** Update the code to remove dependency *A*, or use a version of *A* that includes a `go.mod` file.\n\n**Case 2: Shared dependency with version matching**\n\n- The plugin and `Gateway` share a dependency, and this dependency includes a `go.mod` file.\n- The version matches, and the dependency is promoted to *direct* in `go.mod`.\n- Outcome: You’ll need to keep this dependency version in sync with the `Gateway`.\n\n**Case 3: Plugin requires a different version of a shared dependency**\n\n- The plugin and `Gateway` share a dependency, but the plugin needs a different version.\n- If the other version is a major release (e.g., `/v4`), it’s treated as a separate package, allowing both versions to coexist.\n- If it’s just a minor/patch difference, the plugin will likely fail to load due to a version conflict.\n\n**Recommendation:** For best results, use Go package versions that follow the Go module versioning (metaversion). However, keep in mind that many `Gateway` dependencies use basic `v1` semantic versioning, which doesn’t always enforce strict versioned import paths.\n\n### List plugin symbols\n\nSometimes it's useful to list symbols from a plugin. For example, we can list the symbols as they are compiled into our testplugin:\n\n```\n# nm -gD testplugin.so | grep testplugin\n00000000014db4b0 R go:link.pkghashbytes.testplugin\n000000000170f7d0 D go:link.pkghash.testplugin\n000000000130f5e0 T testplugin.AddFooBarHeader\n000000000130f900 T testplugin.AddFooBarHeader.deferwrap1\n000000000130f980 T testplugin.AuthCheck\n0000000001310100 T testplugin.AuthCheck.deferwrap1\n000000000130f540 T testplugin.init\n0000000001310ce0 T testplugin.init.0\n0000000001ce9580 D testplugin..inittask\n0000000001310480 T testplugin.InjectConfigData\n0000000001310180 T testplugin.InjectMetadata\n0000000001d2a3e0 B testplugin.logger\n0000000001310cc0 T testplugin.main\n0000000001310820 T testplugin.MakeOutboundCall\n0000000001310c40 T testplugin.MakeOutboundCall.deferwrap1\n```\n\nThis command prints other symbols that are part of the binary. In the worst case, a build compatibility issue may cause a crash in the Gateway due to an unrecoverable error and this can be used to further debug the binaries produced.\n\nA very basic check to ensure Gateway/plugin compatibility is using the built in `go version -m <file>`:\n\n```\n[output truncated]\n\tbuild\t-buildmode=exe\n\tbuild\t-compiler=gc\n\tbuild\t-race=true\n\tbuild\t-tags=goplugin\n\tbuild\t-trimpath=true\n\tbuild\tCGO_ENABLED=1\n\tbuild\tGOARCH=amd64\n\tbuild\tGOOS=linux\n\tbuild\tGOAMD64=v1\n\tbuild\tvcs=git\n\tbuild\tvcs.revision=1db1935d899296c91a55ba528e7b653aec02883b\n\tbuild\tvcs.time=2024-09-24T12:54:26Z\n\tbuild\tvcs.modified=false\n```\n\nThese options should match between the Gateway binary and the plugin. You can use the command for both binaries and then compare the outputs.\n"},"items":[{"name":"go-development-flow.md","path":"docs/plugins/go-development-flow.md","rawUrl":"https://raw.githubusercontent.com/TykTechnologies/tyk/HEAD/docs/plugins/go-development-flow.md","title":"Plugins Skill","category":"anthropic-skill","format":"markdown","content":"---\ntitle: Custom Go plugin development flow\ntags:\n    - custom plugin\n    - golang\n    - go plugin\n    - middleware\n    - debugging go plugins\ndescription: Development flow working with Go Plugins\ndate: \"2024-10-11\"\n---\n\nWe recommend that you familiarize yourself with the following official Go documentation to help you work effectively with Go plugins:\n\n- [The official plugin package documentation - Warnings](https://pkg.go.dev/plugin)\n- [Tutorial: Getting started with multi-module workspaces](https://go.dev/doc/tutorial/workspaces)\n\n{{< note success >}} **Note**\n\nPlugins are currently supported only on Linux, FreeBSD, and macOS, making them unsuitable for applications intended to be portable. {{< /note >}}\n\nPlugins need to be compiled to native shared object code, which can then be loaded by Tyk Gateway. It's important to understand the need for plugins to be compiled using exactly the same environment and [build flags]({{< ref \"product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-development-flow#build-flags\" >}}) as the Gateway. To simplify this and minimise the risk of compatibility problems, we recommend the use of [Go workspaces](https://go.dev/blog/get-familiar-with-workspaces), to provide a consistent environment.\n\n## Setting up your environment\n\nTo develop plugins, you'll need:\n\n- Go (matching the version used in the Gateway, which you can determine using `go.mod`).\n- Git to check out Tyk Gateway source code.\n- A folder with the code that you want to build into plugins.\n\nWe recommend that you set up a *Go workspace*, which, at the end, is going to contain:\n\n- `/tyk-release-x.y.z` - the Tyk Gateway source code\n- `/plugins` - the plugins\n- `/go.work` - the *Go workspace* file\n- `/go.work.sum` - *Go workspace* package checksums\n\nUsing the *Go workspace* ensures build compatibility between the plugins and Gateway.\n\n### 1. Checking out Tyk Gateway source code\n\n```\ngit clone --branch release-5.3.6 https://github.com/TykTechnologies/tyk.git tyk-release-5.3.6 || true\n```\n\nThis example uses a particular `release-5.3.6` branch, to match Tyk Gateway release 5.3.6. With newer `git` versions, you may pass `--branch v5.3.6` and it would use the tag. In case you want to use the tag it's also possible to navigate into the folder and issue `git checkout tags/v5.3.6`.\n\n### 2. Preparing the Go workspace\n\nYour Go workspace can be very simple:\n\n1. Create a `.go` file containing the code for your plugin.\n2. Create a `go.mod` file for the plugin.\n3. Ensure the correct Go version is in use.\n\nAs an example, we can use the [CustomGoPlugin.go](https://github.com/TykTechnologies/custom-go-plugin/blob/master/go/src/CustomGoPlugin.go) sample as the source for our plugin as shown:\n\n```\nmkdir -p plugins\ncd plugins\ngo mod init testplugin\ngo mod edit -go $(go mod edit -json go.mod | jq -r .Go)\nwget -q https://raw.githubusercontent.com/TykTechnologies/custom-go-plugin/refs/heads/master/go/src/CustomGoPlugin.go\ncd -\n```\n\nThe following snippet provides you with a way to get the exact Go version used by Gateway from it's [go.mod](https://github.com/TykTechnologies/tyk/blob/release-5.3.6/go.mod#L3) file:\n\n- `go mod edit -json go.mod | jq -r .Go` (e.g. `1.22.7`)\n\nThis should be used to ensure the version matches between gateway and the plugin.\n\nTo summarize what was done:\n\n1. We created a plugins folder and initialzed a `go` project using `go mod` command.\n2. Set the Go version of `go.mod` to match the one set in the Gateway.\n3. Initialzied the project with sample plugin `go` code.\n\nAt this point, we don't have a *Go workspace* but we will create one next so that we can effectively share the Gateway dependency across Go modules.\n\n### 3. Creating the Go workspace\n\nTo set up the Go workspace, start in the directory that contains the Gateway and the Plugins folder. You'll first, create the `go.work` file to set up your Go workspace, and include the `tyk-release-5.3.6` and `plugins` folders. Then, navigate to the plugins folder to fetch the Gateway dependency at the exact commit hash and run `go mod tidy` to ensure dependencies are up to date.\n\nFollow these commands:\n\n```\ngo work init ./tyk-release-5.3.6\ngo work use ./plugins\ncommit_hash=$(cd tyk-release-5.3.6 && git rev-parse HEAD)\ncd plugins && go get github.com/TykTechnologies/tyk@${commit_hash} && go mod tidy && cd -\n```\n\nThe following snippet provides you to get the commit hash exactly, so it can be used with `go get`.\n\n- `git rev-parse HEAD`\n\nThe Go workspace file (`go.work`) should look like this:\n\n```\ngo 1.22.7\n\nuse (\n\t./plugins\n\t./tyk-release-5.3.6\n)\n```\n\n### 4. Building and validating the plugin\n\nNow that your *Go workspace* is ready, you can build your plugin as follows:\n\n```\ncd tyk-release-5.3.6 && go build -tags=goplugin -trimpath . && cd -\ncd plugins           && go build -trimpath -buildmode=plugin . && cd -\n```\n\nThese steps build both the Gateway and the plugin.\n\nYou can use the Gateway binary that you just built to test that your new plugin loads into the Gateway without having to configure and then make a request to an API using this command:\n\n```\n./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\n```\n\nYou should see an output similar to:\n\n```\ntime=\"Oct 14 13:39:55\" level=info msg=\"--- Go custom plugin init success! ---- \"\n[file=plugins/testplugin.so, symbol=AuthCheck] loaded ok, got 0x76e1aeb52140\n```\n\nThe log shows that the plugin has correctly loaded into the Gateway and that its `init` function has been successfully invoked.\n\n### 5. Summary\n\nIn the preceding steps we have put together an end-to-end build environment for both the Gateway and the plugin. Bear in mind that runtime environments may have additional restrictions beyond Go version and build flags to which the plugin developer must pay attention.\n\nCompatibility in general is a big concern when working with Go plugins: as the plugins are tightly coupled to the Gateway, consideration must always be made for the build restrictions enforced by environment and configuration options.\n\nContinue with [Loading Go Plugins into Tyk](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/loading-go-plugins/).\n\n## Debugging Golang Plugins\n\nPlugins are native Go code compiled to a binary shared object file. The code may depend on `cgo` and require libraries like `libc` provided by the runtime environment. The following are some debugging steps for diagnosing issues arising from using plugins.\n\n### Warnings\n\nThe [Plugin package - Warnings](https://pkg.go.dev/plugin#hdr-Warnings) section in the Go documentation outlines several requirements which can't be ignored when working with plugins. The most important restriction is the following:\n\n> Runtime crashes are likely to occur unless all parts of the program (the application and all its plugins) are compiled using exactly the same version of the toolchain, the same build tags, and the same values of certain flags and environment variables.\n\nWe provide the *Tyk Plugin Compiler* docker image, which we strongly recommend is used to build plugins compatible with the official Gateway releases. This tool provides the cross compilation toolchain, Go version used to build the release, and ensures that compatible flags are used when compiling plugins, like `-trimpath`, `CC`, `CGO_ENABLED`, `GOOS`, `GOARCH`.\n\nThe *Plugin Compiler* also works around known Go issues such as:\n\n- https://github.com/golang/go/issues/19004\n- https://www.reddit.com/r/golang/comments/qxghjv/plugin_already_loaded_when_a_plugin_is_loaded/\n\nSupplying the argument `build_id` to the *Plugin Compiler* ensures the same plugin can be rebuilt. The *Plugin Compiler* does this by replacing the plugin `go.mod` module path.\n\nContinue with [Tyk Plugin Compiler](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-plugin-compiler/).\n\n### Using Incorrect Build Flags\n\nWhen working with Go plugins, it's easy to miss the restriction that the plugin at the very least must be built with the same Go version, and the same flags (notably `-trimpath`) as the Tyk Gateway on which it is to be used.\n\nIf you miss an argument (for example `-trimpath`) when building the plugin, the Gateway will report an error when your API attempts to load the plugin, for example:\n\n```\ntask: [test] cd tyk-release-5.3.6 && go build -tags=goplugin -trimpath .\ntask: [test] cd plugins && go build -buildmode=plugin .\ntask: [test] ./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\ntyk: error: unexpected error: plugin.Open(\"plugins/testplugin\"): plugin was built with a different version of package internal/goarch, try --help\n```\n\nUsually when the error hints at a standard library package, the build flags between the Gateway and plugin binaries don't match.\n\nOther error messages may be reported, depending on what triggered the issue. For example, if you omitted `-race` in the plugin but the gateway was built with `-race`, the following error will be reported:\n\n```\nplugin was built with a different version of package runtime/internal/sys, try --help\n```\n\nStrictly speaking:\n\n- Build flags like `-trimpath`, `-race` need to match.\n- Go toolchain / build env needs to be exactly the same.\n- For cross compilation you must use the same `CC` value for the build (CGO).\n- `CGO_ENABLED=1`, `GOOS`, `GOARCH` must match with runtime.\n\nWhen something is off, you can check what is different by using the `go version -m` command for the Gateway (`go version -m tyk`) and plugin (`go version -m plugin.so`). Inspecting and comparing the output of `build` tokens usually yields the difference that caused the compatibility issue.\n\n### Plugin Compatibility Issues\n\nBelow are some common situations where dependencies might cause issues:\n\n- The `Gateway` has a dependency without a `go.mod` file, but the plugin needs to use it.\n- Both the `Gateway` and the plugin share a dependency. In this case, the plugin must use the exact same version as the `Gateway`.\n- The plugin requires a different version of a shared dependency.\n\nHere’s how to handle each case:\n\n**Case 1: Gateway dependency lacks `go.mod`**\n\n- The plugin depends on the `Gateway`, which uses dependency *A*.\n- *A* doesn’t have a `go.mod` file, so a pseudo version is generated during the build.\n- Result: The build completes, but the plugin fails to load due to a version mismatch.\n\n**Solution:** Update the code to remove dependency *A*, or use a version of *A* that includes a `go.mod` file.\n\n**Case 2: Shared dependency with version matching**\n\n- The plugin and `Gateway` share a dependency, and this dependency includes a `go.mod` file.\n- The version matches, and the dependency is promoted to *direct* in `go.mod`.\n- Outcome: You’ll need to keep this dependency version in sync with the `Gateway`.\n\n**Case 3: Plugin requires a different version of a shared dependency**\n\n- The plugin and `Gateway` share a dependency, but the plugin needs a different version.\n- If the other version is a major release (e.g., `/v4`), it’s treated as a separate package, allowing both versions to coexist.\n- If it’s just a minor/patch difference, the plugin will likely fail to load due to a version conflict.\n\n**Recommendation:** For best results, use Go package versions that follow the Go module versioning (metaversion). However, keep in mind that many `Gateway` dependencies use basic `v1` semantic versioning, which doesn’t always enforce strict versioned import paths.\n\n### List plugin symbols\n\nSometimes it's useful to list symbols from a plugin. For example, we can list the symbols as they are compiled into our testplugin:\n\n```\n# nm -gD testplugin.so | grep testplugin\n00000000014db4b0 R go:link.pkghashbytes.testplugin\n000000000170f7d0 D go:link.pkghash.testplugin\n000000000130f5e0 T testplugin.AddFooBarHeader\n000000000130f900 T testplugin.AddFooBarHeader.deferwrap1\n000000000130f980 T testplugin.AuthCheck\n0000000001310100 T testplugin.AuthCheck.deferwrap1\n000000000130f540 T testplugin.init\n0000000001310ce0 T testplugin.init.0\n0000000001ce9580 D testplugin..inittask\n0000000001310480 T testplugin.InjectConfigData\n0000000001310180 T testplugin.InjectMetadata\n0000000001d2a3e0 B testplugin.logger\n0000000001310cc0 T testplugin.main\n0000000001310820 T testplugin.MakeOutboundCall\n0000000001310c40 T testplugin.MakeOutboundCall.deferwrap1\n```\n\nThis command prints other symbols that are part of the binary. In the worst case, a build compatibility issue may cause a crash in the Gateway due to an unrecoverable error and this can be used to further debug the binaries produced.\n\nA very basic check to ensure Gateway/plugin compatibility is using the built in `go version -m <file>`:\n\n```\n[output truncated]\n\tbuild\t-buildmode=exe\n\tbuild\t-compiler=gc\n\tbuild\t-race=true\n\tbuild\t-tags=goplugin\n\tbuild\t-trimpath=true\n\tbuild\tCGO_ENABLED=1\n\tbuild\tGOARCH=amd64\n\tbuild\tGOOS=linux\n\tbuild\tGOAMD64=v1\n\tbuild\tvcs=git\n\tbuild\tvcs.revision=1db1935d899296c91a55ba528e7b653aec02883b\n\tbuild\tvcs.time=2024-09-24T12:54:26Z\n\tbuild\tvcs.modified=false\n```\n\nThese options should match between the Gateway binary and the plugin. You can use the command for both binaries and then compare the outputs.\n","frontmatter":{"title":"Custom Go plugin development flow","tags":["custom plugin","golang","go plugin","middleware","debugging go plugins"],"description":"Development flow working with Go Plugins","date":"2024-10-11"},"isInternal":false,"tokens":3291,"sizeBytes":13175},{"name":"README.md","path":"ci/tests/python-plugins/extend-python/README.md","rawUrl":"https://raw.githubusercontent.com/TykTechnologies/tyk/HEAD/ci/tests/python-plugins/extend-python/README.md","title":"extend-python Documentation","category":"plugin-manifest","format":"markdown","content":"### Tyk Gateway with Python Coprocess\n\nStarting from Tyk Gateway version `v5.3.0`, Python is no longer bundled with the official Docker images. \nHowever, Tyk Gateway continues to support Python plugins functionality. \n\nIf you wish to use Python plugins, you can extend the official Docker image by adding Python to it. \nThis directory contains a sample Dockerfile that demonstrates how to achieve this.","isInternal":false,"tokens":101,"sizeBytes":402}],"systemPromptSnippet":"<agent_rules repository=\"TykTechnologies/tyk\">\n\n<!-- Skill/Rule: Plugins Skill (docs/plugins/go-development-flow.md) -->\n---\ntitle: Custom Go plugin development flow\ntags:\n    - custom plugin\n    - golang\n    - go plugin\n    - middleware\n    - debugging go plugins\ndescription: Development flow working with Go Plugins\ndate: \"2024-10-11\"\n---\n\nWe recommend that you familiarize yourself with the following official Go documentation to help you work effectively with Go plugins:\n\n- [The official plugin package documentation - Warnings](https://pkg.go.dev/plugin)\n- [Tutorial: Getting started with multi-module workspaces](https://go.dev/doc/tutorial/workspaces)\n\n{{< note success >}} **Note**\n\nPlugins are currently supported only on Linux, FreeBSD, and macOS, making them unsuitable for applications intended to be portable. {{< /note >}}\n\nPlugins need to be compiled to native shared object code, which can then be loaded by Tyk Gateway. It's important to understand the need for plugins to be compiled using exactly the same environment and [build flags]({{< ref \"product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-development-flow#build-flags\" >}}) as the Gateway. To simplify this and minimise the risk of compatibility problems, we recommend the use of [Go workspaces](https://go.dev/blog/get-familiar-with-workspaces), to provide a consistent environment.\n\n## Setting up your environment\n\nTo develop plugins, you'll need:\n\n- Go (matching the version used in the Gateway, which you can determine using `go.mod`).\n- Git to check out Tyk Gateway source code.\n- A folder with the code that you want to build into plugins.\n\nWe recommend that you set up a *Go workspace*, which, at the end, is going to contain:\n\n- `/tyk-release-x.y.z` - the Tyk Gateway source code\n- `/plugins` - the plugins\n- `/go.work` - the *Go workspace* file\n- `/go.work.sum` - *Go workspace* package checksums\n\nUsing the *Go workspace* ensures build compatibility between the plugins and Gateway.\n\n### 1. Checking out Tyk Gateway source code\n\n```\ngit clone --branch release-5.3.6 https://github.com/TykTechnologies/tyk.git tyk-release-5.3.6 || true\n```\n\nThis example uses a particular `release-5.3.6` branch, to match Tyk Gateway release 5.3.6. With newer `git` versions, you may pass `--branch v5.3.6` and it would use the tag. In case you want to use the tag it's also possible to navigate into the folder and issue `git checkout tags/v5.3.6`.\n\n### 2. Preparing the Go workspace\n\nYour Go workspace can be very simple:\n\n1. Create a `.go` file containing the code for your plugin.\n2. Create a `go.mod` file for the plugin.\n3. Ensure the correct Go version is in use.\n\nAs an example, we can use the [CustomGoPlugin.go](https://github.com/TykTechnologies/custom-go-plugin/blob/master/go/src/CustomGoPlugin.go) sample as the source for our plugin as shown:\n\n```\nmkdir -p plugins\ncd plugins\ngo mod init testplugin\ngo mod edit -go $(go mod edit -json go.mod | jq -r .Go)\nwget -q https://raw.githubusercontent.com/TykTechnologies/custom-go-plugin/refs/heads/master/go/src/CustomGoPlugin.go\ncd -\n```\n\nThe following snippet provides you with a way to get the exact Go version used by Gateway from it's [go.mod](https://github.com/TykTechnologies/tyk/blob/release-5.3.6/go.mod#L3) file:\n\n- `go mod edit -json go.mod | jq -r .Go` (e.g. `1.22.7`)\n\nThis should be used to ensure the version matches between gateway and the plugin.\n\nTo summarize what was done:\n\n1. We created a plugins folder and initialzed a `go` project using `go mod` command.\n2. Set the Go version of `go.mod` to match the one set in the Gateway.\n3. Initialzied the project with sample plugin `go` code.\n\nAt this point, we don't have a *Go workspace* but we will create one next so that we can effectively share the Gateway dependency across Go modules.\n\n### 3. Creating the Go workspace\n\nTo set up the Go workspace, start in the directory that contains the Gateway and the Plugins folder. You'll first, create the `go.work` file to set up your Go workspace, and include the `tyk-release-5.3.6` and `plugins` folders. Then, navigate to the plugins folder to fetch the Gateway dependency at the exact commit hash and run `go mod tidy` to ensure dependencies are up to date.\n\nFollow these commands:\n\n```\ngo work init ./tyk-release-5.3.6\ngo work use ./plugins\ncommit_hash=$(cd tyk-release-5.3.6 && git rev-parse HEAD)\ncd plugins && go get github.com/TykTechnologies/tyk@${commit_hash} && go mod tidy && cd -\n```\n\nThe following snippet provides you to get the commit hash exactly, so it can be used with `go get`.\n\n- `git rev-parse HEAD`\n\nThe Go workspace file (`go.work`) should look like this:\n\n```\ngo 1.22.7\n\nuse (\n\t./plugins\n\t./tyk-release-5.3.6\n)\n```\n\n### 4. Building and validating the plugin\n\nNow that your *Go workspace* is ready, you can build your plugin as follows:\n\n```\ncd tyk-release-5.3.6 && go build -tags=goplugin -trimpath . && cd -\ncd plugins           && go build -trimpath -buildmode=plugin . && cd -\n```\n\nThese steps build both the Gateway and the plugin.\n\nYou can use the Gateway binary that you just built to test that your new plugin loads into the Gateway without having to configure and then make a request to an API using this command:\n\n```\n./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\n```\n\nYou should see an output similar to:\n\n```\ntime=\"Oct 14 13:39:55\" level=info msg=\"--- Go custom plugin init success! ---- \"\n[file=plugins/testplugin.so, symbol=AuthCheck] loaded ok, got 0x76e1aeb52140\n```\n\nThe log shows that the plugin has correctly loaded into the Gateway and that its `init` function has been successfully invoked.\n\n### 5. Summary\n\nIn the preceding steps we have put together an end-to-end build environment for both the Gateway and the plugin. Bear in mind that runtime environments may have additional restrictions beyond Go version and build flags to which the plugin developer must pay attention.\n\nCompatibility in general is a big concern when working with Go plugins: as the plugins are tightly coupled to the Gateway, consideration must always be made for the build restrictions enforced by environment and configuration options.\n\nContinue with [Loading Go Plugins into Tyk](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/loading-go-plugins/).\n\n## Debugging Golang Plugins\n\nPlugins are native Go code compiled to a binary shared object file. The code may depend on `cgo` and require libraries like `libc` provided by the runtime environment. The following are some debugging steps for diagnosing issues arising from using plugins.\n\n### Warnings\n\nThe [Plugin package - Warnings](https://pkg.go.dev/plugin#hdr-Warnings) section in the Go documentation outlines several requirements which can't be ignored when working with plugins. The most important restriction is the following:\n\n> Runtime crashes are likely to occur unless all parts of the program (the application and all its plugins) are compiled using exactly the same version of the toolchain, the same build tags, and the same values of certain flags and environment variables.\n\nWe provide the *Tyk Plugin Compiler* docker image, which we strongly recommend is used to build plugins compatible with the official Gateway releases. This tool provides the cross compilation toolchain, Go version used to build the release, and ensures that compatible flags are used when compiling plugins, like `-trimpath`, `CC`, `CGO_ENABLED`, `GOOS`, `GOARCH`.\n\nThe *Plugin Compiler* also works around known Go issues such as:\n\n- https://github.com/golang/go/issues/19004\n- https://www.reddit.com/r/golang/comments/qxghjv/plugin_already_loaded_when_a_plugin_is_loaded/\n\nSupplying the argument `build_id` to the *Plugin Compiler* ensures the same plugin can be rebuilt. The *Plugin Compiler* does this by replacing the plugin `go.mod` module path.\n\nContinue with [Tyk Plugin Compiler](https://tyk.io/docs/product-stack/tyk-gateway/advanced-configurations/plugins/golang/go-plugin-compiler/).\n\n### Using Incorrect Build Flags\n\nWhen working with Go plugins, it's easy to miss the restriction that the plugin at the very least must be built with the same Go version, and the same flags (notably `-trimpath`) as the Tyk Gateway on which it is to be used.\n\nIf you miss an argument (for example `-trimpath`) when building the plugin, the Gateway will report an error when your API attempts to load the plugin, for example:\n\n```\ntask: [test] cd tyk-release-5.3.6 && go build -tags=goplugin -trimpath .\ntask: [test] cd plugins && go build -buildmode=plugin .\ntask: [test] ./tyk-release-5.3.6/tyk plugin load -f plugins/testplugin.so -s AuthCheck\ntyk: error: unexpected error: plugin.Open(\"plugins/testplugin\"): plugin was built with a different version of package internal/goarch, try --help\n```\n\nUsually when the error hints at a standard library package, the build flags between the Gateway and plugin binaries don't match.\n\nOther error messages may be reported, depending on what triggered the issue. For example, if you omitted `-race` in the plugin but the gateway was built with `-race`, the following error will be reported:\n\n```\nplugin was built with a different version of package runtime/internal/sys, try --help\n```\n\nStrictly speaking:\n\n- Build flags like `-trimpath`, `-race` need to match.\n- Go toolchain / build env needs to be exactly the same.\n- For cross compilation you must use the same `CC` value for the build (CGO).\n- `CGO_ENABLED=1`, `GOOS`, `GOARCH` must match with runtime.\n\nWhen something is off, you can check what is different by using the `go version -m` command for the Gateway (`go version -m tyk`) and plugin (`go version -m plugin.so`). Inspecting and comparing the output of `build` tokens usually yields the difference that caused the compatibility issue.\n\n### Plugin Compatibility Issues\n\nBelow are some common situations where dependencies might cause issues:\n\n- The `Gateway` has a dependency without a `go.mod` file, but the plugin needs to use it.\n- Both the `Gateway` and the plugin share a dependency. In this case, the plugin must use the exact same version as the `Gateway`.\n- The plugin requires a different version of a shared dependency.\n\nHere’s how to handle each case:\n\n**Case 1: Gateway dependency lacks `go.mod`**\n\n- The plugin depends on the `Gateway`, which uses dependency *A*.\n- *A* doesn’t have a `go.mod` file, so a pseudo version is generated during the build.\n- Result: The build completes, but the plugin fails to load due to a version mismatch.\n\n**Solution:** Update the code to remove dependency *A*, or use a version of *A* that includes a `go.mod` file.\n\n**Case 2: Shared dependency with version matching**\n\n- The plugin and `Gateway` share a dependency, and this dependency includes a `go.mod` file.\n- The version matches, and the dependency is promoted to *direct* in `go.mod`.\n- Outcome: You’ll need to keep this dependency version in sync with the `Gateway`.\n\n**Case 3: Plugin requires a different version of a shared dependency**\n\n- The plugin and `Gateway` share a dependency, but the plugin needs a different version.\n- If the other version is a major release (e.g., `/v4`), it’s treated as a separate package, allowing both versions to coexist.\n- If it’s just a minor/patch difference, the plugin will likely fail to load due to a version conflict.\n\n**Recommendation:** For best results, use Go package versions that follow the Go module versioning (metaversion). However, keep in mind that many `Gateway` dependencies use basic `v1` semantic versioning, which doesn’t always enforce strict versioned import paths.\n\n### List plugin symbols\n\nSometimes it's useful to list symbols from a plugin. For example, we can list the symbols as they are compiled into our testplugin:\n\n```\n# nm -gD testplugin.so | grep testplugin\n00000000014db4b0 R go:link.pkghashbytes.testplugin\n000000000170f7d0 D go:link.pkghash.testplugin\n000000000130f5e0 T testplugin.AddFooBarHeader\n000000000130f900 T testplugin.AddFooBarHeader.deferwrap1\n000000000130f980 T testplugin.AuthCheck\n0000000001310100 T testplugin.AuthCheck.deferwrap1\n000000000130f540 T testplugin.init\n0000000001310ce0 T testplugin.init.0\n0000000001ce9580 D testplugin..inittask\n0000000001310480 T testplugin.InjectConfigData\n0000000001310180 T testplugin.InjectMetadata\n0000000001d2a3e0 B testplugin.logger\n0000000001310cc0 T testplugin.main\n0000000001310820 T testplugin.MakeOutboundCall\n0000000001310c40 T testplugin.MakeOutboundCall.deferwrap1\n```\n\nThis command prints other symbols that are part of the binary. In the worst case, a build compatibility issue may cause a crash in the Gateway due to an unrecoverable error and this can be used to further debug the binaries produced.\n\nA very basic check to ensure Gateway/plugin compatibility is using the built in `go version -m <file>`:\n\n```\n[output truncated]\n\tbuild\t-buildmode=exe\n\tbuild\t-compiler=gc\n\tbuild\t-race=true\n\tbuild\t-tags=goplugin\n\tbuild\t-trimpath=true\n\tbuild\tCGO_ENABLED=1\n\tbuild\tGOARCH=amd64\n\tbuild\tGOOS=linux\n\tbuild\tGOAMD64=v1\n\tbuild\tvcs=git\n\tbuild\tvcs.revision=1db1935d899296c91a55ba528e7b653aec02883b\n\tbuild\tvcs.time=2024-09-24T12:54:26Z\n\tbuild\tvcs.modified=false\n```\n\nThese options should match between the Gateway binary and the plugin. You can use the command for both binaries and then compare the outputs.\n\n\n<!-- Skill/Rule: extend-python Documentation (ci/tests/python-plugins/extend-python/README.md) -->\n### Tyk Gateway with Python Coprocess\n\nStarting from Tyk Gateway version `v5.3.0`, Python is no longer bundled with the official Docker images. \nHowever, Tyk Gateway continues to support Python plugins functionality. \n\nIf you wish to use Python plugins, you can extend the official Docker image by adding Python to it. \nThis directory contains a sample Dockerfile that demonstrates how to achieve this.\n\n</agent_rules>"}