Compare commits

...

12 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
0bde633c5f chore: simplify policy rule update/delete lookups 2026-06-16 23:52:22 +00:00
copilot-swe-agent[bot]
a7c99f336f refactor: dedupe resource rule value validation 2026-06-16 23:50:38 +00:00
copilot-swe-agent[bot]
0d960181a2 fix: update resource rule routes to use shared policy rules 2026-06-16 23:48:46 +00:00
copilot-swe-agent[bot]
b6862093d1 Initial plan 2026-06-16 23:43:34 +00:00
Owen Schwartz
16c0f4eef4 Merge pull request #3277 from fosrl/dev
Fix middleware and suppoter footer
2026-06-14 14:44:33 -07:00
Owen Schwartz
a0fef89031 Merge pull request #3276 from fosrl/dev
Rewrite headers
2026-06-14 14:13:54 -07:00
Owen Schwartz
f15654ed11 Merge pull request #3275 from fosrl/dev
Fill in missing ui urls from the passed params
2026-06-14 11:36:01 -07:00
Owen Schwartz
0b41fe3d49 Merge pull request #3268 from fosrl/dev
Send browser gateway rsources to remote nodes
2026-06-14 11:11:06 -07:00
Owen Schwartz
b9db0a4490 Merge pull request #3261 from fosrl/dev
1.19.2
2026-06-12 15:02:58 -07:00
Owen Schwartz
d9952b0762 Merge pull request #3250 from fosrl/dev
1.19.1
2026-06-11 22:05:24 -07:00
Owen Schwartz
6e271028f3 Merge pull request #3245 from fosrl/dev
Bugfixes
2026-06-11 16:17:41 -07:00
Owen Schwartz
a724b07846 Merge pull request #3244 from fosrl/dev
fix paywalling
2026-06-11 12:27:49 -07:00
5 changed files with 109 additions and 65 deletions

View File

@@ -154,12 +154,8 @@ export async function createResourceRule(
} }
// Create the new resource rule // Create the new resource rule
const isInlinePolicy = if (resource.resourcePolicyId !== null) {
resource.resourcePolicyId === null && const policyId = resource.resourcePolicyId;
resource.defaultResourcePolicyId !== null;
if (isInlinePolicy) {
const policyId = resource.defaultResourcePolicyId!;
const [newRule] = await db const [newRule] = await db
.insert(resourcePolicyRules) .insert(resourcePolicyRules)
.values({ .values({

View File

@@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express";
import { z } from "zod"; import { z } from "zod";
import { db } from "@server/db"; import { db } from "@server/db";
import { resourceRules, resourcePolicyRules, resources } from "@server/db"; import { resourceRules, resourcePolicyRules, resources } from "@server/db";
import { eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import response from "@server/lib/response"; import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
@@ -73,14 +73,18 @@ export async function deleteResourceRule(
); );
} }
const isInlinePolicy = if (resource.resourcePolicyId !== null) {
resource.resourcePolicyId === null &&
resource.defaultResourcePolicyId !== null;
if (isInlinePolicy) {
const [deletedRule] = await db const [deletedRule] = await db
.delete(resourcePolicyRules) .delete(resourcePolicyRules)
.where(eq(resourcePolicyRules.ruleId, ruleId)) .where(
and(
eq(resourcePolicyRules.ruleId, ruleId),
eq(
resourcePolicyRules.resourcePolicyId,
resource.resourcePolicyId
)
)
)
.returning(); .returning();
if (!deletedRule) { if (!deletedRule) {

View File

@@ -141,16 +141,10 @@ export async function getResource(
); );
} }
const isInlinePolicy =
resource.resourcePolicyId === null &&
resource.defaultResourcePolicyId !== null;
let returnData = resource; let returnData = resource;
if (isInlinePolicy) { if (resource.resourcePolicyId !== null) {
// get the policy // get the policy
const policy = await queryInlinePolicy( const policy = await queryInlinePolicy(resource.resourcePolicyId);
resource.defaultResourcePolicyId!
);
returnData = { returnData = {
...returnData, ...returnData,
sso: policy?.sso || null, sso: policy?.sso || null,

View File

@@ -140,15 +140,11 @@ export async function listResourceRules(
); );
} }
const isInlinePolicy =
resource.resourcePolicyId === null &&
resource.defaultResourcePolicyId !== null;
let rulesList: Awaited<ReturnType<typeof queryResourceRules>>; let rulesList: Awaited<ReturnType<typeof queryResourceRules>>;
let totalCount: number; let totalCount: number;
if (isInlinePolicy) { if (resource.resourcePolicyId !== null) {
const policyId = resource.defaultResourcePolicyId!; const policyId = resource.resourcePolicyId;
const policyRules = await queryPolicyRules(policyId) const policyRules = await queryPolicyRules(policyId)
.limit(limit) .limit(limit)
.offset(offset); .offset(offset);

View File

@@ -1,8 +1,8 @@
import { Request, Response, NextFunction } from "express"; import { Request, Response, NextFunction } from "express";
import { z } from "zod"; import { z } from "zod";
import { db } from "@server/db"; import { db } from "@server/db";
import { resourceRules, resources } from "@server/db"; import { resourcePolicyRules, resourceRules, resources } from "@server/db";
import { eq } from "drizzle-orm"; import { and, eq } from "drizzle-orm";
import response from "@server/lib/response"; import response from "@server/lib/response";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import createHttpError from "http-errors"; import createHttpError from "http-errors";
@@ -37,6 +37,29 @@ const updateResourceRuleSchema = z
error: "At least one field must be provided for update" error: "At least one field must be provided for update"
}); });
function getRuleValueValidationError(
match: "CIDR" | "IP" | "PATH" | "COUNTRY" | "ASN" | "REGION",
value: string
): string | null {
if (match === "CIDR" && !isValidCIDR(value)) {
return "Invalid CIDR provided";
}
if (match === "IP" && !isValidIP(value)) {
return "Invalid IP provided";
}
if (match === "PATH" && !isValidUrlGlobPattern(value)) {
return "Invalid URL glob pattern provided";
}
if (match === "REGION" && !isValidRegionId(value)) {
return "Invalid region ID provided";
}
return null;
}
registry.registerPath({ registry.registerPath({
method: "post", method: "post",
path: "/resource/{resourceId}/rule/{ruleId}", path: "/resource/{resourceId}/rule/{ruleId}",
@@ -128,6 +151,68 @@ export async function updateResourceRule(
); );
} }
if (resource.resourcePolicyId !== null) {
const [existingRule] = await db
.select()
.from(resourcePolicyRules)
.where(
and(
eq(resourcePolicyRules.ruleId, ruleId),
eq(
resourcePolicyRules.resourcePolicyId,
resource.resourcePolicyId
)
)
)
.limit(1);
if (!existingRule) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
`Resource rule with ID ${ruleId} not found`
)
);
}
const match = updateData.match || existingRule.match;
const { value } = updateData;
if (value !== undefined) {
const validationError = getRuleValueValidationError(
match,
value
);
if (validationError) {
return next(
createHttpError(HttpCode.BAD_REQUEST, validationError)
);
}
}
const [updatedRule] = await db
.update(resourcePolicyRules)
.set(updateData)
.where(
and(
eq(resourcePolicyRules.ruleId, ruleId),
eq(
resourcePolicyRules.resourcePolicyId,
resource.resourcePolicyId
)
)
)
.returning();
return response(res, {
data: updatedRule,
success: true,
error: false,
message: "Resource rule updated successfully",
status: HttpCode.OK
});
}
// Verify that the rule exists and belongs to the specified resource // Verify that the rule exists and belongs to the specified resource
const [existingRule] = await db const [existingRule] = await db
.select() .select()
@@ -157,42 +242,11 @@ export async function updateResourceRule(
const { value } = updateData; const { value } = updateData;
if (value !== undefined) { if (value !== undefined) {
if (match === "CIDR") { const validationError = getRuleValueValidationError(match, value);
if (!isValidCIDR(value)) { if (validationError) {
return next( return next(
createHttpError( createHttpError(HttpCode.BAD_REQUEST, validationError)
HttpCode.BAD_REQUEST, );
"Invalid CIDR provided"
)
);
}
} else if (match === "IP") {
if (!isValidIP(value)) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Invalid IP provided"
)
);
}
} else if (match === "PATH") {
if (!isValidUrlGlobPattern(value)) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Invalid URL glob pattern provided"
)
);
}
} else if (match === "REGION") {
if (!isValidRegionId(value)) {
return next(
createHttpError(
HttpCode.BAD_REQUEST,
"Invalid region ID provided"
)
);
}
} }
} }