Skip to content

Unify .env generation between quickstart CLI and contributor flows#2212

Merged
miles-kt-inkeep merged 13 commits intomainfrom
feat/unify-env-generation
Feb 24, 2026
Merged

Unify .env generation between quickstart CLI and contributor flows#2212
miles-kt-inkeep merged 13 commits intomainfrom
feat/unify-env-generation

Conversation

@nick-inkeep
Copy link
Copy Markdown
Collaborator

@nick-inkeep nick-inkeep commented Feb 20, 2026

Summary

Unifies .env generation between the quickstart CLI (create-agents) and the contributor flow (git clone + pnpm setup-dev). The quickstart CLI previously hardcoded ~30 env vars as a template string and generated 5 secrets inline, diverging from the contributor flow which copies .env.example and generates only 2 JWT secrets. This caused:

  1. Missing INKEEP_AGENTS_MANAGE_API_BYPASS_SECRET — broke auto-login and inkeep push during pnpm setup-dev
  2. Inconsistent defaults — OTEL/SigNoz pointed at cloud vs local; contributor flow had 3 secrets the CLI generated but generateJwtKeys() didn't
  3. Drift — any new env var added to .env.example wasn't picked up by the CLI

Additionally fixes two pre-existing CI e2e test failures:
4. 403 INVALID_ORIGIN on signup/login — auth API calls used 127.0.0.1 as Origin header, but Better Auth cookies are scoped to localhost
5. Dashboard standalone server not foundstartDashboardServer() didn't resolve symlinks when using locally-linked packages via linkLocalPackages()

Architectural decisions

Copy+inject over hardcoded template string. createEnvironmentFiles() now reads .env.example and injects CLI-prompted values (API keys, project ID) by finding and replacing lines. This means any new env var added to .env.example is automatically available to CLI users without code changes.

Secret generation deferred to generateSecrets(). The CLI no longer generates any secrets (RSA keys, signing secrets, auth secrets). All secret generation is consolidated in generateSecrets() (renamed from generateJwtKeys()), which runs during pnpm setup-dev. This ensures both flows use identical secret generation logic.

Conservative placeholder detection. generateSecrets() only replaces values that are empty, commented out, or match exact placeholder strings (your-secret-key-change-in-production, adminADMIN!@12). User-customized values are never overwritten.

localhost for auth, 127.0.0.1 for health checks. The e2e test has two URL constants: manageApiUrl (127.0.0.1 — for health checks and non-auth API calls) and dashboardApiUrl (localhost — for auth calls and dashboard env vars). Auth calls must use localhost as Origin because Better Auth's cookie domain is localhost.

Changes

create-agents-template/.env.example

  • Replaced 21-line minimal template with comprehensive 87-line version derived from the monorepo's .env.example
  • Includes all required env vars: DB URLs, API URLs, SpiceDB, bypass secret, OTEL, SigNoz, Nango, MCP OAuth
  • JWT keys/signing secret commented out (prefixed with # ) for generateSecrets() detection
  • OTEL_EXPORTER_OTLP_TRACES_ENDPOINT= set to empty value (not commented out) so setup-dev:optional's set_env_var can find and replace in-place without creating duplicates
  • SigNoz Cloud header (OTEL_EXPORTER_OTLP_TRACES_HEADERS) commented with explanatory note that it's only needed for SigNoz Cloud, not local dev
  • Uses localhost throughout (not 127.0.0.1)
  • Omits monorepo-specific sections: GitHub App, Slack, PostHog, feature flags

packages/agents-core/src/setup/setup.ts

  • Renamed generateJwtKeys()generateSecrets()
  • Extended with secretDefs array handling 3 additional secrets: INKEEP_AGENTS_JWT_SIGNING_SECRET (hex 32 bytes), BETTER_AUTH_SECRET (hex 32 bytes), INKEEP_AGENTS_MANAGE_UI_PASSWORD (base64url 6 bytes)
  • Preserved existing RSA key pair generation behavior
  • Conservative: only replaces commented-out lines, empty values, or exact placeholder strings

packages/create-agents/src/utils.ts

  • Rewrote createEnvironmentFiles() to copy+inject pattern (~20 lines, down from ~80)
  • Removed all inline secret generation (no crypto imports, no RSA, no randomBytes)
  • Injects only CLI-prompted values: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, AZURE_API_KEY, DEFAULT_PROJECT_ID
  • Changed CLI "Next steps" output URL from 127.0.0.1:3002 to localhost:3002

packages/create-agents/src/__tests__/e2e/quickstart.test.ts

  • Updated .env assertions to match copy+inject pattern (no JWT secret check, unquoted localhost URL)
  • Fixed signup and login API calls to use dashboardApiUrl (localhost) as Origin header instead of manageApiUrl (127.0.0.1)

packages/create-agents/src/__tests__/e2e/utils.ts

  • Added fs.realpath() to startDashboardServer() to resolve symlinks when packages are linked via linkLocalPackages()
  • Improved error message with symlink resolution path and actionable suggestion to run turbo build

packages/create-agents/package.json

  • Added turbo run build step to test:e2e and test:e2e:watch scripts to ensure dependent packages (@inkeep/create-agents, @inkeep/agents-api, @inkeep/agents-cli, @inkeep/agents-manage-ui) are built before e2e tests run

Tests

  • Added generate-secrets.test.ts with 5 test cases: all-placeholder, all-custom, mixed, empty-value, missing-lines
  • Updated utils.test.ts with 4 new tests for copy+inject approach, bypass secret presence, no inline secret generation
  • Aligned test mock .env.example content with actual template (OTEL endpoint empty value)

Documentation

  • Updated environment-configuration.mdx and get-started.mdx to reflect unified env generation flow
  • Fixed 127.0.0.1localhost references in CLI reference docs

Test plan

Manual QA verified with real CLI binary, real crypto, Docker databases, API server, and ad-hoc test scripts. Full re-verification after rebase onto main (commit 142bbd17f). ~300 total assertions, 0 failures.

Formal tests (25 passing)

  • generate-secrets.test.ts — 5/5: all-placeholder, all-custom, mixed, empty-value, missing-lines
  • utils.test.ts — 20/20: template logic, env file generation, skip-provider, security

Template completeness (35 assertions)

Validated create-agents-template/.env.example for completeness, correctness, and separation from monorepo.

  • CLI injection vars — All 5 present: ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, AZURE_API_KEY, DEFAULT_PROJECT_ID
  • generateSecrets vars — All 5 present: JWT signing secret, JWT private/public key (commented out), BETTER_AUTH_SECRET, INKEEP_AGENTS_MANAGE_UI_PASSWORD
  • Critical runtime vars — All 6 present: ENVIRONMENT, both DB URLs, API URL, TENANT_ID, bypass secret
  • No 127.0.0.1 — Zero occurrences, 11 localhost URLs
  • Placeholder valuesBETTER_AUTH_SECRET=your-secret-key-change-in-production, UI_PASSWORD=adminADMIN!@12
  • JWT keys commented out — Private key, public key, signing secret all prefixed with # for generateSecrets detection
  • Monorepo vars omittedGITHUB_APP_ID, SLACK_CLIENT_ID, PUBLIC_POSTHOG_KEY, NEXT_PUBLIC_ENABLE_WORK_APPS all absent
  • Third-party services — All 6 present: Nango, SigNoz, OTEL, OAuth, SpiceDB
  • Variable count — 32 active vars, 3 commented vars, 35 total

Live CLI flow (22 assertions)

Ran the real compiled CLI binary (node dist/index.js) against local templates with --local-agents-prefix, --skip-install, --disable-git.

  • File structure — 9/9: .env, .env.example, package.json, docker-compose, inkeep.config.ts, project template, 3 app dirs
  • Bypass secret presentINKEEP_AGENTS_MANAGE_API_BYPASS_SECRET=test-bypass-secret-for-ci (the bug this PR fixes)
  • DEFAULT_PROJECT_ID injected — Set to activities-planner
  • Secrets deferred — Auth secret, UI password are still placeholders; JWT keys still commented out (for setup-dev)
  • Structural parity — .env has exactly 32 active vars matching .env.example
  • localhost consistency — 11 localhost URLs, zero 127.0.0.1 references
  • Third-party services preserved — Nango, SigNoz, OTEL, OAuth, SpiceDB all present

Live setup-dev flow (26 assertions)

Ran the real generateSecrets logic with real node:crypto against the CLI-produced .env file.

  • Real RSA keys — Generated 2048-bit RSA key pair, base64-encoded, decodes to valid PEM (BEGIN PRIVATE KEY / BEGIN PUBLIC KEY)
  • Private key — 2272 chars, longer than public key (604 chars) — correct for RSA
  • Real hex secrets — JWT signing secret and auth secret are 64 hex chars (32 bytes each), valid hex
  • Real password — UI password replaced with base64url random value (8 chars)
  • Placeholder removalyour-secret-key-change-in-production and adminADMIN!@12 both gone
  • CLI values preserved — Project ID, DB URLs, bypass secret all survive secret generation
  • Unique secrets — Signing secret != auth secret
  • Idempotency — Second run: .env content byte-for-byte identical

E2E 403 Origin fix (10 assertions)

Parsed the actual test file to verify the Origin header contract.

  • URL constantsmanageApiUrl = http://127.0.0.1:3002 (health checks), dashboardApiUrl = http://localhost:3002 (auth)
  • Health check — Uses manageApiUrl (127.0.0.1)
  • sign-up Origin — Uses dashboardApiUrl (localhost), not manageApiUrl (127.0.0.1)
  • sign-in Origin — Uses dashboardApiUrl (localhost), not manageApiUrl (127.0.0.1)
  • All Origins — 2 uses of dashboardApiUrl, 0 uses of manageApiUrl as Origin
  • Dashboard envINKEEP_AGENTS_API_URL: dashboardApiUrl
  • .env assertions — Uses localhost:3002 (not 127.0.0.1), no JWT_SIGNING_SECRET check (deferred)
  • Symlink resolutionfs.realpath() before standalone dir lookup, error includes resolved path + build suggestion
  • Cookie domain contracttrustedOrigins includes localhost:3000, localhost:3002; no 127.0.0.1

Docker E2E: setup-dev with real databases

Ran the real pnpm setup-dev against Docker containers (Doltgres :5432, PostgreSQL :5433, SpiceDB :50051).

  • Step 1: .env created.env.example.env copied with correct header and all sections
  • Step 2: Secrets generated — JWT private key (2272 chars, valid PEM), JWT public key (602 chars, valid PEM), signing secret (64 hex), auth secret (64 hex, placeholder replaced), UI password (8 chars, no longer default)
  • Step 3: Port conflicts handled gracefully — Detected existing Docker containers, continued using existing DBs
  • Step 4: Runtime migrations — Completed successfully (manage migration has pre-existing Doltgres constraint issue unrelated to PR)
  • Step 5: Auth init — Organization + admin user created with generated password
  • No 127.0.0.1 — Zero occurrences in generated .env, 12 localhost URLs

Docker E2E: Idempotency test

  • Second setup-dev run — "JWT keys already configured, skipping generation", .env checksum identical (md5: 114afe85094b00f593c68bd859e19b4d before and after)

Docker E2E: API server + auth flow

Started the API server from the PR branch against Docker databases.

  • Health endpoint — HTTP 204 (on localhost:3002)
  • Sign-in (localhost:3002 Origin) — HTTP 200 with session token and user data
  • Sign-in (localhost:3000 Origin) — HTTP 200 (both localhost ports trusted)
  • Bypass secret auth — HTTP 200, returns project data from the manage DB

Additional verification

  • CI config — No CI workflow changes needed; all configs compatible with PR changes
  • Docs accuracy — Both MDX files correctly describe unified flow, <generated by setup-dev>, all 4 secret types, localhost URLs
  • Error handling — Missing .env.example throws with clear message; readFile catches missing .env; JWT failure warns with manual fallback
  • Exact matching — CLI uses startsWith for var matching (no partial collisions); placeholders are exact string comparisons
  • Post-rebase verification — Full QA suite re-run after rebase onto main (10 commits, no conflicts). All scenarios verified clean.

How to verify

  1. Quickstart flow: Run npx @inkeep/create-agents my-test-project, provide API keys, run pnpm setup-dev — verify .env has all vars including INKEEP_AGENTS_MANAGE_API_BYPASS_SECRET and generated secrets
  2. Contributor flow: Clone repo, run pnpm setup-dev — verify .env created from .env.example with all secrets generated
  3. Check that pnpm setup-dev is idempotent (running twice doesn't regenerate secrets)
  4. E2e test: Run the CI e2e test — auth calls should no longer get 403 INVALID_ORIGIN, and dashboard server should start correctly with linked packages

🤖 Generated with Claude Code

@vercel
Copy link
Copy Markdown

vercel Bot commented Feb 20, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agents-api Ready Ready Preview, Comment Feb 24, 2026 7:33am
agents-docs Ready Ready Preview, Comment Feb 24, 2026 7:33am
agents-manage-ui Ready Ready Preview, Comment Feb 24, 2026 7:33am

Request Review

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 20, 2026

🦋 Changeset detected

Latest commit: 15d0c77

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@inkeep/agents-core Patch
@inkeep/create-agents Patch
@inkeep/agents-api Patch
@inkeep/agents-manage-ui Patch
@inkeep/agents-cli Patch
@inkeep/agents-sdk Patch
@inkeep/agents-work-apps Patch
@inkeep/ai-sdk-provider Patch
@inkeep/agents-mcp Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nick-inkeep
Copy link
Copy Markdown
Collaborator Author

CI/CD Failure Investigation

All 3 CI failures are pre-existing on main — not caused by this PR's changes.

Evidence

Check Error Main Branch Status
ci (Cypress E2E) Doltgres: "table not found: projects" 18/20 recent runs failing on main
Create Agents E2E Tests "Constraint sub_agent_skills_sub_agent_skill_unique does not exist" Same Doltgres migration issue as main
Vercel – agents-docs Deployment failed Also failing on main (verified via commit status)

Why these can't be caused by this PR

This PR only touches:

  • create-agents-template/.env.example (template file, not used in CI)
  • packages/create-agents/src/utils.ts (CLI utility)
  • packages/agents-core/src/setup/setup.ts (local dev setup script)
  • Test files in both packages

None of these files affect database migrations, Doltgres schema, Cypress E2E tests, or the agents-docs Vercel deployment.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(2) Total Issues | Risk: Low

🟠⚠️ Major (1) 🟠⚠️

Inline Comments:

  • 🟠 Major: utils.ts:518 Missing error handling for .env.example read — users get cryptic ENOENT on corrupted template

🟡 Minor (1) 🟡

Inline Comments:

  • 🟡 Minor: setup.ts:372 Success message potentially misleading after JWT generation failure

💭 Consider (4) 💭

💭 1) create-agents-template/.env.example:38 AZURE_API_KEY not in monorepo .env.example

Issue: The template adds AZURE_API_KEY which doesn't exist in the monorepo's .env.example or agents-api/src/env.ts schema.

Why: Creates asymmetry — template supports Azure but the core platform doesn't explicitly validate this env var. This is an intentional enhancement per the PR, but worth documenting.

Fix: Consider adding AZURE_API_KEY to the monorepo .env.example for consistency, or document this template-specific enhancement.

Refs: agents-api/src/env.ts:132-145

💭 2) packages/agents-core/src/setup/__tests__/generate-secrets.test.ts Missing test for .env read failure differentiation

Issue: generateSecrets() catches all .env read errors with .catch(() => ''), but no test verifies this behavior or distinguishes ENOENT from permission errors.

Why: While the silent catch is intentional design, a test would document this behavior and catch regressions.

Fix: Add test case verifying behavior when .env read fails.

💭 3) packages/agents-core/src/setup/__tests__/generate-secrets.test.ts Missing test for whitespace-only secret values

Issue: The function uses .trim() to detect empty values, but no test verifies that whitespace-only values like BETTER_AUTH_SECRET= are correctly replaced.

Why: Edge case that could lead to authentication failures if whitespace secrets slip through.

Fix: Add test case with whitespace-only values.

💭 4) packages/agents-core/src/setup/__tests__/generate-secrets.test.ts Missing test for RSA key generation failure recovery

Issue: JWT key generation has a try-catch that logs and continues, but no test verifies other secrets are still generated after RSA failure.

Why: Documents graceful degradation behavior and prevents regressions.

Fix: Add test mocking generateKeyPairSync to throw, verifying other secrets are still generated.


💡 APPROVE WITH SUGGESTIONS

Summary: This is a well-designed unification of the environment setup flows. The architectural decision to copy+inject from .env.example rather than hardcoding a template string is sound and reduces maintenance burden. The secretDefs array pattern for secret generation is clean and extensible. The main actionable item is adding error handling for the .env.example read in the CLI utility to provide a better user experience when template cloning fails. The test coverage is comprehensive (55 tests) with only minor edge cases worth considering.

Discarded (8)
Location Issue Reason Discarded
create-agents-template/.env.example:40-42 DEFAULT_PROJECT_ID asymmetry with monorepo Intentional template-specific variable per PR design
create-agents-template/.env.example:69 Section header formatting inconsistency Pre-existing issue in monorepo, not introduced by this PR
Template omits sections Missing GitHub/Slack/PostHog sections Intentional per PR description — not applicable to quickstart
setup.ts:268 Function rename Positive observation — follows existing patterns
utils.test.ts Variable case sensitivity test Low confidence, template is controlled, unlikely scenario
setup.ts:269 Silent catch for .env read Intentional design — treat missing .env as empty is correct behavior
DevOps findings (6) Various All INFO severity — positive observations confirming good practices
Reviewers (5)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-errors 3 0 1 0 2 0 0
pr-review-tests 5 0 3 0 0 0 2
pr-review-consistency 5 0 1 0 0 0 4
pr-review-devops 6 0 0 0 0 0 6
pr-review-standards 0 0 0 0 0 0 0
Total 19 0 5 0 2 0 12

Note: pr-review-standards returned no findings — the code quality is solid.

Comment thread packages/create-agents/src/utils.ts Outdated
Comment thread packages/agents-core/src/setup/setup.ts
@github-actions github-actions Bot deleted a comment from claude Bot Feb 20, 2026
@vercel vercel Bot temporarily deployed to Preview – agents-docs February 20, 2026 06:10 Inactive
@nick-inkeep
Copy link
Copy Markdown
Collaborator Author

Review assessment — 2 inline threads from automated review:

Thread 1: Missing error handling for .env.example read (utils.ts:518) — Accepted

Valid suggestion. Wrapped fs.readFile('.env.example') in try-catch with a descriptive error message. If the template clone is corrupted after degit, users now see: "Could not read .env.example from the template. The template may be corrupted — try running the command again." instead of a raw ENOENT. Fixed in 700f4a2.

Thread 2: Success message after JWT failure (setup.ts:372) — Declined

The current logging is correct and not misleading. JWT generation failures are already logged separately at line 315 with logError('Failed to generate JWT keys - playground may not work', error). The "Secrets generated and added to .env" message at line 372 accurately refers to the remaining secrets (JWT signing secret, Better Auth secret, UI password) that were successfully generated. Users see both messages — the error for JWT keys and the success for the other secrets — which correctly communicates the state. Adding a jwtGenerationFailed flag would add complexity for a rare edge case that's already well-handled.

@vercel vercel Bot temporarily deployed to Preview – agents-docs February 20, 2026 06:10 Inactive
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 commit, 1 file, 8 lines changed).

Delta Analysis

The delta consists of a single change in packages/create-agents/src/utils.ts:

let envExampleContent: string;
try {
  envExampleContent = await fs.readFile('.env.example', 'utf-8');
} catch {
  throw new Error(
    'Could not read .env.example from the template. The template may be corrupted — try running the command again.',
  );
}

This directly addresses the 🟠 Major issue raised in the previous review — users now see a descriptive error message instead of a cryptic ENOENT when the template is corrupted.

Prior Feedback Status

Issue Status
🟠 Major: Missing error handling for .env.example read Addressed in 700f4a2
🟡 Minor: Success message after JWT failure Declined — author's explanation is reasonable (errors are already logged separately)

New Findings in Delta

None. The error handling implementation is correct:

  • Uses try-catch around the file read
  • Throws with a user-friendly message explaining the likely cause and remediation
  • Matches the suggested fix from the prior review

✅ APPROVE

Summary: The delta cleanly addresses the Major issue from the prior review. The error handling is well-implemented with a helpful message. The author's reasoning for declining the Minor suggestion (JWT failure message) is valid — the separate error log already communicates the failure clearly. Ship it! 🚀

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
Total 0 0 0 0 0 0 0

Note: No subagent reviewers were dispatched for this delta — the change is a minimal error-handling fix that doesn't require specialized review.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 commit, 4 files changed since last automated review).

Delta Analysis

The delta commit (dadb84a6b) makes three categories of consistency improvements:

  1. Documentation updates (agents-docs/content/community/contributing/*.mdx)

    • Updated to reflect that secrets are now generated by pnpm setup-dev rather than being hardcoded placeholders
    • Accurate description: "Generate secrets (JWT keys, signing secret, auth secret, UI password) if not already configured"
  2. URL consistency (packages/create-agents/src/utils.ts)

    • Changed CLI output URLs from 127.0.0.1 to localhost to align with .env.example template
    • Updated inkeep.config.ts template to use localhost:3002
  3. Test assertion updates (packages/create-agents/src/__tests__/e2e/quickstart.test.ts)

    • Updated assertions to match localhost URL format
    • Removed expectation of inline-generated INKEEP_AGENTS_JWT_SIGNING_SECRET (now deferred to generateSecrets())
    • Added clarifying comment explaining the new behavior

Prior Feedback Status

Issue Status
🟠 Major: Missing error handling for .env.example read Addressed in 700f4a2
🟡 Minor: Success message after JWT failure Declined — author's explanation is valid

New Findings in Delta

None. The delta changes are:

  • Internally consistent with the PR's architectural decisions
  • Accurately documented in the updated MDX files
  • Properly tested with updated assertions

✅ APPROVE

Summary: The delta is a clean consistency pass — docs accurately reflect the new secret generation behavior, URLs are aligned to use localhost consistently, and test assertions match the expected behavior. Prior feedback was appropriately addressed. This unification reduces maintenance burden and eliminates drift between quickstart and contributor flows. Ship it! 🚀

Reviewers (2)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-docs 0 0 0 0 0 0 0
pr-review-standards 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: Both reviewers confirmed the delta changes are correct with no issues.

Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 commit, 2 files changed since last automated review).

Delta Analysis

The delta commit (893862e7f) contains two targeted E2E test infrastructure fixes:

1. Origin Header Fix (quickstart.test.ts:210, 264)

Changed Origin: manageApiUrl to Origin: dashboardApiUrl for Better Auth sign-up and sign-in fetch calls.

  • Why correct: Better Auth's trustedOrigins includes http://localhost:3000 and http://localhost:3002 but NOT http://127.0.0.1:*. The dashboard sets auth cookies scoped to localhost, so the Origin header must match.
  • Verified: Cross-referenced with /packages/agents-core/src/auth/auth.ts:266-272 — the fix aligns with the configured trusted origins.

2. Symlink Resolution (utils.ts:277-289)

Added fs.realpath() to resolve symlinks when locating the manage-ui package, with improved error messaging.

  • Why correct: The test uses link: protocol to symlink local packages. Without realpath(), the code looks for .next/standalone/ inside the symlink rather than the actual monorepo directory where the build artifacts exist.
  • Error improvement: Now includes the original symlink path for debugging and actionable guidance ("run turbo build").

Prior Feedback Status

Issue Status
🟠 Major: Missing error handling for .env.example read Addressed in 700f4a2
🟡 Minor: Success message after JWT failure Declined — author's explanation is valid

New Findings in Delta

None. The delta changes are:

  • Correctly fixing CORS/cookie domain issues in E2E auth tests
  • Properly handling symlinked packages in the test infrastructure
  • Improving error messages with actionable guidance

✅ APPROVE

Summary: Clean delta! The E2E test infrastructure fixes are correct and well-reasoned. The Origin header fix addresses a real CORS mismatch (verified against the auth config), and the symlink resolution handles pnpm's link: protocol properly. Prior feedback was appropriately addressed. This PR is ready to ship. 🚀

Reviewers (2)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-tests 0 0 0 0 0 0 0
pr-review-standards 0 0 0 0 0 0 0
Total 0 0 0 0 0 0 0

Note: Both reviewers confirmed the delta changes are correct with no issues. Minimal reviewer set selected due to the narrow scope (test infrastructure only).

@github-actions github-actions Bot deleted a comment from claude Bot Feb 20, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This PR unifies .env generation between the quickstart CLI (create-agents) and contributor flow (pnpm setup-dev). The architectural decision to use a "copy+inject" pattern from .env.example is clean and reduces maintenance burden. All prior Major/Minor issues have been addressed or appropriately declined.

💭 Consider (2) 💭

💭 1) generate-secrets.test.ts Missing test for whitespace-only secret values

Issue: The generateSecrets() function uses .trim() to detect empty values, but no test verifies that whitespace-only values like BETTER_AUTH_SECRET= are correctly replaced.

Why: Edge case that could lead to auth failures if whitespace secrets slip through. Low likelihood but the test would document the behavior.

Fix: Add test case with whitespace-only values:

it('should generate secrets when values are whitespace-only', async () => {
  mockEnvFileContent = [
    'INKEEP_AGENTS_JWT_SIGNING_SECRET=   ',
    'BETTER_AUTH_SECRET=  \t  ',
  ].join('\n');
  // ... verify replacement occurs
});

Refs: setup.ts:356

💭 2) utils.test.ts Missing test for DEFAULT_PROJECT_ID injection

Issue: The createEnvironmentFiles() function injects DEFAULT_PROJECT_ID from config.projectId, but no test explicitly verifies this injection.

Why: Nice-to-have coverage for completeness. If the injection regresses, users would have an empty project ID.

Fix: Add assertion to existing test:

expect(fs.writeFile).toHaveBeenCalledWith(
  '.env',
  expect.stringContaining('DEFAULT_PROJECT_ID=activities-planner')
);

Refs: utils.ts:533


✅ APPROVE

Summary: This is a well-designed unification of the environment setup flows. The "copy+inject" pattern from .env.example is cleaner than the previous hardcoded template string, and the secretDefs array pattern for secret generation is clean and extensible. All prior feedback was appropriately addressed. The two Consider items are optional test coverage improvements that don't block merging. Ship it! 🚀

Discarded (4)
Location Issue Reason Discarded
generate-secrets.test.ts Missing test for RSA key generation failure Previously raised in prior review and declined by author with valid reasoning
utils.test.ts Missing test for partial variable name collision Low confidence, unlikely regression with startsWith() pattern
create-agents-template/.env.example Template diverges from monorepo .env.example Intentional by design — template is simplified for quickstart users
create-agents-template/.env.example Setup instructions differ from monorepo Intentional simplification for quickstart users
Reviewers (6)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-standards 0 0 0 0 0 0 0
pr-review-consistency 2 0 0 0 0 0 2
pr-review-docs 0 0 0 0 0 0 0
pr-review-tests 4 0 2 0 0 0 2
pr-review-devops 0 0 0 0 0 0 0
pr-review-errors 0 0 0 0 0 0 0
Total 6 0 2 0 0 0 4

Note: Low findings count reflects that this is a clean, well-tested PR with prior issues already addressed.

@github-actions github-actions Bot deleted a comment from claude Bot Feb 24, 2026
@itoqa
Copy link
Copy Markdown

itoqa Bot commented Feb 24, 2026

Ito Test Report ❌

21 test cases ran. 20 passed, 1 failed.

This test run validated the unified .env generation between the quickstart CLI and contributor flows, the Origin header CSRF fix, and the dashboard standalone server symlink resolution. The core functionality works correctly: authentication endpoints accept localhost Origin headers (ROUTE-2, ROUTE-3), login flows work properly (ROUTE-1, EDGE-3, EDGE-4), session management behaves as expected (EDGE-5, EDGE-7, EDGE-8), and the dashboard standalone server starts correctly with symlink resolution (LOGIC-3). One security issue was identified: unauthenticated users can view sensitive project data without being redirected to the login page (EDGE-9).

✅ Passed (20)
Test Case Summary Timestamp Screenshot
ROUTE-1 Login succeeded - redirected from /login to /no-organization, confirming authentication works 5:17 ROUTE-1_5-17.png
ROUTE-2 Sign-up endpoint returned 200 with localhost Origin header - user created successfully 6:08 ROUTE-2_6-08.png
ROUTE-3 Sign-in endpoint returned 200 with localhost Origin header - session cookie set for [email protected] 6:25 ROUTE-3_6-25.png
ROUTE-5 Dev-session returned 200 with session cookie, get-session confirmed [email protected] identity 6:48 ROUTE-5_6-48.png
ROUTE-6 Health endpoint returned 204 No Content - API is responsive 21:53 ROUTE-6_21-53.png
LOGIC-1 API health check confirms .env was generated from .env.example with correct values - port 3002 accessible 22:01 LOGIC-1_22-01.png
LOGIC-2 Network analysis complete - all 41 requests use localhost, 0 use 127.0.0.1 23:53 LOGIC-2_23-53.png
LOGIC-3 Login page at /login redirected to /projects - Next.js standalone server with symlink resolution working correctly 22:32 LOGIC-3_22-32.png
EDGE-1 Verified .env secrets not overwritten - login works with expected password and session encryption valid 21:05 EDGE-1_21-05.png
EDGE-2 Mixed origin test - POST with Origin http://127.0.0.1:3002 returned 200 OK in dev mode 25:02 EDGE-2_25-02.png
EDGE-3 Wrong password submitted - alert shows 'Invalid email or password', URL remains /login, email preserved 0:46 EDGE-3_0-46.png
EDGE-4 Login form validation rejects empty fields - form did not submit, URL remains /login 0:25 EDGE-4_0-25.png
EDGE-5 Authenticated user redirected from /login to projects page 17:35 EDGE-5_17-35.png
EDGE-6 Verified createEnvironmentFiles graceful error handling at utils.ts:517-525 and confirmed server running with correct .env 24:33 EDGE-6_24-33.png
EDGE-7 Session cookie set without Domain attribute (host-only). Cookie: Path=/, HttpOnly, SameSite=Lax, no Domain - host-only in browsers 26:03 EDGE-7_26-03.png
EDGE-8 After logout - redirected to /login page, login form visible, session cookies cleared 30:10 EDGE-8_30-10.png
ADV-1 Spoofed 127.0.0.1 Origin - POST returned 200 OK in dev mode, CORS allows both localhost and 127.0.0.1 25:16 ADV-1_25-16.png
ADV-2 Login page loaded - verified no bypass secret in HTML or JS bundles 32:16 ADV-2_32-16.png
ADV-3 Brute force test complete - 10 attempts returned 401, recovery login returned 200 32:46 ADV-3_32-46.png
ADV-4 Invalid Origin header tests complete - all 5 variants returned 200 OK, no crashes 33:18 ADV-4_33-18.png
❌ Failed (1)
Test Case Summary Timestamp Screenshot
EDGE-9 Unauthenticated access to projects page shows actual project data without redirect to /login 30:49 EDGE-9_30-49.png
Direct navigation to protected route without auth redirects to login – Failed
  • Where: /{tenantId}/projects page in the dashboard UI

  • Steps to reproduce:

    1. Clear all browser cookies (ensure no session exists)
    2. Disable dev auto-login (if enabled)
    3. Navigate directly to http://localhost:3000/{tenantId}/projects
  • What failed: Expected unauthenticated users to be redirected to /login with no sensitive data exposed. Instead, the projects page rendered with actual project data visible (project names, descriptions, dates). The page showed "Toggle theme" instead of user menu and API calls returned 401, but sensitive data was already displayed.

  • Code analysis: The projects page is a Server Component that calls fetchProjects() on the server without any authentication check. When the API returns 401, it catches the error and renders FullPageError, which uses a client-side useEffect to redirect to login. However, by the time the redirect happens, the server has already rendered HTML that may contain cached or partially loaded data. There is no Next.js middleware to intercept unauthenticated requests before rendering.

  • Relevant code:

    agents-manage-ui/src/app/[tenantId]/projects/page.tsx (lines 17-52)

    async function ProjectsPage({ params }: PageProps<'/[tenantId]/projects'>) {
      const { tenantId } = await params;
    
      try {
        const { data } = await fetchProjects(tenantId);
        return data.length ? (
          <>
            <PageHeader
              title={metadata.title}
              description={metadata.description}
              action={<CreateProjectButton tenantId={tenantId} />}
            />
            <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3 md:gap-4">
              {data.map((project) => (
                <ProjectItem key={project.id} {...project} tenantId={tenantId} />
              ))}
            </div>
          </>
        ) : (
          // ... empty state
        );
      } catch (error) {
        return <FullPageError errorCode={getErrorCode(error)} context="projects" />;
      }
    }

    agents-manage-ui/src/components/errors/full-page-error.tsx (lines 159-166)

    // Handle 401 unauthorized errors by redirecting to login
    useEffect(() => {
      if ((statusCode === 401 || errorCode === 'unauthorized') && !isRedirecting) {
        setIsRedirecting(true);
        const loginUrl = buildLoginUrlWithCurrentPath();
        router.push(loginUrl);
      }
    }, [statusCode, errorCode, router, isRedirecting]);
  • Why this is likely a bug: The projects page is a Server Component with no server-side authentication guard. The 401 handling relies on a client-side useEffect redirect, which only runs after the server has already rendered and sent HTML to the browser. This creates a race condition where sensitive project data can be visible to unauthenticated users before the redirect occurs. A proper fix would require adding Next.js middleware to protect /[tenantId]/* routes or adding server-side session validation in the page itself.

  • Introduced by this PR: No – pre-existing bug (code not changed in this PR). The modified files in PR Unify .env generation between quickstart CLI and contributor flows #2212 are in packages/agents-core/, packages/create-agents/, create-agents-template/, and agents-docs/ – none affect the agents-manage-ui/src/app/[tenantId]/ route protection logic.

  • Timestamp: 30:49

📋 View Recording

Screen Recording

- Change OTEL_EXPORTER_OTLP_TRACES_ENDPOINT from active localhost value
  to empty string in template .env.example. Empty value causes the
  template's instrumentation guard to skip OTEL initialization, avoiding
  ~8s request timeouts when no collector is running. setup-dev:optional
  replaces the value in-place (no duplicate lines).
- Add commented OTEL_EXPORTER_OTLP_TRACES_HEADERS with note that it's
  only needed for SigNoz Cloud.
- Prepend turbo build to test:e2e scripts so standalone dashboard
  artifacts exist before the E2E test runs.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 commit, 2 files changed since last automated review at 142bbd17f).

Delta Analysis

The delta commit (e6549be24) contains two targeted fixes:

1. Empty OTEL Endpoint Default (create-agents-template/.env.example:57-59)

Changed OTEL_EXPORTER_OTLP_TRACES_ENDPOINT from http://localhost:14318/v1/traces to empty string, added helpful comment for SigNoz Cloud users.

  • Why correct: The instrumentation.ts in the template explicitly checks for a real OTEL endpoint and skips initialization when empty. This avoids confusing OTEL initialization failures for quickstart users who don't have SigNoz/Jaeger set up.
  • Verified: docker-compose.yml has a fallback ${OTEL_EXPORTER_OTLP_TRACES_ENDPOINT:-http://localhost:14318/v1/traces} for when containers run, so Docker-based deployments still work correctly.

2. Build Step Before E2E Tests (packages/create-agents/package.json:25-26)

Added turbo run build --filter=@inkeep/create-agents --filter=@inkeep/agents-api --filter=@inkeep/agents-cli --filter=@inkeep/agents-manage-ui before e2e test execution.

  • Why correct: The e2e tests use link: protocol to symlink local packages. Without building first, the symlinked packages don't have .next/standalone/ artifacts, causing startDashboardServer() to fail.
  • Verified: This directly addresses the "Dashboard standalone server not found" issue mentioned in the PR description.

💭 Consider (1) 💭

Inline Comments:

  • 💭 Consider: utils.test.ts:53 Test mock drift for OTEL endpoint value

Prior Feedback Status

All prior feedback was appropriately addressed or declined:

  • 🟠 Major: Missing error handling for .env.example read — ✅ Addressed in earlier commit
  • 🟡 Minor: Success message after JWT failure — Declined with valid reasoning

✅ APPROVE

Summary: Clean delta! Both changes are correct and well-reasoned. The empty OTEL endpoint default improves the out-of-box experience for quickstart users, and the build step ensures e2e tests have the artifacts they need. The one Consider item (test mock drift) is a minor test fidelity improvement that doesn't affect functionality. This PR is ready to ship! 🚀

Discarded (0)

No findings were discarded in this delta review.

Reviewers (1)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
pr-review-devops 1 0 1 0 1 0 0
Total 1 0 1 0 1 0 0

Note: Minimal reviewer set selected due to narrow scope (2 files, ~5 lines of functional changes).

Comment thread packages/create-agents/src/__tests__/utils.test.ts Outdated
@github-actions github-actions Bot deleted a comment from claude Bot Feb 24, 2026
Update mockEnvExample to use empty OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
matching the actual create-agents-template/.env.example value.

Co-Authored-By: Claude Opus 4.6 <[email protected]>
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 commit, 1 file, 1 line changed since last automated review at e6549be24).

Delta Analysis

The delta commit (12995ad76) contains a single change:

Test mock alignment (packages/create-agents/src/__tests__/utils.test.ts:53)

Changed mockEnvExample OTEL endpoint from http://localhost:14318/v1/traces to empty string:

- 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://localhost:14318/v1/traces',
+ 'OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=',
  • Why correct: This directly addresses the 💭 Consider item from the previous review about test mock drift. The test mock now matches the actual template (create-agents-template/.env.example:57).
  • Impact: Improves test fidelity without functional changes. The tests now validate against realistic template content.

Prior Feedback Status

Issue Status
💭 Consider: Test mock drift for OTEL endpoint Addressed in this commit

All prior Major/Minor issues were already addressed in earlier commits.


✅ APPROVE

Summary: This 1-line fix aligns the test mock with the actual template, directly addressing feedback from the previous review. The PR is in excellent shape — the unified .env generation approach is clean, well-tested, and now has consistent test fixtures. Ship it! 🚀

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
Total 0 0 0 0 0 0 0

Note: No subagent reviewers were dispatched for this delta — the change is a minimal 1-line test fix that directly addresses prior feedback and doesn't require specialized review.

@github-actions github-actions Bot deleted a comment from claude Bot Feb 24, 2026
Copy link
Copy Markdown
Contributor

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

PR Review Summary

(0) Total Issues | Risk: Low

This is a re-review scoped to the delta (1 merge commit since last automated review at 12995ad76).

Delta Analysis

The delta commit (15d0c77bd) is a clean merge from main bringing in 13 commits. None of these commits modify the PR's own files:

PR Files (unchanged) Delta Files (from main)
create-agents-template/.env.example agents-work-apps/src/slack/*
packages/agents-core/src/setup/* agents-api/src/domains/run/services/ArtifactParser.ts
packages/create-agents/src/* agents-docs/content/talk-to-your-agents/slack/*
agents-docs/content/community/contributing/* .github/workflows/cypress.yml

Verification: git diff 12995ad76..15d0c77bd --name-only | grep -E "(create-agents-template|packages/agents-core/src/setup|packages/create-agents|agents-docs/content/community/contributing)" returns no matches.

Prior Feedback Status

All prior feedback was appropriately addressed or declined:

  • 🟠 Major: Missing error handling for .env.example read — ✅ Addressed in earlier commit
  • 🟡 Minor: Success message after JWT failure — Declined with valid reasoning
  • 💭 Consider: Test mock drift for OTEL endpoint — ✅ Addressed

Merge Commit Contents (informational)

The 13 commits from main include:

  • Slack workspace linking limitation (#2286, #2287)
  • Slack message editing fix (#2284)
  • Agent name display improvements (#2279, #2281, #2283)
  • ArtifactParser updates (#2278)
  • Slack citation blocks (#2275)
  • Cypress CI workflow rename (#2285)

These are unrelated to this PR's scope (env generation unification).


✅ APPROVE

Summary: Clean merge from main with no modifications to PR-specific files. The previous review at 12995ad76 was already ✅ APPROVE with 0 issues, and the PR's code remains unchanged. The unified .env generation approach is solid — it reduces maintenance burden, eliminates drift between quickstart CLI and contributor flows, and fixes the bypass secret bug. Ready to ship! 🚀

Reviewers (0)
Reviewer Returned Main Findings Consider While You're Here Inline Comments Pending Recs Discarded
Total 0 0 0 0 0 0 0

Note: No subagent reviewers were dispatched — the delta contains no changes to PR-specific files. This is a clean merge from main.

@itoqa
Copy link
Copy Markdown

itoqa Bot commented Feb 24, 2026

Ito Test Report ❌

18 test cases ran. 17 passed, 1 failed.

This test run verified the Inkeep Agents PR #2212 which unifies .env generation between quickstart CLI and contributor flows. The majority of tests passed successfully, confirming that login functionality works correctly with the Origin header fix (localhost vs 127.0.0.1), API endpoints properly reject unauthorized requests, dashboard navigation functions as expected, and security measures against SQL injection and XSS are effective. One test identified a pre-existing authentication vulnerability where the dashboard is accessible to unauthenticated users when the API bypass secret is configured.

✅ Passed (17)
Test Case Summary Timestamp Screenshot
ROUTE-1 Login page rendered with email/password fields and Sign in button. Login succeeded and user was redirected to /default/projects with admin user visible. 0:30 ROUTE-1_0-30.png
ROUTE-2 Successfully navigated from projects page to Activities Planner project, then to agent detail page with visual builder, clicked Try it button which opened playground pane with AI assistant chat widget 3:04 ROUTE-2_3-04.png
ROUTE-3 API health endpoint at http://localhost:3002/health returned HTTP 204 No Content, confirming the API server is running and healthy 7:14 ROUTE-3_7-14.png
ROUTE-4 API returned HTTP 200 with JSON containing tenantId:default and id:activities-planner when called with bypass secret bearer token 8:30 ROUTE-4_8-30.png
LOGIC-1 All URLs in .env file use localhost. Dashboard serves on localhost:3000, API on localhost:3002. Network requests from browser all target localhost. No 127.0.0.1 references found. 7:21 LOGIC-1_7-21.png
LOGIC-3 CLI utils.ts lines 497-498 show http://localhost:3000 and http://localhost:3002 in next-steps output. grep for 127.0.0.1 returned zero matches confirming all references use localhost. 9:08 LOGIC-3_9-08.png
EDGE-1 Submitted login form with empty email and password fields. HTML5 validation prevented form submission with 'Please fill out this field' message on the required email field. User remained on /login page. 12:52 EDGE-1_12-52.png
EDGE-2 Submitted login form with [email protected] and wrong-password-123. Server returned 401 Unauthorized and the UI displayed 'Invalid email or password' error alert. User remained on /login page. 13:37 EDGE-2_13-37.png
EDGE-4 API correctly returned HTTP 401 Unauthorized with structured error response when called without authentication header 8:30 EDGE-4_8-30.png
EDGE-5 Navigated to /default/projects which loaded correctly with Activities Planner project visible, confirming the dashboard standalone server was found and fs.realpath() fix is working with potentially symlinked packages 6:46 EDGE-5_6-46.png
EDGE-6 Reloaded the agent detail page - user remained authenticated at the same URL with full content visible, admin user shown in header, no redirect to login page 6:22 EDGE-6_6-22.png
ADV-1 SQL injection payload rejected by both client-side HTML5 email validation and server-side API (400 INVALID_EMAIL). Database intact after attempt. Login page loads normally after injection attempt. 28:09 ADV-1_28-09.png
ADV-2 XSS payload rejected by HTML5 email validation (form did not submit) and server-side API (400 INVALID_EMAIL). No alert dialog appeared. No unescaped script tags found in rendered HTML. 29:28 ADV-2_29-28.png
ADV-3 All 4 invalid auth variations (empty token, invalid scheme, empty header, 10000-char token) correctly returned HTTP 401 Unauthorized. API remained responsive after adversarial inputs (health check returned 204). 30:42 ADV-3_30-42.png
ADV-4 Sent 20 rapid POST requests to sign-in endpoint with wrong password - all returned HTTP 401 without crashes. Login with correct credentials after burst returned HTTP 200 successfully. API remained responsive throughout. No rate limiting (429) was observed. 31:37 ADV-4_31-37.png
ADV-5 API returned HTTP 404 with clean structured error 'Project not found: non-existent-project-xyz'. No stack traces or internal details leaked 8:31 ADV-5_8-31.png
ADV-6 API returned HTTP 404 when accessing activities-planner under wrong-tenant, confirming tenant isolation. Project exists under default tenant but is not accessible via wrong-tenant path 8:32 ADV-6_8-32.png
❌ Failed (1)
Test Case Summary Timestamp Screenshot
EDGE-3 Fresh browser context navigated to /default/projects - page loaded with full projects content instead of redirecting to /login. Dashboard accessible without authentication. 20:17 EDGE-3_20-17.png
Dashboard redirects unauthenticated users to login – Failed
  • Where: Dashboard at /default/projects route

  • Steps to reproduce:

    1. Open a fresh browser context with no cookies or session
    2. Navigate directly to http://localhost:3000/default/projects
    3. Observe that the projects page loads with full content instead of redirecting to /login
  • What failed: Expected redirect to /login for unauthenticated users, but the dashboard loaded successfully with full projects content visible. The get-session API correctly returns null for cookieless requests, but when accessed through Next.js SSR, the API request uses the bypass secret, allowing unauthenticated access.

  • Code analysis: Examined the authentication flow in the dashboard codebase. The [tenantId]/layout.tsx has no server-side authentication middleware. The [tenantId]/projects/page.tsx calls fetchProjects() which uses makeManagementApiRequest(). The api-config.ts automatically adds the bypass secret as an Authorization header for all server-side API requests when INKEEP_AGENTS_MANAGE_API_BYPASS_SECRET is set. This means any SSR request from the dashboard bypasses authentication entirely.

  • Relevant code:

    agents-manage-ui/src/lib/api/api-config.ts (lines 63-69)

    const defaultHeaders: HeadersInit = {
      'Content-Type': 'application/json',
      ...options.headers,
      ...(cookieHeader && { Cookie: cookieHeader }),
      ...(process.env.INKEEP_AGENTS_MANAGE_API_BYPASS_SECRET && {
        Authorization: `Bearer ${process.env.INKEEP_AGENTS_MANAGE_API_BYPASS_SECRET}`,
      }),
    };

    agents-manage-ui/src/app/[tenantId]/layout.tsx (lines 9-42)

    const Layout: FC<LayoutProps<'/[tenantId]'>> = ({ children, breadcrumbs }) => {
      return (
        <AppSidebarProvider>
          <SentryScopeProvider>
            <SidebarInset>
              {/* No auth check - renders children directly */}
              <main>{children}</main>
            </SidebarInset>
          </SentryScopeProvider>
        </AppSidebarProvider>
      );
    };
  • Why this is likely a bug: The dashboard is accessible without user authentication when the API bypass secret is configured in the environment. While the bypass secret is intended for CI/testing scenarios, it creates a security vulnerability where any unauthenticated browser request can access protected dashboard content via SSR. The root page.tsx has client-side auth checking via useAuthSession(), but navigating directly to /[tenantId]/projects bypasses that check entirely. A proper fix would require either server-side auth middleware on the [tenantId] routes or conditioning the bypass secret usage on explicit CI/test mode rather than applying it universally to all SSR requests.

  • Introduced by this PR: No – pre-existing bug (code not changed in this PR)

  • Timestamp: 20:17

📋 View Recording

Screen Recording

@miles-kt-inkeep miles-kt-inkeep merged commit 0a0cb6e into main Feb 24, 2026
11 checks passed
@miles-kt-inkeep miles-kt-inkeep deleted the feat/unify-env-generation branch February 24, 2026 14:43
@github-actions
Copy link
Copy Markdown
Contributor

🔎💬 Inkeep AI search and chat service is syncing content for source 'Inkeep Agent Framework Docs'

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.

2 participants