From 97d2be4f2ff9bf5522db5aeebe9b309bee21def2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:29:47 +0000 Subject: [PATCH 01/34] build(deps): bump go.opentelemetry.io/otel from 1.37.0 to 1.39.0 Bumps [go.opentelemetry.io/otel](https://github.com/open-telemetry/opentelemetry-go) from 1.37.0 to 1.39.0. - [Release notes](https://github.com/open-telemetry/opentelemetry-go/releases) - [Changelog](https://github.com/open-telemetry/opentelemetry-go/blob/main/CHANGELOG.md) - [Commits](https://github.com/open-telemetry/opentelemetry-go/compare/v1.37.0...v1.39.0) --- updated-dependencies: - dependency-name: go.opentelemetry.io/otel dependency-version: 1.39.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- go.mod | 15 +++++++-------- go.sum | 22 ++++++++++++---------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 971e8c6..c5253b1 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,13 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.23.2 - -toolchain go1.23.3 +go 1.24.0 require ( github.com/LerianStudio/lib-commons/v2 v2.2.0 github.com/gofiber/fiber/v2 v2.52.9 github.com/golang-jwt/jwt/v5 v5.3.0 - go.opentelemetry.io/otel v1.37.0 + go.opentelemetry.io/otel v1.39.0 + google.golang.org/grpc v1.74.2 ) require github.com/google/uuid v1.6.0 // indirect @@ -17,6 +16,7 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect @@ -36,18 +36,18 @@ require ( github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasthttp v1.64.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect go.opentelemetry.io/otel/sdk v1.37.0 // indirect go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect go.uber.org/mock v0.5.2 // indirect go.uber.org/multierr v1.11.0 // indirect @@ -57,6 +57,5 @@ require ( golang.org/x/text v0.27.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/grpc v1.74.2 // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/go.sum b/go.sum index d71cef3..1a4f3d2 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwTo github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -54,8 +56,8 @@ github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUc github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= @@ -68,12 +70,12 @@ github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZ github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 h1:FGre0nZh5BSw7G73VpT3xs38HchsfPsa2aZtMp0NPOs= go.opentelemetry.io/contrib/bridges/otelzap v0.12.0/go.mod h1:X2PYPViI2wTPIMIOBjG17KNybTzsrATnvPJ02kkz7LM= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 h1:z6lNIajgEBVtQZHjfw2hAccPEBDs+nx58VemmXWa2ec= go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0/go.mod h1:+kyc3bRx/Qkq05P6OCu3mTEIOxYRYzoIg+JsUp5X+PM= go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= @@ -86,8 +88,8 @@ go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7 go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= go.opentelemetry.io/otel/log/logtest v0.13.0 h1:xxaIcgoEEtnwdgj6D6Uo9K/Dynz9jqIxSDu2YObJ69Q= go.opentelemetry.io/otel/log/logtest v0.13.0/go.mod h1:+OrkmsAH38b+ygyag1tLjSFMYiES5UHggzrtY1IIEA8= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= @@ -96,8 +98,8 @@ go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLl go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= From 56d18351d84865e495feb651aeba860fd4de8a28 Mon Sep 17 00:00:00 2001 From: Jefferson Rodrigues Date: Tue, 6 Jan 2026 14:45:47 -0300 Subject: [PATCH 02/34] chore: update lib-commons to v2.7.0-beta.3 for multi-tenant support Generated-by: Claude AI-Model: claude-opus-4-5-20251101 --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 971e8c6..069e9c0 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23.2 toolchain go1.23.3 require ( - github.com/LerianStudio/lib-commons/v2 v2.2.0 + github.com/LerianStudio/lib-commons/v2 v2.7.0-beta.3 github.com/gofiber/fiber/v2 v2.52.9 github.com/golang-jwt/jwt/v5 v5.3.0 go.opentelemetry.io/otel v1.37.0 From d62405753b6273c33b69f195d17b19bbf55b0e9a Mon Sep 17 00:00:00 2001 From: Brecci Date: Fri, 30 Jan 2026 17:42:44 -0300 Subject: [PATCH 03/34] docs: update license to Elastic License 2.0 (ELv2) X-Lerian-Ref: 0x1 --- LICENSE | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d317b57 --- /dev/null +++ b/LICENSE @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor's trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. From d5ce9b98f5a6a86d598df79d7b1022f9c262c097 Mon Sep 17 00:00:00 2001 From: Brecci Date: Fri, 30 Jan 2026 17:42:44 -0300 Subject: [PATCH 04/34] chore: update Go version to fix vulnerabilities X-Lerian-Ref: 0x1 --- go.mod | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index 971e8c6..5ba4aae 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.23.2 +go 1.24.2 -toolchain go1.23.3 +toolchain go1.25.6 require ( github.com/LerianStudio/lib-commons/v2 v2.2.0 From 2607a543790a5aa93fc7d4e566d25e4bce0cc703 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Feb 2026 17:44:16 +0000 Subject: [PATCH 05/34] build(deps): bump github.com/golang-jwt/jwt/v5 from 5.3.0 to 5.3.1 Bumps [github.com/golang-jwt/jwt/v5](https://github.com/golang-jwt/jwt) from 5.3.0 to 5.3.1. - [Release notes](https://github.com/golang-jwt/jwt/releases) - [Commits](https://github.com/golang-jwt/jwt/compare/v5.3.0...v5.3.1) --- updated-dependencies: - dependency-name: github.com/golang-jwt/jwt/v5 dependency-version: 5.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 971e8c6..478e45f 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,9 @@ toolchain go1.23.3 require ( github.com/LerianStudio/lib-commons/v2 v2.2.0 github.com/gofiber/fiber/v2 v2.52.9 - github.com/golang-jwt/jwt/v5 v5.3.0 + github.com/golang-jwt/jwt/v5 v5.3.1 go.opentelemetry.io/otel v1.37.0 + google.golang.org/grpc v1.74.2 ) require github.com/google/uuid v1.6.0 // indirect @@ -57,6 +58,5 @@ require ( golang.org/x/text v0.27.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/grpc v1.74.2 // indirect google.golang.org/protobuf v1.36.6 // indirect ) diff --git a/go.sum b/go.sum index d71cef3..af6db3d 100644 --- a/go.sum +++ b/go.sum @@ -19,8 +19,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= +github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= +github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= From ad1270809fb52227ceaae5c348eb027f918f8387 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Tue, 3 Feb 2026 17:14:22 +0000 Subject: [PATCH 06/34] chore(release): 2.4.1-beta.1 ## [2.4.1-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.0...v2.4.1-beta.1) (2026-02-03) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c6f018..c0a37da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.4.1-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.0...v2.4.1-beta.1) (2026-02-03) + ## [2.4.0](https://github.com/LerianStudio/lib-auth/compare/v2.3.0...v2.4.0) (2026-01-27) From 64c87ff8a15c1018c1a24f321a05c60481d08d57 Mon Sep 17 00:00:00 2001 From: Marcelo Rangel Date: Thu, 5 Feb 2026 12:54:17 -0300 Subject: [PATCH 07/34] chore(makefile): add build, test, coverage and git hooks commands X-Lerian-Ref: 0x1 --- Makefile | 125 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 119 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index c57bb77..cdb995e 100644 --- a/Makefile +++ b/Makefile @@ -1,24 +1,137 @@ -.PHONY: help lint sec +.PHONY: help build test cover coverage coverage-unit lint format tidy sec setup-git-hooks check-hooks + +# Define common utility functions +define print_title + @echo "" + @echo "------------------------------------------" + @echo " $(1) " + @echo "------------------------------------------" +endef + +#------------------------------------------------------- +# Help Command +#------------------------------------------------------- help: @echo "" @echo "lib-auth Commands" - @echo " make help - Display this help message" - @echo " make lint - Run golangci-lint over ./... (auto-installs if missing)" - @echo " make sec - Run gosec over ./... (auto-installs if missing)" + @echo "" + @echo "Core Commands:" + @echo " make help - Display this help message" + @echo " make build - Build and verify compilation" + @echo " make test - Run tests" + @echo " make cover - Run tests with coverage report" + @echo " make coverage - Alias for cover" + @echo " make coverage-unit - Alias for cover" + @echo "" + @echo "Code Quality Commands:" + @echo " make lint - Run golangci-lint (auto-installs if missing)" + @echo " make format - Format code with gofmt and goimports" + @echo " make tidy - Clean dependencies (go mod tidy)" + @echo " make sec - Run security checks with gosec" + @echo "" + @echo "Git Hook Commands:" + @echo " make setup-git-hooks - Install and configure git hooks" + @echo " make check-hooks - Verify git hooks installation status" + @echo "" + +#------------------------------------------------------- +# Core Commands +#------------------------------------------------------- + +build: + $(call print_title,Building all components) + @go build ./... + @echo "[ok] Build completed successfully" + +test: + $(call print_title,Running tests) + @go test -v ./... + @echo "[ok] Tests completed successfully" + +cover: + $(call print_title,Generating test coverage report) + @go test -coverprofile=coverage.out ./... + @go tool cover -html=coverage.out -o coverage.html + @echo "" + @echo "Coverage Summary:" + @echo "----------------------------------------" + @go tool cover -func=coverage.out | grep total | awk '{print "Total coverage: " $$3}' + @echo "----------------------------------------" + @echo "Open coverage.html in your browser to view detailed coverage report" + @echo "[ok] Coverage report generated successfully" + +coverage: cover + +coverage-unit: cover + +#------------------------------------------------------- +# Code Quality Commands +#------------------------------------------------------- lint: + $(call print_title,Running linter) @if ! command -v golangci-lint >/dev/null 2>&1; then \ echo "Installing golangci-lint..."; \ go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \ fi - golangci-lint run ./... + @golangci-lint run ./... + @echo "[ok] Linting completed successfully" + +format: + $(call print_title,Formatting code) + @gofmt -s -w . + @if command -v goimports >/dev/null 2>&1; then \ + goimports -w .; \ + else \ + echo "goimports not found, skipping import organization"; \ + echo "Install with: go install golang.org/x/tools/cmd/goimports@latest"; \ + fi + @echo "[ok] Formatting completed successfully" + +tidy: + $(call print_title,Cleaning dependencies) + @go mod tidy + @echo "[ok] Dependencies cleaned successfully" sec: + $(call print_title,Running security checks) @if ! command -v gosec >/dev/null 2>&1; then \ echo "Installing gosec..."; \ go install github.com/securego/gosec/v2/cmd/gosec@latest; \ fi - gosec ./... + @gosec ./... + @echo "[ok] Security checks completed successfully" +#------------------------------------------------------- +# Git Hook Commands +#------------------------------------------------------- +setup-git-hooks: + $(call print_title,Installing git hooks) + @for hook in .githooks/*; do \ + hook_name=$$(basename $$hook); \ + cp "$$hook" ".git/hooks/$$hook_name"; \ + chmod +x ".git/hooks/$$hook_name"; \ + echo "Installed $$hook_name"; \ + done + @echo "[ok] Git hooks installed successfully" + +check-hooks: + $(call print_title,Verifying git hooks installation) + @err=0; \ + for hook in .githooks/*; do \ + hook_name=$$(basename $$hook); \ + if [ ! -f ".git/hooks/$$hook_name" ]; then \ + echo "Git hook $$hook_name is NOT installed"; \ + err=1; \ + else \ + echo "Git hook $$hook_name is installed"; \ + fi; \ + done; \ + if [ $$err -eq 0 ]; then \ + echo "[ok] All git hooks are properly installed"; \ + else \ + echo "[error] Some git hooks are missing. Run 'make setup-git-hooks' to fix."; \ + exit 1; \ + fi From 8b166d71c3ad962dc09ed1335c60307a484e4f0e Mon Sep 17 00:00:00 2001 From: Marcelo Rangel Date: Fri, 6 Feb 2026 17:08:03 -0300 Subject: [PATCH 08/34] chore(makefile): standardize build system following lib-commons pattern :wrench: Implements comprehensive Makefile infrastructure aligned with Midaz lib-commons standards: Core improvements: - Modular test framework (mk/tests.mk) with unit, integration and coverage targets - Colored console output with ANSI codes for better readability - Smart coverage reporting via scripts/coverage.sh with exclusion support - Enhanced security scanning with SARIF output support (make sec SARIF=1) - Git hooks verification and installation commands - Support for low-resource environments (LOW_RESOURCE=1) - Test filtering by pattern (RUN=) and package (PKG=) New commands: - make test-unit / test-integration / test-all - make coverage-unit / coverage-integration / coverage - make cover-html (generates HTML reports) - make tools (installs gotestsum) - make check-tests / check-hooks / check-envs - make clean (removes build artifacts and reports) Infrastructure files: - mk/tests.mk: Test targets with gotestsum integration and testcontainers support - scripts/coverage.sh: Intelligent coverage script with package filtering - scripts/coverage_ignore.txt: Coverage exclusion patterns - .ignorecoverunit: Unit test coverage exclusions (filters *_mock.go) Updated .gitignore: - Added /dist/, /reports/, coverage files, and gosec-report.sarif All 22 commands tested and validated successfully. X-Lerian-Ref: 0x1 --- .gitignore | 13 +- .ignorecoverunit | 6 + Makefile | 299 +++++++++++++++++++++++--------- mk/tests.mk | 333 ++++++++++++++++++++++++++++++++++++ scripts/coverage.sh | 58 +++++++ scripts/coverage_ignore.txt | 0 6 files changed, 628 insertions(+), 81 deletions(-) create mode 100644 .ignorecoverunit create mode 100644 mk/tests.mk create mode 100755 scripts/coverage.sh create mode 100644 scripts/coverage_ignore.txt diff --git a/.gitignore b/.gitignore index daaa36c..087f175 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ # Go build artifacts /bin/ /out/ +/dist/ # Dependency directories (vendor/) vendor/ @@ -17,7 +18,17 @@ vendor/ # Logs and temporary files *.log *.tmp -*.out + +# Test coverage files +coverage.out +coverage.html +*.coverprofile + +# Test reports directory +/reports/ + +# Security scan reports +gosec-report.sarif # OS-specific files .DS_Store diff --git a/.ignorecoverunit b/.ignorecoverunit new file mode 100644 index 0000000..36f7409 --- /dev/null +++ b/.ignorecoverunit @@ -0,0 +1,6 @@ +# Coverage exclusion patterns for unit tests +# Lines starting with # are comments +# Use * as wildcard for path matching + +# Auto-generated mocks +*_mock.go diff --git a/Makefile b/Makefile index cdb995e..599eaad 100644 --- a/Makefile +++ b/Makefile @@ -1,137 +1,276 @@ -.PHONY: help build test cover coverage coverage-unit lint format tidy sec setup-git-hooks check-hooks +# Define the root directory of the project +LIB_AUTH := $(shell pwd) -# Define common utility functions +#------------------------------------------------------- +# Color definitions (ANSI codes) +#------------------------------------------------------- +GREEN := \033[32m +RED := \033[31m +BOLD := \033[1m +NC := \033[0m + +#------------------------------------------------------- +# Utility functions +#------------------------------------------------------- + +# Check if a command exists +define check_command + @if ! command -v $(1) >/dev/null 2>&1; then \ + echo "$(RED)$(BOLD)[error]$(NC) $(1) is not installed."; \ + echo "Install it with: $(2)"; \ + exit 1; \ + fi +endef + +# Print section title define print_title @echo "" @echo "------------------------------------------" - @echo " $(1) " + @echo " 📝 $(1) " @echo "------------------------------------------" endef +# Include test targets +MK_DIR := $(abspath mk) +include $(MK_DIR)/tests.mk + #------------------------------------------------------- # Help Command #------------------------------------------------------- +.PHONY: help help: @echo "" - @echo "lib-auth Commands" + @echo "" + @echo "Lib-Auth Project Management Commands" + @echo "" @echo "" @echo "Core Commands:" - @echo " make help - Display this help message" - @echo " make build - Build and verify compilation" - @echo " make test - Run tests" - @echo " make cover - Run tests with coverage report" - @echo " make coverage - Alias for cover" - @echo " make coverage-unit - Alias for cover" + @echo " make help - Display this help message" + @echo " make test - Run all tests" + @echo " make build - Build all packages" + @echo " make clean - Clean all build artifacts" + @echo " make cover - Run test coverage" + @echo "" + @echo "" + @echo "Test Suite Commands:" + @echo " make test-unit - Run unit tests" + @echo " make test-integration - Run integration tests with testcontainers (RUN=, LOW_RESOURCE=1)" + @echo " make test-all - Run all tests (unit + integration)" + @echo "" + @echo "" + @echo "Coverage Commands:" + @echo " make coverage-unit - Run unit tests with coverage report (PKG=./path, uses .ignorecoverunit)" + @echo " make coverage-integration - Run integration tests with coverage report (PKG=./path)" + @echo " make coverage - Run all coverage targets (unit + integration)" + @echo " make cover-html - Generate HTML coverage reports" + @echo "" + @echo "" + @echo "Test Tooling:" + @echo " make tools - Install test tools (gotestsum)" + @echo "" @echo "" @echo "Code Quality Commands:" - @echo " make lint - Run golangci-lint (auto-installs if missing)" - @echo " make format - Format code with gofmt and goimports" - @echo " make tidy - Clean dependencies (go mod tidy)" - @echo " make sec - Run security checks with gosec" + @echo " make lint - Run linting on all packages" + @echo " make format - Format code in all packages" + @echo " make tidy - Clean dependencies" + @echo " make check-tests - Verify test coverage for packages" + @echo " make sec - Run security checks using gosec" + @echo " make sec SARIF=1 - Run security checks with SARIF output" + @echo "" @echo "" @echo "Git Hook Commands:" - @echo " make setup-git-hooks - Install and configure git hooks" - @echo " make check-hooks - Verify git hooks installation status" + @echo " make setup-git-hooks - Install and configure git hooks" + @echo " make check-hooks - Verify git hooks installation status" + @echo " make check-envs - Check if github hooks are installed and secret env files are not exposed" + @echo "" + @echo "" + @echo "Release Commands:" + @echo " make goreleaser - Create release snapshot with goreleaser" + @echo "" @echo "" #------------------------------------------------------- # Core Commands #------------------------------------------------------- -build: - $(call print_title,Building all components) - @go build ./... - @echo "[ok] Build completed successfully" - -test: - $(call print_title,Running tests) - @go test -v ./... - @echo "[ok] Tests completed successfully" - -cover: - $(call print_title,Generating test coverage report) - @go test -coverprofile=coverage.out ./... - @go tool cover -html=coverage.out -o coverage.html - @echo "" - @echo "Coverage Summary:" - @echo "----------------------------------------" - @go tool cover -func=coverage.out | grep total | awk '{print "Total coverage: " $$3}' - @echo "----------------------------------------" - @echo "Open coverage.html in your browser to view detailed coverage report" - @echo "[ok] Coverage report generated successfully" -coverage: cover +.PHONY: build +build: + $(call print_title,Building all packages) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + go build ./... + @echo "$(GREEN)$(BOLD)[ok]$(NC) All packages built successfully$(GREEN) ✔️$(NC)" -coverage-unit: cover +.PHONY: clean +clean: + $(call print_title,Cleaning build artifacts) + @rm -rf ./bin ./dist ./reports coverage.out coverage.html + @go clean -cache -testcache + @echo "$(GREEN)$(BOLD)[ok]$(NC) All build artifacts cleaned$(GREEN) ✔️$(NC)" #------------------------------------------------------- # Code Quality Commands #------------------------------------------------------- +.PHONY: lint lint: - $(call print_title,Running linter) - @if ! command -v golangci-lint >/dev/null 2>&1; then \ - echo "Installing golangci-lint..."; \ - go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \ + $(call print_title,Running linters on all packages) + $(call check_command,golangci-lint,"go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest") + @out=$$(golangci-lint run --fix ./... 2>&1); \ + out_err=$$?; \ + echo "$$out"; \ + if [ $$out_err -ne 0 ]; then \ + echo -e "\n$(BOLD)$(RED)An error has occurred during the lint process: \n $$out\n"; \ + exit 1; \ fi - @golangci-lint run ./... - @echo "[ok] Linting completed successfully" + @echo "$(GREEN)$(BOLD)[ok]$(NC) Lint checks passed successfully$(GREEN) ✔️$(NC)" +.PHONY: format format: - $(call print_title,Formatting code) - @gofmt -s -w . + $(call print_title,Formatting code in all packages) + $(call check_command,gofmt,"Install Go from https://golang.org/doc/install") + @gofmt -w ./ @if command -v goimports >/dev/null 2>&1; then \ goimports -w .; \ else \ echo "goimports not found, skipping import organization"; \ echo "Install with: go install golang.org/x/tools/cmd/goimports@latest"; \ fi - @echo "[ok] Formatting completed successfully" - -tidy: - $(call print_title,Cleaning dependencies) - @go mod tidy - @echo "[ok] Dependencies cleaned successfully" + @echo "$(GREEN)$(BOLD)[ok]$(NC) All go files formatted$(GREEN) ✔️$(NC)" -sec: - $(call print_title,Running security checks) - @if ! command -v gosec >/dev/null 2>&1; then \ - echo "Installing gosec..."; \ - go install github.com/securego/gosec/v2/cmd/gosec@latest; \ +.PHONY: check-tests +check-tests: + $(call print_title,Verifying test coverage for packages) + @if [ -f "./scripts/check-tests.sh" ]; then \ + sh ./scripts/check-tests.sh; \ + else \ + echo "Running basic test coverage check..."; \ + go test -cover ./...; \ fi - @gosec ./... - @echo "[ok] Security checks completed successfully" + @echo "$(GREEN)$(BOLD)[ok]$(NC) Test coverage verification completed$(GREEN) ✔️$(NC)" #------------------------------------------------------- # Git Hook Commands #------------------------------------------------------- +.PHONY: setup-git-hooks setup-git-hooks: - $(call print_title,Installing git hooks) - @for hook in .githooks/*; do \ - hook_name=$$(basename $$hook); \ - cp "$$hook" ".git/hooks/$$hook_name"; \ - chmod +x ".git/hooks/$$hook_name"; \ - echo "Installed $$hook_name"; \ - done - @echo "[ok] Git hooks installed successfully" + $(call print_title,Installing and configuring git hooks) + @if [ -d ".githooks" ]; then \ + for hook in .githooks/*; do \ + if [ -f "$$hook" ]; then \ + hook_name=$$(basename $$hook); \ + cp "$$hook" ".git/hooks/$$hook_name"; \ + chmod +x ".git/hooks/$$hook_name"; \ + echo "Installed $$hook_name"; \ + fi; \ + done; \ + else \ + echo "No .githooks directory found"; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) All hooks installed and updated$(GREEN) ✔️$(NC)" +.PHONY: check-hooks check-hooks: - $(call print_title,Verifying git hooks installation) + $(call print_title,Verifying git hooks installation status) @err=0; \ - for hook in .githooks/*; do \ - hook_name=$$(basename $$hook); \ - if [ ! -f ".git/hooks/$$hook_name" ]; then \ - echo "Git hook $$hook_name is NOT installed"; \ - err=1; \ + if [ -d ".githooks" ]; then \ + for hook in .githooks/*; do \ + if [ -f "$$hook" ]; then \ + hook_name=$$(basename $$hook); \ + f=".githooks/$$hook_name"; \ + FILE2=.git/hooks/$$hook_name; \ + if [ -f "$$FILE2" ]; then \ + if cmp -s "$$hook" "$$FILE2"; then \ + echo "$(GREEN)$(BOLD)[ok]$(NC) Hook file $$f installed and updated$(GREEN) ✔️$(NC)"; \ + else \ + echo "$(RED)Hook file $$f installed but out-of-date [OUT-OF-DATE] ✗$(NC)"; \ + err=1; \ + fi; \ + else \ + echo "$(RED)Hook file $$f not installed [NOT INSTALLED] ✗$(NC)"; \ + err=1; \ + fi; \ + fi; \ + done; \ + else \ + echo "No .githooks directory found"; \ + fi; \ + if [ $$err -ne 0 ]; then \ + echo ""; \ + echo "Run $(BOLD)make setup-git-hooks$(NC) to setup your development environment, then try again."; \ + echo ""; \ + exit 1; \ + else \ + echo "$(GREEN)$(BOLD)[ok]$(NC) All hooks are properly installed$(GREEN) ✔️$(NC)"; \ + fi + +.PHONY: check-envs +check-envs: + $(call print_title,Checking git hooks and environment files for security issues) + $(MAKE) check-hooks + @echo "Checking for exposed secrets in environment files..." + @if grep -rq "SECRET.*=" --include=".env" .; then \ + echo "$(RED)Warning: Secrets found in environment files. Make sure these are not committed to the repository.$(NC)"; \ + exit 1; \ + else \ + echo "$(GREEN)No exposed secrets found in environment files$(GREEN) ✔️$(NC)"; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) Environment check completed$(GREEN) ✔️$(NC)" + +#------------------------------------------------------- +# Development Commands +#------------------------------------------------------- + +.PHONY: tidy +tidy: + $(call print_title,Cleaning dependencies) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + go mod tidy + @echo "$(GREEN)$(BOLD)[ok]$(NC) Dependencies cleaned successfully$(GREEN) ✔️$(NC)" + +# SARIF output for GitHub Security tab integration (optional) +# Usage: make sec SARIF=1 +SARIF ?= 0 + +.PHONY: sec +sec: + $(call print_title,Running security checks using gosec) + @if ! command -v gosec >/dev/null 2>&1; then \ + echo "Installing gosec..."; \ + go install github.com/securego/gosec/v2/cmd/gosec@latest; \ + fi + @if find . -name "*.go" -type f -not -path './vendor/*' | grep -q .; then \ + echo "Running security checks on all packages..."; \ + if [ "$(SARIF)" = "1" ]; then \ + echo "Generating SARIF output: gosec-report.sarif"; \ + if gosec -fmt sarif -out gosec-report.sarif ./...; then \ + echo "$(GREEN)$(BOLD)[ok]$(NC) SARIF report generated: gosec-report.sarif$(GREEN) ✔️$(NC)"; \ + else \ + echo -e "\n$(BOLD)$(RED)Security issues found by gosec. Please address them before proceeding.$(NC)\n"; \ + echo "SARIF report with details: gosec-report.sarif"; \ + exit 1; \ + fi; \ else \ - echo "Git hook $$hook_name is installed"; \ + if gosec ./...; then \ + echo "$(GREEN)$(BOLD)[ok]$(NC) Security checks completed$(GREEN) ✔️$(NC)"; \ + else \ + echo -e "\n$(BOLD)$(RED)Security issues found by gosec. Please address them before proceeding.$(NC)\n"; \ + exit 1; \ + fi; \ fi; \ - done; \ - if [ $$err -eq 0 ]; then \ - echo "[ok] All git hooks are properly installed"; \ else \ - echo "[error] Some git hooks are missing. Run 'make setup-git-hooks' to fix."; \ - exit 1; \ + echo "No Go files found, skipping security checks"; \ fi + +#------------------------------------------------------- +# Release Commands +#------------------------------------------------------- + +.PHONY: goreleaser +goreleaser: + $(call print_title,Creating release snapshot with goreleaser) + $(call check_command,goreleaser,"go install github.com/goreleaser/goreleaser@latest") + goreleaser release --snapshot --skip-publish --clean + @echo "$(GREEN)$(BOLD)[ok]$(NC) Release snapshot created successfully$(GREEN) ✔️$(NC)" diff --git a/mk/tests.mk b/mk/tests.mk new file mode 100644 index 0000000..3947a49 --- /dev/null +++ b/mk/tests.mk @@ -0,0 +1,333 @@ +# ------------------------------------------------------ +# Test configuration for lib-auth +# ------------------------------------------------------ + +# Native fuzz test controls +# FUZZ: specific fuzz target name (e.g., FuzzValidateEmail) +# FUZZTIME: duration per fuzz target (default: 10s) +FUZZ ?= +FUZZTIME ?= 10s + +# Integration test filter +# RUN: specific test name pattern (e.g., TestIntegration_FeatureName) +# PKG: specific package to test (e.g., ./auth/...) +# Usage: make test-integration RUN=TestIntegration_FeatureName +# make test-integration PKG=./auth/... +RUN ?= +PKG ?= + +# Computed run pattern: uses RUN if set, otherwise defaults to '^TestIntegration' +ifeq ($(RUN),) + RUN_PATTERN := ^TestIntegration +else + RUN_PATTERN := $(RUN) +endif + +# Low-resource mode for limited machines (sets -p=1 -parallel=1, disables -race) +# Usage: make test-integration LOW_RESOURCE=1 +# make coverage-integration LOW_RESOURCE=1 +LOW_RESOURCE ?= 0 + +# Computed flags for low-resource mode +ifeq ($(LOW_RESOURCE),1) + LOW_RES_P_FLAG := -p 1 + LOW_RES_PARALLEL_FLAG := -parallel 1 + LOW_RES_RACE_FLAG := +else + LOW_RES_P_FLAG := + LOW_RES_PARALLEL_FLAG := + LOW_RES_RACE_FLAG := -race +endif + +# macOS ld64 workaround: newer ld emits noisy LC_DYSYMTAB warnings when linking test binaries with -race. +# If available, prefer Apple's classic linker to silence them. +UNAME_S := $(shell uname -s) +ifeq ($(UNAME_S),Darwin) + # Prefer classic mode to suppress LC_DYSYMTAB warnings on macOS. + # Set DISABLE_OSX_LINKER_WORKAROUND=1 to disable this behavior. + ifneq ($(DISABLE_OSX_LINKER_WORKAROUND),1) + GO_TEST_LDFLAGS := -ldflags="-linkmode=external -extldflags=-ld_classic" + else + GO_TEST_LDFLAGS := + endif +else + GO_TEST_LDFLAGS := +endif + +# ------------------------------------------------------ +# Test tooling configuration +# ------------------------------------------------------ + +TEST_REPORTS_DIR ?= ./reports +GOTESTSUM := $(shell command -v gotestsum 2>/dev/null) +RETRY_ON_FAIL ?= 0 + +.PHONY: tools tools-gotestsum +tools: tools-gotestsum ## Install helpful dev/test tools + +tools-gotestsum: + @if [ -z "$(GOTESTSUM)" ]; then \ + echo "Installing gotestsum..."; \ + GO111MODULE=on go install gotest.tools/gotestsum@latest; \ + else \ + echo "gotestsum already installed: $(GOTESTSUM)"; \ + fi + +#------------------------------------------------------- +# Core Test Commands +#------------------------------------------------------- + +.PHONY: test +test: + $(call print_title,Running all tests) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + @set -e; mkdir -p $(TEST_REPORTS_DIR); \ + if [ -n "$(GOTESTSUM)" ]; then \ + echo "Running tests with gotestsum"; \ + gotestsum --format testname -- -v -race -count=1 $(GO_TEST_LDFLAGS) ./...; \ + else \ + go test -v -race -count=1 $(GO_TEST_LDFLAGS) ./...; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) All tests passed$(GREEN) ✔️$(NC)" + +#------------------------------------------------------- +# Test Suite Aliases +#------------------------------------------------------- + +# Unit tests (excluding integration tests) +.PHONY: test-unit +test-unit: + $(call print_title,Running Go unit tests) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + @set -e; mkdir -p $(TEST_REPORTS_DIR); \ + pkgs=$$(go list ./... | grep -v '/tests'); \ + if [ -z "$$pkgs" ]; then \ + echo "No unit test packages found"; \ + else \ + if [ -n "$(GOTESTSUM)" ]; then \ + echo "Running unit tests with gotestsum"; \ + gotestsum --format testname -- -v -race -count=1 $(GO_TEST_LDFLAGS) $$pkgs || { \ + if [ "$(RETRY_ON_FAIL)" = "1" ]; then \ + echo "Retrying unit tests once..."; \ + gotestsum --format testname -- -v -race -count=1 $(GO_TEST_LDFLAGS) $$pkgs; \ + else \ + exit 1; \ + fi; \ + }; \ + else \ + go test -v -race -count=1 $(GO_TEST_LDFLAGS) $$pkgs; \ + fi; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) Unit tests passed$(GREEN) ✔️$(NC)" + +# Integration tests with testcontainers (no coverage) +# These tests use the `integration` build tag and testcontainers-go to spin up +# ephemeral containers. No external Docker stack is required. +# +# Requirements: +# - Test files must follow the naming convention: *_integration_test.go +# - Test functions must start with TestIntegration_ (e.g., TestIntegration_MyFeature_Works) +.PHONY: test-integration +test-integration: + $(call print_title,Running integration tests with testcontainers) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + $(call check_command,docker,"Install Docker from https://docs.docker.com/get-docker/") + @set -e; mkdir -p $(TEST_REPORTS_DIR); \ + if [ -n "$(PKG)" ]; then \ + echo "Using specified package: $(PKG)"; \ + pkgs=$$(go list $(PKG) 2>/dev/null | tr '\n' ' '); \ + else \ + echo "Finding packages with *_integration_test.go files..."; \ + dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' 2>/dev/null | xargs -n1 dirname 2>/dev/null | sort -u | tr '\n' ' '); \ + pkgs=$$(if [ -n "$$dirs" ]; then go list $$dirs 2>/dev/null | tr '\n' ' '; fi); \ + fi; \ + if [ -z "$$pkgs" ]; then \ + echo "No integration test packages found"; \ + else \ + echo "Packages: $$pkgs"; \ + echo "Running packages sequentially (-p=1) to avoid Docker container conflicts"; \ + if [ "$(LOW_RESOURCE)" = "1" ]; then \ + echo "LOW_RESOURCE mode: -parallel=1, race detector disabled"; \ + fi; \ + if [ -n "$(GOTESTSUM)" ]; then \ + echo "Running testcontainers integration tests with gotestsum"; \ + gotestsum --format testname -- \ + -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' $$pkgs || { \ + if [ "$(RETRY_ON_FAIL)" = "1" ]; then \ + echo "Retrying integration tests once..."; \ + gotestsum --format testname -- \ + -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' $$pkgs; \ + else \ + exit 1; \ + fi; \ + }; \ + else \ + go test -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' $$pkgs; \ + fi; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) Integration tests passed$(GREEN) ✔️$(NC)" + +# Run all tests (unit + integration) +.PHONY: test-all +test-all: + $(call print_title,Running all tests (unit + integration)) + $(call print_title,Running unit tests) + $(MAKE) test-unit + $(call print_title,Running integration tests) + $(MAKE) test-integration + @echo "$(GREEN)$(BOLD)[ok]$(NC) All tests passed$(GREEN) ✔️$(NC)" + +#------------------------------------------------------- +# Coverage Commands +#------------------------------------------------------- + +# Legacy cover command (for backward compatibility) +.PHONY: cover +cover: + $(call print_title,Generating test coverage report) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + @sh ./scripts/coverage.sh + @go tool cover -html=$(TEST_REPORTS_DIR)/coverage.out -o $(TEST_REPORTS_DIR)/coverage.html + @echo "" + @echo "Coverage Summary:" + @echo "----------------------------------------" + @go tool cover -func=$(TEST_REPORTS_DIR)/coverage.out | grep total | awk '{print "Total coverage: " $$3}' + @echo "----------------------------------------" + @echo "Open $(TEST_REPORTS_DIR)/coverage.html in your browser to view detailed coverage report" + @echo "$(GREEN)$(BOLD)[ok]$(NC) Coverage report generated successfully$(GREEN) ✔️$(NC)" + +# Unit tests with coverage (uses covermode=atomic) +# Supports PKG parameter to filter packages (e.g., PKG=./auth/...) +# Supports .ignorecoverunit file to exclude patterns from coverage stats +.PHONY: coverage-unit +coverage-unit: + $(call print_title,Running Go unit tests with coverage) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + @set -e; mkdir -p $(TEST_REPORTS_DIR); \ + if [ -n "$(PKG)" ]; then \ + echo "Using specified package: $(PKG)"; \ + pkgs=$$(go list $(PKG) 2>/dev/null | grep -v '/tests' | tr '\n' ' '); \ + else \ + pkgs=$$(go list ./... | grep -v '/tests'); \ + fi; \ + if [ -z "$$pkgs" ]; then \ + echo "No unit test packages found"; \ + else \ + echo "Packages: $$pkgs"; \ + if [ -n "$(GOTESTSUM)" ]; then \ + echo "Running unit tests with gotestsum (coverage enabled)"; \ + gotestsum --format testname -- -v -race -count=1 $(GO_TEST_LDFLAGS) -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/unit_coverage.out $$pkgs || { \ + if [ "$(RETRY_ON_FAIL)" = "1" ]; then \ + echo "Retrying unit tests once..."; \ + gotestsum --format testname -- -v -race -count=1 $(GO_TEST_LDFLAGS) -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/unit_coverage.out $$pkgs; \ + else \ + exit 1; \ + fi; \ + }; \ + else \ + go test -v -race -count=1 $(GO_TEST_LDFLAGS) -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/unit_coverage.out $$pkgs; \ + fi; \ + if [ -f .ignorecoverunit ]; then \ + echo "Filtering coverage with .ignorecoverunit patterns..."; \ + patterns=$$(grep -v '^#' .ignorecoverunit | grep -v '^$$' | tr '\n' '|' | sed 's/|$$//'); \ + if [ -n "$$patterns" ]; then \ + regex_patterns=$$(echo "$$patterns" | sed 's/\./\\./g' | sed 's/\*/.*/g'); \ + head -1 $(TEST_REPORTS_DIR)/unit_coverage.out > $(TEST_REPORTS_DIR)/unit_coverage_filtered.out; \ + tail -n +2 $(TEST_REPORTS_DIR)/unit_coverage.out | grep -vE "$$regex_patterns" >> $(TEST_REPORTS_DIR)/unit_coverage_filtered.out || true; \ + mv $(TEST_REPORTS_DIR)/unit_coverage_filtered.out $(TEST_REPORTS_DIR)/unit_coverage.out; \ + echo "Excluded patterns: $$patterns"; \ + fi; \ + fi; \ + echo "----------------------------------------"; \ + go tool cover -func=$(TEST_REPORTS_DIR)/unit_coverage.out | grep total | awk '{print "Total coverage: " $$3}'; \ + echo "----------------------------------------"; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) Unit coverage report generated$(GREEN) ✔️$(NC)" + +# Integration tests with testcontainers (with coverage, uses covermode=atomic) +.PHONY: coverage-integration +coverage-integration: + $(call print_title,Running integration tests with testcontainers (coverage enabled)) + $(call check_command,go,"Install Go from https://golang.org/doc/install") + $(call check_command,docker,"Install Docker from https://docs.docker.com/get-docker/") + @set -e; mkdir -p $(TEST_REPORTS_DIR); \ + if [ -n "$(PKG)" ]; then \ + echo "Using specified package: $(PKG)"; \ + pkgs=$$(go list $(PKG) 2>/dev/null | tr '\n' ' '); \ + else \ + echo "Finding packages with *_integration_test.go files..."; \ + dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' 2>/dev/null | xargs -n1 dirname 2>/dev/null | sort -u | tr '\n' ' '); \ + pkgs=$$(if [ -n "$$dirs" ]; then go list $$dirs 2>/dev/null | tr '\n' ' '; fi); \ + fi; \ + if [ -z "$$pkgs" ]; then \ + echo "No integration test packages found"; \ + else \ + echo "Packages: $$pkgs"; \ + echo "Running packages sequentially (-p=1) to avoid Docker container conflicts"; \ + if [ "$(LOW_RESOURCE)" = "1" ]; then \ + echo "LOW_RESOURCE mode: -parallel=1, race detector disabled"; \ + fi; \ + if [ -n "$(GOTESTSUM)" ]; then \ + echo "Running testcontainers integration tests with gotestsum (coverage enabled)"; \ + gotestsum --format testname -- \ + -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/integration_coverage.out \ + $$pkgs || { \ + if [ "$(RETRY_ON_FAIL)" = "1" ]; then \ + echo "Retrying integration tests once..."; \ + gotestsum --format testname -- \ + -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/integration_coverage.out \ + $$pkgs; \ + else \ + exit 1; \ + fi; \ + }; \ + else \ + go test -tags=integration -v $(LOW_RES_RACE_FLAG) -count=1 -timeout 600s $(GO_TEST_LDFLAGS) \ + -p 1 $(LOW_RES_PARALLEL_FLAG) \ + -run '$(RUN_PATTERN)' -covermode=atomic -coverprofile=$(TEST_REPORTS_DIR)/integration_coverage.out \ + $$pkgs; \ + fi; \ + echo "----------------------------------------"; \ + go tool cover -func=$(TEST_REPORTS_DIR)/integration_coverage.out | grep total | awk '{print "Total coverage: " $$3}'; \ + echo "----------------------------------------"; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) Integration coverage report generated$(GREEN) ✔️$(NC)" + +# Run all coverage targets +.PHONY: coverage +coverage: + $(call print_title,Running all coverage targets) + $(MAKE) coverage-unit + $(MAKE) coverage-integration + @echo "$(GREEN)$(BOLD)[ok]$(NC) All coverage reports generated$(GREEN) ✔️$(NC)" + +# Generate HTML coverage report +.PHONY: cover-html +cover-html: + $(call print_title,Generating HTML coverage report) + @if [ -f "$(TEST_REPORTS_DIR)/unit_coverage.out" ]; then \ + echo "Generating HTML report for unit tests..."; \ + go tool cover -html=$(TEST_REPORTS_DIR)/unit_coverage.out -o $(TEST_REPORTS_DIR)/unit_coverage.html; \ + echo "Unit coverage HTML: $(TEST_REPORTS_DIR)/unit_coverage.html"; \ + fi + @if [ -f "$(TEST_REPORTS_DIR)/integration_coverage.out" ]; then \ + echo "Generating HTML report for integration tests..."; \ + go tool cover -html=$(TEST_REPORTS_DIR)/integration_coverage.out -o $(TEST_REPORTS_DIR)/integration_coverage.html; \ + echo "Integration coverage HTML: $(TEST_REPORTS_DIR)/integration_coverage.html"; \ + fi + @if [ -f "$(TEST_REPORTS_DIR)/coverage.out" ]; then \ + echo "Generating HTML report for combined coverage..."; \ + go tool cover -html=$(TEST_REPORTS_DIR)/coverage.out -o $(TEST_REPORTS_DIR)/coverage.html; \ + echo "Combined coverage HTML: $(TEST_REPORTS_DIR)/coverage.html"; \ + fi + @echo "$(GREEN)$(BOLD)[ok]$(NC) HTML coverage reports generated$(GREEN) ✔️$(NC)" diff --git a/scripts/coverage.sh b/scripts/coverage.sh new file mode 100755 index 0000000..e060b62 --- /dev/null +++ b/scripts/coverage.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Define color codes for better readability +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +RED='\033[0;31m' +NC='\033[0m' # No Color + +# Reports directory +TEST_REPORTS_DIR="${TEST_REPORTS_DIR:-./reports}" +mkdir -p "$TEST_REPORTS_DIR" + +echo "${BLUE}Generating test coverage report...${NC}" + +# Check if coverage_ignore.txt exists +if [ ! -f "./scripts/coverage_ignore.txt" ]; then + echo "${YELLOW}Warning: ./scripts/coverage_ignore.txt not found. Using all packages.${NC}" + PACKAGES=$(go list ./... | grep -v '/vendor/') +else + # Get the list of packages to test, excluding those in the ignore list + PACKAGES=$(go list ./... | grep -v '/vendor/' | grep -v -f ./scripts/coverage_ignore.txt) +fi + +if [ -z "$PACKAGES" ]; then + echo "${RED}Error: No packages found to test${NC}" + exit 1 +fi + +echo "${BLUE}Running tests on packages:${NC}" +echo "$PACKAGES" + +# Run the tests and generate coverage profile +echo "" +go test -cover $PACKAGES -coverprofile="$TEST_REPORTS_DIR/coverage.out" -covermode=atomic + +# Check if tests passed +if [ $? -ne 0 ]; then + echo "${RED}Tests failed${NC}" + exit 1 +fi + +# Print coverage summary +printf "\n${GREEN}Coverage Summary:${NC}\n" +go tool cover -func="$TEST_REPORTS_DIR/coverage.out" + +# Print note about coverage exclusions if ignore file exists +if [ -f "./scripts/coverage_ignore.txt" ]; then + printf "\n${YELLOW}NOTE ON COVERAGE:${NC}\n" + echo "Some packages are excluded from coverage metrics (see ./scripts/coverage_ignore.txt)" + echo "These exclusions may include:" + echo "- Test utilities and test packages" + echo "- Mock implementations" + echo "- Generated code" + echo "" +fi + +echo "${GREEN}Coverage report generated successfully${NC}" diff --git a/scripts/coverage_ignore.txt b/scripts/coverage_ignore.txt new file mode 100644 index 0000000..e69de29 From da45b1ad9464aaf7925d932cd5af6b50a58562ea Mon Sep 17 00:00:00 2001 From: Marcelo Rangel Date: Fri, 6 Feb 2026 18:15:03 -0300 Subject: [PATCH 09/34] fix(tests): use safe find -exec instead of xargs pipeline :bug: Replace find | xargs pipeline with find -exec to prevent failures under set -e when no integration test files are found. The -exec approach is more robust and doesn't require null-delimited handling. X-Lerian-Ref: 0x1 --- mk/tests.mk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mk/tests.mk b/mk/tests.mk index 3947a49..ea6fbd8 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -138,7 +138,7 @@ test-integration: pkgs=$$(go list $(PKG) 2>/dev/null | tr '\n' ' '); \ else \ echo "Finding packages with *_integration_test.go files..."; \ - dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' 2>/dev/null | xargs -n1 dirname 2>/dev/null | sort -u | tr '\n' ' '); \ + dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' -exec dirname {} \; 2>/dev/null | sort -u | tr '\n' ' '); \ pkgs=$$(if [ -n "$$dirs" ]; then go list $$dirs 2>/dev/null | tr '\n' ' '; fi); \ fi; \ if [ -z "$$pkgs" ]; then \ @@ -262,7 +262,7 @@ coverage-integration: pkgs=$$(go list $(PKG) 2>/dev/null | tr '\n' ' '); \ else \ echo "Finding packages with *_integration_test.go files..."; \ - dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' 2>/dev/null | xargs -n1 dirname 2>/dev/null | sort -u | tr '\n' ' '); \ + dirs=$$(find . -name '*_integration_test.go' -not -path './vendor/*' -exec dirname {} \; 2>/dev/null | sort -u | tr '\n' ' '); \ pkgs=$$(if [ -n "$$dirs" ]; then go list $$dirs 2>/dev/null | tr '\n' ' '; fi); \ fi; \ if [ -z "$$pkgs" ]; then \ From 667eea342077bb16217906130cf353b954bbf813 Mon Sep 17 00:00:00 2001 From: Marcelo Rangel Date: Fri, 6 Feb 2026 19:34:13 -0300 Subject: [PATCH 10/34] chore(makefile): remove legacy coverage commands :wrench: Remove 'make cover' and 'make cover-html' commands which have been superseded by the more granular coverage-unit and coverage-integration commands. Also removes the associated coverage.sh script and coverage_ignore.txt file. X-Lerian-Ref: 0x1 --- Makefile | 2 -- mk/tests.mk | 36 ----------------------- scripts/coverage.sh | 58 ------------------------------------- scripts/coverage_ignore.txt | 0 4 files changed, 96 deletions(-) delete mode 100755 scripts/coverage.sh delete mode 100644 scripts/coverage_ignore.txt diff --git a/Makefile b/Makefile index 599eaad..9db4a0b 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,6 @@ help: @echo " make test - Run all tests" @echo " make build - Build all packages" @echo " make clean - Clean all build artifacts" - @echo " make cover - Run test coverage" @echo "" @echo "" @echo "Test Suite Commands:" @@ -63,7 +62,6 @@ help: @echo " make coverage-unit - Run unit tests with coverage report (PKG=./path, uses .ignorecoverunit)" @echo " make coverage-integration - Run integration tests with coverage report (PKG=./path)" @echo " make coverage - Run all coverage targets (unit + integration)" - @echo " make cover-html - Generate HTML coverage reports" @echo "" @echo "" @echo "Test Tooling:" diff --git a/mk/tests.mk b/mk/tests.mk index ea6fbd8..8b9cec0 100644 --- a/mk/tests.mk +++ b/mk/tests.mk @@ -187,21 +187,6 @@ test-all: # Coverage Commands #------------------------------------------------------- -# Legacy cover command (for backward compatibility) -.PHONY: cover -cover: - $(call print_title,Generating test coverage report) - $(call check_command,go,"Install Go from https://golang.org/doc/install") - @sh ./scripts/coverage.sh - @go tool cover -html=$(TEST_REPORTS_DIR)/coverage.out -o $(TEST_REPORTS_DIR)/coverage.html - @echo "" - @echo "Coverage Summary:" - @echo "----------------------------------------" - @go tool cover -func=$(TEST_REPORTS_DIR)/coverage.out | grep total | awk '{print "Total coverage: " $$3}' - @echo "----------------------------------------" - @echo "Open $(TEST_REPORTS_DIR)/coverage.html in your browser to view detailed coverage report" - @echo "$(GREEN)$(BOLD)[ok]$(NC) Coverage report generated successfully$(GREEN) ✔️$(NC)" - # Unit tests with coverage (uses covermode=atomic) # Supports PKG parameter to filter packages (e.g., PKG=./auth/...) # Supports .ignorecoverunit file to exclude patterns from coverage stats @@ -310,24 +295,3 @@ coverage: $(MAKE) coverage-unit $(MAKE) coverage-integration @echo "$(GREEN)$(BOLD)[ok]$(NC) All coverage reports generated$(GREEN) ✔️$(NC)" - -# Generate HTML coverage report -.PHONY: cover-html -cover-html: - $(call print_title,Generating HTML coverage report) - @if [ -f "$(TEST_REPORTS_DIR)/unit_coverage.out" ]; then \ - echo "Generating HTML report for unit tests..."; \ - go tool cover -html=$(TEST_REPORTS_DIR)/unit_coverage.out -o $(TEST_REPORTS_DIR)/unit_coverage.html; \ - echo "Unit coverage HTML: $(TEST_REPORTS_DIR)/unit_coverage.html"; \ - fi - @if [ -f "$(TEST_REPORTS_DIR)/integration_coverage.out" ]; then \ - echo "Generating HTML report for integration tests..."; \ - go tool cover -html=$(TEST_REPORTS_DIR)/integration_coverage.out -o $(TEST_REPORTS_DIR)/integration_coverage.html; \ - echo "Integration coverage HTML: $(TEST_REPORTS_DIR)/integration_coverage.html"; \ - fi - @if [ -f "$(TEST_REPORTS_DIR)/coverage.out" ]; then \ - echo "Generating HTML report for combined coverage..."; \ - go tool cover -html=$(TEST_REPORTS_DIR)/coverage.out -o $(TEST_REPORTS_DIR)/coverage.html; \ - echo "Combined coverage HTML: $(TEST_REPORTS_DIR)/coverage.html"; \ - fi - @echo "$(GREEN)$(BOLD)[ok]$(NC) HTML coverage reports generated$(GREEN) ✔️$(NC)" diff --git a/scripts/coverage.sh b/scripts/coverage.sh deleted file mode 100755 index e060b62..0000000 --- a/scripts/coverage.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/bin/bash - -# Define color codes for better readability -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -RED='\033[0;31m' -NC='\033[0m' # No Color - -# Reports directory -TEST_REPORTS_DIR="${TEST_REPORTS_DIR:-./reports}" -mkdir -p "$TEST_REPORTS_DIR" - -echo "${BLUE}Generating test coverage report...${NC}" - -# Check if coverage_ignore.txt exists -if [ ! -f "./scripts/coverage_ignore.txt" ]; then - echo "${YELLOW}Warning: ./scripts/coverage_ignore.txt not found. Using all packages.${NC}" - PACKAGES=$(go list ./... | grep -v '/vendor/') -else - # Get the list of packages to test, excluding those in the ignore list - PACKAGES=$(go list ./... | grep -v '/vendor/' | grep -v -f ./scripts/coverage_ignore.txt) -fi - -if [ -z "$PACKAGES" ]; then - echo "${RED}Error: No packages found to test${NC}" - exit 1 -fi - -echo "${BLUE}Running tests on packages:${NC}" -echo "$PACKAGES" - -# Run the tests and generate coverage profile -echo "" -go test -cover $PACKAGES -coverprofile="$TEST_REPORTS_DIR/coverage.out" -covermode=atomic - -# Check if tests passed -if [ $? -ne 0 ]; then - echo "${RED}Tests failed${NC}" - exit 1 -fi - -# Print coverage summary -printf "\n${GREEN}Coverage Summary:${NC}\n" -go tool cover -func="$TEST_REPORTS_DIR/coverage.out" - -# Print note about coverage exclusions if ignore file exists -if [ -f "./scripts/coverage_ignore.txt" ]; then - printf "\n${YELLOW}NOTE ON COVERAGE:${NC}\n" - echo "Some packages are excluded from coverage metrics (see ./scripts/coverage_ignore.txt)" - echo "These exclusions may include:" - echo "- Test utilities and test packages" - echo "- Mock implementations" - echo "- Generated code" - echo "" -fi - -echo "${GREEN}Coverage report generated successfully${NC}" diff --git a/scripts/coverage_ignore.txt b/scripts/coverage_ignore.txt deleted file mode 100644 index e69de29..0000000 From 5befee4f5490ff4ffad04b8fbbfad516d03bdae3 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Mon, 9 Feb 2026 19:12:21 +0000 Subject: [PATCH 11/34] chore(release): 2.5.0-beta.1 ## [2.5.0-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.1-beta.1...v2.5.0-beta.1) (2026-02-09) ### Bug Fixes * **tests:** use safe find -exec instead of xargs pipeline :bug: ([da45b1a](https://github.com/LerianStudio/lib-auth/commit/da45b1ad9464aaf7925d932cd5af6b50a58562ea)) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c0a37da..8c76e97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [2.5.0-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.1-beta.1...v2.5.0-beta.1) (2026-02-09) + + +### Bug Fixes + +* **tests:** use safe find -exec instead of xargs pipeline :bug: ([da45b1a](https://github.com/LerianStudio/lib-auth/commit/da45b1ad9464aaf7925d932cd5af6b50a58562ea)) + ## [2.4.1-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.0...v2.4.1-beta.1) (2026-02-03) ## [2.4.0](https://github.com/LerianStudio/lib-auth/compare/v2.3.0...v2.4.0) (2026-01-27) From a622a53f0b4579c15d15693eee766403c1807c67 Mon Sep 17 00:00:00 2001 From: Jefferson Rodrigues Date: Fri, 20 Feb 2026 19:37:22 -0300 Subject: [PATCH 12/34] chore: upgrade lib-commons to v3.0.0-beta.2 Update imports from v2 to v3 and point to published version, removing local replace directive. X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 10 +- auth/middleware/middlewareGRPC.go | 4 +- go.mod | 72 +++++++------- go.sum | 154 ++++++++++++++++-------------- 4 files changed, 124 insertions(+), 116 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 7689149..0def432 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -10,13 +10,13 @@ import ( "net/http" "time" - "github.com/LerianStudio/lib-commons/v2/commons/log" - "github.com/LerianStudio/lib-commons/v2/commons/opentelemetry" - "github.com/LerianStudio/lib-commons/v2/commons/zap" + "github.com/LerianStudio/lib-commons/v3/commons/log" + "github.com/LerianStudio/lib-commons/v3/commons/opentelemetry" + "github.com/LerianStudio/lib-commons/v3/commons/zap" "go.opentelemetry.io/otel/attribute" - "github.com/LerianStudio/lib-commons/v2/commons" - libHTTP "github.com/LerianStudio/lib-commons/v2/commons/net/http" + "github.com/LerianStudio/lib-commons/v3/commons" + libHTTP "github.com/LerianStudio/lib-commons/v3/commons/net/http" "github.com/gofiber/fiber/v2" jwt "github.com/golang-jwt/jwt/v5" ) diff --git a/auth/middleware/middlewareGRPC.go b/auth/middleware/middlewareGRPC.go index bd0b91d..f78481d 100644 --- a/auth/middleware/middlewareGRPC.go +++ b/auth/middleware/middlewareGRPC.go @@ -6,8 +6,8 @@ import ( "net/http" "strings" - "github.com/LerianStudio/lib-commons/v2/commons" - "github.com/LerianStudio/lib-commons/v2/commons/opentelemetry" + "github.com/LerianStudio/lib-commons/v3/commons" + "github.com/LerianStudio/lib-commons/v3/commons/opentelemetry" "go.opentelemetry.io/otel/attribute" "google.golang.org/grpc" "google.golang.org/grpc/codes" diff --git a/go.mod b/go.mod index 069e9c0..d4adaf9 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,13 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.23.2 - -toolchain go1.23.3 +go 1.24.0 require ( - github.com/LerianStudio/lib-commons/v2 v2.7.0-beta.3 - github.com/gofiber/fiber/v2 v2.52.9 + github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2 + github.com/gofiber/fiber/v2 v2.52.11 github.com/golang-jwt/jwt/v5 v5.3.0 - go.opentelemetry.io/otel v1.37.0 + go.opentelemetry.io/otel v1.39.0 + google.golang.org/grpc v1.78.0 ) require github.com/google/uuid v1.6.0 // indirect @@ -17,46 +16,47 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/clipperhouse/stringish v0.1.1 // indirect + github.com/clipperhouse/uax29/v2 v2.3.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/klauspost/compress v1.18.0 // indirect + github.com/klauspost/compress v1.18.2 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/rivo/uniseg v0.4.7 // indirect + github.com/mattn/go-runewidth v0.0.19 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect - github.com/tklauser/go-sysconf v0.3.15 // indirect - github.com/tklauser/numcpus v0.10.0 // indirect + github.com/sony/gobreaker v1.0.0 // indirect + github.com/tklauser/go-sysconf v0.3.16 // indirect + github.com/tklauser/numcpus v0.11.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.64.0 // indirect + github.com/valyala/fasthttp v1.69.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect - go.opentelemetry.io/proto/otlp v1.7.1 // indirect - go.uber.org/mock v0.5.2 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 // indirect + go.opentelemetry.io/otel/log v0.15.0 // indirect + go.opentelemetry.io/otel/metric v1.39.0 // indirect + go.opentelemetry.io/otel/sdk v1.39.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.15.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.39.0 // indirect + go.opentelemetry.io/otel/trace v1.39.0 // indirect + go.opentelemetry.io/proto/otlp v1.9.0 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/grpc v1.74.2 // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/net v0.49.0 // indirect + golang.org/x/sys v0.40.0 // indirect + golang.org/x/text v0.33.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 // indirect + google.golang.org/protobuf v1.36.11 // indirect ) diff --git a/go.sum b/go.sum index d71cef3..76a52db 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,18 @@ -github.com/LerianStudio/lib-commons/v2 v2.2.0 h1:pAyerAucWl42gvVUdGpBdUDRBUvNAk7OhtGZxyJ25aE= -github.com/LerianStudio/lib-commons/v2 v2.2.0/go.mod h1:6esN/Ao/Xkp/QwvYt8wXQNMgrhb3exOstKUIPuSUBDM= +github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2 h1:ykbnpOdjQtZ736A/SicvQVPylAihrgENtM5aJ29Bpus= +github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2/go.mod h1:eegTRzYBTMBmXew279htSmBWX0n4syWT9iTDr2ZCwNo= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= +github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= +github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= +github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -17,8 +24,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= -github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -27,12 +34,12 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= -github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= +github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= @@ -41,89 +48,90 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= -github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= +github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= -github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= -github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= +github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= -github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= -github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= -github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tklauser/go-sysconf v0.3.16 h1:frioLaCQSsF5Cy1jgRBrzr6t502KIIwQ0MArYICU0nA= +github.com/tklauser/go-sysconf v0.3.16/go.mod h1:/qNL9xxDhc7tx3HSRsLWNnuzbVfh3e7gh/BmM179nYI= +github.com/tklauser/numcpus v0.11.0 h1:nSTwhKH5e1dMNsCdVBukSZrURJRoHbSEQjdEbY+9RXw= +github.com/tklauser/numcpus v0.11.0/go.mod h1:z+LwcLq54uWZTX0u/bGobaV34u6V7KNlTZejzM6/3MQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.64.0 h1:QBygLLQmiAyiXuRhthf0tuRkqAFcrC42dckN2S+N3og= -github.com/valyala/fasthttp v1.64.0/go.mod h1:dGmFxwkWXSK0NbOSJuF7AMVzU+lkHz0wQVvVITv2UQA= +github.com/valyala/fasthttp v1.69.0 h1:fNLLESD2SooWeh2cidsuFtOcrEi4uB4m1mPrkJMZyVI= +github.com/valyala/fasthttp v1.69.0/go.mod h1:4wA4PfAraPlAsJ5jMSqCE2ug5tqUPwKXxVj8oNECGcw= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 h1:FGre0nZh5BSw7G73VpT3xs38HchsfPsa2aZtMp0NPOs= -go.opentelemetry.io/contrib/bridges/otelzap v0.12.0/go.mod h1:X2PYPViI2wTPIMIOBjG17KNybTzsrATnvPJ02kkz7LM= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 h1:z6lNIajgEBVtQZHjfw2hAccPEBDs+nx58VemmXWa2ec= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0/go.mod h1:+kyc3bRx/Qkq05P6OCu3mTEIOxYRYzoIg+JsUp5X+PM= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= -go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= -go.opentelemetry.io/otel/log/logtest v0.13.0 h1:xxaIcgoEEtnwdgj6D6Uo9K/Dynz9jqIxSDu2YObJ69Q= -go.opentelemetry.io/otel/log/logtest v0.13.0/go.mod h1:+OrkmsAH38b+ygyag1tLjSFMYiES5UHggzrtY1IIEA8= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= -go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= -go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= -go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/bridges/otelzap v0.14.0 h1:2nKw2ZXZOC0N8RBsBbYwGwfKR7kJWzzyCZ6QfUGW/es= +go.opentelemetry.io/contrib/bridges/otelzap v0.14.0/go.mod h1:kvyVt0WEI5BB6XaIStXPIkCSQ2nSkyd8IZnAHLEXge4= +go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= +go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf8jF6WbuGQWUVcqgyWtTR0kOOAWY1DYZ+UhvdmQPw= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= +go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= +go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= +go.opentelemetry.io/otel/log/logtest v0.15.0 h1:porNFuxAjodl6LhePevOc3n7bo3Wi3JhGXNWe7KP8iU= +go.opentelemetry.io/otel/log/logtest v0.15.0/go.mod h1:c8epqBXGHgS1LiNgmD+LuNYK9lSS3mqvtMdxLsfJgLg= +go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= +go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= +go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= +go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= +go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= +go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= +go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= +go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= +go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= +go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= +go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= -google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 h1:X9z6obt+cWRX8XjDVOn+SZWhWe5kZHm46TThU9j+jss= +google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3/go.mod h1:dd646eSK+Dk9kxVBl1nChEOhJPtMXriCcVb4x3o6J+E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= +google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= +google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= +google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 9690684563dc1728829b19b4eb6cb6544430d306 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 20 Feb 2026 22:38:49 +0000 Subject: [PATCH 13/34] chore(release): 2.5.0-beta.2 ## [2.5.0-beta.2](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.1...v2.5.0-beta.2) (2026-02-20) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c76e97..df9333c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.5.0-beta.2](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.1...v2.5.0-beta.2) (2026-02-20) + ## [2.5.0-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.1-beta.1...v2.5.0-beta.1) (2026-02-09) From f3395ba2f6a349c3df04835c894f45c09aa724d4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 20 Feb 2026 22:39:13 +0000 Subject: [PATCH 14/34] build(deps): bump github.com/gofiber/fiber/v2 from 2.52.9 to 2.52.11 Bumps [github.com/gofiber/fiber/v2](https://github.com/gofiber/fiber) from 2.52.9 to 2.52.11. - [Release notes](https://github.com/gofiber/fiber/releases) - [Commits](https://github.com/gofiber/fiber/compare/v2.52.9...v2.52.11) --- updated-dependencies: - dependency-name: github.com/gofiber/fiber/v2 dependency-version: 2.52.11 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ef7a96..fea09a7 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.25.6 require ( github.com/LerianStudio/lib-commons/v2 v2.2.0 - github.com/gofiber/fiber/v2 v2.52.9 + github.com/gofiber/fiber/v2 v2.52.11 github.com/golang-jwt/jwt/v5 v5.3.1 go.opentelemetry.io/otel v1.37.0 google.golang.org/grpc v1.74.2 diff --git a/go.sum b/go.sum index af6db3d..e223b06 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/gofiber/fiber/v2 v2.52.9 h1:YjKl5DOiyP3j0mO61u3NTmK7or8GzzWzCFzkboyP5cw= -github.com/gofiber/fiber/v2 v2.52.9/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= +github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= From fb4e6dad92effa67ef63cabff3a63129fbbafa12 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 20 Feb 2026 22:40:25 +0000 Subject: [PATCH 15/34] chore(release): 2.5.0-beta.3 ## [2.5.0-beta.3](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.2...v2.5.0-beta.3) (2026-02-20) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index df9333c..9a559cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.5.0-beta.3](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.2...v2.5.0-beta.3) (2026-02-20) + ## [2.5.0-beta.2](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.1...v2.5.0-beta.2) (2026-02-20) ## [2.5.0-beta.1](https://github.com/LerianStudio/lib-auth/compare/v2.4.1-beta.1...v2.5.0-beta.1) (2026-02-09) From 7e6132369a286099aa17bf72c9dbb9adfd7976c5 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 20 Feb 2026 22:41:29 +0000 Subject: [PATCH 16/34] chore(release): 2.5.0-beta.4 ## [2.5.0-beta.4](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.3...v2.5.0-beta.4) (2026-02-20) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a559cb..ba31911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.5.0-beta.4](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.3...v2.5.0-beta.4) (2026-02-20) + ## [2.5.0-beta.3](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.2...v2.5.0-beta.3) (2026-02-20) ## [2.5.0-beta.2](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.1...v2.5.0-beta.2) (2026-02-20) From 0a19c602f7e1e98fc3ce9ba1fa76ac4e5e9ea0c8 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 20 Feb 2026 22:47:43 +0000 Subject: [PATCH 17/34] chore(release): 2.5.0-beta.5 ## [2.5.0-beta.5](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.4...v2.5.0-beta.5) (2026-02-20) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba31911..f7c1410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.5.0-beta.5](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.4...v2.5.0-beta.5) (2026-02-20) + ## [2.5.0-beta.4](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.3...v2.5.0-beta.4) (2026-02-20) ## [2.5.0-beta.3](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.2...v2.5.0-beta.3) (2026-02-20) From 17d426258e61f9965e0baf73915372b472c16556 Mon Sep 17 00:00:00 2001 From: Brecci Date: Thu, 26 Feb 2026 16:50:13 -0300 Subject: [PATCH 18/34] test: add first-ever middleware tests for gRPC and HTTP - 17 test functions with 40+ subtests covering both middleware files - gRPC: stripBearer, policyForMethod, grpcErrorFromHTTP, extractTokenFromMD, SubFromMetadata, NewGRPCAuthUnaryPolicy integration - HTTP: checkAuthorization subject construction for normal-user and application tokens, mock server integration, error handling - Documents known bug: application tokens hardcode "admin/" prefix instead of using owner claim from JWT - Add testify v1.11.1 dependency Co-Authored-By: Claude Opus 4.6 --- auth/middleware/middlewareGRPC_test.go | 558 +++++++++++++++++++++++++ auth/middleware/middleware_test.go | 449 ++++++++++++++++++++ go.mod | 57 +-- go.sum | 128 +++--- 4 files changed, 1109 insertions(+), 83 deletions(-) create mode 100644 auth/middleware/middlewareGRPC_test.go create mode 100644 auth/middleware/middleware_test.go diff --git a/auth/middleware/middlewareGRPC_test.go b/auth/middleware/middlewareGRPC_test.go new file mode 100644 index 0000000..ff90515 --- /dev/null +++ b/auth/middleware/middlewareGRPC_test.go @@ -0,0 +1,558 @@ +package middleware + +import ( + "context" + "net/http" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" +) + +// --------------------------------------------------------------------------- +// stripBearer +// --------------------------------------------------------------------------- + +func Test_stripBearer(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + input string + want string + }{ + { + name: "standard_bearer_prefix", + input: "Bearer token123", + want: "token123", + }, + { + name: "lowercase_bearer_prefix", + input: "bearer token123", + want: "token123", + }, + { + name: "uppercase_bearer_prefix", + input: "BEARER token123", + want: "token123", + }, + { + name: "no_prefix_returns_token_as_is", + input: "token123", + want: "token123", + }, + { + name: "whitespace_around_bearer_and_token", + input: " Bearer token123 ", + want: "token123", + }, + { + name: "empty_string", + input: "", + want: "", + }, + { + // NOTE: "Bearer " is trimmed to "Bearer" (6 chars), which is shorter + // than the 7-char "bearer " prefix check, so stripBearer returns + // the trimmed value as-is. This documents actual behavior. + name: "bearer_prefix_with_no_token_returns_bearer_literal", + input: "Bearer ", + want: "Bearer", + }, + { + // Same trimming behavior as above. + name: "bearer_prefix_only_trailing_spaces_returns_bearer_literal", + input: "Bearer ", + want: "Bearer", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + got := stripBearer(tt.input) + assert.Equal(t, tt.want, got) + }) + } +} + +// --------------------------------------------------------------------------- +// policyForMethod +// --------------------------------------------------------------------------- + +func Test_policyForMethod(t *testing.T) { + t.Parallel() + + defaultPol := Policy{Resource: "default-res", Action: "default-act"} + specificPol := Policy{Resource: "users", Action: "read"} + + tests := []struct { + name string + cfg PolicyConfig + fullMethod string + wantPolicy Policy + wantFound bool + }{ + { + name: "method_found_in_method_policies", + cfg: PolicyConfig{ + MethodPolicies: map[string]Policy{ + "/pkg.Service/GetUser": specificPol, + }, + }, + fullMethod: "/pkg.Service/GetUser", + wantPolicy: specificPol, + wantFound: true, + }, + { + name: "method_not_found_falls_back_to_default_policy", + cfg: PolicyConfig{ + MethodPolicies: map[string]Policy{ + "/pkg.Service/GetUser": specificPol, + }, + DefaultPolicy: &defaultPol, + }, + fullMethod: "/pkg.Service/DeleteUser", + wantPolicy: defaultPol, + wantFound: true, + }, + { + name: "method_not_found_no_default_returns_false", + cfg: PolicyConfig{ + MethodPolicies: map[string]Policy{ + "/pkg.Service/GetUser": specificPol, + }, + }, + fullMethod: "/pkg.Service/DeleteUser", + wantPolicy: Policy{}, + wantFound: false, + }, + { + name: "nil_method_policies_with_default_returns_default", + cfg: PolicyConfig{ + MethodPolicies: nil, + DefaultPolicy: &defaultPol, + }, + fullMethod: "/pkg.Service/AnyMethod", + wantPolicy: defaultPol, + wantFound: true, + }, + { + name: "nil_method_policies_no_default_returns_false", + cfg: PolicyConfig{ + MethodPolicies: nil, + DefaultPolicy: nil, + }, + fullMethod: "/pkg.Service/AnyMethod", + wantPolicy: Policy{}, + wantFound: false, + }, + { + name: "empty_method_policies_with_default", + cfg: PolicyConfig{ + MethodPolicies: map[string]Policy{}, + DefaultPolicy: &defaultPol, + }, + fullMethod: "/pkg.Service/AnyMethod", + wantPolicy: defaultPol, + wantFound: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + gotPolicy, gotFound := policyForMethod(tt.cfg, tt.fullMethod) + assert.Equal(t, tt.wantFound, gotFound) + assert.Equal(t, tt.wantPolicy, gotPolicy) + }) + } +} + +// --------------------------------------------------------------------------- +// grpcErrorFromHTTP +// --------------------------------------------------------------------------- + +func Test_grpcErrorFromHTTP(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + httpStatus int + wantCode codes.Code + wantMsg string + }{ + { + name: "401_maps_to_unauthenticated", + httpStatus: http.StatusUnauthorized, + wantCode: codes.Unauthenticated, + wantMsg: "unauthenticated", + }, + { + name: "403_maps_to_permission_denied", + httpStatus: http.StatusForbidden, + wantCode: codes.PermissionDenied, + wantMsg: "forbidden", + }, + { + name: "500_maps_to_internal", + httpStatus: http.StatusInternalServerError, + wantCode: codes.Internal, + wantMsg: "internal error", + }, + { + name: "0_default_maps_to_internal", + httpStatus: 0, + wantCode: codes.Internal, + wantMsg: "internal error", + }, + { + name: "404_unmapped_maps_to_internal", + httpStatus: http.StatusNotFound, + wantCode: codes.Internal, + wantMsg: "internal error", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + err := grpcErrorFromHTTP(tt.httpStatus) + require.Error(t, err) + + st, ok := status.FromError(err) + require.True(t, ok, "expected a gRPC status error") + assert.Equal(t, tt.wantCode, st.Code()) + assert.Equal(t, tt.wantMsg, st.Message()) + }) + } +} + +// --------------------------------------------------------------------------- +// extractTokenFromMD +// --------------------------------------------------------------------------- + +func Test_extractTokenFromMD(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + ctx context.Context + wantToken string + wantOK bool + }{ + { + name: "valid_bearer_token_in_metadata", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer token123"), + ), + wantToken: "token123", + wantOK: true, + }, + { + name: "no_metadata_in_context", + ctx: context.Background(), + wantToken: "", + wantOK: false, + }, + { + name: "empty_authorization_value", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", ""), + ), + wantToken: "", + wantOK: false, + }, + { + // NOTE: "Bearer " trimmed to "Bearer" (6 chars) which is below the + // 7-char prefix check threshold. stripBearer returns "Bearer" as a + // literal token and extractTokenFromMD treats it as non-empty. + name: "authorization_with_bearer_prefix_only_returns_bearer_literal", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer "), + ), + wantToken: "Bearer", + wantOK: true, + }, + { + name: "multiple_authorization_values_takes_first", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs( + "authorization", "Bearer first-token", + "authorization", "Bearer second-token", + ), + ), + wantToken: "first-token", + wantOK: true, + }, + { + name: "token_without_bearer_prefix", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "raw-token-value"), + ), + wantToken: "raw-token-value", + wantOK: true, + }, + { + name: "metadata_present_but_no_authorization_key", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("content-type", "application/json"), + ), + wantToken: "", + wantOK: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + gotToken, gotOK := extractTokenFromMD(tt.ctx) + assert.Equal(t, tt.wantOK, gotOK) + assert.Equal(t, tt.wantToken, gotToken) + }) + } +} + +// --------------------------------------------------------------------------- +// SubFromMetadata +// --------------------------------------------------------------------------- + +func TestSubFromMetadata(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + key string + ctx context.Context + wantSub string + wantErr bool + }{ + { + name: "key_present_in_metadata", + key: "x-tenant-id", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("x-tenant-id", "tenant-abc"), + ), + wantSub: "tenant-abc", + wantErr: false, + }, + { + name: "key_absent_in_metadata", + key: "x-tenant-id", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("other-key", "value"), + ), + wantSub: "", + wantErr: false, + }, + { + name: "no_metadata_in_context", + key: "x-tenant-id", + ctx: context.Background(), + wantSub: "", + wantErr: false, + }, + { + name: "case_insensitive_key_lookup", + key: "X-Tenant-ID", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("x-tenant-id", "tenant-xyz"), + ), + wantSub: "tenant-xyz", + wantErr: false, + }, + { + name: "key_with_leading_trailing_whitespace", + key: " x-tenant-id ", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("x-tenant-id", "tenant-trimmed"), + ), + wantSub: "tenant-trimmed", + wantErr: false, + }, + { + name: "multiple_values_returns_first", + key: "x-scope", + ctx: metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("x-scope", "first", "x-scope", "second"), + ), + wantSub: "first", + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + resolver := SubFromMetadata(tt.key) + gotSub, err := resolver(tt.ctx, "/unused.Method", nil) + + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + assert.Equal(t, tt.wantSub, gotSub) + }) + } +} + +// --------------------------------------------------------------------------- +// NewGRPCAuthUnaryPolicy (integration-level) +// --------------------------------------------------------------------------- + +func TestNewGRPCAuthUnaryPolicy(t *testing.T) { + t.Parallel() + + handlerCalled := false + + noopHandler := func(_ context.Context, _ any) (any, error) { + handlerCalled = true + return "ok", nil + } + + dummyInfo := &grpc.UnaryServerInfo{ + FullMethod: "/pkg.Service/DoThing", + } + + t.Run("auth_disabled_passes_through", func(t *testing.T) { + t.Parallel() + + called := false + handler := func(_ context.Context, _ any) (any, error) { + called = true + return "ok", nil + } + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: false} + interceptor := NewGRPCAuthUnaryPolicy(auth, PolicyConfig{}) + + resp, err := interceptor(context.Background(), "req", dummyInfo, handler) + require.NoError(t, err) + assert.Equal(t, "ok", resp) + assert.True(t, called) + }) + + t.Run("auth_nil_passes_through", func(t *testing.T) { + t.Parallel() + + called := false + handler := func(_ context.Context, _ any) (any, error) { + called = true + return "ok", nil + } + + interceptor := NewGRPCAuthUnaryPolicy(nil, PolicyConfig{}) + + resp, err := interceptor(context.Background(), "req", dummyInfo, handler) + require.NoError(t, err) + assert.Equal(t, "ok", resp) + assert.True(t, called) + }) + + t.Run("auth_enabled_but_empty_address_passes_through", func(t *testing.T) { + t.Parallel() + + called := false + handler := func(_ context.Context, _ any) (any, error) { + called = true + return "ok", nil + } + + auth := &AuthClient{Address: "", Enabled: true} + interceptor := NewGRPCAuthUnaryPolicy(auth, PolicyConfig{}) + + resp, err := interceptor(context.Background(), "req", dummyInfo, handler) + require.NoError(t, err) + assert.Equal(t, "ok", resp) + assert.True(t, called) + }) + + t.Run("missing_token_returns_unauthenticated", func(t *testing.T) { + t.Parallel() + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: true} + interceptor := NewGRPCAuthUnaryPolicy(auth, PolicyConfig{}) + + // Context without any metadata -> no token + resp, err := interceptor(context.Background(), "req", dummyInfo, noopHandler) + require.Error(t, err) + assert.Nil(t, resp) + + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Unauthenticated, st.Code()) + assert.Contains(t, st.Message(), "missing token") + }) + + t.Run("bearer_prefix_only_passes_token_check_but_fails_policy_lookup", func(t *testing.T) { + t.Parallel() + + // NOTE: "Bearer " is trimmed to "Bearer" (6 chars) by stripBearer, + // which is treated as a non-empty token. The interceptor then proceeds + // to the policy lookup phase, which fails because no policy is + // configured for the method. + auth := &AuthClient{Address: "http://localhost:9999", Enabled: true} + interceptor := NewGRPCAuthUnaryPolicy(auth, PolicyConfig{}) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer "), + ) + + resp, err := interceptor(ctx, "req", dummyInfo, noopHandler) + require.Error(t, err) + assert.Nil(t, resp) + + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, st.Code()) + assert.Contains(t, st.Message(), "internal configuration error") + }) + + t.Run("no_policy_for_method_and_no_default_returns_internal", func(t *testing.T) { + t.Parallel() + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: true} + cfg := PolicyConfig{ + MethodPolicies: map[string]Policy{ + "/pkg.Service/OtherMethod": {Resource: "other", Action: "read"}, + }, + // No DefaultPolicy + } + interceptor := NewGRPCAuthUnaryPolicy(auth, cfg) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer valid-token"), + ) + + resp, err := interceptor(ctx, "req", dummyInfo, noopHandler) + require.Error(t, err) + assert.Nil(t, resp) + + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, st.Code()) + assert.Contains(t, st.Message(), "internal configuration error") + }) + + // Prevent compiler from optimizing away the handlerCalled variable + _ = handlerCalled +} diff --git a/auth/middleware/middleware_test.go b/auth/middleware/middleware_test.go new file mode 100644 index 0000000..460310b --- /dev/null +++ b/auth/middleware/middleware_test.go @@ -0,0 +1,449 @@ +package middleware + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/LerianStudio/lib-commons/v2/commons/log" + jwt "github.com/golang-jwt/jwt/v5" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +// --------------------------------------------------------------------------- +// Test helpers +// --------------------------------------------------------------------------- + +// createTestJWT builds a signed JWT string for testing. +// checkAuthorization uses ParseUnverified so the signing key does not matter. +func createTestJWT(claims jwt.MapClaims) string { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + signed, err := token.SignedString([]byte("test-secret")) + if err != nil { + // This should never happen in tests with a valid key. + panic("failed to sign test JWT: " + err.Error()) + } + + return signed +} + +// mockAuthServer returns an httptest.Server that responds to POST /v1/authorize. +func mockAuthServer(t *testing.T, authorized bool, statusCode int) *httptest.Server { + t.Helper() + + return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(statusCode) + + resp := AuthResponse{Authorized: authorized} + + err := json.NewEncoder(w).Encode(resp) + if err != nil { + t.Errorf("mock server: failed to encode response: %v", err) + } + })) +} + +// testLogger is a minimal log.Logger implementation for tests that discards all output. +type testLogger struct{} + +func (l *testLogger) Info(_ ...any) {} +func (l *testLogger) Infof(_ string, _ ...any) {} +func (l *testLogger) Infoln(_ ...any) {} +func (l *testLogger) Error(_ ...any) {} +func (l *testLogger) Errorf(_ string, _ ...any) {} +func (l *testLogger) Errorln(_ ...any) {} +func (l *testLogger) Warn(_ ...any) {} +func (l *testLogger) Warnf(_ string, _ ...any) {} +func (l *testLogger) Warnln(_ ...any) {} +func (l *testLogger) Debug(_ ...any) {} +func (l *testLogger) Debugf(_ string, _ ...any) {} +func (l *testLogger) Debugln(_ ...any) {} +func (l *testLogger) Fatal(_ ...any) {} +func (l *testLogger) Fatalf(_ string, _ ...any) {} +func (l *testLogger) Fatalln(_ ...any) {} +func (l *testLogger) WithFields(_ ...any) log.Logger { return l } +func (l *testLogger) WithDefaultMessageTemplate(_ string) log.Logger { return l } +func (l *testLogger) Sync() error { return nil } + +// --------------------------------------------------------------------------- +// checkAuthorization - subject construction +// --------------------------------------------------------------------------- + +func TestCheckAuthorization_NormalUser_SubjectConstruction(t *testing.T) { + t.Parallel() + + // Mock server captures the request body to verify the constructed subject. + var capturedBody map[string]string + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := json.NewDecoder(r.Body).Decode(&capturedBody) + if err != nil { + t.Errorf("mock server: failed to decode request body: %v", err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := AuthResponse{Authorized: true} + + encErr := json.NewEncoder(w).Encode(resp) + if encErr != nil { + t.Errorf("mock server: failed to encode response: %v", encErr) + } + })) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "acme-org", + "sub": "user123", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "initial-sub", "resource", "action", token, + ) + + require.NoError(t, err) + assert.True(t, authorized) + assert.Equal(t, http.StatusOK, statusCode) + + // For normal-user, sub should be "owner/sub-from-jwt" (overrides the initial sub parameter). + assert.Equal(t, "acme-org/user123", capturedBody["sub"]) +} + +func TestCheckAuthorization_ApplicationUser_SubjectConstruction(t *testing.T) { + t.Parallel() + + // Documents the current behavior: non-normal-user types get "admin/-editor-role". + var capturedBody map[string]string + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := json.NewDecoder(r.Body).Decode(&capturedBody) + if err != nil { + t.Errorf("mock server: failed to decode request body: %v", err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := AuthResponse{Authorized: true} + + encErr := json.NewEncoder(w).Encode(resp) + if encErr != nil { + t.Errorf("mock server: failed to encode response: %v", encErr) + } + })) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "application", + "name": "my-app", + "sub": "app-sub", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "my-app", "resource", "action", token, + ) + + require.NoError(t, err) + assert.True(t, authorized) + assert.Equal(t, http.StatusOK, statusCode) + + // BUG: hardcodes "admin/" prefix. The sub parameter is used as-is with the + // "admin/-editor-role" pattern, regardless of the actual user type. + assert.Equal(t, "admin/my-app-editor-role", capturedBody["sub"]) +} + +func TestCheckAuthorization_MissingOwnerClaim(t *testing.T) { + t.Parallel() + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + // normal-user without "owner" claim should cause an error. + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "sub": "user123", + // "owner" is intentionally missing + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "action", token, + ) + + require.Error(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusUnauthorized, statusCode) + assert.Contains(t, err.Error(), "missing owner claim") +} + +func TestCheckAuthorization_MockServerReturnsAuthorizedTrue(t *testing.T) { + t.Parallel() + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org1", + "sub": "user1", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "read", token, + ) + + require.NoError(t, err) + assert.True(t, authorized) + assert.Equal(t, http.StatusOK, statusCode) +} + +func TestCheckAuthorization_MockServerReturnsAuthorizedFalse(t *testing.T) { + t.Parallel() + + server := mockAuthServer(t, false, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org1", + "sub": "user1", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "read", token, + ) + + require.NoError(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusOK, statusCode) +} + +func TestCheckAuthorization_MockServerReturnsForbiddenWithErrorBody(t *testing.T) { + t.Parallel() + + // When the auth server returns a non-200 response with a Response body that + // has a non-empty Code field, checkAuthorization returns an error. + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusForbidden) + + resp := map[string]string{ + "code": "FORBIDDEN", + "title": "Forbidden", + "message": "You do not have permission", + } + + err := json.NewEncoder(w).Encode(resp) + if err != nil { + t.Errorf("mock server: failed to encode response: %v", err) + } + })) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org1", + "sub": "user1", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "write", token, + ) + + require.Error(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusForbidden, statusCode) +} + +func TestCheckAuthorization_InvalidToken(t *testing.T) { + t.Parallel() + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + // Completely invalid JWT string that cannot be parsed. + invalidToken := "not-a-valid-jwt" + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "action", invalidToken, + ) + + require.Error(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusInternalServerError, statusCode) +} + +func TestCheckAuthorization_EmptyTypeClaim_TreatedAsNonNormalUser(t *testing.T) { + t.Parallel() + + // When the "type" claim is empty or absent, userType != normalUser, + // so the code takes the admin/ branch. + var capturedBody map[string]string + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := json.NewDecoder(r.Body).Decode(&capturedBody) + if err != nil { + t.Errorf("mock server: failed to decode request body: %v", err) + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + + resp := AuthResponse{Authorized: true} + + encErr := json.NewEncoder(w).Encode(resp) + if encErr != nil { + t.Errorf("mock server: failed to encode response: %v", encErr) + } + })) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + // No "type" claim at all -> defaults to empty string -> non-normal-user path + token := createTestJWT(jwt.MapClaims{ + "sub": "some-app", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "some-app", "resource", "action", token, + ) + + require.NoError(t, err) + assert.True(t, authorized) + assert.Equal(t, http.StatusOK, statusCode) + assert.Equal(t, "admin/some-app-editor-role", capturedBody["sub"]) +} + +func TestCheckAuthorization_MockServerDown(t *testing.T) { + t.Parallel() + + // Use a server and immediately close it to simulate a connection failure. + server := mockAuthServer(t, true, http.StatusOK) + server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org1", + "sub": "user1", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "read", token, + ) + + require.Error(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusInternalServerError, statusCode) + assert.Contains(t, err.Error(), "failed to make request") +} + +func TestCheckAuthorization_ServerReturnsInvalidJSON(t *testing.T) { + t.Parallel() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + // Write invalid JSON + _, _ = w.Write([]byte("not-json")) + })) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org1", + "sub": "user1", + }) + + authorized, statusCode, err := auth.checkAuthorization( + context.Background(), "sub", "resource", "read", token, + ) + + require.Error(t, err) + assert.False(t, authorized) + assert.Equal(t, http.StatusInternalServerError, statusCode) + assert.Contains(t, err.Error(), "failed to unmarshal") +} + +// --------------------------------------------------------------------------- +// AuthResponse JSON serialization +// --------------------------------------------------------------------------- + +func TestAuthResponse_JSONRoundTrip(t *testing.T) { + t.Parallel() + + original := AuthResponse{Authorized: true} + + data, err := json.Marshal(original) + require.NoError(t, err) + + var decoded AuthResponse + err = json.Unmarshal(data, &decoded) + require.NoError(t, err) + + assert.Equal(t, original.Authorized, decoded.Authorized) +} diff --git a/go.mod b/go.mod index 069e9c0..56ad4d5 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,14 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.23.2 - -toolchain go1.23.3 +go 1.24.0 require ( github.com/LerianStudio/lib-commons/v2 v2.7.0-beta.3 github.com/gofiber/fiber/v2 v2.52.9 github.com/golang-jwt/jwt/v5 v5.3.0 - go.opentelemetry.io/otel v1.37.0 + github.com/stretchr/testify v1.11.1 + go.opentelemetry.io/otel v1.38.0 + google.golang.org/grpc v1.76.0 ) require github.com/google/uuid v1.6.0 // indirect @@ -17,10 +17,11 @@ require ( github.com/Masterminds/squirrel v1.5.4 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.18.0 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect @@ -29,34 +30,36 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/sony/gobreaker v1.0.0 // indirect github.com/tklauser/go-sysconf v0.3.15 // indirect github.com/tklauser/numcpus v0.10.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect - github.com/valyala/fasthttp v1.64.0 // indirect + github.com/valyala/fasthttp v1.67.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect - go.opentelemetry.io/auto/sdk v1.1.0 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.37.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.37.0 // indirect + go.opentelemetry.io/auto/sdk v1.2.1 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 // indirect + go.opentelemetry.io/otel/log v0.14.0 // indirect + go.opentelemetry.io/otel/metric v1.38.0 // indirect + go.opentelemetry.io/otel/sdk v1.38.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.14.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.38.0 // indirect + go.opentelemetry.io/otel/trace v1.38.0 // indirect go.opentelemetry.io/proto/otlp v1.7.1 // indirect - go.uber.org/mock v0.5.2 // indirect + go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/grpc v1.74.2 // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/net v0.47.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect + google.golang.org/protobuf v1.36.10 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index d71cef3..efdd84e 100644 --- a/go.sum +++ b/go.sum @@ -1,11 +1,12 @@ -github.com/LerianStudio/lib-commons/v2 v2.2.0 h1:pAyerAucWl42gvVUdGpBdUDRBUvNAk7OhtGZxyJ25aE= -github.com/LerianStudio/lib-commons/v2 v2.2.0/go.mod h1:6esN/Ao/Xkp/QwvYt8wXQNMgrhb3exOstKUIPuSUBDM= +github.com/LerianStudio/lib-commons/v2 v2.7.0-beta.3 h1:13Y37Ed0xDd4UMks3Ag6nbBzakz6vxu2XLMkPUPVo1M= +github.com/LerianStudio/lib-commons/v2 v2.7.0-beta.3/go.mod h1:p3gWgBPt9NSKMmRstYtlWOV1BkcSe6yFpdb1i+/NdrQ= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -27,12 +28,16 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1 h1:X5VWvz21y3gzm9Nw/kaUeku/1+uBhcekkmy4IkffJww= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.1/go.mod h1:Zanoh4+gvIgluNqcfMVTJueD4wSS5hT7zTt4Mrutd90= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3 h1:NmZ1PKzSTQbuGHw9DGPFomqkkLWMC+vZCkfs+FHv1Vg= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.3/go.mod h1:zQrxl1YP88HQlA6i9c63DSVPFklWpGX4OWAc9bFuaH4= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= @@ -51,79 +56,90 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= +github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4= github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4= github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso= github.com/tklauser/numcpus v0.10.0/go.mod h1:BiTKazU708GQTYF4mB+cmlpT2Is1gLk7XVuEeem8LsQ= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.64.0 h1:QBygLLQmiAyiXuRhthf0tuRkqAFcrC42dckN2S+N3og= -github.com/valyala/fasthttp v1.64.0/go.mod h1:dGmFxwkWXSK0NbOSJuF7AMVzU+lkHz0wQVvVITv2UQA= +github.com/valyala/fasthttp v1.67.0 h1:tqKlJMUP6iuNG8hGjK/s9J4kadH7HLV4ijEcPGsezac= +github.com/valyala/fasthttp v1.67.0/go.mod h1:qYSIpqt/0XNmShgo/8Aq8E3UYWVVwNS2QYmzd8WIEPM= github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU= github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E= github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 h1:FGre0nZh5BSw7G73VpT3xs38HchsfPsa2aZtMp0NPOs= -go.opentelemetry.io/contrib/bridges/otelzap v0.12.0/go.mod h1:X2PYPViI2wTPIMIOBjG17KNybTzsrATnvPJ02kkz7LM= -go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= -go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 h1:z6lNIajgEBVtQZHjfw2hAccPEBDs+nx58VemmXWa2ec= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0/go.mod h1:+kyc3bRx/Qkq05P6OCu3mTEIOxYRYzoIg+JsUp5X+PM= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 h1:zG8GlgXCJQd5BU98C0hZnBbElszTmUgCNCfYneaDL0A= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0/go.mod h1:hOfBCz8kv/wuq73Mx2H2QnWokh/kHZxkh6SNF2bdKtw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 h1:Ahq7pZmv87yiyn3jeFz/LekZmPLLdKejuO3NcK9MssM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0/go.mod h1:MJTqhM0im3mRLw1i8uGHnCvUEeS7VwRyxlLC78PA18M= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 h1:EtFWSnwW9hGObjkIdmlnWSydO+Qs8OwzfzXLUPg4xOc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0/go.mod h1:QjUEoiGCPkvFZ/MjK6ZZfNOS6mfVEVKYE99dFhuN2LI= -go.opentelemetry.io/otel/log v0.13.0 h1:yoxRoIZcohB6Xf0lNv9QIyCzQvrtGZklVbdCoyb7dls= -go.opentelemetry.io/otel/log v0.13.0/go.mod h1:INKfG4k1O9CL25BaM1qLe0zIedOpvlS5Z7XgSbmN83E= -go.opentelemetry.io/otel/log/logtest v0.13.0 h1:xxaIcgoEEtnwdgj6D6Uo9K/Dynz9jqIxSDu2YObJ69Q= -go.opentelemetry.io/otel/log/logtest v0.13.0/go.mod h1:+OrkmsAH38b+ygyag1tLjSFMYiES5UHggzrtY1IIEA8= -go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= -go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= -go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= -go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= -go.opentelemetry.io/otel/sdk/log v0.13.0 h1:I3CGUszjM926OphK8ZdzF+kLqFvfRY/IIoFq/TjwfaQ= -go.opentelemetry.io/otel/sdk/log v0.13.0/go.mod h1:lOrQyCCXmpZdN7NchXb6DOZZa1N5G1R2tm5GMMTpDBw= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0 h1:9yio6AFZ3QD9j9oqshV1Ibm9gPLlHNxurno5BreMtIA= -go.opentelemetry.io/otel/sdk/log/logtest v0.13.0/go.mod h1:QOGiAJHl+fob8Nu85ifXfuQYmJTFAvcrxL6w5/tu168= -go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= -go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= -go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= -go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= +go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= +go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= +go.opentelemetry.io/contrib/bridges/otelzap v0.13.0 h1:aBKdhLVieqvwWe9A79UHI/0vgp2t/s2euY8X59pGRlw= +go.opentelemetry.io/contrib/bridges/otelzap v0.13.0/go.mod h1:SYqtxLQE7iINgh6WFuVi2AI70148B8EI35DSk0Wr8m4= +go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= +go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0 h1:OMqPldHt79PqWKOMYIAQs3CxAi7RLgPxwfFSwr4ZxtM= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.14.0/go.mod h1:1biG4qiqTxKiUCtoWDPpL3fB3KxVwCiGw81j3nKMuHE= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0 h1:vl9obrcoWVKp/lwl8tRE33853I8Xru9HFbw/skNeLs8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.38.0/go.mod h1:GAXRxmLJcVM3u22IjTg74zWBrRCKq8BnOqUVLodpcpw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0 h1:GqRJVj7UmLjCVyVJ3ZFLdPRmhDUp2zFmQe3RHIOsw24= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.38.0/go.mod h1:ri3aaHSmCTVYu2AWv44YMauwAQc0aqI9gHKIcSbI1pU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0 h1:lwI4Dc5leUqENgGuQImwLo4WnuXFPetmPpkLi2IrX54= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.38.0/go.mod h1:Kz/oCE7z5wuyhPxsXDuaPteSWqjSBD5YaSdbxZYGbGk= +go.opentelemetry.io/otel/log v0.14.0 h1:2rzJ+pOAZ8qmZ3DDHg73NEKzSZkhkGIua9gXtxNGgrM= +go.opentelemetry.io/otel/log v0.14.0/go.mod h1:5jRG92fEAgx0SU/vFPxmJvhIuDU9E1SUnEQrMlJpOno= +go.opentelemetry.io/otel/log/logtest v0.14.0 h1:BGTqNeluJDK2uIHAY8lRqxjVAYfqgcaTbVk1n3MWe5A= +go.opentelemetry.io/otel/log/logtest v0.14.0/go.mod h1:IuguGt8XVP4XA4d2oEEDMVDBBCesMg8/tSGWDjuKfoA= +go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= +go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= +go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E= +go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg= +go.opentelemetry.io/otel/sdk/log v0.14.0 h1:JU/U3O7N6fsAXj0+CXz21Czg532dW2V4gG1HE/e8Zrg= +go.opentelemetry.io/otel/sdk/log v0.14.0/go.mod h1:imQvII+0ZylXfKU7/wtOND8Hn4OpT3YUoIgqJVksUkM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= +go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= +go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM= +go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA= +go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= +go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4= go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.5.2 h1:LbtPTcP8A5k9WPXj54PPPbjcI4Y6lhyOZXn+VS7wNko= -go.uber.org/mock v0.5.2/go.mod h1:wLlUxC2vVTPTaE3UD51E0BGOAElKrILxhVSDYQLld5o= +go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y= +go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= +go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b h1:ULiyYQ0FdsJhwwZUwbaXpZF5yUE3h+RA+gxvBu37ucc= -google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:oDOGiMSXHL4sDTJvFvIB9nRQCGdLP1o/iVaqQK8zB+M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b h1:zPKJod4w6F1+nRGDI9ubnXYhU9NSWoFAijkHkUXeTK8= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= -google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8 h1:mepRgnBZa07I4TRuomDE4sTIYieg/osKmzIf4USdWS4= +google.golang.org/genproto/googleapis/api v0.0.0-20251022142026-3a174f9686a8/go.mod h1:fDMmzKV90WSg1NbozdqrE64fkuTv6mlq2zxo9ad+3yo= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 h1:tRPGkdGHuewF4UisLzzHHr1spKw92qLM98nIzxbC0wY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk= +google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A= +google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c= +google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE= +google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From f4dae96c438554ca65c8fff5336c45410cb9d67d Mon Sep 17 00:00:00 2001 From: Brecci Date: Thu, 26 Feb 2026 16:55:23 -0300 Subject: [PATCH 19/34] feat: make gRPC interceptor tenant-aware with streaming support - Add extractTenantClaims to parse tenantId/tenantSlug/owner from JWT - Propagate tenant metadata (md-tenant-id, md-tenant-slug, md-tenant-owner) in unary interceptor when MULTI_TENANT_ENABLED=true - Add NewGRPCAuthStreamPolicy streaming interceptor mirroring unary behavior - Add wrappedServerStream to override context for streaming calls - Add tests for extraction, propagation, and streaming interceptor Co-Authored-By: Claude Opus 4.6 --- auth/middleware/middlewareGRPC.go | 125 +++++++++ auth/middleware/middlewareGRPC_test.go | 369 +++++++++++++++++++++++++ 2 files changed, 494 insertions(+) diff --git a/auth/middleware/middlewareGRPC.go b/auth/middleware/middlewareGRPC.go index bd0b91d..43f612a 100644 --- a/auth/middleware/middlewareGRPC.go +++ b/auth/middleware/middlewareGRPC.go @@ -2,12 +2,15 @@ package middleware import ( "context" + "errors" "fmt" "net/http" + "os" "strings" "github.com/LerianStudio/lib-commons/v2/commons" "github.com/LerianStudio/lib-commons/v2/commons/opentelemetry" + jwt "github.com/golang-jwt/jwt/v5" "go.opentelemetry.io/otel/attribute" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -97,6 +100,27 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer return nil, status.Error(codes.PermissionDenied, "forbidden") } + // Propagate tenant claims if multi-tenant mode is enabled + if os.Getenv("MULTI_TENANT_ENABLED") == "true" { + tenantID, tenantSlug, tOwner, _ := extractTenantClaims(token) + md, _ := metadata.FromIncomingContext(ctx) + md = md.Copy() + + if tenantID != "" { + md.Set("md-tenant-id", tenantID) + } + + if tenantSlug != "" { + md.Set("md-tenant-slug", tenantSlug) + } + + if tOwner != "" { + md.Set("md-tenant-owner", tOwner) + } + + ctx = metadata.NewIncomingContext(ctx, md) + } + return handler(ctx, req) } } @@ -179,3 +203,104 @@ func SubFromMetadata(key string) func(ctx context.Context, fullMethod string, re return vals[0], nil } } + +// extractTenantClaims extracts tenant-related claims from a JWT without signature verification. +// Returns tenantID, tenantSlug, and owner from the token's custom claims. +// Used by gRPC interceptors to propagate tenant context to downstream services. +func extractTenantClaims(tokenString string) (tenantID, tenantSlug, owner string, err error) { + token, _, err := new(jwt.Parser).ParseUnverified(tokenString, jwt.MapClaims{}) + if err != nil { + return "", "", "", err + } + + claims, ok := token.Claims.(jwt.MapClaims) + if !ok { + return "", "", "", errors.New("invalid token claims") + } + + tenantID, _ = claims["tenantId"].(string) + tenantSlug, _ = claims["tenantSlug"].(string) + owner, _ = claims["owner"].(string) + + return tenantID, tenantSlug, owner, nil +} + +// NewGRPCAuthStreamPolicy authorizes streaming RPCs via per-method Policy. +// Mirrors NewGRPCAuthUnaryPolicy behavior for streaming calls: +// - Resolves Policy by info.FullMethod; falls back to DefaultPolicy. +// - Rejects missing tokens with codes.Unauthenticated. +// - Propagates tenant claims when MULTI_TENANT_ENABLED=true. +func NewGRPCAuthStreamPolicy(auth *AuthClient, cfg PolicyConfig) grpc.StreamServerInterceptor { + return func(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + if auth == nil || !auth.Enabled || auth.Address == "" { + return handler(srv, ss) + } + + ctx := ss.Context() + token, ok := extractTokenFromMD(ctx) + + if !ok || commons.IsNilOrEmpty(&token) { + return status.Error(codes.Unauthenticated, "missing token") + } + + pol, found := policyForMethod(cfg, info.FullMethod) + if !found { + return status.Error(codes.Internal, "internal configuration error") + } + + var sub string + + if cfg.SubResolver != nil { + var err error + + sub, err = cfg.SubResolver(ctx, info.FullMethod, nil) + if err != nil { + return status.Error(codes.Internal, "internal configuration error") + } + } + + authorized, httpStatus, err := auth.checkAuthorization(ctx, sub, pol.Resource, pol.Action, token) + if err != nil { + return grpcErrorFromHTTP(httpStatus) + } + + if !authorized { + return status.Error(codes.PermissionDenied, "forbidden") + } + + // Propagate tenant claims if multi-tenant mode is enabled + if os.Getenv("MULTI_TENANT_ENABLED") == "true" { + tenantID, tenantSlug, tOwner, _ := extractTenantClaims(token) + md, _ := metadata.FromIncomingContext(ctx) + md = md.Copy() + + if tenantID != "" { + md.Set("md-tenant-id", tenantID) + } + + if tenantSlug != "" { + md.Set("md-tenant-slug", tenantSlug) + } + + if tOwner != "" { + md.Set("md-tenant-owner", tOwner) + } + + ctx = metadata.NewIncomingContext(ctx, md) + ss = &wrappedServerStream{ServerStream: ss, ctx: ctx} + } + + return handler(srv, ss) + } +} + +// wrappedServerStream wraps grpc.ServerStream to override Context(). +type wrappedServerStream struct { + grpc.ServerStream + ctx context.Context +} + +// Context returns the wrapped context. +func (w *wrappedServerStream) Context() context.Context { + return w.ctx +} diff --git a/auth/middleware/middlewareGRPC_test.go b/auth/middleware/middlewareGRPC_test.go index ff90515..e092375 100644 --- a/auth/middleware/middlewareGRPC_test.go +++ b/auth/middleware/middlewareGRPC_test.go @@ -5,6 +5,7 @@ import ( "net/http" "testing" + jwt "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "google.golang.org/grpc" @@ -556,3 +557,371 @@ func TestNewGRPCAuthUnaryPolicy(t *testing.T) { // Prevent compiler from optimizing away the handlerCalled variable _ = handlerCalled } + +// --------------------------------------------------------------------------- +// extractTenantClaims +// --------------------------------------------------------------------------- + +func Test_extractTenantClaims(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + tokenString string + wantTenantID string + wantTenantSlug string + wantOwner string + wantErr bool + }{ + { + name: "valid_jwt_with_all_tenant_claims", + tokenString: createTestJWT(jwt.MapClaims{ + "tenantId": "tid-123", + "tenantSlug": "acme-corp", + "owner": "owner-456", + }), + wantTenantID: "tid-123", + wantTenantSlug: "acme-corp", + wantOwner: "owner-456", + wantErr: false, + }, + { + name: "jwt_with_only_owner", + tokenString: createTestJWT(jwt.MapClaims{ + "owner": "owner-only", + }), + wantTenantID: "", + wantTenantSlug: "", + wantOwner: "owner-only", + wantErr: false, + }, + { + name: "jwt_with_only_tenantId", + tokenString: createTestJWT(jwt.MapClaims{ + "tenantId": "tid-only", + }), + wantTenantID: "tid-only", + wantTenantSlug: "", + wantOwner: "", + wantErr: false, + }, + { + name: "invalid_token", + tokenString: "not.a.valid.jwt", + wantTenantID: "", + wantTenantSlug: "", + wantOwner: "", + wantErr: true, + }, + { + name: "empty_token", + tokenString: "", + wantTenantID: "", + wantTenantSlug: "", + wantOwner: "", + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + tenantID, tenantSlug, owner, err := extractTenantClaims(tt.tokenString) + + if tt.wantErr { + require.Error(t, err) + } else { + require.NoError(t, err) + } + + assert.Equal(t, tt.wantTenantID, tenantID) + assert.Equal(t, tt.wantTenantSlug, tenantSlug) + assert.Equal(t, tt.wantOwner, owner) + }) + } +} + +// --------------------------------------------------------------------------- +// NewGRPCAuthUnaryPolicy - tenant propagation +// --------------------------------------------------------------------------- + +func TestNewGRPCAuthUnaryPolicy_TenantPropagation(t *testing.T) { + // Cannot use t.Parallel() because subtests use t.Setenv which modifies process env. + + t.Run("multi_tenant_enabled_propagates_tenant_metadata", func(t *testing.T) { + t.Setenv("MULTI_TENANT_ENABLED", "true") + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org-owner", + "sub": "user1", + "tenantId": "tid-100", + "tenantSlug": "acme", + }) + + defaultPol := Policy{Resource: "res", Action: "read"} + cfg := PolicyConfig{DefaultPolicy: &defaultPol} + interceptor := NewGRPCAuthUnaryPolicy(auth, cfg) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer "+token), + ) + + var capturedCtx context.Context + + handler := func(ctx context.Context, _ any) (any, error) { + capturedCtx = ctx + return "ok", nil + } + + info := &grpc.UnaryServerInfo{FullMethod: "/pkg.Service/DoThing"} + + resp, err := interceptor(ctx, "req", info, handler) + require.NoError(t, err) + assert.Equal(t, "ok", resp) + + // Verify tenant metadata was propagated + md, ok := metadata.FromIncomingContext(capturedCtx) + require.True(t, ok) + assert.Equal(t, []string{"tid-100"}, md.Get("md-tenant-id")) + assert.Equal(t, []string{"acme"}, md.Get("md-tenant-slug")) + assert.Equal(t, []string{"org-owner"}, md.Get("md-tenant-owner")) + }) + + t.Run("multi_tenant_disabled_no_tenant_metadata", func(t *testing.T) { + t.Setenv("MULTI_TENANT_ENABLED", "false") + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "org-owner", + "sub": "user1", + "tenantId": "tid-100", + "tenantSlug": "acme", + }) + + defaultPol := Policy{Resource: "res", Action: "read"} + cfg := PolicyConfig{DefaultPolicy: &defaultPol} + interceptor := NewGRPCAuthUnaryPolicy(auth, cfg) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer "+token), + ) + + var capturedCtx context.Context + + handler := func(ctx context.Context, _ any) (any, error) { + capturedCtx = ctx + return "ok", nil + } + + info := &grpc.UnaryServerInfo{FullMethod: "/pkg.Service/DoThing"} + + resp, err := interceptor(ctx, "req", info, handler) + require.NoError(t, err) + assert.Equal(t, "ok", resp) + + // Verify no tenant metadata was added + md, ok := metadata.FromIncomingContext(capturedCtx) + require.True(t, ok) + assert.Empty(t, md.Get("md-tenant-id")) + assert.Empty(t, md.Get("md-tenant-slug")) + assert.Empty(t, md.Get("md-tenant-owner")) + }) +} + +// --------------------------------------------------------------------------- +// NewGRPCAuthStreamPolicy +// --------------------------------------------------------------------------- + +// fakeServerStream is a minimal grpc.ServerStream for testing. +type fakeServerStream struct { + grpc.ServerStream + ctx context.Context +} + +func (f *fakeServerStream) Context() context.Context { + return f.ctx +} + +func TestNewGRPCAuthStreamPolicy(t *testing.T) { + // Cannot use t.Parallel() because a subtest uses t.Setenv which modifies process env. + + dummyInfo := &grpc.StreamServerInfo{ + FullMethod: "/pkg.Service/StreamThing", + } + + t.Run("auth_disabled_passes_through", func(t *testing.T) { + t.Parallel() + + called := false + + handler := func(_ any, _ grpc.ServerStream) error { + called = true + return nil + } + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: false} + interceptor := NewGRPCAuthStreamPolicy(auth, PolicyConfig{}) + + ss := &fakeServerStream{ctx: context.Background()} + + err := interceptor(nil, ss, dummyInfo, handler) + require.NoError(t, err) + assert.True(t, called) + }) + + t.Run("auth_nil_passes_through", func(t *testing.T) { + t.Parallel() + + called := false + + handler := func(_ any, _ grpc.ServerStream) error { + called = true + return nil + } + + interceptor := NewGRPCAuthStreamPolicy(nil, PolicyConfig{}) + + ss := &fakeServerStream{ctx: context.Background()} + + err := interceptor(nil, ss, dummyInfo, handler) + require.NoError(t, err) + assert.True(t, called) + }) + + t.Run("missing_token_returns_unauthenticated", func(t *testing.T) { + t.Parallel() + + handler := func(_ any, _ grpc.ServerStream) error { + return nil + } + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: true} + interceptor := NewGRPCAuthStreamPolicy(auth, PolicyConfig{}) + + // Context without any metadata -> no token + ss := &fakeServerStream{ctx: context.Background()} + + err := interceptor(nil, ss, dummyInfo, handler) + require.Error(t, err) + + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Unauthenticated, st.Code()) + assert.Contains(t, st.Message(), "missing token") + }) + + t.Run("no_policy_for_method_returns_internal", func(t *testing.T) { + t.Parallel() + + handler := func(_ any, _ grpc.ServerStream) error { + return nil + } + + auth := &AuthClient{Address: "http://localhost:9999", Enabled: true} + cfg := PolicyConfig{ + MethodPolicies: map[string]Policy{ + "/pkg.Service/OtherMethod": {Resource: "other", Action: "read"}, + }, + // No DefaultPolicy + } + interceptor := NewGRPCAuthStreamPolicy(auth, cfg) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer valid-token"), + ) + ss := &fakeServerStream{ctx: ctx} + + err := interceptor(nil, ss, dummyInfo, handler) + require.Error(t, err) + + st, ok := status.FromError(err) + require.True(t, ok) + assert.Equal(t, codes.Internal, st.Code()) + assert.Contains(t, st.Message(), "internal configuration error") + }) + + t.Run("multi_tenant_enabled_propagates_tenant_metadata_in_stream", func(t *testing.T) { + t.Setenv("MULTI_TENANT_ENABLED", "true") + + server := mockAuthServer(t, true, http.StatusOK) + defer server.Close() + + auth := &AuthClient{ + Address: server.URL, + Enabled: true, + Logger: &testLogger{}, + } + + token := createTestJWT(jwt.MapClaims{ + "type": "normal-user", + "owner": "stream-owner", + "sub": "user1", + "tenantId": "tid-stream", + "tenantSlug": "stream-org", + }) + + defaultPol := Policy{Resource: "res", Action: "read"} + cfg := PolicyConfig{DefaultPolicy: &defaultPol} + interceptor := NewGRPCAuthStreamPolicy(auth, cfg) + + ctx := metadata.NewIncomingContext( + context.Background(), + metadata.Pairs("authorization", "Bearer "+token), + ) + ss := &fakeServerStream{ctx: ctx} + + var capturedStream grpc.ServerStream + + handler := func(_ any, ss grpc.ServerStream) error { + capturedStream = ss + return nil + } + + err := interceptor(nil, ss, dummyInfo, handler) + require.NoError(t, err) + + // Verify tenant metadata was propagated via the wrapped stream context + md, ok := metadata.FromIncomingContext(capturedStream.Context()) + require.True(t, ok) + assert.Equal(t, []string{"tid-stream"}, md.Get("md-tenant-id")) + assert.Equal(t, []string{"stream-org"}, md.Get("md-tenant-slug")) + assert.Equal(t, []string{"stream-owner"}, md.Get("md-tenant-owner")) + }) +} + +// --------------------------------------------------------------------------- +// wrappedServerStream +// --------------------------------------------------------------------------- + +func TestWrappedServerStream_Context(t *testing.T) { + t.Parallel() + + ctx := context.WithValue(context.Background(), struct{}{}, "test-value") //nolint:staticcheck // test-only context key + inner := &fakeServerStream{ctx: context.Background()} + wrapped := &wrappedServerStream{ServerStream: inner, ctx: ctx} + + assert.Equal(t, ctx, wrapped.Context()) + assert.NotEqual(t, inner.Context(), wrapped.Context()) +} From 805aadb8ff2f1a6a8547733eeaf2618220511ee7 Mon Sep 17 00:00:00 2001 From: Brecci Date: Thu, 26 Feb 2026 17:45:30 -0300 Subject: [PATCH 20/34] fix: replace deprecated commons API calls Replace NewTracerFromContext + NewHeaderIDFromContext with the unified NewTrackingFromContext across HTTP and gRPC middleware. X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 9 +++------ auth/middleware/middlewareGRPC.go | 3 +-- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 7689149..2be9718 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -112,8 +112,7 @@ func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler { return func(c *fiber.Ctx) error { ctx := opentelemetry.ExtractHTTPContext(c) - tracer := commons.NewTracerFromContext(ctx) - reqID := commons.NewHeaderIDFromContext(ctx) + _, tracer, reqID, _ := commons.NewTrackingFromContext(ctx) if !auth.Enabled || auth.Address == "" { return c.Next() @@ -158,8 +157,7 @@ func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler { // checkAuthorization sends an authorization request to the external service and returns whether the action is authorized. func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, action, accessToken string) (bool, int, error) { - tracer := commons.NewTracerFromContext(ctx) - reqID := commons.NewHeaderIDFromContext(ctx) + _, tracer, reqID, _ := commons.NewTrackingFromContext(ctx) ctx, span := tracer.Start(ctx, "lib_auth.check_authorization") defer span.End() @@ -298,8 +296,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a // It takes the client ID and client secret as parameters and returns the access token if the request is successful. // If the request fails at any step, an error is returned with a descriptive message. func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clientSecret string) (string, error) { - tracer := commons.NewTracerFromContext(ctx) - reqID := commons.NewHeaderIDFromContext(ctx) + _, tracer, reqID, _ := commons.NewTrackingFromContext(ctx) ctx, span := tracer.Start(ctx, "lib_auth.get_application_token") defer span.End() diff --git a/auth/middleware/middlewareGRPC.go b/auth/middleware/middlewareGRPC.go index 43f612a..705f0ba 100644 --- a/auth/middleware/middlewareGRPC.go +++ b/auth/middleware/middlewareGRPC.go @@ -50,8 +50,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer } token, ok := extractTokenFromMD(ctx) - tracer := commons.NewTracerFromContext(ctx) - reqID := commons.NewHeaderIDFromContext(ctx) + _, tracer, reqID, _ := commons.NewTrackingFromContext(ctx) ctx, span := tracer.Start(ctx, "lib_auth.authorize_grpc_unary_policy") defer span.End() From 4b6b5c55dd052a1e20cd32a81a66563a6ec545e4 Mon Sep 17 00:00:00 2001 From: Brecci Date: Fri, 27 Feb 2026 13:04:54 -0300 Subject: [PATCH 21/34] chore: fix lint issues --- auth/middleware/middleware.go | 8 +- auth/middleware/middleware_test.go | 36 ++++----- go.mod | 63 ++++++++-------- go.sum | 115 +++++++++++++++-------------- 4 files changed, 119 insertions(+), 103 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index a521713..e0d22e8 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -51,11 +51,17 @@ const ( // If the service is healthy, it logs a successful connection message; otherwise, it logs the failure reason. func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient { var l log.Logger + var err error if logger != nil { l = *logger } else { - l = zap.InitializeLogger() + l, err = zap.InitializeLoggerWithError() + if err != nil { + err = fmt.Errorf("failed to initialize logger: %w", err) + + l = &log.NoneLogger{} + } } if !enabled || address == "" { diff --git a/auth/middleware/middleware_test.go b/auth/middleware/middleware_test.go index 460310b..ea6ddec 100644 --- a/auth/middleware/middleware_test.go +++ b/auth/middleware/middleware_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/LerianStudio/lib-commons/v2/commons/log" + "github.com/LerianStudio/lib-commons/v3/commons/log" jwt "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -51,24 +51,24 @@ func mockAuthServer(t *testing.T, authorized bool, statusCode int) *httptest.Ser // testLogger is a minimal log.Logger implementation for tests that discards all output. type testLogger struct{} -func (l *testLogger) Info(_ ...any) {} -func (l *testLogger) Infof(_ string, _ ...any) {} -func (l *testLogger) Infoln(_ ...any) {} -func (l *testLogger) Error(_ ...any) {} -func (l *testLogger) Errorf(_ string, _ ...any) {} -func (l *testLogger) Errorln(_ ...any) {} -func (l *testLogger) Warn(_ ...any) {} -func (l *testLogger) Warnf(_ string, _ ...any) {} -func (l *testLogger) Warnln(_ ...any) {} -func (l *testLogger) Debug(_ ...any) {} -func (l *testLogger) Debugf(_ string, _ ...any) {} -func (l *testLogger) Debugln(_ ...any) {} -func (l *testLogger) Fatal(_ ...any) {} -func (l *testLogger) Fatalf(_ string, _ ...any) {} -func (l *testLogger) Fatalln(_ ...any) {} -func (l *testLogger) WithFields(_ ...any) log.Logger { return l } +func (l *testLogger) Info(_ ...any) {} +func (l *testLogger) Infof(_ string, _ ...any) {} +func (l *testLogger) Infoln(_ ...any) {} +func (l *testLogger) Error(_ ...any) {} +func (l *testLogger) Errorf(_ string, _ ...any) {} +func (l *testLogger) Errorln(_ ...any) {} +func (l *testLogger) Warn(_ ...any) {} +func (l *testLogger) Warnf(_ string, _ ...any) {} +func (l *testLogger) Warnln(_ ...any) {} +func (l *testLogger) Debug(_ ...any) {} +func (l *testLogger) Debugf(_ string, _ ...any) {} +func (l *testLogger) Debugln(_ ...any) {} +func (l *testLogger) Fatal(_ ...any) {} +func (l *testLogger) Fatalf(_ string, _ ...any) {} +func (l *testLogger) Fatalln(_ ...any) {} +func (l *testLogger) WithFields(_ ...any) log.Logger { return l } func (l *testLogger) WithDefaultMessageTemplate(_ string) log.Logger { return l } -func (l *testLogger) Sync() error { return nil } +func (l *testLogger) Sync() error { return nil } // --------------------------------------------------------------------------- // checkAuthorization - subject construction diff --git a/go.mod b/go.mod index 18badb7..20cbc00 100644 --- a/go.mod +++ b/go.mod @@ -1,13 +1,14 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.24.0 +go 1.25.0 require ( - github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2 - github.com/gofiber/fiber/v2 v2.52.11 - github.com/golang-jwt/jwt/v5 v5.3.0 - go.opentelemetry.io/otel v1.39.0 - google.golang.org/grpc v1.78.0 + github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8 + github.com/gofiber/fiber/v2 v2.52.12 + github.com/golang-jwt/jwt/v5 v5.3.1 + github.com/stretchr/testify v1.11.1 + go.opentelemetry.io/otel v1.40.0 + google.golang.org/grpc v1.79.1 ) require github.com/google/uuid v1.6.0 // indirect @@ -17,19 +18,20 @@ require ( github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/clipperhouse/stringish v0.1.1 // indirect - github.com/clipperhouse/uax29/v2 v2.3.0 // indirect + github.com/clipperhouse/uax29/v2 v2.7.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/joho/godotenv v1.5.1 // indirect - github.com/klauspost/compress v1.18.2 // indirect + github.com/klauspost/compress v1.18.4 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.19 // indirect + github.com/mattn/go-runewidth v0.0.20 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/sony/gobreaker v1.0.0 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect @@ -38,25 +40,26 @@ require ( github.com/valyala/fasthttp v1.69.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.12.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.13.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.37.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.37.0 // indirect - go.opentelemetry.io/otel/log v0.13.0 // indirect - go.opentelemetry.io/otel/metric v1.39.0 // indirect - go.opentelemetry.io/otel/sdk v1.37.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.13.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.37.0 // indirect - go.opentelemetry.io/otel/trace v1.39.0 // indirect - go.opentelemetry.io/proto/otlp v1.7.1 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.15.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect + go.opentelemetry.io/otel/log v0.16.0 // indirect + go.opentelemetry.io/otel/metric v1.40.0 // indirect + go.opentelemetry.io/otel/sdk v1.40.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.16.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect + go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.42.0 // indirect - golang.org/x/sys v0.34.0 // indirect - golang.org/x/text v0.27.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250804133106-a7a43d27e69b // indirect - google.golang.org/protobuf v1.36.6 // indirect + go.uber.org/zap v1.27.1 // indirect + golang.org/x/net v0.51.0 // indirect + golang.org/x/sys v0.41.0 // indirect + golang.org/x/text v0.34.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect + google.golang.org/protobuf v1.36.11 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e68b6c8..3e53a70 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2 h1:ykbnpOdjQtZ736A/SicvQVPylAihrgENtM5aJ29Bpus= -github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.2/go.mod h1:eegTRzYBTMBmXew279htSmBWX0n4syWT9iTDr2ZCwNo= +github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8 h1:zH/tQ+I1rUrPUB6wIUY3rJohFrp4CH7rXprMs6+RoPg= +github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8/go.mod h1:eegTRzYBTMBmXew279htSmBWX0n4syWT9iTDr2ZCwNo= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= @@ -8,10 +8,8 @@ github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1x github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= -github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= -github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= -github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= +github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= +github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -24,8 +22,8 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= -github.com/gofiber/fiber/v2 v2.52.11 h1:5f4yzKLcBcF8ha1GQTWB+mpblWz3Vz6nSAbTL31HkWs= -github.com/gofiber/fiber/v2 v2.52.11/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= +github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= +github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -34,12 +32,16 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4 h1:kEISI/Gx67NzH3nJxAmY/dGac80kKZgZt134u7Y/k1s= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.27.4/go.mod h1:6Nz966r3vQYCqIzWsuEl9d7cf7mRhtDmm++sOxlnfxI= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= -github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/klauspost/compress v1.18.4 h1:RPhnKRAQ4Fh8zU2FY/6ZFDwTVTxgJ/EMydqSTzE9a2c= +github.com/klauspost/compress v1.18.4/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= @@ -48,11 +50,13 @@ github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHP github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= -github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= +github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= +github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= @@ -76,34 +80,34 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/bridges/otelzap v0.14.0 h1:2nKw2ZXZOC0N8RBsBbYwGwfKR7kJWzzyCZ6QfUGW/es= -go.opentelemetry.io/contrib/bridges/otelzap v0.14.0/go.mod h1:kvyVt0WEI5BB6XaIStXPIkCSQ2nSkyd8IZnAHLEXge4= -go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48= -go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0 h1:W+m0g+/6v3pa5PgVf2xoFMi5YtNR06WtS7ve5pcvLtM= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.15.0/go.mod h1:JM31r0GGZ/GU94mX8hN4D8v6e40aFlUECSQ48HaLgHM= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0 h1:cEf8jF6WbuGQWUVcqgyWtTR0kOOAWY1DYZ+UhvdmQPw= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.39.0/go.mod h1:k1lzV5n5U3HkGvTCJHraTAGJ7MqsgL1wrGwTj1Isfiw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0 h1:f0cb2XPmrqn4XMy9PNliTgRKJgS5WcL/u0/WRYGz4t0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.39.0/go.mod h1:vnakAaFckOMiMtOIhFI2MNH4FYrZzXCYxmb1LlhoGz8= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0 h1:in9O8ESIOlwJAEGTkkf34DesGRAc/Pn8qJ7k3r/42LM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.39.0/go.mod h1:Rp0EXBm5tfnv0WL+ARyO/PHBEaEAT8UUHQ6AGJcSq6c= -go.opentelemetry.io/otel/log v0.15.0 h1:0VqVnc3MgyYd7QqNVIldC3dsLFKgazR6P3P3+ypkyDY= -go.opentelemetry.io/otel/log v0.15.0/go.mod h1:9c/G1zbyZfgu1HmQD7Qj84QMmwTp2QCQsZH1aeoWDE4= -go.opentelemetry.io/otel/log/logtest v0.15.0 h1:porNFuxAjodl6LhePevOc3n7bo3Wi3JhGXNWe7KP8iU= -go.opentelemetry.io/otel/log/logtest v0.15.0/go.mod h1:c8epqBXGHgS1LiNgmD+LuNYK9lSS3mqvtMdxLsfJgLg= -go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0= -go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs= -go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18= -go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE= -go.opentelemetry.io/otel/sdk/log v0.15.0 h1:WgMEHOUt5gjJE93yqfqJOkRflApNif84kxoHWS9VVHE= -go.opentelemetry.io/otel/sdk/log v0.15.0/go.mod h1:qDC/FlKQCXfH5hokGsNg9aUBGMJQsrUyeOiW5u+dKBQ= -go.opentelemetry.io/otel/sdk/log/logtest v0.14.0 h1:Ijbtz+JKXl8T2MngiwqBlPaHqc4YCaP/i13Qrow6gAM= -go.opentelemetry.io/otel/sdk/log/logtest v0.14.0/go.mod h1:dCU8aEL6q+L9cYTqcVOk8rM9Tp8WdnHOPLiBgp0SGOA= -go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8= -go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew= -go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI= -go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA= +go.opentelemetry.io/contrib/bridges/otelzap v0.15.0 h1:x4qzjKkTl2hXmLl+IviSXvzaTyCJSYvpFZL5SRVLBxs= +go.opentelemetry.io/contrib/bridges/otelzap v0.15.0/go.mod h1:h7dZHJgqkzUiKFXCTJBrPWH0LEZaZXBFzKWstjWBRxw= +go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= +go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= +go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4= +go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes= +go.opentelemetry.io/otel/log/logtest v0.16.0 h1:jr1CG3Z6FD9pwUaL/D0s0X4lY2ZVm1jP3JfCtzGxUmE= +go.opentelemetry.io/otel/log/logtest v0.16.0/go.mod h1:qeeZw+cI/rAtCzZ03Kq1ozq6C4z/PCa+K+bb0eJfKNs= +go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= +go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= +go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= +go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= +go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI= +go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4= +go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4= +go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y= +go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= +go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= +go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= +go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -114,24 +118,27 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= -golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= +golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= +golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= -golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= -golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= +golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= +golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= -google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3 h1:X9z6obt+cWRX8XjDVOn+SZWhWe5kZHm46TThU9j+jss= -google.golang.org/genproto/googleapis/api v0.0.0-20260114163908-3f89685c29c3/go.mod h1:dd646eSK+Dk9kxVBl1nChEOhJPtMXriCcVb4x3o6J+E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3 h1:C4WAdL+FbjnGlpp2S+HMVhBeCq2Lcib4xZqfPNF6OoQ= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260114163908-3f89685c29c3/go.mod h1:j9x/tPzZkyxcgEFkiKEEGxfvyumM01BEtsW8xzOahRQ= -google.golang.org/grpc v1.78.0 h1:K1XZG/yGDJnzMdd/uZHAkVqJE+xIDOcmdSFZkBUicNc= -google.golang.org/grpc v1.78.0/go.mod h1:I47qjTo4OKbMkjA/aOOwxDIiPSBofUtQUI5EfpWvW7U= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:tu/dtnW1o3wfaxCOjSLn5IRX4YDcJrtlpzYkhHhGaC4= +google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= +google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= +google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 78150e9e7ffcbbbf163731d3b8874e2f46b31ede Mon Sep 17 00:00:00 2001 From: Brecci Date: Fri, 27 Feb 2026 13:12:38 -0300 Subject: [PATCH 22/34] chore: fix lint issues with govet --- auth/middleware/middleware.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index e0d22e8..5111045 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -51,6 +51,7 @@ const ( // If the service is healthy, it logs a successful connection message; otherwise, it logs the failure reason. func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient { var l log.Logger + var err error if logger != nil { @@ -58,9 +59,9 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient } else { l, err = zap.InitializeLoggerWithError() if err != nil { - err = fmt.Errorf("failed to initialize logger: %w", err) - l = &log.NoneLogger{} + + l.Errorf("failed to initialize logger, using NoneLogger: %v\n", err) } } From 5b60e5f3bf490dbb67b97bb671b8a74419aa645a Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 27 Feb 2026 17:58:44 +0000 Subject: [PATCH 23/34] chore(release): 2.5.0-beta.6 ## [2.5.0-beta.6](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.5...v2.5.0-beta.6) (2026-02-27) ### Features * make gRPC interceptor tenant-aware with streaming support ([f4dae96](https://github.com/LerianStudio/lib-auth/commit/f4dae96c438554ca65c8fff5336c45410cb9d67d)) ### Bug Fixes * replace deprecated commons API calls ([805aadb](https://github.com/LerianStudio/lib-auth/commit/805aadb8ff2f1a6a8547733eeaf2618220511ee7)) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c1410..7c809a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [2.5.0-beta.6](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.5...v2.5.0-beta.6) (2026-02-27) + + +### Features + +* make gRPC interceptor tenant-aware with streaming support ([f4dae96](https://github.com/LerianStudio/lib-auth/commit/f4dae96c438554ca65c8fff5336c45410cb9d67d)) + + +### Bug Fixes + +* replace deprecated commons API calls ([805aadb](https://github.com/LerianStudio/lib-auth/commit/805aadb8ff2f1a6a8547733eeaf2618220511ee7)) + ## [2.5.0-beta.5](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.4...v2.5.0-beta.5) (2026-02-20) ## [2.5.0-beta.4](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.3...v2.5.0-beta.4) (2026-02-20) From a7c724a34b90d84e98880238a05816350ab5da2e Mon Sep 17 00:00:00 2001 From: Fred Amaral Date: Tue, 10 Mar 2026 16:07:02 -0300 Subject: [PATCH 24/34] chore(deps): upgrade lib-commons from v3 to v4 Replace lib-commons/v3 with v4.0.0 stable release. Updates transitive dependencies including OTel from 1.40.0 to 1.42.0, grpc from 1.79.1 to 1.79.2, and adds new transitive deps required by v4 (go-playground/validator, shopspring/decimal, gabriel-vasile/mimetype). Removes Masterminds/squirrel and lann/* which are no longer indirect requirements. X-Lerian-Ref: 0x1 --- go.mod | 42 +++++++++++++++------------ go.sum | 92 +++++++++++++++++++++++++++++++--------------------------- 2 files changed, 73 insertions(+), 61 deletions(-) diff --git a/go.mod b/go.mod index 20cbc00..df41dc3 100644 --- a/go.mod +++ b/go.mod @@ -1,38 +1,41 @@ module github.com/LerianStudio/lib-auth/v2 -go 1.25.0 +go 1.25.7 require ( - github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8 + github.com/LerianStudio/lib-commons/v4 v4.0.0 github.com/gofiber/fiber/v2 v2.52.12 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/stretchr/testify v1.11.1 - go.opentelemetry.io/otel v1.40.0 - google.golang.org/grpc v1.79.1 + go.opentelemetry.io/otel v1.42.0 + google.golang.org/grpc v1.79.2 ) require github.com/google/uuid v1.6.0 // indirect require ( - github.com/Masterminds/squirrel v1.5.4 // indirect github.com/andybalholm/brotli v1.2.0 // indirect github.com/cenkalti/backoff/v5 v5.0.3 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/clipperhouse/uax29/v2 v2.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/gabriel-vasile/mimetype v1.4.13 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect + github.com/go-playground/locales v0.14.1 // indirect + github.com/go-playground/universal-translator v0.18.1 // indirect + github.com/go-playground/validator/v10 v10.30.1 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 // indirect github.com/joho/godotenv v1.5.1 // indirect github.com/klauspost/compress v1.18.4 // indirect - github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect - github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect + github.com/leodido/go-urn v1.4.0 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mattn/go-runewidth v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.21 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sony/gobreaker v1.0.0 // indirect github.com/tklauser/go-sysconf v0.3.16 // indirect github.com/tklauser/numcpus v0.11.0 // indirect @@ -40,21 +43,22 @@ require ( github.com/valyala/fasthttp v1.69.0 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/bridges/otelzap v0.15.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 // indirect - go.opentelemetry.io/otel/log v0.16.0 // indirect - go.opentelemetry.io/otel/metric v1.40.0 // indirect - go.opentelemetry.io/otel/sdk v1.40.0 // indirect - go.opentelemetry.io/otel/sdk/log v0.16.0 // indirect - go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect - go.opentelemetry.io/otel/trace v1.40.0 // indirect + go.opentelemetry.io/contrib/bridges/otelzap v0.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 // indirect + go.opentelemetry.io/otel/log v0.18.0 // indirect + go.opentelemetry.io/otel/metric v1.42.0 // indirect + go.opentelemetry.io/otel/sdk v1.42.0 // indirect + go.opentelemetry.io/otel/sdk/log v0.18.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.42.0 // indirect + go.opentelemetry.io/otel/trace v1.42.0 // indirect go.opentelemetry.io/proto/otlp v1.9.0 // indirect go.uber.org/mock v0.6.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.1 // indirect + golang.org/x/crypto v0.48.0 // indirect golang.org/x/net v0.51.0 // indirect golang.org/x/sys v0.41.0 // indirect golang.org/x/text v0.34.0 // indirect diff --git a/go.sum b/go.sum index 3e53a70..000d0ce 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ -github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8 h1:zH/tQ+I1rUrPUB6wIUY3rJohFrp4CH7rXprMs6+RoPg= -github.com/LerianStudio/lib-commons/v3 v3.0.0-beta.8/go.mod h1:eegTRzYBTMBmXew279htSmBWX0n4syWT9iTDr2ZCwNo= -github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= -github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= +github.com/LerianStudio/lib-commons/v4 v4.0.0 h1:OEdpRKnbLoOhZoUZyI5FgIe7ZbwJzu/syfgpkDzyi3o= +github.com/LerianStudio/lib-commons/v4 v4.0.0/go.mod h1:WMQ17ouiJ13uUVhH/eY+p++4xb/NOtR44yIMGZ0r8Ow= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= @@ -11,9 +9,10 @@ github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk= github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM= +github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -22,6 +21,14 @@ github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= +github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= +github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= +github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.30.1 h1:f3zDSN/zOma+w6+1Wswgd9fLkdwy06ntQJp0BBvFG0w= +github.com/go-playground/validator/v10 v10.30.1/go.mod h1:oSuBIQzuJxL//3MelwSLD5hc2Tu889bF0Idm9Dg26cM= github.com/gofiber/fiber/v2 v2.52.12 h1:0LdToKclcPOj8PktUdIKo9BUohjjwfnQl42Dhw8/WUw= github.com/gofiber/fiber/v2 v2.52.12/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= @@ -42,16 +49,14 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw= -github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk= -github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw= +github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= +github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.20 h1:WcT52H91ZUAwy8+HUkdM3THM6gXqXuLJi9O3rjcQQaQ= -github.com/mattn/go-runewidth v0.0.20/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= +github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w= +github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -59,10 +64,11 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sony/gobreaker v1.0.0 h1:feX5fGGXSl3dYd4aHZItw+FpHLvvoaqkawKjVNiFMNQ= github.com/sony/gobreaker v1.0.0/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= @@ -80,34 +86,34 @@ github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/bridges/otelzap v0.15.0 h1:x4qzjKkTl2hXmLl+IviSXvzaTyCJSYvpFZL5SRVLBxs= -go.opentelemetry.io/contrib/bridges/otelzap v0.15.0/go.mod h1:h7dZHJgqkzUiKFXCTJBrPWH0LEZaZXBFzKWstjWBRxw= -go.opentelemetry.io/otel v1.40.0 h1:oA5YeOcpRTXq6NN7frwmwFR0Cn3RhTVZvXsP4duvCms= -go.opentelemetry.io/otel v1.40.0/go.mod h1:IMb+uXZUKkMXdPddhwAHm6UfOwJyh4ct1ybIlV14J0g= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0 h1:ZVg+kCXxd9LtAaQNKBxAvJ5NpMf7LpvEr4MIZqb0TMQ= -go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.16.0/go.mod h1:hh0tMeZ75CCXrHd9OXRYxTlCAdxcXioWHFIpYw2rZu8= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0 h1:NOyNnS19BF2SUDApbOKbDtWZ0IK7b8FJ2uAGdIWOGb0= -go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.40.0/go.mod h1:VL6EgVikRLcJa9ftukrHu/ZkkhFBSo1lzvdBC9CF1ss= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0 h1:DvJDOPmSWQHWywQS6lKL+pb8s3gBLOZUtw4N+mavW1I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.40.0/go.mod h1:EtekO9DEJb4/jRyN4v4Qjc2yA7AtfCBuz2FynRUWTXs= -go.opentelemetry.io/otel/log v0.16.0 h1:DeuBPqCi6pQwtCK0pO4fvMB5eBq6sNxEnuTs88pjsN4= -go.opentelemetry.io/otel/log v0.16.0/go.mod h1:rWsmqNVTLIA8UnwYVOItjyEZDbKIkMxdQunsIhpUMes= -go.opentelemetry.io/otel/log/logtest v0.16.0 h1:jr1CG3Z6FD9pwUaL/D0s0X4lY2ZVm1jP3JfCtzGxUmE= -go.opentelemetry.io/otel/log/logtest v0.16.0/go.mod h1:qeeZw+cI/rAtCzZ03Kq1ozq6C4z/PCa+K+bb0eJfKNs= -go.opentelemetry.io/otel/metric v1.40.0 h1:rcZe317KPftE2rstWIBitCdVp89A2HqjkxR3c11+p9g= -go.opentelemetry.io/otel/metric v1.40.0/go.mod h1:ib/crwQH7N3r5kfiBZQbwrTge743UDc7DTFVZrrXnqc= -go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8= -go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE= -go.opentelemetry.io/otel/sdk/log v0.16.0 h1:e/b4bdlQwC5fnGtG3dlXUrNOnP7c8YLVSpSfEBIkTnI= -go.opentelemetry.io/otel/sdk/log v0.16.0/go.mod h1:JKfP3T6ycy7QEuv3Hj8oKDy7KItrEkus8XJE6EoSzw4= -go.opentelemetry.io/otel/sdk/log/logtest v0.16.0 h1:/XVkpZ41rVRTP4DfMgYv1nEtNmf65XPPyAdqV90TMy4= -go.opentelemetry.io/otel/sdk/log/logtest v0.16.0/go.mod h1:iOOPgQr5MY9oac/F5W86mXdeyWZGleIx3uXO98X2R6Y= -go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw= -go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg= -go.opentelemetry.io/otel/trace v1.40.0 h1:WA4etStDttCSYuhwvEa8OP8I5EWu24lkOzp+ZYblVjw= -go.opentelemetry.io/otel/trace v1.40.0/go.mod h1:zeAhriXecNGP/s2SEG3+Y8X9ujcJOTqQ5RgdEJcawiA= +go.opentelemetry.io/contrib/bridges/otelzap v0.17.0 h1:oCltVHJcblcth2z9B9dRTeZIZTe2Sf9Ad9h8bcc+s8M= +go.opentelemetry.io/contrib/bridges/otelzap v0.17.0/go.mod h1:G/VE1A/hRn6mEWdfC8rMvSdQVGM64KUPi4XilLkwcQw= +go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho= +go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0 h1:deI9UQMoGFgrg5iLPgzueqFPHevDl+28YKfSpPTI6rY= +go.opentelemetry.io/otel/exporters/otlp/otlplog/otlploggrpc v0.18.0/go.mod h1:PFx9NgpNUKXdf7J4Q3agRxMs3Y07QhTCVipKmLsMKnU= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0 h1:MdKucPl/HbzckWWEisiNqMPhRrAOQX8r4jTuGr636gk= +go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.42.0/go.mod h1:RolT8tWtfHcjajEH5wFIZ4Dgh5jpPdFXYV9pTAk/qjc= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0 h1:THuZiwpQZuHPul65w4WcwEnkX2QIuMT+UFoOrygtoJw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.42.0/go.mod h1:J2pvYM5NGHofZ2/Ru6zw/TNWnEQp5crgyDeSrYpXkAw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0 h1:zWWrB1U6nqhS/k6zYB74CjRpuiitRtLLi68VcgmOEto= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.42.0/go.mod h1:2qXPNBX1OVRC0IwOnfo1ljoid+RD0QK3443EaqVlsOU= +go.opentelemetry.io/otel/log v0.18.0 h1:XgeQIIBjZZrliksMEbcwMZefoOSMI1hdjiLEiiB0bAg= +go.opentelemetry.io/otel/log v0.18.0/go.mod h1:KEV1kad0NofR3ycsiDH4Yjcoj0+8206I6Ox2QYFSNgI= +go.opentelemetry.io/otel/log/logtest v0.18.0 h1:2QeyoKJdIgK2LJhG1yn78o/zmpXx1EditeyRDREqVS8= +go.opentelemetry.io/otel/log/logtest v0.18.0/go.mod h1:v1vh3PYR9zIa5MK6HwkH2lMrLBg/Y9Of6Qc+krlesX0= +go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4= +go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI= +go.opentelemetry.io/otel/sdk v1.42.0 h1:LyC8+jqk6UJwdrI/8VydAq/hvkFKNHZVIWuslJXYsDo= +go.opentelemetry.io/otel/sdk v1.42.0/go.mod h1:rGHCAxd9DAph0joO4W6OPwxjNTYWghRWmkHuGbayMts= +go.opentelemetry.io/otel/sdk/log v0.18.0 h1:n8OyZr7t7otkeTnPTbDNom6rW16TBYGtvyy2Gk6buQw= +go.opentelemetry.io/otel/sdk/log v0.18.0/go.mod h1:C0+wxkTwKpOCZLrlJ3pewPiiQwpzycPI/u6W0Z9fuYk= +go.opentelemetry.io/otel/sdk/log/logtest v0.18.0 h1:l3mYuPsuBx6UKE47BVcPrZoZ0q/KER57vbj2qkgDLXA= +go.opentelemetry.io/otel/sdk/log/logtest v0.18.0/go.mod h1:7cHtiVJpZebB3wybTa4NG+FUo5NPe3PROz1FqB0+qdw= +go.opentelemetry.io/otel/sdk/metric v1.42.0 h1:D/1QR46Clz6ajyZ3G8SgNlTJKBdGp84q9RKCAZ3YGuA= +go.opentelemetry.io/otel/sdk/metric v1.42.0/go.mod h1:Ua6AAlDKdZ7tdvaQKfSmnFTdHx37+J4ba8MwVCYM5hc= +go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY= +go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc= go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A= go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -118,6 +124,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= +golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo= golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -133,8 +141,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1: google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ= google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY= -google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= +google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU= +google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= From 2e12d9b1598eaafb27b1b427d8006a24eeea18ca Mon Sep 17 00:00:00 2001 From: Fred Amaral Date: Tue, 10 Mar 2026 16:07:10 -0300 Subject: [PATCH 25/34] feat(middleware): migrate to lib-commons v4 API Adapt all middleware call sites to the breaking changes introduced in lib-commons v4: - opentelemetry: span args changed from pointer to value (HandleSpanError, SetSpanAttributesFromValue) - opentelemetry: ExtractHTTPContext and InjectHTTPContext signatures reversed (ctx first) - SetSpanAttributesFromStruct replaced by SetSpanAttributesFromValue - NoneLogger replaced by log.NewNop() - Add logErrorf/logInfof helpers for nil-safe logger calls - Add initializeDefaultLogger to replace zap.InitializeLoggerWithError() - Update testLogger to implement the new v4 log.Logger interface (Log/With/WithGroup/Enabled/Sync) X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 158 +++++++++++++++++++---------- auth/middleware/middlewareGRPC.go | 12 +-- auth/middleware/middleware_test.go | 25 ++--- 3 files changed, 116 insertions(+), 79 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 5111045..852b860 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -8,15 +8,17 @@ import ( "fmt" "io" "net/http" + "os" + "strings" "time" - "github.com/LerianStudio/lib-commons/v3/commons/log" - "github.com/LerianStudio/lib-commons/v3/commons/opentelemetry" - "github.com/LerianStudio/lib-commons/v3/commons/zap" + "github.com/LerianStudio/lib-commons/v4/commons/log" + "github.com/LerianStudio/lib-commons/v4/commons/opentelemetry" + "github.com/LerianStudio/lib-commons/v4/commons/zap" "go.opentelemetry.io/otel/attribute" - "github.com/LerianStudio/lib-commons/v3/commons" - libHTTP "github.com/LerianStudio/lib-commons/v3/commons/net/http" + "github.com/LerianStudio/lib-commons/v4/commons" + libHTTP "github.com/LerianStudio/lib-commons/v4/commons/net/http" "github.com/gofiber/fiber/v2" jwt "github.com/golang-jwt/jwt/v5" ) @@ -46,6 +48,54 @@ const ( pluginName string = "plugin-auth" ) +func logErrorf(ctx context.Context, logger log.Logger, format string, args ...any) { + if logger == nil { + return + } + + logger.Log(ctx, log.LevelError, fmt.Sprintf(format, args...)) +} + +func logInfof(ctx context.Context, logger log.Logger, format string, args ...any) { + if logger == nil { + return + } + + logger.Log(ctx, log.LevelInfo, fmt.Sprintf(format, args...)) +} + +func initializeDefaultLogger() (log.Logger, error) { + envName := strings.ToLower(strings.TrimSpace(os.Getenv("ENV_NAME"))) + + environment := zap.EnvironmentLocal + + switch envName { + case string(zap.EnvironmentProduction): + environment = zap.EnvironmentProduction + case string(zap.EnvironmentStaging): + environment = zap.EnvironmentStaging + case string(zap.EnvironmentUAT): + environment = zap.EnvironmentUAT + case string(zap.EnvironmentDevelopment), "dev": + environment = zap.EnvironmentDevelopment + } + + otelLibraryName := strings.TrimSpace(os.Getenv("OTEL_LIBRARY_NAME")) + if otelLibraryName == "" { + otelLibraryName = "lib-auth" + } + + logger, err := zap.New(zap.Config{ + Environment: environment, + OTelLibraryName: otelLibraryName, + }) + if err != nil { + return nil, err + } + + return logger, nil +} + // NewAuthClient creates a new instance of AuthClient. // It checks the health of the authorization service if the client is enabled and the address is provided. // If the service is healthy, it logs a successful connection message; otherwise, it logs the failure reason. @@ -57,11 +107,11 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient if logger != nil { l = *logger } else { - l, err = zap.InitializeLoggerWithError() + l, err = initializeDefaultLogger() if err != nil { - l = &log.NoneLogger{} + l = log.NewNop() - l.Errorf("failed to initialize logger, using NoneLogger: %v\n", err) + logErrorf(context.Background(), l, "failed to initialize logger, using NopLogger: %v", err) } } @@ -80,29 +130,29 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient resp, err := client.Get(healthURL) if err != nil { - l.Errorf(failedToConnectMsg, err) + logErrorf(context.Background(), l, failedToConnectMsg, err) return &AuthClient{Address: address, Enabled: enabled, Logger: l} } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - l.Errorf(failedToConnectMsg, resp.Status) + logErrorf(context.Background(), l, failedToConnectMsg, resp.Status) return &AuthClient{Address: address, Enabled: enabled, Logger: l} } body, err := io.ReadAll(resp.Body) if err != nil { - l.Errorf("Failed to read response body: %v\n", err) + logErrorf(context.Background(), l, "Failed to read response body: %v", err) return &AuthClient{Address: address, Enabled: enabled, Logger: l} } if string(body) == "healthy" { - l.Infof("Connected to %s ✅ \n", pluginName) + logInfof(context.Background(), l, "Connected to %s", pluginName) } else { - l.Errorf(failedToConnectMsg, string(body)) + logErrorf(context.Background(), l, failedToConnectMsg, string(body)) } return &AuthClient{ @@ -117,7 +167,7 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient // If the user is authorized, the request is passed to the next handler; otherwise, a 403 Forbidden status is returned. func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler { return func(c *fiber.Ctx) error { - ctx := opentelemetry.ExtractHTTPContext(c) + ctx := opentelemetry.ExtractHTTPContext(c.UserContext(), c) _, tracer, reqID, _ := commons.NewTrackingFromContext(ctx) @@ -177,20 +227,20 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a token, _, err := new(jwt.Parser).ParseUnverified(accessToken, jwt.MapClaims{}) if err != nil { - auth.Logger.Errorf("Failed to parse token: %v", err) + logErrorf(ctx, auth.Logger, "Failed to parse token: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to parse token", err) + opentelemetry.HandleSpanError(span, "Failed to parse token", err) return false, http.StatusInternalServerError, err } claims, ok := token.Claims.(jwt.MapClaims) if !ok { - auth.Logger.Errorf("Failed to parse claims: token.Claims is not of type jwt.MapClaims") + logErrorf(ctx, auth.Logger, "Failed to parse claims: token.Claims is not of type jwt.MapClaims") err := errors.New("token claims are not in the expected format") - opentelemetry.HandleSpanError(&span, "Failed to parse claims", err) + opentelemetry.HandleSpanError(span, "Failed to parse claims", err) return false, http.StatusInternalServerError, err } @@ -202,11 +252,11 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a } else { owner, _ := claims["owner"].(string) if owner == "" { - auth.Logger.Errorf("Missing owner claim in token") + logErrorf(ctx, auth.Logger, "Missing owner claim in token") err := errors.New("missing owner claim in token") - opentelemetry.HandleSpanError(&span, "Missing owner claim in token", err) + opentelemetry.HandleSpanError(span, "Missing owner claim in token", err) return false, http.StatusUnauthorized, err } @@ -221,41 +271,41 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a "action": action, } - err = opentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", requestBody) + err = opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", requestBody, nil) if err != nil { - opentelemetry.HandleSpanError(&span, "Failed to convert request body to JSON string", err) + opentelemetry.HandleSpanError(span, "Failed to convert request body to JSON string", err) return false, http.StatusInternalServerError, err } requestBodyJSON, err := json.Marshal(requestBody) if err != nil { - auth.Logger.Errorf("Failed to marshal request body: %v", err) + logErrorf(ctx, auth.Logger, "Failed to marshal request body: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to marshal request body", err) + opentelemetry.HandleSpanError(span, "Failed to marshal request body", err) return false, http.StatusInternalServerError, err } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/authorize", auth.Address), bytes.NewBuffer(requestBodyJSON)) if err != nil { - auth.Logger.Errorf("Failed to create request: %v", err) + logErrorf(ctx, auth.Logger, "Failed to create request: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to create request", err) + opentelemetry.HandleSpanError(span, "Failed to create request", err) return false, http.StatusInternalServerError, fmt.Errorf("failed to create request: %w", err) } - opentelemetry.InjectHTTPContext(&req.Header, ctx) + opentelemetry.InjectHTTPContext(ctx, req.Header) req.Header.Set("Content-Type", "application/json") req.Header.Set("Authorization", accessToken) resp, err := client.Do(req) if err != nil { - auth.Logger.Errorf("Failed to make request: %v", err) + logErrorf(ctx, auth.Logger, "Failed to make request: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to make request", err) + opentelemetry.HandleSpanError(span, "Failed to make request", err) return false, http.StatusInternalServerError, fmt.Errorf("failed to make request: %w", err) } @@ -263,35 +313,35 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a body, err := io.ReadAll(resp.Body) if err != nil { - auth.Logger.Errorf("Failed to read response body: %v", err) + logErrorf(ctx, auth.Logger, "Failed to read response body: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to read response body", err) + opentelemetry.HandleSpanError(span, "Failed to read response body", err) return false, http.StatusInternalServerError, fmt.Errorf("failed to read response body: %w", err) } var respError commons.Response if err := json.Unmarshal(body, &respError); err != nil { - auth.Logger.Errorf("Failed to unmarshal auth error response: %v", err) + logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to unmarshal auth error response", err) + opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err) return false, http.StatusInternalServerError, fmt.Errorf("failed to unmarshal auth error response: %w", err) } if respError.Code != "" && resp.StatusCode != http.StatusInternalServerError { - auth.Logger.Errorf("Authorization request failed: %s", respError.Message) + logErrorf(ctx, auth.Logger, "Authorization request failed: %s", respError.Message) - opentelemetry.HandleSpanError(&span, "Authorization request failed", respError) + opentelemetry.HandleSpanError(span, "Authorization request failed", respError) return false, resp.StatusCode, respError } var response AuthResponse if err := json.Unmarshal(body, &response); err != nil { - auth.Logger.Errorf("Failed to unmarshal response: %v", err) + logErrorf(ctx, auth.Logger, "Failed to unmarshal response: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to unmarshal response", err) + opentelemetry.HandleSpanError(span, "Failed to unmarshal response", err) return false, http.StatusInternalServerError, fmt.Errorf("failed to unmarshal response: %w", err) } @@ -324,40 +374,40 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien "clientSecret": clientSecret, } - err := opentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", requestBody) + err := opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", requestBody, nil) if err != nil { - opentelemetry.HandleSpanError(&span, "Failed to convert request body to JSON string", err) + opentelemetry.HandleSpanError(span, "Failed to convert request body to JSON string", err) return "", fmt.Errorf("failed to convert request body to JSON string: %w", err) } requestBodyJSON, err := json.Marshal(requestBody) if err != nil { - auth.Logger.Errorf("Failed to marshal request body: %v", err) + logErrorf(ctx, auth.Logger, "Failed to marshal request body: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to marshal request body", err) + opentelemetry.HandleSpanError(span, "Failed to marshal request body", err) return "", fmt.Errorf("failed to marshal request body: %w", err) } req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/v1/login/oauth/access_token", auth.Address), bytes.NewBuffer(requestBodyJSON)) if err != nil { - auth.Logger.Errorf("Failed to create request: %v", err) + logErrorf(ctx, auth.Logger, "Failed to create request: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to create request", err) + opentelemetry.HandleSpanError(span, "Failed to create request", err) return "", fmt.Errorf("failed to create request: %w", err) } - opentelemetry.InjectHTTPContext(&req.Header, ctx) + opentelemetry.InjectHTTPContext(ctx, req.Header) req.Header.Set("Content-Type", "application/json") resp, err := client.Do(req) if err != nil { - auth.Logger.Errorf("Failed to make request: %v", err) + logErrorf(ctx, auth.Logger, "Failed to make request: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to make request", err) + opentelemetry.HandleSpanError(span, "Failed to make request", err) return "", fmt.Errorf("failed to make request: %w", err) } @@ -365,35 +415,35 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien body, err := io.ReadAll(resp.Body) if err != nil { - auth.Logger.Errorf("Failed to read response body: %v", err) + logErrorf(ctx, auth.Logger, "Failed to read response body: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to read response body", err) + opentelemetry.HandleSpanError(span, "Failed to read response body", err) return "", fmt.Errorf("failed to read response body: %w", err) } var respError commons.Response if err := json.Unmarshal(body, &respError); err != nil { - auth.Logger.Errorf("Failed to unmarshal auth error response: %v", err) + logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to unmarshal auth error response", err) + opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err) return "", fmt.Errorf("failed to unmarshal auth error response: %w", err) } if respError.Code != "" && resp.StatusCode != http.StatusInternalServerError { - auth.Logger.Errorf("Failed to get application token: %s", respError.Message) + logErrorf(ctx, auth.Logger, "Failed to get application token: %s", respError.Message) - opentelemetry.HandleSpanError(&span, "Failed to get application token", respError) + opentelemetry.HandleSpanError(span, "Failed to get application token", respError) return "", respError } var response oauth2Token if err := json.Unmarshal(body, &response); err != nil { - auth.Logger.Errorf("Failed to unmarshal response: %v", err) + logErrorf(ctx, auth.Logger, "Failed to unmarshal response: %v", err) - opentelemetry.HandleSpanError(&span, "Failed to unmarshal response", err) + opentelemetry.HandleSpanError(span, "Failed to unmarshal response", err) return "", fmt.Errorf("failed to unmarshal response: %w", err) } diff --git a/auth/middleware/middlewareGRPC.go b/auth/middleware/middlewareGRPC.go index 15a0aa2..87e3482 100644 --- a/auth/middleware/middlewareGRPC.go +++ b/auth/middleware/middlewareGRPC.go @@ -8,8 +8,8 @@ import ( "os" "strings" - "github.com/LerianStudio/lib-commons/v3/commons" - "github.com/LerianStudio/lib-commons/v3/commons/opentelemetry" + "github.com/LerianStudio/lib-commons/v4/commons" + "github.com/LerianStudio/lib-commons/v4/commons/opentelemetry" jwt "github.com/golang-jwt/jwt/v5" "go.opentelemetry.io/otel/attribute" "google.golang.org/grpc" @@ -63,7 +63,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer pol, found := policyForMethod(cfg, info.FullMethod) if !found { - opentelemetry.HandleSpanError(&span, "no policy configured for method", fmt.Errorf("%s", info.FullMethod)) + opentelemetry.HandleSpanError(span, "no policy configured for method", fmt.Errorf("%s", info.FullMethod)) return nil, status.Error(codes.Internal, "internal configuration error") } @@ -75,7 +75,7 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer sub, err = cfg.SubResolver(ctx, info.FullMethod, req) if err != nil { - opentelemetry.HandleSpanError(&span, "failed to resolve subject", err) + opentelemetry.HandleSpanError(span, "failed to resolve subject", err) return nil, status.Error(codes.Internal, "internal configuration error") } @@ -86,8 +86,8 @@ func NewGRPCAuthUnaryPolicy(auth *AuthClient, cfg PolicyConfig) grpc.UnaryServer "resource": pol.Resource, "action": pol.Action, } - if err := opentelemetry.SetSpanAttributesFromStruct(&span, "app.request.payload", payload); err != nil { - opentelemetry.HandleSpanError(&span, "failed to set span payload", err) + if err := opentelemetry.SetSpanAttributesFromValue(span, "app.request.payload", payload, nil); err != nil { + opentelemetry.HandleSpanError(span, "failed to set span payload", err) } authorized, httpStatus, err := auth.checkAuthorization(ctx, sub, pol.Resource, pol.Action, token) diff --git a/auth/middleware/middleware_test.go b/auth/middleware/middleware_test.go index ea6ddec..d0a72f7 100644 --- a/auth/middleware/middleware_test.go +++ b/auth/middleware/middleware_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - "github.com/LerianStudio/lib-commons/v3/commons/log" + "github.com/LerianStudio/lib-commons/v4/commons/log" jwt "github.com/golang-jwt/jwt/v5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -51,24 +51,11 @@ func mockAuthServer(t *testing.T, authorized bool, statusCode int) *httptest.Ser // testLogger is a minimal log.Logger implementation for tests that discards all output. type testLogger struct{} -func (l *testLogger) Info(_ ...any) {} -func (l *testLogger) Infof(_ string, _ ...any) {} -func (l *testLogger) Infoln(_ ...any) {} -func (l *testLogger) Error(_ ...any) {} -func (l *testLogger) Errorf(_ string, _ ...any) {} -func (l *testLogger) Errorln(_ ...any) {} -func (l *testLogger) Warn(_ ...any) {} -func (l *testLogger) Warnf(_ string, _ ...any) {} -func (l *testLogger) Warnln(_ ...any) {} -func (l *testLogger) Debug(_ ...any) {} -func (l *testLogger) Debugf(_ string, _ ...any) {} -func (l *testLogger) Debugln(_ ...any) {} -func (l *testLogger) Fatal(_ ...any) {} -func (l *testLogger) Fatalf(_ string, _ ...any) {} -func (l *testLogger) Fatalln(_ ...any) {} -func (l *testLogger) WithFields(_ ...any) log.Logger { return l } -func (l *testLogger) WithDefaultMessageTemplate(_ string) log.Logger { return l } -func (l *testLogger) Sync() error { return nil } +func (l *testLogger) Log(_ context.Context, _ log.Level, _ string, _ ...log.Field) {} +func (l *testLogger) With(_ ...log.Field) log.Logger { return l } +func (l *testLogger) WithGroup(_ string) log.Logger { return l } +func (l *testLogger) Enabled(_ log.Level) bool { return false } +func (l *testLogger) Sync(_ context.Context) error { return nil } // --------------------------------------------------------------------------- // checkAuthorization - subject construction From 6ba51e5df9cbbdf62fc906c1837d6de41641946a Mon Sep 17 00:00:00 2001 From: Fred Amaral Date: Tue, 10 Mar 2026 16:32:19 -0300 Subject: [PATCH 26/34] fix(auth/middleware): prevent panic on logger initialization failure If the default logger initialization fails, the previous code attempts to log this error using the uninitialized logger instance itself. This causes a nil pointer dereference and panics the application. This commit replaces the faulty call with `stdlog.Printf`. Using the standard library logger ensures the initialization error is reported safely without crashing. The application then gracefully falls back to using a no-op logger. --- auth/middleware/middleware.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 852b860..8fd225c 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -7,6 +7,7 @@ import ( "errors" "fmt" "io" + stdlog "log" "net/http" "os" "strings" @@ -109,9 +110,9 @@ func NewAuthClient(address string, enabled bool, logger *log.Logger) *AuthClient } else { l, err = initializeDefaultLogger() if err != nil { - l = log.NewNop() + stdlog.Printf("failed to initialize logger, using NopLogger: %v", err) - logErrorf(context.Background(), l, "failed to initialize logger, using NopLogger: %v", err) + l = log.NewNop() } } From 7175a5bba7e3840d71161bd1a81841531da1dff5 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Tue, 10 Mar 2026 19:38:11 +0000 Subject: [PATCH 27/34] chore(release): 2.5.0-beta.7 ## [2.5.0-beta.7](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.6...v2.5.0-beta.7) (2026-03-10) ### Features * **middleware:** migrate to lib-commons v4 API ([2e12d9b](https://github.com/LerianStudio/lib-auth/commit/2e12d9b1598eaafb27b1b427d8006a24eeea18ca)) ### Bug Fixes * **auth/middleware:** prevent panic on logger initialization failure ([6ba51e5](https://github.com/LerianStudio/lib-auth/commit/6ba51e5df9cbbdf62fc906c1837d6de41641946a)) --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c809a0..0117bf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## [2.5.0-beta.7](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.6...v2.5.0-beta.7) (2026-03-10) + + +### Features + +* **middleware:** migrate to lib-commons v4 API ([2e12d9b](https://github.com/LerianStudio/lib-auth/commit/2e12d9b1598eaafb27b1b427d8006a24eeea18ca)) + + +### Bug Fixes + +* **auth/middleware:** prevent panic on logger initialization failure ([6ba51e5](https://github.com/LerianStudio/lib-auth/commit/6ba51e5df9cbbdf62fc906c1837d6de41641946a)) + ## [2.5.0-beta.6](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.5...v2.5.0-beta.6) (2026-02-27) From 4f51877ef95b4db01304cb9df5ba3a38919e55ff Mon Sep 17 00:00:00 2001 From: Brecci Date: Tue, 17 Mar 2026 12:13:58 -0300 Subject: [PATCH 28/34] fix(auth/middleware): return 401 instead of 500 for malformed tokens checkAuthorization returned HTTP 500 when JWT parsing failed (malformed/invalid token). The Authorize caller also hardcoded 500, ignoring the returned status code. Now returns 401 Unauthorized for parse failures and the caller respects the returned status code. X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 6 +++--- auth/middleware/middleware_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 8fd225c..3d5acee 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -200,7 +200,7 @@ func (auth *AuthClient) Authorize(sub, resource, action string) fiber.Handler { span.End() - return c.Status(http.StatusInternalServerError).SendString("Internal Server Error") + return c.Status(statusCode).SendString(http.StatusText(statusCode)) } else if authorized { span.End() @@ -232,7 +232,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a opentelemetry.HandleSpanError(span, "Failed to parse token", err) - return false, http.StatusInternalServerError, err + return false, http.StatusUnauthorized, err } claims, ok := token.Claims.(jwt.MapClaims) @@ -243,7 +243,7 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a opentelemetry.HandleSpanError(span, "Failed to parse claims", err) - return false, http.StatusInternalServerError, err + return false, http.StatusUnauthorized, err } userType, _ := claims["type"].(string) diff --git a/auth/middleware/middleware_test.go b/auth/middleware/middleware_test.go index d0a72f7..3600cc7 100644 --- a/auth/middleware/middleware_test.go +++ b/auth/middleware/middleware_test.go @@ -305,7 +305,7 @@ func TestCheckAuthorization_InvalidToken(t *testing.T) { require.Error(t, err) assert.False(t, authorized) - assert.Equal(t, http.StatusInternalServerError, statusCode) + assert.Equal(t, http.StatusUnauthorized, statusCode) } func TestCheckAuthorization_EmptyTypeClaim_TreatedAsNonNormalUser(t *testing.T) { From 72bfae433900a4a38a90703b8b805c2d7a50cf40 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Tue, 17 Mar 2026 15:23:35 +0000 Subject: [PATCH 29/34] chore(release): 2.5.0-beta.8 ## [2.5.0-beta.8](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.7...v2.5.0-beta.8) (2026-03-17) ### Bug Fixes * **auth/middleware:** return 401 instead of 500 for malformed tokens ([4f51877](https://github.com/LerianStudio/lib-auth/commit/4f51877ef95b4db01304cb9df5ba3a38919e55ff)) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0117bf5..4b03b6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [2.5.0-beta.8](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.7...v2.5.0-beta.8) (2026-03-17) + + +### Bug Fixes + +* **auth/middleware:** return 401 instead of 500 for malformed tokens ([4f51877](https://github.com/LerianStudio/lib-auth/commit/4f51877ef95b4db01304cb9df5ba3a38919e55ff)) + ## [2.5.0-beta.7](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.6...v2.5.0-beta.7) (2026-03-10) From 165db5fdd324bb56304edd96b7e4d4579e351ade Mon Sep 17 00:00:00 2001 From: Brecci Date: Fri, 20 Mar 2026 18:58:01 -0300 Subject: [PATCH 30/34] fix(auth/middleware): handle numeric code field in auth error response The auth service may return the 'code' field as a number (e.g. 401) instead of a string. This caused json.Unmarshal to fail with a type mismatch, surfacing as a 500 instead of propagating the actual error. Add unmarshalErrorResponse helper using json.RawMessage to tolerate both string and numeric code values in checkAuthorization and GetApplicationToken. X-Lerian-Ref: 0x1 --- auth/middleware/middleware.go | 41 +++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/auth/middleware/middleware.go b/auth/middleware/middleware.go index 3d5acee..758f06c 100644 --- a/auth/middleware/middleware.go +++ b/auth/middleware/middleware.go @@ -49,6 +49,39 @@ const ( pluginName string = "plugin-auth" ) +// unmarshalErrorResponse unmarshals a JSON response body into commons.Response, +// tolerating a numeric "code" field (the auth service may return code as a number). +func unmarshalErrorResponse(body []byte) (commons.Response, error) { + var raw struct { + EntityType string `json:"entityType,omitempty"` + Title string `json:"title,omitempty"` + Message string `json:"message,omitempty"` + Code json.RawMessage `json:"code,omitempty"` + } + + if err := json.Unmarshal(body, &raw); err != nil { + return commons.Response{}, err + } + + resp := commons.Response{ + EntityType: raw.EntityType, + Title: raw.Title, + Message: raw.Message, + } + + if len(raw.Code) > 0 { + var code string + if err := json.Unmarshal(raw.Code, &code); err == nil { + resp.Code = code + } else { + // Numeric code — use raw representation (e.g. "401") + resp.Code = string(raw.Code) + } + } + + return resp, nil +} + func logErrorf(ctx context.Context, logger log.Logger, format string, args ...any) { if logger == nil { return @@ -321,8 +354,8 @@ func (auth *AuthClient) checkAuthorization(ctx context.Context, sub, resource, a return false, http.StatusInternalServerError, fmt.Errorf("failed to read response body: %w", err) } - var respError commons.Response - if err := json.Unmarshal(body, &respError); err != nil { + respError, err := unmarshalErrorResponse(body) + if err != nil { logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err) opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err) @@ -423,8 +456,8 @@ func (auth *AuthClient) GetApplicationToken(ctx context.Context, clientID, clien return "", fmt.Errorf("failed to read response body: %w", err) } - var respError commons.Response - if err := json.Unmarshal(body, &respError); err != nil { + respError, err := unmarshalErrorResponse(body) + if err != nil { logErrorf(ctx, auth.Logger, "Failed to unmarshal auth error response: %v", err) opentelemetry.HandleSpanError(span, "Failed to unmarshal auth error response", err) From a22c8aa7f7c650b12ae67134ba5bbc26e90c85cd Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Fri, 20 Mar 2026 22:05:03 +0000 Subject: [PATCH 31/34] chore(release): 2.5.0-beta.9 ## [2.5.0-beta.9](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.8...v2.5.0-beta.9) (2026-03-20) ### Bug Fixes * **auth/middleware:** handle numeric code field in auth error response ([165db5f](https://github.com/LerianStudio/lib-auth/commit/165db5fdd324bb56304edd96b7e4d4579e351ade)) --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b03b6b..a09594b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## [2.5.0-beta.9](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.8...v2.5.0-beta.9) (2026-03-20) + + +### Bug Fixes + +* **auth/middleware:** handle numeric code field in auth error response ([165db5f](https://github.com/LerianStudio/lib-auth/commit/165db5fdd324bb56304edd96b7e4d4579e351ade)) + ## [2.5.0-beta.8](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.7...v2.5.0-beta.8) (2026-03-17) From 5a83709df6f78020951a69f4a4ee37e7be0bfb34 Mon Sep 17 00:00:00 2001 From: Jefferson Rodrigues Date: Sat, 21 Mar 2026 18:14:40 -0300 Subject: [PATCH 32/34] chore(deps): bump lib-commons to v4.2.0-beta.9 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index df41dc3..28738e8 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/LerianStudio/lib-auth/v2 go 1.25.7 require ( - github.com/LerianStudio/lib-commons/v4 v4.0.0 + github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9 github.com/gofiber/fiber/v2 v2.52.12 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 000d0ce..53e487e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/LerianStudio/lib-commons/v4 v4.0.0 h1:OEdpRKnbLoOhZoUZyI5FgIe7ZbwJzu/syfgpkDzyi3o= -github.com/LerianStudio/lib-commons/v4 v4.0.0/go.mod h1:WMQ17ouiJ13uUVhH/eY+p++4xb/NOtR44yIMGZ0r8Ow= +github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9 h1:B6S5rHeaPOi4sMTWfGFa+AdVrJiUwU0P+/JUiOmy/HQ= +github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9/go.mod h1:89mzZKE3Hf0aDdKo3qfjfPL38ZsQRciqRbEeR718O+g= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= From bd384b64aacc30aead2b2daf9d3c685ac9ddd18f Mon Sep 17 00:00:00 2001 From: Jefferson Rodrigues Date: Sat, 21 Mar 2026 18:15:19 -0300 Subject: [PATCH 33/34] chore(deps): bump lib-commons to v4.2.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 28738e8..e7ecbc2 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/LerianStudio/lib-auth/v2 go 1.25.7 require ( - github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9 + github.com/LerianStudio/lib-commons/v4 v4.2.0 github.com/gofiber/fiber/v2 v2.52.12 github.com/golang-jwt/jwt/v5 v5.3.1 github.com/stretchr/testify v1.11.1 diff --git a/go.sum b/go.sum index 53e487e..24ad951 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9 h1:B6S5rHeaPOi4sMTWfGFa+AdVrJiUwU0P+/JUiOmy/HQ= -github.com/LerianStudio/lib-commons/v4 v4.2.0-beta.9/go.mod h1:89mzZKE3Hf0aDdKo3qfjfPL38ZsQRciqRbEeR718O+g= +github.com/LerianStudio/lib-commons/v4 v4.2.0 h1:4gbQRcTiToo2JVsFymbMPE6eDui5wiVZInkR98+KoXs= +github.com/LerianStudio/lib-commons/v4 v4.2.0/go.mod h1:89mzZKE3Hf0aDdKo3qfjfPL38ZsQRciqRbEeR718O+g= github.com/andybalholm/brotli v1.2.0 h1:ukwgCxwYrmACq68yiUqwIWnGY0cTPox/M94sVwToPjQ= github.com/andybalholm/brotli v1.2.0/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY= github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= From 8636317f2e301d7256c7d7d0ca5ad77aa55c53f9 Mon Sep 17 00:00:00 2001 From: lerian-studio Date: Sat, 21 Mar 2026 21:16:44 +0000 Subject: [PATCH 34/34] chore(release): 2.5.0-beta.10 ## [2.5.0-beta.10](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.9...v2.5.0-beta.10) (2026-03-21) --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a09594b..fb3124f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,5 @@ +## [2.5.0-beta.10](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.9...v2.5.0-beta.10) (2026-03-21) + ## [2.5.0-beta.9](https://github.com/LerianStudio/lib-auth/compare/v2.5.0-beta.8...v2.5.0-beta.9) (2026-03-20)