feat(opsserver): add health, audit, cluster health, and durable credential management hardening

This commit is contained in:
2026-04-30 07:10:21 +00:00
parent c3e5cabe3d
commit f4e5f02d0c
34 changed files with 1722 additions and 320 deletions
+206
View File
@@ -0,0 +1,206 @@
import { assertEquals, assertRejects } from 'jsr:@std/assert';
import { describe, it } from 'jsr:@std/testing/bdd';
import { TypedRequest } from '@api.global/typedrequest';
import {
createTestContainer,
getTestPorts,
loginAndGetIdentity,
TEST_ACCESS_KEY,
} from './helpers/server.helper.ts';
import { ObjectStorageContainer } from '../ts/index.ts';
import type { IReq_CreateBucket, IReq_ListBuckets } from '../ts_interfaces/requests/buckets.ts';
import type {
IReq_AddCredential,
IReq_GetCredentials,
IReq_RemoveCredential,
} from '../ts_interfaces/requests/credentials.ts';
import type * as interfaces from '../ts_interfaces/index.ts';
const PORT_INDEX = 8;
const ports = getTestPorts(PORT_INDEX);
const url = `http://localhost:${ports.uiPort}/typedrequest`;
const storageDirectory = `.nogit/testdata-${PORT_INDEX}`;
const cleanupStorageDirectory = async () => {
try {
await Deno.remove(storageDirectory, { recursive: true });
} catch (error) {
if (!(error instanceof Deno.errors.NotFound)) {
throw error;
}
}
};
describe('Credential persistence', { sanitizeResources: false, sanitizeOps: false }, () => {
it('persists managed credentials across restart and refreshes the internal client', async () => {
await cleanupStorageDirectory();
let activeContainer: ObjectStorageContainer | null = null;
const stopContainer = async () => {
if (!activeContainer) {
return;
}
try {
await activeContainer.stop();
} finally {
activeContainer = null;
}
};
try {
activeContainer = createTestContainer(PORT_INDEX);
await activeContainer.start();
let identity: interfaces.data.IIdentity = await loginAndGetIdentity(ports.uiPort);
const addCredential = new TypedRequest<IReq_AddCredential>(url, 'addCredential');
await addCredential.fire({
identity,
accessKeyId: 'persisted-key',
secretAccessKey: 'persisted-secret',
});
const removeCredential = new TypedRequest<IReq_RemoveCredential>(url, 'removeCredential');
await removeCredential.fire({ identity, accessKeyId: TEST_ACCESS_KEY });
const getCredentials = new TypedRequest<IReq_GetCredentials>(url, 'getCredentials');
const credentialsBeforeRestart = await getCredentials.fire({ identity });
assertEquals(credentialsBeforeRestart.credentials.length, 1);
assertEquals(credentialsBeforeRestart.credentials[0].accessKeyId, 'persisted-key');
const listBuckets = new TypedRequest<IReq_ListBuckets>(url, 'listBuckets');
const bucketsBeforeRestart = await listBuckets.fire({ identity });
assertEquals(Array.isArray(bucketsBeforeRestart.buckets), true);
await stopContainer();
activeContainer = createTestContainer(PORT_INDEX);
await activeContainer.start();
identity = await loginAndGetIdentity(ports.uiPort);
const credentialsAfterRestart = await getCredentials.fire({ identity });
assertEquals(credentialsAfterRestart.credentials.length, 1);
assertEquals(credentialsAfterRestart.credentials[0].accessKeyId, 'persisted-key');
const createBucket = new TypedRequest<IReq_CreateBucket>(url, 'createBucket');
await createBucket.fire({ identity, bucketName: 'persisted-creds-bucket' });
const bucketsAfterRestart = await listBuckets.fire({ identity });
assertEquals(
bucketsAfterRestart.buckets.some((bucket) => bucket.name === 'persisted-creds-bucket'),
true,
);
} finally {
await stopContainer();
await cleanupStorageDirectory();
}
});
it('lets explicit environment credentials override persisted managed credentials', async () => {
const portIndex = 10;
const envPorts = getTestPorts(portIndex);
const envUrl = `http://localhost:${envPorts.uiPort}/typedrequest`;
const envStorageDirectory = `.nogit/testdata-${portIndex}`;
const previousAccessKey = Deno.env.get('OBJST_ACCESS_KEY');
const previousSecretKey = Deno.env.get('OBJST_SECRET_KEY');
let container: ObjectStorageContainer | null = null;
const cleanupEnvStorageDirectory = async () => {
try {
await Deno.remove(envStorageDirectory, { recursive: true });
} catch (error) {
if (!(error instanceof Deno.errors.NotFound)) {
throw error;
}
}
};
try {
await cleanupEnvStorageDirectory();
await Deno.mkdir(`${envStorageDirectory}/.objectstorage`, { recursive: true });
await Deno.writeTextFile(
`${envStorageDirectory}/.objectstorage/admin-config.json`,
JSON.stringify({
accessCredentials: [{ accessKeyId: 'persisted-key', secretAccessKey: 'persisted-secret' }],
}),
);
Deno.env.set('OBJST_ACCESS_KEY', 'env-key');
Deno.env.set('OBJST_SECRET_KEY', 'env-secret');
container = createTestContainer(portIndex, { storageDirectory: envStorageDirectory });
await container.start();
const identity = await loginAndGetIdentity(envPorts.uiPort);
const getCredentials = new TypedRequest<IReq_GetCredentials>(envUrl, 'getCredentials');
const response = await getCredentials.fire({ identity });
assertEquals(response.credentials.length, 1);
assertEquals(response.credentials[0].accessKeyId, 'env-key');
} finally {
if (container) {
await container.stop();
}
if (previousAccessKey === undefined) {
Deno.env.delete('OBJST_ACCESS_KEY');
} else {
Deno.env.set('OBJST_ACCESS_KEY', previousAccessKey);
}
if (previousSecretKey === undefined) {
Deno.env.delete('OBJST_SECRET_KEY');
} else {
Deno.env.set('OBJST_SECRET_KEY', previousSecretKey);
}
await cleanupEnvStorageDirectory();
}
});
it('does not persist rejected credential replacements', async () => {
const portIndex = 11;
const rejectPorts = getTestPorts(portIndex);
const rejectUrl = `http://localhost:${rejectPorts.uiPort}/typedrequest`;
const rejectStorageDirectory = `.nogit/testdata-${portIndex}`;
let container: ObjectStorageContainer | null = null;
const cleanupRejectStorageDirectory = async () => {
try {
await Deno.remove(rejectStorageDirectory, { recursive: true });
} catch (error) {
if (!(error instanceof Deno.errors.NotFound)) {
throw error;
}
}
};
try {
await cleanupRejectStorageDirectory();
container = createTestContainer(portIndex, { storageDirectory: rejectStorageDirectory });
await container.start();
await assertRejects(() =>
container!.replaceAccessCredentials([
{ accessKeyId: 'duplicate-key', secretAccessKey: 'secret-a' },
{ accessKeyId: 'duplicate-key', secretAccessKey: 'secret-b' },
])
);
const identity = await loginAndGetIdentity(rejectPorts.uiPort);
const getCredentials = new TypedRequest<IReq_GetCredentials>(rejectUrl, 'getCredentials');
const response = await getCredentials.fire({ identity });
assertEquals(response.credentials.length, 1);
assertEquals(response.credentials[0].accessKeyId, TEST_ACCESS_KEY);
await assertRejects(() =>
Deno.readTextFile(`${rejectStorageDirectory}/.objectstorage/admin-config.json`)
);
} finally {
if (container) {
await container.stop();
}
await cleanupRejectStorageDirectory();
}
});
});