Filter container interfaces from device discovery and policies
Build and Deploy Gateway / build-and-push (push) Successful in 11s
Build and Deploy Gateway / deploy (push) Successful in 14s

This commit is contained in:
2026-08-07 17:16:36 +03:00
parent 53e6cf2146
commit 608f8cfcf2
8 changed files with 68 additions and 16 deletions
+39 -1
View File
@@ -13,6 +13,40 @@ import {
import { fingerprintDirectDevices } from '../../src/server/services/devicePolicyService.js';
import { createJsonStore } from '../../src/server/services/stateStore.js';
test('container neighbors are hidden while a real 172 LAN device remains valid', () => {
const observedAt = '2026-08-07T12:00:00.000Z';
const parsed = parseNeighborSnapshot([
{ dst: '172.17.0.2', dev: 'docker0', lladdr: '00:11:22:33:44:51', state: ['REACHABLE'] },
{ dst: '172.18.0.2', dev: 'br-1234', lladdr: '00:11:22:33:44:52', state: ['REACHABLE'] },
{ dst: '172.19.0.2', dev: 'veth1234', lladdr: '00:11:22:33:44:53', state: ['REACHABLE'] },
{ dst: '172.20.0.7', dev: 'eth0', lladdr: '00:11:22:33:44:54', state: ['REACHABLE'] },
], observedAt);
assert.deepEqual(parsed.map(({ ip, interface: deviceInterface }) => [ip, deviceInterface]), [
['172.20.0.7', 'eth0'],
]);
const storedDevice = (ip, deviceInterface) => ({
id: `dev_${ip.replaceAll('.', '').padEnd(16, '0').slice(0, 16)}`,
alias: '',
pinned: false,
hostname: null,
manufacturer: null,
mac: ip === '172.17.0.2' ? '00:11:22:33:44:51' : '00:11:22:33:44:54',
ip,
interface: deviceInterface,
firstSeenAt: observedAt,
lastSeenAt: observedAt,
source: 'neighbor',
confidence: 'high',
});
const migrated = migrateDeviceInventoryState({
schemaVersion: 2,
devices: [storedDevice('172.17.0.2', 'docker0'), storedDevice('172.20.0.7', 'eth0')],
traffic: { baselinesByMac: {}, totalsByMac: {}, rebaselineMacs: [] },
});
assert.deepEqual(migrated.devices.map(({ ip }) => ip), ['172.20.0.7']);
});
test('device inventory discovers, merges, persists metadata and expires anonymous devices', async (t) => {
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'harbor-devices-'));
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
@@ -252,7 +286,10 @@ test('legacy dataplane samples preserve saved proxy totals while Gateway totals
const neighbor = {
observedAt,
error: null,
observations: [{ ip: '192.168.50.7', mac, interface: 'eth0', observedAt, active: true }],
observations: [
{ ip: '192.168.50.7', mac, interface: 'eth0', observedAt, active: true },
{ ip: '172.17.0.2', mac: '00:11:22:33:44:66', interface: 'docker0', observedAt, active: true },
],
};
let row = {
mac,
@@ -270,6 +307,7 @@ test('legacy dataplane samples preserve saved proxy totals while Gateway totals
});
let snapshot = await service.refresh();
assert.equal(snapshot.devices.length, 1);
assert.equal(snapshot.devices[0].proxyUploadBytes, '30');
row = { mac, uploadBytes: '15', downloadBytes: '27' };
snapshot = await service.refresh();
+2
View File
@@ -18,6 +18,8 @@ test('device policy rules match the full identity before the TPROXY fallback', (
assert.deepEqual(normalizeDirectDevices([{ ...directDevice, mac: directDevice.mac.toUpperCase() }]), [directDevice]);
assert.throws(() => normalizeDirectDevices([directDevice, directDevice]), /повторяющаяся/);
assert.throws(() => normalizeDirectDevices([{ ...directDevice, interface: 'br-user' }]), /identity/);
assert.throws(() => normalizeDirectDevices([{ ...directDevice, interface: 'docker0' }]), /identity/);
assert.throws(() => normalizeDirectDevices([{ ...directDevice, interface: 'veth1234' }]), /identity/);
const restore = buildDevicePolicyRestore({
devices: [directDevice],
+2
View File
@@ -36,6 +36,8 @@ test('traffic selection keeps only unambiguous IPv4 neighbors', () => {
observation('192.168.50.10', '00:11:22:33:44:77', 'bad interface'),
observation('192.168.50.11', '00:11:22:33:44:88', 'br-docker0'),
observation('192.168.50.12', '00:11:22:33:44:99', 'eth+'),
observation('172.17.0.2', '00:11:22:33:44:aa', 'docker0'),
observation('172.18.0.2', '00:11:22:33:44:bb', 'veth1234'),
observation('2001:db8::7', '00:11:22:33:44:88'),
]);