@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.
Files changed (60) hide show
  1. package/.dockerignore +75 -0
  2. package/.env.example +67 -0
  3. package/.github/workflows/ci-cd.yml +30 -0
  4. package/.prettierignore +62 -0
  5. package/.prettierrc +11 -0
  6. package/.vscode/settings.json +29 -0
  7. package/CLAUDE.md +170 -0
  8. package/Dockerfile +76 -0
  9. package/README.md +22 -0
  10. package/bun.lock +707 -0
  11. package/docs/superpowers/specs/2026-04-20-smarter-scanner-navigation-design.md +121 -0
  12. package/eslint.config.js +80 -0
  13. package/package.json +55 -0
  14. package/plans/DATA.md +703 -0
  15. package/plans/POLLING.md +569 -0
  16. package/plans/RUNNER.md +288 -0
  17. package/src/adapters/PuppeteerAdapter.ts +394 -0
  18. package/src/auth/credential-manager.ts +17 -0
  19. package/src/auth/form-identifier.test.ts +136 -0
  20. package/src/auth/form-identifier.ts +54 -0
  21. package/src/auth/login-executor.ts +112 -0
  22. package/src/auth/password-detector.test.ts +61 -0
  23. package/src/auth/password-detector.ts +119 -0
  24. package/src/auth/signic-registrar.ts +186 -0
  25. package/src/browser/chromium.ts +35 -0
  26. package/src/config/index.test.ts +23 -0
  27. package/src/config/index.ts +35 -0
  28. package/src/email/deep-link.test.ts +17 -0
  29. package/src/email/deep-link.ts +23 -0
  30. package/src/email/sender.ts +35 -0
  31. package/src/email/templates.ts +34 -0
  32. package/src/index.test.ts +17 -0
  33. package/src/index.ts +110 -0
  34. package/src/orchestrator.ts +220 -0
  35. package/src/plugins/content/ai-checks.ts +115 -0
  36. package/src/plugins/content/checks.test.ts +49 -0
  37. package/src/plugins/content/checks.ts +141 -0
  38. package/src/plugins/content/index.ts +73 -0
  39. package/src/plugins/registry.test.ts +49 -0
  40. package/src/plugins/registry.ts +21 -0
  41. package/src/plugins/security/header-checks.ts +56 -0
  42. package/src/plugins/security/html-checks.ts +93 -0
  43. package/src/plugins/security/index.ts +58 -0
  44. package/src/plugins/security/network-checks.test.ts +74 -0
  45. package/src/plugins/security/network-checks.ts +136 -0
  46. package/src/plugins/seo/checks.test.ts +70 -0
  47. package/src/plugins/seo/checks.ts +173 -0
  48. package/src/plugins/seo/index.ts +85 -0
  49. package/src/plugins/types.ts +43 -0
  50. package/src/plugins/ui-consistency/comparator.test.ts +108 -0
  51. package/src/plugins/ui-consistency/comparator.ts +58 -0
  52. package/src/plugins/ui-consistency/index.ts +36 -0
  53. package/src/plugins/ui-consistency/style-extractor.ts +79 -0
  54. package/src/runner/executor.test.ts +37 -0
  55. package/src/runner/executor.ts +167 -0
  56. package/src/runner/reporter.ts +19 -0
  57. package/src/runner/worker-pool.ts +106 -0
  58. package/src/runner-manager.ts +163 -0
  59. package/src/scanner/email-checker.ts +106 -0
  60. 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 }}
@@ -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,11 @@
1
+ {
2
+ "semi": true,
3
+ "trailingComma": "es5",
4
+ "singleQuote": false,
5
+ "printWidth": 80,
6
+ "tabWidth": 2,
7
+ "useTabs": false,
8
+ "bracketSpacing": true,
9
+ "arrowParens": "avoid",
10
+ "endOfLine": "lf"
11
+ }
@@ -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
+ ```