Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
73 lines
2.8 KiB
JavaScript
73 lines
2.8 KiB
JavaScript
// backend/services/audit/__tests__/rowDiff.test.js
|
|
//
|
|
// ADR-0066 P1 — Unit tests for computeRowDiff.
|
|
//
|
|
// Pure CPU; no DB. Validates the diff helper used by row.update audits
|
|
// to stay within the 8 KiB cap on writeAudit() details.
|
|
|
|
import { describe, it, expect } from 'vitest';
|
|
import { computeRowDiff } from '../rowDiff.js';
|
|
|
|
describe('computeRowDiff — per-column diff for row.update audits', () => {
|
|
it('returns null when nothing changed', () => {
|
|
const a = { title: 'x', status: 'open' };
|
|
const b = { title: 'x', status: 'open' };
|
|
expect(computeRowDiff(a, b)).toBeNull();
|
|
});
|
|
|
|
it('emits only the columns whose values differ', () => {
|
|
const a = { title: 'x', status: 'open', priority: 1 };
|
|
const b = { title: 'x', status: 'closed', priority: 1 };
|
|
expect(computeRowDiff(a, b)).toEqual({
|
|
changed_columns: ['status'],
|
|
before: { status: 'open' },
|
|
after: { status: 'closed' },
|
|
});
|
|
});
|
|
|
|
it('captures additions as before=null', () => {
|
|
const a = { title: 'x' };
|
|
const b = { title: 'x', registry_table_id: 2197 };
|
|
const diff = computeRowDiff(a, b);
|
|
expect(diff.changed_columns).toEqual(['registry_table_id']);
|
|
expect(diff.before).toEqual({ registry_table_id: null });
|
|
expect(diff.after).toEqual({ registry_table_id: 2197 });
|
|
});
|
|
|
|
it('captures removals as after=null (ADR-0067 canonical-erase detector)', () => {
|
|
// The stop-condition (a) for P3 soak: someone saves a documents-widget
|
|
// config that strips registry_table_id. This is what the soak detector
|
|
// SQL grep'es for.
|
|
const a = { registry_table_id: 2197, documents_table_id: 2197, project_id: 146 };
|
|
const b = { documents_table_id: 2197, project_id: 146 };
|
|
const diff = computeRowDiff(a, b);
|
|
expect(diff.changed_columns).toEqual(['registry_table_id']);
|
|
expect(diff.before).toEqual({ registry_table_id: 2197 });
|
|
expect(diff.after).toEqual({ registry_table_id: null });
|
|
});
|
|
|
|
it('treats null/non-object inputs as empty objects', () => {
|
|
expect(computeRowDiff(null, { x: 1 })).toEqual({
|
|
changed_columns: ['x'],
|
|
before: { x: null },
|
|
after: { x: 1 },
|
|
});
|
|
expect(computeRowDiff({ x: 1 }, null)).toEqual({
|
|
changed_columns: ['x'],
|
|
before: { x: 1 },
|
|
after: { x: null },
|
|
});
|
|
expect(computeRowDiff(null, null)).toBeNull();
|
|
});
|
|
|
|
it('uses deep-equality for nested objects (no false positives)', () => {
|
|
const a = { config: { registry_table_id: 2197, project_id: 146 } };
|
|
const b = { config: { registry_table_id: 2197, project_id: 146 } };
|
|
expect(computeRowDiff(a, b)).toBeNull();
|
|
|
|
const c = { config: { registry_table_id: 2197 } };
|
|
const d = { config: { registry_table_id: 100008 } };
|
|
const diff = computeRowDiff(c, d);
|
|
expect(diff.changed_columns).toEqual(['config']);
|
|
});
|
|
});
|