Files
worldmonitor/Dockerfile.relay
Elie Habib c31662c3c9 fix(relay): COPY missing _seed-envelope-source + _seed-contract — chokepointFlows stale 32h (#3132)
* fix(relay): COPY _seed-envelope-source + _seed-contract into Dockerfile.relay

Root cause of chokepointFlows STALE_SEED (1911min stale, maxStaleMin=720):
since 2026-04-14 (PR #3097/#3101 landing), scripts/_seed-utils.mjs imports
_seed-envelope-source.mjs and _seed-contract.mjs. Dockerfile.relay COPY'd
_seed-utils.mjs but NOT its new transitive dependencies, so every execFile
invocation of seed-chokepoint-flows.mjs, seed-climate-news.mjs, and
seed-ember-electricity.mjs crashed at import with ERR_MODULE_NOT_FOUND.
The ais-relay loop kept firing every 6h but each child died instantly —
no visible error because execFile only surfaces child stderr to the
parent relay's log stream.

Local repro: node scripts/seed-chokepoint-flows.mjs runs fine in 3.6s
and writes 7 records. Same command inside the relay container would
throw at the import line because the file doesn't exist.

Fix:
1. Add COPY scripts/_seed-envelope-source.mjs and
   COPY scripts/_seed-contract.mjs to Dockerfile.relay.
2. Add a static guard test (tests/dockerfile-relay-imports.test.mjs)
   that BFS's the transitive-import graph from every COPY'd entrypoint
   and fails if any reached scripts/*.mjs|cjs isn't also COPY'd. This
   would have caught the original regression.

Matches feedback_dockerfile_relay_explicit_copy.md — we now have a test
enforcing it.

* fix(test): scanner also covers require() and createRequire(...)(...) — greptile P2

Review finding on PR #3132: collectRelativeImports only matched ESM
import/export syntax, so require('./x.cjs') in ais-relay.cjs and
createRequire(import.meta.url)('./x.cjs') in _seed-utils.mjs were
invisible to the guard. No active bug (_proxy-utils.cjs is already
COPY'd) but a future createRequire pointing at a new uncopied helper
would slip through.

Two regexes now cover both forms:
- cjsRe: direct require('./x') — with a non-identifier lookbehind so
  'thisrequire(' or 'foorequire(' can't match.
- createRequireRe: createRequire(...)('./x') chained-call — the outer
  call is applied to createRequire's return value, not to a 'require('
  token, so the first regex misses it on its own.

Added a unit test asserting both forms resolve on known sites
(_seed-utils.mjs and ais-relay.cjs) so the next edit to this file
can't silently drop coverage.
2026-04-16 17:28:16 +04:00

51 lines
2.3 KiB
Docker

# =============================================================================
# AIS Relay Sidecar
# =============================================================================
# Runs scripts/ais-relay.cjs as a standalone container.
# Dependencies: ws (WebSocket), telegram (OSINT polling), plus others in
# scripts/package.json (fast-xml-parser, @anthropic-ai/sdk, etc.)
# Set AISSTREAM_API_KEY in docker-compose.yml or Railway env.
# =============================================================================
FROM node:22-alpine
# curl required by OREF polling (Node.js JA3 fingerprint blocked by Akamai; curl passes)
RUN apk add --no-cache curl
WORKDIR /app
# Install scripts/ runtime dependencies (telegram, ws, fast-xml-parser, etc.)
COPY scripts/package.json scripts/package-lock.json ./scripts/
RUN npm ci --prefix scripts --omit=dev
# Relay script and shared helpers
COPY scripts/ais-relay.cjs ./scripts/ais-relay.cjs
COPY scripts/_proxy-utils.cjs ./scripts/_proxy-utils.cjs
COPY scripts/_seed-utils.mjs ./scripts/_seed-utils.mjs
# _seed-envelope-source.mjs and _seed-contract.mjs are transitively imported
# by _seed-utils.mjs (lines 9-10) and by seed-chokepoint-flows.mjs /
# seed-ember-electricity.mjs directly. Missing them here = silent
# ERR_MODULE_NOT_FOUND on every execFile invocation, which looks like a hung
# Railway cron (the initial-seed path throws, the 6h setInterval keeps firing
# but each child dies on import). tests/dockerfile-relay-imports.test.mjs
# guards this COPY list against future regressions.
COPY scripts/_seed-envelope-source.mjs ./scripts/_seed-envelope-source.mjs
COPY scripts/_seed-contract.mjs ./scripts/_seed-contract.mjs
COPY scripts/_country-resolver.mjs ./scripts/_country-resolver.mjs
COPY scripts/seed-climate-news.mjs ./scripts/seed-climate-news.mjs
COPY scripts/seed-chokepoint-flows.mjs ./scripts/seed-chokepoint-flows.mjs
COPY scripts/seed-ember-electricity.mjs ./scripts/seed-ember-electricity.mjs
# Shared helper required by the relay (rss-allowed-domains.cjs)
COPY shared/ ./shared/
# Data files required by the relay (telegram-channels.json, etc.)
COPY data/ ./data/
EXPOSE 3004
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://localhost:3004/health || exit 1
CMD ["node", "scripts/ais-relay.cjs"]