@sudobility/testomniac_runner 0.0.128
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/.dockerignore +75 -0
- package/.env.example +67 -0
- package/.github/workflows/ci-cd.yml +30 -0
- package/.prettierignore +62 -0
- package/.prettierrc +11 -0
- package/.vscode/settings.json +29 -0
- package/CLAUDE.md +170 -0
- package/Dockerfile +76 -0
- package/README.md +22 -0
- package/bun.lock +707 -0
- package/docs/superpowers/specs/2026-04-20-smarter-scanner-navigation-design.md +121 -0
- package/eslint.config.js +80 -0
- package/package.json +55 -0
- package/plans/DATA.md +703 -0
- package/plans/POLLING.md +569 -0
- package/plans/RUNNER.md +288 -0
- package/src/adapters/PuppeteerAdapter.ts +394 -0
- package/src/auth/credential-manager.ts +17 -0
- package/src/auth/form-identifier.test.ts +136 -0
- package/src/auth/form-identifier.ts +54 -0
- package/src/auth/login-executor.ts +112 -0
- package/src/auth/password-detector.test.ts +61 -0
- package/src/auth/password-detector.ts +119 -0
- package/src/auth/signic-registrar.ts +186 -0
- package/src/browser/chromium.ts +35 -0
- package/src/config/index.test.ts +23 -0
- package/src/config/index.ts +35 -0
- package/src/email/deep-link.test.ts +17 -0
- package/src/email/deep-link.ts +23 -0
- package/src/email/sender.ts +35 -0
- package/src/email/templates.ts +34 -0
- package/src/index.test.ts +17 -0
- package/src/index.ts +110 -0
- package/src/orchestrator.ts +220 -0
- package/src/plugins/content/ai-checks.ts +115 -0
- package/src/plugins/content/checks.test.ts +49 -0
- package/src/plugins/content/checks.ts +141 -0
- package/src/plugins/content/index.ts +73 -0
- package/src/plugins/registry.test.ts +49 -0
- package/src/plugins/registry.ts +21 -0
- package/src/plugins/security/header-checks.ts +56 -0
- package/src/plugins/security/html-checks.ts +93 -0
- package/src/plugins/security/index.ts +58 -0
- package/src/plugins/security/network-checks.test.ts +74 -0
- package/src/plugins/security/network-checks.ts +136 -0
- package/src/plugins/seo/checks.test.ts +70 -0
- package/src/plugins/seo/checks.ts +173 -0
- package/src/plugins/seo/index.ts +85 -0
- package/src/plugins/types.ts +43 -0
- package/src/plugins/ui-consistency/comparator.test.ts +108 -0
- package/src/plugins/ui-consistency/comparator.ts +58 -0
- package/src/plugins/ui-consistency/index.ts +36 -0
- package/src/plugins/ui-consistency/style-extractor.ts +79 -0
- package/src/runner/executor.test.ts +37 -0
- package/src/runner/executor.ts +167 -0
- package/src/runner/reporter.ts +19 -0
- package/src/runner/worker-pool.ts +106 -0
- package/src/runner-manager.ts +163 -0
- package/src/scanner/email-checker.ts +106 -0
- package/tsconfig.json +21 -0
package/.dockerignore
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
node_modules/
|
|
2
|
+
npm-debug.log*
|
|
3
|
+
.pnpm-debug.log*
|
|
4
|
+
yarn-debug.log*
|
|
5
|
+
yarn-error.log*
|
|
6
|
+
|
|
7
|
+
# Environment files
|
|
8
|
+
.env
|
|
9
|
+
.env.local
|
|
10
|
+
.env.production
|
|
11
|
+
|
|
12
|
+
# Temporary files
|
|
13
|
+
.tmp/
|
|
14
|
+
tmp/
|
|
15
|
+
temp/
|
|
16
|
+
|
|
17
|
+
# OS generated files
|
|
18
|
+
.DS_Store
|
|
19
|
+
.DS_Store?
|
|
20
|
+
._*
|
|
21
|
+
.Spotlight-V100
|
|
22
|
+
.Trashes
|
|
23
|
+
ehthumbs.db
|
|
24
|
+
Thumbs.db
|
|
25
|
+
|
|
26
|
+
# IDE files
|
|
27
|
+
.vscode/
|
|
28
|
+
.idea/
|
|
29
|
+
*.swp
|
|
30
|
+
*.swo
|
|
31
|
+
|
|
32
|
+
# Build outputs
|
|
33
|
+
dist/
|
|
34
|
+
build/
|
|
35
|
+
|
|
36
|
+
# Logs
|
|
37
|
+
logs/
|
|
38
|
+
*.log
|
|
39
|
+
|
|
40
|
+
# Testing
|
|
41
|
+
coverage/
|
|
42
|
+
|
|
43
|
+
# Git
|
|
44
|
+
.git/
|
|
45
|
+
.gitignore
|
|
46
|
+
|
|
47
|
+
# Documentation
|
|
48
|
+
*.md
|
|
49
|
+
docs/
|
|
50
|
+
README*
|
|
51
|
+
CHANGELOG*
|
|
52
|
+
plans/
|
|
53
|
+
|
|
54
|
+
# Test files
|
|
55
|
+
tests/
|
|
56
|
+
test/
|
|
57
|
+
*.test.js
|
|
58
|
+
*.test.ts
|
|
59
|
+
*.spec.js
|
|
60
|
+
*.spec.ts
|
|
61
|
+
__tests__
|
|
62
|
+
|
|
63
|
+
# Development scripts
|
|
64
|
+
scripts/
|
|
65
|
+
|
|
66
|
+
# Docker files
|
|
67
|
+
Dockerfile*
|
|
68
|
+
docker-compose*.yml
|
|
69
|
+
.dockerignore
|
|
70
|
+
|
|
71
|
+
# Development configs
|
|
72
|
+
.eslintrc*
|
|
73
|
+
eslint.config.*
|
|
74
|
+
.prettierrc*
|
|
75
|
+
.prettierignore
|
package/.env.example
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# =============================================================================
|
|
2
|
+
# Testomniac Scanner Environment Variables
|
|
3
|
+
# =============================================================================
|
|
4
|
+
# Copy this file to .env and fill in your values.
|
|
5
|
+
|
|
6
|
+
# -----------------------------------------------------------------------------
|
|
7
|
+
# Server
|
|
8
|
+
# -----------------------------------------------------------------------------
|
|
9
|
+
PORT=8030
|
|
10
|
+
NODE_ENV=development
|
|
11
|
+
LOG_LEVEL=info
|
|
12
|
+
|
|
13
|
+
# -----------------------------------------------------------------------------
|
|
14
|
+
# API Connection (Required)
|
|
15
|
+
# -----------------------------------------------------------------------------
|
|
16
|
+
# URL of the testomniac_api instance
|
|
17
|
+
TESTOMNIAC_API_URL=http://localhost:8027
|
|
18
|
+
|
|
19
|
+
# Shared secret for authenticating with the API. Must match SCANNER_API_KEY in the API's .env.
|
|
20
|
+
# Generate with: openssl rand -hex 32
|
|
21
|
+
SCANNER_API_KEY=
|
|
22
|
+
|
|
23
|
+
# -----------------------------------------------------------------------------
|
|
24
|
+
# Scan Polling
|
|
25
|
+
# -----------------------------------------------------------------------------
|
|
26
|
+
# How often (ms) the scanner polls the API for pending runs
|
|
27
|
+
SCAN_POLL_INTERVAL_MS=10000
|
|
28
|
+
|
|
29
|
+
# -----------------------------------------------------------------------------
|
|
30
|
+
# OpenAI (Required for AI analysis phase)
|
|
31
|
+
# -----------------------------------------------------------------------------
|
|
32
|
+
OPENAI_API_KEY=
|
|
33
|
+
|
|
34
|
+
# -----------------------------------------------------------------------------
|
|
35
|
+
# Email Reports (Optional - only needed if sending scan report emails)
|
|
36
|
+
# -----------------------------------------------------------------------------
|
|
37
|
+
# Postmark API token for sending emails
|
|
38
|
+
POSTMARK_SERVER_TOKEN=
|
|
39
|
+
|
|
40
|
+
# Sender email address for report emails
|
|
41
|
+
POSTMARK_FROM_EMAIL=
|
|
42
|
+
|
|
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).
|
|
45
|
+
# Generate with: openssl rand -hex 32
|
|
46
|
+
DEEP_LINK_SECRET=
|
|
47
|
+
|
|
48
|
+
# Base URL of the frontend app, used for building deep-link URLs in emails
|
|
49
|
+
APP_BASE_URL=http://localhost:3000
|
|
50
|
+
|
|
51
|
+
# -----------------------------------------------------------------------------
|
|
52
|
+
# Signic Email Verification (Optional - for email-based auth scanning)
|
|
53
|
+
# -----------------------------------------------------------------------------
|
|
54
|
+
SIGNIC_INDEXER_URL=https://api.signic.email/idx
|
|
55
|
+
SIGNIC_WILDDUCK_URL=https://api.signic.email/api
|
|
56
|
+
|
|
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
|
|
65
|
+
|
|
66
|
+
# Directory for storing screenshots and other scan artifacts
|
|
67
|
+
ARTIFACT_DIR=./artifacts
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
# CI/CD workflow for testomniac_runner
|
|
3
|
+
|
|
4
|
+
name: CI/CD
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
push:
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
- develop
|
|
11
|
+
pull_request:
|
|
12
|
+
branches:
|
|
13
|
+
- main
|
|
14
|
+
- develop
|
|
15
|
+
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
id-token: write
|
|
19
|
+
deployments: write
|
|
20
|
+
|
|
21
|
+
jobs:
|
|
22
|
+
cicd:
|
|
23
|
+
uses: johnqh/workflows/.github/workflows/unified-cicd.yml@main
|
|
24
|
+
with:
|
|
25
|
+
docker-image-name: "testomniac_runner"
|
|
26
|
+
skip-npm-publish: false
|
|
27
|
+
secrets:
|
|
28
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
29
|
+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
30
|
+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
package/.prettierignore
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Build outputs
|
|
5
|
+
dist/
|
|
6
|
+
build/
|
|
7
|
+
|
|
8
|
+
# Package files
|
|
9
|
+
*.tgz
|
|
10
|
+
*.tar.gz
|
|
11
|
+
|
|
12
|
+
# Logs
|
|
13
|
+
*.log
|
|
14
|
+
npm-debug.log*
|
|
15
|
+
yarn-debug.log*
|
|
16
|
+
yarn-error.log*
|
|
17
|
+
|
|
18
|
+
# Runtime data
|
|
19
|
+
pids
|
|
20
|
+
*.pid
|
|
21
|
+
*.seed
|
|
22
|
+
*.pid.lock
|
|
23
|
+
|
|
24
|
+
# Coverage directory used by tools like istanbul
|
|
25
|
+
coverage/
|
|
26
|
+
|
|
27
|
+
# TypeScript cache
|
|
28
|
+
*.tsbuildinfo
|
|
29
|
+
|
|
30
|
+
# Optional npm cache directory
|
|
31
|
+
.npm
|
|
32
|
+
|
|
33
|
+
# ESLint cache
|
|
34
|
+
.eslintcache
|
|
35
|
+
|
|
36
|
+
# Prettier cache
|
|
37
|
+
.prettierignore
|
|
38
|
+
|
|
39
|
+
# OS generated files
|
|
40
|
+
.DS_Store
|
|
41
|
+
.DS_Store?
|
|
42
|
+
._*
|
|
43
|
+
.Spotlight-V100
|
|
44
|
+
.Trashes
|
|
45
|
+
ehthumbs.db
|
|
46
|
+
Thumbs.db
|
|
47
|
+
|
|
48
|
+
# IDE files
|
|
49
|
+
.vscode/
|
|
50
|
+
.idea/
|
|
51
|
+
|
|
52
|
+
# Git
|
|
53
|
+
.git/
|
|
54
|
+
.gitignore
|
|
55
|
+
|
|
56
|
+
# Package lock files (auto-generated)
|
|
57
|
+
package-lock.json
|
|
58
|
+
yarn.lock
|
|
59
|
+
bun.lock
|
|
60
|
+
|
|
61
|
+
# Generated types
|
|
62
|
+
types/
|
package/.prettierrc
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"cSpell.enabled": false,
|
|
3
|
+
"editor.formatOnSave": true,
|
|
4
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
5
|
+
"editor.codeActionsOnSave": {
|
|
6
|
+
"source.fixAll.eslint": "explicit"
|
|
7
|
+
},
|
|
8
|
+
"[typescript]": {
|
|
9
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
10
|
+
},
|
|
11
|
+
"[typescriptreact]": {
|
|
12
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
13
|
+
},
|
|
14
|
+
"[javascript]": {
|
|
15
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
16
|
+
},
|
|
17
|
+
"[javascriptreact]": {
|
|
18
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
19
|
+
},
|
|
20
|
+
"[json]": {
|
|
21
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
22
|
+
},
|
|
23
|
+
"[css]": {
|
|
24
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
25
|
+
},
|
|
26
|
+
"[markdown]": {
|
|
27
|
+
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Testomniac Runner
|
|
2
|
+
|
|
3
|
+
Thin wrapper service that launches Puppeteer, polls for pending runs, and delegates all execution logic to `@sudobility/testomniac_runner_service` via `runTestRun()`. Provides server-side concerns: browser management, test execution worker pool, email reports, auth flows, and plugin implementations.
|
|
4
|
+
|
|
5
|
+
**Package**: `testomniac_runner` (private, BUSL-1.1)
|
|
6
|
+
|
|
7
|
+
## Tech Stack
|
|
8
|
+
|
|
9
|
+
- **Language**: TypeScript (strict mode)
|
|
10
|
+
- **Runtime**: Bun
|
|
11
|
+
- **Package Manager**: Bun (do not use npm/yarn/pnpm for installing dependencies)
|
|
12
|
+
- **Browser**: Puppeteer-core with Chrome for Testing
|
|
13
|
+
- **AI**: OpenAI SDK (GPT-4o) — passed via config to runner_service
|
|
14
|
+
- **HTTP**: Hono (health endpoint)
|
|
15
|
+
- **Logging**: Pino
|
|
16
|
+
- **Test**: Vitest
|
|
17
|
+
- **Email**: Postmark
|
|
18
|
+
- **Auth**: Signic SDK (disposable email for registration testing)
|
|
19
|
+
|
|
20
|
+
## Project Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
src/
|
|
24
|
+
├── index.ts # Worker entrypoint — polls API for pending runs
|
|
25
|
+
├── orchestrator.ts # Creates PuppeteerAdapter, calls runTestRun()
|
|
26
|
+
├── runner-manager.ts # Manages concurrent runs, claims pending runs
|
|
27
|
+
├── config/
|
|
28
|
+
│ └── index.ts # Environment config loader (loadConfig)
|
|
29
|
+
├── browser/
|
|
30
|
+
│ └── chromium.ts # Browser launch/close manager (ChromiumManager)
|
|
31
|
+
├── adapters/
|
|
32
|
+
│ └── PuppeteerAdapter.ts # BrowserAdapter implementation wrapping Puppeteer page
|
|
33
|
+
├── auth/
|
|
34
|
+
│ ├── form-identifier.ts # Classify forms: login vs signup vs other
|
|
35
|
+
│ ├── credential-manager.ts # Credential storage for test accounts
|
|
36
|
+
│ ├── login-executor.ts # Form-based automated login
|
|
37
|
+
│ ├── signic-registrar.ts # Auto-registration via Signic disposable email
|
|
38
|
+
│ └── password-detector.ts # Password requirement detection from forms
|
|
39
|
+
├── runner/
|
|
40
|
+
│ ├── executor.ts # Maps JSON test actions to Puppeteer commands
|
|
41
|
+
│ ├── worker-pool.ts # Concurrent test execution (default 3 workers)
|
|
42
|
+
│ └── reporter.ts # Pass/fail summary computation
|
|
43
|
+
├── email/
|
|
44
|
+
│ ├── deep-link.ts # JWT token generation for report deep links
|
|
45
|
+
│ ├── templates.ts # HTML/text email templates
|
|
46
|
+
│ └── sender.ts # Postmark email sending
|
|
47
|
+
├── scanner/
|
|
48
|
+
│ └── email-checker.ts # Signic inbox polling for verification emails
|
|
49
|
+
└── plugins/ # Plugin implementations (concrete checks)
|
|
50
|
+
├── types.ts # Plugin interface (re-exported from runner_service)
|
|
51
|
+
├── registry.ts # Local plugin registration
|
|
52
|
+
├── seo/ # SEO checks: title, meta, H1, images, structured data, Open Graph
|
|
53
|
+
├── security/ # Security checks: API keys, headers, CSRF, mixed content
|
|
54
|
+
├── content/ # Content checks: placeholders, readability, copyright, AI spelling
|
|
55
|
+
└── ui-consistency/ # Cross-page style comparison: fonts, colors, spacing
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Deleted (moved to runner_service)
|
|
59
|
+
|
|
60
|
+
The following directories/files were removed during refactoring. All this logic now lives in `@sudobility/testomniac_runner_service`:
|
|
61
|
+
|
|
62
|
+
- `ai/` (analyzer, persona/use-case/input generators, token tracker)
|
|
63
|
+
- `generation/` (all test element templates and generator)
|
|
64
|
+
- `api/client.ts` (now `getApiClient` from runner_service)
|
|
65
|
+
- `domain/` (types, url-ownership)
|
|
66
|
+
- `config/constants.ts` (now in runner_service)
|
|
67
|
+
- `browser/page-utils.ts` (normalizeHtml, computeHashes)
|
|
68
|
+
- `scanner/` (most modules — only `email-checker.ts` remains locally)
|
|
69
|
+
|
|
70
|
+
## Commands
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
bun run dev # Start runner worker in watch mode (polls for pending runs)
|
|
74
|
+
bun run build # Bundle with Bun
|
|
75
|
+
bun run start # Run production build
|
|
76
|
+
bun run test # Run Vitest tests
|
|
77
|
+
bun run test:unit # Run unit tests only
|
|
78
|
+
bun run test:watch # Vitest watch mode
|
|
79
|
+
bun run typecheck # TypeScript check
|
|
80
|
+
bun run lint # ESLint
|
|
81
|
+
bun run lint:fix # ESLint auto-fix
|
|
82
|
+
bun run format # Prettier write
|
|
83
|
+
bun run format:check # Prettier check
|
|
84
|
+
bun run verify # typecheck + lint + test + build
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Environment Variables
|
|
88
|
+
|
|
89
|
+
| Variable | Description | Default |
|
|
90
|
+
|----------|-------------|---------|
|
|
91
|
+
| `PORT` | Health endpoint port | `8030` |
|
|
92
|
+
| `TESTOMNIAC_API_URL` | API server URL | `http://localhost:8027` |
|
|
93
|
+
| `SCANNER_API_KEY` | Shared secret for API auth | required |
|
|
94
|
+
| `OPENAI_API_KEY` | OpenAI API key for AI analysis | required for AI phase |
|
|
95
|
+
| `CHROMIUM_PATH` | Path to Chrome/Chromium binary | `/usr/bin/chromium` |
|
|
96
|
+
| `USER_DATA_DIR` | Browser profile directory | `./browser-profile` |
|
|
97
|
+
| `ARTIFACT_DIR` | Screenshots/logs storage | `./artifacts` |
|
|
98
|
+
| `SCAN_POLL_INTERVAL_MS` | Poll interval for pending runs | `10000` |
|
|
99
|
+
| `MAX_CONCURRENT_RUNNERS` | Max parallel runs | `5` |
|
|
100
|
+
| `LOG_LEVEL` | Pino log level | `info` |
|
|
101
|
+
| `POSTMARK_SERVER_TOKEN` | Postmark email API token | optional |
|
|
102
|
+
| `POSTMARK_FROM_EMAIL` | Sender email address | optional |
|
|
103
|
+
| `DEEP_LINK_SECRET` | JWT secret for report deep links | optional |
|
|
104
|
+
| `APP_BASE_URL` | Frontend URL for deep links | `http://localhost:3000` |
|
|
105
|
+
| `SIGNIC_INDEXER_URL` | Signic email indexer URL | optional |
|
|
106
|
+
| `SIGNIC_WILDDUCK_URL` | Signic WildDuck API URL | optional |
|
|
107
|
+
|
|
108
|
+
## Architecture
|
|
109
|
+
|
|
110
|
+
The runner is a **stateless HTTP-polling worker**. It never accesses PostgreSQL directly — all communication goes through `testomniac_api` via HTTP with `X-Scanner-Key` authentication.
|
|
111
|
+
|
|
112
|
+
### Polling Loop (`src/index.ts`)
|
|
113
|
+
```
|
|
114
|
+
Every SCAN_POLL_INTERVAL_MS (10s):
|
|
115
|
+
GET /api/v1/scanner/runs/pending (via getApiClient from runner_service)
|
|
116
|
+
If run found → runFullScan(runner, run)
|
|
117
|
+
On error → PATCH /runs/:id/complete with failure
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
`RunnerManager` tracks active runs and spawns up to `MAX_CONCURRENT_RUNNERS` (default 5). Within a run, test jobs execute with 3 worker threads by default.
|
|
121
|
+
|
|
122
|
+
### Orchestrator (`src/orchestrator.ts`)
|
|
123
|
+
|
|
124
|
+
The orchestrator is a thin wrapper around `runTestRun()` from runner_service:
|
|
125
|
+
|
|
126
|
+
1. Loads config, creates `ApiClient` via `getApiClient()`
|
|
127
|
+
2. Launches Chromium via `ChromiumManager`
|
|
128
|
+
3. Creates `PuppeteerAdapter` wrapping a Puppeteer page
|
|
129
|
+
4. Builds default expertises and event handlers
|
|
130
|
+
5. Calls `runTestRun()` from `@sudobility/testomniac_runner_service`
|
|
131
|
+
6. Sends email report after completion (if user email provided)
|
|
132
|
+
|
|
133
|
+
All execution logic (element extraction, page analysis, test generation, expertise evaluation, finding creation) lives in runner_service.
|
|
134
|
+
|
|
135
|
+
### Browser Management
|
|
136
|
+
- Puppeteer-core (no bundled browser) + Chrome for Testing
|
|
137
|
+
- Persistent browser profile in `USER_DATA_DIR`
|
|
138
|
+
- Headless mode with `--no-sandbox`
|
|
139
|
+
- `PuppeteerAdapter` implements `BrowserAdapter` from `@sudobility/testomniac_runner_service`
|
|
140
|
+
- Custom `tmnc-replay:` selector scheme for robust element targeting
|
|
141
|
+
|
|
142
|
+
## Related Projects
|
|
143
|
+
|
|
144
|
+
- **testomniac_runner_service** (`@sudobility/testomniac_runner_service`) — Shared library containing ALL execution logic. This runner calls `runTestRun()` from it.
|
|
145
|
+
- **testomniac_api** (`localhost:8027`) — REST API this runner polls and reports to. All state flows through the API.
|
|
146
|
+
- **testomniac_extension** — Chrome extension that also calls `runTestRun()` from runner_service, using `ChromeAdapter` instead of `PuppeteerAdapter`.
|
|
147
|
+
- **testomniac_types** (`@sudobility/testomniac_types`) — Shared type definitions.
|
|
148
|
+
- **testomniac_app** — Web frontend that displays scan results.
|
|
149
|
+
- **testomniac_runner_mcp** — MCP server for AI-driven browser automation (also wraps runner_service).
|
|
150
|
+
|
|
151
|
+
## Coding Patterns
|
|
152
|
+
|
|
153
|
+
- **Thin wrapper around `runTestRun()`**: The orchestrator builds adapter + config + handlers and delegates everything to runner_service.
|
|
154
|
+
- **All type imports from runner_service or testomniac_types**: No local `domain/types.ts` or `config/constants.ts`.
|
|
155
|
+
- **`getApiClient` from runner_service**: No local API client.
|
|
156
|
+
- **Pino logger per module**: `const logger = pino({ name: "module-name" })`
|
|
157
|
+
- **Plugin implementations are local**: Plugin interface/registry defined in runner_service, but concrete plugin code (SEO, security, content, UI consistency) lives here.
|
|
158
|
+
- **Colocated tests**: `*.test.ts` files alongside source files
|
|
159
|
+
- **JSON-based test actions**: Test cases store action sequences as JSONB, executor maps to Puppeteer calls
|
|
160
|
+
|
|
161
|
+
## Gotchas
|
|
162
|
+
|
|
163
|
+
- **`browser-profile/` and `artifacts/` are gitignored** — they contain runtime data
|
|
164
|
+
- **Chrome lock files (`SingletonLock`)** can persist after crashes — delete to fix "browser already running"
|
|
165
|
+
- **OpenAI calls fail silently if `OPENAI_API_KEY` is empty** — AI phase is skipped, not errored
|
|
166
|
+
- **First run is slow** — creates fresh Chrome profile on first launch
|
|
167
|
+
- **`puppeteer-core` needs explicit `CHROMIUM_PATH`** — it does not bundle a browser
|
|
168
|
+
- **Docker needs Chromium + all dependencies** — Dockerfile installs libgtk-3, libxss1, etc. for headless Chrome
|
|
169
|
+
- **Artifacts directory must be writable** — runner saves screenshots as JPEG (quality 72) to `ARTIFACT_DIR`
|
|
170
|
+
- **Most scanner/ directory was deleted**: Only `email-checker.ts` remains locally. All other scanner modules are now in runner_service.
|
package/Dockerfile
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
FROM --platform=${BUILDPLATFORM} oven/bun:latest
|
|
2
|
+
ARG TARGETPLATFORM
|
|
3
|
+
ARG TARGETARCH
|
|
4
|
+
ARG TARGETVARIANT
|
|
5
|
+
ARG NPM_TOKEN
|
|
6
|
+
|
|
7
|
+
RUN printf "I'm building for TARGETPLATFORM=${TARGETPLATFORM}" \
|
|
8
|
+
&& printf ", TARGETARCH=${TARGETARCH}" \
|
|
9
|
+
&& printf ", TARGETVARIANT=${TARGETVARIANT} \n" \
|
|
10
|
+
&& printf "With uname -s : " && uname -s \
|
|
11
|
+
&& printf "and uname -m : " && uname -m
|
|
12
|
+
|
|
13
|
+
# Install system dependencies including Chromium and its required libraries
|
|
14
|
+
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
15
|
+
dumb-init \
|
|
16
|
+
curl \
|
|
17
|
+
chromium \
|
|
18
|
+
fonts-liberation \
|
|
19
|
+
libasound2 \
|
|
20
|
+
libatk-bridge2.0-0 \
|
|
21
|
+
libatk1.0-0 \
|
|
22
|
+
libatspi2.0-0 \
|
|
23
|
+
libcairo2 \
|
|
24
|
+
libcups2 \
|
|
25
|
+
libdbus-1-3 \
|
|
26
|
+
libdrm2 \
|
|
27
|
+
libgbm1 \
|
|
28
|
+
libglib2.0-0 \
|
|
29
|
+
libgtk-3-0 \
|
|
30
|
+
libnspr4 \
|
|
31
|
+
libnss3 \
|
|
32
|
+
libpango-1.0-0 \
|
|
33
|
+
libx11-6 \
|
|
34
|
+
libxcb1 \
|
|
35
|
+
libxcomposite1 \
|
|
36
|
+
libxdamage1 \
|
|
37
|
+
libxext6 \
|
|
38
|
+
libxfixes3 \
|
|
39
|
+
libxkbcommon0 \
|
|
40
|
+
libxrandr2 \
|
|
41
|
+
xdg-utils \
|
|
42
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
43
|
+
|
|
44
|
+
# Set Chromium path for puppeteer-core
|
|
45
|
+
ENV CHROMIUM_PATH=/usr/bin/chromium
|
|
46
|
+
|
|
47
|
+
WORKDIR /app
|
|
48
|
+
|
|
49
|
+
RUN groupadd -g 1001 appuser && \
|
|
50
|
+
useradd -r -u 1001 -g appuser appuser
|
|
51
|
+
|
|
52
|
+
COPY package.json bun.lock* bunfig.toml* ./
|
|
53
|
+
|
|
54
|
+
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc && \
|
|
55
|
+
echo "@sudobility:registry=https://registry.npmjs.org/" >> ~/.npmrc
|
|
56
|
+
|
|
57
|
+
RUN bun install --production && \
|
|
58
|
+
rm -f ~/.npmrc
|
|
59
|
+
|
|
60
|
+
COPY . .
|
|
61
|
+
|
|
62
|
+
RUN bun run build
|
|
63
|
+
|
|
64
|
+
RUN mkdir -p /app/logs /app/artifacts /app/browser-profile && \
|
|
65
|
+
chown -R appuser:appuser /app
|
|
66
|
+
|
|
67
|
+
USER appuser
|
|
68
|
+
|
|
69
|
+
EXPOSE 8030
|
|
70
|
+
|
|
71
|
+
HEALTHCHECK --interval=30s --timeout=15s --start-period=30s --retries=3 \
|
|
72
|
+
CMD curl -f http://localhost:${PORT:-8030}/health || exit 1
|
|
73
|
+
|
|
74
|
+
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
|
|
75
|
+
|
|
76
|
+
CMD ["bun", "run", "start"]
|
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# testomniac_runner
|
|
2
|
+
|
|
3
|
+
Scanner worker service for Testomniac.
|
|
4
|
+
|
|
5
|
+
This project is responsible for:
|
|
6
|
+
- polling for pending scan runs
|
|
7
|
+
- driving browser automation and discovery
|
|
8
|
+
- reporting progress through the shared PostgreSQL event model
|
|
9
|
+
- exposing a lightweight `/health` endpoint for container orchestration
|
|
10
|
+
|
|
11
|
+
## Development
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
bun install
|
|
15
|
+
bun run dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Default health endpoint:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
curl http://localhost:8030/health
|
|
22
|
+
```
|