mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-17 04:47:11 +00:00
Compare commits
12 Commits
copilot/pu
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0bde633c5f | ||
|
|
a7c99f336f | ||
|
|
0d960181a2 | ||
|
|
b6862093d1 | ||
|
|
16c0f4eef4 | ||
|
|
a0fef89031 | ||
|
|
f15654ed11 | ||
|
|
0b41fe3d49 | ||
|
|
b9db0a4490 | ||
|
|
d9952b0762 | ||
|
|
6e271028f3 | ||
|
|
a724b07846 |
@@ -1,7 +1,4 @@
|
||||
import {
|
||||
getResourceRuleValueValidationError,
|
||||
isValidUrlGlobPattern
|
||||
} from "./validators";
|
||||
import { isValidUrlGlobPattern } from "./validators";
|
||||
import { assertEquals } from "@test/assert";
|
||||
|
||||
function runTests() {
|
||||
@@ -239,43 +236,6 @@ function runTests() {
|
||||
"Path with isolated percent sign should be invalid"
|
||||
);
|
||||
|
||||
// ASN validation tests
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", "AS15169"),
|
||||
null,
|
||||
"Standard ASN should be valid"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", " As15169 "),
|
||||
null,
|
||||
"Standard ASN should be valid with mixed case and whitespace"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", "ALL"),
|
||||
null,
|
||||
"ALL ASN selector should be valid"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", " all "),
|
||||
null,
|
||||
"ALL ASN selector should be valid with mixed case and whitespace"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", "AS0"),
|
||||
null,
|
||||
"AS0 alias should be valid"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", " as0 "),
|
||||
null,
|
||||
"AS0 alias should be valid with mixed case and whitespace"
|
||||
);
|
||||
assertEquals(
|
||||
getResourceRuleValueValidationError("ASN", "not-an-asn"),
|
||||
"Invalid ASN provided",
|
||||
"Invalid ASN should return an error"
|
||||
);
|
||||
|
||||
console.log("All tests passed!");
|
||||
}
|
||||
|
||||
|
||||
@@ -100,10 +100,7 @@ export function getResourceRuleValueValidationError(
|
||||
? null
|
||||
: "Invalid country code provided";
|
||||
case "ASN":
|
||||
const normalizedValue = value.trim().toUpperCase();
|
||||
return /^AS\d+$/.test(normalizedValue) ||
|
||||
normalizedValue === "ALL" ||
|
||||
normalizedValue === "AS0"
|
||||
return /^AS\d+$/i.test(value.trim())
|
||||
? null
|
||||
: "Invalid ASN provided";
|
||||
default:
|
||||
|
||||
@@ -154,12 +154,8 @@ export async function createResourceRule(
|
||||
}
|
||||
|
||||
// Create the new resource rule
|
||||
const isInlinePolicy =
|
||||
resource.resourcePolicyId === null &&
|
||||
resource.defaultResourcePolicyId !== null;
|
||||
|
||||
if (isInlinePolicy) {
|
||||
const policyId = resource.defaultResourcePolicyId!;
|
||||
if (resource.resourcePolicyId !== null) {
|
||||
const policyId = resource.resourcePolicyId;
|
||||
const [newRule] = await db
|
||||
.insert(resourcePolicyRules)
|
||||
.values({
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } 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 HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
@@ -73,14 +73,18 @@ export async function deleteResourceRule(
|
||||
);
|
||||
}
|
||||
|
||||
const isInlinePolicy =
|
||||
resource.resourcePolicyId === null &&
|
||||
resource.defaultResourcePolicyId !== null;
|
||||
|
||||
if (isInlinePolicy) {
|
||||
if (resource.resourcePolicyId !== null) {
|
||||
const [deletedRule] = await db
|
||||
.delete(resourcePolicyRules)
|
||||
.where(eq(resourcePolicyRules.ruleId, ruleId))
|
||||
.where(
|
||||
and(
|
||||
eq(resourcePolicyRules.ruleId, ruleId),
|
||||
eq(
|
||||
resourcePolicyRules.resourcePolicyId,
|
||||
resource.resourcePolicyId
|
||||
)
|
||||
)
|
||||
)
|
||||
.returning();
|
||||
|
||||
if (!deletedRule) {
|
||||
|
||||
@@ -141,16 +141,10 @@ export async function getResource(
|
||||
);
|
||||
}
|
||||
|
||||
const isInlinePolicy =
|
||||
resource.resourcePolicyId === null &&
|
||||
resource.defaultResourcePolicyId !== null;
|
||||
|
||||
let returnData = resource;
|
||||
if (isInlinePolicy) {
|
||||
if (resource.resourcePolicyId !== null) {
|
||||
// get the policy
|
||||
const policy = await queryInlinePolicy(
|
||||
resource.defaultResourcePolicyId!
|
||||
);
|
||||
const policy = await queryInlinePolicy(resource.resourcePolicyId);
|
||||
returnData = {
|
||||
...returnData,
|
||||
sso: policy?.sso || null,
|
||||
|
||||
@@ -140,15 +140,11 @@ export async function listResourceRules(
|
||||
);
|
||||
}
|
||||
|
||||
const isInlinePolicy =
|
||||
resource.resourcePolicyId === null &&
|
||||
resource.defaultResourcePolicyId !== null;
|
||||
|
||||
let rulesList: Awaited<ReturnType<typeof queryResourceRules>>;
|
||||
let totalCount: number;
|
||||
|
||||
if (isInlinePolicy) {
|
||||
const policyId = resource.defaultResourcePolicyId!;
|
||||
if (resource.resourcePolicyId !== null) {
|
||||
const policyId = resource.resourcePolicyId;
|
||||
const policyRules = await queryPolicyRules(policyId)
|
||||
.limit(limit)
|
||||
.offset(offset);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db } from "@server/db";
|
||||
import { resourceRules, resources } from "@server/db";
|
||||
import { eq } from "drizzle-orm";
|
||||
import { resourcePolicyRules, resourceRules, resources } from "@server/db";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
@@ -37,6 +37,29 @@ const updateResourceRuleSchema = z
|
||||
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({
|
||||
method: "post",
|
||||
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
|
||||
const [existingRule] = await db
|
||||
.select()
|
||||
@@ -157,42 +242,11 @@ export async function updateResourceRule(
|
||||
const { value } = updateData;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (match === "CIDR") {
|
||||
if (!isValidCIDR(value)) {
|
||||
return next(
|
||||
createHttpError(
|
||||
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"
|
||||
)
|
||||
);
|
||||
}
|
||||
const validationError = getRuleValueValidationError(match, value);
|
||||
if (validationError) {
|
||||
return next(
|
||||
createHttpError(HttpCode.BAD_REQUEST, validationError)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -139,6 +139,7 @@ Restart=always
|
||||
RestartSec=2
|
||||
UMask=0077
|
||||
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
|
||||
@@ -83,19 +83,9 @@ export function createPolicyRuleValueSchema(t: TranslateFn, match: string) {
|
||||
{ message: t("rulesErrorInvalidCountryDescription") }
|
||||
);
|
||||
case "ASN":
|
||||
return required.refine(
|
||||
(value) => {
|
||||
const normalizedValue = value.trim().toUpperCase();
|
||||
return (
|
||||
/^AS\d+$/.test(normalizedValue) ||
|
||||
normalizedValue === "ALL" ||
|
||||
normalizedValue === "AS0"
|
||||
);
|
||||
},
|
||||
{
|
||||
message: t("rulesErrorInvalidAsnDescription")
|
||||
}
|
||||
);
|
||||
return required.refine((value) => /^AS\d+$/i.test(value.trim()), {
|
||||
message: t("rulesErrorInvalidAsnDescription")
|
||||
});
|
||||
default:
|
||||
return required;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user