Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions messages/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,26 @@
"actionDeleteResourceRule": "Delete Resource Rule",
"actionListResourceRules": "List Resource Rules",
"actionUpdateResourceRule": "Update Resource Rule",
"ruleTemplates": "Rule Templates",
"ruleTemplatesDescription": "Assign rule templates to automatically apply consistent rules across multiple resources",
"ruleTemplatesSearch": "Search templates...",
"ruleTemplateAdd": "Create Template",
"ruleTemplateErrorDelete": "Failed to delete template",
"ruleTemplateCreated": "Template created",
"ruleTemplateCreatedDescription": "Rule template created successfully",
"ruleTemplateErrorCreate": "Failed to create template",
"ruleTemplateErrorCreateDescription": "An error occurred while creating the template",
"ruleTemplateSetting": "Rule Template Settings",
"ruleTemplateSettingDescription": "Manage template details and rules",
"ruleTemplateErrorLoad": "Failed to load template",
"ruleTemplateErrorLoadDescription": "An error occurred while loading the template",
"ruleTemplateUpdated": "Template updated",
"ruleTemplateUpdatedDescription": "Template updated successfully",
"ruleTemplateErrorUpdate": "Failed to update template",
"ruleTemplateErrorUpdateDescription": "An error occurred while updating the template",
"save": "Save",
"saving": "Saving...",
"templateDetails": "Template Details",
"actionListOrgs": "List Organizations",
"actionCheckOrgId": "Check ID",
"actionCreateOrg": "Create Organization",
Expand Down Expand Up @@ -1093,6 +1113,7 @@
"sidebarInvitations": "Invitations",
"sidebarRoles": "Roles",
"sidebarShareableLinks": "Shareable Links",
"sidebarRuleTemplates": "Rule Templates",
"sidebarApiKeys": "API Keys",
"sidebarSettings": "Settings",
"sidebarAllUsers": "All Users",
Expand Down
39 changes: 39 additions & 0 deletions server/db/pg/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,49 @@ export const resourceRules = pgTable("resourceRules", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
templateRuleId: integer("templateRuleId")
.references(() => templateRules.ruleId, { onDelete: "cascade" }),
enabled: boolean("enabled").notNull().default(true),
priority: integer("priority").notNull(),
action: varchar("action").notNull(), // ACCEPT, DROP
match: varchar("match").notNull(), // CIDR, PATH, IP
value: varchar("value").notNull()
});

// Rule templates (reusable rule sets)
export const ruleTemplates = pgTable("ruleTemplates", {
templateId: varchar("templateId").primaryKey(),
orgId: varchar("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
name: varchar("name").notNull(),
description: varchar("description"),
createdAt: bigint("createdAt", { mode: "number" }).notNull()
});

// Rules within templates
export const templateRules = pgTable("templateRules", {
ruleId: serial("ruleId").primaryKey(),
templateId: varchar("templateId")
.notNull()
.references(() => ruleTemplates.templateId, { onDelete: "cascade" }),
enabled: boolean("enabled").notNull().default(true),
priority: integer("priority").notNull(),
action: varchar("action").notNull(), // ACCEPT, DROP
match: varchar("match").notNull(), // CIDR, IP, PATH
value: varchar("value").notNull()
});

// Template assignments to resources
export const resourceTemplates = pgTable("resourceTemplates", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
templateId: varchar("templateId")
.notNull()
.references(() => ruleTemplates.templateId, { onDelete: "cascade" })
});

export const supporterKey = pgTable("supporterKey", {
keyId: serial("keyId").primaryKey(),
key: varchar("key").notNull(),
Expand Down Expand Up @@ -637,3 +673,6 @@ export type OlmSession = InferSelectModel<typeof olmSessions>;
export type UserClient = InferSelectModel<typeof userClients>;
export type RoleClient = InferSelectModel<typeof roleClients>;
export type OrgDomains = InferSelectModel<typeof orgDomains>;
export type RuleTemplate = InferSelectModel<typeof ruleTemplates>;
export type TemplateRule = InferSelectModel<typeof templateRules>;
export type ResourceTemplate = InferSelectModel<typeof resourceTemplates>;
39 changes: 39 additions & 0 deletions server/db/sqlite/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -534,13 +534,49 @@ export const resourceRules = sqliteTable("resourceRules", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
templateRuleId: integer("templateRuleId")
.references(() => templateRules.ruleId, { onDelete: "cascade" }),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
priority: integer("priority").notNull(),
action: text("action").notNull(), // ACCEPT, DROP
match: text("match").notNull(), // CIDR, PATH, IP
value: text("value").notNull()
});

// Rule templates (reusable rule sets)
export const ruleTemplates = sqliteTable("ruleTemplates", {
templateId: text("templateId").primaryKey(),
orgId: text("orgId")
.notNull()
.references(() => orgs.orgId, { onDelete: "cascade" }),
name: text("name").notNull(),
description: text("description"),
createdAt: integer("createdAt").notNull()
});

// Rules within templates
export const templateRules = sqliteTable("templateRules", {
ruleId: integer("ruleId").primaryKey({ autoIncrement: true }),
templateId: text("templateId")
.notNull()
.references(() => ruleTemplates.templateId, { onDelete: "cascade" }),
enabled: integer("enabled", { mode: "boolean" }).notNull().default(true),
priority: integer("priority").notNull(),
action: text("action").notNull(), // ACCEPT, DROP
match: text("match").notNull(), // CIDR, IP, PATH
value: text("value").notNull()
});

// Template assignments to resources
export const resourceTemplates = sqliteTable("resourceTemplates", {
resourceId: integer("resourceId")
.notNull()
.references(() => resources.resourceId, { onDelete: "cascade" }),
templateId: text("templateId")
.notNull()
.references(() => ruleTemplates.templateId, { onDelete: "cascade" })
});

export const supporterKey = sqliteTable("supporterKey", {
keyId: integer("keyId").primaryKey({ autoIncrement: true }),
key: text("key").notNull(),
Expand Down Expand Up @@ -679,3 +715,6 @@ export type ApiKey = InferSelectModel<typeof apiKeys>;
export type ApiKeyAction = InferSelectModel<typeof apiKeyActions>;
export type ApiKeyOrg = InferSelectModel<typeof apiKeyOrg>;
export type OrgDomains = InferSelectModel<typeof orgDomains>;
export type RuleTemplate = InferSelectModel<typeof ruleTemplates>;
export type TemplateRule = InferSelectModel<typeof templateRules>;
export type ResourceTemplate = InferSelectModel<typeof resourceTemplates>;
1 change: 1 addition & 0 deletions server/openApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export enum OpenAPITags {
Invitation = "Invitation",
Target = "Target",
Rule = "Rule",
RuleTemplate = "Rule Template",
AccessToken = "Access Token",
Idp = "Identity Provider",
Client = "Client",
Expand Down
75 changes: 75 additions & 0 deletions server/routers/external.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as accessToken from "./accessToken";
import * as idp from "./idp";
import * as license from "./license";
import * as apiKeys from "./apiKeys";
import * as ruleTemplate from "./ruleTemplate";
import HttpCode from "@server/types/HttpCode";
import {
verifyAccessTokenAccess,
Expand Down Expand Up @@ -339,6 +340,80 @@ authenticated.delete(
resource.deleteResourceRule
);

// Rule template routes
authenticated.post(
"/org/:orgId/rule-templates",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
ruleTemplate.createRuleTemplate
);
authenticated.get(
"/org/:orgId/rule-templates",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listResourceRules),
ruleTemplate.listRuleTemplates
);
authenticated.get(
"/org/:orgId/rule-templates/:templateId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listResourceRules),
ruleTemplate.getRuleTemplate
);
authenticated.put(
"/org/:orgId/rule-templates/:templateId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
ruleTemplate.updateRuleTemplate
);
authenticated.get(
"/org/:orgId/rule-templates/:templateId/rules",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.listResourceRules),
ruleTemplate.listTemplateRules
);
authenticated.post(
"/org/:orgId/rule-templates/:templateId/rules",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
ruleTemplate.addTemplateRule
);
authenticated.put(
"/org/:orgId/rule-templates/:templateId/rules/:ruleId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
ruleTemplate.updateTemplateRule
);
authenticated.delete(
"/org/:orgId/rule-templates/:templateId/rules/:ruleId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.deleteResourceRule),
ruleTemplate.deleteTemplateRule
);
authenticated.delete(
"/org/:orgId/rule-templates/:templateId",
verifyOrgAccess,
verifyUserHasAction(ActionsEnum.deleteResourceRule),
ruleTemplate.deleteRuleTemplate
);
authenticated.put(
"/resource/:resourceId/templates/:templateId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.createResourceRule),
ruleTemplate.assignTemplateToResource
);
authenticated.delete(
"/resource/:resourceId/templates/:templateId",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.deleteResourceRule),
ruleTemplate.unassignTemplateFromResource
);
authenticated.get(
"/resource/:resourceId/templates",
verifyResourceAccess,
verifyUserHasAction(ActionsEnum.listResourceRules),
ruleTemplate.listResourceTemplates
);

authenticated.get(
"/target/:targetId",
verifyTargetAccess,
Expand Down
1 change: 1 addition & 0 deletions server/routers/resource/listResourceRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function queryResourceRules(resourceId: number) {
.select({
ruleId: resourceRules.ruleId,
resourceId: resourceRules.resourceId,
templateRuleId: resourceRules.templateRuleId,
action: resourceRules.action,
match: resourceRules.match,
value: resourceRules.value,
Expand Down
Loading
Loading