Skip to content

Conversation

@potofpie
Copy link
Member

@potofpie potofpie commented Jan 9, 2026

Summary

Adds validation to prevent public variable prefixes from being added as secrets across the CLI commands.

Key Validation Rules

  • Public var prefixes (VITE_, AGENTUITY_PUBLIC_, PUBLIC_) cannot be marked as secrets - they are exposed to the frontend
  • Reserved AGENTUITY_* keys (except AGENTUITY_PUBLIC_*) are blocked from being set by users - they are reserved for system use
  • AGENTUITY_PUBLIC_* keys ARE allowed as env vars (not secrets)

CLI Command Changes

Command Change
secret set Validates reserved keys + public vars as secrets
secret push Uses splitEnvAndSecrets, routes public vars to env
secret import Uses splitEnvAndSecrets, routes public vars to env
secret pull Allows AGENTUITY_PUBLIC_* in .env file
env set Allows AGENTUITY_PUBLIC_* keys, blocks reserved
env push Uses updated filterAgentuitySdkKeys
env import Allows AGENTUITY_PUBLIC_* in .env file
env pull Allows AGENTUITY_PUBLIC_* in .env file

New Utility Functions (env-util.ts)

  • isPublicVarKey(): Check if key has public var prefix
  • isReservedAgentuityKey(): Check if key is reserved AGENTUITY_* (not PUBLIC_)
  • validateNoPublicSecrets(): Validate secrets don't contain public vars
  • getPublicSecretKeys(): Get public var keys from secrets object

Updated Functions

  • filterAgentuitySdkKeys(): Now allows AGENTUITY_PUBLIC_* keys
  • splitEnvAndSecrets(): Routes public vars to env, not secrets

Tests

  • 48 unit tests for validation functions (packages/cli/test/config/env-util.test.ts)
  • 9 integration tests for CLI command validation (apps/testing/integration-suite/src/test/cli-env-secrets.ts)

Related

Companion PR in app repo: #969 (already merged)

Summary by CodeRabbit

  • New Features

    • Secrets are now managed through the env commands (env set --secret, env get, env list, env delete) with per-item secret flags and env/secret counts.
  • Bug Fixes

    • Stronger validation: reserved platform-prefixed keys blocked; public-prefixed keys preserved as env vars. Masking defaults adjusted (secrets masked by default).
  • Removed

    • Dedicated secret command group and subcommands removed in favor of the env-based workflow.
  • Tests

    • Added extensive unit and integration tests covering detection, import/push/pull flows, and CI orchestration.
  • Documentation

    • CLI docs and examples updated to reflect the env-based secret workflow.

✏️ Tip: You can customize this high-level summary in your review settings.

- Add validation to prevent public var prefixes (VITE_, AGENTUITY_PUBLIC_, PUBLIC_) from being set as secrets
- Block reserved AGENTUITY_* keys (except AGENTUITY_PUBLIC_*) from being set by users
- Allow AGENTUITY_PUBLIC_* keys as env vars

CLI command changes:
- secret set: Validates reserved keys + public vars as secrets
- secret push: Uses splitEnvAndSecrets, warns about public vars
- secret import: Uses splitEnvAndSecrets, warns about public vars
- secret pull: Allows AGENTUITY_PUBLIC_* in .env file
- env set: Allows AGENTUITY_PUBLIC_* keys
- env push: Uses updated filterAgentuitySdkKeys
- env import: Allows AGENTUITY_PUBLIC_* in .env file
- env pull: Allows AGENTUITY_PUBLIC_* in .env file

New utility functions in env-util.ts:
- isPublicVarKey(): Check if key has public var prefix
- isReservedAgentuityKey(): Check if key is reserved AGENTUITY_* (not PUBLIC_)
- validateNoPublicSecrets(): Validate secrets don't contain public vars
- getPublicSecretKeys(): Get public var keys from secrets object

Updated functions:
- filterAgentuitySdkKeys(): Now allows AGENTUITY_PUBLIC_* keys
- splitEnvAndSecrets(): Routes public vars to env, not secrets

Tests:
- Added 48 unit tests for new validation functions
- Added 9 integration tests for CLI command validation
@coderabbitai
Copy link

coderabbitai bot commented Jan 9, 2026

📝 Walkthrough

Walkthrough

Consolidates secret management into the cloud env flow: removes the standalone cloud secret command, adds env-util helpers/validations for public vs reserved keys, updates env subcommands to handle env vs secrets (flags, masking, counts), adjusts local .env write rules, and adds tests/docs for the changes.

Changes

Cohort / File(s) Summary
Command surface
packages/cli/src/cmd/cloud/index.ts, packages/cli/src/cmd/cloud/secret/*
Removes the cloud secret command group and unregisters its subcommands; secret functionality migrated into cloud env.
Env command implementations
packages/cli/src/cmd/cloud/env/*.ts
(set.ts, get.ts, list.ts, delete.ts, import.ts, push.ts, pull.ts)
Add secret-aware behavior: secret flag/options and response fields; split payloads (env vs secrets); validate public/reserved prefixes; change masking/TTY logic; report envCount/secretCount; adjust local .env skip logic to preserve AGENTUITY_PUBLIC_*.
Removed secret modules
packages/cli/src/cmd/cloud/secret/*
(get.ts, push.ts, pull.ts, set.ts, import.ts, delete.ts, list.ts, index.ts)
Deleted standalone secret subcommands, their schemas, handlers, and exports.
Env utilities
packages/cli/src/env-util.ts
New utilities and signatures: PUBLIC_VAR_PREFIXES, isPublicVarKey(), isReservedAgentuityKey(), getPublicSecretKeys(), validateNoPublicSecrets(); updated filterAgentuitySdkKeys() and splitEnvAndSecrets() to treat public vars as env and exclude reserved SDK keys.
Package exports
packages/cli/package.json
Exposes ./env-util entry (import + types) in package exports.
Tests & integration
packages/cli/test/config/env-util.test.ts, apps/testing/integration-suite/app.ts, apps/testing/integration-suite/src/test/cli-env-secrets.ts, apps/testing/integration-suite/src/test/cli-deployment.ts
Adds unit tests for env-util, a comprehensive integration test suite for CLI env/secret behavior (registered at app startup), and a placeholder deployment test.
CI / test runner
apps/testing/integration-suite/scripts/ci-test.sh, apps/testing/integration-suite/src/test/api-route.ts
Adds run_tests helper, splits test phases (exclude/register suites), and adds exclude query param for /api/test/run filtering.
Helpers & web
apps/testing/integration-suite/src/test/helpers/index.ts, apps/testing/integration-suite/src/web/index.html
uniqueId delimiter changed from hyphens to underscores; removed async attribute from script tag.
Docs & prompts
packages/cli/README.md, packages/cli/docs/secret-detection.md, packages/cli/src/cmd/ai/capabilities/show.ts, packages/cli/src/cmd/ai/prompt/llm.ts
Update docs and AI prompts to use env set --secret workflow and describe automatic classification and prompt behavior.

Sequence Diagram(s)

sequenceDiagram
  participant User as CLI User
  participant CLI as agentuity CLI (cloud env)
  participant Util as env-util
  participant Cloud as Cloud API
  participant FS as Local FS (.env)

  User->>CLI: run "cloud env set KEY value [--secret]"
  CLI->>Util: isReservedAgentuityKey / isPublicVarKey / looksLikeSecret
  alt looksLikeSecret && no --secret
    CLI->>User: prompt "store as secret? (Y/n)"
    User-->>CLI: confirm
  end
  CLI->>Cloud: projectEnvUpdate({ env: {...}, secrets: {...} })
  Cloud-->>CLI: success
  CLI->>FS: read .env
  CLI->>Util: filterAgentuitySdkKeys (preserve AGENTUITY_PUBLIC_*)
  CLI->>FS: write .env
  CLI-->>User: success (includes secret: boolean)
Loading
sequenceDiagram
  participant User as CLI User
  participant CLI as agentuity CLI (env import/push)
  participant Util as env-util
  participant Cloud as Cloud API
  participant FS as Local FS

  User->>CLI: run "cloud env import|push file"
  CLI->>FS: read file -> rawVars
  CLI->>Util: splitEnvAndSecrets(rawVars)
  alt public keys found in secrets
    CLI->>User: warn and auto-move public keys to env
  end
  CLI->>Cloud: projectEnvUpdate({ env: {...}, secrets: {...} })
  Cloud-->>CLI: success (envCount, secretCount)
  CLI->>FS: merge with local .env, skip reserved AGENTUITY_ except AGENTUITY_PUBLIC_*
  CLI-->>User: summary (envCount / secretCount / total)
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/public-var-secret-validation

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

@github-actions
Copy link

github-actions bot commented Jan 9, 2026

📦 Canary Packages Published

version: 0.1.7-60c628a

Packages
Package Version URL
@agentuity/frontend 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-frontend-0.1.7-60c628a.tgz
@agentuity/schema 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-schema-0.1.7-60c628a.tgz
@agentuity/evals 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-evals-0.1.7-60c628a.tgz
@agentuity/cli 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-cli-0.1.7-60c628a.tgz
@agentuity/workbench 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-workbench-0.1.7-60c628a.tgz
@agentuity/react 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-react-0.1.7-60c628a.tgz
@agentuity/core 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-core-0.1.7-60c628a.tgz
@agentuity/auth 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-auth-0.1.7-60c628a.tgz
@agentuity/runtime 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-runtime-0.1.7-60c628a.tgz
@agentuity/server 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-server-0.1.7-60c628a.tgz
Install

Add to your package.json:

{
  "dependencies": {
    "@agentuity/frontend": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-frontend-0.1.7-60c628a.tgz",
    "@agentuity/schema": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-schema-0.1.7-60c628a.tgz",
    "@agentuity/evals": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-evals-0.1.7-60c628a.tgz",
    "@agentuity/cli": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-cli-0.1.7-60c628a.tgz",
    "@agentuity/workbench": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-workbench-0.1.7-60c628a.tgz",
    "@agentuity/react": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-react-0.1.7-60c628a.tgz",
    "@agentuity/core": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-core-0.1.7-60c628a.tgz",
    "@agentuity/auth": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-auth-0.1.7-60c628a.tgz",
    "@agentuity/runtime": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-runtime-0.1.7-60c628a.tgz",
    "@agentuity/server": "https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-server-0.1.7-60c628a.tgz"
  }
}

Or install directly:

bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-frontend-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-schema-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-evals-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-cli-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-workbench-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-react-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-core-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-auth-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-runtime-0.1.7-60c628a.tgz
bun add https://agentuity-sdk-objects.t3.storage.dev/npm/0.1.7-60c628a/agentuity-server-0.1.7-60c628a.tgz
CLI Executables
Platform Version URL
darwin-arm64 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.7-60c628a/agentuity-darwin-arm64.gz
linux-arm64 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.7-60c628a/agentuity-linux-arm64.gz
linux-x64 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.7-60c628a/agentuity-linux-x64.gz
darwin-x64 0.1.7-60c628a https://agentuity-sdk-objects.t3.storage.dev/binary/0.1.7-60c628a/agentuity-darwin-x64.gz
Run Canary CLI
agentuity canary 0.1.7-60c628a [command] [...args]

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @apps/testing/integration-suite/src/test/cli-env-secrets.ts:
- Around line 106-129: Replace hardcoded env keys with uniqueId()-generated
names to prevent cross-test interference: import the uniqueId helper at the top
of the test file and for the 'cli-env-secrets' test named
'env-set-allows-agentuity-public-prefix' replace "AGENTUITY_PUBLIC_TEST_VAR"
with a variable like const key = `AGENTUITY_PUBLIC_${uniqueId()}` and use that
key in the cliAgent.run command and subsequent assertions (also update the other
two passing tests that reference VITE_TEST_VAR and PUBLIC_TEST_VAR in the same
file to use uniqueId() similarly). Ensure the generated key strings keep the
required prefixes (AGENTUITY_PUBLIC_, VITE_, PUBLIC_) when constructing the
unique keys and use those variables everywhere in the test logic/assertions.
- Around line 170-194: The test 'cli-env-secrets' /
'secret-set-allows-valid-key' uses a hardcoded key MY_TEST_SECRET_KEY; replace
it with a uniqueId-generated key (e.g., const key =
uniqueId('MY_TEST_SECRET_KEY') and use that variable in the cliAgent.run
command) to ensure test isolation, and add/import the uniqueId helper if not
already imported in this file; keep the rest of the assertions unchanged so they
validate against the generated key.

In @packages/cli/package.json:
- Around line 17-24: The package export for "./env-util" currently points to the
TypeScript source ("./src/env-util.ts"); update the package.json exports entry
to reference the compiled dist output instead (mirror how "./vite-plugin" uses
"./dist/..."), e.g., change both "import" and "types" for "./env-util" to point
at the corresponding files under "./dist" (ensure the compiled JS and .d.ts
exist in dist after build), so Node ESM consumers load the compiled module
rather than the TS source.

In @packages/cli/src/cmd/cloud/secret/push.ts:
- Around line 49-62: The warning message is misleading because publicSecretKeys
returned by validateNoPublicSecrets are reclassified into env and included in
the payload; update the message in the block that handles publicSecretKeys
(references: splitEnvAndSecrets, validateNoPublicSecrets, publicSecretKeys,
secrets, env, tui.warning) to state that these keys are being moved/reclassified
to env (e.g., "Reclassifying public variables to env: ...") instead of "Skipping
public variables", and keep the subsequent deletion from secrets and assignment
to env unchanged.
🧹 Nitpick comments (5)
packages/cli/src/cmd/cloud/secret/pull.ts (1)

58-63: pulled/success count may be wrong now that some keys are skipped from the file.

You’re skipping reserved AGENTUITY_ keys (good), but count still reports Object.keys(cloudSecrets).length, which can include keys that never made it into .env.

One way to align the reported count with what’s written
 		await writeEnvFile(targetEnvPath, mergedEnv, {
-			skipKeys: Object.keys(mergedEnv).filter(
+			skipKeys: Object.keys(mergedEnv).filter(
 				(k) => k.startsWith('AGENTUITY_') && !k.startsWith('AGENTUITY_PUBLIC_')
 			),
 		});
@@
-		const count = Object.keys(cloudSecrets).length;
+		const skipped = new Set(
+			Object.keys(mergedEnv).filter(
+				(k) => k.startsWith('AGENTUITY_') && !k.startsWith('AGENTUITY_PUBLIC_')
+			)
+		);
+		const count = Object.keys(mergedEnv).filter((k) => !skipped.has(k)).length;
 		tui.success(`Pulled ${count} secret${count !== 1 ? 's' : ''} to ${targetEnvPath}`);

Also applies to: 84-86

packages/cli/src/cmd/cloud/env/set.ts (1)

5-12: Error message should clarify the AGENTUITY_PUBLIC_ exception.

The isReservedAgentuityKey() check correctly allows AGENTUITY_PUBLIC_ prefixed variables, but the fatal error message "Cannot set AGENTUITY_ prefixed variables..." does not document this exception, which may confuse users. Update the message to indicate that AGENTUITY_PUBLIC_* variables are permitted:

Suggested change
-			tui.fatal('Cannot set AGENTUITY_ prefixed variables. These are reserved for system use.');
+			tui.fatal(
+				'Cannot set AGENTUITY_ prefixed variables (except AGENTUITY_PUBLIC_*). These are reserved for system use.'
+			);

Also applies to: packages/cli/src/cmd/cloud/secret/set.ts

packages/cli/src/cmd/cloud/env/pull.ts (1)

58-62: Use isReservedAgentuityKey() (or filterAgentuitySdkKeys()) instead of case-sensitive startsWith checks.

Current skipKeys won’t catch lowercase/mixed-case keys and duplicates logic already centralized in env-util.ts.

Proposed change
-import { findExistingEnvFile, readEnvFile, writeEnvFile, mergeEnvVars } from '../../../env-util';
+import {
+	findExistingEnvFile,
+	readEnvFile,
+	writeEnvFile,
+	mergeEnvVars,
+	isReservedAgentuityKey,
+} from '../../../env-util';

 	await writeEnvFile(targetEnvPath, mergedEnv, {
-		skipKeys: Object.keys(mergedEnv).filter(
-			(k) => k.startsWith('AGENTUITY_') && !k.startsWith('AGENTUITY_PUBLIC_')
-		),
+		skipKeys: Object.keys(mergedEnv).filter(isReservedAgentuityKey),
 	});
packages/cli/src/cmd/cloud/env/import.ts (1)

139-142: Avoid duplicating reserved-key logic when writing the merged .env (case-sensitivity + drift risk).

Since you already depend on filterAgentuitySdkKeys(), you can just filter the merged object before writing (or use isReservedAgentuityKey like elsewhere).

Proposed change (simplify using existing helper)
-		await writeEnvFile(localEnvPath, mergedEnv, {
-			skipKeys: Object.keys(mergedEnv).filter(
-				(k) => k.startsWith('AGENTUITY_') && !k.startsWith('AGENTUITY_PUBLIC_')
-			),
-		});
+		await writeEnvFile(localEnvPath, filterAgentuitySdkKeys(mergedEnv));
packages/cli/src/cmd/cloud/secret/set.ts (1)

49-59: Validation logic matches the objective (reserved AGENTUITY_ blocked; public prefixes blocked as secrets).*

Consider using getCommand('env set ...') to construct the command suggestion for consistency with how this codebase generates command help text in examples.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5f1179 and 3bee19c.

📒 Files selected for processing (13)
  • apps/testing/integration-suite/app.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/package.json
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/pull.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/env-util.ts
  • packages/cli/test/config/env-util.test.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/test/config/env-util.test.ts
  • apps/testing/integration-suite/app.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/env-util.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/pull.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
packages/*/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/*/test/**/*.{ts,tsx}: Place test files in test/ folder (never in src/ or __tests__/)
Import from ../src/ in test files to reference source code
Use @agentuity/test-utils for mocks and test helpers

Files:

  • packages/cli/test/config/env-util.test.ts
apps/testing/integration-suite/**/app.ts

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Test files must be imported in app.ts to register tests with the test suite

Files:

  • apps/testing/integration-suite/app.ts
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/pull.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/env-util.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/pull.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
apps/testing/integration-suite/src/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Use path aliases for imports: @agents/* and @test/* instead of relative paths

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
apps/testing/integration-suite/src/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

apps/testing/integration-suite/src/test/**/*.{ts,tsx}: Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation
Test files must follow the pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers
Import test registration function and assertion helpers from @test/suite and @test/helpers
Use decodeKVValue() helper from @test/helpers/kv to decode stringified Uint8Arrays when reading KV values
Tests must be registered by calling test() function from @test/suite, not just defined

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/test/config/env-util.test.ts
  • apps/testing/integration-suite/app.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/env-util.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/pull.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
🧬 Code graph analysis (9)
packages/cli/test/config/env-util.test.ts (1)
packages/cli/src/env-util.ts (5)
  • isPublicVarKey (19-22)
  • isReservedAgentuityKey (27-30)
  • validateNoPublicSecrets (43-45)
  • filterAgentuitySdkKeys (205-216)
  • splitEnvAndSecrets (229-261)
packages/cli/src/cmd/cloud/env/set.ts (1)
packages/cli/src/env-util.ts (1)
  • isReservedAgentuityKey (27-30)
packages/cli/src/cmd/cloud/secret/pull.ts (1)
packages/cli/src/env-util.ts (1)
  • writeEnvFile (136-171)
packages/cli/src/cmd/cloud/secret/set.ts (1)
packages/cli/src/env-util.ts (3)
  • isReservedAgentuityKey (27-30)
  • isPublicVarKey (19-22)
  • PUBLIC_VAR_PREFIXES (14-14)
packages/cli/src/cmd/cloud/secret/push.ts (2)
packages/cli/src/env-util.ts (3)
  • filterAgentuitySdkKeys (205-216)
  • splitEnvAndSecrets (229-261)
  • validateNoPublicSecrets (43-45)
packages/server/src/api/project/env-update.ts (1)
  • projectEnvUpdate (33-55)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (2)
apps/testing/integration-suite/src/test/suite.ts (1)
  • test (218-220)
apps/testing/integration-suite/src/test/helpers/index.ts (2)
  • assertEqual (31-34)
  • assert (22-26)
packages/cli/src/cmd/cloud/env/import.ts (1)
packages/cli/src/env-util.ts (1)
  • filterAgentuitySdkKeys (205-216)
packages/cli/src/cmd/cloud/env/pull.ts (1)
packages/cli/src/env-util.ts (1)
  • writeEnvFile (136-171)
packages/cli/src/cmd/cloud/secret/import.ts (2)
packages/cli/src/env-util.ts (7)
  • filterAgentuitySdkKeys (205-216)
  • splitEnvAndSecrets (229-261)
  • validateNoPublicSecrets (43-45)
  • findExistingEnvFile (50-52)
  • readEnvFile (111-130)
  • mergeEnvVars (178-198)
  • writeEnvFile (136-171)
packages/server/src/api/project/env-update.ts (1)
  • projectEnvUpdate (33-55)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Build
  • GitHub Check: Pack & Upload
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Template Integration Tests
🔇 Additional comments (20)
apps/testing/integration-suite/app.ts (1)

10-30: Good: new integration tests are registered in app.ts.

This follows the integration-suite rule that test modules must be imported in app.ts to register with the suite.

packages/cli/src/cmd/cloud/env/push.ts (1)

40-42: LGTM: push filters reserved AGENTUITY_ while keeping AGENTUITY_PUBLIC_ eligible.

packages/cli/test/config/env-util.test.ts (1)

2-9: Test coverage for public/reserved key classification and env-vs-secret splitting looks solid.

The new cases cover the key prefix rules, case-insensitivity, reserved key exclusion, and splitEnvAndSecrets behavior in a way that matches the CLI contract.

Also applies to: 203-347

packages/cli/src/cmd/cloud/env/import.ts (1)

71-76: Updated messaging (“reserved AGENTUITY_ prefixed”) matches the new reserved/public split.

packages/cli/src/cmd/cloud/secret/push.ts (1)

22-22: Update command description and spinner text to accurately reflect that both env and secrets are pushed.

Line 22 and 74 say "secrets" but the implementation pushes both env and secrets (see lines 77–78). The backend correctly merges these with existing values (per the comment in env-update.ts), so there's no risk of unintended overwrites, but the copy should match the actual behavior to avoid user confusion.

packages/cli/src/cmd/cloud/secret/import.ts (7)

11-12: LGTM! Validation imports are correctly added.

The new imports for validateNoPublicSecrets and splitEnvAndSecrets are correctly sourced from the env-util module and align with the PR objectives.


68-80: LGTM! Filtering logic correctly updated.

The variable rename from filteredSecrets to filteredVars accurately reflects the new semantics where the filtered set can contain both env vars and secrets. The updated early-return message correctly identifies that reserved AGENTUITY_ prefixed keys are filtered out (except AGENTUITY_PUBLIC_).


82-95: LGTM! Public variable validation and correction logic is sound.

The implementation correctly:

  • Splits filtered variables into env and secrets using the new utility
  • Validates that no public variables ended up in secrets
  • Moves any public variables from secrets to env with an appropriate warning
  • Provides clear messaging about frontend exposure

101-102: LGTM! Cloud push payload correctly structured.

The projectEnvUpdate call now correctly sends both env and secrets as separate fields, which aligns with the API contract shown in the relevant code snippets and supports the new env/secret split logic.


109-109: LGTM! Local merge uses correct variable.

Using filteredVars (which contains both env and secrets before the split) for the local .env merge is correct, as the local file should contain all imported variables.


112-114: LGTM! Skip keys logic correctly refined.

The skipKeys filter now correctly excludes reserved AGENTUITY_ keys while allowing AGENTUITY_PUBLIC_ keys to be written to the local .env file. This aligns with the PR objectives.


117-127: LGTM! Count calculation and reporting are accurate.

The updated logic correctly:

  • Calculates separate counts for env and secrets
  • Reports total imported variables with breakdown
  • Adjusts skipped count to account for the total (env + secrets) rather than just secrets

The success message provides clear visibility into how variables were categorized.

apps/testing/integration-suite/src/test/cli-env-secrets.ts (3)

10-13: LGTM! Imports follow path alias conventions.

The imports correctly use @test/suite, @test/helpers, and @agents/cli/agent path aliases as specified in the coding guidelines for integration tests.


16-31: Missing uniqueId() for test isolation.

The tests directly use hardcoded key names like AGENTUITY_SDK_KEY, VITE_API_KEY, PUBLIC_URL, and AGENTUITY_PUBLIC_KEY. Per coding guidelines, "Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation."

While these specific keys are meant to test validation rules and won't be persisted to the cloud (since they're rejected), the guideline applies to all identifiers. Consider whether test isolation is necessary here.

If these keys are purely for validation testing and never reach the cloud/storage layer (i.e., they fail early validation), test isolation may not be strictly necessary. However, if there's any chance of cross-test interference or if the guideline is absolute, these should use uniqueId().

Can you confirm whether validation-only tests that never persist data still require uniqueId() for identifiers?

Also applies to: 34-49, 52-67, 70-85


16-194: Test structure follows recommended pattern.

All tests follow the expected pattern:

  • Setup section with authentication check
  • Execute section calling cliAgent.run()
  • Assert section with appropriate assertion helpers (assertEqual, assert)

The tests are properly registered using the test() function from @test/suite, and assertions use helpers from @test/helpers as required by the coding guidelines.

packages/cli/src/env-util.ts (5)

11-22: LGTM! Public variable detection is correctly implemented.

The PUBLIC_VAR_PREFIXES constant and isPublicVarKey function correctly identify public/frontend-exposed variables. The implementation:

  • Uses as const for type safety
  • Converts keys to uppercase for case-insensitive comparison
  • Covers all three public prefixes mentioned in the PR objectives (VITE_, AGENTUITY_PUBLIC_, PUBLIC_)

24-30: LGTM! Reserved key detection correctly excludes AGENTUITY_PUBLIC_.

The isReservedAgentuityKey function correctly identifies reserved AGENTUITY_ prefixed keys while explicitly allowing AGENTUITY_PUBLIC_ keys. The case-insensitive comparison ensures consistent behavior.


32-45: LGTM! Validation functions are correctly structured.

Both getPublicSecretKeys and validateNoPublicSecrets are correctly implemented:

  • getPublicSecretKeys identifies public variables that were incorrectly placed in secrets
  • validateNoPublicSecrets provides a semantic wrapper with clear naming for validation use cases
  • The implementation correctly leverages isPublicVarKey for filtering

200-216: LGTM! filterAgentuitySdkKeys correctly updated.

The function now:

  • Safely handles undefined input by returning an empty object
  • Uses the centralized isReservedAgentuityKey function for consistent filtering
  • Correctly allows AGENTUITY_PUBLIC_ keys through (since they're not reserved)
  • Maintains the original filtering semantics while improving consistency

The updated JSDoc comment accurately reflects the new behavior.


227-261: LGTM! splitEnvAndSecrets correctly handles new rules.

The updated function correctly implements the env/secret split logic:

  • Skips reserved AGENTUITY_ keys (except AGENTUITY_PUBLIC_) early in the loop (lines 239-242)
  • Routes public variables to env, never secrets (lines 244-248)
  • Maintains the original suffix and exact-match logic for secret detection
  • Updated JSDoc comment accurately documents the new behavior

The implementation prevents public variables from becoming secrets while preserving backward-compatible secret detection for non-public keys.

Comment on lines 17 to 24
"./vite-plugin": {
"import": "./dist/cmd/build/vite/index.js",
"types": "./dist/cmd/build/vite/index.d.ts"
},
"./env-util": {
"import": "./src/env-util.ts",
"types": "./src/env-util.ts"
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify where env-util compiles to, and whether dist artifacts exist.
set -euo pipefail

echo "== Find env-util source =="
fd -a 'env-util\.ts$' packages/cli/src || echo "No matches"

echo "== Check for built artifacts (common locations) =="
fd -a 'env-util\.(js|d\.ts)$' packages/cli/dist packages/cli || echo "No matches"

echo "== Inspect package exports block =="
python3 <<'PY'
import json
p='packages/cli/package.json'
with open(p,'r',encoding='utf-8') as f:
  data=json.load(f)
print(json.dumps(data.get("exports",{}).get("./env-util",{}), indent=2))
PY

echo "== Check build script in package.json =="
python3 <<'PY'
import json
p='packages/cli/package.json'
with open(p,'r',encoding='utf-8') as f:
  data=json.load(f)
scripts = data.get("scripts", {})
for key in ["build", "build:*"]:
  if key in scripts:
    print(f"{key}: {scripts[key]}")
for key in scripts:
  if "build" in key:
    print(f"{key}: {scripts[key]}")
PY

echo "== List contents of packages/cli/src =="
ls -la packages/cli/src/ 2>/dev/null | head -20 || echo "Directory not found"

echo "== List contents of packages/cli/dist (if exists) =="
ls -la packages/cli/dist/ 2>/dev/null | head -20 || echo "Directory not found or empty"

Repository: agentuity/sdk

Length of output: 143


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check env-util source existence =="
find packages/cli/src -name "*env-util*" -type f 2>/dev/null | head -20

echo "== Extract exports.env-util from package.json =="
cat packages/cli/package.json | grep -A 5 '"./env-util"' || echo "Pattern not found"

echo "== Check if dist directory exists =="
test -d packages/cli/dist && echo "dist exists" || echo "dist does not exist"

Repository: agentuity/sdk

Length of output: 333


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check build scripts =="
grep -A 3 '"build"' packages/cli/package.json | head -10

echo "== Check files field =="
grep -A 10 '"files"' packages/cli/package.json

echo "== Check tsconfig existence =="
ls -la packages/cli/tsconfig* 2>/dev/null | head -5 || echo "No tsconfig found"

echo "== Check all exports =="
python3 -c "
import json
with open('packages/cli/package.json', 'r') as f:
    exports = json.load(f).get('exports', {})
    for key in sorted(exports.keys()):
        print(f'{key}:')
        print(f'  {exports[key]}')
" 2>/dev/null || echo "Failed to parse"

Repository: agentuity/sdk

Length of output: 1077


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== Check tsconfig.json output configuration =="
cat packages/cli/tsconfig.json

echo "== Check if env-util.ts would compile to a separate dist file or as part of index =="
grep -r "env-util" packages/cli/src --include="*.ts" | head -5

Repository: agentuity/sdk

Length of output: 933


Export ./env-util from compiled dist output, not TypeScript source.

The export currently points to ./src/env-util.ts (line 21-23), which will break Node ESM consumers without a TypeScript loader. The tsconfig compiles all src/**/* to dist/ (outDir + rootDir), and dist is included in published files, but the export ignores the compiled output. This is inconsistent with ./vite-plugin and the main export, both of which correctly reference ./dist/*.

Required change
 		"./env-util": {
-			"import": "./src/env-util.ts",
-			"types": "./src/env-util.ts"
+			"import": "./dist/env-util.js",
+			"types": "./dist/env-util.d.ts"
 		}
📝 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
"./vite-plugin": {
"import": "./dist/cmd/build/vite/index.js",
"types": "./dist/cmd/build/vite/index.d.ts"
},
"./env-util": {
"import": "./src/env-util.ts",
"types": "./src/env-util.ts"
}
"./vite-plugin": {
"import": "./dist/cmd/build/vite/index.js",
"types": "./dist/cmd/build/vite/index.d.ts"
},
"./env-util": {
"import": "./dist/env-util.js",
"types": "./dist/env-util.d.ts"
}
🤖 Prompt for AI Agents
In @packages/cli/package.json around lines 17 - 24, The package export for
"./env-util" currently points to the TypeScript source ("./src/env-util.ts");
update the package.json exports entry to reference the compiled dist output
instead (mirror how "./vite-plugin" uses "./dist/..."), e.g., change both
"import" and "types" for "./env-util" to point at the corresponding files under
"./dist" (ensure the compiled JS and .d.ts exist in dist after build), so Node
ESM consumers load the compiled module rather than the TS source.

Comment on lines 49 to 62
// Split into env and secrets (public vars will be in env, not secrets)
const { env, secrets } = splitEnvAndSecrets(filteredEnv);

// Check for any public vars that would have been treated as secrets
const publicSecretKeys = validateNoPublicSecrets(secrets);
if (publicSecretKeys.length > 0) {
tui.warning(
`Skipping public variables: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
);
for (const key of publicSecretKeys) {
delete secrets[key];
env[key] = filteredEnv[key];
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Warning text is misleading: you’re not “skipping” public vars, you’re reclassifying them to env.

This currently says “Skipping public variables …” but then moves them into env and includes them in the update payload.

Proposed change
-			tui.warning(
-				`Skipping public variables: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
-			);
+			tui.warning(
+				`Public variables cannot be secrets. Treating as env: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
+			);
📝 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
// Split into env and secrets (public vars will be in env, not secrets)
const { env, secrets } = splitEnvAndSecrets(filteredEnv);
// Check for any public vars that would have been treated as secrets
const publicSecretKeys = validateNoPublicSecrets(secrets);
if (publicSecretKeys.length > 0) {
tui.warning(
`Skipping public variables: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
);
for (const key of publicSecretKeys) {
delete secrets[key];
env[key] = filteredEnv[key];
}
}
// Split into env and secrets (public vars will be in env, not secrets)
const { env, secrets } = splitEnvAndSecrets(filteredEnv);
// Check for any public vars that would have been treated as secrets
const publicSecretKeys = validateNoPublicSecrets(secrets);
if (publicSecretKeys.length > 0) {
tui.warning(
`Public variables cannot be secrets. Treating as env: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
);
for (const key of publicSecretKeys) {
delete secrets[key];
env[key] = filteredEnv[key];
}
}
🤖 Prompt for AI Agents
In @packages/cli/src/cmd/cloud/secret/push.ts around lines 49 - 62, The warning
message is misleading because publicSecretKeys returned by
validateNoPublicSecrets are reclassified into env and included in the payload;
update the message in the block that handles publicSecretKeys (references:
splitEnvAndSecrets, validateNoPublicSecrets, publicSecretKeys, secrets, env,
tui.warning) to state that these keys are being moved/reclassified to env (e.g.,
"Reclassifying public variables to env: ...") instead of "Skipping public
variables", and keep the subsequent deletion from secrets and assignment to env
unchanged.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @packages/cli/src/cmd/cloud/env/get.ts:
- Around line 31-32: Remove the schema-level default for mask (drop
.default(!!process.stdout.isTTY)) and compute the effective mask inside the
handler: determine maskDefault = isSecret ? true : !!process.stdout.isTTY, then
set shouldMask = (opts?.mask !== undefined) ? opts.mask : maskDefault; replace
any existing shouldMask logic that uses opts?.mask !== false / === true and
reference the symbols isSecret, opts.mask, and shouldMask (in the handler that
formats env output) so secrets are masked by default even in non-TTY unless the
user explicitly passes --no-mask.

In @packages/cli/src/cmd/cloud/env/push.ts:
- Around line 65-75: The warning message is misleading: validateNoPublicSecrets
returns keys that are moved from secrets into env (not skipped). Update the
tui.warning call that references publicSecretKeys to say these keys are being
moved to env/exposed to the frontend (e.g., "Moving public variables to env:
...") so it matches the subsequent logic that deletes from secrets and assigns
env[key] = filteredEnv[key]; keep the same variables (publicSecretKeys, secrets,
env, filteredEnv) and location around that block so the message accurately
describes the action.
🧹 Nitpick comments (2)
apps/testing/integration-suite/src/test/cli-deployment.ts (1)

226-231: Clarify scope of this placeholder test.

The deploy-syncs-env-vars test covers functionality that is not tested elsewhere in cli-env-secrets.ts (which contains only env-set and secret validation tests, no deployment-related tests). The placeholder addresses a real gap in deployment env sync coverage.

Decide whether this test should be implemented now or deferred as a placeholder. If implemented, follow the required test pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers from @test/helpers.

packages/cli/src/cmd/cloud/env/list.ts (1)

33-34: Consider adding mutual exclusivity validation for --secrets and --env-only flags.

Both flags can technically be set to true simultaneously (e.g., env list --secrets --env-only), which would result in showing all variables—the same as the default behavior. While not incorrect, this might confuse users.

💡 Optional: Add validation or clarify behavior

You could either:

  1. Make the flags mutually exclusive with a validation check
  2. Document that setting both is equivalent to the default behavior
+		// If both filters are set, it's equivalent to showing all
+		if (opts?.secrets && opts?.['env-only']) {
+			tui.warning('Both --secrets and --env-only specified; showing all variables');
+		}
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3bee19c and 1e9a39b.

📒 Files selected for processing (22)
  • apps/testing/integration-suite/src/test/cli-deployment.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/README.md
  • packages/cli/docs/secret-detection.md
  • packages/cli/src/cmd/ai/capabilities/show.ts
  • packages/cli/src/cmd/ai/prompt/llm.ts
  • packages/cli/src/cmd/cloud/env/delete.ts
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/index.ts
  • packages/cli/src/cmd/cloud/env/list.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/index.ts
  • packages/cli/src/cmd/cloud/secret/delete.ts
  • packages/cli/src/cmd/cloud/secret/get.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
  • packages/cli/src/cmd/cloud/secret/index.ts
  • packages/cli/src/cmd/cloud/secret/list.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
💤 Files with no reviewable changes (9)
  • packages/cli/src/cmd/cloud/index.ts
  • packages/cli/src/cmd/cloud/secret/list.ts
  • packages/cli/src/cmd/cloud/secret/pull.ts
  • packages/cli/src/cmd/cloud/secret/get.ts
  • packages/cli/src/cmd/cloud/secret/import.ts
  • packages/cli/src/cmd/cloud/secret/index.ts
  • packages/cli/src/cmd/cloud/secret/delete.ts
  • packages/cli/src/cmd/cloud/secret/set.ts
  • packages/cli/src/cmd/cloud/secret/push.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧰 Additional context used
📓 Path-based instructions (5)
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/ai/capabilities/show.ts
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/ai/prompt/llm.ts
  • packages/cli/src/cmd/cloud/env/index.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/delete.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/list.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/ai/capabilities/show.ts
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/ai/prompt/llm.ts
  • packages/cli/src/cmd/cloud/env/index.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/delete.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/list.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/ai/capabilities/show.ts
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/ai/prompt/llm.ts
  • packages/cli/src/cmd/cloud/env/index.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • apps/testing/integration-suite/src/test/cli-deployment.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/delete.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/list.ts
apps/testing/integration-suite/src/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Use path aliases for imports: @agents/* and @test/* instead of relative paths

Files:

  • apps/testing/integration-suite/src/test/cli-deployment.ts
apps/testing/integration-suite/src/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

apps/testing/integration-suite/src/test/**/*.{ts,tsx}: Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation
Test files must follow the pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers
Import test registration function and assertion helpers from @test/suite and @test/helpers
Use decodeKVValue() helper from @test/helpers/kv to decode stringified Uint8Arrays when reading KV values
Tests must be registered by calling test() function from @test/suite, not just defined

Files:

  • apps/testing/integration-suite/src/test/cli-deployment.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/ai/capabilities/show.ts
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/ai/prompt/llm.ts
  • packages/cli/src/cmd/cloud/env/index.ts
  • packages/cli/src/cmd/cloud/env/set.ts
  • apps/testing/integration-suite/src/test/cli-deployment.ts
  • packages/cli/src/cmd/cloud/env/import.ts
  • packages/cli/src/cmd/cloud/env/delete.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/list.ts
🧬 Code graph analysis (4)
packages/cli/src/cmd/cloud/env/get.ts (1)
packages/server/src/api/project/get.ts (1)
  • projectGet (30-48)
apps/testing/integration-suite/src/test/cli-deployment.ts (2)
apps/testing/integration-suite/src/test/suite.ts (1)
  • test (218-220)
apps/testing/integration-suite/src/test/helpers/index.ts (1)
  • assert (22-26)
packages/cli/src/cmd/cloud/env/delete.ts (2)
packages/server/src/api/project/get.ts (1)
  • projectGet (30-48)
packages/server/src/api/project/env-delete.ts (1)
  • projectEnvDelete (20-41)
packages/cli/src/cmd/cloud/env/push.ts (2)
packages/cli/src/env-util.ts (5)
  • findExistingEnvFile (50-52)
  • readEnvFile (111-130)
  • filterAgentuitySdkKeys (205-216)
  • splitEnvAndSecrets (229-261)
  • validateNoPublicSecrets (43-45)
packages/server/src/api/project/env-update.ts (1)
  • projectEnvUpdate (33-55)
🔇 Additional comments (11)
packages/cli/src/cmd/cloud/env/index.ts (1)

13-24: LGTM! Documentation updates align with new secret handling capabilities.

The updated description and examples clearly communicate the unified env/secrets management approach. The new --secret example is helpful for discoverability.

packages/cli/src/cmd/cloud/env/delete.ts (2)

47-52: Null safety check is correctly handled via optional chaining.

The use of projectData.secrets?.[args.key] and projectData.env?.[args.key] correctly handles cases where secrets or env might be undefined. The logic correctly identifies whether the key exists as a secret or environment variable.


54-81: LGTM! Clean implementation of conditional deletion.

The handler correctly:

  1. Determines the key type by checking cloud data
  2. Uses the appropriate field (secrets vs env) in the deletion payload
  3. Provides clear user feedback distinguishing between secret and env var deletions
  4. Returns the secret flag for programmatic consumers
packages/cli/src/cmd/cloud/env/list.ts (1)

89-101: LGTM! Well-implemented masking and display logic.

The masking correctly applies only to secrets when the mask option is enabled. The output clearly distinguishes between env vars and secrets with the [secret] indicator, and the dynamic count header provides useful context.

packages/cli/src/cmd/cloud/env/set.ts (3)

59-69: LGTM! Validation logic correctly enforces the PR requirements.

The validation correctly:

  1. First checks for reserved AGENTUITY_* prefixed keys (except AGENTUITY_PUBLIC_*)
  2. Then validates that public var prefixes cannot be stored as secrets

The error messages are clear and include the list of public prefixes for user clarity.


83-110: LGTM! Clean implementation of conditional secret/env storage.

The handler correctly constructs the appropriate payload based on the isSecret flag and provides clear feedback to the user. The response schema properly includes the secret boolean for programmatic consumers.


71-80: The tui.confirm prompt handles non-interactive environments safely and will not hang.

The confirm() function at line 75 already gracefully handles non-TTY environments (CI/non-interactive pipelines) by returning the defaultValue (true) without prompting. However, this means the auto-detection will silently store the variable as a secret in CI without user awareness, which may not be the desired behavior for automated pipelines. Consider adding a TTY check before triggering the auto-detection prompt (e.g., if (process.stdin.isTTY && !isSecret && looksLikeSecret(...))) to skip the prompt in non-interactive environments.

Likely an incorrect or invalid review comment.

packages/cli/src/cmd/cloud/env/push.ts (1)

86-100: LGTM! Response includes detailed breakdown of pushed items.

The success message and return value provide useful information about the number of env vars vs secrets pushed.

packages/cli/src/cmd/cloud/env/import.ts (3)

97-104: Good: Import correctly handles public variables with clear messaging.

Unlike push.ts, the warning message here accurately states "Moving public variables to env" which matches the actual behavior. This is the correct approach.


136-142: LGTM! Skipped count correctly reflects filtered reserved keys.

The skipped calculation (Object.keys(importedVars).length - totalCount) correctly represents the number of reserved AGENTUITY_* keys that were filtered out, since totalCount equals all keys that made it through the filter (regardless of whether they ended up as env or secrets).


115-124: Verify: Secrets are written to local .env file.

The merge logic writes all filteredVars (including secrets) to the local .env file. This may be intentional for local development convenience, but it could also pose a security concern if users expect secrets to remain only in the cloud.

Is this the intended behavior? If so, consider adding a comment clarifying that imported secrets are also written locally for development purposes. If not, the merge should exclude secret keys:

-		const mergedEnv = mergeEnvVars(localEnv, filteredVars);
+		// Merge only env vars (not secrets) to local .env
+		const mergedEnv = mergeEnvVars(localEnv, env);

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @apps/testing/integration-suite/src/test/cli-env-secrets.ts:
- Around line 117-120: The asserts pass values that can be undefined (e.g.,
setResult.stdout?.includes(...), setResult.success) but assert requires a
boolean; update each failing assertion (examples include the `assert` using
`setResult.success || setResult.stdout?.includes('set successfully')` and other
occurrences listed) to coerce the condition to a strict boolean by applying `!!`
or `?? false` (for example `!!setResult.success ||
!!setResult.stdout?.includes(...)` or `(setResult.success ||
setResult.stdout?.includes(...)) ?? false`) so every `assert(condition,
message)` call receives a boolean; apply this pattern to all affected assertions
on lines noted (118, 129, 153, 164, 190, 206, 232, 242, 266, 276, 299, 319, 357,
398, 442, 500, 506, 550, 573, 584) referencing the same `assert` usages.
🧹 Nitpick comments (1)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

110-111: Use uniqueId() helper instead of Date.now() for test keys.

The coding guidelines require using uniqueId() for all keys and identifiers in tests to ensure test isolation. Currently, Date.now() is used which may cause collisions if tests run within the same millisecond.

♻️ Proposed fix

Import and use uniqueId():

 import { test } from '@test/suite';
 import { assert, assertEqual } from '@test/helpers';
 import cliAgent from '@agents/cli/agent';
 import { isAuthenticated } from '@test/helpers/cli';
+import { uniqueId } from '@test/helpers';

 // ...

-	const testKey = `MASK_TEST_${Date.now()}`;
+	const testKey = `MASK_TEST_${uniqueId()}`;

Apply this pattern to all test key declarations throughout the file.

As per coding guidelines, tests must use uniqueId() helper for all keys to ensure test isolation.

Also applies to: 145-146, 179-180, 222-223, 256-257, 290-291, 333-334, 371-372, 412-413, 484-485, 528-529, 565-566

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e9a39b and 604fcc1.

📒 Files selected for processing (2)
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/src/cmd/cloud/env/list.ts
🧰 Additional context used
📓 Path-based instructions (5)
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/cloud/env/list.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/cloud/env/list.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/cloud/env/list.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
apps/testing/integration-suite/src/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Use path aliases for imports: @agents/* and @test/* instead of relative paths

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
apps/testing/integration-suite/src/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

apps/testing/integration-suite/src/test/**/*.{ts,tsx}: Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation
Test files must follow the pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers
Import test registration function and assertion helpers from @test/suite and @test/helpers
Use decodeKVValue() helper from @test/helpers/kv to decode stringified Uint8Arrays when reading KV values
Tests must be registered by calling test() function from @test/suite, not just defined

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/cloud/env/list.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧬 Code graph analysis (1)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (3)
apps/testing/integration-suite/src/test/suite.ts (1)
  • test (218-220)
apps/testing/integration-suite/src/test/helpers/index.ts (2)
  • assertEqual (31-34)
  • assert (22-26)
packages/cli/src/tui.ts (1)
  • output (430-432)
🪛 GitHub Actions: Build Packages & Test
apps/testing/integration-suite/src/test/cli-env-secrets.ts

[error] 118-118: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 129-129: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'boolean'.


[error] 153-153: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 164-164: TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'boolean'.


[error] 190-190: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


206-206: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 232-232: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 242-242: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 266-266: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 276-276: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 299-299: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 319-319: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 357-357: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 398-398: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 442-442: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 500-500: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 506-506: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 550-550: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 573-573: TS2345: Argument of type 'boolean | undefined' is not assignable to parameter of type 'boolean'.


[error] 584-584: TS2345: Argument of type 'string | boolean | undefined' is not assignable to parameter of type 'boolean'.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Template Integration Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Pack & Upload
🔇 Additional comments (4)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

1-14: LGTM on overall test structure and coverage.

The test module correctly:

  • Documents the validation rules in the header comment
  • Uses path aliases (@test/suite, @test/helpers, @agents/cli/agent) as required
  • Follows the setup → execute → assert pattern
  • Registers tests using the test() function from @test/suite
  • Covers the key scenarios: reserved key blocking, public prefix blocking for secrets, masking behavior, CRUD operations, and auto-detection
packages/cli/src/cmd/cloud/env/list.ts (3)

7-12: LGTM on schema definitions.

The EnvItemSchema and EnvListResponseSchema are well-structured. The z.record(z.string(), EnvItemSchema) pattern correctly maps string keys to the item schema in Zod 4.


40-68: LGTM on handler fetch and filtering logic.

The implementation correctly:

  • Fetches unmasked values to enable proper masking at display time
  • Builds a combined result object with type information
  • Filters based on --secrets and --env-only flags with sensible defaults (show both when neither flag is set)

89-101: LGTM on masking and display logic.

The masking logic correctly applies only to secrets when mask is true (the default), and the type indicator [secret] provides clear differentiation. Using tui.bold(), tui.muted(), and tui.maskSecret() aligns with the coding guidelines for CLI output formatting.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @apps/testing/integration-suite/src/test/cli-env-secrets.ts:
- Line 110: Replace Date.now() usages used to generate test keys with the
uniqueId() helper to avoid collisions; specifically update the constant
assignment for testKey (`MASK_TEST_${Date.now()}`) to `MASK_TEST_${uniqueId()}`
and apply the same replacement for all other test key templates mentioned
(NOMASK_TEST_, AGENTUITY_PUBLIC_TEST_, VITE_TEST_, PUBLIC_TEST_, SECRET_KEY_,
MY_API_KEY_, CONFIG_VAL_, NORMAL_VAR_, CRUD_TEST_, OVERWRITE_TEST_,
CONVERT_TEST_) so each becomes e.g. `NOMASK_TEST_${uniqueId()}`; ensure
uniqueId() is imported/available in the test file before use.
- Around line 10-13: Add the missing uniqueId() import to the existing helper
imports so tests use uniqueId for keys/identifiers: update the import line that
currently imports assert and assertEqual from '@test/helpers' to also import
uniqueId (e.g., import { assert, assertEqual, uniqueId } from '@test/helpers')
and then replace any hardcoded test keys in the CLI env secrets test with calls
to uniqueId() where required for isolation.
🧹 Nitpick comments (1)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

17-18: Consider extracting authentication guard into a helper.

The authentication check pattern const authenticated = await isAuthenticated(); if (!authenticated) return; is repeated in every test. Consider creating a test wrapper or setup hook to reduce duplication.

♻️ Example helper pattern
async function authenticatedTest(fn: () => Promise<void>): Promise<void> {
	const authenticated = await isAuthenticated();
	if (!authenticated) return;
	await fn();
}

Usage:

test('cli-env-secrets', 'env-set-secret-blocks-reserved-agentuity-key', async () => {
	await authenticatedTest(async () => {
		const result = await cliAgent.run({
			command: 'cloud env set AGENTUITY_SDK_KEY test_value --secret',
		});
		// ... assertions
	});
});

Also applies to: 35-36, 53-54, 71-72, 89-90, 107-108, 142-143, 176-177, 221-222, 257-258, 293-294, 338-339, 376-377, 417-418, 461-462, 475-476, 489-490, 533-534, 570-571

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 604fcc1 and 60c628a.

📒 Files selected for processing (1)
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/testing/integration-suite/src/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Use path aliases for imports: @agents/* and @test/* instead of relative paths

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
apps/testing/integration-suite/src/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

apps/testing/integration-suite/src/test/**/*.{ts,tsx}: Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation
Test files must follow the pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers
Import test registration function and assertion helpers from @test/suite and @test/helpers
Use decodeKVValue() helper from @test/helpers/kv to decode stringified Uint8Arrays when reading KV values
Tests must be registered by calling test() function from @test/suite, not just defined

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
🧬 Code graph analysis (1)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (2)
apps/testing/integration-suite/src/test/suite.ts (1)
  • test (218-220)
apps/testing/integration-suite/src/test/helpers/index.ts (2)
  • assertEqual (31-34)
  • assert (22-26)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Pack & Upload
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Build
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Template Integration Tests
🔇 Additional comments (1)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

16-617: Comprehensive test coverage with good assertion patterns.

The test suite provides excellent coverage of:

  • Reserved key validation (AGENTUITY_* blocking)
  • Public var prefix validation (VITE_, PUBLIC_, AGENTUITY_PUBLIC_*)
  • Secret masking behavior (default masking, --no-mask flag)
  • Auto-detection of secret-like keys/values
  • Full CRUD operations with cleanup
  • Edge cases (not found, overwrite, secret-to-env conversion)

The defensive assertion patterns (checking both result.success and stdout content) handle different success/failure reporting methods well.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @packages/cli/src/cmd/cloud/env/get.ts:
- Around line 59-61: The handler uses opts?.mask but the CLI schema defines the
option as maskSecret, causing a TS property error; update the code around
maskDefault/shouldMask to read opts?.maskSecret (and treat it as boolean)
instead of opts?.mask so shouldMask = opts?.maskSecret !== undefined ?
opts.maskSecret : maskDefault and keep the existing logic using isSecret and
process.stdout.isTTY unchanged.
🧹 Nitpick comments (4)
packages/cli/src/cmd/cloud/env/push.ts (2)

48-49: Clarify the comment to reflect that AGENTUITY_PUBLIC_* keys are allowed.

The comment states "Filter out reserved AGENTUITY_ prefixed keys," but according to the PR objectives, filterAgentuitySdkKeys() now allows AGENTUITY_PUBLIC_* keys through. Consider updating the comment to be more precise.

📝 Suggested comment clarification
-		// Filter out reserved AGENTUITY_ prefixed keys
+		// Filter out reserved AGENTUITY_ prefixed keys (except AGENTUITY_PUBLIC_*)
 		const filteredEnv = filterAgentuitySdkKeys(localEnv);

65-75: Consider removing redundant public secret validation.

The splitEnvAndSecrets function already routes public variables (identified by isPublicVarKey) to the env object rather than secrets (see lines 239-242 in env-util.ts). This means validateNoPublicSecrets(secrets) should always return an empty array, making the validation and relocation logic at lines 66-75 redundant.

If this is intentional defensive programming, consider adding a comment explaining why. Otherwise, this code can be simplified.

♻️ Proposed simplification
 		// Split into env and secrets based on key naming conventions
 		const { env, secrets } = splitEnvAndSecrets(filteredEnv);
-
-		// Check for any public vars that would have been treated as secrets
-		const publicSecretKeys = validateNoPublicSecrets(secrets);
-		if (publicSecretKeys.length > 0) {
-			tui.warning(
-				`Moving public variables to env: ${publicSecretKeys.join(', ')} (these are exposed to the frontend)`
-			);
-			for (const key of publicSecretKeys) {
-				delete secrets[key];
-				env[key] = filteredEnv[key];
-			}
-		}

Note: Only apply this change if the defensive check is confirmed to be unnecessary. If there are edge cases where public vars might end up in secrets despite splitEnvAndSecrets logic, keep the validation.

apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

133-138: Consider using the command string format consistently for delete.

Other tests pass options like --secret directly in the command string (e.g., line 115: `cloud env set ${testKey} ${testValue} --secret`), but the cleanup here uses the args array format. While both work, consistency would improve readability.

♻️ Suggested change for consistency
 	// Cleanup
 	await cliAgent.run({
-		command: 'cloud env delete',
-		args: [testKey],
+		command: `cloud env delete ${testKey}`,
 	});
apps/testing/integration-suite/scripts/ci-test.sh (1)

166-169: Remove or use the unused EVENT variable.

The static analysis hint correctly identifies that EVENT is assigned but never used. Either remove the capture or use it for logging/debugging if needed.

♻️ Option 1: Remove unused variable
 		if [[ "$line" =~ ^event:\ (.*)$ ]]; then
-			EVENT="${BASH_REMATCH[1]}"
 			continue
 		fi
♻️ Option 2: Keep for debugging (suppress warning)
 		if [[ "$line" =~ ^event:\ (.*)$ ]]; then
-			EVENT="${BASH_REMATCH[1]}"
+			# shellcheck disable=SC2034
+			EVENT="${BASH_REMATCH[1]}"  # Captured for potential debugging
 			continue
 		fi
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 60c628a and fb0ce0c.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • apps/testing/integration-suite/scripts/ci-test.sh
  • apps/testing/integration-suite/src/test/api-route.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • apps/testing/integration-suite/src/test/helpers/index.ts
  • apps/testing/integration-suite/src/web/index.html
  • packages/cli/src/cmd/cloud/env/get.ts
  • packages/cli/src/cmd/cloud/env/push.ts
🧰 Additional context used
📓 Path-based instructions (6)
apps/testing/integration-suite/src/**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

Use path aliases for imports: @agents/* and @test/* instead of relative paths

Files:

  • apps/testing/integration-suite/src/test/helpers/index.ts
  • apps/testing/integration-suite/src/test/api-route.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
apps/testing/integration-suite/src/test/**/*.{ts,tsx}

📄 CodeRabbit inference engine (apps/testing/integration-suite/AGENTS.md)

apps/testing/integration-suite/src/test/**/*.{ts,tsx}: Use uniqueId() helper for all keys, namespaces, and identifiers in tests to ensure test isolation
Test files must follow the pattern: setup section with uniqueId(), execute section calling agent.run(), and assert section with assertion helpers
Import test registration function and assertion helpers from @test/suite and @test/helpers
Use decodeKVValue() helper from @test/helpers/kv to decode stringified Uint8Arrays when reading KV values
Tests must be registered by calling test() function from @test/suite, not just defined

Files:

  • apps/testing/integration-suite/src/test/helpers/index.ts
  • apps/testing/integration-suite/src/test/api-route.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • apps/testing/integration-suite/src/test/helpers/index.ts
  • apps/testing/integration-suite/src/test/api-route.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/get.ts
apps/testing/integration-suite/src/web/**/index.html

📄 CodeRabbit inference engine (apps/testing/integration-suite/src/web/AGENTS.md)

apps/testing/integration-suite/src/web/**/index.html: index.html must have a <div id="root"></div> element
Use a module script tag: <script type="module" src="/web/frontend.tsx"></script> in index.html

Files:

  • apps/testing/integration-suite/src/web/index.html
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/get.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/get.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • apps/testing/integration-suite/src/test/helpers/index.ts
  • apps/testing/integration-suite/src/test/api-route.ts
  • apps/testing/integration-suite/src/test/cli-env-secrets.ts
  • packages/cli/src/cmd/cloud/env/push.ts
  • packages/cli/src/cmd/cloud/env/get.ts
🧬 Code graph analysis (4)
apps/testing/integration-suite/src/test/api-route.ts (1)
apps/testing/integration-suite/src/test/suite.ts (2)
  • testSuite (213-213)
  • test (218-220)
apps/testing/integration-suite/src/test/cli-env-secrets.ts (3)
apps/testing/integration-suite/src/test/suite.ts (1)
  • test (218-220)
apps/testing/integration-suite/src/test/helpers/index.ts (3)
  • assertEqual (32-35)
  • assert (23-27)
  • uniqueId (12-18)
packages/cli/src/tui.ts (1)
  • output (430-432)
packages/cli/src/cmd/cloud/env/push.ts (2)
packages/cli/src/env-util.ts (5)
  • findExistingEnvFile (50-52)
  • readEnvFile (111-130)
  • filterAgentuitySdkKeys (205-216)
  • splitEnvAndSecrets (229-261)
  • validateNoPublicSecrets (43-45)
packages/server/src/api/project/env-update.ts (1)
  • projectEnvUpdate (33-55)
packages/cli/src/cmd/cloud/env/get.ts (3)
packages/cli/src/cmd/cloud/db/get.ts (1)
  • getSubcommand (20-164)
packages/cli/src/cmd/cloud/storage/get.ts (1)
  • getSubcommand (17-107)
packages/server/src/api/project/get.ts (1)
  • projectGet (30-48)
🪛 GitHub Actions: Build Packages & Test
packages/cli/src/cmd/cloud/env/get.ts

[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.


[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.

🪛 GitHub Actions: NPM Pack & Upload
packages/cli/src/cmd/cloud/env/get.ts

[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.

🪛 Shellcheck (0.11.0)
apps/testing/integration-suite/scripts/ci-test.sh

[warning] 167-167: EVENT appears unused. Verify use (or export if used externally).

(SC2034)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
🔇 Additional comments (7)
packages/cli/src/cmd/cloud/env/push.ts (2)

5-18: LGTM!

The new imports from env-util and the extended response schema with granular counts align well with the PR objectives.


77-100: LGTM!

The push operation correctly sends env and secrets separately to projectEnvUpdate, calculates counts accurately, and provides clear user feedback with proper pluralization.

apps/testing/integration-suite/src/web/index.html (1)

1-22: LGTM!

The file meets coding guidelines: has <div id="root"></div> and uses a module script tag. The relative path ./frontend.tsx is appropriate for the file's location within the web directory.

apps/testing/integration-suite/src/test/helpers/index.ts (1)

12-18: LGTM!

The change from hyphens to underscores ensures generated IDs are valid environment variable names (POSIX shell compatibility). The comment clearly documents the rationale.

apps/testing/integration-suite/src/test/api-route.ts (1)

45-54: LGTM!

The exclude parameter implementation is clean: parses comma-separated suite names, trims whitespace, and filters accordingly. The approach correctly preserves compatibility with existing suite and test parameters.

apps/testing/integration-suite/src/test/cli-env-secrets.ts (1)

1-14: LGTM!

Comprehensive integration test suite covering validation rules, secret handling, masking, auto-detection, CRUD operations, and edge cases. Tests properly use path aliases (@test/*, @agents/*) and uniqueId() for test isolation as per coding guidelines.

apps/testing/integration-suite/scripts/ci-test.sh (1)

229-235: LGTM - well-designed two-phase execution.

The approach of running most tests at high concurrency while isolating cli-env-secrets tests at concurrency=1 is appropriate given that those tests interact with cloud APIs that can't handle concurrent modifications to the same resources.

Comment on lines +59 to +61
// For secrets, mask by default even in non-TTY; for env vars, mask only in TTY by default
const maskDefault = isSecret ? true : !!process.stdout.isTTY;
const shouldMask = opts?.mask !== undefined ? opts.mask : maskDefault;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix property name mismatch causing TypeScript error.

The schema defines the option as maskSecret (line 29), but the handler accesses opts?.mask. This causes the pipeline failure TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.

🐛 Proposed fix
 		// For secrets, mask by default even in non-TTY; for env vars, mask only in TTY by default
 		const maskDefault = isSecret ? true : !!process.stdout.isTTY;
-		const shouldMask = opts?.mask !== undefined ? opts.mask : maskDefault;
+		const shouldMask = opts?.maskSecret !== undefined ? opts.maskSecret : maskDefault;
📝 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
// For secrets, mask by default even in non-TTY; for env vars, mask only in TTY by default
const maskDefault = isSecret ? true : !!process.stdout.isTTY;
const shouldMask = opts?.mask !== undefined ? opts.mask : maskDefault;
// For secrets, mask by default even in non-TTY; for env vars, mask only in TTY by default
const maskDefault = isSecret ? true : !!process.stdout.isTTY;
const shouldMask = opts?.maskSecret !== undefined ? opts.maskSecret : maskDefault;
🧰 Tools
🪛 GitHub Actions: Build Packages & Test

[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.


[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.

🪛 GitHub Actions: NPM Pack & Upload

[error] 61-61: TypeScript error TS2339: Property 'mask' does not exist on type '{ maskSecret?: boolean | undefined; }'.

🤖 Prompt for AI Agents
In @packages/cli/src/cmd/cloud/env/get.ts around lines 59 - 61, The handler uses
opts?.mask but the CLI schema defines the option as maskSecret, causing a TS
property error; update the code around maskDefault/shouldMask to read
opts?.maskSecret (and treat it as boolean) instead of opts?.mask so shouldMask =
opts?.maskSecret !== undefined ? opts.maskSecret : maskDefault and keep the
existing logic using isSecret and process.stdout.isTTY unchanged.

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