Skip to content

fix: enable automated E2E test execution via Docker#5725

Draft
ruslanPL-EnvisionBlockchain wants to merge 5 commits intodevelopfrom
fix/cypress-docker-execution
Draft

fix: enable automated E2E test execution via Docker#5725
ruslanPL-EnvisionBlockchain wants to merge 5 commits intodevelopfrom
fix/cypress-docker-execution

Conversation

@ruslanPL-EnvisionBlockchain
Copy link
Collaborator

Description:

This PR includes the following changes:

  • Added a Docker-based Cypress runner that works locally and in CI (including a Chromium-capable image).
  • Added a single entrypoint that assembles the Cypress command, prepares artifact directories, and forwards env vars.
  • Added robust tag handling so grepTags=all and multi-tag inputs like preparing policies work reliably (spaces and commas supported).
  • Added a way to override API origins for Docker/Desktop networking so containers can reach host services consistently.
  • Added artifact export/collection for reports, JUnit, screenshots, videos, and downloads (and updated CI to upload them).
  • Updated documentation with exact run commands, tag usage, Docker notes, and how to open reports locally.

Related issue(s):

Fixes #

Notes for reviewer:

Checklist

  • Documented (Code comments, README, etc.)
  • Tested (E2E automated tests)

const variables = FormulaImportExport.getItems(expression?.variables, []);
for (const item of variables) {
items.push({
uuid: GenerateUUIDv4(),

Check failure

Code scanning / CodeQL

Insecure randomness

This uses a cryptographically insecure random number generated at [Math.random()](1) in a security context.

Copilot Autofix

AI 4 days ago

In general, to fix this problem we must stop using Math.random to generate UUIDs and instead use a cryptographically secure source of randomness. In Node, this is typically crypto.randomUUID() (Node 14.17+/16+) or crypto.randomBytes; in browsers, crypto.getRandomValues. Since GenerateUUIDv4 is shared via @guardian/interfaces and used from Node code, we should implement it using a secure source that works in both environments or gracefully falls back where needed.

The best single change without altering existing behavior at call sites is to update interfaces/src/helpers/generate-uuid-v4.ts so that GenerateUUIDv4 (and, for completeness, GenerateID) use a CSPRNG. We will: (1) import Node’s crypto module; (2) implement a small helper that obtains random bytes using crypto.randomUUID() if available, otherwise crypto.randomBytes, and in a browser environment uses globalThis.crypto.getRandomValues if present; and (3) implement UUID v4 formatting and 32-hex ID formatting using those bytes instead of Math.random. The public API (GenerateUUIDv4() and GenerateID()) and their return types stay the same, so existing code like GenerateUUIDv4() in formula.ts continues to work while now being backed by secure randomness.

Concretely:

  • Edit interfaces/src/helpers/generate-uuid-v4.ts:
    • Add import crypto from 'crypto'; at the top.
    • Replace the GenerateUUIDv4 implementation to first try crypto.randomUUID() when available, then otherwise generate 16 random bytes and set the version/variant bits per RFC 4122.
    • Replace GenerateID so it uses a buffer of random bytes (e.g., 16 bytes = 32 hex chars) and maps those to hex characters.
  • No changes are required in common/src/import-export/formula.ts, since it already imports and calls GenerateUUIDv4 by name.

Suggested changeset 1
interfaces/src/helpers/generate-uuid-v4.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/interfaces/src/helpers/generate-uuid-v4.ts b/interfaces/src/helpers/generate-uuid-v4.ts
--- a/interfaces/src/helpers/generate-uuid-v4.ts
+++ b/interfaces/src/helpers/generate-uuid-v4.ts
@@ -1,23 +1,64 @@
+import crypto from 'crypto';
+
 /**
- * Generate random UUID
+ * Generate random UUID (v4) using a cryptographically secure PRNG.
  */
 export function GenerateUUIDv4() {
-    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
-        // tslint:disable-next-line:no-bitwise
-        const r = Math.random() * 16 | 0;
-        // tslint:disable-next-line:no-bitwise
-        const v = c === 'x' ? r : (r & 0x3 | 0x8);
-        return v.toString(16);
-    });
+    // Prefer native crypto.randomUUID when available (Node 14.17+/16+, modern browsers)
+    const anyCrypto: any = (globalThis as any).crypto ?? crypto;
+    if (anyCrypto && typeof anyCrypto.randomUUID === 'function') {
+        return anyCrypto.randomUUID();
+    }
+
+    const bytes = new Uint8Array(16);
+
+    if ((globalThis as any).crypto && typeof (globalThis as any).crypto.getRandomValues === 'function') {
+        (globalThis as any).crypto.getRandomValues(bytes);
+    } else {
+        const nodeBytes = crypto.randomBytes(16);
+        for (let i = 0; i < 16; i++) {
+            bytes[i] = nodeBytes[i];
+        }
+    }
+
+    // Per RFC 4122: set version to 4
+    bytes[6] = (bytes[6] & 0x0f) | 0x40;
+    // Per RFC 4122: set variant to 10xxxxxx
+    bytes[8] = (bytes[8] & 0x3f) | 0x80;
+
+    const hex: string[] = [];
+    for (let i = 0; i < bytes.length; i++) {
+        const h = bytes[i].toString(16).padStart(2, '0');
+        hex.push(h);
+    }
+
+    return (
+        hex[0] + hex[1] + hex[2] + hex[3] + '-' +
+        hex[4] + hex[5] + '-' +
+        hex[6] + hex[7] + '-' +
+        hex[8] + hex[9] + '-' +
+        hex[10] + hex[11] + hex[12] + hex[13] + hex[14] + hex[15]
+    );
 }
 
 /**
- * Generate random UUID
+ * Generate random 32-hex-character ID using a cryptographically secure PRNG.
  */
 export function GenerateID() {
-    return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, (c) => {
-        // tslint:disable-next-line:no-bitwise
-        const v = Math.random() * 16 | 0;
-        return v.toString(16);
-    });
+    // 16 bytes => 32 hex characters
+    const bytes = new Uint8Array(16);
+    if ((globalThis as any).crypto && typeof (globalThis as any).crypto.getRandomValues === 'function') {
+        (globalThis as any).crypto.getRandomValues(bytes);
+    } else {
+        const nodeBytes = crypto.randomBytes(16);
+        for (let i = 0; i < 16; i++) {
+            bytes[i] = nodeBytes[i];
+        }
+    }
+
+    let id = '';
+    for (let i = 0; i < bytes.length; i++) {
+        id += bytes[i].toString(16).padStart(2, '0');
+    }
+    return id;
 }
\ No newline at end of file
EOF
Copilot is powered by AI and may make mistakes. Always verify output.
const formulas = FormulaImportExport.getItems(expression?.formulas, []);
for (const item of formulas) {
items.push({
uuid: GenerateUUIDv4(),

Check failure

Code scanning / CodeQL

Insecure randomness

This uses a cryptographically insecure random number generated at [Math.random()](1) in a security context.

Copilot Autofix

AI 4 days ago

In general, to fix insecure randomness, any function that currently uses Math.random to generate security‑sensitive identifiers should instead use a cryptographically secure random source. In Node.js this is typically crypto.randomBytes, and in browsers it is crypto.getRandomValues. For a UUID v4 generator, we want 16 bytes of secure randomness and to set the version and variant bits according to RFC 4122, or equivalently, generate random hex digits using secure random numbers instead of Math.random.

The best targeted fix here is to change GenerateUUIDv4 (and, for completeness, the similar GenerateID) in interfaces/src/helpers/generate-uuid-v4.ts to use a CSPRNG while preserving the existing function signatures and return formats. We can do this by importing Node’s crypto module and using crypto.randomBytes when window.crypto (browser) is not available, and window.crypto.getRandomValues (or self.crypto) when in a browser context. To minimize functional changes, we keep the same UUID string pattern (xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx) and GenerateID’s 32‑hex‑character string; only the internal randomness source changes.

Concretely:

  • Update interfaces/src/helpers/generate-uuid-v4.ts to:
    • Import randomBytes from Node’s crypto module.
    • Add a small helper getSecureRandomByte() that returns a number in [0, 255] using window.crypto.getRandomValues when available, otherwise randomBytes(1)[0].
    • Rewrite GenerateUUIDv4’s .replace callback to use getSecureRandomByte() (appropriately masked/scaled to 4‑bit values) instead of Math.random.
    • Rewrite GenerateID similarly to use secure random nibbles, again replacing Math.random with the helper.
      These changes are entirely confined to interfaces/src/helpers/generate-uuid-v4.ts; the code in common/src/import-export/formula.ts can stay as is, since once GenerateUUIDv4 is secure the use at line 270 (and others) is safe.

Suggested changeset 1
interfaces/src/helpers/generate-uuid-v4.ts
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/interfaces/src/helpers/generate-uuid-v4.ts b/interfaces/src/helpers/generate-uuid-v4.ts
--- a/interfaces/src/helpers/generate-uuid-v4.ts
+++ b/interfaces/src/helpers/generate-uuid-v4.ts
@@ -1,23 +1,45 @@
+import { randomBytes } from 'crypto';
+
 /**
+ * Get a cryptographically secure random byte (0-255)
+ */
+function getSecureRandomByte(): number {
+    // Browser environments
+    const g: any = (typeof globalThis !== 'undefined') ? globalThis : (typeof window !== 'undefined' ? window : undefined);
+    if (g && g.crypto && typeof g.crypto.getRandomValues === 'function') {
+        const array = new Uint8Array(1);
+        g.crypto.getRandomValues(array);
+        return array[0];
+    }
+
+    // Node.js fallback
+    return randomBytes(1)[0];
+}
+
+/**
  * Generate random UUID
  */
 export function GenerateUUIDv4() {
     return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
+        const randomByte = getSecureRandomByte();
+        // use lower 4 bits
         // tslint:disable-next-line:no-bitwise
-        const r = Math.random() * 16 | 0;
+        const r = randomByte & 0x0f;
         // tslint:disable-next-line:no-bitwise
-        const v = c === 'x' ? r : (r & 0x3 | 0x8);
+        const v = c === 'x' ? r : ((r & 0x3) | 0x8);
         return v.toString(16);
     });
 }
 
 /**
- * Generate random UUID
+ * Generate random ID (32 hex characters)
  */
 export function GenerateID() {
-    return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, (c) => {
+    return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, () => {
+        const randomByte = getSecureRandomByte();
+        // use lower 4 bits
         // tslint:disable-next-line:no-bitwise
-        const v = Math.random() * 16 | 0;
+        const v = randomByte & 0x0f;
         return v.toString(16);
     });
 }
\ No newline at end of file
EOF
@@ -1,23 +1,45 @@
import { randomBytes } from 'crypto';

/**
* Get a cryptographically secure random byte (0-255)
*/
function getSecureRandomByte(): number {
// Browser environments
const g: any = (typeof globalThis !== 'undefined') ? globalThis : (typeof window !== 'undefined' ? window : undefined);
if (g && g.crypto && typeof g.crypto.getRandomValues === 'function') {
const array = new Uint8Array(1);
g.crypto.getRandomValues(array);
return array[0];
}

// Node.js fallback
return randomBytes(1)[0];
}

/**
* Generate random UUID
*/
export function GenerateUUIDv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const randomByte = getSecureRandomByte();
// use lower 4 bits
// tslint:disable-next-line:no-bitwise
const r = Math.random() * 16 | 0;
const r = randomByte & 0x0f;
// tslint:disable-next-line:no-bitwise
const v = c === 'x' ? r : (r & 0x3 | 0x8);
const v = c === 'x' ? r : ((r & 0x3) | 0x8);
return v.toString(16);
});
}

/**
* Generate random UUID
* Generate random ID (32 hex characters)
*/
export function GenerateID() {
return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, (c) => {
return 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'.replace(/[x]/g, () => {
const randomByte = getSecureRandomByte();
// use lower 4 bits
// tslint:disable-next-line:no-bitwise
const v = Math.random() * 16 | 0;
const v = randomByte & 0x0f;
return v.toString(16);
});
}
Copilot is powered by AI and may make mistakes. Always verify output.
@ruslanPL-EnvisionBlockchain ruslanPL-EnvisionBlockchain changed the base branch from main to develop February 16, 2026 14:06
@github-actions
Copy link

github-actions bot commented Feb 16, 2026

Test Results

 32 files  ±0   64 suites  ±0   7m 37s ⏱️ + 2m 16s
 35 tests ±0   35 ✅ +3  0 💤 ±0  0 ❌  - 3 
164 runs  ±0  164 ✅ +3  0 💤 ±0  0 ❌  - 3 

Results for commit 297f850. ± Comparison against base commit 2cef73a.

♻️ This comment has been updated with latest results.

@ruslanPL-EnvisionBlockchain ruslanPL-EnvisionBlockchain changed the title Enable automated E2E test execution via Docker fix(*): enable automated E2E test execution via Docker Feb 17, 2026
@ruslanPL-EnvisionBlockchain ruslanPL-EnvisionBlockchain force-pushed the fix/cypress-docker-execution branch 6 times, most recently from 52722e3 to 2b222e9 Compare February 17, 2026 15:02
Base automatically changed from develop to main February 17, 2026 21:33
@Pyatakov Pyatakov changed the base branch from main to develop February 17, 2026 21:45
@Pyatakov Pyatakov changed the title fix(*): enable automated E2E test execution via Docker fix: enable automated E2E test execution via Docker Feb 17, 2026
- Corrected links in README and added sections for running tests with tags, Docker setup, and CI/CD integration.
- Enhanced the entrypoint script to automatically prepend the 'preparing' tag for user account creation.
- Updated docker-compose configuration to improve environment variable handling and image naming.
- Adjusted GitHub Actions workflow to ensure proper Docker image building and test result handling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments