feat(api, web): implement policy mode management for agents and rules
- Added support for policy modes ('blacklist' and 'whitelist') in agent and policy set management.
- Updated API endpoints to handle policy mode during agent assignment and rule operations.
- Enhanced the web UI to display and manage policy modes for agents and rules, ensuring all assigned sets share a consistent mode.
- Introduced new validation to enforce single policy mode across assigned sets for agents.
- Improved error handling for policy mode conflicts and updated documentation accordingly.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
d5784b9f35
commit
90d50c2556
15 files changed
+1261
-266
No files matched your search
@@ -0,0 +1,127 @@
|
||||
import { describe, it, expect, afterAll } from 'vitest'
|
||||
import { buildApp } from '../../app.js'
|
||||
import type { AppConfig } from '../../config.js'
|
||||
|
||||
const testConfig: AppConfig = {
|
||||
databaseUrl: 'sqlite::memory:',
|
||||
jwtSecret: 'test',
|
||||
jwtTtlHours: 24,
|
||||
serverPort: 8080,
|
||||
staticDir: null,
|
||||
logLevel: 'error',
|
||||
authRequired: false,
|
||||
authIssuer: 'https://auth.test',
|
||||
authPortalUrl: 'http://localhost:5175',
|
||||
publicBaseUrl: 'https://fw.example.com',
|
||||
enrollSeed: 'test-seed',
|
||||
}
|
||||
|
||||
describe('policy set mode + rules', () => {
|
||||
const appPromise = buildApp({ memory: true, config: testConfig })
|
||||
|
||||
afterAll(async () => {
|
||||
const app = await appPromise
|
||||
await app.close()
|
||||
})
|
||||
|
||||
it('set policy_mode and reorder; disabled rules skipped in policy', async () => {
|
||||
const app = await appPromise
|
||||
await app.ready()
|
||||
|
||||
const created = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/policy-sets',
|
||||
payload: {
|
||||
name: 'WL set',
|
||||
policy_mode: 'whitelist',
|
||||
},
|
||||
})
|
||||
expect(created.statusCode).toBe(200)
|
||||
const set = created.json() as { id: string; policy_mode: string }
|
||||
expect(set.policy_mode).toBe('whitelist')
|
||||
|
||||
const r1 = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/rules',
|
||||
payload: {
|
||||
set_id: set.id,
|
||||
action: 'allow',
|
||||
cidr: '10.0.0.1/32',
|
||||
},
|
||||
})
|
||||
expect(r1.statusCode).toBe(200)
|
||||
const rule1 = r1.json() as { id: string; enabled: boolean; priority: number }
|
||||
|
||||
const r2 = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/v1/rules',
|
||||
payload: {
|
||||
set_id: set.id,
|
||||
action: 'allow',
|
||||
cidr: '10.0.0.2/32',
|
||||
},
|
||||
})
|
||||
const rule2 = r2.json() as { id: string }
|
||||
|
||||
const reordered = await app.inject({
|
||||
method: 'PUT',
|
||||
url: `/api/v1/policy-sets/${set.id}/rules/reorder`,
|
||||
payload: { ordered_ids: [rule2.id, rule1.id] },
|
||||
})
|
||||
expect(reordered.statusCode).toBe(200)
|
||||
const items = (
|
||||
reordered.json() as { items: { id: string; priority: number }[] }
|
||||
).items
|
||||
expect(items[0]?.id).toBe(rule2.id)
|
||||
expect(items[0]!.priority).toBeLessThan(items[1]!.priority)
|
||||
|
||||
await app.inject({
|
||||
method: 'PATCH',
|
||||
url: `/api/v1/rules/${rule1.id}`,
|
||||
payload: { enabled: false },
|
||||
})
|
||||
|
||||
// enroll + approve agent, assign set
|
||||
const enroll = await app.inject({
|
||||
method: 'POST',
|
||||
url: '/v1/agent/enroll',
|
||||
headers: {
|
||||
'content-type': 'application/json',
|
||||
'x-evofw-seed': 'test-seed',
|
||||
},
|
||||
payload: {
|
||||
name: 'mt-wl',
|
||||
platform: 'linux',
|
||||
token: 'evofw_policy_mode_token_abcdef12',
|
||||
},
|
||||
})
|
||||
const agent = enroll.json() as { id: string }
|
||||
await app.inject({
|
||||
method: 'POST',
|
||||
url: `/api/v1/agents/${agent.id}/approve`,
|
||||
})
|
||||
const assign = await app.inject({
|
||||
method: 'PUT',
|
||||
url: `/api/v1/agents/${agent.id}/policy-sets`,
|
||||
payload: { set_ids: [set.id] },
|
||||
})
|
||||
expect(assign.statusCode).toBe(200)
|
||||
|
||||
const policy = await app.inject({
|
||||
method: 'GET',
|
||||
url: '/v1/agent/policy',
|
||||
headers: {
|
||||
authorization: 'Bearer evofw_policy_mode_token_abcdef12',
|
||||
},
|
||||
})
|
||||
expect(policy.statusCode).toBe(200)
|
||||
const body = policy.json() as {
|
||||
policy_mode: string
|
||||
allow_cidrs: string[]
|
||||
}
|
||||
expect(body.policy_mode).toBe('whitelist')
|
||||
expect(body.allow_cidrs).toContain('10.0.0.2/32')
|
||||
expect(body.allow_cidrs).not.toContain('10.0.0.1/32')
|
||||
expect(rule1.enabled).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user