feat: enforce encrypted bundles in organization security#1343
Conversation
|
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 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. 📒 Files selected for processing (26)
📝 WalkthroughWalkthroughAdds 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
Sequence Diagram(s)mermaid mermaid Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ 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. Comment |
There was a problem hiding this comment.
💡 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".
| -- Get the org's enforcement setting for this app | ||
| SELECT enforce_encrypted_bundles INTO org_enforcing | ||
| FROM public.orgs | ||
| WHERE id = NEW.owner_org; |
There was a problem hiding this comment.
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 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)
99-151: Trigger can run beforeowner_orgis populated, allowing unenforced inserts
check_encrypted_bundle_on_insertlooks upenforce_encrypted_bundlesusingNEW.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_orgis populated by the existingforce_valid_owner_org_app_versions/auto-owner trigger, which is also aBEFORE INSERTtrigger 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 fromapp_id) will seeNEW.owner_orgasNULLin this trigger.org_enforcingstaysNULL, so the earlyIF org_enforcing IS NULL ... THEN RETURN NEWpath 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_orgentirely and derive the org fromNEW.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/afterAllsnapshot ofstripe_infoplus the stricterbeforeEachreset (status, product, anchors, exceeded flags, plan_calculated_at, plus clearingdaily_build_timeandapp_metrics_cache) gives much better test isolation. Behaviorally this is sound.If you want a bit more type safety, you could replace
anywith 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
Databasefrom your localsupabase.typeshelper.)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 toggleThe new
enforceEncryptedBundlesstate, the extendedloadDataselect,toggleEnforceEncryptedBundles, and the Encrypted Bundles Enforcement section in the template all line up with the neworgs.enforce_encrypted_bundlescolumn and messages keys. Permission gating viahasOrgPermandisSavingmatches 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 ofget_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
getAppOrganizationusessupabaseAdminplus anorgs!inner(enforce_encrypted_bundles)join, which is appropriate for reading org-level security flags while bypassing RLS, and still sits behind the explicithasAppRightApikeycheck so unauthorized API keys can’t probe other orgs.checkEncryptedBundleEnforcementmirrors the DB semantics (non-emptysession_keywhen the org requires encryption) and surfaces a clearencryption_requirederror code for the API layer.createBundlenow:
- validates inputs,
- enforces app write permissions,
- fetches the app+org, then
- enforces encryption before inserting, and
- passes
appWithOrg.owner_orginto the insert, ensuring the DB trigger sees the correct org even when callers don’t explicitly sendowner_org.If you ever want to avoid duplicating the enforcement logic in TS and SQL, you could call the
check_org_encrypted_bundle_enforcementfunction 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
📒 Files selected for processing (8)
messages/en.jsonsrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqltests/build_time_tracking.test.tstests/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.tstests/build_time_tracking.test.tssrc/pages/settings/organization/Security.vuesupabase/functions/_backend/public/bundle/create.tssrc/types/supabase.types.tssupabase/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.tstests/build_time_tracking.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode with path aliases mapping
~/tosrc/
Files:
tests/enforce-encrypted-bundles.test.tstests/build_time_tracking.test.tssupabase/functions/_backend/public/bundle/create.tssrc/types/supabase.types.tssupabase/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.tsincludinggetEndpointUrl(path)for correct worker routing andUSE_CLOUDFLARE_WORKERS=truefor CF Workers testing
Files:
tests/enforce-encrypted-bundles.test.tstests/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.tstests/build_time_tracking.test.tssupabase/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
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue componentsUse 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 withunplugin-vue-routerand types are available insrc/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_gofor native mobile functionality
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/pages/settings/organization/Security.vuesrc/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
konstaanywhere else in the app
Files:
src/pages/settings/organization/Security.vuesrc/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.tssupabase/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.tssupabase/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 insupabase/functions/_backend/as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
UsecreateHonofromutils/hono.tsfor all Hono framework application initialization and routing
All database operations must usegetPgClient()orgetDrizzleClient()fromutils/pg.tsfor PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must acceptContext<MiddlewareKeyVariables>and usec.get('requestId'),c.get('apikey'), andc.get('auth')for request context
Use structured logging withcloudlog({ requestId: c.get('requestId'), message: '...' })for all backend logging
UsemiddlewareAPISecretfor internal API endpoints andmiddlewareKeyfor external API keys; validate againstowner_orgin theapikeystable
Checkc.get('auth')?.authTypeto determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns withschemafrompostgress_schema.tsfor all database operations; usealiasV2()for self-joins or multiple table references
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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:backendfor backend files
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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, usesupabase 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 theprocess_all_cron_tasksfunction 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.vuesrc/types/supabase.types.tssupabase/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.vuesupabase/functions/_backend/public/bundle/create.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsrc/types/supabase.types.tssupabase/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.tssupabase/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.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsrc/types/supabase.types.tssupabase/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 scopedThe 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/Updatecorrectly include the newenforce_encrypted_bundlesboolean, matching the added column.- New functions
check_org_encrypted_bundle_enforcementandis_bundle_encryptedhave argument and return types that align with their SQL definitions.find_apikey_by_valuenow exposesexpires_at, which fits theapikeys.Rowshape and supports theis_apikey_expiredcheck inget_orgs_v7().- Both
get_orgs_v7overloads now surfaceenforce_encrypted_bundlesand keep theuuid-parameter variant non-public, while the no-arg wrapper remains granted toanon/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
impactedMemberslist, 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 qualifiespublicin the function usingSET search_path = '', which is good practice.public.check_org_encrypted_bundle_enforcement(org_id uuid, session_key text)mirrors the same semantics, logs viapublic.pg_logwhen enforcement blocks an upload, and returns a boolean “allow/deny” flag as advertised.- EXECUTE is granted only to
authenticatedandservice_role, which is appropriate for backend/API usage.No issues here.
156-335:get_orgs_v7changes correctly surface encryption flag and maintain access-control pattern
- The
get_orgs_v7(userid uuid)body now includeso.enforce_encrypted_bundlesin its projection, alongside existing security fields (2FA and password policy redaction viashould_redact_2fa/should_redact_password), which matches the new org column.- As per prior guidance, this
uuid-parameter overload is revoked fromPUBLIC/anon/authenticatedand only granted topostgresandservice_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_orgswhen present.- Delegates to
get_orgs_v7(user_id)and exposes the newenforce_encrypted_bundlesfield in its return type.- Is granted to
anon,authenticated, andservice_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
randomUUIDfor 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_keyvs null. The nestedbeforeAll/afterAllproperly 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 stringcasts are necessary workarounds for the TypeScript types expecting non-null strings while testing null behavior.
412-428: LGTM!Test correctly validates that
get_orgs_v7includes the newenforce_encrypted_bundlesfield. 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_bundlesfield is correctly typed: non-nullable inRow(DB has default), optional inInsertandUpdate. This aligns with the database migration that setsDEFAULT false.
2235-2238: LGTM!New RPC function type
check_org_encrypted_bundle_enforcementcorrectly defined with required parameters and boolean return type.
2863-2863: LGTM!
is_bundle_encryptedfunction type correctly added withsession_keystring parameter and boolean return.
2990-2993: LGTM!
reject_access_due_to_2fa_for_orgfunction 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: booleancorrectly added to bothget_orgs_v7overloads.Note:
max_apikey_expiration_dayschanged fromnumber | nulltonumber. This suggests the view now coalesces null values. Verify this is intentional and that frontend consumers handle this correctly.
37-86: LGTM!
expires_atfield correctly added toapikeystable types. The nullable type allows for keys without expiration.
| 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' |
There was a problem hiding this comment.
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.
| 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.
There was a problem hiding this comment.
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_timerecords 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
📒 Files selected for processing (2)
tests/build_time_tracking.test.tstests/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.tstests/build_time_tracking.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode with path aliases mapping
~/tosrc/
Files:
tests/test-utils.tstests/build_time_tracking.test.ts
tests/**/*.{ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Backend tests must use helpers from
tests/test-utils.tsincludinggetEndpointUrl(path)for correct worker routing andUSE_CLOUDFLARE_WORKERS=truefor CF Workers testing
Files:
tests/test-utils.tstests/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.tstests/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_EMAILas unused, but it's now used on line 50 for themanagement_emailfield. The import is valid and necessary.
5-7: LGTM! Dedicated test constants improve isolation.Using
BUILD_TIME_ORG_IDandBUILD_TIME_STRIPE_CUSTOMER_IDprevents 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
upsertand 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.
daabdc9 to
2017d02
Compare
There was a problem hiding this comment.
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 ofmax_apikey_expiration_daysinget_orgs_v7return typeIn both overloads of
get_orgs_v7, the return surface types modelmax_apikey_expiration_daysasnumber, but the underlying source columnorgs.max_apikey_expiration_daysis nullable and the SQLSELECTin the migration passes it through without aCOALESCE. If the column can still beNULLat runtime, callers may seenulleven though the type isnumber.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_dayshere tonumber | 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. TheTEST_EMAILimport is correctly used on line 49 for the org's management email.Note: The previous review flagged
TEST_EMAILas 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:
encrypted-bundles-enforcement-disabledencrypted-bundles-enforcement-enabledenforce-encrypted-bundlesenforce-encrypted-bundles-descriptionhashed-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” wordingThe 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 nitThe 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 consistentThe 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 terminologyElsewhere 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 stringsMost 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 stringsThis 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 consistencyMost 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.jsonincludes additional keys likeencrypted-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 typesThe 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_v7return type formax_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
📒 Files selected for processing (22)
messages/de.jsonmessages/en.jsonmessages/es.jsonmessages/fr.jsonmessages/hi.jsonmessages/id.jsonmessages/it.jsonmessages/ja.jsonmessages/ko.jsonmessages/pl.jsonmessages/pt-br.jsonmessages/ru.jsonmessages/tr.jsonmessages/vi.jsonmessages/zh-cn.jsonsrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqltests/build_time_tracking.test.tstests/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.tstests/build_time_tracking.test.tssrc/pages/settings/organization/Security.vuesupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssrc/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.tstests/build_time_tracking.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode with path aliases mapping
~/tosrc/
Files:
tests/enforce-encrypted-bundles.test.tstests/build_time_tracking.test.tssupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssrc/types/supabase.types.ts
tests/**/*.{ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Backend tests must use helpers from
tests/test-utils.tsincludinggetEndpointUrl(path)for correct worker routing andUSE_CLOUDFLARE_WORKERS=truefor CF Workers testing
Files:
tests/enforce-encrypted-bundles.test.tstests/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.tstests/build_time_tracking.test.tssupabase/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
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue componentsUse 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 withunplugin-vue-routerand types are available insrc/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_gofor native mobile functionality
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/pages/settings/organization/Security.vuesrc/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
konstaanywhere else in the app
Files:
src/pages/settings/organization/Security.vuesrc/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.tssupabase/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.tssupabase/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 insupabase/functions/_backend/as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
UsecreateHonofromutils/hono.tsfor all Hono framework application initialization and routing
All database operations must usegetPgClient()orgetDrizzleClient()fromutils/pg.tsfor PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must acceptContext<MiddlewareKeyVariables>and usec.get('requestId'),c.get('apikey'), andc.get('auth')for request context
Use structured logging withcloudlog({ requestId: c.get('requestId'), message: '...' })for all backend logging
UsemiddlewareAPISecretfor internal API endpoints andmiddlewareKeyfor external API keys; validate againstowner_orgin theapikeystable
Checkc.get('auth')?.authTypeto determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns withschemafrompostgress_schema.tsfor all database operations; usealiasV2()for self-joins or multiple table references
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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:backendfor backend files
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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, usesupabase 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 theprocess_all_cron_tasksfunction 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.tstests/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.vuesupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssrc/types/supabase.types.tssupabase/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.tssupabase/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.tssupabase/functions/_backend/utils/supabase.types.tssrc/types/supabase.types.tssupabase/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 accurateThe 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 wordingThe 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 featureThe 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_encryptedandcheck_org_encrypted_bundle_enforcementRPCs. Theget_orgs_v7test correctly verifies the new field is included.supabase/functions/_backend/public/bundle/create.ts (3)
132-138: LGTM!The
AppWithOrginterface properly models the joined query result with enforcement-related fields from theorgstable.
140-153: LGTM!Using
supabaseAdminis 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_orgis 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
orgsRow/Insert/Update now exposeenforce_encrypted_bundlesandrequired_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 cleanlyFetching
enforce_encrypted_bundlesandrequired_encryption_keyfromorgsand wiring them intoenforceEncryptedBundles/requiredEncryptionKeykeeps 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 derivesorg_idand closes the earlier ordering holeThe new
check_encrypted_bundle_on_inserttrigger:
- Uses
NEW.owner_orgwhen present, otherwise looks upapps.owner_orgbyNEW.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_orgcould be bypassed because the auto‑owner trigger ran later, and ensures enforcement even for inserts that omitowner_org. The logging payloads also look suitably detailed for debugging.Also applies to: 149-198, 206-213
| 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 | ||
| } |
There was a problem hiding this comment.
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 DEFINERwithGRANT 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_roleand enforces that the caller is a super_admin of the target org before invokingdelete_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.
988fd31 to
9154ac3
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (3)
src/pages/settings/organization/Security.vue (2)
432-447: Treat failures incountNonCompliantBundlesas blocking, not "zero non‑compliant"
countNonCompliantBundlesreturnsnullon RPC error, but callers at lines 465-497 and 591-621 treatcounts === nullas "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_bundlescannot be safely invoked directly from the frontend
saveEncryptedBundlesEnforcementcallssupabase.rpc('delete_non_compliant_bundles', ...)but this function isSECURITY DEFINERwithGRANT 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_roleand enforces that the caller is a super_admin of the target org before invokingdelete_non_compliant_bundles.supabase/migrations/20260101042511_enforce_encrypted_bundles.sql (1)
503-550: Tighten access tocount_non_compliant_bundlesto avoid cross‑tenant data leakage
count_non_compliant_bundlesisSECURITY DEFINERand bypasses RLS onapp_versions/apps, but it is granted to"authenticated"as well as"service_role". Because it only takesorg_idas input and does no membership checks, any authenticated user could call it with arbitraryorg_idvalues 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_roleonly (similar todelete_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
patternattribute 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 optionalThe 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: PrefergetEndpointUrl('/bundle')over interpolatingBASE_URLTo stay aligned with the backend test guidelines and ensure correct routing when
USE_CLOUDFLARE_WORKERSis toggled, consider replacing${BASE_URL}/bundlewithgetEndpointUrl('/bundle')fromtest-utilsin these tests.As per coding guidelines, backend tests should use the shared helpers from
tests/test-utils.tsfor 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 testsThis 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) andget_orgs_v7surfacingenforce_encrypted_bundles.One follow‑up worth considering is adding tests that exercise the new
count_non_compliant_bundlesanddelete_non_compliant_bundlesfunctions 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 fororgsjoinThe new flow looks good:
- You resolve
appWithOrgviasupabaseAdminand then runcheckEncryptedBundleEnforcementbefore checking version existence and inserting.checkEncryptedBundleEnforcementmatches the SQL trigger semantics for bothsession_keypresence andrequired_encryption_key/key_idprefix matching, so API‑ and DB‑level enforcement should be consistent.Two small follow‑ups you might consider:
AppWithOrgis obtained viaas unknown as AppWithOrgand assumesorgs!inner(...)yields a single object. To guard against shape changes (e.g., array vs object) and keep type safety, you could derive this type fromDatabase['public']['Tables']['apps']['Row']/orgsand normalize theorgsfield (e.g.,const org = Array.isArray(app.orgs) ? app.orgs[0] : app.orgs) before using it.- Since the enforcement rules are now duplicated between this helper and
check_encrypted_bundle_on_insertin 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-jsjoin 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_encryptedtakes asession_keyparameter, suggesting it validates whether a session key indicates encryption. The name could be more precise (e.g.,is_session_key_encryptedorhas_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
📒 Files selected for processing (22)
messages/de.jsonmessages/en.jsonmessages/es.jsonmessages/fr.jsonmessages/hi.jsonmessages/id.jsonmessages/it.jsonmessages/ja.jsonmessages/ko.jsonmessages/pl.jsonmessages/pt-br.jsonmessages/ru.jsonmessages/tr.jsonmessages/vi.jsonmessages/zh-cn.jsonsrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/functions/_backend/public/bundle/create.tssupabase/functions/_backend/utils/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqltests/build_time_tracking.test.tstests/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.tstests/build_time_tracking.test.tssupabase/functions/_backend/public/bundle/create.tssrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/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.tstests/build_time_tracking.test.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode with path aliases mapping
~/tosrc/
Files:
tests/enforce-encrypted-bundles.test.tstests/build_time_tracking.test.tssupabase/functions/_backend/public/bundle/create.tssrc/types/supabase.types.tssupabase/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.tsincludinggetEndpointUrl(path)for correct worker routing andUSE_CLOUDFLARE_WORKERS=truefor CF Workers testing
Files:
tests/enforce-encrypted-bundles.test.tstests/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.tstests/build_time_tracking.test.tssupabase/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.tssupabase/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.tssupabase/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 insupabase/functions/_backend/as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
UsecreateHonofromutils/hono.tsfor all Hono framework application initialization and routing
All database operations must usegetPgClient()orgetDrizzleClient()fromutils/pg.tsfor PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must acceptContext<MiddlewareKeyVariables>and usec.get('requestId'),c.get('apikey'), andc.get('auth')for request context
Use structured logging withcloudlog({ requestId: c.get('requestId'), message: '...' })for all backend logging
UsemiddlewareAPISecretfor internal API endpoints andmiddlewareKeyfor external API keys; validate againstowner_orgin theapikeystable
Checkc.get('auth')?.authTypeto determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns withschemafrompostgress_schema.tsfor all database operations; usealiasV2()for self-joins or multiple table references
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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:backendfor backend files
Files:
supabase/functions/_backend/public/bundle/create.tssupabase/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
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue componentsUse 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 withunplugin-vue-routerand types are available insrc/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_gofor native mobile functionality
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/pages/settings/organization/Security.vuesrc/types/supabase.types.ts
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/pages/settings/organization/Security.vuesrc/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
konstaanywhere else in the app
Files:
src/pages/settings/organization/Security.vuesrc/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, usesupabase 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 theprocess_all_cron_tasksfunction 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.tstests/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.tssupabase/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.tssrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsupabase/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.tssrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsupabase/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()forORG_ID,STRIPE_CUSTOMER_ID, andAPPNAMEensures proper test isolation and avoids conflicts with parallel test runs. TheTEST_EMAILimport on line 3 is correctly used on line 49 for themanagement_emailfield, so the previous review comment flagging it as unused is now outdated.
15-74: Well-structured test setup with proper isolation.The
beforeAllhook correctly establishes the test context by:
- Creating dedicated
stripe_infowith a unique customer ID- Creating a dedicated org linked to that customer
- Ensuring the test user is a
super_adminmember (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):
build_logs→daily_build_time→app_versions→apps→org_users→orgs→stripe_infoThis 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 solidIsolated org/app/stripe fixtures with symmetric cleanup in
afterAllare 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 correctlyDeriving
org_idfromNEW.owner_orgwhen present or frompublic.appsviaNEW.app_idotherwise neatly avoids the previous ordering issue withforce_valid_owner_org_app_versions. The trigger then:
- Skips enforcement when the org doesn’t enforce encrypted bundles.
- Rejects missing/empty
session_keywith a clear error and audit log.- Enforces
required_encryption_keyvia a prefix match onkey_idconsistent 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 privateThe updated
get_orgs_v7(userid uuid):
- Extends the return shape with
enforce_encrypted_bundlesandrequired_encryption_key.- Leaves all the existing 2FA/password‑policy redaction logic intact.
- Is explicitly revoked from
PUBLIC/anon/authenticatedand only granted topostgresandservice_role.The wrapper
get_orgs_v7()remainsSECURITY DEFINER, handles API key vs session identity, and is granted toanon/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 schemaThe added
enforce_encrypted_bundles/required_encryption_keyfields onorgsand the new/extended function typings (is_bundle_encrypted,check_org_encrypted_bundle_enforcement,count_non_compliant_bundles,delete_non_compliant_bundles,get_orgs_v7extras) all line up with the SQL migration. The tests intests/enforce-encrypted-bundles.test.tsare 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_enforcementfunction is properly typed with clear parameters. Note thatsession_key(bundle encryption data) differs fromrequired_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_bundlesanddelete_non_compliant_bundlesfunctions provide appropriate signatures for managing encryption compliance. The optionalrequired_keyparameter 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_bundlesis required in Row (implying a database default) and optional in Insert/Update, whilerequired_encryption_keyis appropriately nullable across all contexts.The
required_encryption_keyfield 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.
| 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')) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Search for the translation key in the codebase
rg "encrypted-bundles-enforcement-enabled-with-deletion" --type-list | head -20Repository: 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 -30Repository: 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 -50Repository: 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 -50Repository: 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.jsonRepository: 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 -lRepository: 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.vueRepository: 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
doneRepository: 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.
| logo: string | ||
| management_email: string | ||
| max_apikey_expiration_days: number | null | ||
| max_apikey_expiration_days: number |
There was a problem hiding this comment.
🧩 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 100Repository: 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=sqlRepository: 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.tsRepository: 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.
There was a problem hiding this comment.
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 layerThe
enforce_encrypted_bundlesandrequired_encryption_keycolumns 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
📒 Files selected for processing (6)
messages/en.jsonsrc/pages/settings/organization/Security.vuesrc/types/supabase.types.tssupabase/functions/_backend/utils/supabase.types.tssupabase/migrations/20260101042511_enforce_encrypted_bundles.sqltests/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
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue componentsUse 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.vuesupabase/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 withunplugin-vue-routerand types are available insrc/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_gofor 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 fromsrc/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:fixto 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
konstaanywhere 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, usesupabase 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 theprocess_all_cron_tasksfunction 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
~/tosrc/
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 insupabase/functions/_backend/as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
UsecreateHonofromutils/hono.tsfor all Hono framework application initialization and routing
All database operations must usegetPgClient()orgetDrizzleClient()fromutils/pg.tsfor PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must acceptContext<MiddlewareKeyVariables>and usec.get('requestId'),c.get('apikey'), andc.get('auth')for request context
Use structured logging withcloudlog({ requestId: c.get('requestId'), message: '...' })for all backend logging
UsemiddlewareAPISecretfor internal API endpoints andmiddlewareKeyfor external API keys; validate againstowner_orgin theapikeystable
Checkc.get('auth')?.authTypeto determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns withschemafrompostgress_schema.tsfor all database operations; usealiasV2()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:backendfor 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.vuesupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsupabase/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.vuesupabase/migrations/20260101042511_enforce_encrypted_bundles.sqlsupabase/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 positiveThe 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_bundlesandrequired_encryption_keyare wired throughRow/Insert/Updatewith 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 surfacesThe 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_v7return 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)andcheck_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 withpg_logcalls 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 modelThe rewritten
get_orgs_v7(userid)and its no-arg wrapper:
- Preserve the existing 2FA/password redaction model,
- Add
enforce_encrypted_bundlesandrequired_encryption_keyto the returned shape, and- Keep the
uuid-parameterized variant restricted topostgres/service_roleonly, 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, andnonCompliantBundleCountsare initialized and kept in sync with theorgsrow (enforce_encrypted_bundles,required_encryption_key) vialoadData, 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
saveEncryptedBundlesEnforcementfor 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-completeThe new “Encrypted Bundles” section:
- Reuses the existing toggle pattern with proper
hasOrgPerm/isSavingdisabling,- 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
nonCompliantBundleCountsand 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 logicThe introduction of
IconFingerprintand updated header/description for the password policy section are purely presentational and do not alter the underlying behavior ofpolicyEnabledor the associated handlers (handlePolicyToggle,updatePasswordPolicy). The visual change is self-contained and consistent with the rest of the settings UI.
There was a problem hiding this comment.
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.35but the test forces7.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 nowbeforeAll/afterAllignore 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: Avoidnull as unknown as stringin 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.usersinserts, but this is easy to break over time—consider adding a short comment pointing to the correspondingpublic.usersrows forcli_hashed@capgo.appandencrypted@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_keycolumns (relying on DB defaults). If tests assume a known default state, you may want to include them explicitly forEncrypted 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
📒 Files selected for processing (21)
messages/de.jsonmessages/en.jsonmessages/es.jsonmessages/fr.jsonmessages/hi.jsonmessages/id.jsonmessages/it.jsonmessages/ja.jsonmessages/ko.jsonmessages/pl.jsonmessages/pt-br.jsonmessages/ru.jsonmessages/tr.jsonmessages/vi.jsonmessages/zh-cn.jsonsrc/types/supabase.types.tssupabase/functions/_backend/utils/supabase.types.tssupabase/seed.sqltests/enforce-encrypted-bundles.test.tstests/test-utils.tstests/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.tsincludinggetEndpointUrl(path)for correct worker routing andUSE_CLOUDFLARE_WORKERS=truefor CF Workers testing
Files:
tests/updates.test.tstests/test-utils.tstests/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.tstests/test-utils.tstests/enforce-encrypted-bundles.test.tssupabase/functions/_backend/utils/supabase.types.tssrc/types/supabase.types.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Use path aliases:
~/maps tosrc/for imports in TypeScript files
Files:
tests/updates.test.tstests/test-utils.tstests/enforce-encrypted-bundles.test.tssupabase/functions/_backend/utils/supabase.types.tssrc/types/supabase.types.ts
supabase/seed.sql
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Seed database with
supabase db resetto apply all migrations and test data fromsupabase/seed.sqlUpdate
supabase/seed.sqlto 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 insupabase/functions/_backend/as shared code deployed to Cloudflare Workers (API/Plugin/Files workers), Supabase Edge Functions, and other platforms
UsecreateHonofromutils/hono.tsfor all Hono framework application initialization and routing
All database operations must usegetPgClient()orgetDrizzleClient()fromutils/pg.tsfor PostgreSQL access during active migration to Cloudflare D1
All Hono endpoint handlers must acceptContext<MiddlewareKeyVariables>and usec.get('requestId'),c.get('apikey'), andc.get('auth')for request context
Use structured logging withcloudlog({ requestId: c.get('requestId'), message: '...' })for all backend logging
UsemiddlewareAPISecretfor internal API endpoints andmiddlewareKeyfor external API keys; validate againstowner_orgin theapikeystable
Checkc.get('auth')?.authTypeto determine authentication type ('apikey' vs 'jwt') in backend endpoints
Use Drizzle ORM query patterns withschemafrompostgress_schema.tsfor all database operations; usealiasV2()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:backendfor 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 fromsrc/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:fixto 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.sqlsupabase/functions/_backend/utils/supabase.types.tssrc/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.sqlsrc/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.sqlsupabase/functions/_backend/utils/supabase.types.tssrc/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_ENCRYPTEDconstant uses a UUID format (b8c9d0e1-f2a3-4b4c-9d5e-6f7a8b9c0d14), which is appropriate for a test constant intests/test-utils.tsand 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 insertcus_encrypted_test_123to avoid unique conflicts.
248-249: public.users additions: OK, but keep trigger-disable scope tight.Good use of
DISABLE TRIGGER generate_org_on_user_createaround 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 anypublic.app_versionsrows 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_bundlesandrequired_encryption_keypropagation across Row/Insert/Update looks consistent.
2235-2238: Verify DB signature + GRANTs forcheck_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(*)/bigintinternally, PostgREST can sometimes surface values as strings. Since the generated types saynumber, please confirm the actual return types and generated typings align (or cast in SQL toint/numericas needed).Also applies to: 2316-2319, 2856-2857
2591-2657: Theget_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 wrapperget_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).
| check_org_encrypted_bundle_enforcement: { | ||
| Args: { org_id: string; session_key: string } | ||
| Returns: boolean | ||
| } |
There was a problem hiding this comment.
🧩 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 -20Repository: 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 -20Repository: 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 -50Repository: 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.tsRepository: 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 -40Repository: 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 -60Repository: 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 -40Repository: 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 -60Repository: 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.
| 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') | ||
| } | ||
| }) |
There was a problem hiding this comment.
🧩 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"
fiRepository: 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"
fiRepository: 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.tsRepository: 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 -30Repository: 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 -50Repository: 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.tsRepository: 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.jsonRepository: 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 -60Repository: 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 3Repository: 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 -50Repository: 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.tsRepository: 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 2Repository: 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 -70Repository: 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.tsRepository: 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 -120Repository: 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"
fiRepository: 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>
3778279 to
18d980c
Compare
Resolve conflict in tests/updates.test.ts - keep plugin_version 7.1.0
…les test Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|




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
bun test:backend --testNamePattern="Encrypted Bundles Enforcement"to verify all 17 tests passencryption_requiredcodeChecklist
bun run lint:backend && bun run lint🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Improvements
Localization
Tests
✏️ Tip: You can customize this high-level summary in your review settings.