Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 72 additions & 36 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"testcontainers": "12.2.1"
},
"devDependencies": {
"@biomejs/biome": "2.5.15",
"@biomejs/biome": "2.6.2",
"@types/node": "26.6.5",
"get-port": "7.2.0",
"tsx": "4.23.15",
Expand Down
4 changes: 4 additions & 0 deletions src/Event.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ suite('Event', () => {
test(
'throws an error if the hash verification fails.',
containerStartTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
await container.stop();
const imageTag = getImageTag();
Expand Down Expand Up @@ -203,6 +204,7 @@ suite('Event', () => {
test(
'throws an error if the signature verification fails.',
containerStartTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
await container.stop();
const imageTag = getImageTag();
Expand Down Expand Up @@ -238,6 +240,7 @@ suite('Event', () => {
},
);

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
test('verifies the signature.', containerStartTimeout, async (): Promise<void> => {
await container.stop();
const imageTag = getImageTag();
Expand Down Expand Up @@ -273,6 +276,7 @@ suite('Event', () => {
test(
'verifies the signature of an event as written, read, and observed, whatever its data and trace context.',
containerStartTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
await container.stop();
const imageTag = getImageTag();
Expand Down
21 changes: 13 additions & 8 deletions src/Event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,20 @@ const hashVersionRegex = /^esdb:hash:(?<version>[^:]*):/u;
// have like this.
const missingField = '-';

// A signature starts with this prefix, followed by its bytes in hex.
const signaturePrefix = 'esdb:signature:v1:';

const getSha256 = (input: string): string =>
crypto.createHash('sha256').update(input).digest('hex');

const getSignatureBytes = (signature: string): Buffer => {
if (!signature.startsWith(signaturePrefix)) {
throw new Error(`Signature must start with '${signaturePrefix}'`);
}

return Buffer.from(signature.slice(signaturePrefix.length), 'hex');
};

class Event {
public specversion: string;
public id: string;
Expand All @@ -33,6 +44,7 @@ class Event {
public tracestate?: string;
public signature: string | null;

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The constructor assigns each field of the event, one statement per field.
public constructor({
specversion,
id,
Expand Down Expand Up @@ -145,14 +157,7 @@ class Event {

this.verifyHash();

const signaturePrefix = 'esdb:signature:v1:';

if (!this.signature.startsWith(signaturePrefix)) {
throw new Error(`Signature must start with '${signaturePrefix}'`);
}

const signature = this.signature.slice(signaturePrefix.length);
const signatureBytes = Buffer.from(signature, 'hex');
const signatureBytes = getSignatureBytes(this.signature);
const hashBytes = Buffer.from(this.hash, 'utf8');

const isSignatureValid = crypto.verify(null, hashBytes, verificationKey, signatureBytes);
Expand Down
2 changes: 2 additions & 0 deletions src/abortSignal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ suite('abortSignal', { timeout: 30_000 }, () => {
defineTestsFor(request);
}

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
test('throws an abort error if the caller aborts while the response body arrives.', async (): Promise<void> => {
server.respond = (_request: FakeRequest, response: ServerResponse): void => {
writeHead(response, 200, 'application/json');
Expand Down Expand Up @@ -173,6 +174,7 @@ suite('abortSignal', { timeout: 30_000 }, () => {
await server.connectionsClosed();
});

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
test('throws an unknown outcome if the caller aborts a write while the response body arrives.', async (): Promise<void> => {
server.respond = (_request: FakeRequest, response: ServerResponse): void => {
writeHead(response, 200, 'application/json');
Expand Down
1 change: 1 addition & 0 deletions src/container/isReachable.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface Answer {
delay?: number;
}

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: A suite counts each of its tests as a statement.
suite('isReachable', () => {
let server: FakeServer;

Expand Down
6 changes: 6 additions & 0 deletions src/container/startContainer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const listContainers = async (testId: string): Promise<ContainerInfo[]> => {
// instead of asking for its events afterwards. Docker passes on its events in
// order, so to stop, the test creates a container of its own and waits for its
// event, after which the events of all containers created before have arrived.
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: Watching opens the event stream of Docker, collects the start labels from it, and returns the function that ends it, all of which share the stream.
const watchCreatedContainers = async (
testId: string,
image: string,
Expand Down Expand Up @@ -98,6 +99,7 @@ const watchCreatedContainers = async (
};
};

// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: A suite counts each of its tests as a statement.
suite('startContainer', () => {
const image = `thenativeweb/eventsourcingdb:${getImageTag()}`;

Expand Down Expand Up @@ -256,6 +258,7 @@ suite('startContainer', () => {
test(
'replaces a running container whose port testcontainers cannot find, and removes it.',
integrationTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
const testId = randomUUID();
const endFailing = await failPortLookups(1);
Expand Down Expand Up @@ -327,6 +330,7 @@ suite('startContainer', () => {
test(
'does not count pulling the image towards the startup timeout.',
integrationTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
const testId = randomUUID();
const client = await getContainerRuntimeClient();
Expand Down Expand Up @@ -377,6 +381,7 @@ suite('startContainer', () => {
test(
'removes a container that Docker creates only after the wait for it has ended, without waiting for it.',
integrationTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
const testId = randomUUID();
const client = await getContainerRuntimeClient();
Expand Down Expand Up @@ -439,6 +444,7 @@ suite('startContainer', () => {
test(
'reports a failed removal after the error of the start, and goes on with the next attempt.',
integrationTimeout,
// biome-ignore lint/nursery/noExcessiveStatementsPerFunction: The test is one linear sequence of steps, and splitting it would make it harder to follow.
async (): Promise<void> => {
const testId = randomUUID();
const client = await getContainerRuntimeClient();
Expand Down
Loading
Loading