Skip to content

feat: selfhost layer#88

Merged
imrim12 merged 18 commits into
mainfrom
feat/selfhost-layer
Jun 8, 2026
Merged

feat: selfhost layer#88
imrim12 merged 18 commits into
mainfrom
feat/selfhost-layer

Conversation

@imrim12

@imrim12 imrim12 commented Jun 2, 2026

Copy link
Copy Markdown
Member

No description provided.

@gitguardian

gitguardian Bot commented Jun 2, 2026

Copy link
Copy Markdown

⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

🔎 Detected hardcoded secret in your pull request
GitGuardian id GitGuardian status Secret Commit Filename
33536830 Triggered Generic High Entropy Secret 39d610a test/unit/crypto.test.ts View secret
🛠 Guidelines to remediate hardcoded secrets
  1. Understand the implications of revoking this secret by investigating where it is used in your code.
  2. Replace and store your secret safely. Learn here the best practices.
  3. Revoke and rotate this secret.
  4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

To avoid such incidents in the future consider


🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

HaoNguyen-Ron and others added 6 commits June 3, 2026 09:12
…ruth

Move all seed logic from server/services/ into server/tasks/seed/
(permissions, users, organizations, all). Move the six backdoor routes
into server/api/auth/demo/, tighten dev-only guards to import.meta.dev,
and exclude them from the production bundle via $production.nitro.ignore.

Add DEFAULT_ROLE_ABILITIES as the single role→permission source of truth
in shared/permissions.ts. Derive DEFAULT_PERSONAL_ORG_ABILITIES and
DEFAULT_MEMBER_ABILITIES from it. Source ensureSystemRoles and
createPersonalOrganization from the map. Ship a roles:sync Nitro task
(planRolePermissionSync + syncDefaultRolePermissions) plus a bearer-
guarded POST /api/auth/roles/sync prod trigger for rollout after map
edits.

Update all callers: e2e helper, AuthLoginCard, CLI dev commands, unit
tests, and docs. Adds a defineTask global stub for node unit tests.
Server and client now both use ability.can(action, subject). abilitiesToRules
and buildAbility live in shared/casl.ts. satisfiesAbility and canSubjectAction
are deleted. assertGrantable and route guards accept MongoAbility. The
manage→impersonate guard prevents wildcard escalation to system actions.
Phase 01 — invitation inversion: auth carries an opaque `metadata` blob;
project layer owns the `projectMemberTable` write via an `invitation:accepted`
Nitro hook. The `invitationFields` UI registry slot lets the project layer
contribute the Projects select field without auth importing `useProjectApi`.
Expand-contract: `metadata` column added, legacy `project_ids` kept for the
7-day pending-invite drain. `rg "#layers/project" layers/auth` → 0 matches.

Phase 02 — authz catalog inversion: replaced static `TENANT_SUBJECTS` /
`DEFAULT_ROLE_ABILITIES` in `shared/permissions.ts` with a server-side
`definePermissionDomain` registry. Each layer (user/project/billing/selfhost)
registers its own subjects and default-role keys; the union reproduces the
prior catalog exactly (parity test). `shared/permissions.ts` retains only
`SYSTEM_ABILITY_KEYS`, `DefaultRole`, `DEFAULT_ROLE_NAME`, and `PermissionDef`.
`OrganizationRoleModal` now fetches the catalog from `/api/permissions`.
Boot plugin asserts all 4 domains registered at startup.
Fold the credit grant into the same db.batch as the reward transaction and the reward_paid flag, so they commit (or roll back) together. Previously grantCredit ran as a separate write after the batch — if it failed, reward_paid was already true and the referrer was permanently under-paid with no retry.
imrim12 added 3 commits June 8, 2026 23:10
refreshUserSessions scanned the entire session: KV namespace (O(total live sessions)) on every permission change. Maintain a user-sessions:{userId} index at the session-write chokepoints and read only that user's sessions, with a self-healing prune of dead/reassigned ids on read (so logout/expiry/impersonation drift need no eager updates).
Bulk dispatch (up to 500 recipients) could exceed a Worker's wall-time budget when sent inline. When the DISPATCH_QUEUE binding is present, the route now composes the email once into KV and fans recipients out as queue messages drained by a cloudflare:queue consumer plugin (per-recipient retry + DLQ). Off-Cloudflare (dev/tests/unbound) it falls back to synchronous send, so the feature is safe-by-default and activates automatically once the queue is provisioned (see cloudflare/README.md). The wrangler queues block ships commented to avoid breaking the default deploy.
The credit upsert sat unconditionally in the batch, so a concurrent/duplicate delivery no-op'd the status CAS but still applied +amount again. Claim the transaction via the status CAS with .returning() and credit (grantCredit) only when the claim matched a row, so a top-up can be credited at most once.
@imrim12 imrim12 merged commit 9b972b7 into main Jun 8, 2026
4 of 5 checks passed
@imrim12 imrim12 deleted the feat/selfhost-layer branch June 8, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants