feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: add tls and api key authentication support - #1

Merged
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth
Mar 21, 2026
Merged

feat: add tls and api key authentication support#1
vieiralucas merged 7 commits into
mainfrom
feat/tls-api-key-auth

Conversation

@vieiralucas

@vieiralucasvieiralucas commented Mar 21, 2026

Copy link
Copy Markdown
Member

Summary

Add TLS and API key authentication support to the Java SDK, achieving feature parity with the Rust SDK (Epic 15).

  • withTlsCaCert() for server-side TLS verification
  • withTlsClientCert() for mTLS
  • withApiKey() for Bearer token auth via ApiKeyInterceptor
  • Backward compatible: no auth options = same behavior as before

Test plan

  • Unit tests pass (builder, invalid cert handling)
  • Integration tests pass with TLS+auth-enabled fila-server
  • Auth rejection test validates UNAUTHENTICATED response

🤖 Generated with Claude Code


Summary by cubic

Adds TLS (system trust, custom CA, and mTLS) and API key auth to the Java SDK so clients can connect securely and authenticate. Backward compatible: without options, the client still uses plaintext with no auth.

  • New Features

    • FilaClient.Builder: withTls(), withTlsCaCert(byte[]), withTlsClientCert(byte[], byte[]), withApiKey(String) (Bearer via ApiKeyInterceptor)
    • Uses io.grpc.TlsChannelCredentials; sends API key in authorization metadata on every RPC
    • withTlsCaCert() implies TLS; withTls() uses the JVM default trust store
    • proto/fila/v1/admin.proto: Create/Revoke/List API keys, Set/Get ACL; added cluster fields to stats and queue info
    • README examples for system trust, custom CA, mTLS, and API keys; unit and integration tests for TLS + auth
  • Bug Fixes

    • Fail fast when a client cert is provided without TLS; keep throwing FilaException to avoid breaking callers
    • Catch IllegalArgumentException from TLS trust manager for invalid certs
    • Parse host/port before TLS setup; support IPv6 bracket addresses
    • Fix TLS-only test to assert UNAUTHENTICATED without an API key
    • Revert PATH-based binary lookup to keep TLS tests skipped in CI until infra is ready
    • Apply spotless formatting

Written for commit 82eef1c. Summary will update on new commits.

Add TLS (withTlsCaCert, withTlsClientCert) and API key auth (withApiKey)
builder methods to FilaClient. Uses grpc-java TlsChannelCredentials for
TLS and a ClientInterceptor for Bearer token auth. Update admin.proto
with API key and ACL management RPCs. All options are optional and
backward compatible — plaintext without auth remains the default.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

7 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="README.md">
<violation number="1" location="README.md:54">
P2: Use try-with-resources in the new client-construction examples so copied code closes `FilaClient` correctly.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:273">
P1: Setting client cert/key without a CA cert silently falls back to a plaintext connection, discarding the mTLS configuration with no error. Add a validation check at the start of `build()` to fail fast when `clientCertPem` is set but `caCertPem` is null.</violation>
<violation number="2" location="src/main/java/dev/faisca/fila/FilaClient.java:308">
P2: `parseHost`/`parsePort` break on IPv6 addresses. `lastIndexOf(':')` finds a colon inside the IPv6 address itself, corrupting both the host and port. Consider using `URI` parsing or at minimum handling the `[host]:port` bracket convention.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:45">
P2: `connectWithTlsOnly` still sets an API key, so it does not validate TLS-only behavior and can miss regressions in no-auth TLS handling.</violation>
<violation number="2" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:95">
P2: `rejectWithoutApiKey` should assert `UNAUTHENTICATED`, not just any `RpcException`, to ensure auth rejection is what is being tested.</violation>
</file>
<file name="proto/fila/v1/admin.proto">
<violation number="1" location="proto/fila/v1/admin.proto:15">
P1: Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:115">
P2: Binary availability check does not handle executables on PATH, causing TLS/auth integration tests to be skipped incorrectly.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);

// API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.

@cubic-dev-aicubic-dev-aiBotMar 21, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Unauthenticated CreateApiKey can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call CreateApiKey(is_superadmin=true) and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow is_superadmin on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At proto/fila/v1/admin.proto, line 15:
<comment>Unauthenticated `CreateApiKey` can create superadmin keys. Since this RPC bypasses auth (per the comment), any network-reachable client can call `CreateApiKey(is_superadmin=true)` and obtain a key that bypasses all ACL checks. Consider restricting the unauthenticated bootstrap path—e.g., only allow it when no keys exist yet, or disallow `is_superadmin` on unauthenticated calls—so that an open bootstrap endpoint cannot be exploited post-setup.</comment>
<file context>
@@ -11,6 +11,15 @@ service FilaAdmin {
rpc Redrive(RedriveRequest) returns (RedriveResponse);
rpc ListQueues(ListQueuesRequest) returns (ListQueuesResponse);
+
+ // API key management. CreateApiKey bypasses auth (bootstrap); others require a valid key.
+ rpc CreateApiKey(CreateApiKeyRequest) returns (CreateApiKeyResponse);
+ rpc RevokeApiKey(RevokeApiKeyRequest) returns (RevokeApiKeyResponse);
</file context>
Fix with Cubic

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

This is a server-side authorization concern, not a client SDK issue. The Fila server handles this through the bootstrap_apikey mechanism: when auth is enabled, CreateApiKey requires a valid bootstrap key (configured via config or env var). The proto definition must match the server's proto — changing it here would break compatibility. The SDK is just a client; it doesn't make authorization decisions.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the feedback! I've saved this as a new learning to improve future reviews.

Comment threadREADME.md Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TestServer.java
- catch IllegalArgumentException from TLS trustManager for invalid certs (fixes CI build failure)
- validate client cert requires CA cert — fail fast instead of silent plaintext fallback
- handle IPv6 bracket notation in address parsing
- fix connectWithTlsOnly test to actually test without API key
- assert UNAUTHENTICATED status code in rejectWithoutApiKey test
- handle PATH-based binary lookup in TestServer.isBinaryAvailable
- use try-with-resources in README examples

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

3 issues found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/test/java/dev/faisca/fila/TestServer.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TestServer.java:122">
P2: Binary detection for PATH commands is platform-dependent because it hard-codes `which`; environments without `which` will incorrectly report the server binary as unavailable.</violation>
</file>
<file name="src/test/java/dev/faisca/fila/TlsAuthClientTest.java">
<violation number="1" location="src/test/java/dev/faisca/fila/TlsAuthClientTest.java:84">
P2: `connectWithTlsOnly()` asserts only exception type, so it can pass on non-auth failures. Assert `UNAUTHENTICATED` to verify the intended behavior.</violation>
</file>
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:297">
P2: This catch is too broad: malformed address/port errors are misreported as "invalid certificate" because `NumberFormatException` is also an `IllegalArgumentException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/test/java/dev/faisca/fila/TestServer.java Outdated
Comment threadsrc/test/java/dev/faisca/fila/TlsAuthClientTest.java Outdated
Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java
- move parseHost/parsePort before tls try block so NumberFormatException
from malformed addresses is not misreported as "invalid certificate"
- assert UNAUTHENTICATED status code in connectWithTlsOnly test instead
of only checking exception type
Add withTls() builder method that enables TLS using the JVM's default
trust store (cacerts), so users with servers using public CA certs
don't need to pass caCert manually. withTlsCaCert() now implies
withTls(). Client cert validation updated to require either method.

@cubic-dev-aicubic-dev-aiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 issue found across 3 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="src/main/java/dev/faisca/fila/FilaClient.java">
<violation number="1" location="src/main/java/dev/faisca/fila/FilaClient.java:288">
P2: Changing this validation from `FilaException` to `IllegalStateException` is a breaking behavior change for callers that consistently handle SDK errors via `FilaException`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment threadsrc/main/java/dev/faisca/fila/FilaClient.java Outdated
Cubic identified that changing the exception type from FilaException
to IllegalStateException is a breaking change for callers that catch
FilaException consistently. Reverted to FilaException.
@vieiralucas
vieiralucas merged commit 90be229 into mainMar 21, 2026
2 checks passed
@vieiralucas
vieiralucas deleted the feat/tls-api-key-auth branch March 24, 2026 13:16
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@vieiralucas