Node/Express service that:
- Receives Appspace outbound webhooks, enriches with Workspace ONE MDM
data (matched by serial), and posts Adaptive Card alerts to Webex.
- Runs a Webex bot in WebSocket mode with two commands:
* `offline [filter]` - lists currently offline / lost / failed
Appspace devices, enriched with per-device MDM facts + console links.
* `restart-offline [filter]` - sends WS1 SoftReset (reboot) to every
currently-offline device that has a WS1 record. Capped at 50 per
invocation with bounded concurrency to protect the WS1 API.
Notes on hardening already applied:
- In-flight promise coalescing in mdm.js and index.js so burst webhook
traffic can't stampede the WS1 token / device-cache refresh or the
Appspace token refresh.
- Structured logger that serializes Error instances (message, stack,
code, axios response.status/data) instead of stringifying to "{}".
- Webex 7439-char message-limit handling: `offline` builds its body
incrementally against a character budget and reports accurate
"N more not shown" truncation.
- Uses string phrases for `framework.hears(...)` so the framework's
`(^| )phrase($| )` wrapper handles group-space @mentions correctly,
and a shared `extractFilterArg()` helper so filter parsing works
identically in DMs and mentioned messages.
Config, Docker, smoke-test profile, and healthcheck included.
Secrets are managed via `.env` (gitignored); see `.env.example`.
Co-authored-by: Cursor <cursoragent@cursor.com>
25 lines
No EOL
905 B
Docker
25 lines
No EOL
905 B
Docker
FROM node:20-alpine
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy package files first for better layer caching
|
|
COPY --chown=node:node package*.json ./
|
|
RUN npm ci --only=production && npm cache clean --force
|
|
|
|
# Copy the rest of the application code
|
|
COPY --chown=node:node . .
|
|
|
|
# Production environment
|
|
ENV NODE_ENV=production
|
|
|
|
# Run as non-root user (node user is provided by the base image, uid 1000)
|
|
USER node
|
|
|
|
EXPOSE 3000
|
|
|
|
# Pure Node.js healthcheck - does not depend on wget, curl, or other binaries
|
|
# that may not be present in minimal Alpine images. Respects PORT env var.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
|
|
CMD node -e 'const h=require("http");const p=process.env.PORT||3000;const r=h.get("http://localhost:"+p+"/health",res=>process.exit(res.statusCode==200?0:1));r.on("error",()=>process.exit(1));r.setTimeout(2000,()=>{r.destroy();process.exit(1)})' || exit 1
|
|
|
|
CMD ["npm", "start"] |