Skip to content

Add feature flag to enable shared cache#39

Open
KevinGruber2001 wants to merge 18 commits intomainfrom
38-integrate-shared-cache-node-into-theia-cloud
Open

Add feature flag to enable shared cache#39
KevinGruber2001 wants to merge 18 commits intomainfrom
38-integrate-shared-cache-node-into-theia-cloud

Conversation

@KevinGruber2001
Copy link

@KevinGruber2001 KevinGruber2001 commented Nov 16, 2025

In this PR a feature flag is added to the Theia Cloud Operator, to mount a gradle configureation file into the Thea IDEs to enable them to access the remote cache.

At the moment, no authorization is configured. Which means that the Remote Gradle Cache needs to allow anonymouse access

Summary by CodeRabbit

  • New Features
    • Configurable remote caching: enable/disable flag, remote cache URL, and cache-push control.
    • Exposed env vars for cache management (REMOTE_CACHE_ENABLED, REMOTE_CACHE_URL, REMOTE_CACHE_PUSH) and build/runtime trust (NODE_EXTRA_CA_CERTS, GRADLE_OPTS).
    • Automatic TLS/trust configuration for HTTPS cache URLs, with an optional mounted trust-bundle for workloads.

@coderabbitai
Copy link

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

Adds remote caching configuration: two new operator arguments (enableCaching, cacheUrl), exposes them via accessors, propagates into template replacement placeholders, and updates deployment templates with cache-related env vars, optional TLS trust bundle mounts, and related placeholders.

Changes

Cohort / File(s) Summary
Operator arguments
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/TheiaCloudOperatorArguments.java
Added fields enableCaching (boolean, default false) and cacheUrl (String), accessors isEnableCaching() / getCacheUrl(), and included them in hashCode(), equals(), and toString().
Handler import
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java
Added import for TheiaCloudOperatorArguments. No behavioral changes.
Template replacement logic
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java
Added placeholders: PLACEHOLDER_ENV_CACHE_ENABLED, PLACEHOLDER_ENV_CACHE_URL, PLACEHOLDER_ENV_CACHE_PUSH, and trust-related placeholders (PLACEHOLDER_CA_BUNDLE_PEM_PATH, PLACEHOLDER_GRADLE_TRUST_OPTS, PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH, PLACEHOLDER_TRUST_BUNDLE_CONFIGMAP). Implemented conditional logic to populate cache env placeholders and trust/mount placeholders when caching is enabled and cacheUrl indicates HTTPS.
Deployment templates
java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml, java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml
Added env vars REMOTE_CACHE_ENABLED, REMOTE_CACHE_URL, REMOTE_CACHE_PUSH, plus NODE_EXTRA_CA_CERTS and GRADLE_OPTS. Added optional trust-bundle volume and corresponding volumeMount (mount path and ConfigMap name are placeholders).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant CLI as Operator CLI
    participant Operator as TheiaCloudOperator
    participant Replacer as TemplateReplacer
    participant K8s as Kubernetes API
    participant Container as App Container

    CLI->>Operator: start with args (enableCaching, cacheUrl)
    Operator->>Replacer: provide AppDefinition + caching args
    Replacer->>Replacer: set placeholders (cache-enabled/url/push, trust mounts if https)
    Replacer->>K8s: submit Deployment manifest with envs/volumes replaced
    K8s->>Container: container receives REMOTE_CACHE_* envs and optional trust bundle
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I hopped in with flags and a curious cheer,
A cache and a URL have quietly appeared,
Placeholders tucked into deployment beds,
Trust bundles nest where HTTPS treads,
Operator hummed — configuration clear.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.69% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add feature flag to enable shared cache' accurately describes the main change - adding a feature flag (enableCaching) to support shared cache functionality in the Theia Cloud Operator.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 38-integrate-shared-cache-node-into-theia-cloud

No actionable comments were generated in the recent review. 🎉

🧹 Recent nitpick comments
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java (1)

176-180: Hardcoded trust store paths, password, and ConfigMap name reduce configurability.

The trust store password (changeit), paths (/etc/ssl/theia-trust/...), and ConfigMap name (theia-internal-trust) are all hardcoded. While changeit is the standard Java default, coupling these values here makes it difficult to adapt to different cluster setups without code changes.

Consider extracting these as operator arguments or at least as named constants, similar to how other configurable values (e.g., arguments.getKeycloakURL()) are handled. This can be deferred to a follow-up if needed.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@KevinGruber2001 KevinGruber2001 moved this from Milestone 1 to In Progress in Scalable Cloud Tools Project Jan 17, 2026
@KevinGruber2001 KevinGruber2001 marked this pull request as ready for review January 17, 2026 20:13
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java`:
- Around line 57-61: Remove the unused imports in AddedHandlerUtil: delete the
import lines for ConfigMapVolumeSource, ObjectMeta, OwnerReference, Volume, and
VolumeMount since they are not referenced anywhere in the AddedHandlerUtil
class; update the import block accordingly so only used classes remain and run a
quick compile or IDE organize-imports to ensure no other unused imports remain.

In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/EagerSessionHandler.java`:
- Around line 165-175: The comment and warning in EagerSessionHandler around the
try block misleadingly state that a per-session gradle.properties/init config is
created and mounted, but AddedHandlerUtil.configureGradleCaching only injects
environment variables; update the comment and the LOGGER.warn message to
accurately state that configureGradleCaching injects env vars into the
deployment (refer to AddedHandlerUtil.configureGradleCaching and
deploymentName), or if mounting gradle.properties was intended implement the
mount logic instead of calling configureGradleCaching; adjust the text in the
try-block comment and the formatLogMessage call so logs reflect the actual
behavior.
🧹 Nitpick comments (3)
java/operator/.idea/workspace.xml (1)

1-24: IDE configuration file should not be committed.

The .idea/workspace.xml file contains user-specific and machine-specific IntelliJ IDEA settings that should not be tracked in version control. These files can cause merge conflicts and clutter the repository.

♻️ Recommended fix
  1. Remove this file from the PR:

    git rm --cached java/operator/.idea/workspace.xml
  2. Ensure .idea/workspace.xml is in your .gitignore:

    +**/workspace.xml

Note: Project-level .idea files (like codeStyles, runConfigurations) can be shared, but workspace.xml contains user-specific settings and should always be excluded.

java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/TheiaCloudOperatorArguments.java (1)

125-131: Consider defaulting enableCaching to false for safer rollout.

Enabling caching by default (enableCaching = true) changes behavior for all existing deployments upon upgrade. This could cause unexpected issues if the cache service isn't deployed. A safer approach would be to default to false and require explicit opt-in.

Additionally, the default cacheUrl uses HTTP. While this may be acceptable for internal cluster communication, the PR description mentions "switching the default cache URL to use TLS." If HTTPS is intended, update the default accordingly.

Suggested changes
 `@Option`(names = {
         "--enableCaching" }, description = "Whether to enable caching of Theia application containers.", required = false)
-private boolean enableCaching = true;
+private boolean enableCaching = false;

 `@Option`(names = {
-        "--cacheUrl" }, description = "The URL of the remote cache server.", required = false, defaultValue = "http://theia-cloud-combined-cache:8080/cache/")
+        "--cacheUrl" }, description = "The URL of the remote cache server.", required = false, defaultValue = "https://theia-cloud-combined-cache:8080/cache/")
 private String cacheUrl;
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java (1)

260-317: Implementation looks correct, with a few considerations.

The method properly configures Gradle caching environment variables. A few observations:

  1. Duplicate env vars risk: If this method is called multiple times on the same deployment (e.g., during retries), it will add duplicate environment variables. Consider checking for existing env vars before adding or clearing them first.

  2. Hardcoded push permission: GRADLE_REMOTE_CACHE_PUSH is hardcoded to "true". The comment at line 306 acknowledges this could be made configurable. For a read-only cache scenario, this would need to be false.

Optional: Prevent duplicate env vars
+    private static void setOrReplaceEnvVar(Container container, String name, String value) {
+        container.getEnv().removeIf(env -> name.equals(env.getName()));
+        EnvVar envVar = new EnvVar();
+        envVar.setName(name);
+        envVar.setValue(value);
+        container.getEnv().add(envVar);
+    }
+
     public static void configureGradleCaching(String correlationId, Deployment deployment,
                                               AppDefinition appDefinition,
                                               TheiaCloudOperatorArguments arguments) {
         // ... existing code to find container and init env list ...

-        // Always set the ENABLED variable for explicit control
-        EnvVar cacheEnabledEnv = new EnvVar();
-        cacheEnabledEnv.setName("GRADLE_REMOTE_CACHE_ENABLED");
-        cacheEnabledEnv.setValue(String.valueOf(cachingEnabled));
-        container.getEnv().add(cacheEnabledEnv);
+        setOrReplaceEnvVar(container, "GRADLE_REMOTE_CACHE_ENABLED", String.valueOf(cachingEnabled));

         if (cachingEnabled) {
-            // Set cache URL
-            EnvVar cacheUrlEnv = new EnvVar();
-            cacheUrlEnv.setName("GRADLE_REMOTE_CACHE_URL");
-            cacheUrlEnv.setValue(arguments.getCacheUrl().trim());
-            container.getEnv().add(cacheUrlEnv);
-
-            // Set push permission (default: true, could be made configurable)
-            EnvVar cachePushEnv = new EnvVar();
-            cachePushEnv.setName("GRADLE_REMOTE_CACHE_PUSH");
-            cachePushEnv.setValue("true");
-            container.getEnv().add(cachePushEnv);
+            setOrReplaceEnvVar(container, "GRADLE_REMOTE_CACHE_URL", arguments.getCacheUrl().trim());
+            setOrReplaceEnvVar(container, "GRADLE_REMOTE_CACHE_PUSH", "true");
             // ...
         }
     }

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java`:
- Around line 253-295: The configureRemoteCaching method currently always
appends REMOTE_CACHE_* EnvVar entries causing duplicates and leaving stale
REMOTE_CACHE_URL/REMOTE_CACHE_PUSH when caching is turned off; update
configureRemoteCaching to upsert env vars by name in the container's env list
(use findContainerIdxInDeployment to locate the container and container.getEnv()
to operate on the list), i.e. if an EnvVar with name
"REMOTE_CACHE_ENABLED"/"REMOTE_CACHE_URL"/"REMOTE_CACHE_PUSH" exists update its
value, otherwise add it; when cachingEnabled is false ensure you remove any
existing "REMOTE_CACHE_URL" and "REMOTE_CACHE_PUSH" entries (and only
set/override "REMOTE_CACHE_ENABLED" to "false"), avoiding duplicate entries on
redeploys.
🧹 Nitpick comments (1)
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/session/LazySessionHandler.java (1)

472-476: Fix indentation to match the surrounding lambda body.

The new code has inconsistent indentation compared to the rest of the lambda body (lines 459-470 and 478-481). This should be aligned to match the existing code style within the lambda.

Additionally, the comment on line 475 is slightly misleading—configureRemoteCaching is called unconditionally and always sets REMOTE_CACHE_ENABLED (to either "true" or "false"). Consider rewording to clarify that configuration is always applied:

Suggested fix for indentation and comment
-            AddedHandlerUtil.addCustomEnvVarsToDeploymentFromSession(correlationId, deployment, session,
-                appDefinition);
-
-            // If caching is enabled, configure remote build cache via environment variables
-            AddedHandlerUtil.configureRemoteCaching(correlationId, deployment, appDefinition, arguments);
+                    AddedHandlerUtil.addCustomEnvVarsToDeploymentFromSession(correlationId, deployment, session,
+                            appDefinition);
+
+                    // Configure remote build cache environment variables (enabled/disabled based on arguments)
+                    AddedHandlerUtil.configureRemoteCaching(correlationId, deployment, appDefinition, arguments);

Copy link

@lukaskratzel lukaskratzel left a comment

Choose a reason for hiding this comment

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

I think you could handle this in a simpler way by setting the environment variables directly in the deployment template, which I have done so far for all my changes touching on environment variables. You can find the relevant template file here: java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml

The replacements for the templates are handled through this file: java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/TheiaCloudHandlerUtil.java.

But if that doesn't work for you we can also try this approach.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java`:
- Around line 162-186: The cache URL is inconsistently handled: trim the value
once and reuse it rather than calling arguments.getCacheUrl() twice; change both
checks to use a local String (e.g., cacheUrl = arguments.getCacheUrl() == null ?
"" : arguments.getCacheUrl().trim()) and then use cacheUrl.isEmpty() and
cacheUrl.startsWith("https://") for the HTTPS branch; update the conditional
expressions that set PLACEHOLDER_ENV_CACHE_* and the trust bundle block in
DefaultDeploymentTemplateReplacements to reference this trimmed cacheUrl and the
stricter startsWith("https://") check to avoid mismatches and duplication.

In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml`:
- Around line 100-107: The template currently always emits a volumeMount for
name "trust-bundle" with mountPath set to the placeholder
"placeholder-trust-bundle-mount-path", which can become an empty string and
produce an invalid pod spec; update the templateDeployment.yaml to omit the
entire volumeMount entry when the trust bundle is disabled (i.e., when the
placeholder resolves to empty). Specifically, make the volumeMount conditional
(or filter out entries) so that the "trust-bundle" volumeMount is only included
when the NODE_EXTRA_CA_CERTS/GRADLE_OPTS trust configuration provides a
non-empty mount path, or implement a post-render step that removes volumeMounts
with an empty mountPath before creating the Deployment.

In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml`:
- Around line 73-78: The REMOTE_CACHE_PUSH environment variable in
templateDeploymentWithoutOAuthProxy.yaml allows anonymous cache push which can
enable untrusted clients to inject poisoned cache entries; change the default
placeholder for REMOTE_CACHE_PUSH to "false" (disable push by default) in the
Deployment template (the REMOTE_CACHE_PUSH env entry) and add a prominent note
in the README/PR description indicating that enabling push requires
authenticated remote-cache access and must not be enabled without proper auth;
ensure any rollout/upgrade logic that reads REMOTE_CACHE_PUSH treats
missing/placeholder values as false.
- Around line 85-92: The template renders empty trust-bundle env vars and a
volumeMount even when caching/remote cache is disabled, producing invalid
Kubernetes YAML (empty NODE_EXTRA_CA_CERTS, GRADLE_OPTS, and mountPath). Update
the templateDeploymentWithoutOAuthProxy.yaml to conditionally omit the
NODE_EXTRA_CA_CERTS and GRADLE_OPTS env entries and the trust-bundle volumeMount
(name "trust-bundle" / mountPath) unless remote caching is enabled (or the
resolved PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH is non-empty); alternatively move
the guard into the code that replaces PLACEHOLDER_CA_BUNDLE_PEM_PATH,
PLACEHOLDER_GRADLE_TRUST_OPTS, and PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH so they
are not set to empty strings but removed when REMOTE_CACHE_ENABLED is
false—ensure the volumeMount and env vars are only rendered when the mountPath
and trust options are present.
🧹 Nitpick comments (2)
java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java (1)

176-180: Hardcoded paths, configmap name, and truststore password.

The trust bundle mount path, PEM path, JKS path, configmap name (theia-internal-trust), and truststore password (changeit) are all hardcoded inline. Consider:

  • Extracting these as named constants at minimum for maintainability and grep-ability.
  • Making the configmap name configurable via operator arguments, since cluster operators may already have a trust bundle configmap under a different name.
  • The changeit password is Java's well-known default, but embedding credentials in source is a code smell. If this JKS is generated at runtime, document that assumption; otherwise consider making the password configurable.
java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml (1)

86-91: Cache and trust-bundle configuration is added unconditionally to all deployments.

The remote cache env vars (lines 86–91), trust-bundle volumeMount (lines 104–107), and trust-bundle volume (lines 123–126) are baked into the template regardless of whether the enableCaching flag is set. This means every Theia deployment will carry these entries even when caching is not used.

This is acceptable if the placeholder replacement logic substitutes benign defaults (e.g., empty strings, "false") when caching is disabled. However, it adds noise to every deployment manifest. Consider whether conditional injection at the Java level (similar to how placeholder-monitor-port appears to be handled) would be cleaner for keeping non-caching deployments uncluttered.

Also applies to: 123-126

Comment on lines 162 to 186
if (arguments.isEnableCaching() && arguments.getCacheUrl() != null
&& !arguments.getCacheUrl().trim().isEmpty()) {
environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "true");
environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, arguments.getCacheUrl().trim());
environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "true");
} else {
environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "false");
environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, "");
environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "false");
}

if (arguments.isEnableCaching() && arguments.getCacheUrl() != null
&& arguments.getCacheUrl().startsWith("https")) {
// Only set trust config when using HTTPS for the cache
environmentVariables.put(PLACEHOLDER_CA_BUNDLE_PEM_PATH, "/etc/ssl/theia-trust/trust-bundle.pem");
environmentVariables.put(PLACEHOLDER_GRADLE_TRUST_OPTS,
"-Djavax.net.ssl.trustStore=/etc/ssl/theia-trust/truststore.jks -Djavax.net.ssl.trustStorePassword=changeit");
environmentVariables.put(PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH, "/etc/ssl/theia-trust");
environmentVariables.put(PLACEHOLDER_TRUST_BUNDLE_CONFIGMAP, "theia-internal-trust");
} else {
environmentVariables.put(PLACEHOLDER_CA_BUNDLE_PEM_PATH, "");
environmentVariables.put(PLACEHOLDER_GRADLE_TRUST_OPTS, "");
environmentVariables.put(PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH, "");
environmentVariables.put(PLACEHOLDER_TRUST_BUNDLE_CONFIGMAP, "");
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Inconsistent URL handling between the two caching blocks.

Two issues:

  1. Missing trim() in the HTTPS check (Line 174): The first block (Line 165) trims the URL before use, but the second block checks arguments.getCacheUrl().startsWith("https") on the raw value. A URL with leading whitespace (e.g., " https://...") would pass the first block but fail the HTTPS detection.

  2. startsWith("https") is too loose (Line 174): This would also match nonsensical values like "httpsnotaurl". Use startsWith("https://") instead.

Consider extracting the trimmed URL and the shared condition to reduce duplication:

Proposed fix
-        if (arguments.isEnableCaching() && arguments.getCacheUrl() != null
-                && !arguments.getCacheUrl().trim().isEmpty()) {
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "true");
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, arguments.getCacheUrl().trim());
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "true");
-        } else {
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "false");
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, "");
-            environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "false");
-        }
-
-        if (arguments.isEnableCaching() && arguments.getCacheUrl() != null
-                && arguments.getCacheUrl().startsWith("https")) {
+        String cacheUrl = arguments.getCacheUrl() != null ? arguments.getCacheUrl().trim() : "";
+        boolean cachingEnabled = arguments.isEnableCaching() && !cacheUrl.isEmpty();
+
+        if (cachingEnabled) {
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "true");
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, cacheUrl);
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "true");
+        } else {
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_ENABLED, "false");
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_URL, "");
+            environmentVariables.put(PLACEHOLDER_ENV_CACHE_PUSH, "false");
+        }
+
+        if (cachingEnabled && cacheUrl.startsWith("https://")) {
🤖 Prompt for AI Agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java`
around lines 162 - 186, The cache URL is inconsistently handled: trim the value
once and reuse it rather than calling arguments.getCacheUrl() twice; change both
checks to use a local String (e.g., cacheUrl = arguments.getCacheUrl() == null ?
"" : arguments.getCacheUrl().trim()) and then use cacheUrl.isEmpty() and
cacheUrl.startsWith("https://") for the HTTPS branch; update the conditional
expressions that set PLACEHOLDER_ENV_CACHE_* and the trust bundle block in
DefaultDeploymentTemplateReplacements to reference this trimmed cacheUrl and the
stricter startsWith("https://") check to avoid mismatches and duplication.

Comment on lines +100 to +107
- name: NODE_EXTRA_CA_CERTS
value: placeholder-ca-bundle-pem-path
- name: GRADLE_OPTS
value: placeholder-gradle-trust-opts
volumeMounts:
- name: trust-bundle
mountPath: placeholder-trust-bundle-mount-path
readOnly: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "*DefaultDeploymentTemplateReplacements*" -o -name "*TheiaCloudOperatorArguments*" | head -20

Repository: ls1intum/theia-cloud

Length of output: 344


🏁 Script executed:

fd -t f "DefaultDeploymentTemplateReplacements|TheiaCloudOperatorArguments" --extension java

Repository: ls1intum/theia-cloud

Length of output: 340


🏁 Script executed:

wc -l ./java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java ./java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/TheiaCloudOperatorArguments.java

Repository: ls1intum/theia-cloud

Length of output: 368


🏁 Script executed:

cat -n ./java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/DefaultDeploymentTemplateReplacements.java

Repository: ls1intum/theia-cloud

Length of output: 18935


🏁 Script executed:

cat -n ./java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/TheiaCloudOperatorArguments.java

Repository: ls1intum/theia-cloud

Length of output: 20955


🏁 Script executed:

cat -n java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml | head -150

Repository: ls1intum/theia-cloud

Length of output: 5433


🏁 Script executed:

cat -n java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml | sed -n '90,130p'

Repository: ls1intum/theia-cloud

Length of output: 1624


🏁 Script executed:

# Search for how mountPath is used elsewhere and if there are any guards for empty values
rg "mountPath" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/ -A 1 -B 1

Repository: ls1intum/theia-cloud

Length of output: 1936


🏁 Script executed:

# Check if there's any YAML validation or post-processing that might handle empty mountPath
fd ".*\.java" java/operator/org.eclipse.theia.cloud.operator/src/main/java --exec rg -l "mountPath|volumeMount" {} \;

Repository: ls1intum/theia-cloud

Length of output: 332


🏁 Script executed:

# Check if there's any YAML post-processing or validation that strips empty volumeMounts
find . -type f -name "*.java" -path "*/operator/*" | xargs rg -l "volumeMount|replaceAll|placeholder" | head -10

Repository: ls1intum/theia-cloud

Length of output: 1139


🏁 Script executed:

# Look at how the YAML is actually deployed - search for deployment creation methods
rg -A 10 -B 5 "createDeployment|applyDeployment" java/operator/org.eclipse.theia.cloud.operator/src/main/java --type java | head -100

Repository: ls1intum/theia-cloud

Length of output: 17790


🏁 Script executed:

# Find and examine the removeEmptyResources method which may handle empty values
rg -A 30 "removeEmptyResources" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/AddedHandlerUtil.java

Repository: ls1intum/theia-cloud

Length of output: 224


🏁 Script executed:

fd -t f "AddedHandlerUtil" java/operator/org.eclipse.theia.cloud.operator/src/main/java

Repository: ls1intum/theia-cloud

Length of output: 187


🏁 Script executed:

# Search for removeEmptyResources method
rg -B 5 -A 30 "removeEmptyResources" java/operator/org.eclipse.theia.cloud.operator/src/main/java/

Repository: ls1intum/theia-cloud

Length of output: 18734


🏁 Script executed:

# Check if removeEmptyResources handles volumeMounts or environment variables
wc -l java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java

Repository: ls1intum/theia-cloud

Length of output: 191


🏁 Script executed:

# Read the entire removeEmptyResources method and surrounding code
cat -n java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java | sed -n '400,550p'

Repository: ls1intum/theia-cloud

Length of output: 46


🏁 Script executed:

# Read the entire removeEmptyResources method
cat -n java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/handler/AddedHandlerUtil.java | grep -A 60 "public static void removeEmptyResources"

Repository: ls1intum/theia-cloud

Length of output: 3640


🏁 Script executed:

# Search for how the template replacements are applied to YAML
rg -B 5 -A 15 "createDeployment.*template.*replacements" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/K8sResourceFactory.java | head -60

Repository: ls1intum/theia-cloud

Length of output: 3507


🏁 Script executed:

# Look for the actual string replacement logic
rg -B 5 -A 10 "replaceAll|replace\(" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/K8sResourceFactory.java | head -80

Repository: ls1intum/theia-cloud

Length of output: 46


🏁 Script executed:

# Find the loadTemplate method
rg -B 5 -A 25 "private.*String loadTemplate" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/K8sResourceFactory.java

Repository: ls1intum/theia-cloud

Length of output: 1162


🏁 Script executed:

# Find the readResourceAndReplacePlaceholders method
rg -B 5 -A 30 "readResourceAndReplacePlaceholders" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/util/JavaResourceUtil.java

Repository: ls1intum/theia-cloud

Length of output: 1950


Remove empty mountPath or conditionally include the volumeMount.

When caching is disabled or the cache URL doesn't use HTTPS, the placeholder-trust-bundle-mount-path placeholder is replaced with an empty string (""), resulting in:

volumeMounts:
  - name: trust-bundle
    mountPath: ""
    readOnly: true

An empty mountPath is invalid in Kubernetes and will be rejected by API validation. Either:

  1. Conditionally include this volumeMount only when trust configuration is enabled, or
  2. Remove empty volumeMounts during deployment creation (similar to how removeEmptyResources handles resource limits).

The trust-bundle ConfigMap and environment variables are correctly set to empty strings when disabled, but the volumeMount entry itself should not exist in the pod spec.

🤖 Prompt for AI Agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml`
around lines 100 - 107, The template currently always emits a volumeMount for
name "trust-bundle" with mountPath set to the placeholder
"placeholder-trust-bundle-mount-path", which can become an empty string and
produce an invalid pod spec; update the templateDeployment.yaml to omit the
entire volumeMount entry when the trust bundle is disabled (i.e., when the
placeholder resolves to empty). Specifically, make the volumeMount conditional
(or filter out entries) so that the "trust-bundle" volumeMount is only included
when the NODE_EXTRA_CA_CERTS/GRADLE_OPTS trust configuration provides a
non-empty mount path, or implement a post-render step that removes volumeMounts
with an empty mountPath before creating the Deployment.

Comment on lines +73 to +78
- name: REMOTE_CACHE_ENABLED
value: placeholder-cache-enabled
- name: REMOTE_CACHE_URL
value: placeholder-cache-url
- name: REMOTE_CACHE_PUSH
value: placeholder-cache-push
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Security note: anonymous cache push without authorization.

The PR description acknowledges that no authorization is configured, requiring anonymous access on the remote cache. However, REMOTE_CACHE_PUSH being enabled with anonymous access means any client (not just trusted builds) could push poisoned cache entries. Consider documenting this risk prominently or defaulting REMOTE_CACHE_PUSH to false until authentication is implemented.

🤖 Prompt for AI Agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml`
around lines 73 - 78, The REMOTE_CACHE_PUSH environment variable in
templateDeploymentWithoutOAuthProxy.yaml allows anonymous cache push which can
enable untrusted clients to inject poisoned cache entries; change the default
placeholder for REMOTE_CACHE_PUSH to "false" (disable push by default) in the
Deployment template (the REMOTE_CACHE_PUSH env entry) and add a prominent note
in the README/PR description indicating that enabling push requires
authenticated remote-cache access and must not be enabled without proper auth;
ensure any rollout/upgrade logic that reads REMOTE_CACHE_PUSH treats
missing/placeholder values as false.

Comment on lines +85 to +92
- name: NODE_EXTRA_CA_CERTS
value: placeholder-ca-bundle-pem-path
- name: GRADLE_OPTS
value: placeholder-gradle-trust-opts
volumeMounts:
- name: trust-bundle
mountPath: placeholder-trust-bundle-mount-path
readOnly: true
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check how the placeholder replacement logic handles cache-related and trust-bundle placeholders
# Look for the replacement constants and logic

echo "=== Searching for trust-bundle and cache placeholder replacement logic ==="
rg -n "placeholder-ca-bundle-pem-path|placeholder-gradle-trust-opts|placeholder-trust-bundle" --type java -C 3

echo ""
echo "=== Searching for cache-enabled replacement logic ==="
rg -n "cache-enabled|cacheUrl|enableCaching|REMOTE_CACHE_ENABLED" --type java -C 3

echo ""
echo "=== Looking for YAML template variable replacement logic ==="
rg -n "replaceAll|replace\(|NODE_EXTRA_CA_CERTS|GRADLE_OPTS" --type java -C 2 | head -100

Repository: ls1intum/theia-cloud

Length of output: 16217


🏁 Script executed:

#!/bin/bash
# Find where replacements are created and how trust-bundle placeholders are handled

echo "=== Finding methods in DefaultDeploymentTemplateReplacements that build replacements ==="
rg -n "PLACEHOLDER_CA_BUNDLE_PEM_PATH|PLACEHOLDER_GRADLE_TRUST_OPTS|PLACEHOLDER_TRUST_BUNDLE" --type java -B 5 -A 10

echo ""
echo "=== Looking for conditional logic based on enableCaching or cacheUrl ==="
rg -n "enableCaching|cacheUrl" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator/replacements/ --type java -B 3 -A 3

Repository: ls1intum/theia-cloud

Length of output: 9554


🏁 Script executed:

#!/bin/bash
# Check the YAML template to see if volumeMount is conditionally rendered

echo "=== Looking at the template file around lines 85-92 ==="
sed -n '80,100p' java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml

echo ""
echo "=== Checking for conditional YAML syntax in templates ==="
rg -n "if|else|#|volumeMount" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml -C 2 | head -80

echo ""
echo "=== Looking for volumeMounts section entirely ==="
rg -n "volumeMounts:" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml -A 10

Repository: ls1intum/theia-cloud

Length of output: 1952


🏁 Script executed:

#!/bin/bash
# Check the volumes section and understand the complete picture

echo "=== Looking at the volumes section ==="
sed -n '95,110p' java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml

echo ""
echo "=== Check the complete volumes section ==="
rg -n "volumes:" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml -A 15

Repository: ls1intum/theia-cloud

Length of output: 590


🏁 Script executed:

#!/bin/bash
# Verify if Kubernetes allows empty mountPath and check for any validation

echo "=== Check the entire env var section ==="
sed -n '70,92p' java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml

echo ""
echo "=== Look for any template processing or validation logic ==="
rg -n "mountPath|NODE_EXTRA_CA_CERTS|GRADLE_OPTS" java/operator/org.eclipse.theia.cloud.operator/src/main/java --type java -C 2 | head -50

Repository: ls1intum/theia-cloud

Length of output: 2645


🏁 Script executed:

#!/bin/bash
# Check if there are any other templates or conditional rendering mechanisms

echo "=== List all template files ==="
find java/operator/org.eclipse.theia.cloud.operator/src/main/resources -name "*.yaml" -o -name "*.yml"

echo ""
echo "=== Check if there's a template with OAuth proxy for comparison ==="
wc -l java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment*.yaml

echo ""
echo "=== Check if the OAuth proxy template has the same issue ==="
rg -n "NODE_EXTRA_CA_CERTS|GRADLE_OPTS|trust-bundle" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeployment.yaml -A 2 | head -40

Repository: ls1intum/theia-cloud

Length of output: 1951


🏁 Script executed:

#!/bin/bash
# Let me verify one more thing - check if there's any post-processing or validation of the generated YAML

echo "=== Look for YAML validation or processing after replacement ==="
rg -n "Deployment|validate|mountPath" java/operator/org.eclipse.theia.cloud.operator/src/main/java/org/eclipse/theia/cloud/operator --type java | grep -i "yaml\|mount\|validate" | head -20

echo ""
echo "=== Check how the template is used after replacement ==="
rg -n "applyTemplate|getDeploymentTemplate" java/operator/org.eclipse.theia.cloud.operator/src/main/java --type java -A 5 | head -40

Repository: ls1intum/theia-cloud

Length of output: 1859


🏁 Script executed:

#!/bin/bash
# Verify the actual issue - check if there are tests or documentation about this behavior

echo "=== Look for tests related to the deployment template or replacement logic ==="
find . -name "*Test.java" -o -name "*Tests.java" | xargs grep -l "DefaultDeploymentTemplateReplacements\|mountPath\|placeholder-trust-bundle" 2>/dev/null | head -5

echo ""
echo "=== Check if there's any issue tracking or comments about this ==="
rg -n "TODO|FIXME|BUG|empty|mountPath" java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml

echo ""
echo "=== Look at the entire env and volumeMounts section ==="
sed -n '70,105p' java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml

Repository: ls1intum/theia-cloud

Length of output: 1615


Empty trust-bundle configuration when caching is disabled creates invalid Kubernetes YAML.

When caching is disabled (or cache URL doesn't use HTTPS), the placeholder replacement logic sets PLACEHOLDER_CA_BUNDLE_PEM_PATH, PLACEHOLDER_GRADLE_TRUST_OPTS, and PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH to empty strings. This results in:

  • NODE_EXTRA_CA_CERTS: "" and GRADLE_OPTS: "" in the container spec
  • mountPath: "" in the volumeMount, which violates Kubernetes schema

The volumeMount entry itself remains unconditionally rendered in the template. Although the configMap is optional: true, an empty mountPath is invalid and can cause deployment validation failures.

Either conditionally omit these configurations in the template when caching is disabled, or handle empty values at the application level by checking REMOTE_CACHE_ENABLED before using these variables.

🤖 Prompt for AI Agents
In
`@java/operator/org.eclipse.theia.cloud.operator/src/main/resources/templateDeploymentWithoutOAuthProxy.yaml`
around lines 85 - 92, The template renders empty trust-bundle env vars and a
volumeMount even when caching/remote cache is disabled, producing invalid
Kubernetes YAML (empty NODE_EXTRA_CA_CERTS, GRADLE_OPTS, and mountPath). Update
the templateDeploymentWithoutOAuthProxy.yaml to conditionally omit the
NODE_EXTRA_CA_CERTS and GRADLE_OPTS env entries and the trust-bundle volumeMount
(name "trust-bundle" / mountPath) unless remote caching is enabled (or the
resolved PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH is non-empty); alternatively move
the guard into the code that replaces PLACEHOLDER_CA_BUNDLE_PEM_PATH,
PLACEHOLDER_GRADLE_TRUST_OPTS, and PLACEHOLDER_TRUST_BUNDLE_MOUNT_PATH so they
are not set to empty strings but removed when REMOTE_CACHE_ENABLED is
false—ensure the volumeMount and env vars are only rendered when the mountPath
and trust options are present.

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

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

Integrate Shared Cache Node into Theia Cloud

2 participants