@sudobility/testomniac_runner 0.0.128 → 0.0.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example CHANGED
@@ -1,67 +1,77 @@
1
1
  # =============================================================================
2
- # Testomniac Scanner Environment Variables
2
+ # Testomniac Runner Environment Variables
3
3
  # =============================================================================
4
4
  # Copy this file to .env and fill in your values.
5
5
 
6
6
  # -----------------------------------------------------------------------------
7
7
  # Server
8
8
  # -----------------------------------------------------------------------------
9
+
10
+ # Port for the health/status HTTP endpoint (Hono server)
9
11
  PORT=8030
10
- NODE_ENV=development
12
+
13
+ # Pino log level: trace | debug | info | warn | error | fatal
11
14
  LOG_LEVEL=info
12
15
 
13
16
  # -----------------------------------------------------------------------------
14
- # API Connection (Required)
17
+ # API
15
18
  # -----------------------------------------------------------------------------
16
- # URL of the testomniac_api instance
17
- TESTOMNIAC_API_URL=http://localhost:8027
18
19
 
19
- # Shared secret for authenticating with the API. Must match SCANNER_API_KEY in the API's .env.
20
+ # URL of the testomniac_api instance this runner polls for pending runs
21
+ TESTOMNIAC_API_URL=https://api.testomniac.com
22
+
23
+ # Shared secret for X-Scanner-Key auth. Must match SCANNER_API_KEY in the API's .env.
20
24
  # Generate with: openssl rand -hex 32
21
25
  SCANNER_API_KEY=
22
26
 
23
27
  # -----------------------------------------------------------------------------
24
- # Scan Polling
28
+ # Polling & Concurrency
25
29
  # -----------------------------------------------------------------------------
26
- # How often (ms) the scanner polls the API for pending runs
30
+
31
+ # How often (ms) the runner polls the API for pending runs
27
32
  SCAN_POLL_INTERVAL_MS=10000
28
33
 
34
+ # Maximum number of test runs executing in parallel
35
+ MAX_CONCURRENT_RUNNERS=5
36
+
29
37
  # -----------------------------------------------------------------------------
30
- # OpenAI (Required for AI analysis phase)
38
+ # Browser
31
39
  # -----------------------------------------------------------------------------
32
- OPENAI_API_KEY=
40
+
41
+ # Path to Chrome/Chromium binary. Auto-detected from Puppeteer cache if not set.
42
+ # Only set this to override auto-detection (e.g. Docker: /usr/bin/chromium).
43
+ # CHROMIUM_PATH=/usr/bin/chromium
44
+
45
+ # Directory for persistent browser profile (cookies, cache, etc.)
46
+ USER_DATA_DIR=./testomniac-browser-profile
47
+
48
+ # Directory for screenshots and other scan artifacts (JPEG, quality 72)
49
+ ARTIFACT_DIR=./testomniac-artifacts
33
50
 
34
51
  # -----------------------------------------------------------------------------
35
- # Email Reports (Optional - only needed if sending scan report emails)
52
+ # Email Reports (Optional only needed if sending scan report emails)
36
53
  # -----------------------------------------------------------------------------
37
- # Postmark API token for sending emails
54
+
55
+ # Postmark API token for sending emails. Leave empty to disable email reports.
38
56
  POSTMARK_SERVER_TOKEN=
39
57
 
40
- # Sender email address for report emails
58
+ # Sender email address shown on report emails
41
59
  POSTMARK_FROM_EMAIL=
42
60
 
43
- # Secret key for signing deep-link JWTs in report emails.
44
- # If not set, deep links will use an empty key (insecure but functional).
61
+ # Secret for signing deep-link JWTs embedded in report emails.
62
+ # If empty, deep links use an empty key (insecure fine for local dev).
45
63
  # Generate with: openssl rand -hex 32
46
64
  DEEP_LINK_SECRET=
47
65
 
48
- # Base URL of the frontend app, used for building deep-link URLs in emails
66
+ # Base URL of the frontend app, used to build deep-link URLs in emails
49
67
  APP_BASE_URL=http://localhost:3000
50
68
 
51
69
  # -----------------------------------------------------------------------------
52
- # Signic Email Verification (Optional - for email-based auth scanning)
70
+ # Signic Email Verification (Optional for email-based auth scanning)
53
71
  # -----------------------------------------------------------------------------
54
- SIGNIC_INDEXER_URL=https://api.signic.email/idx
55
- SIGNIC_WILDDUCK_URL=https://api.signic.email/api
56
72
 
57
- # -----------------------------------------------------------------------------
58
- # Browser / Filesystem
59
- # -----------------------------------------------------------------------------
60
- # Path to Chromium binary
61
- CHROMIUM_PATH=/usr/bin/chromium
62
-
63
- # Directory for browser profile persistence
64
- USER_DATA_DIR=./browser-profile
73
+ # Signic indexer URL for polling verification/confirmation emails
74
+ SIGNIC_INDEXER_URL=https://api.signic.email/idx
65
75
 
66
- # Directory for storing screenshots and other scan artifacts
67
- ARTIFACT_DIR=./artifacts
76
+ # Signic email API URL for disposable email account management
77
+ SIGNIC_EMAIL_API_URL=https://api.signic.email/api
@@ -24,6 +24,7 @@ jobs:
24
24
  with:
25
25
  docker-image-name: "testomniac_runner"
26
26
  skip-npm-publish: false
27
+ npm-access: "public"
27
28
  secrets:
28
29
  NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
29
30
  DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
package/bun.lock CHANGED
@@ -8,8 +8,8 @@
8
8
  "@noble/curves": "^1.0.0",
9
9
  "@noble/hashes": "^1.0.0",
10
10
  "@sudobility/signic_sdk": "^0.1.7",
11
- "@sudobility/testomniac_runner_service": "^0.1.127",
12
- "@sudobility/testomniac_types": "^0.0.66",
11
+ "@sudobility/testomniac_runner_service": "^0.1.128",
12
+ "@sudobility/testomniac_types": "^0.0.67",
13
13
  "hono": "^4.7.0",
14
14
  "jose": "^6.1.2",
15
15
  "openai": "^6.7.0",
@@ -172,9 +172,9 @@
172
172
 
173
173
  "@sudobility/signic_sdk": ["@sudobility/signic_sdk@0.1.7", "", {}, "sha512-5XSgHSVsmyrMQ/ui1nDywwzt9dbRCsaeJ5tX6mKw2ZXbTZ82OsMr+dqDyV9XV3pfy7IHRIZq73af5KBamx72Fw=="],
174
174
 
175
- "@sudobility/testomniac_runner_service": ["@sudobility/testomniac_runner_service@0.1.127", "", { "peerDependencies": { "@sudobility/testomniac_types": "^0.0.66", "openai": ">=6.0.0", "react": ">=18.0.0" }, "optionalPeers": ["openai", "react"] }, "sha512-H/zf41bhFyvd0JR9TZlqPDJksdlmdTCrmvuoRDBVrJ58Wk7ktVESYBs9DCTj6Spd6SOsanu+rK+3bNjrZorsfQ=="],
175
+ "@sudobility/testomniac_runner_service": ["@sudobility/testomniac_runner_service@0.1.128", "", { "peerDependencies": { "@sudobility/testomniac_types": "^0.0.67", "openai": ">=6.0.0", "react": ">=18.0.0" }, "optionalPeers": ["openai", "react"] }, "sha512-YWFjcMmZROSHSNUZLt9czUJeWoYmIj69JCXUP9CD9sw5/UTzFFLwIdkqtAE2lG4RDo/Yb/5heZPmffZ1EfPPqw=="],
176
176
 
177
- "@sudobility/testomniac_types": ["@sudobility/testomniac_types@0.0.66", "", { "peerDependencies": { "@sudobility/types": "^1.9.62" } }, "sha512-2oGnWAX1QM2J5AsMYl89PiLALIg5TFZFkm0C7VQxnHkvH1mRUfyLNjnrX/3kCMn5SwwL1/ljXDUWb+FYXEW/qA=="],
177
+ "@sudobility/testomniac_types": ["@sudobility/testomniac_types@0.0.67", "", { "peerDependencies": { "@sudobility/types": "^1.9.62" } }, "sha512-kNBDk7AsFx1rqUWLq4nx0nf1alV9G7U5xbxj8qDvZKa+cCnUSiZFRtDB88ENWQzeIPVJAU8MaVo5yUKVL46eYg=="],
178
178
 
179
179
  "@sudobility/types": ["@sudobility/types@1.9.61", "", {}, "sha512-SODGpstB/iKfK3H/4BvJx/FBcc1h3gutUjGotyxN19VnOfWyzaDoEmW7eyoxOAYhZyXMXagSiii+NIEZvuxKog=="],
180
180
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sudobility/testomniac_runner",
3
- "version": "0.0.128",
3
+ "version": "0.0.130",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -24,8 +24,8 @@
24
24
  "@noble/curves": "^1.0.0",
25
25
  "@noble/hashes": "^1.0.0",
26
26
  "@sudobility/signic_sdk": "^0.1.7",
27
- "@sudobility/testomniac_runner_service": "^0.1.127",
28
- "@sudobility/testomniac_types": "^0.0.66",
27
+ "@sudobility/testomniac_runner_service": "^0.1.128",
28
+ "@sudobility/testomniac_types": "^0.0.67",
29
29
  "hono": "^4.7.0",
30
30
  "jose": "^6.1.2",
31
31
  "openai": "^6.7.0",
@@ -51,7 +51,7 @@ export async function autoRegister(
51
51
 
52
52
  const client = new SignicClient({
53
53
  indexerUrl: config.signicIndexerUrl,
54
- wildduckUrl: config.signicWildduckUrl,
54
+ wildduckUrl: config.signicEmailApiUrl,
55
55
  signMessage: async (message: string) => signEthMessage(message, privateKey),
56
56
  });
57
57
 
@@ -1,7 +1,66 @@
1
+ import { existsSync, readdirSync } from "node:fs";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
1
4
  import puppeteer, { type Browser, type Page } from "puppeteer-core";
2
5
  import type { Config } from "../config/index";
3
6
  import type { Screen } from "@sudobility/testomniac_types";
4
7
 
8
+ /**
9
+ * Finds the latest Chrome for Testing binary in the Puppeteer cache.
10
+ * Falls back to common system paths, then to the config value.
11
+ */
12
+ export function resolveChromiumPath(configPath: string): string {
13
+ // Explicit env var / config always wins
14
+ if (process.env.CHROMIUM_PATH) return process.env.CHROMIUM_PATH;
15
+
16
+ // Scan Puppeteer cache for the latest Chrome for Testing
17
+ const cacheDir = join(homedir(), ".cache", "puppeteer", "chrome");
18
+ if (existsSync(cacheDir)) {
19
+ const platform =
20
+ process.platform === "darwin"
21
+ ? process.arch === "arm64"
22
+ ? "mac_arm"
23
+ : "mac-x64"
24
+ : "linux";
25
+ const versions = readdirSync(cacheDir)
26
+ .filter(d => d.startsWith(platform + "-"))
27
+ .sort()
28
+ .reverse();
29
+
30
+ for (const version of versions) {
31
+ const candidates =
32
+ process.platform === "darwin"
33
+ ? [
34
+ join(
35
+ cacheDir,
36
+ version,
37
+ "chrome-mac-arm64",
38
+ "Google Chrome for Testing.app",
39
+ "Contents",
40
+ "MacOS",
41
+ "Google Chrome for Testing"
42
+ ),
43
+ join(
44
+ cacheDir,
45
+ version,
46
+ "chrome-mac-x64",
47
+ "Google Chrome for Testing.app",
48
+ "Contents",
49
+ "MacOS",
50
+ "Google Chrome for Testing"
51
+ ),
52
+ ]
53
+ : [join(cacheDir, version, "chrome-linux64", "chrome")];
54
+
55
+ for (const candidate of candidates) {
56
+ if (existsSync(candidate)) return candidate;
57
+ }
58
+ }
59
+ }
60
+
61
+ return configPath;
62
+ }
63
+
5
64
  export class ChromiumManager {
6
65
  private browser: Browser | null = null;
7
66
 
@@ -9,7 +68,7 @@ export class ChromiumManager {
9
68
 
10
69
  async launch(): Promise<Browser> {
11
70
  this.browser = await puppeteer.launch({
12
- executablePath: this.config.chromiumPath,
71
+ executablePath: resolveChromiumPath(this.config.chromiumPath),
13
72
  userDataDir: this.config.userDataDir,
14
73
  headless: true,
15
74
  args: ["--no-sandbox", "--disable-setuid-sandbox"],
@@ -17,7 +17,7 @@ describe("config", () => {
17
17
 
18
18
  it("uses defaults for optional values", () => {
19
19
  const config = loadConfig();
20
- expect(config.artifactDir).toBe("./artifacts");
21
- expect(config.userDataDir).toBe("./browser-profile");
20
+ expect(config.artifactDir).toBe("./testomniac-artifacts");
21
+ expect(config.userDataDir).toBe("./testomniac-browser-profile");
22
22
  });
23
23
  });
@@ -1,13 +1,12 @@
1
1
  export interface Config {
2
2
  apiUrl: string;
3
3
  scannerApiKey: string;
4
- openaiApiKey: string;
5
4
  postmarkServerToken: string;
6
5
  postmarkFromEmail: string;
7
6
  deepLinkSecret: string;
8
7
  appBaseUrl: string;
9
8
  signicIndexerUrl: string;
10
- signicWildduckUrl: string;
9
+ signicEmailApiUrl: string;
11
10
  chromiumPath: string;
12
11
  userDataDir: string;
13
12
  artifactDir: string;
@@ -16,20 +15,19 @@ export interface Config {
16
15
 
17
16
  export function loadConfig(): Config {
18
17
  return {
19
- apiUrl: process.env.TESTOMNIAC_API_URL || "http://localhost:8027",
18
+ apiUrl: process.env.TESTOMNIAC_API_URL || "https://api.testomniac.com",
20
19
  scannerApiKey: process.env.SCANNER_API_KEY || "",
21
- openaiApiKey: process.env.OPENAI_API_KEY || "",
22
20
  postmarkServerToken: process.env.POSTMARK_SERVER_TOKEN || "",
23
21
  postmarkFromEmail: process.env.POSTMARK_FROM_EMAIL || "",
24
22
  deepLinkSecret: process.env.DEEP_LINK_SECRET || "",
25
23
  appBaseUrl: process.env.APP_BASE_URL || "http://localhost:3000",
26
24
  signicIndexerUrl:
27
25
  process.env.SIGNIC_INDEXER_URL || "https://api.signic.email/idx",
28
- signicWildduckUrl:
29
- process.env.SIGNIC_WILDDUCK_URL || "https://api.signic.email/api",
26
+ signicEmailApiUrl:
27
+ process.env.SIGNIC_EMAIL_API_URL || "https://api.signic.email/api",
30
28
  chromiumPath: process.env.CHROMIUM_PATH || "/usr/bin/chromium",
31
- userDataDir: process.env.USER_DATA_DIR || "./browser-profile",
32
- artifactDir: process.env.ARTIFACT_DIR || "./artifacts",
29
+ userDataDir: process.env.USER_DATA_DIR || "./testomniac-browser-profile",
30
+ artifactDir: process.env.ARTIFACT_DIR || "./testomniac-artifacts",
33
31
  maxConcurrentRunners: Number(process.env.MAX_CONCURRENT_RUNNERS ?? 5),
34
32
  };
35
33
  }