mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-10-20 09:09:35 +02:00
feat(admin): count revoked html-view capabilities in the logout audit line
The admin forced logout already revoked the user's rendered-HTML capabilities but recorded only the cookie sessions and web-tab capabilities it retired. The `user.logout` audit entry now carries `revokedHtmlViews` next to `revokedWebviews`, and the revocation test reads it back from admin-audit.jsonl. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
7dd78d9d71
commit
7b4832b3e4
2 files changed
+15
-3
No files matched your search
@@ -184,8 +184,8 @@ export function registerAdminRoutes(app: FastifyInstance, ctx: SessionPort & Aut
|
|||||||
// Web-tab proxy capabilities are a second credential the cookie purge does not
|
// Web-tab proxy capabilities are a second credential the cookie purge does not
|
||||||
// touch; a forced logout that left them alive would not be a logout.
|
// touch; a forced logout that left them alive would not be a logout.
|
||||||
const revokedWebviews = webviewCapabilities.revokeOwner(normalizeUsername(username));
|
const revokedWebviews = webviewCapabilities.revokeOwner(normalizeUsername(username));
|
||||||
htmlViewCapabilities.revokeOwner(normalizeUsername(username));
|
const revokedHtmlViews = htmlViewCapabilities.revokeOwner(normalizeUsername(username));
|
||||||
audit(req, 'user.logout', username, { revoked, revokedWebviews });
|
audit(req, 'user.logout', username, { revoked, revokedWebviews, revokedHtmlViews });
|
||||||
return { success: true, data: { revoked } };
|
return { success: true, data: { revoked } };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,9 @@
|
|||||||
* The rendered-HTML capabilities (`htmlViewCapabilities`) are pinned at the same sites.
|
* The rendered-HTML capabilities (`htmlViewCapabilities`) are pinned at the same sites.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
|
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
||||||
|
import { readFileSync } from 'node:fs';
|
||||||
|
import { dataPath } from '../src/config/instance.js';
|
||||||
import { WebviewCapabilityStore, webviewCapabilities } from '../src/webview-capabilities.js';
|
import { WebviewCapabilityStore, webviewCapabilities } from '../src/webview-capabilities.js';
|
||||||
import { HtmlViewCapabilityStore, htmlViewCapabilities } from '../src/html-view-capabilities.js';
|
import { HtmlViewCapabilityStore, htmlViewCapabilities } from '../src/html-view-capabilities.js';
|
||||||
import { createRouteTestHarness, type RouteTestHarness } from './routes/_route-test-utils.js';
|
import { createRouteTestHarness, type RouteTestHarness } from './routes/_route-test-utils.js';
|
||||||
@@ -157,6 +159,16 @@ describe('admin routes (multi-user)', () => {
|
|||||||
expect(htmlViewCapabilities.resolve(bossPage)).toBeDefined();
|
expect(htmlViewCapabilities.resolve(bossPage)).toBeDefined();
|
||||||
webviewCapabilities.revokeWebview('wv-boss-forced');
|
webviewCapabilities.revokeWebview('wv-boss-forced');
|
||||||
htmlViewCapabilities.revokeOwner('boss');
|
htmlViewCapabilities.revokeOwner('boss');
|
||||||
|
|
||||||
|
// The audit line counts both kinds of capability it retired.
|
||||||
|
await vi.waitFor(() => {
|
||||||
|
const entries = readFileSync(dataPath('admin-audit.jsonl'), 'utf8')
|
||||||
|
.trim()
|
||||||
|
.split('\n')
|
||||||
|
.map((line) => JSON.parse(line));
|
||||||
|
const logout = entries.filter((e) => e.action === 'user.logout' && e.target === 'PEON').pop();
|
||||||
|
expect(logout?.detail).toMatchObject({ revokedWebviews: 1, revokedHtmlViews: 1 });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('deleting a user revokes whatever that user had open', async () => {
|
it('deleting a user revokes whatever that user had open', async () => {
|
||||||
|
|||||||
Reference in new issue
Block a user