From ac528fe704226d24bd53698f8d5f0758a3a649d1 Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Fri, 21 Aug 2026 12:30:07 +0530 Subject: [PATCH 1/2] docs: use the permission key form and list all reconcile kinds --- docs/content/docs/authz/permission.mdx | 29 ++++++++++++++++--------- docs/content/docs/authz/policy.mdx | 7 +----- docs/content/docs/reference/cli.mdx | 12 ++++++---- docs/rfcs/0001-declarative-reconcile.md | 5 ++--- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/docs/content/docs/authz/permission.mdx b/docs/content/docs/authz/permission.mdx index 08498904c0..070e91f260 100644 --- a/docs/content/docs/authz/permission.mdx +++ b/docs/content/docs/authz/permission.mdx @@ -81,26 +81,35 @@ Permissions in Frontier follow a hierarchical structure, where higher-level perm Frontier allow the its platform administrators (Superusers) to create permissions to meet specific authorization requirements beyond the predefined set of permissions. Custom permissions allow for more granular control over access to resources and actions within an application or system. They enable organizations to define and enforce fine-grained access policies tailored to their unique needs. -When creating custom permissions, administrators typically define the name and scope (namespace) of the permission. The name should be descriptive and indicative of the action or resource it governs. The scope determines where the permission applies, such as the platform(making it available across all the organizations in Frontier), organization, project or group. +When creating a custom permission, an administrator gives it a `key` in the form `service.resource.verb`. The key names the service, the resource the permission acts on, and the action it grants. For example, `potato.cart.delete` grants the delete action on the cart resource of the potato service. :::note -The permissions can either be created dynamically when the Frontier is running, or can either be provided in the server configurations. +Custom permissions are created through the [reconcile flow](../reconcile.md) (a `kind: Permission` desired-state file) or through the [CreatePermission admin API](../apis/admin-service-create-permission). The older way of listing them in the server config file has been removed. ::: -For example, let's say you have an e-commerce application where users can manage their shopping carts. To control access to cart-related actions, you can create custom permissions in the **potato/cart** namespace. +For example, let's say you have an e-commerce application where users can manage their shopping carts. To control access to cart-related actions, you can create custom permissions for the cart resource. Sample custom permission requirements: -| **Permission Name** | **Permission Title** | **Namespace** | **Description** | -| ------------------- | -------------------- | ------------- | ---------------------------------------------------------- | -| **delete** | Cart Delete | potato/cart | Grants the ability to delete items from the shopping cart. | -| **update** | Cart Update | potato/cart | Allows updating the contents of the shopping cart. | -| **get** | Cart Get | potato/cart | Enables retrieving the details of the shopping cart. | +| **Key** | **Permission Title** | **Description** | +| -------------------- | -------------------- | ---------------------------------------------------------- | +| `potato.cart.delete` | Cart Delete | Grants the ability to delete items from the shopping cart. | +| `potato.cart.update` | Cart Update | Allows updating the contents of the shopping cart. | +| `potato.cart.get` | Cart Get | Enables retrieving the details of the shopping cart. | -This is how the [resource config file](https://github.com/raystack/frontier/blob/7cae6bf86e99fe96650c6dcd4e8207cb916b8184/test/e2e/smoke/testdata/resource/potato.yaml#L4) will look like +This is how the desired-state file for these permissions looks: + +```yaml +apiVersion: v1 +kind: Permission +spec: + - key: potato.cart.delete + - key: potato.cart.update + - key: potato.cart.get +``` :::info -While creating permissions, it is important to note that the namespace is appended to the permission name to generate a permission slug. For instance, the **delete** permission name will be appended with namespace **potato/cart**, to generate the final permission slug as **potato_cart_delete** in Frontier. This naming convention is used to ensure uniqueness and organization of permissions within Frontier. While creating a role, we pass the list of these permission slugs being binded to that role. +Frontier turns a permission key into a slug by replacing the dots with underscores. So `potato.cart.delete` becomes the slug `potato_cart_delete`. When you create a role, you bind it to these permission slugs. ::: ## Managing Permission diff --git a/docs/content/docs/authz/policy.mdx b/docs/content/docs/authz/policy.mdx index b3e0c75f6a..3c5daac889 100644 --- a/docs/content/docs/authz/policy.mdx +++ b/docs/content/docs/authz/policy.mdx @@ -78,12 +78,7 @@ between the principal and the object. We maintain spiceDB schema in [base_schema.zed](https://github.com/raystack/frontier/blob/4434204940f3a599b7e0ef399679f381db46c09a/internal/bootstrap/schema/base_schema.zed) file in Frontier. The schema is then used to build the base set of permissions on predefined namespaces. Some permissions are -hardcoded in the schema, but Frontier allows custom permission set on Project resources. Custom permissions are dynamically -generated at frontier boot-up by merging them in the SpiceDB schema. To create custom permissions on a project resource -a [rule set](https://github.com/raystack/frontier/blob/ccf00da8a636f363546b1dbe6c7933323c369dca/internal/bootstrap/testdata/compute_service.yml) -can be configured in the [config.yaml](https://github.com/raystack/frontier/blob/7fca56ef567791bf4ea1280aa3f9b4ae997b1bf5/config/sample.config.yaml#L29) -file. Same is also exposed in the [Frontier API](../apis/admin-service-create-permission.api.mdx) to create -custom permissions on a project resource. +hardcoded in the schema, but Frontier allows custom permission set on Project resources. Custom permissions are managed through the [reconcile flow](../reconcile.md) (a `kind: Permission` desired-state file) or the [CreatePermission admin API](../apis/admin-service-create-permission). Creating one merges it into the SpiceDB schema, so the permission is ready to use in roles right away. The older way of declaring them in the server config file has been removed. Frontier models roles as collection of permissions which can be created/updated/deleted dynamically at run time. diff --git a/docs/content/docs/reference/cli.mdx b/docs/content/docs/reference/cli.mdx index 0a101b572f..8f4c0cbf93 100644 --- a/docs/content/docs/reference/cli.mdx +++ b/docs/content/docs/reference/cli.mdx @@ -34,7 +34,7 @@ List of supported environment variables Export the current state of a kind as a desired-state YAML file, printed to stdout. The output is the format `frontier reconcile` reads: reconciling it changes nothing. Supported kinds: `PlatformUser`, `Permission`, `Role`, -`Preference`, `Webhook`. See the +`Preference`, `Webhook`, `BillingProduct`, `BillingPlan`, and `MetaSchema`. See the [Reconcile guide](../reconcile.md) for the file format and the flow. ``` @@ -250,10 +250,14 @@ Make platform resources match a desired-state YAML file, through the admin API. Supported kinds: `PlatformUser` (anyone listed is added, anyone not listed is removed), `Permission` (custom permissions), `Role` (platform-level roles), `Preference` (platform settings, where a setting -left out of the file resets to its default), and `Webhook` (webhook endpoints). +left out of the file resets to its default), `Webhook` (webhook endpoints), +`BillingProduct` (billing products and their prices), `BillingPlan` (billing +plans and the products they bundle), and `MetaSchema` (metadata validation +schemas, where a schema left out resets to its shipped default). Deleting a permission, a custom role, or a webhook needs an explicit -`delete: true` on its entry; nothing is deleted by omission, and a predefined -role cannot be deleted. Use +`delete: true` on its entry; nothing is deleted by omission, a predefined +role cannot be deleted, and a billing product or plan cannot be deleted +through the API. Use `frontier export` to print the current state in this file format, and see the [Reconcile guide](../reconcile.md) for the full flow. diff --git a/docs/rfcs/0001-declarative-reconcile.md b/docs/rfcs/0001-declarative-reconcile.md index 8afe0746e7..eaae751a81 100644 --- a/docs/rfcs/0001-declarative-reconcile.md +++ b/docs/rfcs/0001-declarative-reconcile.md @@ -16,7 +16,7 @@ file with the live server, prints a plan, and applies the difference through the be seeded from a running server. This document sets the rules every kind follows. The kinds are PlatformUser, Permission, Role, -Preference, and Webhook. New kinds plug in under the same rules without changing the commands +Preference, Webhook, MetaSchema, BillingProduct, and BillingPlan. New kinds plug in under the same rules without changing the commands or the file format. ## At a glance @@ -42,7 +42,7 @@ means and whether you can delete it: flowchart TD r["A resource the kind manages"] --> q{"Can reconcile
create and delete it?"} q -->|"yes"| o["Object
Permission, Webhook, custom Role
on the server but not in the file: the plan fails
to delete one, set delete: true"] - q -->|"no"| v["Value
PlatformUser, Preference, predefined Role
always exists, so no delete flag
not in the file: back to its default"] + q -->|"no"| v["Value
PlatformUser, Preference, predefined Role, MetaSchema
always exists, so no delete flag
not in the file: back to its default"] ``` The kinds split cleanly, except Role, which is both: a custom role is an object, a predefined @@ -286,7 +286,6 @@ roles, committed as the desired-state files, then dropping the setting from the comes from the running server instead of the CLI's compiled copy. This removes the image-version coupling. - Passing the auth token without putting it in the process arguments. -- Billing plans as a kind, replacing the boot-time plans loader. - Removing relation-based ownership from the base schema, so narrowing a predefined role restricts everyone who holds it. From d46f9a7a0071da73032b9ef486d8b994d579e55b Mon Sep 17 00:00:00 2001 From: Rohil Surana Date: Fri, 21 Aug 2026 12:30:07 +0530 Subject: [PATCH 2/2] docs: replace removed app.admin.users with the admin.bootstrap config --- docs/content/docs/basics.mdx | 14 ++++++++------ docs/content/docs/configurations.mdx | 16 +++++++++------- docs/content/docs/reference/configurations.mdx | 18 +++++++++++------- 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/docs/content/docs/basics.mdx b/docs/content/docs/basics.mdx index db958cc5ea..987857b53c 100644 --- a/docs/content/docs/basics.mdx +++ b/docs/content/docs/basics.mdx @@ -50,11 +50,13 @@ app: # platform level administration admin: - # email list of users which needs to be converted as superusers - # if the user is already present in the system, it is promoted to su - # if not, a new account is created with provided email id and promoted to su - users: - - test@example.com + # bootstrap seeds a superuser service account from config. Automation such as + # the GitOps reconcile flow logs in as it, so there is always a superuser + # without needing an existing one. Log in with: + # Authorization: Basic base64(client_id:client_secret). + bootstrap: + client_id: "" + client_secret: "" # smtp configuration for sending emails mailer: smtp_host: sandbox.smtp.mailtrap.io @@ -85,7 +87,7 @@ to host frontier at somewhere like auth.example.com and main app at anywhere in - app.authentication.session.hash_secret_key: random 32 char key - app.authentication.session.block_secret_key: random 32 char key - app.cors_origin: url of the frontend to allow cross-origin request -- admin.users: list of emails we want to be promoted as instance admins +- admin.bootstrap: client_id and client_secret for the bootstrap superuser service account that automation logs in as - app.mailer.*: all these details are used to send the email to user. Get test configurations from `mailtrap.io` for testing. - db.url: local database instance credentials in following form - `postgres://:@:/?sslmode=disable` diff --git a/docs/content/docs/configurations.mdx b/docs/content/docs/configurations.mdx index 5b25ccde3d..10f42f525f 100644 --- a/docs/content/docs/configurations.mdx +++ b/docs/content/docs/configurations.mdx @@ -147,12 +147,15 @@ app: validity: 15m # platform level administration admin: - # Email list of users which needs to be converted as superusers - # if the user is already present in the system, it is promoted to su - # if not, a new account is created with provided email id and promoted to su. - # UUIDs/slugs of existing users can also be provided instead of email ids - # but in that case a new user will not be created. - users: [] + # bootstrap seeds a superuser service account from config, using a client_id + # and client_secret. Automation such as the GitOps reconcile flow logs in as + # it, so there is always a superuser without needing an existing one. The + # account is created and promoted on every boot, and the secret is rotated if + # you change it here. Log in with: Authorization: Basic base64(client_id:client_secret). + # Leave both empty to turn this off. + bootstrap: + client_id: "" + client_secret: "" # smtp configuration for sending emails mailer: smtp_host: smtp.example.com @@ -346,7 +349,6 @@ If everything goes well, you should see something like this: ```bash 2023-05-17T00:02:54.324+0530 info frontier starting {"version": "v0.5.1"} -2023-05-17T00:02:54.331+0530 debug resource config cache refreshed {"resource_config_count": 0} 2023-05-17T00:02:54.333+0530 info Connected to spiceDB: localhost:50051 2023-05-17T00:02:54.339+0530 info metaschemas loaded {"count": 4} ``` diff --git a/docs/content/docs/reference/configurations.mdx b/docs/content/docs/reference/configurations.mdx index d82753a323..0a08afbbc8 100644 --- a/docs/content/docs/reference/configurations.mdx +++ b/docs/content/docs/reference/configurations.mdx @@ -120,12 +120,15 @@ app: validity: 15m # platform level administration admin: - # Email list of users which needs to be converted as superusers - # if the user is already present in the system, it is promoted to su - # if not, a new account is created with provided email id and promoted to su. - # UUIDs/slugs of existing users can also be provided instead of email ids - # but in that case a new user will not be created. - users: [] + # bootstrap seeds a superuser service account from config, using a client_id + # and client_secret. Automation such as the GitOps reconcile flow logs in as + # it, so there is always a superuser without needing an existing one. The + # account is created and promoted on every boot, and the secret is rotated if + # you change it here. Log in with: Authorization: Basic base64(client_id:client_secret). + # Leave both empty to turn this off. + bootstrap: + client_id: "" + client_secret: "" # smtp configuration for sending emails mailer: smtp_host: smtp.example.com @@ -271,7 +274,8 @@ Configuration to allow authentication in Frontier. | **Field** | **Description** | **Example** | **Required** | | ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------ | -| **app.admin.users** | Email list of users to be converted as superusers.
If the user is already present, they will be promoted to superuser. | | Optional | +| **app.admin.bootstrap.client_id** | Client id of the bootstrap superuser service account. Automation such as the GitOps reconcile flow logs in as it. Leave empty to turn it off. | | Optional | +| **app.admin.bootstrap.client_secret** | Client secret of the bootstrap superuser service account. The secret is rotated when you change it. | | Optional | ### Database Configurations