Skip to content

feat(prompts): add Jinja2 conditional templating with compiled preview#6

Open
napan24 wants to merge 34 commits into
fkfrom
l1-voicebot-integration
Open

feat(prompts): add Jinja2 conditional templating with compiled preview#6
napan24 wants to merge 34 commits into
fkfrom
l1-voicebot-integration

Conversation

@napan24
Copy link
Copy Markdown
Collaborator

@napan24 napan24 commented May 19, 2026

What does this PR do?

PR title must follow Conventional Commits, for example feat(web): add trace filters or fix: handle empty dataset names.

Fixes # (issue)

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • Chore (tooling, dependencies, CI, workflows, repo upkeep, or other maintenance work)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (restructures existing code without changing behavior, e.g. simplify logic, split modules, reduce duplication)
  • This change requires a documentation update

Mandatory Tasks

  • Make sure you have self-reviewed the code. A decent size PR without self-review might be rejected.

Checklist

  • I haven't read the contributing guide
  • My code doesn't follow the style guidelines of this project (pnpm run format)
  • I haven't commented my code, particularly in hard-to-understand areas
  • I haven't checked if my PR needs changes to the documentation
  • I haven't checked if my changes generate no new warnings (npm run lint)
  • I haven't added tests that prove my fix is effective or that my feature works
  • I haven't checked if new and existing unit tests pass locally with my changes

Summary by CodeRabbit

  • New Features

    • Jinja2-style Conditional Prompts: conditionals, loops, filters, and richer templating
    • Compiled Prompt Preview in the playground with per-message warnings
    • JSON Variable Types for arrays/objects
    • Prompt Compilation API endpoint for server-side template compilation
  • Enhancements

    • Optional org-creation toggle for self-hosted deployments
    • Extended GCP credential support (including WIF)
    • Extra Headers available for more LLM adapters
    • Audit-logs entitlement added to self-hosted all-plans
  • Documentation

    • Added full Conditional Prompts guide with examples and troubleshooting
  • Tests

    • New tests covering template compilation and variable extraction

Review Change Stack

napan.vijayvargiya and others added 14 commits May 11, 2026 16:20
- Include node_modules in final Docker image to fix turbopack module resolution
- Add Dockerfile.patch with node_modules fix applied
- Preserve Dockerfile.patch-complete for reference
- Update CreateLLMApiKeyForm.tsx to show extra headers for GoogleAIStudio/VertexAI
- Update worker Dockerfile for consistency
…mins

- Modified canCreateOrganizations() to check org roles (OWNER/ADMIN) or site admin flag
- Only users with OWNER/ADMIN role in any existing org or site admin status can create new orgs
- Project creation already controlled by RBAC projects:create scope (OWNER/ADMIN only)
- When LANGFUSE_DISABLE_ORG_CREATION=true, only these users are allowed

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…oviderConfigSchemas

- Updated WorkloadIdentityFederationSchema to use .loose() instead of deprecated .passthrough()
- Fixes ESLint warnings about deprecated Zod methods
Co-authored-by: napan.vijayvargiya <napan.vijayvargiya@flipkart.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: add Docker publish workflow for PRs and main branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): pin action versions to full SHAs to fix zizmor alerts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: napan.vijayvargiya <napan.vijayvargiya@flipkart.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* ci: add Docker publish workflow for PRs and main branch

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): pin action versions to full SHAs to fix zizmor alerts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): fix invalid secrets expressions causing workflow to be silently skipped

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): remove invalid Docker Hub secrets if-condition

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): fix incorrect action SHAs for buildx and build-push-action

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* ci(docker): use version tags instead of broken SHAs for docker actions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(docker): fix cross-compilation of migrate binary for arm64

Removes GOBIN so go install works when cross-compiling. The binary lands
in $GOPATH/bin/${GOOS}_${GOARCH}/migrate for cross builds and
$GOPATH/bin/migrate for native builds; copy whichever exists to /out/migrate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(docker): fix cross-compilation of migrate binary in devcontainer Dockerfile

Same GOBIN cross-compilation fix as web/Dockerfile.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: napan.vijayvargiya <napan.vijayvargiya@flipkart.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89d5358e-9a48-40e6-9a00-9301a0ad87c3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR adds Jinja2/Nunjucks conditional prompt support with dual-format templates (default/jinja2), a public compilation API, real-time Nunjucks preview in playground and UI, and updates both backend and worker evaluation systems to use the new shared template compiler. It includes Docker optimizations, environment configuration, and credential validation improvements.

Changes

Conditional Prompts Implementation

Layer / File(s) Summary
Shared Template Compilation Module
packages/shared/package.json, packages/shared/src/server/index.ts, packages/shared/src/server/prompt-compiler/index.ts
Core infrastructure exports compilePromptTemplate (supporting "default" mustache and "jinja2" Nunjucks formats with SHA-256 LRU caching) and extractTemplateVariables (regex-based static variable extraction from templates). Dependencies on nunjucks@^3.2.4 and @types/nunjucks@^3.2.6 are added.
Prompt Config Schema and Variable Typing
packages/shared/src/features/prompts/types.ts, packages/shared/src/server/llm/types.ts, web/src/components/editor/CodeMirrorEditor.tsx
Introduces PromptConfigSchema with templateFormat enum, PromptVariableType union (`"string"
Prompt Compilation API Endpoint
fern/apis/server/definition/prompts.yml, web/src/features/prompts/server/handlers/promptCompileHandler.ts, web/src/pages/api/public/v2/prompts/[promptName]/compile.ts
Fern API definition adds POST /prompts/{promptName}/compile endpoint with request/response schemas; handler authorizes, fetches prompt, compiles template by format (text via compilePromptTemplate, chat via compileChatMessages), and returns HTTP 200 with isActive and optional compilationErrors.
Playground Variable Editing & Preview
web/src/features/playground/page/context/index.tsx, web/src/features/playground/page/components/PromptVariableComponent.tsx, web/src/features/playground/page/components/CompiledPromptPreview.tsx, web/src/features/playground/page/components/ConfigurationDropdowns.tsx
Context gains optional updatePromptVariableType callback; PromptVariableComponent adds type selector UI and JSON validation; CompiledPromptPreview uses client-side Nunjucks environment to render and display compiled messages with per-message error tracking.
Prompt Management Form & Detail
web/src/features/prompts/components/NewPromptForm/index.tsx, web/src/features/prompts/components/prompt-detail.tsx, web/src/features/prompts/components/Jinja2ResolutionPanel.tsx, web/src/features/prompts/server/actions/createPrompt.ts
Form adds template format selector and merges format into prompt config on submit; detail view parses config and conditionally renders Jinja2ResolutionPanel (interactive variable input + compiled output) for jinja2 prompts; createPrompt auto-extracts variables based on format and merges them with user-provided inputKeys.
Chat Message & Worker Evaluation Integration
packages/shared/src/server/llm/compileChatMessages.ts, worker/src/features/evaluation/evalRuntime.ts, worker/src/features/evaluation/observationEval/extractObservationVariables.ts, worker/src/features/utils/utilities.ts
Chat compilation passes format through to template compiler; worker eval runtime accepts optional templateFormat and parses JSON variables when format is jinja2; compileTemplateString delegates to shared compilePromptTemplate and logs warnings on compilation errors.
Code Editor Syntax Support
web/src/components/editor/CodeMirrorEditor.tsx
Tokenizer now highlights Jinja2 comments ({# #}) and block tags ({% %}); linter refines unclosed bracket detection to skip Jinja2 markers and adds warnings for unclosed Jinja2 blocks.
Tests and Documentation
web/src/__tests__/server/unit/prompt-compiler.servertest.ts, CONDITIONAL_PROMPTS.md
Test suite validates default/jinja2 substitution, conditionals, loops, error handling, and caching; CONDITIONAL_PROMPTS.md documents syntax, UI workflow, API usage, examples, best practices, and migration from the default format.

Infrastructure and Supporting Updates

Layer / File(s) Summary
Docker Build Configuration
web/Dockerfile, web/Dockerfile.patch, web/Dockerfile.patch-complete, worker/Dockerfile, .devcontainer/Dockerfile
Alpine package handling simplified to libc6-compat via apk add --no-cache; dumb-init and tzdata installation switches to binary download via wget with fallback tolerance; turbo version pinned to 2.9.5; web build memory tuned to fixed 4096MB; sequential compilation enforced via CPUS=1 and --concurrency=1; multi-stage builds with $BUILDPLATFORM for cross-compilation; migrate binary copy logic adjusted.
Environment and Authorization
web/src/env.mjs, web/src/server/auth.ts
Adds optional LANGFUSE_DISABLE_ORG_CREATION environment variable; refactors canCreateOrganizations to accept admin status and organization roles, allowing admins or users with OWNER/ADMIN roles to create orgs when creation is disabled.
GCP Credentials and LLM
packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts, packages/shared/src/server/llm/fetchLLMCompletion.ts, web/src/features/public-api/components/CreateLLMApiKeyForm.tsx
GCP credential validation now accepts union of standard service account and Workload Identity Federation (WIF) external account formats; GoogleAIStudio adapter conditionally passes extraHeaders to LangChain; Extra Headers field displayed for GoogleAIStudio and VertexAI in addition to OpenAI/Anthropic.
Entitlements and UI Text
web/src/features/entitlements/constants/entitlements.ts, web/src/features/playground/page/components/Variables.tsx
Audit-logs entitlement added to self-hosted/OSS plans; playground variable help text updated to describe {{variable}}, Jinja2 constructs, and JSON typing.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client/Playground
  participant API as Compile Handler
  participant DB as Database
  participant Compiler as Shared Compiler
  participant LLM as LLM Integration
  
  Client->>API: POST /prompts/{promptName}/compile<br/>{variables, version?, label?}
  API->>API: Authorize & rate limit
  API->>DB: Fetch prompt by name/version
  DB-->>API: Prompt {type, content, config}
  API->>Compiler: compilePromptTemplate or compileChatMessages<br/>(content, variables, format)
  Compiler-->>API: {compiled, errors}
  API-->>Client: HTTP 200 {prompt, isActive, compilationErrors}
  
  Client->>Client: Update compiled preview in UI
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 Templates dance with Jinja's grace,
{% if %} loops embrace the space,
Conditions bloom where default could not tread,
JSON variables flow where once was just thread,
Compile now, preview with flair—
Conditional prompts beyond compare! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.25% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: adding Jinja2 conditional templating support to the prompts feature with a compiled preview UI component.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch l1-voicebot-integration

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.

@github-actions
Copy link
Copy Markdown

@claude review

@ox-security
Copy link
Copy Markdown

ox-security Bot commented May 19, 2026

OX Security Logo

OX Security reviewed this pull request — nothing to fix.

No issues found

Branch l1-voicebot-integrationfk

View scan in OX Security →

Comment thread .github/workflows/docker-publish.yml Fixed
Comment thread .github/workflows/docker-publish.yml Fixed
Comment thread .github/workflows/docker-publish.yml Fixed
Comment thread .github/workflows/docker-publish.yml Fixed
napan.vijayvargiya and others added 4 commits May 20, 2026 00:14
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@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: 20

♻️ Duplicate comments (3)
web/Dockerfile.patch-complete (2)

29-29: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Critical: Disabling TLS certificate validation exposes builds to MITM attacks.

Same issue as in Dockerfile.patch - NODE_TLS_REJECT_UNAUTHORIZED=0 disables certificate verification, allowing potential package interception.

Also applies to: 35-36

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/Dockerfile.patch-complete` at line 29, The Dockerfile currently disables
TLS verification by prefixing the RUN invoking pnpm ("RUN
NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm install --frozen-lockfile"); remove this
environment override so certificate validation remains enabled, and instead fix
the build to trust the correct CA (install ca-certificates in the image or add
the internal CA to the system/npm/pnpm trust store) or point pnpm to a registry
with a valid certificate; ensure the RUN line is changed to "RUN pnpm install
--frozen-lockfile" and any necessary CA installation/configuration steps are
added earlier in the Dockerfile so builds do not require
NODE_TLS_REJECT_UNAUTHORIZED=0.

11-11: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

--allow-untrusted bypasses APK signature verification.

Same concern flagged in other Dockerfiles. The || true also masks failures.

Also applies to: 45-45

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/Dockerfile.patch-complete` at line 11, The RUN instruction "apk add
--no-cache --allow-untrusted libc6-compat || true" bypasses APK signature
verification and masks failures; remove the "--allow-untrusted" flag and the "||
true" fallback so apk will fail on errors, and instead ensure the image uses a
trusted APK repository or adds the correct CA/certs before installing (or pin
the package version if needed); update the same pattern elsewhere where you used
"--allow-untrusted" or "|| true" to preserve secure installation behavior.
worker/Dockerfile (1)

50-50: ⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Critical: Disabling TLS certificate validation exposes builds to MITM attacks.

Same issue as in web Dockerfiles - NODE_TLS_REJECT_UNAUTHORIZED=0 during build disables certificate verification.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 50, The Dockerfile build step is disabling TLS
verification by setting NODE_TLS_REJECT_UNAUTHORIZED=0 in the RUN command;
remove that environment override from the build command and instead ensure the
build environment trusts the required CA(s) (e.g., install/root CA certificates
into the image or configure npm/git to use secure registries with proper certs)
so the turbo run build --filter=worker... step runs without bypassing TLS;
search for the RUN line containing "NODE_TLS_REJECT_UNAUTHORIZED" and replace it
with a secure approach (install/update CA bundle or configure credentials)
rather than disabling verification.
🧹 Nitpick comments (3)
worker/Dockerfile (1)

73-73: 💤 Low value

No-op sed commands can be removed.

The sed s/aarch64/aarch64/ | sed s/x86_64/x86_64/ replacements do nothing (replacing strings with themselves). Remove for clarity.

🧹 Proposed cleanup
-RUN wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_$(uname -m | sed s/aarch64/aarch64/ | sed s/x86_64/x86_64/) && chmod +x /usr/bin/dumb-init
+RUN wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_$(uname -m) && chmod +x /usr/bin/dumb-init
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 73, The RUN command that downloads dumb-init
contains two no-op sed replacements; edit the RUN line that constructs the URL
(the one downloading to /usr/bin/dumb-init) to remove the `| sed
s/aarch64/aarch64/ | sed s/x86_64/x86_64/` pipeline and use the raw `$(uname
-m)` (or a simple mapping if you intended to normalize arch names) so the wget
URL is built cleanly and then keep the existing chmod +x for /usr/bin/dumb-init.
web/Dockerfile.patch-complete (1)

63-63: 💤 Low value

Hardcoded NEXTAUTH_URL may cause authentication issues.

NEXTAUTH_URL=http://localhost:3000 is hardcoded. While this can be overridden at runtime, ensure this is intentional. If the container is deployed without overriding this variable, authentication callbacks will fail.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/Dockerfile.patch-complete` at line 63, The Dockerfile currently hardcodes
the NEXTAUTH_URL environment variable which can break authentication if not
overridden; change the Dockerfile to make NEXTAUTH_URL configurable instead of
fixed by either (a) replacing ENV NEXTAUTH_URL=http://localhost:3000 with an ARG
NEXTAUTH_URL and then ENV NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000} so
callers can pass --build-arg or (b) remove the default and rely on runtime ENV
injection, and update any startup/docs to require setting NEXTAUTH_URL;
reference the NEXTAUTH_URL ENV/ARG and the Dockerfile lines where NEXTAUTH_URL
is set when making the change.
web/src/features/prompts/components/NewPromptForm/index.tsx (1)

42-42: ⚡ Quick win

Derive TemplateFormat from shared prompt config contract to avoid drift.

At Line 42 and Line 97-Line 99, this local union duplicates shared schema intent. Prefer deriving from shared types so UI options stay aligned with backend validation.

Suggested refactor
-import {
+import {
   type CreatePromptTRPCType,
+  type PromptConfig,
   PRODUCTION_LABEL,
   type Prompt,
   PromptType,
   extractVariables,
   getIsCharOrUnderscore,
 } from "`@langfuse/shared`";
 
-type TemplateFormat = "default" | "jinja2";
+type TemplateFormat = PromptConfig["templateFormat"];
As per coding guidelines, "Use `@langfuse/shared` in frontend-safe web code for shared types, zod schemas, domain contracts...".

Also applies to: 97-99

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/prompts/components/NewPromptForm/index.tsx` at line 42, The
local TemplateFormat union type duplicates shared schema intent; replace it by
importing the shared type from `@langfuse/shared` (the prompt config contract) and
use that instead of defining type TemplateFormat = "default" | "jinja2"; update
all usages (including where the UI builds the format options and the component
NewPromptForm) to reference the imported type and/or derive the options from the
shared enum/schema so frontend stays aligned with backend validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CONDITIONAL_PROMPTS.md`:
- Around line 21-24: The markdown code fences in CONDITIONAL_PROMPTS.md are
missing language identifiers; update each triple-backtick fence that surrounds
the "Chat Prompt\nName: customer-support" block and the conditional block that
starts with "[System Role]" / "{% if language == 'spanish' %}" to include a
language (e.g., change ``` to ```text or ```yaml as appropriate) so markdownlint
rule MD040 is satisfied and the fenced blocks are properly highlighted.
- Around line 63-68: The markdown table in CONDITIONAL_PROMPTS.md violates MD058
because it lacks blank lines around the table; add a single blank line
immediately before the table header line beginning with "| Name | Type | Value
|" and a single blank line immediately after the final table row (the line with
`| "documents" | JSON | [...] |`) so the table is separated by blank lines from
surrounding content and satisfies MD058.
- Line 46: The token "cliente" in the sentence "Eres un asistente de servicio al
cliente." is triggering codespell; either change the phrase (e.g., reword to
"Eres un asistente de servicio al consumidor" or "Eres un asistente de atención
al cliente") or add the word "cliente" to the codespell ignore list so the
example in CONDITIONAL_PROMPTS.md is not flagged—update the file by editing that
sentence or add "cliente" to the project's codespell ignore configuration.

In `@packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts`:
- Around line 64-67: The current credential_source schema (credential_source:
z.object({}).loose()) accepts empty objects; update the schema for
credential_source to require at least one and only one of the valid WIF keys
(file, url, executable, environment_id, certificate) by defining a z.object with
those optional keys (e.g., file: z.string().optional(), url:
z.string().optional(), executable: z.object(...).optional(), environment_id:
z.string().optional(), certificate: z.string().optional()) and add a
.refine(...) on that object to assert exactly one key is present (or use a
z.union of single-key objects) so malformed external-account keys are rejected
at parse time; apply this change where credential_source is declared to prevent
invalid WIF credentials slipping through.

In `@packages/shared/src/server/llm/compileChatMessages.ts`:
- Around line 22-28: The current replaceTextVariables function discards
compilePromptTemplate(...).errors and returns only .compiled; change it to
capture the full result (e.g., const result = compilePromptTemplate(...)), and
propagate compilation errors to callers by either returning both compiled and
errors (or throwing a compilation error) instead of dropping them; update the
replaceTextVariables implementation (and the other two call-sites in this file
that call compilePromptTemplate at the noted locations) to pass through the
errors so the compile API handler and upstream code can surface
compilationErrors.

In `@packages/shared/src/server/prompt-compiler/index.ts`:
- Around line 43-47: The size check uses template.length (characters) but the
limit is in bytes; replace that check with a true UTF-8 byte-length calculation
(e.g., const size = Buffer.byteLength(template, 'utf8') or new
TextEncoder().encode(template).length for browser-safe code) and compare size
against MAX_TEMPLATE_SIZE, returning the same compiled/error shape (compiled,
errors) when the byte length exceeds MAX_TEMPLATE_SIZE; update the conditional
that references template and MAX_TEMPLATE_SIZE accordingly.

In `@web/Dockerfile`:
- Line 137: The RUN line in the Dockerfile downloads dumb-init and installs
tzdata but weakens security by using --allow-untrusted and silencing failures
with "|| true", and contains redundant sed no-ops; update the command to:
download dumb-init with a failing-on-error downloader (e.g., wget or curl with
-O and --fail), keep the chmod step, remove the sed pipeline, and install tzdata
with apk add --no-cache tzdata (omit --allow-untrusted) so package signatures
are enforced and do not swallow errors—ensure the RUN fails on error so build
stops on failure.

In `@web/Dockerfile.patch`:
- Line 10: The Dockerfile contains a RUN instruction "apk add --no-cache
--allow-untrusted libc6-compat || true" that disables APK signature
verification; remove the "--allow-untrusted" flag (and the "|| true" if not
required) so package installs fail on signature issues, or if you must keep it
for your internal registry, add a clear comment above this RUN explaining why
"--allow-untrusted" is required and document the risks and registry
configuration that justify it.
- Around line 28-29: Remove the unsafe environment override
NODE_TLS_REJECT_UNAUTHORIZED=0 from the RUN that executes "pnpm install
--frozen-lockfile" and instead configure trusted TLS properly: add your internal
CA certs into the image trust store (install the CA into
/usr/local/share/ca-certificates and run update-ca-certificates) or configure
pnpm/npm to use a scoped registry with strict-ssl disabled only for that
registry (e.g., set npm/pnpm registry auth/ca via .npmrc or pnpm config), and
add a short comment documenting why any non-default TLS behavior is required;
update the RUN that references "pnpm install --frozen-lockfile" and ensure the
COPY --from=pruner step remains unchanged.
- Around line 40-46: The Dockerfile inherits from langfuse:3 but does not set a
runtime USER, so add an explicit USER directive (matching the repository
convention like USER nextjs or the non-root UID/GID 1001 used in the COPY
--chown=1001:1001 lines) or confirm and document that langfuse:3 already
configures a non-root user; update the Dockerfile to include the chosen USER
after the LABEL build.id="$BUILD_ID" (or equivalent spot) to ensure the
container does not run as root at runtime.

In `@web/src/__tests__/server/unit/prompt-compiler.servertest.ts`:
- Around line 24-28: The test title says "returns original template unchanged on
error" but it passes a valid template to compilePromptTemplate, so update the
test to actually trigger an error path: call compilePromptTemplate with an
invalid template string or path that will cause parsing/compilation to throw
(for example a malformed template or a non-existent template identifier) and
assert that result.compiled contains the original input; alternatively, if you
prefer to keep the current input, rename the test to reflect normal behavior
("returns compiled template for valid input") so the test name matches the
behavior of compilePromptTemplate.

In `@web/src/components/editor/CodeMirrorEditor.tsx`:
- Line 73: The UNCLOSED_BLOCK_REGEX currently treats any `{` inside a block as a
hard stop and causes false "unclosed block tag" warnings; update
UNCLOSED_BLOCK_REGEX so the negative lookahead permits `{` characters and only
matches an opening `{%` that truly lacks a closing `%}` (e.g. use a lookahead
that allows any character including `{` when searching for `%}`), then ensure
the warning logic that uses UNCLOSED_BLOCK_REGEX (the unclosed-block detection
around the existing check/warning) uses the updated regex so valid `{% ... %}`
expressions with `{` inside are no longer flagged.

In `@web/src/features/entitlements/constants/entitlements.ts`:
- Line 31: The enterprise entitlements array contains a duplicate "audit-logs"
because it's already included via selfHostedAllPlansEntitlements; remove the
duplicate by deleting the explicit "audit-logs" entry from the enterprise
entitlements constant (e.g., selfHostedEnterpriseEntitlements) so entitlements
are only inherited from selfHostedAllPlansEntitlements and remain canonical.

In `@web/src/features/playground/page/context/index.tsx`:
- Around line 967-972: The current JSON handling in the playground variable
parsing (the branch where v.variableType === "json") silently falls back to a
string on parse error; change this to fail fast by throwing a descriptive error
(including the variable name) when JSON.parse(v.value) throws instead of
assigning the raw string to variableMap. Locate the block that checks
v.variableType === "json" and replace the empty catch fallback with a thrown
Error (or otherwise surface a validation error to the caller/execution flow) so
execution is rejected for invalid JSON-typed variables and the error can be
shown to the user.

In `@web/src/features/prompts/components/Jinja2ResolutionPanel.tsx`:
- Around line 27-55: The current useMemo block for computing compiled performs
side effects (calls setVarValues and setErrors) which violates memo purity; move
the varValues initialization into a useEffect that runs when variables changes
(useEffect(() => { setVarValues(...) }, [variables])) and make the memo that
computes the template rendering pure by returning both the rendered string and
any errors (e.g., { result, errors }) without calling setErrors or setVarValues
inside it; then use a separate useEffect to apply setErrors when the memoized
errors change and keep the final rendered string in a const compiled =
memo.result so UI reads a pure value while state updates happen in effects.

In `@web/src/features/prompts/components/prompt-detail.tsx`:
- Around line 293-296: The for-block extractor currently adds the full dotted
iterable (from forRegex matching in promptText) to the matches set, causing
inconsistent keys; update the logic where you process m[1] so you normalize to
the root key (e.g., const root = m[1].split('.')[0]) and add that root to
matches instead of the full dotted path, keeping the existing forRegex, m
variable, and matches Set usage in prompt-detail.tsx.
- Around line 272-276: Replace the unsafe PromptConfigSchema.parse(...) call
with PromptConfigSchema.safeParse(...) and use the parsedResult.success ?
parsedResult.data : <fallback> pattern to avoid throwing on malformed persisted
config; specifically, change the code that sets promptConfig (currently using
PromptConfigSchema.parse and reading prompt?.config) to call
PromptConfigSchema.safeParse on the same input, default to {} (or the existing
default config) when safeParse returns success === false, and optionally surface
or log the parse error for debugging. This ensures promptConfig is always a
valid object and prevents render crashes.

In `@web/src/features/public-api/components/CreateLLMApiKeyForm.tsx`:
- Around line 1229-1234: The form currently shows extra-header inputs for
LLMAdapter.VertexAI via CreateLLMApiKeyForm (checks currentAdapter against
LLMAdapter.VertexAI and calls renderExtraHeadersField()) but the backend
VertexAI execution path does not forward those headers, making inputs no-op;
either remove LLMAdapter.VertexAI from that client-side condition or update the
VertexAI request handling (e.g., the VertexAI execution function/class that
builds/send requests) to read the extra headers provided by the form and attach
them to outbound requests (preserving header names/values and any existing
header merging logic) so the UI inputs are actually forwarded.

In `@web/src/server/auth.ts`:
- Around line 164-168: The credentials provider builds the initial user object
but calls canCreateOrganizations(dbUser.email, dbUser.admin) without the
orgRoles parameter, which can incorrectly deny org creation; update the
credentials flow to fetch the user's organization memberships (orgRoles) the
same way the session callback does and pass that orgRoles value into
canCreateOrganizations(dbUser.email, dbUser.admin, orgRoles) so the provider
uses the same three-argument check as the session callback.

In `@worker/Dockerfile`:
- Line 6: The RUN line "RUN apk add --no-cache --allow-untrusted libc6-compat ||
true" disables signature checks and masks failures; remove the --allow-untrusted
and the "|| true", ensure the package is available by running "apk update" (or
add the correct --repository) before installing, and let the command fail the
build on error so installation issues are visible; update the Dockerfile to use
only "apk add --no-cache libc6-compat" (or add the correct repository) and
remove the permissive flags.

---

Duplicate comments:
In `@web/Dockerfile.patch-complete`:
- Line 29: The Dockerfile currently disables TLS verification by prefixing the
RUN invoking pnpm ("RUN NODE_TLS_REJECT_UNAUTHORIZED=0 pnpm install
--frozen-lockfile"); remove this environment override so certificate validation
remains enabled, and instead fix the build to trust the correct CA (install
ca-certificates in the image or add the internal CA to the system/npm/pnpm trust
store) or point pnpm to a registry with a valid certificate; ensure the RUN line
is changed to "RUN pnpm install --frozen-lockfile" and any necessary CA
installation/configuration steps are added earlier in the Dockerfile so builds
do not require NODE_TLS_REJECT_UNAUTHORIZED=0.
- Line 11: The RUN instruction "apk add --no-cache --allow-untrusted
libc6-compat || true" bypasses APK signature verification and masks failures;
remove the "--allow-untrusted" flag and the "|| true" fallback so apk will fail
on errors, and instead ensure the image uses a trusted APK repository or adds
the correct CA/certs before installing (or pin the package version if needed);
update the same pattern elsewhere where you used "--allow-untrusted" or "||
true" to preserve secure installation behavior.

In `@worker/Dockerfile`:
- Line 50: The Dockerfile build step is disabling TLS verification by setting
NODE_TLS_REJECT_UNAUTHORIZED=0 in the RUN command; remove that environment
override from the build command and instead ensure the build environment trusts
the required CA(s) (e.g., install/root CA certificates into the image or
configure npm/git to use secure registries with proper certs) so the turbo run
build --filter=worker... step runs without bypassing TLS; search for the RUN
line containing "NODE_TLS_REJECT_UNAUTHORIZED" and replace it with a secure
approach (install/update CA bundle or configure credentials) rather than
disabling verification.

---

Nitpick comments:
In `@web/Dockerfile.patch-complete`:
- Line 63: The Dockerfile currently hardcodes the NEXTAUTH_URL environment
variable which can break authentication if not overridden; change the Dockerfile
to make NEXTAUTH_URL configurable instead of fixed by either (a) replacing ENV
NEXTAUTH_URL=http://localhost:3000 with an ARG NEXTAUTH_URL and then ENV
NEXTAUTH_URL=${NEXTAUTH_URL:-http://localhost:3000} so callers can pass
--build-arg or (b) remove the default and rely on runtime ENV injection, and
update any startup/docs to require setting NEXTAUTH_URL; reference the
NEXTAUTH_URL ENV/ARG and the Dockerfile lines where NEXTAUTH_URL is set when
making the change.

In `@web/src/features/prompts/components/NewPromptForm/index.tsx`:
- Line 42: The local TemplateFormat union type duplicates shared schema intent;
replace it by importing the shared type from `@langfuse/shared` (the prompt config
contract) and use that instead of defining type TemplateFormat = "default" |
"jinja2"; update all usages (including where the UI builds the format options
and the component NewPromptForm) to reference the imported type and/or derive
the options from the shared enum/schema so frontend stays aligned with backend
validation.

In `@worker/Dockerfile`:
- Line 73: The RUN command that downloads dumb-init contains two no-op sed
replacements; edit the RUN line that constructs the URL (the one downloading to
/usr/bin/dumb-init) to remove the `| sed s/aarch64/aarch64/ | sed
s/x86_64/x86_64/` pipeline and use the raw `$(uname -m)` (or a simple mapping if
you intended to normalize arch names) so the wget URL is built cleanly and then
keep the existing chmod +x for /usr/bin/dumb-init.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6631b925-c76e-4539-bddb-72c2ed32a964

📥 Commits

Reviewing files that changed from the base of the PR and between 880d2a5 and 8e4de91.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (35)
  • CONDITIONAL_PROMPTS.md
  • fern/apis/server/definition/prompts.yml
  • packages/shared/package.json
  • packages/shared/src/features/prompts/types.ts
  • packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts
  • packages/shared/src/server/index.ts
  • packages/shared/src/server/llm/compileChatMessages.ts
  • packages/shared/src/server/llm/fetchLLMCompletion.ts
  • packages/shared/src/server/llm/types.ts
  • packages/shared/src/server/prompt-compiler/index.ts
  • web/Dockerfile
  • web/Dockerfile.patch
  • web/Dockerfile.patch-complete
  • web/package.json
  • web/src/__tests__/server/unit/prompt-compiler.servertest.ts
  • web/src/components/editor/CodeMirrorEditor.tsx
  • web/src/env.mjs
  • web/src/features/entitlements/constants/entitlements.ts
  • web/src/features/playground/page/components/CompiledPromptPreview.tsx
  • web/src/features/playground/page/components/ConfigurationDropdowns.tsx
  • web/src/features/playground/page/components/PromptVariableComponent.tsx
  • web/src/features/playground/page/components/Variables.tsx
  • web/src/features/playground/page/context/index.tsx
  • web/src/features/prompts/components/Jinja2ResolutionPanel.tsx
  • web/src/features/prompts/components/NewPromptForm/index.tsx
  • web/src/features/prompts/components/prompt-detail.tsx
  • web/src/features/prompts/server/actions/createPrompt.ts
  • web/src/features/prompts/server/handlers/promptCompileHandler.ts
  • web/src/features/public-api/components/CreateLLMApiKeyForm.tsx
  • web/src/pages/api/public/v2/prompts/[promptName]/compile.ts
  • web/src/server/auth.ts
  • worker/Dockerfile
  • worker/src/features/evaluation/evalRuntime.ts
  • worker/src/features/evaluation/observationEval/extractObservationVariables.ts
  • worker/src/features/utils/utilities.ts

Comment thread CONDITIONAL_PROMPTS.md
Comment on lines +21 to +24
```
Chat Prompt
Name: customer-support
```
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add languages to fenced code blocks (MD040).

These fences are missing language identifiers and trigger markdownlint warnings.

Suggested fix
-```
+```text
 Chat Prompt
 Name: customer-support

@@
- +text
[System Role]
{% if language == 'spanish' %}
Eres un asistente de servicio al cliente.
{% else %}
You are a customer support assistant.
{% endif %}

[User Message]
{{ user_message }}

Also applies to: 43-53

🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 21-21: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONDITIONAL_PROMPTS.md` around lines 21 - 24, The markdown code fences in
CONDITIONAL_PROMPTS.md are missing language identifiers; update each
triple-backtick fence that surrounds the "Chat Prompt\nName: customer-support"
block and the conditional block that starts with "[System Role]" / "{% if
language == 'spanish' %}" to include a language (e.g., change ``` to ```text or
```yaml as appropriate) so markdownlint rule MD040 is satisfied and the fenced
blocks are properly highlighted.

Comment thread CONDITIONAL_PROMPTS.md Outdated
```
[System Role]
{% if language == 'spanish' %}
Eres un asistente de servicio al cliente.
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Codespell is currently failing CI on this token.

cliente at Line 46 is being flagged by the pipeline. Either rephrase this snippet or add the word to your codespell ignore list so docs examples in Spanish stop breaking checks.

One simple in-file fix
- Eres un asistente de servicio al cliente.
+ Eres un asistente de atención al usuario.
📝 Committable suggestion

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

Suggested change
Eres un asistente de servicio al cliente.
Eres un asistente de atención al usuario.
🧰 Tools
🪛 GitHub Actions: Codespell / 0_Check for spelling errors.txt

[error] 46-46: codespell reported a spelling issue: "cliente ==> client, clientele"

🪛 GitHub Actions: Codespell / Check for spelling errors

[error] 46-46: codespell found spelling issue: "cliente" ==> "client" (or "clientele").

🪛 GitHub Check: Check for spelling errors

[failure] 46-46:
cliente ==> client, clientele

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONDITIONAL_PROMPTS.md` at line 46, The token "cliente" in the sentence "Eres
un asistente de servicio al cliente." is triggering codespell; either change the
phrase (e.g., reword to "Eres un asistente de servicio al consumidor" or "Eres
un asistente de atención al cliente") or add the word "cliente" to the codespell
ignore list so the example in CONDITIONAL_PROMPTS.md is not flagged—update the
file by editing that sentence or add "cliente" to the project's codespell ignore
configuration.

Comment thread CONDITIONAL_PROMPTS.md
Comment on lines +63 to +68
| Name | Type | Value |
|------|------|-------|
| `user_type` | String | `premium` |
| `language` | String | `spanish` |
| `documents` | JSON | `[{"title": "API Docs", "url": "..."}, ...]` |

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Surround the table with blank lines (MD058).

The table block needs blank lines before/after to satisfy markdownlint.

Suggested fix
 Example variables:
+
 | Name | Type | Value |
 |------|------|-------|
 | `user_type` | String | `premium` |
 | `language` | String | `spanish` |
 | `documents` | JSON | `[{"title": "API Docs", "url": "..."}, ...]` |
+
 ### 4. Use JSON Variables in Loops
📝 Committable suggestion

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

Suggested change
| Name | Type | Value |
|------|------|-------|
| `user_type` | String | `premium` |
| `language` | String | `spanish` |
| `documents` | JSON | `[{"title": "API Docs", "url": "..."}, ...]` |
Example variables:
| Name | Type | Value |
|------|------|-------|
| `user_type` | String | `premium` |
| `language` | String | `spanish` |
| `documents` | JSON | `[{"title": "API Docs", "url": "..."}, ...]` |
### 4. Use JSON Variables in Loops
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)

[warning] 63-63: Tables should be surrounded by blank lines

(MD058, blanks-around-tables)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONDITIONAL_PROMPTS.md` around lines 63 - 68, The markdown table in
CONDITIONAL_PROMPTS.md violates MD058 because it lacks blank lines around the
table; add a single blank line immediately before the table header line
beginning with "| Name | Type | Value |" and a single blank line immediately
after the final table row (the line with `| "documents" | JSON | [...] |`) so
the table is separated by blank lines from surrounding content and satisfies
MD058.

Comment on lines +64 to +67
credential_source: z.object({}).loose(),
service_account_impersonation_url: z.string().optional(),
})
.loose(); // Allow additional fields for flexibility
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find packages/shared/src/interfaces -name "*.ts" | head -20

Repository: flipkart-incubator/langfuse

Length of output: 449


🏁 Script executed:

cd packages/shared/src/interfaces && wc -l customLLMProviderConfigSchemas.ts

Repository: flipkart-incubator/langfuse

Length of output: 108


🏁 Script executed:

cat -n packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts | sed -n '50,75p'

Repository: flipkart-incubator/langfuse

Length of output: 1096


🏁 Script executed:

# Search for how credential_source is used in the codebase
rg "credential_source" --type ts --type js -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 571


🏁 Script executed:

# Look for WIF/external account credential implementations and tests
rg -i "external_account|workload.?identity" --type ts --type js -B 1 -A 1

Repository: flipkart-incubator/langfuse

Length of output: 2741


🏁 Script executed:

# Check if there are any tests or configuration examples for GCP service accounts
fd -i "gcp\|service.*account" --type f | grep -E "\.(ts|js|json)$" | head -20

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Look at the entire file to understand context
cat -n packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts

Repository: flipkart-incubator/langfuse

Length of output: 2944


🏁 Script executed:

# Search for how GCPServiceAccountKey is used/validated
rg "GCPServiceAccountKey" --type ts --type js -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 2858


🏁 Script executed:

# Check if there are tests or docs related to external account credentials
find . -name "*.test.*" -o -name "*.spec.*" | xargs rg -l "credential_source\|external_account" 2>/dev/null | head -10

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check how the credential is actually used when parsing/authenticating
grep -n "credential_source" packages/shared/src/server/llm/fetchLLMCompletion.ts -B 5 -A 10

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Search for any tests or validation examples of external account credentials
find . -type f \( -name "*.test.ts" -o -name "*.spec.ts" -o -name "*.json" \) | xargs grep -l "external_account\|credential_source" 2>/dev/null

Repository: flipkart-incubator/langfuse

Length of output: 55


🏁 Script executed:

# Look at the router file where the schema is used
grep -n "GCPServiceAccountKeySchema\|credential_source" web/src/features/llm-api-key/server/router.ts -B 3 -A 3

Repository: flipkart-incubator/langfuse

Length of output: 615


🏁 Script executed:

# Check Google auth library documentation or constants in the codebase
rg "credential_source|external_account" --type json --type txt -l

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Look at how GCP credentials are actually instantiated
grep -n "new.*GoogleAuth\|google-auth-library\|credentials" packages/shared/src/server/llm/fetchLLMCompletion.ts -B 2 -A 5

Repository: flipkart-incubator/langfuse

Length of output: 2550


🏁 Script executed:

# Search for any documentation or comments about credential source requirements
rg -i "credential.source|wif|workload.identity" --type ts -B 2 -A 2 | head -50

Repository: flipkart-incubator/langfuse

Length of output: 3763


🏁 Script executed:

# Check if there are any integration tests or examples with external account credentials
find . -type f \( -name "*.test.ts" -o -name "*.spec.ts" \) -exec grep -l "external_account" {} \;

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Look at how the GoogleAuth library is initialized and what it expects
grep -n "GoogleAuth\|google-auth-library" packages/shared/src/server/llm/fetchLLMCompletion.ts -B 2 -A 5

Repository: flipkart-incubator/langfuse

Length of output: 730


🏁 Script executed:

# Check the exact type/import of GoogleAuth and its credential handling
head -50 packages/shared/src/server/llm/fetchLLMCompletion.ts

Repository: flipkart-incubator/langfuse

Length of output: 1592


🏁 Script executed:

# Search for any documentation or examples of WIF credential_source structure
rg -i "credential.*source|subject.*token|external.*account" --type md -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check if there are any GitHub issues or comments related to WIF/external account validation
rg -i "wif\|external.account" --type ts -B 3 -A 3 | grep -i "todo\|fixme\|issue\|validate\|check"

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Look at the actual Google API documentation references or links in code
rg "google.com\|googleapis\|credential" packages/shared/src/server/llm/fetchLLMCompletion.ts | head -20

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check Google's external account credential documentation reference
# by looking at what fields are actually used when the creds are passed to GoogleAuth
grep -n "credentials:" packages/shared/src/server/llm/fetchLLMCompletion.ts -A 10 | head -30

Repository: flipkart-incubator/langfuse

Length of output: 934


🏁 Script executed:

# Verify if credential_source is actually passed through or if it's transformed
rg "credential_source" packages/shared/src/server/llm -B 5 -A 5

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check if there are package.json references to google-auth-library
cat packages/shared/package.json | grep -i google

Repository: flipkart-incubator/langfuse

Length of output: 198


🏁 Script executed:

# Check the ChatVertexAI and google-auth-library to understand credential validation
# Look at package version and how credentials are used
cat packages/shared/package.json | grep -A 2 -B 2 "`@langchain/google`"

Repository: flipkart-incubator/langfuse

Length of output: 304


🏁 Script executed:

# Check if there are any error handling for invalid credential_source
rg "credential_source\|authOptions" packages/shared/src/server/llm/fetchLLMCompletion.ts -A 10 | grep -E "catch|error|throw|Error"

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Verify what happens when an empty credential_source is passed to GoogleAuth
# by checking the exact flow
grep -n "new ChatVertexAI" packages/shared/src/server/llm/fetchLLMCompletion.ts -A 15

Repository: flipkart-incubator/langfuse

Length of output: 791


🏁 Script executed:

# Search for Google external account credential documentation or examples in code
rg "file|url|executable|aws" packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts

Repository: flipkart-incubator/langfuse

Length of output: 239


🏁 Script executed:

# Check if there are any comments or docs about the structure credential_source should have
grep -B 5 -A 5 "credential_source" packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts

Repository: flipkart-incubator/langfuse

Length of output: 437


🏁 Script executed:

# Verify the actual behavior - test if empty credential_source causes issues
# by checking if there are any validators downstream
rg "credential_source" packages/shared/src/server --type ts -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 53


🌐 Web query:

Google external account credential format credential_source structure

💡 Result:

The credential_source object is a critical component of Google's Workload Identity Federation configuration, used to define how an external credential (the subject token) is retrieved from the local environment for exchange with Google's Security Token Service (STS) [1][2]. The structure of the credential_source object depends on the retrieval mechanism. You must provide exactly one of the following primary fields to specify the source [3][4][5]: - file: The absolute path to a local file containing the credential [1][6]. - url: The URL of a local metadata server or identity provider endpoint to retrieve the credential [1][6]. - executable: A configuration object for running a local command to retrieve the credential [1]. - environment_id: An identifier for AWS-sourced credentials (must start with "AWS") [3][4]. - certificate: A configuration object for certificate-sourced credentials [3][4]. For URL-sourced credentials, you may also include: - headers: A map of custom HTTP headers to attach to the request [3][1][6]. For both file and URL-sourced credentials, you can specify a format object to define how to parse the response [3][1][5]: - format.type: The format of the response, typically "text" or "json" [1]. - format.subject_token_field_name: If the type is "json", this specifies the field name containing the subject token [1][6][5]. Example for a URL-sourced credential: { "url": "http://www.example.com", "format": { "type": "json", "subject_token_field_name": "access_token" }, "headers": {"Authorization": "Bearer "} } Example for a file-sourced credential: { "file": "/path/to/token/file.txt" } These configurations are typically generated using the gcloud CLI command gcloud iam workload-identity-pools create-cred-config, which ensures the JSON structure adheres to the required schema [7].

Citations:


credential_source accepts empty objects, allowing invalid WIF credentials through validation.

z.object({}).loose() passes {}, but Google's Workload Identity Federation credentials require credential_source to contain exactly one of: file, url, executable, environment_id, or certificate. Malformed external-account keys are accepted at parse time and fail later at runtime during authentication. Add a minimal structural guard to validate at parse time.

Suggested patch
 export const WorkloadIdentityFederationSchema = z
   .object({
     type: z.literal("external_account"),
     audience: z.string(),
     subject_token_type: z.string(),
     token_url: z.string(),
-    credential_source: z.object({}).loose(),
+    credential_source: z
+      .object({})
+      .loose()
+      .refine((v) => Object.keys(v).length > 0, {
+        message: "credential_source must not be empty",
+      }),
     service_account_impersonation_url: z.string().optional(),
   })
   .loose(); // Allow additional fields for flexibility
📝 Committable suggestion

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

Suggested change
credential_source: z.object({}).loose(),
service_account_impersonation_url: z.string().optional(),
})
.loose(); // Allow additional fields for flexibility
credential_source: z
.object({})
.loose()
.refine((v) => Object.keys(v).length > 0, {
message: "credential_source must not be empty",
}),
service_account_impersonation_url: z.string().optional(),
})
.loose(); // Allow additional fields for flexibility
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/interfaces/customLLMProviderConfigSchemas.ts` around
lines 64 - 67, The current credential_source schema (credential_source:
z.object({}).loose()) accepts empty objects; update the schema for
credential_source to require at least one and only one of the valid WIF keys
(file, url, executable, environment_id, certificate) by defining a z.object with
those optional keys (e.g., file: z.string().optional(), url:
z.string().optional(), executable: z.object(...).optional(), environment_id:
z.string().optional(), certificate: z.string().optional()) and add a
.refine(...) on that object to assert exactly one key is present (or use a
z.union of single-key objects) so malformed external-account keys are rejected
at parse time; apply this change where credential_source is declared to prevent
invalid WIF credentials slipping through.

Comment on lines 22 to 28
function replaceTextVariables(
content: string,
textVariables: Record<string, string>,
textVariables: Record<string, unknown>,
format: TemplateFormat = "default",
): string {
let result = content;
for (const [varName, varValue] of Object.entries(textVariables)) {
// Create regex that handles optional whitespace around variable name
const variablePattern = new RegExp(`{{\\s*${varName}\\s*}}`, "g");
result = result.replace(variablePattern, varValue);
}
return result;
return compilePromptTemplate(content, textVariables, format).compiled;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Propagate template compilation errors instead of silently discarding them.

Line 27 drops compilePromptTemplate(...).errors. For chat prompts, template failures become silent, so callers (including the compile API handler) can’t report compilationErrors.

Suggested fix
 function replaceTextVariables(
   content: string,
   textVariables: Record<string, unknown>,
   format: TemplateFormat = "default",
 ): string {
-  return compilePromptTemplate(content, textVariables, format).compiled;
+  const result = compilePromptTemplate(content, textVariables, format);
+  if (result.errors.length > 0) {
+    throw new Error(result.errors.join("; "));
+  }
+  return result.compiled;
 }

Also applies to: 85-85, 119-119

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/server/llm/compileChatMessages.ts` around lines 22 - 28,
The current replaceTextVariables function discards
compilePromptTemplate(...).errors and returns only .compiled; change it to
capture the full result (e.g., const result = compilePromptTemplate(...)), and
propagate compilation errors to callers by either returning both compiled and
errors (or throwing a compilation error) instead of dropping them; update the
replaceTextVariables implementation (and the other two call-sites in this file
that call compilePromptTemplate at the noted locations) to pass through the
errors so the compile API handler and upstream code can surface
compilationErrors.

Comment on lines +272 to +276
const promptConfig = PromptConfigSchema.parse(
typeof prompt?.config === "object" && prompt.config !== null
? prompt.config
: {},
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, locate and read the file around the flagged lines
wc -l web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 129


🏁 Script executed:

# Check the structure of the file to understand context
head -30 web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 1048


🏁 Script executed:

# Read the specific section in question (lines 260-290 for context)
sed -n '260,290p' web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 1123


🏁 Script executed:

# Find where PromptConfigSchema is defined
rg "PromptConfigSchema\s*=" --type ts --type tsx

Repository: flipkart-incubator/langfuse

Length of output: 99


🏁 Script executed:

# Check imports at the top of the file to understand where PromptConfigSchema comes from
head -80 web/src/features/prompts/components/prompt-detail.tsx | grep -A5 -B5 "PromptConfigSchema\|import"

Repository: flipkart-incubator/langfuse

Length of output: 3394


🏁 Script executed:

# Find PromptConfigSchema definition in langfuse/shared
fd "PromptConfigSchema" --type f --path "*shared*"

Repository: flipkart-incubator/langfuse

Length of output: 305


🏁 Script executed:

# Search for PromptConfigSchema in shared package
rg "PromptConfigSchema" --type ts -A 5 --max-count 5

Repository: flipkart-incubator/langfuse

Length of output: 5623


🏁 Script executed:

# Check how promptConfig is used in the file
sed -n '272,350p' web/src/features/prompts/components/prompt-detail.tsx | head -80

Repository: flipkart-incubator/langfuse

Length of output: 2472


🏁 Script executed:

# Look for error boundaries or try-catch in the component
rg "try\s*{|catch\s*{|Error\s*Boundary|ErrorBoundary" web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 209


🏁 Script executed:

# Look for error boundaries or try-catch in the component
rg "try|catch|ErrorBoundary|Error" web/src/features/prompts/components/prompt-detail.tsx | head -20

Repository: flipkart-incubator/langfuse

Length of output: 208


🏁 Script executed:

# Get the schema definition from shared package
cat packages/shared/src/features/prompts/types.ts | grep -A 10 "PromptConfigSchema"

Repository: flipkart-incubator/langfuse

Length of output: 555


🏁 Script executed:

# Check if prompt data is validated before being passed to the component
grep -A 10 "prompt" web/src/features/prompts/components/prompt-detail.tsx | grep -E "fetch|query|api" | head -5

Repository: flipkart-incubator/langfuse

Length of output: 384


🏁 Script executed:

# Look for the API query that fetches the prompt data
rg "useQuery.*prompt" web/src/features/prompts/components/prompt-detail.tsx -B 3 -A 3

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check how other components in the codebase handle PromptConfigSchema parsing
rg "PromptConfigSchema\.parse|PromptConfigSchema\.safeParse" -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 1911


🏁 Script executed:

# Check the API endpoint that returns prompt data
rg "prompts\.allVersions" --type ts -B 5 -A 10 | head -40

Repository: flipkart-incubator/langfuse

Length of output: 3487


🏁 Script executed:

# Check the return type of the API query
fd "trpc" -t f | xargs grep -l "allVersions" | head -3

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Look at the prompt type and how config is defined in the database/API response
rg "config.*:" packages/shared/src -A 2 -B 2 | grep -A 5 -B 5 "PromptVersion\|Prompt "

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check if there's server-side validation of prompt config before returning to client
rg "PromptConfigSchema" web/src/features/prompts/server -B 3 -A 3 | head -50

Repository: flipkart-incubator/langfuse

Length of output: 2673


🏁 Script executed:

# Check if the component is wrapped in error boundary or has error handling
sed -n '1,50p' web/src/features/prompts/components/prompt-detail.tsx | tail -20

Repository: flipkart-incubator/langfuse

Length of output: 1209


🏁 Script executed:

# Check the end of the component to see how it's exported
tail -20 web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 635


🏁 Script executed:

# Check if prompt query has any validation/error handling before parse
sed -n '200,275p' web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 2235


🏁 Script executed:

# Check parent page component for error boundaries
rg "ErrorBoundary" web/src/pages/project/\[projectId\]/prompts -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check the database schema for how prompt config is stored and validated
find packages/shared -name "*prompt*" -type f | xargs grep -l "config" | head -3

Repository: flipkart-incubator/langfuse

Length of output: 162


🏁 Script executed:

# Check if Zod enum validation will throw or coerce
rg "templateFormat.*enum" packages/shared -B 2 -A 2

Repository: flipkart-incubator/langfuse

Length of output: 471


🏁 Script executed:

# Verify the exact Zod version and its behavior
cat package.json | grep -A 2 -B 2 "zod"

Repository: flipkart-incubator/langfuse

Length of output: 177


🏁 Script executed:

# Check if there are other client-side parsing patterns with .parse()
rg "\.parse\(" web/src/features --type ts | grep -v ".parseLn\|parseFloat\|parseInt" | wc -l

Repository: flipkart-incubator/langfuse

Length of output: 75


🏁 Script executed:

# Compare patterns: how many use safeParse vs parse in client code
rg "Schema\.safeParse|Schema\.parse" web/src/features --type ts | head -20

Repository: flipkart-incubator/langfuse

Length of output: 2439


🏁 Script executed:

# Verify the actual API return type definition
fd "trpc" -t f | xargs grep -l "allVersions" | head -1 | xargs cat | grep -A 20 "allVersions"

Repository: flipkart-incubator/langfuse

Length of output: 53


🏁 Script executed:

# Check if promptHistory or prompt query has error handling
sed -n '240,275p' web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 1159


🏁 Script executed:

# Look at how the component handles loading/error states
sed -n '320,340p' web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 627


🏁 Script executed:

# Double-check: is there a try-catch around the parse call?
sed -n '268,280p' web/src/features/prompts/components/prompt-detail.tsx

Repository: flipkart-incubator/langfuse

Length of output: 438


Use safeParse to prevent render crashes from malformed prompt config.

Line 272 uses PromptConfigSchema.parse(), which throws on invalid config and can crash the entire page render. Since this is client-side code parsing persisted data, use safeParse() with a fallback instead. This pattern is already established in the codebase (see useExperimentPromptData.ts).

Suggested fix
-  const promptConfig = PromptConfigSchema.parse(
-    typeof prompt?.config === "object" && prompt.config !== null
-      ? prompt.config
-      : {},
-  );
+  const promptConfigResult = PromptConfigSchema.safeParse(
+    typeof prompt?.config === "object" && prompt.config !== null
+      ? prompt.config
+      : {},
+  );
+  const promptConfig = promptConfigResult.success ? promptConfigResult.data : {};
📝 Committable suggestion

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

Suggested change
const promptConfig = PromptConfigSchema.parse(
typeof prompt?.config === "object" && prompt.config !== null
? prompt.config
: {},
);
const promptConfigResult = PromptConfigSchema.safeParse(
typeof prompt?.config === "object" && prompt.config !== null
? prompt.config
: {},
);
const promptConfig = promptConfigResult.success ? promptConfigResult.data : {};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/prompts/components/prompt-detail.tsx` around lines 272 -
276, Replace the unsafe PromptConfigSchema.parse(...) call with
PromptConfigSchema.safeParse(...) and use the parsedResult.success ?
parsedResult.data : <fallback> pattern to avoid throwing on malformed persisted
config; specifically, change the code that sets promptConfig (currently using
PromptConfigSchema.parse and reading prompt?.config) to call
PromptConfigSchema.safeParse on the same input, default to {} (or the existing
default config) when safeParse returns success === false, and optionally surface
or log the parse error for debugging. This ensures promptConfig is always a
valid object and prevents render crashes.

Comment on lines +293 to +296
const forRegex = /{%[-\s]*for\s+\w+\s+in\s+([\w.]+)\s*[-\s]*%}/g;
while ((m = forRegex.exec(promptText)) !== null) {
if (m[1]) matches.add(m[1]);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Normalize Jinja2 for iterable variables to root keys.

The for-block extraction currently adds full dotted paths (e.g. user.items), while other branches add root keys (user). This creates inconsistent variable inputs and breaks expected preview resolution for nested objects.

Suggested fix
     const forRegex = /{%[-\s]*for\s+\w+\s+in\s+([\w.]+)\s*[-\s]*%}/g;
     while ((m = forRegex.exec(promptText)) !== null) {
-      if (m[1]) matches.add(m[1]);
+      const name = m[1]?.split(".")[0];
+      if (name) matches.add(name);
     }
🧰 Tools
🪛 OpenGrep (1.21.0)

[ERROR] 294-294: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/prompts/components/prompt-detail.tsx` around lines 293 -
296, The for-block extractor currently adds the full dotted iterable (from
forRegex matching in promptText) to the matches set, causing inconsistent keys;
update the logic where you process m[1] so you normalize to the root key (e.g.,
const root = m[1].split('.')[0]) and add that root to matches instead of the
full dotted path, keeping the existing forRegex, m variable, and matches Set
usage in prompt-detail.tsx.

Comment on lines +1229 to +1234
{[
LLMAdapter.OpenAI,
LLMAdapter.Anthropic,
LLMAdapter.GoogleAIStudio,
LLMAdapter.VertexAI,
].includes(currentAdapter) && renderExtraHeadersField()}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

VertexAI is listed for Extra Headers, but those headers are not sent in the backend path.

This makes VertexAI header inputs effectively no-op. Either remove LLMAdapter.VertexAI here for now, or add matching forwarding in the VertexAI execution path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/features/public-api/components/CreateLLMApiKeyForm.tsx` around lines
1229 - 1234, The form currently shows extra-header inputs for
LLMAdapter.VertexAI via CreateLLMApiKeyForm (checks currentAdapter against
LLMAdapter.VertexAI and calls renderExtraHeadersField()) but the backend
VertexAI execution path does not forward those headers, making inputs no-op;
either remove LLMAdapter.VertexAI from that client-side condition or update the
VertexAI request handling (e.g., the VertexAI execution function/class that
builds/send requests) to read the extra headers provided by the form and attach
them to outbound requests (preserving header names/values and any existing
header merging logic) so the UI inputs are actually forwarded.

Comment thread web/src/server/auth.ts
Comment on lines +164 to 168
canCreateOrganizations: canCreateOrganizations(
dbUser.email,
dbUser.admin,
),
organizations: [],
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing orgRoles in credentials provider may incorrectly deny org creation.

The credentials provider calls canCreateOrganizations(dbUser.email, dbUser.admin) without passing orgRoles. When LANGFUSE_DISABLE_ORG_CREATION=true, users who are OWNER/ADMIN in existing orgs but not site admins will be incorrectly denied org creation capability during initial authentication.

Compare with lines 863-867 where the session callback correctly passes all three parameters.

🔧 Proposed fix: Fetch org memberships for credentials flow
       const dbUser = await prisma.user.findUnique({
         where: {
           email: credentials.email.toLowerCase(),
         },
+        include: {
+          organizationMemberships: {
+            select: { role: true },
+          },
+        },
       });

       // ... existing validation ...

       const userObj: User = {
         id: dbUser.id,
         name: dbUser.name,
         email: dbUser.email,
         image: dbUser.image,
         emailVerified: dbUser.emailVerified?.toISOString(),
         featureFlags: parseFlags(dbUser.featureFlags),
         canCreateOrganizations: canCreateOrganizations(
           dbUser.email,
           dbUser.admin,
+          dbUser.organizationMemberships.map((m) => m.role),
         ),
         organizations: [],
       };
📝 Committable suggestion

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

Suggested change
canCreateOrganizations: canCreateOrganizations(
dbUser.email,
dbUser.admin,
),
organizations: [],
const dbUser = await prisma.user.findUnique({
where: {
email: credentials.email.toLowerCase(),
},
include: {
organizationMemberships: {
select: { role: true },
},
},
});
// ... existing validation ...
const userObj: User = {
id: dbUser.id,
name: dbUser.name,
email: dbUser.email,
image: dbUser.image,
emailVerified: dbUser.emailVerified?.toISOString(),
featureFlags: parseFlags(dbUser.featureFlags),
canCreateOrganizations: canCreateOrganizations(
dbUser.email,
dbUser.admin,
dbUser.organizationMemberships.map((m) => m.role),
),
organizations: [],
};
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/src/server/auth.ts` around lines 164 - 168, The credentials provider
builds the initial user object but calls canCreateOrganizations(dbUser.email,
dbUser.admin) without the orgRoles parameter, which can incorrectly deny org
creation; update the credentials flow to fetch the user's organization
memberships (orgRoles) the same way the session callback does and pass that
orgRoles value into canCreateOrganizations(dbUser.email, dbUser.admin, orgRoles)
so the provider uses the same three-argument check as the session callback.

Comment thread worker/Dockerfile Outdated
# It's important to update the index before installing packages to ensure you're getting the latest versions.
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk update && apk upgrade --no-cache libcrypto3 libssl3 libc6-compat busybox ssl_client zlib
RUN apk add --no-cache --allow-untrusted libc6-compat || true
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

--allow-untrusted and || true weaken package security and mask failures.

Using --allow-untrusted bypasses signature verification. The || true silences any installation failure, which could leave the image in an inconsistent state without indication.

🔧 Proposed fix
-RUN apk add --no-cache --allow-untrusted libc6-compat || true
+RUN apk add --no-cache libc6-compat
📝 Committable suggestion

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

Suggested change
RUN apk add --no-cache --allow-untrusted libc6-compat || true
RUN apk add --no-cache libc6-compat
🧰 Tools
🪛 Checkov (3.2.529)

[medium] 6-6: Ensure that packages with untrusted or missing signatures are not used by apk via the '--allow-untrusted' option

(CKV2_DOCKER_7)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 6, The RUN line "RUN apk add --no-cache
--allow-untrusted libc6-compat || true" disables signature checks and masks
failures; remove the --allow-untrusted and the "|| true", ensure the package is
available by running "apk update" (or add the correct --repository) before
installing, and let the command fail the build on error so installation issues
are visible; update the Dockerfile to use only "apk add --no-cache libc6-compat"
(or add the correct repository) and remove the permissive flags.

persist-credentials: false

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}

- name: Build and push ${{ matrix.component }}
uses: docker/build-push-action@v6

steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v4
uses: docker/setup-buildx-action@v3

- name: Log in to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v3

- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v5
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

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

⚠️ Outside diff range comments (2)
worker/Dockerfile (2)

73-73: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Verify downloaded dumb-init binary integrity.

Line 73 downloads an executable without checksum/signature verification; this is a supply-chain risk.

Suggested fix
-RUN wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_$(uname -m | sed s/aarch64/aarch64/ | sed s/x86_64/x86_64/) && chmod +x /usr/bin/dumb-init
+ARG DUMB_INIT_VERSION=1.2.5
+ARG DUMB_INIT_SHA256_AMD64=<expected_sha256>
+ARG DUMB_INIT_SHA256_ARM64=<expected_sha256>
+RUN arch="$(uname -m)" && \
+    file="dumb-init_${DUMB_INIT_VERSION}_${arch}" && \
+    wget -O /usr/bin/dumb-init "https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/${file}" && \
+    if [ "$arch" = "x86_64" ]; then echo "${DUMB_INIT_SHA256_AMD64}  /usr/bin/dumb-init" | sha256sum -c -; \
+    elif [ "$arch" = "aarch64" ]; then echo "${DUMB_INIT_SHA256_ARM64}  /usr/bin/dumb-init" | sha256sum -c -; \
+    else echo "unsupported arch: $arch" && exit 1; fi && \
+    chmod +x /usr/bin/dumb-init
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 73, The RUN step that downloads dumb-init directly
needs integrity verification: fetch the corresponding release SHA256 checksum or
signature from the dumb-init GitHub releases (matching v1.2.5 and the target
architecture), verify the downloaded binary against that checksum before running
chmod, and fail the build if verification fails; update the Dockerfile RUN line
that downloads /usr/bin/dumb-init to perform the checksum fetch + verification
(and remove checksum files after verification) so the image build aborts on
mismatched or missing checksum.

50-50: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Do not disable TLS verification during build.

Line 50 (NODE_TLS_REJECT_UNAUTHORIZED=0) permits insecure HTTPS and can taint build artifacts via MITM.

Suggested fix
-RUN NODE_TLS_REJECT_UNAUTHORIZED=0 turbo run build --filter=worker...
+RUN turbo run build --filter=worker...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 50, The Dockerfile RUN that prefixes the build
with NODE_TLS_REJECT_UNAUTHORIZED=0 (the RUN line invoking "turbo run build
--filter=worker...") disables TLS verification and must be removed; replace the
insecure env with a secure approach by removing the NODE_TLS_REJECT_UNAUTHORIZED
override from the RUN step, ensure the build step uses proper trusted CA
certificates (e.g., provide NODE_EXTRA_CA_CERTS or bake the CA into the base
image or pass a secure build ARG), and if you need non-default certs only for
runtime, set them at container runtime rather than during the "turbo run build"
step.
♻️ Duplicate comments (2)
worker/Dockerfile (1)

6-6: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove untrusted APK install and failure masking.

Line 6 disables signature verification and hides install failures, which can produce a silently compromised/broken image.

Suggested fix
-RUN apk add --no-cache --allow-untrusted libc6-compat || true
+RUN apk add --no-cache libc6-compat
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@worker/Dockerfile` at line 6, The RUN instruction currently disables APK
signature verification and masks failures; update the Dockerfile RUN line that
installs libc6-compat to remove the --allow-untrusted flag and the "|| true"
failure-suppressor so the build fails on error (e.g., use a plain "apk add
--no-cache libc6-compat"), and if the package is not available ensure the image
pulls from a proper Alpine repository or adds the required key/repository before
installing so installation errors are not silently ignored.
web/Dockerfile (1)

137-137: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Harden runtime bootstrap command (APK trust + binary integrity).

Line 137 still (1) bypasses APK signature checks and masks failures, and (2) installs dumb-init without integrity verification.

Suggested fix
-RUN wget -O /usr/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.5/dumb-init_1.2.5_$(uname -m | sed s/aarch64/aarch64/ | sed s/x86_64/x86_64/) && chmod +x /usr/bin/dumb-init && apk add --no-cache --allow-untrusted tzdata || true
+ARG DUMB_INIT_VERSION=1.2.5
+ARG DUMB_INIT_SHA256_AMD64=<expected_sha256>
+ARG DUMB_INIT_SHA256_ARM64=<expected_sha256>
+RUN arch="$(uname -m)" && \
+    file="dumb-init_${DUMB_INIT_VERSION}_${arch}" && \
+    wget -O /usr/bin/dumb-init "https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/${file}" && \
+    if [ "$arch" = "x86_64" ]; then echo "${DUMB_INIT_SHA256_AMD64}  /usr/bin/dumb-init" | sha256sum -c -; \
+    elif [ "$arch" = "aarch64" ]; then echo "${DUMB_INIT_SHA256_ARM64}  /usr/bin/dumb-init" | sha256sum -c -; \
+    else echo "unsupported arch: $arch" && exit 1; fi && \
+    chmod +x /usr/bin/dumb-init && \
+    apk add --no-cache tzdata
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/Dockerfile` at line 137, The Dockerfile RUN line currently disables APK
trust and masks failures while downloading dumb-init; change the RUN that uses
wget and apk so it: (1) removes --allow-untrusted and the "|| true" mask and
fails the build on errors, (2) installs tzdata via apk add --no-cache tzdata
(not allowing unverified packages), and (3) verifies the dumb-init binary
integrity before moving to /usr/bin (e.g., download to /tmp/dumb-init, verify a
pinned SHA256 checksum or PGP signature, then chmod and mv to
/usr/bin/dumb-init); alternatively prefer installing dumb-init from the distro
apk repo if available. Ensure the modified RUN still uses uname -m mapping logic
if needed and that failures propagate so the build fails on verification or apk
errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@worker/Dockerfile`:
- Line 73: The RUN step that downloads dumb-init directly needs integrity
verification: fetch the corresponding release SHA256 checksum or signature from
the dumb-init GitHub releases (matching v1.2.5 and the target architecture),
verify the downloaded binary against that checksum before running chmod, and
fail the build if verification fails; update the Dockerfile RUN line that
downloads /usr/bin/dumb-init to perform the checksum fetch + verification (and
remove checksum files after verification) so the image build aborts on
mismatched or missing checksum.
- Line 50: The Dockerfile RUN that prefixes the build with
NODE_TLS_REJECT_UNAUTHORIZED=0 (the RUN line invoking "turbo run build
--filter=worker...") disables TLS verification and must be removed; replace the
insecure env with a secure approach by removing the NODE_TLS_REJECT_UNAUTHORIZED
override from the RUN step, ensure the build step uses proper trusted CA
certificates (e.g., provide NODE_EXTRA_CA_CERTS or bake the CA into the base
image or pass a secure build ARG), and if you need non-default certs only for
runtime, set them at container runtime rather than during the "turbo run build"
step.

---

Duplicate comments:
In `@web/Dockerfile`:
- Line 137: The Dockerfile RUN line currently disables APK trust and masks
failures while downloading dumb-init; change the RUN that uses wget and apk so
it: (1) removes --allow-untrusted and the "|| true" mask and fails the build on
errors, (2) installs tzdata via apk add --no-cache tzdata (not allowing
unverified packages), and (3) verifies the dumb-init binary integrity before
moving to /usr/bin (e.g., download to /tmp/dumb-init, verify a pinned SHA256
checksum or PGP signature, then chmod and mv to /usr/bin/dumb-init);
alternatively prefer installing dumb-init from the distro apk repo if available.
Ensure the modified RUN still uses uname -m mapping logic if needed and that
failures propagate so the build fails on verification or apk errors.

In `@worker/Dockerfile`:
- Line 6: The RUN instruction currently disables APK signature verification and
masks failures; update the Dockerfile RUN line that installs libc6-compat to
remove the --allow-untrusted flag and the "|| true" failure-suppressor so the
build fails on error (e.g., use a plain "apk add --no-cache libc6-compat"), and
if the package is not available ensure the image pulls from a proper Alpine
repository or adds the required key/repository before installing so installation
errors are not silently ignored.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ba374529-11be-4fd2-8193-02c93ac36e75

📥 Commits

Reviewing files that changed from the base of the PR and between 8e4de91 and 990439a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • .devcontainer/Dockerfile
  • packages/shared/package.json
  • packages/shared/src/server/index.ts
  • web/Dockerfile
  • web/package.json
  • web/src/env.mjs
  • worker/Dockerfile
💤 Files with no reviewable changes (1)
  • web/src/env.mjs
✅ Files skipped from review due to trivial changes (1)
  • packages/shared/src/server/index.ts

@kingster kingster changed the base branch from main to fk May 20, 2026 07:54
napan.vijayvargiya and others added 12 commits May 20, 2026 13:37
…ates-table

Pass templateFormat through when cloning an eval template so the object
satisfies the PartialEvalTemplate type now that templateFormat is a required
field on EvalTemplate following the Jinja2 eval support migration.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…te shape

The ConfigWithTemplateSchema Zod object used by jobConfigsByTarget defines the
evalTemplate sub-schema explicitly; templateFormat was not listed, so the
inferred EvalJobConfigWithTemplate type was missing the field added in the
Jinja2 migration. Adding it here fixes the TS build error in
useExperimentEvaluatorData.ts.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace "cliente" (flagged by codespell as misspelling of "client")
with "consumidor" in the Spanish example string.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@napan24 napan24 changed the title Jinja2 Integration to Langfuse feat(prompts): add Jinja2 conditional templating with compiled preview May 22, 2026
Sign up for free to 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.

3 participants