Skip to content

feat: enforce encrypted bundles in organization security#1343

Merged
riderx merged 5 commits intomainfrom
riderx/enforce-encrypted-keys
Jan 12, 2026
Merged

feat: enforce encrypted bundles in organization security#1343
riderx merged 5 commits intomainfrom
riderx/enforce-encrypted-keys

Conversation

@riderx
Copy link
Copy Markdown
Member

@riderx riderx commented Jan 1, 2026

Summary

Adds a new organization security setting to enforce encrypted bundles. When enabled, all bundle uploads to apps in that organization must include a valid session_key (encryption data). Implements both database-level enforcement via trigger and API-level validation for defense in depth.

Test plan

  • Run bun test:backend --testNamePattern="Encrypted Bundles Enforcement" to verify all 17 tests pass
  • Test UI: Navigate to Organization Settings > Security and verify the new "Enforce Encrypted Bundles" toggle appears between 2FA and Members sections
  • Test API enforcement: Upload a bundle without session_key to an org with enforcement enabled - should receive 400 error with encryption_required code
  • Test backward compatibility: Upload bundles to orgs without enforcement enabled - should work normally with or without session_key

Checklist

  • My code follows the code style of this project and passes bun run lint:backend && bun run lint
  • My change requires a change to the documentation
  • My change has adequate E2E test coverage (17 tests covering all scenarios)
  • I have tested my code manually

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Organization-level Encrypted Bundles enforcement with optional required encryption key and deletion of non-compliant bundles.
  • Improvements

    • Settings UI: enforcement toggle, key input, status badges, warnings, counts and confirmation flows.
    • Backend/DB: insert-time enforcement, enforcement checks, non-compliant bundle counting and deletion, org schema fields.
  • Localization

    • Added encrypted-bundles UI text across many languages.
  • Tests

    • End-to-end and unit tests covering enforcement, API/DB paths, and lifecycle scenarios.

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

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 1, 2026

Warning

Rate limit exceeded

@riderx has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 26 minutes and 46 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 30f95db and bf581c9.

📒 Files selected for processing (26)
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/hi.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/pl.json
  • messages/pt-br.json
  • messages/ru.json
  • messages/tr.json
  • messages/vi.json
  • messages/zh-cn.json
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/pg.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • supabase/seed.sql
  • tests/build_time_tracking.test.ts
  • tests/enforce-encrypted-bundles.test.ts
  • tests/test-utils.ts
  • tests/updates.test.ts
📝 Walkthrough

Walkthrough

Adds an organization-level "Encrypted Bundles" policy: DB schema, functions/triggers, Supabase type updates, backend bundle creation checks, frontend settings UI and flows, tests, seed/test fixtures, and i18n strings across locales to manage and enforce a required encryption key for bundles.

Changes

Cohort / File(s) Change summary
Database migration & functions
supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
Add enforce_encrypted_bundles and required_encryption_key to orgs; add is_bundle_encrypted, check_org_encrypted_bundle_enforcement, check_encrypted_bundle_on_insert trigger, count_non_compliant_bundles, delete_non_compliant_bundles; extend get_orgs_v7 overloads and adjust grants.
DB types / public function surfaces
supabase/functions/_backend/utils/supabase.types.ts, src/types/supabase.types.ts
Propagate new org fields into Table/Insert/Update/View shapes; add Function signatures for check_org_encrypted_bundle_enforcement, is_bundle_encrypted, count_non_compliant_bundles, delete_non_compliant_bundles; adjust max_apikey_expiration_days nullability.
Backend bundle create function
supabase/functions/_backend/public/bundle/create.ts
Use supabaseAdmin to fetch app+org (AppWithOrg), accept optional key_id in payload, add checkEncryptedBundleEnforcement to enforce per-org rules before insert, include key_id on insert when present.
Frontend settings UI
src/pages/settings/organization/Security.vue
Add state/logic for enforceEncryptedBundles, requiredEncryptionKey, nonCompliantBundleCounts; implement RPC calls to count/delete non-compliant bundles; add toggle/save/update flows with warnings/dialogs, new UI elements and icons.
Tests & test utilities
tests/enforce-encrypted-bundles.test.ts, tests/build_time_tracking.test.ts, tests/test-utils.ts
New E2E test covering enforcement lifecycle, RPCs, trigger behavior, and bundle creation; test scaffolding and fixtures extended; new encrypted test constants added.
Seed data
supabase/seed.sql
Add encrypted test org/app/app_version/apikey rows and related seed adjustments to support encrypted-bundle tests.
i18n
messages/en.json, messages/*.json (many locales)
Add English translation keys for extended dialogs and many localized keys (label, description, enabled/disabled status, warnings, key input text, error strings) across locales.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Admin as Org Admin (UI)
participant Frontend as Security.vue
participant RPC as Supabase RPC / Backend
participant DB as Database Functions/Trigger
Admin->>Frontend: Toggle "Enable Encrypted Bundles" / update key
Frontend->>RPC: call count_non_compliant_bundles(org_id, required_key?)
RPC->>DB: execute count_non_compliant_bundles
DB-->>RPC: returns counts
RPC-->>Frontend: counts
alt non-compliant > 0
Frontend->>Admin: Show warning (delete or cancel)
Admin->>Frontend: Confirm enable + delete
Frontend->>RPC: call delete_non_compliant_bundles(org_id, required_key)
RPC->>DB: delete_non_compliant_bundles
DB-->>RPC: deleted_count
RPC-->>Frontend: success
end
Frontend->>RPC: update org row (enforce_encrypted_bundles, required_encryption_key)
RPC->>DB: update orgs
DB-->>RPC: ack
RPC-->>Frontend: success
Frontend-->>Admin: show toast (enabled)

mermaid
sequenceDiagram
participant Client as Bundle Uploader
participant CreateFn as /bundle/create function
participant AdminAPI as Supabase Admin fetch (getAppOrganization)
participant DB as Database / Trigger
Client->>CreateFn: POST create bundle (payload, session_key?, key_id?)
CreateFn->>AdminAPI: getAppOrganization(appId) via supabaseAdmin
AdminAPI-->>CreateFn: returns AppWithOrg (owner_org, enforcement settings)
CreateFn->>DB: call check_org_encrypted_bundle_enforcement(org_id, session_key)
DB-->>CreateFn: allowed / raises enforcement error
alt allowed
CreateFn->>DB: insert bundle (includes key_id if present)
DB-->>CreateFn: inserted bundle
CreateFn-->>Client: 200 OK
else denied
DB-->>CreateFn: raises enforcement error
CreateFn-->>Client: 400 encryption_required
end

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

enhancement

"I hopped through code with a twitchy nose,
New keys and guards in tidy rows.
Bundles now safe beneath my paw —
Encrypt or else, that's the law! 🐇🔐"

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: introducing enforcement of encrypted bundles at the organization security level.
Description check ✅ Passed The PR description covers the summary, test plan, and checklist sections from the template, providing clear details on the feature, testing approach, and compliance status.

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


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

❤️ Share

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

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +109 to +112
-- Get the org's enforcement setting for this app
SELECT enforce_encrypted_bundles INTO org_enforcing
FROM public.orgs
WHERE id = NEW.owner_org;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce encryption after owner_org is populated

The trigger looks up enforcement using NEW.owner_org, but owner_org is populated by the existing force_valid_owner_org_app_versions BEFORE trigger (see supabase/migrations/20250530233128_base.sql around lines 4098-4102) which fires after this one due to name ordering. That means any insert that omits owner_org (e.g., direct SDK inserts relying on the auto-owner trigger) will see org_enforcing as NULL here and bypass encryption even when the org requires it. Consider moving the enforcement check to run after auto_owner_org_by_app_id (e.g., rename trigger to sort after, or derive org from app_id directly) to avoid this bypass.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

@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

♻️ Duplicate comments (1)
supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)

99-151: Trigger can run before owner_org is populated, allowing unenforced inserts

check_encrypted_bundle_on_insert looks up enforce_encrypted_bundles using NEW.owner_org:

SELECT enforce_encrypted_bundles INTO org_enforcing
FROM public.orgs
WHERE id = NEW.owner_org;
...
IF org_enforcing IS NULL OR org_enforcing = false THEN
  RETURN NEW;
END IF;

However, as called out in a previous review, owner_org is populated by the existing force_valid_owner_org_app_versions/auto-owner trigger, which is also a BEFORE INSERT trigger and fires after this one due to trigger name ordering. That means:

  • Inserts that omit owner_org (relying on the auto-owner trigger to infer it from app_id) will see NEW.owner_org as NULL in this trigger.
  • org_enforcing stays NULL, so the early IF org_enforcing IS NULL ... THEN RETURN NEW path is taken.
  • The bundle is inserted unencrypted even when the owning org has enforce_encrypted_bundles = true, defeating the DB‑level enforcement you’re aiming for.

To close this gap, you can either ensure this trigger runs after the owner-org-populating trigger, or avoid depending on NEW.owner_org entirely and derive the org from NEW.app_id. The latter is more robust and doesn’t rely on trigger ordering. For example:

Suggested fix: derive org from app_id
-  -- Get the org's enforcement setting for this app
-  SELECT enforce_encrypted_bundles INTO org_enforcing
-  FROM public.orgs
-  WHERE id = NEW.owner_org;
+  -- Get the org's enforcement setting for this app via its owner_org
+  SELECT o.enforce_encrypted_bundles INTO org_enforcing
+  FROM public.apps a
+  JOIN public.orgs o ON o.id = a.owner_org
+  WHERE a.app_id = NEW.app_id;

You can keep the rest of the trigger logic (logging and exception) unchanged.

This is the same concern raised earlier and still needs to be addressed to make the trigger a true “hard enforcement” layer.

🧹 Nitpick comments (5)
tests/build_time_tracking.test.ts (1)

12-24: Stripe info snapshot + per-test reset logic looks solid (typing could be tightened)

The new beforeAll/afterAll snapshot of stripe_info plus the stricter beforeEach reset (status, product, anchors, exceeded flags, plan_calculated_at, plus clearing daily_build_time and app_metrics_cache) gives much better test isolation. Behaviorally this is sound.

If you want a bit more type safety, you could replace any with the generated Supabase type, e.g.:

Optional typing improvement
-// Use a mutex-like approach: save original state and restore after tests
-let originalStripeInfo: any = null
+// Use a mutex-like approach: save original state and restore after tests
+let originalStripeInfo: Database['public']['Tables']['stripe_info']['Row'] | null = null

(Import Database from your local supabase.types helper.)

This is optional and doesn’t affect runtime behavior.

Also applies to: 26-48, 84-91, 114-139

src/pages/settings/organization/Security.vue (1)

53-55: Encrypted bundles enforcement wiring is correct; optionally refresh org store after toggle

The new enforceEncryptedBundles state, the extended loadData select, toggleEnforceEncryptedBundles, and the Encrypted Bundles Enforcement section in the template all line up with the new orgs.enforce_encrypted_bundles column and messages keys. Permission gating via hasOrgPerm and isSaving matches how hashed API keys are handled.

One optional improvement: after a successful update you might want to refresh organizations so currentOrganization (and any other consumers of get_orgs_v7) see the new flag immediately, similar to what you already do for password/API key policies.

For example:

Optional store refresh
    if (error) {
      console.error('Failed to update enforce_encrypted_bundles:', error)
      // Revert optimistic update
      enforceEncryptedBundles.value = previousValue
      toast.error(t('error-saving-settings'))
      return
    }

-    toast.success(newValue ? t('encrypted-bundles-enforcement-enabled') : t('encrypted-bundles-enforcement-disabled'))
+    toast.success(newValue ? t('encrypted-bundles-enforcement-enabled') : t('encrypted-bundles-enforcement-disabled'))
+    await organizationStore.fetchOrganizations()

Also applies to: 156-179, 429-467, 821-863

supabase/functions/_backend/public/bundle/create.ts (1)

4-4: App/org lookup and encrypted bundle enforcement are correctly integrated

  • getAppOrganization uses supabaseAdmin plus an orgs!inner(enforce_encrypted_bundles) join, which is appropriate for reading org-level security flags while bypassing RLS, and still sits behind the explicit hasAppRightApikey check so unauthorized API keys can’t probe other orgs.
  • checkEncryptedBundleEnforcement mirrors the DB semantics (non-empty session_key when the org requires encryption) and surfaces a clear encryption_required error code for the API layer.
  • createBundle now:
    • validates inputs,
    • enforces app write permissions,
    • fetches the app+org, then
    • enforces encryption before inserting, and
    • passes appWithOrg.owner_org into the insert, ensuring the DB trigger sees the correct org even when callers don’t explicitly send owner_org.

If you ever want to avoid duplicating the enforcement logic in TS and SQL, you could call the check_org_encrypted_bundle_enforcement function via Supabase instead, but that’s an optional refactor rather than a requirement.

Also applies to: 131-151, 167-179, 230-238

tests/enforce-encrypted-bundles.test.ts (2)

59-66: Consider adding error handling to cleanup.

While the random UUID isolation mitigates stale data issues, silent cleanup failures could accumulate test artifacts over time. Consider logging or handling errors.

🔎 Optional: Add error logging to cleanup
 afterAll(async () => {
   // Clean up in reverse order of dependencies
-  await getSupabaseClient().from('app_versions').delete().eq('app_id', APPNAME)
-  await getSupabaseClient().from('apps').delete().eq('app_id', APPNAME)
-  await getSupabaseClient().from('org_users').delete().eq('org_id', testOrgId)
-  await getSupabaseClient().from('orgs').delete().eq('id', testOrgId)
-  await getSupabaseClient().from('stripe_info').delete().eq('customer_id', customerId)
+  const cleanups = [
+    getSupabaseClient().from('app_versions').delete().eq('app_id', APPNAME),
+    getSupabaseClient().from('apps').delete().eq('app_id', APPNAME),
+    getSupabaseClient().from('org_users').delete().eq('org_id', testOrgId),
+    getSupabaseClient().from('orgs').delete().eq('id', testOrgId),
+    getSupabaseClient().from('stripe_info').delete().eq('customer_id', customerId),
+  ]
+  for (const cleanup of cleanups) {
+    const { error } = await cleanup
+    if (error) console.warn('Cleanup warning:', error.message)
+  }
 })

81-105: Consider verifying the reset operation succeeded.

The reset at line 101-104 doesn't check for errors. If it fails silently, subsequent tests in other describe blocks could be affected.

🔎 Optional: Add verification to reset
       // Reset back to false for other tests
-      await getSupabaseClient()
+      const { error: resetError } = await getSupabaseClient()
         .from('orgs')
         .update({ enforce_encrypted_bundles: false })
         .eq('id', testOrgId)
+      expect(resetError).toBeNull()
     })
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ff3df08 and 1715310.

📒 Files selected for processing (8)
  • messages/en.json
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • tests/build_time_tracking.test.ts
  • tests/enforce-encrypted-bundles.test.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • src/pages/settings/organization/Security.vue
  • supabase/functions/_backend/public/bundle/create.ts
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
tests/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Backend tests should be located in the tests/ directory and use Vitest test runner

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
tests/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend tests must use helpers from tests/test-utils.ts including getEndpointUrl(path) for correct worker routing and USE_CLOUDFLARE_WORKERS=true for CF Workers testing

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/{migrations,tests,__tests__}/**/*.{sql,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
src/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.vue: Use Vue 3 with Composition API and <script setup> syntax for frontend components
Style components using TailwindCSS with DaisyUI components

src/**/*.vue: Use Vue 3 <script setup> syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn, d-input, d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
Use useRoute() from vue-router to access route parameters and useRouter() for programmatic navigation in Vue components

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/pages/settings/organization/Security.vue
src/pages/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

Use file-based routing with unplugin-vue-router for frontend pages

Frontend file-based routing uses src/pages/ directory structure; routes auto-generate with unplugin-vue-router and types are available in src/typed-router.d.ts

Files:

  • src/pages/settings/organization/Security.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}

📄 CodeRabbit inference engine (CLAUDE.md)

Mobile apps should use Capacitor with app ID ee.forgr.capacitor_go for native mobile functionality

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use ~/ alias for imports from src/ directory in frontend TypeScript and Vue components

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend ESLint must pass before commit; run bun lint:fix to auto-fix issues in frontend files

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for the safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{css,scss,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo design palette from src/styles/style.css (e.g., --color-primary-500: #515271, --color-azure-500: #119eff) when introducing new UI, using deep slate bases with the Extract azure highlight and soft radii

Files:

  • src/pages/settings/organization/Security.vue
supabase/functions/_backend/**

📄 CodeRabbit inference engine (CLAUDE.md)

Backend logic should be organized in supabase/functions/_backend/ with subdirectories for plugins, private endpoints, public endpoints, triggers, and utilities

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Supabase Edge Functions use Deno runtime

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/_backend/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/functions/_backend/**/*.{ts,js}: Backend code must be placed in supabase/functions/_backend/ as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
Use createHono from utils/hono.ts for all Hono framework application initialization and routing
All database operations must use getPgClient() or getDrizzleClient() from utils/pg.ts for PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must accept Context<MiddlewareKeyVariables> and use c.get('requestId'), c.get('apikey'), and c.get('auth') for request context
Use structured logging with cloudlog({ requestId: c.get('requestId'), message: '...' }) for all backend logging
Use middlewareAPISecret for internal API endpoints and middlewareKey for external API keys; validate against owner_org in the apikeys table
Check c.get('auth')?.authType to determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns with schema from postgress_schema.ts for all database operations; use aliasV2() for self-joins or multiple table references

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend ESLint must pass before commit; run bun lint:backend for backend files

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/migrations/**/*.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Database migrations must be created with supabase migration new <feature_slug> and never modify previously committed migrations

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/migrations/*.sql

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/*.sql: When creating schema changes, use supabase migration new <feature_slug> to create a single migration file and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, treating seeding as part of the current feature and not modifying previously committed migrations
Do not create new cron jobs; instead update the process_all_cron_tasks function in a new migration file to add your job if needed

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧠 Learnings (16)
📓 Common learnings
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to playwright/e2e/**/*.{ts,js} : Cover customer-facing flows with Playwright MCP suite; add scenarios under `playwright/e2e` and run them locally with `bun run test:front` before shipping UI changes

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Backend tests modify local database; always reset database with `supabase db reset` before running tests to ensure clean state

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Backend tests that modify local database state require a running Supabase instance

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to tests/**/*.{ts,js} : Backend tests must use helpers from `tests/test-utils.ts` including `getEndpointUrl(path)` for correct worker routing and `USE_CLOUDFLARE_WORKERS=true` for CF Workers testing

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to tests/**/*.{test,spec}.{ts,tsx} : Backend tests should be located in the `tests/` directory and use Vitest test runner

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-25T11:22:19.594Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.

Applied to files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table

Applied to files:

  • src/pages/settings/organization/Security.vue
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Check `c.get('auth')?.authType` to determine authentication type ('apikey' vs 'jwt') in backend endpoints

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-24T14:11:10.256Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:409-539
Timestamp: 2025-12-24T14:11:10.256Z
Learning: In supabase/migrations for get_orgs_v6 and get_orgs_v7: The inner functions with user_id parameter (get_orgs_v6(uuid) and get_orgs_v7(uuid)) should NOT be granted to anon/authenticated roles as this allows any user to query other users' organizations; only the no-argument wrapper functions should be public as they perform authentication checks.

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `createHono` from `utils/hono.ts` for all Hono framework application initialization and routing

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : All Hono endpoint handlers must accept `Context<MiddlewareKeyVariables>` and use `c.get('requestId')`, `c.get('apikey')`, and `c.get('auth')` for request context

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to supabase/functions/**/*.ts : Supabase Edge Functions use Deno runtime

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-25T11:22:13.039Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:13.039Z
Learning: In SQL migrations under the repository (e.g., supabase/migrations), enforce that when an org has enforcing_2fa=true, all users (including super_admins) must have 2FA enabled before accessing any org functions, including check_org_members_2fa_enabled. Do not grant admin exceptions to 2FA requirements. This ensures consistent security enforcement across all org-related operations; implement this rule within relevant migrations and associated stored procedures/tests.

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧬 Code graph analysis (2)
tests/enforce-encrypted-bundles.test.ts (1)
tests/test-utils.ts (4)
  • getSupabaseClient (359-378)
  • TEST_EMAIL (54-54)
  • USER_ID (45-45)
  • BASE_URL (19-19)
supabase/functions/_backend/public/bundle/create.ts (1)
supabase/functions/_backend/utils/hono.ts (1)
  • simpleError (247-249)
🪛 GitHub Actions: Run tests
tests/build_time_tracking.test.ts

[error] 3-3: TS6133: 'TEST_EMAIL' is declared but its value is never read. (from vue-tsc --noEmit during bun typecheck)

🔇 Additional comments (18)
messages/en.json (1)

798-801: Encrypted bundles i18n keys are consistent and correctly scoped

The new translation keys for encrypted bundles enforcement match the feature behavior and are used consistently in Security.vue. No changes needed.

src/types/supabase.types.ts (1)

1344-1399: Supabase type updates for encrypted bundles and org security are consistent with the migration

  • orgs.Row/Insert/Update correctly include the new enforce_encrypted_bundles boolean, matching the added column.
  • New functions check_org_encrypted_bundle_enforcement and is_bundle_encrypted have argument and return types that align with their SQL definitions.
  • find_apikey_by_value now exposes expires_at, which fits the apikeys.Row shape and supports the is_apikey_expired check in get_orgs_v7().
  • Both get_orgs_v7 overloads now surface enforce_encrypted_bundles and keep the uuid-parameter variant non-public, while the no-arg wrapper remains granted to anon/authenticated/service_role, preserving the intended access-control model from previous org/2FA work.
  • reject_access_due_to_2fa_for_org’s typing matches its usage in the migrations.

No changes needed here.

Also applies to: 2235-2238, 2313-2323, 2601-2665, 2863-2864, 2990-2993

src/pages/settings/organization/Security.vue (1)

671-819: 2FA and password policy UI restructuring preserves behavior and respects permissions

  • The combined 2FA Enforcement section (toggle + status cards + impacted members list) reuses the existing computed counts and impactedMembers list, and is only rendered for super admins (hasOrgPerm) when showing member details.
  • The “all compliant” vs “impacted members” branches are mutually exclusive and correctly keyed off the same derived counts.
  • The new fingerprint icon/header block for the Password Policy section is purely presentational; it doesn’t change the underlying config or save logic.

This keeps the earlier 2FA/password policy behavior intact while improving layout, and continues to expose member-level status only to super admins, which aligns with the security intent from prior org/2FA work.

Also applies to: 867-879

supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (2)

24-92: Helper functions for encryption enforcement are minimal and correctly scoped

  • public.is_bundle_encrypted(session_key text) is IMMUTABLE, uses a simple non-null/non-empty check, and fully qualifies public in the function using SET search_path = '', which is good practice.
  • public.check_org_encrypted_bundle_enforcement(org_id uuid, session_key text) mirrors the same semantics, logs via public.pg_log when enforcement blocks an upload, and returns a boolean “allow/deny” flag as advertised.
  • EXECUTE is granted only to authenticated and service_role, which is appropriate for backend/API usage.

No issues here.


156-335: get_orgs_v7 changes correctly surface encryption flag and maintain access-control pattern

  • The get_orgs_v7(userid uuid) body now includes o.enforce_encrypted_bundles in its projection, alongside existing security fields (2FA and password policy redaction via should_redact_2fa / should_redact_password), which matches the new org column.
  • As per prior guidance, this uuid-parameter overload is revoked from PUBLIC/anon/authenticated and only granted to postgres and service_role, keeping it as a private helper.
  • The public wrapper get_orgs_v7():
    • Resolves identity from API key or session (get_apikey_header, find_apikey_by_value, is_apikey_expired, get_identity).
    • Honors limited_to_orgs when present.
    • Delegates to get_orgs_v7(user_id) and exposes the new enforce_encrypted_bundles field in its return type.
    • Is granted to anon, authenticated, and service_role, which matches the existing pattern for org listings.

Overall this keeps the org listing API consistent with the new encrypted-bundles setting and maintains the intended separation between the internal and public variants of get_orgs_v7.

Also applies to: 340-423

tests/enforce-encrypted-bundles.test.ts (7)

1-9: LGTM!

Good use of randomUUID for test data isolation, preventing conflicts between parallel test runs. Imports follow coding guidelines (no semicolons, single quotes).


10-57: LGTM!

Setup correctly handles the dependency order: stripe_info → orgs → org_users → apps. Error handling with throws ensures test failures are visible if setup fails.


108-158: LGTM!

Tests correctly verify that both encrypted and unencrypted bundles are allowed when enforcement is disabled. The external GitHub URL could cause occasional flakiness but is acceptable for integration tests.


160-233: LGTM!

Excellent coverage of enforcement scenarios including the edge case of empty session_key vs null. The nested beforeAll/afterAll properly isolates the enforcement state for this test group.


235-321: LGTM!

Critical tests validating the database-level enforcement trigger. This ensures defense-in-depth by testing that enforcement works even when bypassing the API layer.


323-410: LGTM!

Thorough coverage of the helper RPC functions. The null as unknown as string casts are necessary workarounds for the TypeScript types expecting non-null strings while testing null behavior.


412-428: LGTM!

Test correctly validates that get_orgs_v7 includes the new enforce_encrypted_bundles field. The assertions verify both presence and type, which is sufficient for this integration test.

supabase/functions/_backend/utils/supabase.types.ts (6)

1343-1400: LGTM!

The enforce_encrypted_bundles field is correctly typed: non-nullable in Row (DB has default), optional in Insert and Update. This aligns with the database migration that sets DEFAULT false.


2235-2238: LGTM!

New RPC function type check_org_encrypted_bundle_enforcement correctly defined with required parameters and boolean return type.


2863-2863: LGTM!

is_bundle_encrypted function type correctly added with session_key string parameter and boolean return.


2990-2993: LGTM!

reject_access_due_to_2fa_for_org function type added. This appears to be a related security function for 2FA enforcement at the org level.


2600-2664: LGTM with a note on type change.

enforce_encrypted_bundles: boolean correctly added to both get_orgs_v7 overloads.

Note: max_apikey_expiration_days changed from number | null to number. This suggests the view now coalesces null values. Verify this is intentional and that frontend consumers handle this correctly.


37-86: LGTM!

expires_at field correctly added to apikeys table types. The nullable type allows for keys without expiration.

Comment thread tests/build_time_tracking.test.ts Outdated
Comment on lines 1 to 3
import { randomUUID } from 'node:crypto'
import { afterAll, beforeEach, describe, expect, it } from 'vitest'
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'
import { BASE_URL, fetchWithRetry, getSupabaseClient, ORG_ID, PRODUCT_ID, resetAndSeedAppDataStats, resetAppData, resetAppDataStats, STRIPE_INFO_CUSTOMER_ID, TEST_EMAIL, USER_ID } from './test-utils.ts'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused TEST_EMAIL import to fix TS6133

TEST_EMAIL is imported but never used, which matches the vue-tsc error and breaks bun typecheck.

You can safely drop it from the import list:

Proposed fix
-import { BASE_URL, fetchWithRetry, getSupabaseClient, ORG_ID, PRODUCT_ID, resetAndSeedAppDataStats, resetAppData, resetAppDataStats, STRIPE_INFO_CUSTOMER_ID, TEST_EMAIL, USER_ID } from './test-utils.ts'
+import { BASE_URL, fetchWithRetry, getSupabaseClient, ORG_ID, PRODUCT_ID, resetAndSeedAppDataStats, resetAppData, resetAppDataStats, STRIPE_INFO_CUSTOMER_ID, USER_ID } from './test-utils.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
import { randomUUID } from 'node:crypto'
import { afterAll, beforeEach, describe, expect, it } from 'vitest'
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'
import { BASE_URL, fetchWithRetry, getSupabaseClient, ORG_ID, PRODUCT_ID, resetAndSeedAppDataStats, resetAppData, resetAppDataStats, STRIPE_INFO_CUSTOMER_ID, TEST_EMAIL, USER_ID } from './test-utils.ts'
import { randomUUID } from 'node:crypto'
import { afterAll, beforeAll, beforeEach, describe, expect, it } from 'vitest'
import { BASE_URL, fetchWithRetry, getSupabaseClient, ORG_ID, PRODUCT_ID, resetAndSeedAppDataStats, resetAppData, resetAppDataStats, STRIPE_INFO_CUSTOMER_ID, USER_ID } from './test-utils.ts'
🧰 Tools
🪛 GitHub Actions: Run tests

[error] 3-3: TS6133: 'TEST_EMAIL' is declared but its value is never read. (from vue-tsc --noEmit during bun typecheck)

🤖 Prompt for AI Agents
In tests/build_time_tracking.test.ts around lines 1 to 3, the imported symbol
TEST_EMAIL is never used which triggers TS6133 and breaks bun typecheck; remove
TEST_EMAIL from the named import list in the import statement (keep all other
imports intact) so the file only imports the symbols actually used.

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (1)
tests/build_time_tracking.test.ts (1)

135-141: Consider a batch delete for daily_build_time cleanup.

The loop-based cleanup works but could be simplified with a single query using a subquery or JOIN to delete all daily_build_time records for apps in the org.

🔎 Optional optimization
-  // Clear daily_build_time for all apps in this org
-  const { data: orgApps } = await supabase.from('apps').select('app_id').eq('owner_org', ORG_ID)
-  if (orgApps) {
-    for (const app of orgApps) {
-      await supabase.from('daily_build_time').delete().eq('app_id', app.app_id)
-    }
-  }
+  // Clear daily_build_time for all apps in this org
+  const { data: orgApps } = await supabase.from('apps').select('app_id').eq('owner_org', ORG_ID)
+  if (orgApps && orgApps.length > 0) {
+    const appIds = orgApps.map(app => app.app_id)
+    await supabase.from('daily_build_time').delete().in('app_id', appIds)
+  }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1715310 and 454d5c0.

📒 Files selected for processing (2)
  • tests/build_time_tracking.test.ts
  • tests/test-utils.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • tests/test-utils.ts
  • tests/build_time_tracking.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • tests/test-utils.ts
  • tests/build_time_tracking.test.ts
tests/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend tests must use helpers from tests/test-utils.ts including getEndpointUrl(path) for correct worker routing and USE_CLOUDFLARE_WORKERS=true for CF Workers testing

Files:

  • tests/test-utils.ts
  • tests/build_time_tracking.test.ts
**/{migrations,tests,__tests__}/**/*.{sql,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Files:

  • tests/test-utils.ts
  • tests/build_time_tracking.test.ts
tests/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Backend tests should be located in the tests/ directory and use Vitest test runner

Files:

  • tests/build_time_tracking.test.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to {capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}} : Mobile apps should use Capacitor with app ID `ee.forgr.capacitor_go` for native mobile functionality

Applied to files:

  • tests/test-utils.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to playwright/e2e/**/*.{ts,js} : Cover customer-facing flows with Playwright MCP suite; add scenarios under `playwright/e2e` and run them locally with `bun run test:front` before shipping UI changes

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Backend tests modify local database; always reset database with `supabase db reset` before running tests to ensure clean state

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Backend tests that modify local database state require a running Supabase instance

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to tests/**/*.{ts,js} : Backend tests must use helpers from `tests/test-utils.ts` including `getEndpointUrl(path)` for correct worker routing and `USE_CLOUDFLARE_WORKERS=true` for CF Workers testing

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to tests/**/*.{test,spec}.{ts,tsx} : Backend tests should be located in the `tests/` directory and use Vitest test runner

Applied to files:

  • tests/build_time_tracking.test.ts
🧬 Code graph analysis (1)
tests/build_time_tracking.test.ts (1)
tests/test-utils.ts (7)
  • ORG_ID (42-42)
  • BUILD_TIME_ORG_ID (54-54)
  • BUILD_TIME_STRIPE_CUSTOMER_ID (55-55)
  • getSupabaseClient (362-381)
  • PRODUCT_ID (58-58)
  • USER_ID (45-45)
  • TEST_EMAIL (57-57)
⏰ 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). (1)
  • GitHub Check: Run tests
🔇 Additional comments (6)
tests/test-utils.ts (1)

53-55: LGTM! Clear test isolation constants.

The dedicated build-time test identifiers are well-documented and follow the established naming pattern. This approach prevents test interference and improves test reliability.

tests/build_time_tracking.test.ts (5)

3-3: Past review concern is now resolved.

The previous review flagged TEST_EMAIL as unused, but it's now used on line 50 for the management_email field. The import is valid and necessary.


5-7: LGTM! Dedicated test constants improve isolation.

Using BUILD_TIME_ORG_ID and BUILD_TIME_STRIPE_CUSTOMER_ID prevents interference with other test suites and makes the test intent clear.


16-75: LGTM! Comprehensive test bootstrap with proper guards.

The beforeAll setup correctly:

  • Creates dedicated stripe_info with appropriate subscription data
  • Establishes a dedicated org for build-time tests
  • Uses check-before-insert pattern (lines 57-74) to prevent duplicate key errors when tests run multiple times

The idempotent approach with upsert and conditional inserts ensures tests can run reliably in any state.


77-148: LGTM! Thorough beforeEach ensures test isolation.

The comprehensive reset strategy guarantees each test starts with a clean, predictable state:

  • Resets stripe_info to baseline (trial expired, limits not exceeded)
  • Creates app and app_version for proper onboarding state
  • Clears all dependent data (build_logs, app_metrics_cache, daily_build_time, credit tables)

This defensive approach prevents flaky tests from residual state.


150-163: LGTM! Complete afterAll cleanup prevents test pollution.

The comprehensive teardown removes all test artifacts in the correct dependency order, ensuring no orphaned data remains after the test suite completes.

@riderx riderx force-pushed the riderx/enforce-encrypted-keys branch from daabdc9 to 2017d02 Compare January 4, 2026 15:33
Copy link
Copy Markdown
Contributor

@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

Caution

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

⚠️ Outside diff range comments (1)
src/types/supabase.types.ts (1)

2610-2675: Double‑check nullability of max_apikey_expiration_days in get_orgs_v7 return type

In both overloads of get_orgs_v7, the return surface types model max_apikey_expiration_days as number, but the underlying source column orgs.max_apikey_expiration_days is nullable and the SQL SELECT in the migration passes it through without a COALESCE. If the column can still be NULL at runtime, callers may see null even though the type is number.

Either:

  • guarantee non‑null in SQL (e.g. via COALESCE(...) and a NOT NULL invariant), or
  • relax the TS return type for max_apikey_expiration_days here to number | null.
♻️ Duplicate comments (1)
tests/build_time_tracking.test.ts (1)

1-9: LGTM! Test isolation with unique IDs.

The test setup uses randomUUID() to generate unique identifiers per test run, ensuring proper isolation when tests run in parallel. The TEST_EMAIL import is correctly used on line 49 for the org's management email.

Note: The previous review flagged TEST_EMAIL as unused, but it is actually used on line 49 (management_email: TEST_EMAIL).

🧹 Nitpick comments (12)
messages/tr.json (1)

771-774: Keys are not in alphabetical order.

The new translation keys should be sorted alphabetically. Currently they appear after hashed-api-keys-enforcement-enabled, but alphabetically they should come before it:

Expected order:

  1. encrypted-bundles-enforcement-disabled
  2. encrypted-bundles-enforcement-enabled
  3. enforce-encrypted-bundles
  4. enforce-encrypted-bundles-description
  5. hashed-api-keys-enforcement-enabled (line 770)
🔎 Proposed fix to reorder keys alphabetically
  "hashed-api-keys-enforcement-disabled": "Güvenli API anahtarları zorunluluğu devre dışı bırakıldı.",
  "hashed-api-keys-enforcement-enabled": "Güvenli API anahtarları zorunluluğu etkinleştirildi.",
- "enforce-encrypted-bundles": "Şifreli Paketleri Zorunlu Kıl",
- "enforce-encrypted-bundles-description": "Etkinleştirildiğinde, bu kuruluşa yüklenen tüm paketler şifreli olmalıdır. Şifreleme olmadan paketler (session_key olmadan) reddedilecektir.",
- "encrypted-bundles-enforcement-enabled": "Şifreli paket gereksinimi etkinleştirildi.",
- "encrypted-bundles-enforcement-disabled": "Şifreli paket gereksinimi devre dışı bırakıldı.",
  "header-event-desc": "Olay türü (örn. app_versions.INSERT)",

Move these keys to before hashed-api-keys-enforcement-disabled:

  "good": "İyi",
+ "encrypted-bundles-enforcement-disabled": "Şifreli paket gereksinimi devre dışı bırakıldı.",
+ "encrypted-bundles-enforcement-enabled": "Şifreli paket gereksinimi etkinleştirildi.",
+ "enforce-encrypted-bundles": "Şifreli Paketleri Zorunlu Kıl",
+ "enforce-encrypted-bundles-description": "Etkinleştirildiğinde, bu kuruluşa yüklenen tüm paketler şifreli olmalıdır. Şifreleme olmadan paketler (session_key olmadan) reddedilecektir.",
  "hashed-api-keys-enforcement-disabled": "Güvenli API anahtarları zorunluluğu devre dışı bırakıldı.",
messages/fr.json (1)

771-774: Consider aligning terminology with the hashed-api-keys pattern for consistency.

The encrypted bundles enforcement messages use "L'exigence de bundles chiffrés" (the requirement for encrypted bundles), while the similar hashed-api-keys feature uses "L'application des clés API sécurisées" (the enforcement of secure API keys). Since both are security enforcement toggles in the same settings section, using consistent terminology would improve UX coherence.

🔎 Proposed harmonization
-  "encrypted-bundles-enforcement-enabled": "L'exigence de bundles chiffrés a été activée.",
-  "encrypted-bundles-enforcement-disabled": "L'exigence de bundles chiffrés a été désactivée.",
+  "encrypted-bundles-enforcement-enabled": "L'application des bundles chiffrés a été activée.",
+  "encrypted-bundles-enforcement-disabled": "L'application des bundles chiffrés a été désactivée.",
messages/id.json (1)

771-774: Encrypted-bundles strings look correct; consider aligning terminology with existing “bundle” wording

The new keys correctly describe enforcing encryption and rejecting uploads missing session_key, and they sit consistently next to the hashed‑API‑keys enforcement strings.

If you want to keep the Indonesian locale fully consistent, you might consider replacing the English “Bundle/bundle” here with the same “bundel”/“Paket” wording used in nearby bundle‑related strings (e.g. bundle, bundles, bundle-not-found). Not required for functionality, just a translation polish.

messages/de.json (1)

771-774: German encrypted‑bundles strings look good; only a tiny terminology nit

The four new keys are semantically correct and align well with the existing 2FA/password/API‑key enforcement phrasing. If you ever clean up terminology, you might consider standardizing on either “Bündel”/“Pakete” or “Bundle(s)” throughout this locale, but it’s not blocking.

messages/es.json (1)

771-774: Spanish: align terminology with existing “paquete(s)” instead of “bundle(s)”

The meaning is correct, but these four strings currently mix English “bundle(s)” into otherwise Spanish copy, while the rest of the locale uses “paquete/paquetes” for bundles. For consistency and readability, consider something like:

  • "enforce-encrypted-bundles""Exigir paquetes cifrados"
  • "enforce-encrypted-bundles-description""Cuando está habilitado, todos los paquetes subidos a esta organización deben estar cifrados. Los paquetes sin cifrado (sin session_key) serán rechazados."
  • "encrypted-bundles-enforcement-enabled""Se ha activado el requisito de paquetes cifrados."
  • "encrypted-bundles-enforcement-disabled""Se ha desactivado el requisito de paquetes cifrados."
messages/pl.json (1)

771-774: Polish encrypted‑bundles strings are clear and consistent

The new Polish texts correctly describe the enforcement behavior and match existing “encrypted bundle” terminology. If you want perfect parallelism with hashed-api-keys-enforcement-*, you could optionally switch to “Wymuszanie zaszyfrowanych pakietów …”, but the current wording is entirely fine.

messages/zh-cn.json (1)

771-774: Align encrypted-bundles wording with existing bundle/enforcement terminology

Elsewhere this locale uses “捆绑包” for bundle and “强制执行” for enforcement (e.g. hashed API keys). These four strings switch to “包” and “加密包要求”, which is slightly inconsistent and may read less clearly in the security UI.

Consider updating to reuse the same wording:

Proposed zh-CN diff for consistency
-  "enforce-encrypted-bundles": "强制加密包",
-  "enforce-encrypted-bundles-description": "启用后,上传到此组织的所有包必须加密。未加密的包(没有session_key)将被拒绝。",
-  "encrypted-bundles-enforcement-enabled": "加密包要求已启用。",
-  "encrypted-bundles-enforcement-disabled": "加密包要求已禁用。",
+  "enforce-encrypted-bundles": "强制加密捆绑包",
+  "enforce-encrypted-bundles-description": "启用后,上传到此组织的所有捆绑包必须加密。未加密的捆绑包(没有 session_key)将被拒绝。",
+  "encrypted-bundles-enforcement-enabled": "已启用加密捆绑包强制执行。",
+  "encrypted-bundles-enforcement-disabled": "已禁用加密捆绑包强制执行。",
messages/ru.json (1)

771-774: Use the same “пакет/пакеты” terminology as other bundle strings

Most Russian strings translate “bundle” as “пакет/пакеты”, while these four use “бандлы/бандлов”, which is inconsistent and may feel less polished.

Switching to “пакеты” will align with the rest of the UI:

Proposed ru diff for terminology
-  "enforce-encrypted-bundles": "Требовать зашифрованные бандлы",
-  "enforce-encrypted-bundles-description": "При включении все бандлы, загруженные в эту организацию, должны быть зашифрованы. Бандлы без шифрования (без session_key) будут отклонены.",
-  "encrypted-bundles-enforcement-enabled": "Требование зашифрованных бандлов было включено.",
-  "encrypted-bundles-enforcement-disabled": "Требование зашифрованных бандлов было отключено.",
+  "enforce-encrypted-bundles": "Требовать зашифрованные пакеты",
+  "enforce-encrypted-bundles-description": "При включении все пакеты, загруженные в эту организацию, должны быть зашифрованы. Пакеты без шифрования (без session_key) будут отклонены.",
+  "encrypted-bundles-enforcement-enabled": "Требование зашифрованных пакетов было включено.",
+  "encrypted-bundles-enforcement-disabled": "Требование зашифрованных пакетов было отключено.",
messages/pt-br.json (1)

771-774: Localize “bundle” to “pacote” to match existing pt-BR strings

This locale consistently uses “pacote/pacotes” for bundles; these four strings keep “Bundles/bundles” in English, which breaks that convention.

Using “pacotes criptografados” will align with the rest of the UI:

Proposed pt-BR diff for vocabulary
-  "enforce-encrypted-bundles": "Exigir Bundles Criptografados",
-  "enforce-encrypted-bundles-description": "Quando ativado, todos os bundles enviados para esta organização devem ser criptografados. Bundles sem criptografia (sem session_key) serão rejeitados.",
-  "encrypted-bundles-enforcement-enabled": "O requisito de bundles criptografados foi ativado.",
-  "encrypted-bundles-enforcement-disabled": "O requisito de bundles criptografados foi desativado.",
+  "enforce-encrypted-bundles": "Exigir Pacotes Criptografados",
+  "enforce-encrypted-bundles-description": "Quando ativado, todos os pacotes enviados para esta organização devem ser criptografados. Pacotes sem criptografia (sem session_key) serão rejeitados.",
+  "encrypted-bundles-enforcement-enabled": "O requisito de pacotes criptografados foi ativado.",
+  "encrypted-bundles-enforcement-disabled": "O requisito de pacotes criptografados foi desativado.",
messages/it.json (1)

771-774: Use “pacchetto/pacchetti” instead of “bundle” for consistency

Most Italian strings translate “bundle” as “pacchetto/pacchetti”; these four introduce “Bundle/bundle”, which is inconsistent with existing security/messaging text.

Aligning to “pacchetti crittografati” keeps terminology uniform:

Proposed it diff for consistency
-  "enforce-encrypted-bundles": "Richiedi Bundle Crittografati",
-  "enforce-encrypted-bundles-description": "Quando abilitato, tutti i bundle caricati in questa organizzazione devono essere crittografati. I bundle senza crittografia (senza session_key) verranno rifiutati.",
-  "encrypted-bundles-enforcement-enabled": "Il requisito dei bundle crittografati è stato abilitato.",
-  "encrypted-bundles-enforcement-disabled": "Il requisito dei bundle crittografati è stato disabilitato.",
+  "enforce-encrypted-bundles": "Richiedi Pacchetti Crittografati",
+  "enforce-encrypted-bundles-description": "Quando abilitato, tutti i pacchetti caricati in questa organizzazione devono essere crittografati. I pacchetti senza crittografia (senza session_key) verranno rifiutati.",
+  "encrypted-bundles-enforcement-enabled": "Il requisito dei pacchetti crittografati è stato abilitato.",
+  "encrypted-bundles-enforcement-disabled": "Il requisito dei pacchetti crittografati è stato disabilitato.",
messages/vi.json (1)

771-774: Consider adding the complete set of encrypted bundles translation keys.

The Vietnamese locale adds only the basic 4 keys, but messages/en.json includes additional keys like encrypted-bundles-enforcement-enabled-with-deletion, required-encryption-key, required-encryption-key-description, change-encryption-key-warning-title, etc. (lines 805-824 in en.json). If these are intentionally omitted for phased localization, this is fine—otherwise, consider adding them to maintain parity.

supabase/functions/_backend/utils/supabase.types.ts (1)

1338-1397: Keep backend Supabase types in lockstep with the schema and frontend types

The additions for enforce_encrypted_bundles, required_encryption_key, and the new helper functions are consistent with the migration and match the shapes used on the frontend.

If you adjust the get_orgs_v7 return type for max_apikey_expiration_days (nullable vs non‑null) as suggested in the frontend types, make the same change here to avoid subtle divergence between client and backend views of the same function.

Also applies to: 2232-2235, 2281-2287, 2313-2316, 2610-2675, 2874-2875

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4d4cc6 and 8f69819.

📒 Files selected for processing (22)
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/hi.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/pl.json
  • messages/pt-br.json
  • messages/ru.json
  • messages/tr.json
  • messages/vi.json
  • messages/zh-cn.json
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • tests/build_time_tracking.test.ts
  • tests/enforce-encrypted-bundles.test.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • src/pages/settings/organization/Security.vue
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
tests/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Backend tests should be located in the tests/ directory and use Vitest test runner

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
tests/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend tests must use helpers from tests/test-utils.ts including getEndpointUrl(path) for correct worker routing and USE_CLOUDFLARE_WORKERS=true for CF Workers testing

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/{migrations,tests,__tests__}/**/*.{sql,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
src/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.vue: Use Vue 3 with Composition API and <script setup> syntax for frontend components
Style components using TailwindCSS with DaisyUI components

src/**/*.vue: Use Vue 3 <script setup> syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn, d-input, d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
Use useRoute() from vue-router to access route parameters and useRouter() for programmatic navigation in Vue components

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/pages/settings/organization/Security.vue
src/pages/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

Use file-based routing with unplugin-vue-router for frontend pages

Frontend file-based routing uses src/pages/ directory structure; routes auto-generate with unplugin-vue-router and types are available in src/typed-router.d.ts

Files:

  • src/pages/settings/organization/Security.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}

📄 CodeRabbit inference engine (CLAUDE.md)

Mobile apps should use Capacitor with app ID ee.forgr.capacitor_go for native mobile functionality

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use ~/ alias for imports from src/ directory in frontend TypeScript and Vue components

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend ESLint must pass before commit; run bun lint:fix to auto-fix issues in frontend files

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for the safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{css,scss,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo design palette from src/styles/style.css (e.g., --color-primary-500: #515271, --color-azure-500: #119eff) when introducing new UI, using deep slate bases with the Extract azure highlight and soft radii

Files:

  • src/pages/settings/organization/Security.vue
supabase/functions/_backend/**

📄 CodeRabbit inference engine (CLAUDE.md)

Backend logic should be organized in supabase/functions/_backend/ with subdirectories for plugins, private endpoints, public endpoints, triggers, and utilities

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Supabase Edge Functions use Deno runtime

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/_backend/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/functions/_backend/**/*.{ts,js}: Backend code must be placed in supabase/functions/_backend/ as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
Use createHono from utils/hono.ts for all Hono framework application initialization and routing
All database operations must use getPgClient() or getDrizzleClient() from utils/pg.ts for PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must accept Context<MiddlewareKeyVariables> and use c.get('requestId'), c.get('apikey'), and c.get('auth') for request context
Use structured logging with cloudlog({ requestId: c.get('requestId'), message: '...' }) for all backend logging
Use middlewareAPISecret for internal API endpoints and middlewareKey for external API keys; validate against owner_org in the apikeys table
Check c.get('auth')?.authType to determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns with schema from postgress_schema.ts for all database operations; use aliasV2() for self-joins or multiple table references

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend ESLint must pass before commit; run bun lint:backend for backend files

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/migrations/**/*.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Database migrations must be created with supabase migration new <feature_slug> and never modify previously committed migrations

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/migrations/*.sql

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/*.sql: When creating schema changes, use supabase migration new <feature_slug> to create a single migration file and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, treating seeding as part of the current feature and not modifying previously committed migrations
Do not create new cron jobs; instead update the process_all_cron_tasks function in a new migration file to add your job if needed

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧠 Learnings (16)
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to playwright/e2e/**/*.{ts,js} : Cover customer-facing flows with Playwright MCP suite; add scenarios under `playwright/e2e` and run them locally with `bun run test:front` before shipping UI changes

Applied to files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to **/{migrations,tests,__tests__}/**/*.{sql,ts,js} : Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Backend tests modify local database; always reset database with `supabase db reset` before running tests to ensure clean state

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to tests/**/*.{ts,js} : Backend tests must use helpers from `tests/test-utils.ts` including `getEndpointUrl(path)` for correct worker routing and `USE_CLOUDFLARE_WORKERS=true` for CF Workers testing

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Backend tests that modify local database state require a running Supabase instance

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to tests/**/*.{test,spec}.{ts,tsx} : Backend tests should be located in the `tests/` directory and use Vitest test runner

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-25T11:22:19.594Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table

Applied to files:

  • src/pages/settings/organization/Security.vue
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Check `c.get('auth')?.authType` to determine authentication type ('apikey' vs 'jwt') in backend endpoints

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `createHono` from `utils/hono.ts` for all Hono framework application initialization and routing

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : All Hono endpoint handlers must accept `Context<MiddlewareKeyVariables>` and use `c.get('requestId')`, `c.get('apikey')`, and `c.get('auth')` for request context

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to supabase/functions/**/*.ts : Supabase Edge Functions use Deno runtime

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-24T14:11:10.256Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:409-539
Timestamp: 2025-12-24T14:11:10.256Z
Learning: In supabase/migrations for get_orgs_v6 and get_orgs_v7: The inner functions with user_id parameter (get_orgs_v6(uuid) and get_orgs_v7(uuid)) should NOT be granted to anon/authenticated roles as this allows any user to query other users' organizations; only the no-argument wrapper functions should be public as they perform authentication checks.

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
📚 Learning: 2025-12-25T11:22:13.039Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:13.039Z
Learning: In SQL migrations under the repository (e.g., supabase/migrations), enforce that when an org has enforcing_2fa=true, all users (including super_admins) must have 2FA enabled before accessing any org functions, including check_org_members_2fa_enabled. Do not grant admin exceptions to 2FA requirements. This ensures consistent security enforcement across all org-related operations; implement this rule within relevant migrations and associated stored procedures/tests.

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧬 Code graph analysis (4)
tests/enforce-encrypted-bundles.test.ts (1)
tests/test-utils.ts (4)
  • getSupabaseClient (359-378)
  • TEST_EMAIL (54-54)
  • USER_ID (45-45)
  • BASE_URL (19-19)
supabase/functions/_backend/public/bundle/create.ts (1)
supabase/functions/_backend/utils/hono.ts (1)
  • simpleError (247-249)
supabase/functions/_backend/utils/supabase.types.ts (1)
src/types/supabase.types.ts (1)
  • Json (1-7)
src/types/supabase.types.ts (1)
supabase/functions/_backend/utils/supabase.types.ts (1)
  • Json (1-7)
🪛 GitHub Actions: Run tests
supabase/functions/_backend/public/bundle/create.ts

[error] 200-200: ESLint: Unexpected string concatenation. Prefer-template (prefer-template)

🔇 Additional comments (18)
messages/hi.json (1)

771-774: Hindi encrypted-bundles translations are consistent and accurate

The four new strings clearly express enforcement, required encryption, and the enabled/disabled status, and they follow the same pattern and tone as the existing hashed‑API‑keys enforcement messages. No changes needed.

messages/ko.json (1)

771-774: Korean encrypted-bundles strings match existing security wording

The label, description, and enabled/disabled status messages are natural Korean, accurately describe the requirement (including session_key), and mirror the existing hashed‑API‑keys enforcement phrasing. Looks good as is.

messages/ja.json (1)

771-774: Japanese encrypted-bundles translations are clear and aligned with the feature

The new Japanese strings correctly communicate enforcing encrypted bundles, including rejection of uploads lacking session_key, and follow the same style as nearby enforcement texts. No adjustments needed.

tests/enforce-encrypted-bundles.test.ts (6)

10-66: LGTM! Test setup and teardown are well-structured.

The test uses proper isolation with unique IDs per run, creates all required entities (stripe_info, org, org_user, app), and cleans up in the correct reverse dependency order. This follows the backend testing guidelines.


69-106: LGTM!

The org setting management tests correctly verify the default value and update behavior.


108-158: LGTM!

Baseline tests correctly verify that both encrypted and unencrypted bundles are allowed when enforcement is disabled.


160-233: LGTM!

Encryption enforcement tests cover the critical scenarios: rejection of unencrypted bundles, rejection of empty session_key, and acceptance of encrypted bundles. The scoped beforeAll/afterAll pattern is appropriate.


235-321: LGTM!

Database trigger enforcement tests provide good coverage for defense-in-depth validation, verifying that enforcement works at the database level independent of the API layer.


323-428: LGTM!

Helper function tests provide comprehensive coverage for is_bundle_encrypted and check_org_encrypted_bundle_enforcement RPCs. The get_orgs_v7 test correctly verifies the new field is included.

supabase/functions/_backend/public/bundle/create.ts (3)

132-138: LGTM!

The AppWithOrg interface properly models the joined query result with enforcement-related fields from the orgs table.


140-153: LGTM!

Using supabaseAdmin is appropriate here to bypass RLS for security enforcement checks. The join query efficiently retrieves app and org data in a single call.


256-263: LGTM!

The enforcement check is correctly integrated into the bundle creation flow after URL validation and before inserting the bundle. The appWithOrg.owner_org is properly used for the bundle insertion.

tests/build_time_tracking.test.ts (2)

15-162: LGTM! Comprehensive test setup and teardown.

The test setup creates a dedicated org and stripe_info for build time tests, with proper beforeEach reset logic and afterAll cleanup. The use of upsert with appropriate conflict keys ensures idempotent setup.


164-388: LGTM!

Build time tracking tests cover essential scenarios: excessive build time handling, flag reset, platform multipliers (iOS 2x, Android 1x), upsert behavior, and input validation. Tests properly use the per-run identifiers for isolation.

messages/en.json (1)

801-824: LGTM!

The English translation keys for the encrypted bundles feature are comprehensive, covering all UI states: enforcement toggles, warnings, required key management, and bundle deletion scenarios. The keys use proper placeholder syntax (e.g., {count}) for dynamic content.

src/types/supabase.types.ts (1)

1338-1397: Encryption enforcement fields and helper RPCs are wired correctly into Supabase types

orgs Row/Insert/Update now expose enforce_encrypted_bundles and required_encryption_key, and the new functions (check_org_encrypted_bundle_enforcement, count_non_compliant_bundles, delete_non_compliant_bundles, is_bundle_encrypted) have argument/return shapes that match the SQL definitions in the migration. This should give both frontend and backend code the right type coverage for the new enforcement flow.

Also applies to: 2232-2235, 2281-2287, 2313-2316, 2874-2875

src/pages/settings/organization/Security.vue (1)

53-57: Org encryption state is loaded and bound cleanly

Fetching enforce_encrypted_bundles and required_encryption_key from orgs and wiring them into enforceEncryptedBundles / requiredEncryptionKey keeps the UI state in sync with the canonical org record. This integrates well with the rest of the existing security settings loading.

Also applies to: 158-182

supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)

108-147: DB trigger enforcement correctly derives org_id and closes the earlier ordering hole

The new check_encrypted_bundle_on_insert trigger:

  • Uses NEW.owner_org when present, otherwise looks up apps.owner_org by NEW.app_id, and
  • Enforces both “must be encrypted” and “must match required key fingerprint” with clear audit logs and specific error codes.

This avoids the previous issue where relying solely on NEW.owner_org could be bypassed because the auto‑owner trigger ran later, and ensures enforcement even for inserts that omit owner_org. The logging payloads also look suitably detailed for debugging.

Also applies to: 149-198, 206-213

Comment thread src/pages/settings/organization/Security.vue Outdated
Comment on lines +500 to +527
async function saveEncryptedBundlesEnforcement(enable: boolean, keyFingerprint: string | null, deleteNonCompliant: boolean = false) {
if (!currentOrganization.value)
return

const previousEnforcement = enforceEncryptedBundles.value
const previousKey = requiredEncryptionKey.value

// Optimistic update
enforceEncryptedBundles.value = enable
requiredEncryptionKey.value = keyFingerprint

isSaving.value = true

try {
// If enabling and we need to delete non-compliant bundles, do that first
if (enable && deleteNonCompliant) {
const { error: deleteError } = await supabase.rpc('delete_non_compliant_bundles', {
org_id: currentOrganization.value.gid,
required_key: keyFingerprint || undefined,
})

if (deleteError) {
console.error('Failed to delete non-compliant bundles:', deleteError)
enforceEncryptedBundles.value = previousEnforcement
requiredEncryptionKey.value = previousKey
toast.error(t('error-deleting-non-compliant-bundles'))
return
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

delete_non_compliant_bundles cannot be safely invoked directly from the frontend

saveEncryptedBundlesEnforcement and updateRequiredEncryptionKey call:

  • supabase.rpc('delete_non_compliant_bundles', { org_id, required_key })

but in the migration this function is:

  • SECURITY DEFINER with GRANT EXECUTE ... TO "service_role" only.

With a browser Supabase client configured with the anon key, these calls will hit permission errors and the destructive delete path will never succeed. Granting this function to anon would also be unsafe because it bypasses RLS and takes an arbitrary org_id, enabling cross‑tenant deletion if misused.

To keep the model safe and functional:

  • Move the deletion operation behind a backend endpoint (Supabase Edge Function / Cloudflare Worker) that runs as service_role and enforces that the caller is a super_admin of the target org before invoking delete_non_compliant_bundles, and
  • Have the Vue component call that backend endpoint instead of the SQL RPC directly.

Also applies to: 573-626

🤖 Prompt for AI Agents
In src/pages/settings/organization/Security.vue around lines 500-527 (and
similarly at 573-626), the frontend is calling
supabase.rpc('delete_non_compliant_bundles', ...) which will fail or be unsafe
because that RPC is SECURITY DEFINER and only granted to the service_role; do
not call it from the browser. Create a backend endpoint (Supabase Edge Function
or Cloudflare Worker) that runs with the service_role key, validates the caller
is a super_admin of the target org (using server-side checks), and then invokes
delete_non_compliant_bundles; update the Vue component to call this backend
endpoint instead of supabase.rpc, remove any direct service_role usage from
client code, and surface errors/toasts based on the backend response.

Comment thread supabase/functions/_backend/public/bundle/create.ts
Comment thread supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
@riderx riderx force-pushed the riderx/enforce-encrypted-keys branch from 988fd31 to 9154ac3 Compare January 4, 2026 17:55
Copy link
Copy Markdown
Contributor

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

♻️ Duplicate comments (3)
src/pages/settings/organization/Security.vue (2)

432-447: Treat failures in countNonCompliantBundles as blocking, not "zero non‑compliant"

countNonCompliantBundles returns null on RPC error, but callers at lines 465-497 and 591-621 treat counts === null as "no non-compliant bundles" and proceed without showing the warning or attempting deletion. This means transient errors or permission issues on the counting RPC silently bypass the intended UX safeguards.

Consider returning an explicit error indicator and aborting the operation with a toast when counting fails, instead of assuming zero non-compliant bundles.


500-527: delete_non_compliant_bundles cannot be safely invoked directly from the frontend

saveEncryptedBundlesEnforcement calls supabase.rpc('delete_non_compliant_bundles', ...) but this function is SECURITY DEFINER with GRANT EXECUTE ... TO "service_role" only. With a browser Supabase client configured with the anon key, these calls will hit permission errors.

Move the deletion operation behind a backend endpoint (Supabase Edge Function / Cloudflare Worker) that runs as service_role and enforces that the caller is a super_admin of the target org before invoking delete_non_compliant_bundles.

supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)

503-550: Tighten access to count_non_compliant_bundles to avoid cross‑tenant data leakage

count_non_compliant_bundles is SECURITY DEFINER and bypasses RLS on app_versions/apps, but it is granted to "authenticated" as well as "service_role". Because it only takes org_id as input and does no membership checks, any authenticated user could call it with arbitrary org_id values and learn non‑compliant bundle counts for other tenants.

To align with the pattern used elsewhere and protect tenant isolation, consider:

  • Restricting this function to service_role only (similar to delete_non_compliant_bundles), and
  • Exposing it via a backend endpoint that validates the caller’s org membership/role before invoking the function on their behalf.

This mirrors an earlier review concern that backend‑only helpers which bypass RLS should not be directly callable from browser clients by generic authenticated users.

Also applies to: 554-623

🧹 Nitpick comments (6)
src/pages/settings/organization/Security.vue (1)

1035-1051: Consider adding pattern validation for the encryption key fingerprint.

The input allows any 21 characters, but if the key fingerprint has a specific format (e.g., base64-like characters), adding a pattern attribute or input validation would prevent user errors. Currently, users could enter invalid characters that would never match actual bundle session keys.

🔎 Optional: Add pattern validation
 <input
   v-model="requiredEncryptionKey"
   type="text"
   maxlength="21"
+  pattern="[A-Za-z0-9+/=]{21}"
   :placeholder="t('required-encryption-key-placeholder')"
   :disabled="isSaving"
   class="flex-1 px-4 py-2 border rounded-lg font-mono text-sm dark:bg-gray-700 dark:border-gray-600 dark:text-white disabled:opacity-50"
 >
messages/es.json (1)

771-774: Encrypted bundles strings are clear; terminology nit is optional

The new Spanish strings correctly convey the enforcement semantics and match the English keys. If you want full consistency with the rest of this file, you could standardize on either “bundles” or “paquetes” in related strings, but this is non‑blocking.

tests/enforce-encrypted-bundles.test.ts (2)

116-127: Prefer getEndpointUrl('/bundle') over interpolating BASE_URL

To stay aligned with the backend test guidelines and ensure correct routing when USE_CLOUDFLARE_WORKERS is toggled, consider replacing ${BASE_URL}/bundle with getEndpointUrl('/bundle') from test-utils in these tests.

As per coding guidelines, backend tests should use the shared helpers from tests/test-utils.ts for endpoint URLs.

Also applies to: 141-151, 178-188, 197-207, 215-225


68-105: End‑to‑end coverage for encrypted bundle enforcement is strong; consider adding count/delete tests

This suite nicely covers:

  • Org flag defaulting and updates.
  • API behavior with enforcement off/on, including empty session_key.
  • Trigger‑level enforcement via direct inserts.
  • Helper RPCs (is_bundle_encrypted, check_org_encrypted_bundle_enforcement) and get_orgs_v7 surfacing enforce_encrypted_bundles.

One follow‑up worth considering is adding tests that exercise the new count_non_compliant_bundles and delete_non_compliant_bundles functions added in the migration (seed a mix of compliant/non‑compliant bundles, assert counts, then deletions). That would fully cover the database‑side cleanup path introduced by this feature.

As per coding guidelines, database changes in migrations should be paired with Postgres‑level tests where practical.

Also applies to: 108-158, 160-233, 235-321, 323-410, 412-427

supabase/functions/_backend/public/bundle/create.ts (1)

132-153: Encryption enforcement flow is correct; consider tightening typing for orgs join

The new flow looks good:

  • You resolve appWithOrg via supabaseAdmin and then run checkEncryptedBundleEnforcement before checking version existence and inserting.
  • checkEncryptedBundleEnforcement matches the SQL trigger semantics for both session_key presence and required_encryption_key/key_id prefix matching, so API‑ and DB‑level enforcement should be consistent.

Two small follow‑ups you might consider:

  1. AppWithOrg is obtained via as unknown as AppWithOrg and assumes orgs!inner(...) yields a single object. To guard against shape changes (e.g., array vs object) and keep type safety, you could derive this type from Database['public']['Tables']['apps']['Row']/orgs and normalize the orgs field (e.g., const org = Array.isArray(app.orgs) ? app.orgs[0] : app.orgs) before using it.
  2. Since the enforcement rules are now duplicated between this helper and check_encrypted_bundle_on_insert in the migration, it’s worth calling out in a comment that both must be updated together if the policy ever changes.

If unsure about the exact shape Supabase returns for orgs!inner(...), please double‑check the current @supabase/supabase-js join behavior and adjust the typing/normalization accordingly.

Also applies to: 169-205, 206-223, 256-264

src/types/supabase.types.ts (1)

2874-2874: Consider clarifying function naming.

The function is_bundle_encrypted takes a session_key parameter, suggesting it validates whether a session key indicates encryption. The name could be more precise (e.g., is_session_key_encrypted or has_encryption_key) to clarify it's checking the key itself rather than a specific bundle entity.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8f69819 and 250c90d.

📒 Files selected for processing (22)
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/hi.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/pl.json
  • messages/pt-br.json
  • messages/ru.json
  • messages/tr.json
  • messages/vi.json
  • messages/zh-cn.json
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • tests/build_time_tracking.test.ts
  • tests/enforce-encrypted-bundles.test.ts
🚧 Files skipped from review as they are similar to previous changes (12)
  • messages/zh-cn.json
  • messages/pl.json
  • messages/de.json
  • messages/vi.json
  • messages/pt-br.json
  • messages/ko.json
  • messages/ru.json
  • messages/it.json
  • messages/id.json
  • messages/fr.json
  • messages/hi.json
  • messages/en.json
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
tests/**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Backend tests should be located in the tests/ directory and use Vitest test runner

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/functions/_backend/public/bundle/create.ts
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
tests/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend tests must use helpers from tests/test-utils.ts including getEndpointUrl(path) for correct worker routing and USE_CLOUDFLARE_WORKERS=true for CF Workers testing

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
**/{migrations,tests,__tests__}/**/*.{sql,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/functions/_backend/**

📄 CodeRabbit inference engine (CLAUDE.md)

Backend logic should be organized in supabase/functions/_backend/ with subdirectories for plugins, private endpoints, public endpoints, triggers, and utilities

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Supabase Edge Functions use Deno runtime

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/_backend/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/functions/_backend/**/*.{ts,js}: Backend code must be placed in supabase/functions/_backend/ as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
Use createHono from utils/hono.ts for all Hono framework application initialization and routing
All database operations must use getPgClient() or getDrizzleClient() from utils/pg.ts for PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must accept Context<MiddlewareKeyVariables> and use c.get('requestId'), c.get('apikey'), and c.get('auth') for request context
Use structured logging with cloudlog({ requestId: c.get('requestId'), message: '...' }) for all backend logging
Use middlewareAPISecret for internal API endpoints and middlewareKey for external API keys; validate against owner_org in the apikeys table
Check c.get('auth')?.authType to determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns with schema from postgress_schema.ts for all database operations; use aliasV2() for self-joins or multiple table references

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend ESLint must pass before commit; run bun lint:backend for backend files

Files:

  • supabase/functions/_backend/public/bundle/create.ts
  • supabase/functions/_backend/utils/supabase.types.ts
src/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.vue: Use Vue 3 with Composition API and <script setup> syntax for frontend components
Style components using TailwindCSS with DaisyUI components

src/**/*.vue: Use Vue 3 <script setup> syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn, d-input, d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
Use useRoute() from vue-router to access route parameters and useRouter() for programmatic navigation in Vue components

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/pages/settings/organization/Security.vue
src/pages/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

Use file-based routing with unplugin-vue-router for frontend pages

Frontend file-based routing uses src/pages/ directory structure; routes auto-generate with unplugin-vue-router and types are available in src/typed-router.d.ts

Files:

  • src/pages/settings/organization/Security.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}

📄 CodeRabbit inference engine (CLAUDE.md)

Mobile apps should use Capacitor with app ID ee.forgr.capacitor_go for native mobile functionality

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use ~/ alias for imports from src/ directory in frontend TypeScript and Vue components

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend ESLint must pass before commit; run bun lint:fix to auto-fix issues in frontend files

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{vue,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for the safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
src/**/*.{css,scss,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo design palette from src/styles/style.css (e.g., --color-primary-500: #515271, --color-azure-500: #119eff) when introducing new UI, using deep slate bases with the Extract azure highlight and soft radii

Files:

  • src/pages/settings/organization/Security.vue
supabase/migrations/**/*.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Database migrations must be created with supabase migration new <feature_slug> and never modify previously committed migrations

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/migrations/*.sql

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/*.sql: When creating schema changes, use supabase migration new <feature_slug> to create a single migration file and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, treating seeding as part of the current feature and not modifying previously committed migrations
Do not create new cron jobs; instead update the process_all_cron_tasks function in a new migration file to add your job if needed

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧠 Learnings (19)
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to playwright/e2e/**/*.{ts,js} : Cover customer-facing flows with Playwright MCP suite; add scenarios under `playwright/e2e` and run them locally with `bun run test:front` before shipping UI changes

Applied to files:

  • tests/enforce-encrypted-bundles.test.ts
  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-27T03:51:23.575Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-27T03:51:23.575Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests; keep fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • tests/build_time_tracking.test.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Backend tests modify local database; always reset database with `supabase db reset` before running tests to ensure clean state

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to tests/**/*.{ts,js} : Backend tests must use helpers from `tests/test-utils.ts` including `getEndpointUrl(path)` for correct worker routing and `USE_CLOUDFLARE_WORKERS=true` for CF Workers testing

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Backend tests that modify local database state require a running Supabase instance

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to tests/**/*.{test,spec}.{ts,tsx} : Backend tests should be located in the `tests/` directory and use Vitest test runner

Applied to files:

  • tests/build_time_tracking.test.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/**/*.{ts,js} : Backend ESLint must pass before commit; run `bun lint:backend` for backend files

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to src/**/*.{vue,ts,js} : Frontend ESLint must pass before commit; run `bun lint:fix` to auto-fix issues in frontend files

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `createHono` from `utils/hono.ts` for all Hono framework application initialization and routing

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : All Hono endpoint handlers must accept `Context<MiddlewareKeyVariables>` and use `c.get('requestId')`, `c.get('apikey')`, and `c.get('auth')` for request context

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-05T17:34:25.556Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-05T17:34:25.556Z
Learning: Applies to supabase/functions/**/*.ts : Supabase Edge Functions use Deno runtime

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
📚 Learning: 2025-12-24T14:11:10.256Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:409-539
Timestamp: 2025-12-24T14:11:10.256Z
Learning: In supabase/migrations for get_orgs_v6 and get_orgs_v7: The inner functions with user_id parameter (get_orgs_v6(uuid) and get_orgs_v7(uuid)) should NOT be granted to anon/authenticated roles as this allows any user to query other users' organizations; only the no-argument wrapper functions should be public as they perform authentication checks.

Applied to files:

  • supabase/functions/_backend/public/bundle/create.ts
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-25T11:22:19.594Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : All database operations must use `getPgClient()` or `getDrizzleClient()` from `utils/pg.ts` for PostgreSQL access during active migration to Cloudflare D1

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Backend code must be placed in `supabase/functions/_backend/` as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-25T11:22:13.039Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:13.039Z
Learning: In SQL migrations under the repository (e.g., supabase/migrations), enforce that when an org has enforcing_2fa=true, all users (including super_admins) must have 2FA enabled before accessing any org functions, including check_org_members_2fa_enabled. Do not grant admin exceptions to 2FA requirements. This ensures consistent security enforcement across all org-related operations; implement this rule within relevant migrations and associated stored procedures/tests.

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Check `c.get('auth')?.authType` to determine authentication type ('apikey' vs 'jwt') in backend endpoints

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🧬 Code graph analysis (4)
tests/enforce-encrypted-bundles.test.ts (1)
tests/test-utils.ts (4)
  • getSupabaseClient (359-378)
  • TEST_EMAIL (54-54)
  • USER_ID (45-45)
  • BASE_URL (19-19)
supabase/functions/_backend/public/bundle/create.ts (1)
supabase/functions/_backend/utils/hono.ts (1)
  • simpleError (247-249)
src/types/supabase.types.ts (1)
supabase/functions/_backend/utils/supabase.types.ts (1)
  • Json (1-7)
supabase/functions/_backend/utils/supabase.types.ts (1)
src/types/supabase.types.ts (1)
  • Json (1-7)
⏰ 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). (1)
  • GitHub Check: Run tests
🔇 Additional comments (12)
messages/ja.json (1)

771-774: LGTM!

The new Japanese translation keys for encrypted bundles enforcement are well-structured and follow the existing naming conventions (matching the pattern of hashed-api-keys-enforcement-* keys). The translations appear accurate.

tests/build_time_tracking.test.ts (3)

1-10: LGTM! Test isolation pattern is well-implemented.

The per-run unique ID pattern using randomUUID() for ORG_ID, STRIPE_CUSTOMER_ID, and APPNAME ensures proper test isolation and avoids conflicts with parallel test runs. The TEST_EMAIL import on line 3 is correctly used on line 49 for the management_email field, so the previous review comment flagging it as unused is now outdated.


15-74: Well-structured test setup with proper isolation.

The beforeAll hook correctly establishes the test context by:

  • Creating dedicated stripe_info with a unique customer ID
  • Creating a dedicated org linked to that customer
  • Ensuring the test user is a super_admin member (with idempotent check-then-insert pattern)

This follows the recommended patterns from the learnings for backend tests.


149-162: Comprehensive cleanup in afterAll.

The cleanup properly removes all test data in the correct order (respecting foreign key constraints):

  1. build_logsdaily_build_timeapp_versionsappsorg_usersorgsstripe_info

This ensures no test data pollution between runs.

messages/tr.json (1)

771-774: LGTM!

The new Turkish translation keys for encrypted bundles enforcement are well-structured and follow the existing naming conventions. The translations appear accurate and consistent with the Japanese locale additions.

tests/enforce-encrypted-bundles.test.ts (1)

5-57: Fixture setup and teardown look solid

Isolated org/app/stripe fixtures with symmetric cleanup in afterAll are well structured and should keep these tests independent from the rest of the suite.

Also applies to: 59-66

supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (2)

121-147: Trigger now robust to owner_org trigger ordering and enforces key checks correctly

Deriving org_id from NEW.owner_org when present or from public.apps via NEW.app_id otherwise neatly avoids the previous ordering issue with force_valid_owner_org_app_versions. The trigger then:

  • Skips enforcement when the org doesn’t enforce encrypted bundles.
  • Rejects missing/empty session_key with a clear error and audit log.
  • Enforces required_encryption_key via a prefix match on key_id consistent with the API helper.

This aligns the database‑level enforcement with the application‑level behavior and closes the SDK‑insert bypass that existed before.

Also applies to: 149-164, 166-198


222-255: get_orgs_v7 changes correctly surface encryption flags and keep inner function private

The updated get_orgs_v7(userid uuid):

  • Extends the return shape with enforce_encrypted_bundles and required_encryption_key.
  • Leaves all the existing 2FA/password‑policy redaction logic intact.
  • Is explicitly revoked from PUBLIC/anon/authenticated and only granted to postgres and service_role.

The wrapper get_orgs_v7() remains SECURITY DEFINER, handles API key vs session identity, and is granted to anon/authenticated/service_role, matching the “inner function + authenticated wrapper” pattern from the earlier 2FA work.

Based on learnings, keeping the userid‑taking variant non‑public avoids users querying other users’ orgs directly.

Also applies to: 319-390, 393-403, 408-493

supabase/functions/_backend/utils/supabase.types.ts (1)

1339-1357: Supabase types are in sync with encrypted bundle enforcement schema

The added enforce_encrypted_bundles / required_encryption_key fields on orgs and the new/extended function typings (is_bundle_encrypted, check_org_encrypted_bundle_enforcement, count_non_compliant_bundles, delete_non_compliant_bundles, get_orgs_v7 extras) all line up with the SQL migration. The tests in tests/enforce-encrypted-bundles.test.ts are using these shapes as expected, so the generated typings look correct.

Also applies to: 1359-1377, 1379-1397, 2232-2235, 2281-2287, 2314-2316, 2610-2675, 2874-2875

src/types/supabase.types.ts (3)

2232-2235: LGTM: Function signature is well-defined.

The check_org_encrypted_bundle_enforcement function is properly typed with clear parameters. Note that session_key (bundle encryption data) differs from required_encryption_key (org-level requirement) - these represent different but related concepts in the encryption enforcement flow.


2280-2287: LGTM: Compliance management functions are well-typed.

The count_non_compliant_bundles and delete_non_compliant_bundles functions provide appropriate signatures for managing encryption compliance. The optional required_key parameter allows flexible enforcement modes.

Also applies to: 2313-2316


1343-1343: LGTM: New encryption enforcement fields properly typed.

The new fields are correctly defined across Row, Insert, and Update types. enforce_encrypted_bundles is required in Row (implying a database default) and optional in Insert/Update, while required_encryption_key is appropriately nullable across all contexts.

The required_encryption_key field stores only the first 21 characters of the base64-encoded public key (a fingerprint), not the actual encryption key material. It is used solely for validating that bundles were encrypted with the correct key identifier, posing no security risk to cryptographic secrets.

Comment on lines +547 to +558
if (enable) {
const deletedCount = nonCompliantBundleCounts.value?.total_non_compliant ?? 0
if (deletedCount > 0) {
toast.success(t('encrypted-bundles-enforcement-enabled-with-deletion', { count: deletedCount }))
}
else {
toast.success(t('encrypted-bundles-enforcement-enabled'))
}
}
else {
toast.success(t('encrypted-bundles-enforcement-disabled'))
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for the translation key in the codebase
rg "encrypted-bundles-enforcement-enabled-with-deletion" --type-list | head -20

Repository: Cap-go/capgo

Length of output: 445


🏁 Script executed:

# Find all message/locale files
fd -e json -e ts -e js | grep -E "(message|locale|i18n|lang)" | head -30

Repository: Cap-go/capgo

Length of output: 386


🏁 Script executed:

# Search more broadly for any messages directory or locale files
find . -type f -name "*.json" -o -name "*.ts" -o -name "*.js" | grep -iE "(message|locale|i18n|lang|translation)" | head -50

Repository: Cap-go/capgo

Length of output: 422


🏁 Script executed:

# Search for the translation key in messages directory
rg "encrypted-bundles-enforcement-enabled-with-deletion" messages/

Repository: Cap-go/capgo

Length of output: 229


🏁 Script executed:

# Check the structure of the English message file to understand the format
cat messages/en.json | head -50

Repository: Cap-go/capgo

Length of output: 3234


🏁 Script executed:

# Check if the translation key exists in Japanese and Turkish locale files
rg "encrypted-bundles-enforcement-enabled-with-deletion" messages/ja.json messages/tr.json

Repository: Cap-go/capgo

Length of output: 38


🏁 Script executed:

# Count how many locale files contain this key
rg "encrypted-bundles-enforcement-enabled-with-deletion" messages/ | wc -l

Repository: Cap-go/capgo

Length of output: 57


🏁 Script executed:

# Check the Security.vue file to verify the code context
sed -n '547,558p' src/pages/settings/organization/Security.vue

Repository: Cap-go/capgo

Length of output: 475


🏁 Script executed:

# Check which locale files are missing the key by searching all messages files
for file in messages/*.json; do
  if ! grep -q "encrypted-bundles-enforcement-enabled-with-deletion" "$file"; then
    echo "Missing in: $file"
  else
    echo "Present in: $file"
  fi
done

Repository: Cap-go/capgo

Length of output: 496


Add missing translation key to all non-English locale files

The translation key encrypted-bundles-enforcement-enabled-with-deletion referenced on line 550 exists only in messages/en.json and is missing from 14 other locale files (de, es, fr, hi, id, it, ja, ko, pl, pt-br, ru, tr, vi, zh-cn). This will cause untranslated fallback text to display in non-English locales.

Add the following key to all non-English message files:

"encrypted-bundles-enforcement-enabled-with-deletion": "{count} non-compliant bundle(s) have been deleted. Encrypted bundles enforcement is now enabled."
🤖 Prompt for AI Agents
In src/pages/settings/organization/Security.vue around lines 547 to 558 the
translation key encrypted-bundles-enforcement-enabled-with-deletion is used but
only exists in messages/en.json; add this key to the 14 non-English locale files
(de, es, fr, hi, id, it, ja, ko, pl, pt-br, ru, tr, vi, zh-cn) with the string
"{count} non-compliant bundle(s) have been deleted. Encrypted bundles
enforcement is now enabled." so non-English users see the proper translated
fallback.

Comment thread src/pages/settings/organization/Security.vue
logo: string
management_email: string
max_apikey_expiration_days: number | null
max_apikey_expiration_days: number
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the migration file mentioned in the learnings
find . -name "20251224103713_2fa_enforcement.sql" -o -name "*2fa_enforcement*"

Repository: Cap-go/capgo

Length of output: 231


🏁 Script executed:

# Search for get_orgs_v7 function definition in migrations
rg -n "CREATE OR REPLACE FUNCTION get_orgs_v7" --type=sql -A 100

Repository: Cap-go/capgo

Length of output: 38


🏁 Script executed:

# Check how max_apikey_expiration_days is used in the function
rg -n "max_apikey_expiration_days" --type=sql

Repository: Cap-go/capgo

Length of output: 6060


🏁 Script executed:

# Verify the type definition in supabase.types.ts around the mentioned lines
sed -n '2600,2680p' src/types/supabase.types.ts

Repository: Cap-go/capgo

Length of output: 2828


Fix type definition for max_apikey_expiration_days in get_orgs_v7 returns.

The max_apikey_expiration_days field should be number | null rather than number. The database schema explicitly allows NULL (with comment "NULL means no maximum"), but the TypeScript types incorrectly define it as non-nullable. This causes a type-safety mismatch and could lead to runtime errors. Update both occurrences (lines 2628 and 2661).

🤖 Prompt for AI Agents
In src/types/supabase.types.ts around lines 2628 and 2661, the type for
max_apikey_expiration_days is defined as number but the DB allows NULL; update
both occurrences to be number | null so the get_orgs_v7 return types accurately
reflect the schema (NULL means no maximum), and run type checks to ensure no
other code assumes a non-null value.

Copy link
Copy Markdown
Contributor

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

🧹 Nitpick comments (1)
supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)

17-27: Org-level encryption columns are well-defined; consider enforcing key length at the DB layer

The enforce_encrypted_bundles and required_encryption_key columns and comments accurately capture the feature semantics. Since the UI enforces exactly 21 characters for the fingerprint, you may want to back that with a CHECK constraint (e.g. CHECK (required_encryption_key IS NULL OR char_length(required_encryption_key) = 21)) to prevent inconsistent values from other callers.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 250c90d and 0c1ab62.

📒 Files selected for processing (6)
  • messages/en.json
  • src/pages/settings/organization/Security.vue
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • tests/build_time_tracking.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/build_time_tracking.test.ts
  • src/types/supabase.types.ts
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.vue: Use Vue 3 with Composition API and <script setup> syntax for frontend components
Style components using TailwindCSS with DaisyUI components

src/**/*.vue: Use Vue 3 <script setup> syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn, d-input, d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
Use useRoute() from vue-router to access route parameters and useRouter() for programmatic navigation in Vue components

Use DaisyUI (d- prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent

Files:

  • src/pages/settings/organization/Security.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use single quotes and no semicolons per @antfu/eslint-config

Files:

  • src/pages/settings/organization/Security.vue
  • supabase/functions/_backend/utils/supabase.types.ts
src/pages/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

Use file-based routing with unplugin-vue-router for frontend pages

Frontend file-based routing uses src/pages/ directory structure; routes auto-generate with unplugin-vue-router and types are available in src/typed-router.d.ts

Files:

  • src/pages/settings/organization/Security.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}

📄 CodeRabbit inference engine (CLAUDE.md)

Mobile apps should use Capacitor with app ID ee.forgr.capacitor_go for native mobile functionality

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use ~/ alias for imports from src/ directory in frontend TypeScript and Vue components

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend ESLint must pass before commit; run bun lint:fix to auto-fix issues in frontend files

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,css,scss}

📄 CodeRabbit inference engine (AGENTS.md)

The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{vue,ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Konsta components are reserved for the safe area helpers; avoid importing konsta anywhere else in the app

Files:

  • src/pages/settings/organization/Security.vue
src/**/*.{css,scss,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Mirror the Capgo design palette from src/styles/style.css (e.g., --color-primary-500: #515271, --color-azure-500: #119eff) when introducing new UI, using deep slate bases with the Extract azure highlight and soft radii

Files:

  • src/pages/settings/organization/Security.vue
supabase/migrations/**/*.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Database migrations must be created with supabase migration new <feature_slug> and never modify previously committed migrations

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
**/{migrations,tests,__tests__}/**/*.{sql,ts,js}

📄 CodeRabbit inference engine (AGENTS.md)

Always cover database changes with Postgres-level tests and complement them with end-to-end tests for affected user flows

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/migrations/*.sql

📄 CodeRabbit inference engine (AGENTS.md)

supabase/migrations/*.sql: When creating schema changes, use supabase migration new <feature_slug> to create a single migration file and keep editing that file until the feature ships; never edit previously committed migrations
A migration that introduces a new table may include seed inserts for that table, treating seeding as part of the current feature and not modifying previously committed migrations
Do not create new cron jobs; instead update the process_all_cron_tasks function in a new migration file to add your job if needed

Files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
supabase/functions/_backend/**

📄 CodeRabbit inference engine (CLAUDE.md)

Backend logic should be organized in supabase/functions/_backend/ with subdirectories for plugins, private endpoints, public endpoints, triggers, and utilities

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript strict mode with path aliases mapping ~/ to src/

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Supabase Edge Functions use Deno runtime

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/_backend/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/functions/_backend/**/*.{ts,js}: Backend code must be placed in supabase/functions/_backend/ as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
Use createHono from utils/hono.ts for all Hono framework application initialization and routing
All database operations must use getPgClient() or getDrizzleClient() from utils/pg.ts for PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must accept Context<MiddlewareKeyVariables> and use c.get('requestId'), c.get('apikey'), and c.get('auth') for request context
Use structured logging with cloudlog({ requestId: c.get('requestId'), message: '...' }) for all backend logging
Use middlewareAPISecret for internal API endpoints and middlewareKey for external API keys; validate against owner_org in the apikeys table
Check c.get('auth')?.authType to determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns with schema from postgress_schema.ts for all database operations; use aliasV2() for self-joins or multiple table references

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend ESLint must pass before commit; run bun lint:backend for backend files

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
🧠 Learnings (9)
📓 Common learnings
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table
📚 Learning: 2025-12-24T14:11:10.256Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:409-539
Timestamp: 2025-12-24T14:11:10.256Z
Learning: In supabase/migrations for get_orgs_v6 and get_orgs_v7: The inner functions with user_id parameter (get_orgs_v6(uuid) and get_orgs_v7(uuid)) should NOT be granted to anon/authenticated roles as this allows any user to query other users' organizations; only the no-argument wrapper functions should be public as they perform authentication checks.

Applied to files:

  • src/pages/settings/organization/Security.vue
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table

Applied to files:

  • src/pages/settings/organization/Security.vue
  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
  • supabase/functions/_backend/utils/supabase.types.ts
📚 Learning: 2025-12-25T11:22:19.594Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:19.594Z
Learning: In the 2FA enforcement implementation for supabase/migrations: When an org has enforcing_2fa=true, all users including super_admins must have 2FA enabled before accessing any org functions (including check_org_members_2fa_enabled); this is intentional behavior to ensure consistent security enforcement without exceptions for admins.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : All database operations must use `getPgClient()` or `getDrizzleClient()` from `utils/pg.ts` for PostgreSQL access during active migration to Cloudflare D1

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Backend code must be placed in `supabase/functions/_backend/` as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.

Applied to files:

  • src/pages/settings/organization/Security.vue
📚 Learning: 2025-12-25T11:22:13.039Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:85-96
Timestamp: 2025-12-25T11:22:13.039Z
Learning: In SQL migrations under the repository (e.g., supabase/migrations), enforce that when an org has enforcing_2fa=true, all users (including super_admins) must have 2FA enabled before accessing any org functions, including check_org_members_2fa_enabled. Do not grant admin exceptions to 2FA requirements. This ensures consistent security enforcement across all org-related operations; implement this rule within relevant migrations and associated stored procedures/tests.

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Check `c.get('auth')?.authType` to determine authentication type ('apikey' vs 'jwt') in backend endpoints

Applied to files:

  • supabase/migrations/20260101042511_enforce_encrypted_bundles.sql
🪛 Gitleaks (8.30.0)
messages/en.json

[high] 813-814: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ 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). (1)
  • GitHub Check: Run tests
🔇 Additional comments (9)
messages/en.json (1)

801-825: Encrypted bundles i18n strings look correct; static-analysis hit is a false positive

The new encrypted-bundles / key-management messages are consistent with the feature semantics and existing security wording. The Gitleaks “generic-api-key” finding on these lines is just flagging human-readable labels (save-encryption-key, validation text), not an actual secret or credential, so no change is required.

supabase/functions/_backend/utils/supabase.types.ts (2)

1339-1395: Org encryption-enforcement fields are correctly surfaced in types

enforce_encrypted_bundles and required_encryption_key are wired through Row/Insert/Update with the right nullability and shapes for the new org columns, matching the migration and UI expectations.


2229-2232: New function typings align with the SQL surfaces

The added entries for:

  • check_org_encrypted_bundle_enforcement(org_id, session_key),
  • count_non_compliant_bundles(org_id, required_key?),
  • delete_non_compliant_bundles(org_id, required_key?),
  • is_bundle_encrypted(session_key),

and the extended get_orgs_v7 return types (enforce_encrypted_bundles, required_encryption_key) all match the migration signatures and the ways they’re consumed in the Vue layer (RPC calls and org loading). This keeps the generated client typings in sync with the DB contract.

Also applies to: 2277-2284, 2310-2313, 2585-2650, 2850-2851

supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (2)

34-44: Helper functions cleanly separate bundle-level and org-level enforcement

is_bundle_encrypted(session_key) and check_org_encrypted_bundle_enforcement(org_id, session_key) are small, side‑effect‑free guards that centralize “is this encrypted” and “does this org enforce encryption” logic. Combined with pg_log calls on denial, they give you a simple, auditable contract for API‑side checks before insert.

Also applies to: 58-94


222-403: get_orgs_v7 extensions keep new org flags consistent with existing access model

The rewritten get_orgs_v7(userid) and its no-arg wrapper:

  • Preserve the existing 2FA/password redaction model,
  • Add enforce_encrypted_bundles and required_encryption_key to the returned shape, and
  • Keep the uuid-parameterized variant restricted to postgres/service_role only, with the public wrapper handling identity resolution and API key scoping.

This matches prior hardening work on org listing functions and keeps the new flags available wherever orgs are loaded.

src/pages/settings/organization/Security.vue (4)

53-57: Encrypted bundles state is correctly wired from org data into local refs

enforceEncryptedBundles, requiredEncryptionKey, and nonCompliantBundleCounts are initialized and kept in sync with the orgs row (enforce_encrypted_bundles, required_encryption_key) via loadData, which keeps the Security UI aligned with backend state.

Also applies to: 164-182


585-643: Required encryption key update flow and validation are sound

updateRequiredEncryptionKey:

  • Enforces the 21-character fingerprint requirement client-side,
  • When enforcement is active, temporarily applies the new key only for counting, then warns if any bundles would be deleted, and
  • Reuses saveEncryptedBundlesEnforcement for both “just save” and “save + delete non‑compliant” paths.

This matches the DB contract and gives admins a clear, gated way to change keys without accidental silent deletions.


997-1074: Encrypted bundles UI and warning dialogs are consistent and i18n-complete

The new “Encrypted Bundles” section:

  • Reuses the existing toggle pattern with proper hasOrgPerm / isSaving disabling,
  • Shows the optional required-key input only when enforcement is on and the user is permitted, and
  • Uses the new i18n keys (e.g. enforce-encrypted-bundles, required-encryption-key-*, encrypted-bundles-enforcement-*, bundles-*) in both the main section and Teleport warning content.

The Teleport blocks bind directly to nonCompliantBundleCounts and dialog IDs, so the counts and warning text stay in sync with the underlying RPC results.

Also applies to: 1420-1452


1076-1167: Password policy header/icon adjustments integrate cleanly with existing logic

The introduction of IconFingerprint and updated header/description for the password policy section are purely presentational and do not alter the underlying behavior of policyEnabled or the associated handlers (handlePolicyToggle, updatePasswordPolicy). The visual change is self-contained and consistent with the rest of the settings UI.

Copy link
Copy Markdown
Contributor

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

🤖 Fix all issues with AI agents
In @src/types/supabase.types.ts:
- Around line 2235-2238: The RPC type definitions for
check_org_encrypted_bundle_enforcement and is_bundle_encrypted have session_key
typed as string but the underlying SQL allows NULL; update the Args for both
RPCs so session_key is typed as string | null (e.g., Args: { org_id: string;
session_key: string | null }) to match the SQL signatures and callers that may
pass NULL.

In @supabase/seed.sql:
- Around line 497-500: The apikeys seed inserts id values up to 111 but the
sequence used by nextval() may still be lower and could recycle 111; update the
sequence after seeding so it follows the current maximum id by calling
setval(pg_get_serial_sequence('public.apikeys','id'), (SELECT MAX(id) FROM
public.apikeys)) (or ALTER SEQUENCE ... RESTART WITH MAX(id)+1) so that
public.apikeys.id, nextval(), and the sequence are advanced past 111 and no
duplicate key is produced.

In @tests/enforce-encrypted-bundles.test.ts:
- Around line 353-369: The test calls getSupabaseClient().rpc('get_orgs_v7', {
userid: USER_ID_ENCRYPTED }) and TypeScript infers the RPC result as unknown;
fix by providing an explicit result type to rpc (or by casting the returned
data) so data is typed as an array of org objects that include
enforce_encrypted_bundles: boolean; e.g. supply a generic type to
rpc<'get_orgs_v7', Array<{ enforce_encrypted_bundles: boolean; [key: string]:
any }>>() or cast the rpc result to Array<{ enforce_encrypted_bundles: boolean;
[key: string]: any }>, updating the test around the getSupabaseClient().rpc(...)
call to remove the unknown type and satisfy asserts on
org.enforce_encrypted_bundles.
🧹 Nitpick comments (9)
tests/updates.test.ts (1)

181-187: Consider using the stated minimum plugin version (7.0.35) to better test the gating boundary.

Right now the comment says >= 7.0.35 but the test forces 7.1.0, which won’t catch boundary/compare regressions.

Proposed tweak
   function makeUpdatePayload() {
     const baseData = getBaseData(APP_NAME_UPDATE)
     baseData.version_name = '1.1.0'
     // Manifest support requires plugin_version >= 7.0.35 for v7
-    baseData.plugin_version = '7.1.0'
+    baseData.plugin_version = '7.0.35'
     return baseData
   }
messages/es.json (1)

786-789: Consider aligning “bundles” vs “paquetes” terminology for consistency in Spanish.

If the UI elsewhere uses “paquete(s)”, these new strings may read inconsistent.

messages/zh-cn.json (1)

786-789: Consider using “捆绑包” consistently instead of “包” in these new strings.
This file overwhelmingly uses “捆绑包” elsewhere; aligning terminology improves UX consistency.

tests/enforce-encrypted-bundles.test.ts (3)

16-46: Check setup/teardown writes for errors (fail fast).
Right now beforeAll/afterAll ignore potential Supabase errors, which can make subsequent test failures misleading.

Example pattern
 beforeAll(async () => {
   // Ensure enforcement is disabled at the start of tests
-  await getSupabaseClient()
+  const { error: orgUpdateError } = await getSupabaseClient()
     .from('orgs')
     .update({ enforce_encrypted_bundles: false })
     .eq('id', ORG_ID_ENCRYPTED)
+  if (orgUpdateError)
+    throw orgUpdateError

88-120: Assert the exact API contract (400 + encryption_required) instead of substring matching.
This aligns with the PR objective and reduces false positives.

Proposed tightening
       // The API should reject this request
       expect(response.ok).toBe(false)
+      expect(response.status).toBe(400)
       const data = await response.json()
-      expect(data.error).toContain('encryption')
+      expect(String(data.error)).toContain('encryption_required')

264-350: Avoid null as unknown as string in RPC calls (prefer ''), or adjust function arg typings to allow null.
Casting away types here hides real incompatibilities and makes future refactors harder.

supabase/seed.sql (2)

57-58: Seeded auth users: ensure downstream fixtures reference the new UUIDs consistently.

Looks consistent with the later public.users inserts, but this is easy to break over time—consider adding a short comment pointing to the corresponding public.users rows for cli_hashed@capgo.app and encrypted@capgo.app.


260-261: New org fixtures: consider explicitly setting encryption policy defaults for deterministic tests.

The insert omits the new enforce_encrypted_bundles / required_encryption_key columns (relying on DB defaults). If tests assume a known default state, you may want to include them explicitly for Encrypted Test Org.

messages/en.json (1)

815-839: Wording: avoid leaking internal field names (“session_key”) into user-facing copy.

Consider rephrasing "Bundles without encryption (no session_key)..." to something user-facing (e.g., “missing encryption metadata”), unless your audience is expected to know the API field name. Also: Gitleaks’ “Generic API Key” hit here looks like a false positive, but please double-check no real secrets were accidentally added to translations.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c1ab62 and 30f95db.

📒 Files selected for processing (21)
  • messages/de.json
  • messages/en.json
  • messages/es.json
  • messages/fr.json
  • messages/hi.json
  • messages/id.json
  • messages/it.json
  • messages/ja.json
  • messages/ko.json
  • messages/pl.json
  • messages/pt-br.json
  • messages/ru.json
  • messages/tr.json
  • messages/vi.json
  • messages/zh-cn.json
  • src/types/supabase.types.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • supabase/seed.sql
  • tests/enforce-encrypted-bundles.test.ts
  • tests/test-utils.ts
  • tests/updates.test.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • messages/ru.json
  • messages/fr.json
  • messages/hi.json
  • messages/ko.json
  • messages/tr.json
  • messages/id.json
  • messages/vi.json
  • messages/pt-br.json
  • messages/de.json
🧰 Additional context used
📓 Path-based instructions (9)
tests/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend tests must use helpers from tests/test-utils.ts including getEndpointUrl(path) for correct worker routing and USE_CLOUDFLARE_WORKERS=true for CF Workers testing

Files:

  • tests/updates.test.ts
  • tests/test-utils.ts
  • tests/enforce-encrypted-bundles.test.ts
**/*.{js,ts,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use single quotes and no semicolons in JavaScript/TypeScript code

Files:

  • tests/updates.test.ts
  • tests/test-utils.ts
  • tests/enforce-encrypted-bundles.test.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

Use path aliases: ~/ maps to src/ for imports in TypeScript files

Files:

  • tests/updates.test.ts
  • tests/test-utils.ts
  • tests/enforce-encrypted-bundles.test.ts
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
supabase/seed.sql

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Seed database with supabase db reset to apply all migrations and test data from supabase/seed.sql

Update supabase/seed.sql to back new or evolved tests, keeping fixtures focused on current behavior while leaving committed migrations unchanged

Files:

  • supabase/seed.sql
supabase/functions/_backend/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

supabase/functions/_backend/**/*.{ts,js}: Backend code must be placed in supabase/functions/_backend/ as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
Use createHono from utils/hono.ts for all Hono framework application initialization and routing
All database operations must use getPgClient() or getDrizzleClient() from utils/pg.ts for PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must accept Context<MiddlewareKeyVariables> and use c.get('requestId'), c.get('apikey'), and c.get('auth') for request context
Use structured logging with cloudlog({ requestId: c.get('requestId'), message: '...' }) for all backend logging
Use middlewareAPISecret for internal API endpoints and middlewareKey for external API keys; validate against owner_org in the apikeys table
Check c.get('auth')?.authType to determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns with schema from postgress_schema.ts for all database operations; use aliasV2() for self-joins or multiple table references

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.{ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Backend ESLint must pass before commit; run bun lint:backend for backend files

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
supabase/functions/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

supabase/functions/**/*.ts: Never use the Supabase admin SDK (with service key) for user-facing APIs; always use the client SDK with user authentication so RLS policies are enforced
The admin SDK should only be used for accessing data that is not user-accessible or for internal operations (triggers, CRON jobs, etc.)
When admin access is unavoidable for a user-facing endpoint, sanitize all user inputs carefully to prevent PostgREST query injection

Files:

  • supabase/functions/_backend/utils/supabase.types.ts
src/**/*.{ts,tsx,vue,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use ~/ alias for imports from src/ directory in frontend TypeScript and Vue components

Files:

  • src/types/supabase.types.ts
src/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Frontend ESLint must pass before commit; run bun lint:fix to auto-fix issues in frontend files

Files:

  • src/types/supabase.types.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Applies to supabase/migrations/**/*.sql : Pass app_id to BOTH `get_identity_org_appid()` AND `check_min_rights()` in RLS policies
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Applies to supabase/seed.sql : Update `supabase/seed.sql` to back new or evolved tests, keeping fixtures focused on current behavior while leaving committed migrations unchanged

Applied to files:

  • supabase/seed.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/seed.sql : Seed database with `supabase db reset` to apply all migrations and test data from `supabase/seed.sql`

Applied to files:

  • supabase/seed.sql
📚 Learning: 2025-12-24T14:11:10.256Z
Learnt from: WcaleNieWolny
Repo: Cap-go/capgo PR: 1300
File: supabase/migrations/20251224103713_2fa_enforcement.sql:409-539
Timestamp: 2025-12-24T14:11:10.256Z
Learning: In supabase/migrations for get_orgs_v6 and get_orgs_v7: The inner functions with user_id parameter (get_orgs_v6(uuid) and get_orgs_v7(uuid)) should NOT be granted to anon/authenticated roles as this allows any user to query other users' organizations; only the no-argument wrapper functions should be public as they perform authentication checks.

Applied to files:

  • supabase/seed.sql
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Applies to supabase/migrations/**/*.sql : Pass app_id to BOTH `get_identity_org_appid()` AND `check_min_rights()` in RLS policies

Applied to files:

  • supabase/seed.sql
  • src/types/supabase.types.ts
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Use `middlewareAPISecret` for internal API endpoints and `middlewareKey` for external API keys; validate against `owner_org` in the `apikeys` table

Applied to files:

  • supabase/seed.sql
  • supabase/functions/_backend/utils/supabase.types.ts
  • src/types/supabase.types.ts
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: A migration that introduces a new table may include seed inserts for that table, treating that seeding as part of the current feature and not modifying previously committed migrations

Applied to files:

  • supabase/seed.sql
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Applies to supabase/migrations/**/*.sql : Use both `authenticated` and `anon` roles in RLS policies (anon enables API key auth)

Applied to files:

  • supabase/seed.sql
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Supabase types should be auto-generated via CLI

Applied to files:

  • supabase/seed.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Test accounts available after `supabase db reset`: `testcapgo.app` / `testtest` (demo user) and `admincapgo.app` / `adminadmin` (admin user)

Applied to files:

  • supabase/seed.sql
📚 Learning: 2026-01-09T18:24:11.070Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T18:24:11.070Z
Learning: Applies to supabase/migrations/**/*.sql : `get_identity_org_allowed()` is an absolute last resort; only use it when the table genuinely has NO app_id column and there is NO way to join to get an app_id

Applied to files:

  • supabase/seed.sql
📚 Learning: 2025-12-23T02:53:12.055Z
Learnt from: CR
Repo: Cap-go/capgo PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-12-23T02:53:12.055Z
Learning: Applies to supabase/functions/_backend/**/*.{ts,js} : Check `c.get('auth')?.authType` to determine authentication type ('apikey' vs 'jwt') in backend endpoints

Applied to files:

  • src/types/supabase.types.ts
🧬 Code graph analysis (1)
tests/enforce-encrypted-bundles.test.ts (1)
tests/test-utils.ts (6)
  • APIKEY_ENCRYPTED (76-76)
  • getSupabaseClient (385-404)
  • ORG_ID_ENCRYPTED (75-75)
  • APP_NAME_ENCRYPTED (77-77)
  • getEndpointUrl (28-38)
  • USER_ID_ENCRYPTED (74-74)
🪛 GitHub Actions: Run tests
tests/enforce-encrypted-bundles.test.ts

[error] 112-112: TypeScript error TS18046: 'data' is of type 'unknown'.

🪛 Gitleaks (8.30.0)
tests/test-utils.ts

[high] 76-76: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

tests/enforce-encrypted-bundles.test.ts

[high] 39-39: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 40-40: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 52-52: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 57-57: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 71-71: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 76-76: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

messages/en.json

[high] 827-828: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (13)
messages/ja.json (1)

786-789: New encrypted-bundles enforcement strings look consistent and clear.

messages/pl.json (1)

786-789: Polish encrypted-bundles enforcement strings look good.

messages/it.json (1)

786-789: Translations for encrypted bundles enforcement look good.
Clear and consistent with the security-setting tone in this locale.

src/types/supabase.types.ts (1)

1344-1403: Org schema typing updates (encryption enforcement + required key) are consistent.

tests/test-utils.ts (1)

73-78: Gitleaks is not configured in CI, so the concern about flagging is not applicable.

The repository has no Gitleaks setup or secret scanning in any CI workflows (tests.yml, build_and_deploy.yml, or elsewhere). The APIKEY_ENCRYPTED constant uses a UUID format (b8c9d0e1-f2a3-4b4c-9d5e-6f7a8b9c0d14), which is appropriate for a test constant in tests/test-utils.ts and will not trigger actual security scanning.

Likely an incorrect or invalid review comment.

supabase/seed.sql (4)

237-238: Stripe seed rows: OK; keep customer_id/subscription_id uniqueness assumptions in mind.

LGTM for adding sub_encrypted. Just ensure no other seed/test paths also insert cus_encrypted_test_123 to avoid unique conflicts.


248-249: public.users additions: OK, but keep trigger-disable scope tight.

Good use of DISABLE TRIGGER generate_org_on_user_create around the insert set.


474-475: org_users for new orgs: LGTM.

Adds the expected super_admin memberships for the new orgs.


518-520: New apps: verify whether encrypted/RLS apps need seeded app_versions/channels for the test plan.

You seed com.encrypted.app, but don’t seed any public.app_versions rows for it in this function. If the encrypted-bundles enforcement tests expect existing bundles (for counting/deletion), you may need to seed at least one compliant/non-compliant version here (or ensure tests create them explicitly).

supabase/functions/_backend/utils/supabase.types.ts (4)

1344-1403: orgs table type additions: LGTM.

enforce_encrypted_bundles and required_encryption_key propagation across Row/Insert/Update looks consistent.


2235-2238: Verify DB signature + GRANTs for check_org_encrypted_bundle_enforcement.

Types assume (org_id: string, session_key: string) -> boolean. Please confirm the SQL function matches this signature and is only callable by intended roles.


2283-2290: Verify PostgREST return typing for count/delete helpers (bigint vs number).

If these functions use COUNT(*)/bigint internally, PostgREST can sometimes surface values as strings. Since the generated types say number, please confirm the actual return types and generated typings align (or cast in SQL to int/numeric as needed).

Also applies to: 2316-2319, 2856-2857


2591-2657: The get_orgs_v7(userid) overload is properly secured and not publicly granted.

The SQL migrations consistently implement the correct security pattern: get_orgs_v7(uuid) is explicitly revoked from PUBLIC, anon, and authenticated roles, with EXECUTE permissions granted only to postgres and service_role. Only the no-arg wrapper get_orgs_v7() is publicly accessible, and it performs the necessary authentication checks internally before calling the userid overload. This pattern is enforced uniformly across all related migrations (20251224103713_2fa_enforcement.sql, 20251228080032_hashed_api_keys.sql, 20251228100000_password_policy_enforcement.sql, 20260101042511_enforce_encrypted_bundles.sql, and 20260104110000_add_apikey_policy_to_get_orgs_v7.sql).

Comment on lines +2235 to +2238
check_org_encrypted_bundle_enforcement: {
Args: { org_id: string; session_key: string }
Returns: boolean
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) Find all migration files and search for get_orgs_v7 and related GRANT statements
echo "=== Searching for get_orgs_v7 function definitions and GRANT statements ==="
fd -t f '\.sql$' supabase/migrations | head -20

Repository: Cap-go/capgo

Length of output: 1327


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 2) Search for get_orgs_v7 in migration files with context
echo "=== Searching for get_orgs_v7 ==="
rg -n 'get_orgs_v7' supabase/migrations/ -A 3 -B 3 2>/dev/null || echo "No matches found"

# 3) Search for GRANT/REVOKE patterns around get_orgs_v7
echo "=== Searching for GRANT statements on get_orgs_v7 ==="
rg -n 'grant.*get_orgs_v7|grant.*to\s+(anon|authenticated)' supabase/migrations/ -i 2>/dev/null || echo "No direct matches"

Repository: Cap-go/capgo

Length of output: 36431


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 4) Look for the supabase.types.ts file and extract the relevant lines
echo "=== Checking supabase.types.ts for check_org_encrypted_bundle_enforcement ==="
wc -l src/types/supabase.types.ts
# Get line 2235-2238 and surrounding context
sed -n '2230,2245p' src/types/supabase.types.ts 2>/dev/null || echo "File or lines not found"

Repository: Cap-go/capgo

Length of output: 610


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 5) Get the other mentioned line ranges
echo "=== Checking additional line ranges in supabase.types.ts ==="
sed -n '2283,2295p' src/types/supabase.types.ts 2>/dev/null | head -20
sed -n '2316,2325p' src/types/supabase.types.ts 2>/dev/null | head -20

Repository: Cap-go/capgo

Length of output: 853


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 6) Search for check_org_encrypted_bundle_enforcement function in migrations
echo "=== Searching for check_org_encrypted_bundle_enforcement definition ==="
rg -n 'check_org_encrypted_bundle_enforcement' supabase/migrations/ -A 10 -B 2 2>/dev/null || echo "Not found in migrations"

# 7) Search for session_key parameter usage
echo "=== Searching for session_key in migrations ==="
rg -n 'session_key' supabase/migrations/ -B 2 -A 2 2>/dev/null | head -50

Repository: Cap-go/capgo

Length of output: 9354


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check all referenced line ranges for context
echo "=== Lines 2283-2290 ==="
sed -n '2283,2290p' src/types/supabase.types.ts

echo ""
echo "=== Lines 2316-2319 ==="
sed -n '2316,2319p' src/types/supabase.types.ts

echo ""
echo "=== Lines 2591-2656 (first 30 lines) ==="
sed -n '2591,2620p' src/types/supabase.types.ts

echo ""
echo "=== Lines 2856-2857 ==="
sed -n '2856,2857p' src/types/supabase.types.ts

Repository: Cap-go/capgo

Length of output: 1760


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify that check_org_encrypted_bundle_enforcement can receive null session_key
echo "=== Checking if session_key can be null in callers ==="
rg -n 'check_org_encrypted_bundle_enforcement' --type ts --type tsx -A 2 -B 2 supabase/functions/ src/ 2>/dev/null | head -40

Repository: Cap-go/capgo

Length of output: 110


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the app_versions table schema to see if session_key is nullable
echo "=== Checking app_versions.session_key column definition ==="
rg -n 'app_versions.*session_key|session_key.*app_versions' supabase/migrations/ -B 5 -A 2 2>/dev/null | head -60

Repository: Cap-go/capgo

Length of output: 115


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Let's search more broadly for app_versions schema and session_key
echo "=== Looking for app_versions table schema ==="
rg -n 'CREATE TABLE.*app_versions|alter table.*app_versions' supabase/migrations/ -A 15 2>/dev/null | grep -A 10 -B 5 'session_key' | head -40

Repository: Cap-go/capgo

Length of output: 1451


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check how is_bundle_encrypted is called and whether null is passed
echo "=== Searching for is_bundle_encrypted calls ==="
rg -n 'is_bundle_encrypted' supabase/migrations/ -B 2 -A 1 2>/dev/null | head -60

Repository: Cap-go/capgo

Length of output: 1704


Fix session_key nullability in RPC type definitions.

The check_org_encrypted_bundle_enforcement and is_bundle_encrypted function parameters accept nullable text in PostgreSQL (session_key can be NULL), but the TypeScript types define them as string. Update both to string | null to match the actual SQL function signatures and handle cases where null is passed. The functions already handle nullability correctly (e.g., session_key IS NOT NULL AND session_key <> ''), but the type definitions must reflect this.

Note: The get_orgs_v7(userid) permissions are already correctly configured—the userid-parameter variant is properly revoked from public roles and granted only to postgres/service_role as per security requirements.

🤖 Prompt for AI Agents
In @src/types/supabase.types.ts around lines 2235 - 2238, The RPC type
definitions for check_org_encrypted_bundle_enforcement and is_bundle_encrypted
have session_key typed as string but the underlying SQL allows NULL; update the
Args for both RPCs so session_key is typed as string | null (e.g., Args: {
org_id: string; session_key: string | null }) to match the SQL signatures and
callers that may pass NULL.

Comment thread supabase/seed.sql
Comment on lines +353 to +369
describe('get_orgs_v7 includes enforce_encrypted_bundles', () => {
it('should include enforce_encrypted_bundles field in get_orgs_v7 response', async () => {
// Use get_orgs_v7 with the encrypted user
const { data, error } = await getSupabaseClient()
.rpc('get_orgs_v7', { userid: USER_ID_ENCRYPTED })

expect(error).toBeNull()
expect(data).toBeDefined()
expect(Array.isArray(data)).toBe(true)
expect(data!.length).toBeGreaterThan(0)

// Check that ALL orgs in the response have the enforce_encrypted_bundles field
for (const org of data!) {
expect(org.enforce_encrypted_bundles).toBeDefined()
expect(typeof org.enforce_encrypted_bundles).toBe('boolean')
}
})
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Check if the test file exists and examine the relevant lines
if [ -f tests/enforce-encrypted-bundles.test.ts ]; then
  echo "=== File exists. Checking lines 353-369 ==="
  sed -n '353,369p' tests/enforce-encrypted-bundles.test.ts
  echo ""
  echo "=== Full context around the RPC call ==="
  sed -n '340,375p' tests/enforce-encrypted-bundles.test.ts
else
  echo "File not found at tests/enforce-encrypted-bundles.test.ts"
fi

Repository: Cap-go/capgo

Length of output: 1919


🏁 Script executed:

# Check if the supabase types file exists
if [ -f src/types/supabase.types.ts ]; then
  echo "=== supabase.types.ts exists ==="
  echo "=== Checking for get_orgs_v7 type definition ==="
  grep -A 5 "get_orgs_v7" src/types/supabase.types.ts | head -20
else
  echo "supabase.types.ts not found at src/types/"
  echo "=== Checking what's in src/types/ ==="
  ls -la src/types/ 2>/dev/null || echo "Directory doesn't exist"
fi

Repository: Cap-go/capgo

Length of output: 287


🏁 Script executed:

# Check the imports in the test file to see what's already imported
echo "=== Current imports in the test file ==="
head -15 tests/enforce-encrypted-bundles.test.ts

Repository: Cap-go/capgo

Length of output: 777


🏁 Script executed:

# Search for other RPC calls in test files to see how they handle typing
echo "=== Looking for other typed RPC calls in test files ==="
rg '\.rpc<' tests/ --type ts -A 1 | head -30

Repository: Cap-go/capgo

Length of output: 111


🏁 Script executed:

# Get the complete get_orgs_v7 Returns type definition
echo "=== Full get_orgs_v7 type definition ==="
rg -A 30 'get_orgs_v7:' src/types/supabase.types.ts | head -50

Repository: Cap-go/capgo

Length of output: 1210


🏁 Script executed:

# Verify the enforce_encrypted_bundles field exists in the type
echo "=== Checking for enforce_encrypted_bundles in the type ==="
rg 'enforce_encrypted_bundles' src/types/supabase.types.ts

Repository: Cap-go/capgo

Length of output: 349


🏁 Script executed:

# Check the supabase client version and its RPC typing capabilities
echo "=== Checking package.json for @supabase/supabase-js version ==="
grep -A 2 '"@supabase/supabase-js"' package.json

Repository: Cap-go/capgo

Length of output: 226


🏁 Script executed:

# Check if the import path would work correctly
echo "=== Verifying import path from tests/ to src/types/ ==="
cd tests && ls -la ../src/types/supabase.types.ts 2>&1 || echo "Path check failed"

Repository: Cap-go/capgo

Length of output: 193


🏁 Script executed:

# Check the migration file to understand the get_orgs_v7 function signature
echo "=== Checking get_orgs_v7 definition in migration ==="
rg -B 5 -A 20 'CREATE.*FUNCTION.*get_orgs_v7' supabase/migrations/20251224103713_2fa_enforcement.sql | head -60

Repository: Cap-go/capgo

Length of output: 1795


🏁 Script executed:

# Verify if the RPC accepts userid parameter by checking the actual function definition
echo "=== Searching for get_orgs_v7 parameter specification ==="
rg 'get_orgs_v7.*userid|get_orgs_v7.*uuid' supabase/migrations/ -A 3

Repository: Cap-go/capgo

Length of output: 10705


🏁 Script executed:

# Check the wrapper function get_orgs_v7() to see how it handles authentication
echo "=== Checking get_orgs_v7() wrapper implementation ==="
rg -A 30 'CREATE OR REPLACE FUNCTION public.get_orgs_v7\(\)' supabase/migrations/20260104110000_add_apikey_policy_to_get_orgs_v7.sql | head -50

Repository: Cap-go/capgo

Length of output: 997


🏁 Script executed:

# Check the test-utils to see how getSupabaseClient() is configured
echo "=== Checking getSupabaseClient setup ==="
grep -A 20 'export.*getSupabaseClient' tests/test-utils.ts

Repository: Cap-go/capgo

Length of output: 598


🏁 Script executed:

# Check if the test is supposed to use the wrapper or the UUID variant
echo "=== Checking other RPC calls in the test file ==="
rg '\.rpc\(' tests/enforce-encrypted-bundles.test.ts -B 2 -A 2

Repository: Cap-go/capgo

Length of output: 1652


🏁 Script executed:

# Check if the wrapper function get_orgs_v7() returns enforce_encrypted_bundles
echo "=== Check wrapper function full return type ==="
rg -A 50 'CREATE OR REPLACE FUNCTION public.get_orgs_v7\(\)' supabase/migrations/20260104110000_add_apikey_policy_to_get_orgs_v7.sql | grep -A 30 'RETURNS TABLE'

Repository: Cap-go/capgo

Length of output: 964


🏁 Script executed:

# Check what the wrapper function does - does it call the parameterized version?
echo "=== Check wrapper function implementation body ==="
rg -A 100 'CREATE OR REPLACE FUNCTION public.get_orgs_v7\(\)' supabase/migrations/20260104110000_add_apikey_policy_to_get_orgs_v7.sql | tail -70

Repository: Cap-go/capgo

Length of output: 2291


🏁 Script executed:

# Check if the test-utils provides any helper that should be used instead
echo "=== Check full test-utils.ts to see if there's a helper for this ==="
head -100 tests/test-utils.ts

Repository: Cap-go/capgo

Length of output: 5845


🏁 Script executed:

# Verify the Database type structure for get_orgs_v7 - does it have both variants?
echo "=== Checking full get_orgs_v7 type structure ==="
rg -A 100 'get_orgs_v7:' src/types/supabase.types.ts | head -120

Repository: Cap-go/capgo

Length of output: 3458


🏁 Script executed:

# Check if there are any existing TypeScript errors in the test file
echo "=== Check for TypeScript compilation issues ==="
if command -v tsc &> /dev/null; then
  tsc --noEmit tests/enforce-encrypted-bundles.test.ts 2>&1 | head -20 || true
else
  echo "TypeScript compiler not available in sandbox"
fi

Repository: Cap-go/capgo

Length of output: 148


Fix TS18046: type get_orgs_v7 RPC result (currently unknown).
This is breaking CI.

Proposed fix
 import { afterAll, beforeAll, describe, expect, it } from 'vitest'
 import { APIKEY_ENCRYPTED, APP_NAME_ENCRYPTED, getEndpointUrl, getSupabaseClient, ORG_ID_ENCRYPTED, USER_ID_ENCRYPTED } from './test-utils.ts'
+import type { Database } from '../src/types/supabase.types'

+type GetOrgsV7Return = Database['public']['Functions']['get_orgs_v7']['Returns']

   describe('get_orgs_v7 includes enforce_encrypted_bundles', () => {
     it('should include enforce_encrypted_bundles field in get_orgs_v7 response', async () => {
       // Use get_orgs_v7 with the encrypted user
       const { data, error } = await getSupabaseClient()
-        .rpc('get_orgs_v7', { userid: USER_ID_ENCRYPTED })
+        .rpc<GetOrgsV7Return>('get_orgs_v7', { userid: USER_ID_ENCRYPTED })

       expect(error).toBeNull()
       expect(data).toBeDefined()
       expect(Array.isArray(data)).toBe(true)
       expect(data!.length).toBeGreaterThan(0)
🤖 Prompt for AI Agents
In @tests/enforce-encrypted-bundles.test.ts around lines 353 - 369, The test
calls getSupabaseClient().rpc('get_orgs_v7', { userid: USER_ID_ENCRYPTED }) and
TypeScript infers the RPC result as unknown; fix by providing an explicit result
type to rpc (or by casting the returned data) so data is typed as an array of
org objects that include enforce_encrypted_bundles: boolean; e.g. supply a
generic type to rpc<'get_orgs_v7', Array<{ enforce_encrypted_bundles: boolean;
[key: string]: any }>>() or cast the rpc result to Array<{
enforce_encrypted_bundles: boolean; [key: string]: any }>, updating the test
around the getSupabaseClient().rpc(...) call to remove the unknown type and
satisfy asserts on org.enforce_encrypted_bundles.

This PR adds the ability for organizations to enforce that all bundles
must be encrypted (have a session_key).

Key changes:
- Add enforce_encrypted_bundles column to orgs table (default false)
- Add database trigger to reject unencrypted bundles when enforcement enabled
- Add SQL functions for counting/deleting non-compliant bundles
- Add helper functions: is_bundle_encrypted, check_org_encrypted_bundle_enforcement
- Update get_orgs_v7 to include enforce_encrypted_bundles field
- Add UI for managing encryption enforcement in Security settings
- Add isolated test data in seed.sql for encrypted bundles tests
- Add tests for encryption enforcement feature
- Fix manifest entries test (requires plugin_version >= 7.0.35)
- Improve build_time_tracking test isolation with per-run unique IDs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@riderx riderx force-pushed the riderx/enforce-encrypted-keys branch from 3778279 to 18d980c Compare January 10, 2026 05:44
@sonarqubecloud
Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@riderx riderx merged commit 390236e into main Jan 12, 2026
9 of 11 checks passed
@riderx riderx deleted the riderx/enforce-encrypted-keys branch January 12, 2026 13:18
@coderabbitai coderabbitai Bot mentioned this pull request Jan 12, 2026
11 tasks
This was referenced Jan 23, 2026
@coderabbitai coderabbitai Bot mentioned this pull request Feb 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant