Skip to content

Develop#80

Merged
ClaraTersi merged 48 commits intomainfrom
develop
Mar 21, 2026
Merged

Develop#80
ClaraTersi merged 48 commits intomainfrom
develop

Conversation

@qnen
Copy link
Contributor

@qnen qnen commented Mar 20, 2026

Pull Request Checklist

Pull Request Type

  • Feature
  • Fix
  • Refactor
  • Pipeline
  • Tests
  • Documentation
  • Helm

Checklist

Please check each item after it's completed.

  • I have tested these changes locally.
  • I have updated the documentation accordingly.
  • I have added necessary comments to the code, especially in complex areas.
  • I have ensured that my changes adhere to the project's coding standards.
  • I have checked for any potential security issues.
  • I have ensured that all tests pass.
  • I have updated the version appropriately (if applicable).
  • I have confirmed this code is ready for review.

Additional Notes

Obs: Please, always remember to target your PR to develop branch instead of main.

dependabot bot and others added 30 commits December 15, 2025 15:29
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](open-telemetry/opentelemetry-go@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] <support@github.com>
Generated-by: Claude
AI-Model: claude-opus-4-5-20251101
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](golang-jwt/jwt@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] <support@github.com>
…elv2

docs: update license to Elastic License 2.0 (ELv2)
## [2.4.1-beta.1](v2.4.0...v2.4.1-beta.1) (2026-02-03)
…rn 🔧

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
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
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
chore: add build, test and coverage commands
## [2.5.0-beta.1](v2.4.1-beta.1...v2.5.0-beta.1) (2026-02-09)

### Bug Fixes

* **tests:** use safe find -exec instead of xargs pipeline 🐛 ([da45b1a](da45b1a))
Update imports from v2 to v3 and point to published version, removing local replace directive.

X-Lerian-Ref: 0x1
…p/github.com/golang-jwt/jwt/v5-5.3.1

build(deps): bump github.com/golang-jwt/jwt/v5 from 5.3.0 to 5.3.1
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](gofiber/fiber@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] <support@github.com>
…p/github.com/gofiber/fiber/v2-2.52.11

build(deps): bump github.com/gofiber/fiber/v2 from 2.52.9 to 2.52.11
…p/go.opentelemetry.io/otel-1.39.0

build(deps): bump go.opentelemetry.io/otel from 1.37.0 to 1.39.0
- 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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
Replace NewTracerFromContext + NewHeaderIDFromContext with the unified NewTrackingFromContext across HTTP and gRPC middleware.

X-Lerian-Ref: 0x1
fredcamaral and others added 7 commits March 10, 2026 16:07
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
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.
feat(middleware): migrate lib-commons from v3 to v4
## [2.5.0-beta.7](v2.5.0-beta.6...v2.5.0-beta.7) (2026-03-10)

### Features

* **middleware:** migrate to lib-commons v4 API ([2e12d9b](2e12d9b))

### Bug Fixes

* **auth/middleware:** prevent panic on logger initialization failure ([6ba51e5](6ba51e5))
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
fix(auth/middleware): return 401 instead of 500 for malformed tokens
## [2.5.0-beta.8](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](4f51877))
@qnen qnen self-assigned this Mar 20, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8a604aa3-d158-40e3-bdca-92e336c0b7f2

📥 Commits

Reviewing files that changed from the base of the PR and between a22c8aa and 8636317.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • CHANGELOG.md
  • go.mod

Walkthrough

This pull request upgrades the Go toolchain and many dependencies (including lib-commons v2→v4), expands the Makefile into a project task runner with a new mk/tests.mk include, and adds LICENSE and coverage ignore files. The auth middleware is refactored to use updated commons and OpenTelemetry APIs, adds tolerant error unmarshalling for numeric/string code fields, initializes a default logger fallback, changes malformed-token handling to return 401, and adds tenant-aware gRPC streaming support with tenant propagation. Extensive HTTP and gRPC middleware tests were added.

Sequence Diagram(s)

sequenceDiagram
    participant Client as gRPC Client
    participant StreamInterceptor as gRPC Stream Interceptor
    participant AuthClient as Auth Service Client
    participant TokenHandler as Token & Claims Handler
    participant Metadata as Context & Metadata
    participant Handler as Method Handler

    Client->>StreamInterceptor: Start streaming RPC
    StreamInterceptor->>StreamInterceptor: Check auth enabled / resolve policy
    StreamInterceptor->>TokenHandler: Extract token from metadata
    alt token missing
        StreamInterceptor->>Client: Return Unauthenticated (gRPC) error
    else token present
        TokenHandler->>TokenHandler: Parse/inspect token (ParseUnverified / verify)
        StreamInterceptor->>AuthClient: call auth.checkAuthorization
        alt authorization fails
            AuthClient->>StreamInterceptor: Unauthorized/Forbidden
            StreamInterceptor->>Client: Return corresponding gRPC error
        else authorization succeeds
            alt MULTI_TENANT_ENABLED == "true"
                TokenHandler->>TokenHandler: Extract tenant claims (id, slug, owner)
                Metadata->>Metadata: Inject tenant metadata keys (md-tenant-*)
            end
            StreamInterceptor->>Handler: Invoke wrapped stream with enriched Context()
            Handler->>Handler: Read tenant metadata from Context()
            Handler-->>Client: Stream responses
        end
    end
Loading
🚥 Pre-merge checks | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Develop' is vague and does not describe the actual changes in the changeset. Use a descriptive title that summarizes the main change, such as 'chore(release): bump to 2.5.0-beta.9 and update lib-commons to v4' or similar.
Description check ⚠️ Warning The PR description is incomplete; it contains only an unchecked template with no substantive explanation of the changes. Fill in the checklist boxes, describe the changes made in the Additional Notes section, and explain the PR objectives and rationale.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can use your project's `golangci-lint` configuration to improve the quality of Go code reviews.

Add a configuration file to your project to customize how CodeRabbit runs golangci-lint.

coderabbitai[bot]
coderabbitai bot previously requested changes Mar 20, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@auth/middleware/middleware_test.go`:
- Around line 156-158: The comment next to the assertion on capturedBody["sub"]
in middleware_test.go currently prefixes "BUG:" but documents expected hardcoded
"admin/" behavior; if this behavior is intentional, remove the "BUG:" prefix (or
replace with "NOTE:"/TODO) to avoid misleading reviewers and update the comment
to state it's expected; if it's actually a bug, create an issue tracking the
bug, reference that issue ID in a TODO comment next to the assert.Equal line
(capturedBody["sub"]) and keep the test as-is until the bug is fixed so CI
surfaces the failure.

In `@auth/middleware/middlewareGRPC_test.go`:
- Around line 424-429: The test currently declares handlerCalled and sets it
inside noopHandler but never asserts it; either remove the handlerCalled
variable and the blank identifier assignment that suppresses the warning (i.e.,
drop handlerCalled and the trailing "_ = handlerCalled" lines and keep
noopHandler returning "ok"), or keep handlerCalled and add assertions in the
error-case tests to verify the handler was not invoked (e.g., assert
handlerCalled == false after calling the middleware) so the tracking variable is
actually used; update tests that reference handlerCalled/noopHandler
accordingly.

In `@auth/middleware/middlewareGRPC.go`:
- Around line 270-290: Extract the duplicated tenant propagation block into a
helper function propagateTenantClaims(ctx context.Context, token string, logger
log.Logger) context.Context that checks os.Getenv("MULTI_TENANT_ENABLED"), calls
extractTenantClaims(token), logs extraction errors, copies incoming metadata,
sets "md-tenant-id", "md-tenant-slug", and "md-tenant-owner" when present, and
returns metadata.NewIncomingContext(ctx, md); then replace the duplicated code
in both the unary interceptor (where extractTenantClaims is currently used) and
the stream interceptor (where wrappedServerStream is created) by calling ctx =
propagateTenantClaims(ctx, token, auth.Logger) and for the stream update ss =
&wrappedServerStream{ServerStream: ss, ctx: ctx} after calling the helper.
- Around line 102-121: extractTenantClaims' returned error is being discarded;
capture the fourth return value (err) instead of using '_' and log it at debug
level when MULTI_TENANT_ENABLED is true so tenant propagation failures are
visible during troubleshooting. Update the block that calls
extractTenantClaims(token) to assign the error (e.g., tenantID, tenantSlug,
tOwner, err := extractTenantClaims(token)), and if err != nil call the existing
logger (e.g., authLogger or the package logger) with a debug message including
the error and token/ctx context; leave behavior unchanged otherwise and still
set metadata via metadata.FromIncomingContext / metadata.NewIncomingContext as
before.

In `@go.mod`:
- Line 11: The dependency google.golang.org/grpc pinned to v1.79.2 contains a
critical auth bypass (CVE-2026-33186); update the module version in go.mod to
v1.79.3 or later to fix it. If you cannot upgrade immediately, add an outermost
unary and stream interceptor on your gRPC server (where you call grpc.NewServer
or configure interceptors) that rejects requests whose full method string is
empty or does not start with '/' to block malformed :path values; after
upgrading remove the temporary interceptor. Ensure you update go.mod's
google.golang.org/grpc entry and run go mod tidy to refresh the lock.

In `@LICENSE`:
- Around line 1-93: The repo added Elastic License 2.0 (LICENSE) but lacked
propagation; update README.md to add an explicit "License" section that names
"Elastic License 2.0" and briefly calls out the hosted/managed-service
restriction, add SPDX-License-Identifier: Elastic-2.0 headers to all source
files (e.g., top of .go/.ts/.js files) and ensure go.mod contains license
metadata (module/comments or a license directive) so tooling sees Elastic-2.0;
search for README.md, go.mod and all source files to apply these changes
consistently and commit them alongside the LICENSE file.

In `@Makefile`:
- Around line 269-274: Update the goreleaser Makefile target "goreleaser" to
replace the removed flag form "--skip-publish" with the new "--skip=publish";
specifically, in the command invoked by the goreleaser target (the line that
currently runs "goreleaser release --snapshot --skip-publish --clean"), change
the flag to "--skip=publish" so the release snapshot command works with
goreleaser v1.21+ and v2.0.

In `@mk/tests.mk`:
- Around line 221-230: The current glob-to-regex conversion in mk/tests.mk (the
sed pipeline that builds regex_patterns from patterns read from
.ignorecoverunit) only escapes '.' and converts '*' to '.*', so it fails on
other glob metacharacters (e.g., '+', '?', '[]') — update the file to either (A)
document this limitation immediately above the block that defines
patterns/regex_patterns and explain acceptable pattern syntax for
.ignorecoverunit, or (B) replace the simple sed conversion that produces
regex_patterns with a more robust glob-to-regex conversion (e.g., a small
perl/python one-liner or utility) that properly escapes regex metacharacters
while translating globs; ensure the rest of the flow (reading patterns into
patterns, filtering unit_coverage.out into unit_coverage_filtered.out, and mv
back) still uses the new regex_patterns variable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 9c2b8bbb-9f36-4172-871a-6381f3e5d35f

📥 Commits

Reviewing files that changed from the base of the PR and between 93da6b0 and 72bfae4.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (11)
  • .gitignore
  • .ignorecoverunit
  • CHANGELOG.md
  • LICENSE
  • Makefile
  • auth/middleware/middleware.go
  • auth/middleware/middlewareGRPC.go
  • auth/middleware/middlewareGRPC_test.go
  • auth/middleware/middleware_test.go
  • go.mod
  • mk/tests.mk

Comment on lines +156 to +158
// BUG: hardcodes "admin/" prefix. The sub parameter is used as-is with the
// "admin/<sub>-editor-role" pattern, regardless of the actual user type.
assert.Equal(t, "admin/my-app-editor-role", capturedBody["sub"])
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Documented behavior: hardcoded "admin/" prefix for non-normal users.

The test documents this as a potential bug with the comment on lines 156-157. If this is intentional behavior, consider removing the "BUG:" prefix from the comment to avoid confusion. If it's actually a bug, consider opening an issue to track it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middleware_test.go` around lines 156 - 158, The comment next
to the assertion on capturedBody["sub"] in middleware_test.go currently prefixes
"BUG:" but documents expected hardcoded "admin/" behavior; if this behavior is
intentional, remove the "BUG:" prefix (or replace with "NOTE:"/TODO) to avoid
misleading reviewers and update the comment to state it's expected; if it's
actually a bug, create an issue tracking the bug, reference that issue ID in a
TODO comment next to the assert.Equal line (capturedBody["sub"]) and keep the
test as-is until the bug is fixed so CI surfaces the failure.

Comment on lines +424 to +429
handlerCalled := false

noopHandler := func(_ context.Context, _ any) (any, error) {
handlerCalled = true
return "ok", nil
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove unused handlerCalled variable or add assertions.

The handlerCalled variable is set in noopHandler but never asserted on. The blank identifier assignment at line 558 just suppresses the compiler warning. For error-case tests (lines 495, 520, 547), you should either assert that the handler was not called, or simplify by removing the tracking variable entirely.

♻️ Option 1: Remove tracking (simpler)
-	handlerCalled := false
-
-	noopHandler := func(_ context.Context, _ any) (any, error) {
-		handlerCalled = true
-		return "ok", nil
-	}
+	noopHandler := func(_ context.Context, _ any) (any, error) {
+		return "ok", nil
+	}

And remove line 558:

-	// Prevent compiler from optimizing away the handlerCalled variable
-	_ = handlerCalled
♻️ Option 2: Assert handler not called in error tests
+	handlerCalled = false // reset before test
 	resp, err := interceptor(context.Background(), "req", dummyInfo, noopHandler)
 	require.Error(t, err)
 	assert.Nil(t, resp)
+	assert.False(t, handlerCalled, "handler should not be called on error")

Also applies to: 557-558

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middlewareGRPC_test.go` around lines 424 - 429, The test
currently declares handlerCalled and sets it inside noopHandler but never
asserts it; either remove the handlerCalled variable and the blank identifier
assignment that suppresses the warning (i.e., drop handlerCalled and the
trailing "_ = handlerCalled" lines and keep noopHandler returning "ok"), or keep
handlerCalled and add assertions in the error-case tests to verify the handler
was not invoked (e.g., assert handlerCalled == false after calling the
middleware) so the tracking variable is actually used; update tests that
reference handlerCalled/noopHandler accordingly.

Comment on lines +102 to +121
// 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)
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider logging when tenant claim extraction fails.

The extractTenantClaims error is silently discarded on line 104. While this is defensive (authorization already passed), logging at debug level could help troubleshoot tenant propagation issues in multi-tenant deployments.

💡 Suggested improvement
 		// Propagate tenant claims if multi-tenant mode is enabled
 		if os.Getenv("MULTI_TENANT_ENABLED") == "true" {
-			tenantID, tenantSlug, tOwner, _ := extractTenantClaims(token)
+			tenantID, tenantSlug, tOwner, extractErr := extractTenantClaims(token)
+			if extractErr != nil {
+				logErrorf(ctx, auth.Logger, "failed to extract tenant claims: %v", extractErr)
+			}
 			md, _ := metadata.FromIncomingContext(ctx)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middlewareGRPC.go` around lines 102 - 121,
extractTenantClaims' returned error is being discarded; capture the fourth
return value (err) instead of using '_' and log it at debug level when
MULTI_TENANT_ENABLED is true so tenant propagation failures are visible during
troubleshooting. Update the block that calls extractTenantClaims(token) to
assign the error (e.g., tenantID, tenantSlug, tOwner, err :=
extractTenantClaims(token)), and if err != nil call the existing logger (e.g.,
authLogger or the package logger) with a debug message including the error and
token/ctx context; leave behavior unchanged otherwise and still set metadata via
metadata.FromIncomingContext / metadata.NewIncomingContext as before.

Comment on lines +270 to +290
// 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}
}
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Duplicate tenant propagation logic between unary and stream interceptors.

Lines 270-290 duplicate the tenant claim propagation logic from lines 102-121. Consider extracting this into a shared helper function to reduce maintenance burden.

♻️ Proposed refactor
// propagateTenantClaims extracts tenant claims from the token and injects them into metadata.
// Returns the updated context with tenant metadata.
func propagateTenantClaims(ctx context.Context, token string, logger log.Logger) context.Context {
	if os.Getenv("MULTI_TENANT_ENABLED") != "true" {
		return ctx
	}

	tenantID, tenantSlug, tOwner, err := extractTenantClaims(token)
	if err != nil {
		logErrorf(ctx, logger, "failed to extract tenant claims: %v", err)
		return ctx
	}

	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)
	}

	return metadata.NewIncomingContext(ctx, md)
}

Then use in both interceptors:

ctx = propagateTenantClaims(ctx, token, auth.Logger)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middlewareGRPC.go` around lines 270 - 290, Extract the
duplicated tenant propagation block into a helper function
propagateTenantClaims(ctx context.Context, token string, logger log.Logger)
context.Context that checks os.Getenv("MULTI_TENANT_ENABLED"), calls
extractTenantClaims(token), logs extraction errors, copies incoming metadata,
sets "md-tenant-id", "md-tenant-slug", and "md-tenant-owner" when present, and
returns metadata.NewIncomingContext(ctx, md); then replace the duplicated code
in both the unary interceptor (where extractTenantClaims is currently used) and
the stream interceptor (where wrappedServerStream is created) by calling ctx =
propagateTenantClaims(ctx, token, auth.Logger) and for the stream update ss =
&wrappedServerStream{ServerStream: ss, ctx: ctx} after calling the helper.

github.com/golang-jwt/jwt/v5 v5.3.1
github.com/stretchr/testify v1.11.1
go.opentelemetry.io/otel v1.42.0
google.golang.org/grpc v1.79.2
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check for security advisories affecting grpc-go
gh api graphql -f query='
{
  securityVulnerabilities(first: 5, ecosystem: GO, package: "google.golang.org/grpc") {
    nodes {
      advisory {
        summary
        severity
        publishedAt
        ghsaId
      }
      vulnerableVersionRange
      firstPatchedVersion {
        identifier
      }
    }
  }
}'

Repository: LerianStudio/lib-auth

Length of output: 225


🌐 Web query:

GHSA-p77j-4mvh-x3m3 google.golang.org/grpc vulnerability

💡 Result:

GHSA-p77j-4mvh-x3m3 (aka CVE-2026-33186) is a critical authorization-bypass in gRPC-Go (google.golang.org/grpc) caused by improper validation of the HTTP/2 :path pseudo-header. If an attacker sends a request whose :path omits the required leading slash (e.g., Service/Method instead of /Service/Method), the server may still route it, but path-based authorization interceptors may evaluate the non-canonical method string and fail to match “deny” rules—potentially allowing access when a fallback “allow” rule exists. [1]

  • Affected: google.golang.org/grpc < 1.79.3 [1]
  • Fixed in: 1.79.3 [1]
  • Recommended remediation: upgrade to v1.79.3+. [1]
  • Workaround (if you can’t upgrade immediately): add an outermost interceptor that rejects any method where info.FullMethod is empty or doesn’t start with / (the advisory includes an example), and/or enforce strict HTTP/2 pseudo-header validation at the proxy/load balancer layer. [1]

Source: GitHub Advisory Database / grpc-go security advisory. [1]

References:
[1] GHSA-p77j-4mvh-x3m3


🌐 Web query:

gRPC-Go authorization bypass missing leading slash :path vulnerability

💡 Result:

What the vulnerability is

A recently disclosed issue (tracked publicly as CVE-2026-33186) describes an authorization bypass in gRPC-Go when an attacker sends an HTTP/2 request with a malformed :path pseudo-header that is missing the required leading / (e.g., pkg.Service/Method instead of /pkg.Service/Method). The bypass occurs only when authorization logic “fails open” (i.e., treats an unrecognized / unmatched method name as allowed). One reported affected scenario is gRPC-Go’s experimental xDS RBAC authorizer behavior in certain policy modes. [1]

Why it can bypass auth (mechanics)

In gRPC-Go’s xDS RBAC implementation, RBAC matching is performed against values placed into metadata, including :path. The code populates :path from the gRPC method name (grpc.Method(ctx)) rather than from the raw incoming :path header. [2] If an attacker can influence the method string format such that it doesn’t match policy expectations (e.g., missing the leading slash), then policies that rely on matching may not trigger, and any configuration that effectively allows on non-match can be bypassed. [1]

Impact / when you are actually vulnerable

You are most likely exposed if all of the following are true:

  • You use gRPC-Go xDS RBAC / authorization (the experimental RBAC path described in the disclosure). [1]
  • Your effective authorization stance is fail-open on “unknown/unmatched method” (commonly: deny-list style policies where “no match” means “allow”). [1]

If you use allow-list style authorization (default-deny: “only explicitly allowed methods pass”), this specific issue is much less likely to become an auth bypass (though malformed :path should still be treated as suspicious input). [1]

Mitigations you can apply immediately

  • Fail closed: ensure your authorizer denies any request whose method/path is not recognized or does not match an expected canonical form. [1]
  • Enforce canonical gRPC method format at the edge (proxy / gateway / interceptor): reject any request where :path does not start with /.
  • Prefer ALLOW (default-deny) RBAC policy posture over DENY-only posture for method-level access control. [1]

Patch status (as of 2026-03-20)

Public discussion exists, but I did not find an official upstream gRPC-Go security advisory or fixed-version reference in the sources retrieved above; treat this as “track upstream and be ready to upgrade” once gRPC-Go publishes a fix/release.


Sources: [1] [2]


🌐 Web query:

google.golang.org/grpc v1.79.2 security vulnerability patched version

💡 Result:

For google.golang.org/grpc v1.79.2, the patched (non-vulnerable) version is v1.79.3. The gRPC-Go advisory GHSA-p77j-4mvh-x3m3 / CVE-2026-33186 lists affected versions < 1.79.3 and patched version 1.79.3. [1]

Sources:
[1] (github.com)

Citations:


Critical security vulnerability in google.golang.org/grpc v1.79.2: Upgrade to v1.79.3 or later.

GHSA-p77j-4mvh-x3m3 (CVE-2026-33186) is a critical authorization bypass in gRPC-Go caused by improper validation of the HTTP/2 :path pseudo-header. If an attacker sends a request with a malformed :path that omits the required leading slash (e.g., Service/Method instead of /Service/Method), path-based authorization interceptors may fail to match deny rules and incorrectly allow access. Upgrade immediately to v1.79.3+.

If an immediate upgrade is not possible, add an outermost interceptor that rejects any request where the method name is empty or does not start with /.

🧰 Tools
🪛 OSV Scanner (2.3.3)

[CRITICAL] 11-11: google.golang.org/grpc 1.79.2: gRPC-Go has an authorization bypass via missing leading slash in :path

(GHSA-p77j-4mvh-x3m3)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@go.mod` at line 11, The dependency google.golang.org/grpc pinned to v1.79.2
contains a critical auth bypass (CVE-2026-33186); update the module version in
go.mod to v1.79.3 or later to fix it. If you cannot upgrade immediately, add an
outermost unary and stream interceptor on your gRPC server (where you call
grpc.NewServer or configure interceptors) that rejects requests whose full
method string is empty or does not start with '/' to block malformed :path
values; after upgrading remove the temporary interceptor. Ensure you update
go.mod's google.golang.org/grpc entry and run go mod tidy to refresh the lock.

Comment on lines +1 to +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.
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Read-only consistency check for license references across repo artifacts.
fd -HI 'LICENSE*|README*|NOTICE*|COPYING*|go.mod|package.json|pyproject.toml|setup.py|pom.xml|Cargo.toml' .
rg -n -C2 'SPDX|license|Elastic|Apache|MIT|BSD|GPL|MPL' .

Repository: LerianStudio/lib-auth

Length of output: 3615


🏁 Script executed:

# Check README.md for license section
head -100 ./README.md | tail -50

# Check go.mod for license declaration
cat ./go.mod

# Search for any SPDX headers or old license references in code
rg -l 'SPDX-License-Identifier|Apache|MIT|BSD' --type-list | head -20
fd -e go -e ts -e js -e py | head -20 | xargs -I {} head -5 {}

Repository: LerianStudio/lib-auth

Length of output: 5048


🏁 Script executed:

# Check if README.md mentions license/Elastic
rg -i 'license|elastic' ./README.md -A 2 -B 2

# Search for SPDX headers in source files
rg 'SPDX-License-Identifier' 

# List all files in repo to check for conflicting licenses
find . -maxdepth 2 -type f \( -name "LICENSE*" -o -name "COPYING*" -o -name "NOTICE*" \)

# Check if any go.mod file has license field
rg 'license' ./go.mod

Repository: LerianStudio/lib-auth

Length of output: 74


Update README and source files to document Elastic License 2.0 adoption.

The Elastic License 2.0 file was added, but the license change is not documented elsewhere. README.md contains no license statement, source files have no SPDX headers, and go.mod includes no license metadata. This creates a compliance gap where downstream users and integrators remain unaware of the licensing restrictions (notably the hosted/managed service limitation). Add an explicit license section to README.md, include SPDX-License-Identifier headers in source files, and consider adding license metadata to go.mod for visibility.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@LICENSE` around lines 1 - 93, The repo added Elastic License 2.0 (LICENSE)
but lacked propagation; update README.md to add an explicit "License" section
that names "Elastic License 2.0" and briefly calls out the
hosted/managed-service restriction, add SPDX-License-Identifier: Elastic-2.0
headers to all source files (e.g., top of .go/.ts/.js files) and ensure go.mod
contains license metadata (module/comments or a license directive) so tooling
sees Elastic-2.0; search for README.md, go.mod and all source files to apply
these changes consistently and commit them alongside the LICENSE file.

Comment on lines +269 to +274
.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)"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

goreleaser --skip-publish deprecated flag

💡 Result:

goreleaser release --skip-publish was deprecated (since v1.21) as part of consolidating multiple --skip-* flags into a single --skip flag, and it was removed in GoReleaser v2.0 (2024-05-26). Use --skip=publish instead. [1]

Examples:

  • Before: goreleaser release --skip-validate --skip-publish
  • After: goreleaser release --skip=validate,publish (or --skip=validate --skip=publish) [1]

goreleaser release --help lists publish as a valid --skip option. [2]

Sources
[1] GoReleaser Deprecation notices (the --skip consolidation, incl. --skip-publish) (goreleaser.com)
[2] GoReleaser goreleaser release command docs (--skip valid options incl. publish) (goreleaser.com)

Citations:


Replace deprecated --skip-publish flag with --skip=publish.

The --skip-publish flag was deprecated in goreleaser v1.21 and removed entirely in v2.0 (2024-05-26). This will cause the command to fail with newer goreleaser versions.

♻️ Proposed fix
 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
+	goreleaser release --snapshot --skip=publish --clean
 	`@echo` "$(GREEN)$(BOLD)[ok]$(NC) Release snapshot created successfully$(GREEN) ✔️$(NC)"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.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)"
.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)"
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 269-269: Missing required phony target "all"

(minphony)


[warning] 269-269: Missing required phony target "test"

(minphony)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` around lines 269 - 274, Update the goreleaser Makefile target
"goreleaser" to replace the removed flag form "--skip-publish" with the new
"--skip=publish"; specifically, in the command invoked by the goreleaser target
(the line that currently runs "goreleaser release --snapshot --skip-publish
--clean"), change the flag to "--skip=publish" so the release snapshot command
works with goreleaser v1.21+ and v2.0.

Comment on lines +221 to +230
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; \
Copy link

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Regex conversion for .ignorecoverunit patterns is basic.

The sed substitutions on lines 225-225 convert .\. and *.*, which handles the documented patterns (*_mock.go). However, this won't correctly handle more complex glob patterns or paths containing regex metacharacters like +, ?, [, etc.

This is acceptable for the current use case, but consider documenting this limitation in .ignorecoverunit or using a more robust glob-to-regex conversion if patterns become more complex.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@mk/tests.mk` around lines 221 - 230, The current glob-to-regex conversion in
mk/tests.mk (the sed pipeline that builds regex_patterns from patterns read from
.ignorecoverunit) only escapes '.' and converts '*' to '.*', so it fails on
other glob metacharacters (e.g., '+', '?', '[]') — update the file to either (A)
document this limitation immediately above the block that defines
patterns/regex_patterns and explain acceptable pattern syntax for
.ignorecoverunit, or (B) replace the simple sed conversion that produces
regex_patterns with a more robust glob-to-regex conversion (e.g., a small
perl/python one-liner or utility) that properly escapes regex metacharacters
while translating globs; ensure the rest of the flow (reading patterns into
patterns, filtering unit_coverage.out into unit_coverage_filtered.out, and mv
back) still uses the new regex_patterns variable.

qnen and others added 2 commits March 20, 2026 18:58
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
…code

fix(auth/middleware): handle numeric code field in auth error response
@qnen qnen temporarily deployed to create_release March 20, 2026 22:04 — with GitHub Actions Inactive
## [2.5.0-beta.9](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](165db5f))
@lerian-studio-midaz-push-bot
Copy link

🎉 This PR is included in version 2.5.0-beta.9 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
auth/middleware/middleware.go (1)

160-166: ⚠️ Potential issue | 🟠 Major

Add HTTP timeouts to all outbound auth-service clients.

All three http.Client{} instances in this file (lines 160, 260, 403) lack timeout configuration. Clients without timeouts can hang indefinitely on network stalls, which risks goroutine exhaustion and service unavailability under load.

💡 Proposed fix
@@
 const (
 	normalUser string = "normal-user"
 	pluginName string = "plugin-auth"
+	defaultHTTPTimeout        = 5 * time.Second
 )
@@
-	client := &http.Client{}
+	client := &http.Client{Timeout: defaultHTTPTimeout}
@@
-	client := &http.Client{}
+	client := &http.Client{Timeout: defaultHTTPTimeout}
@@
-	client := &http.Client{}
+	client := &http.Client{Timeout: defaultHTTPTimeout}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@auth/middleware/middleware.go` around lines 160 - 166, The three outbound
HTTP clients created as client := &http.Client{} in middleware.go (the client
used to GET healthURL and the other two client instances at the other locations)
lack timeouts and can hang; update each client construction to set a sensible
Timeout (e.g. replace &http.Client{} with &http.Client{Timeout:
httpClientTimeout} or a literal like 5*time.Second), make the timeout
configurable via a package-level const/var (httpClientTimeout) or existing
config, and consider reusing a single shared http.Client instead of creating
per-request clients; ensure the time package is imported if needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@auth/middleware/middleware.go`:
- Around line 160-166: The three outbound HTTP clients created as client :=
&http.Client{} in middleware.go (the client used to GET healthURL and the other
two client instances at the other locations) lack timeouts and can hang; update
each client construction to set a sensible Timeout (e.g. replace &http.Client{}
with &http.Client{Timeout: httpClientTimeout} or a literal like 5*time.Second),
make the timeout configurable via a package-level const/var (httpClientTimeout)
or existing config, and consider reusing a single shared http.Client instead of
creating per-request clients; ensure the time package is imported if needed.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f31cbe06-e3a5-467f-be80-815efca4a0b5

📥 Commits

Reviewing files that changed from the base of the PR and between 72bfae4 and a22c8aa.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • auth/middleware/middleware.go

@lerian-studio-midaz-push-bot
Copy link

🎉 This PR is included in version 2.5.0-beta.10 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

@jeffersonrodrigues92 jeffersonrodrigues92 self-requested a review March 21, 2026 21:17
@ClaraTersi ClaraTersi merged commit bff6723 into main Mar 21, 2026
18 of 19 checks passed
@lerian-studio-midaz-push-bot
Copy link

🎉 This PR is included in version 2.5.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants