feat(api): unify policy handling with default action updates
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m53s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped

- Updated `evofw-firewall.sh` and related scripts to replace `policy_mode` with `default_action`, enhancing clarity and consistency in policy management.
- Adjusted agent routes and evaluation logic to accommodate the new default action structure, ensuring backward compatibility with legacy modes.
- Enhanced tests to validate the new default action behavior and its integration within the agent policy framework.
- Refactored related components in the web interface to align with the updated policy handling, improving user experience and reducing confusion around policy modes.
This commit is contained in:
Denozordec
2026-07-23 10:52:28 +07:00
parent a6eb21a10d
commit 1f7273f38d
30 changed files with 1469 additions and 621 deletions
+94 -9
View File
@@ -7,7 +7,13 @@ export const agentStatusSchema = z.enum([
'approved',
'revoked',
])
/** Packet default when CIDR is in neither deny nor allow set. */
export const defaultActionSchema = z.enum(['accept', 'drop'])
/** @deprecated Use defaultActionSchema. Kept for API input compat. */
export const policyModeSchema = z.enum(['blacklist', 'whitelist'])
export const policyActionSchema = z.enum(['allow', 'deny'])
export const ipListTypeSchema = z.enum([
'static',
@@ -16,6 +22,21 @@ export const ipListTypeSchema = z.enum([
'evobgp_community',
])
/** Map legacy blacklist/whitelist → default_action. */
export function defaultActionFromLegacyMode(
mode: string | null | undefined,
): 'accept' | 'drop' {
if (mode === 'whitelist' || mode === 'drop') return 'drop'
return 'accept'
}
/** Optional mirror for old agent binaries. */
export function legacyModeFromDefaultAction(
action: 'accept' | 'drop',
): 'blacklist' | 'whitelist' {
return action === 'drop' ? 'whitelist' : 'blacklist'
}
export const agentSchema = z.object({
id: z.string(),
name: z.string(),
@@ -23,7 +44,9 @@ export const agentSchema = z.object({
platform: agentPlatformSchema,
token_prefix: z.string(),
status: agentStatusSchema,
policy_mode: policyModeSchema,
default_action: defaultActionSchema,
/** @deprecated mirror of default_action for older clients */
policy_mode: policyModeSchema.optional(),
policy_generation: z.number().int(),
last_seen_at: z.string().nullable().optional(),
last_seen_ip: z.string().nullable().optional(),
@@ -76,7 +99,8 @@ export const policySetSchema = z.object({
name: z.string(),
description: z.string().nullable().optional(),
enabled: z.boolean(),
policy_mode: policyModeSchema,
/** @deprecated ignored — sets have no exclusive mode */
policy_mode: policyModeSchema.optional(),
rules_count: z.number().int().optional(),
agents_count: z.number().int().optional(),
created_at: z.string(),
@@ -104,13 +128,15 @@ export const createPolicySetBodySchema = z.object({
name: z.string().min(1),
description: z.string().nullable().optional(),
enabled: z.boolean().optional().default(true),
policy_mode: policyModeSchema.optional().default('blacklist'),
/** @deprecated ignored */
policy_mode: policyModeSchema.optional(),
})
export const patchPolicySetBodySchema = z.object({
name: z.string().min(1).optional(),
description: z.string().nullable().optional(),
enabled: z.boolean().optional(),
/** @deprecated ignored */
policy_mode: policyModeSchema.optional(),
})
@@ -158,11 +184,26 @@ export const createOverrideBodySchema = z.object({
comment: z.string().nullable().optional(),
})
export const patchAgentBodySchema = z.object({
name: z.string().min(1).optional(),
policy_mode: policyModeSchema.optional(),
settings: z.record(z.string(), z.unknown()).optional(),
})
export const patchAgentBodySchema = z
.object({
name: z.string().min(1).optional(),
default_action: defaultActionSchema.optional(),
/** @deprecated use default_action */
policy_mode: policyModeSchema.optional(),
settings: z.record(z.string(), z.unknown()).optional(),
})
.transform((v) => {
const default_action =
v.default_action ??
(v.policy_mode !== undefined
? defaultActionFromLegacyMode(v.policy_mode)
: undefined)
return {
name: v.name,
default_action,
settings: v.settings,
}
})
export const cloneFromBodySchema = z.object({
include_overrides: z.boolean().optional().default(false),
@@ -190,12 +231,47 @@ export const applyReportBodySchema = z.object({
export const agentPolicySchema = z.object({
generation: z.number().int(),
hash: z.string(),
policy_mode: policyModeSchema,
apply_version: z.number().int(),
default_action: defaultActionSchema,
/** @deprecated mirror for old agents */
policy_mode: policyModeSchema.optional(),
deny_cidrs: z.array(z.string()),
allow_cidrs: z.array(z.string()),
sync_interval_sec: z.number().int(),
})
export const agentPolicyPreviewSchema = z.object({
default_action: defaultActionSchema,
hash: z.string(),
generation: z.number().int(),
sync_interval_sec: z.number().int(),
apply_version: z.literal(2),
summary: z.object({
sets: z.number().int(),
rules_deny: z.number().int(),
rules_allow: z.number().int(),
cidrs_deny: z.number().int(),
cidrs_allow: z.number().int(),
overrides: z.number().int(),
conflicts_dropped: z.number().int(),
}),
chain: z.array(
z.object({
set_id: z.string().nullable(),
set_name: z.string().nullable(),
rule_id: z.string().nullable(),
action: policyActionSchema,
source_kind: z.enum(['list', 'cidr', 'hostname', 'override']),
source_label: z.string(),
cidr_count: z.number().int(),
}),
),
deny_cidrs: z.array(z.string()),
allow_cidrs: z.array(z.string()),
deny_cidrs_total: z.number().int(),
allow_cidrs_total: z.number().int(),
})
export const dashboardStatsSchema = z.object({
agents_total: z.number().int(),
agents_approved: z.number().int(),
@@ -235,11 +311,20 @@ export const installLinkSchema = z.object({
.optional(),
})
export const evobgpCommunitySchema = z.object({
id: z.string(),
community: z.string(),
title: z.string().nullable().optional(),
})
export type Agent = z.infer<typeof agentSchema>
export type IpList = z.infer<typeof ipListSchema>
export type PolicyRule = z.infer<typeof policyRuleSchema>
export type PolicySet = z.infer<typeof policySetSchema>
export type IpOverride = z.infer<typeof ipOverrideSchema>
export type AgentPolicy = z.infer<typeof agentPolicySchema>
export type AgentPolicyPreview = z.infer<typeof agentPolicyPreviewSchema>
export type DashboardStats = z.infer<typeof dashboardStatsSchema>
export type InstallLink = z.infer<typeof installLinkSchema>
export type EvobgpCommunity = z.infer<typeof evobgpCommunitySchema>
export type DefaultAction = z.infer<typeof defaultActionSchema>