Skip to content

Commit 99c8305

Browse files
authored
🚀 release: v1.0.0-beta.5 - Merge pull request #7 from wgtechlabs/dev
2 parents 85b8681 + 6692519 commit 99c8305

File tree

8 files changed

+313
-68
lines changed

8 files changed

+313
-68
lines changed

.env.railway

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
REDIS_URL="${{Redis (Webhook).REDIS_URL}}" # Auto-configured Redis for webhook event storage
2+
PORT="3000" # Server port for webhook endpoints
3+
NODE_ENV="production" # Environment mode (keep as production for Railway)
4+
TARGET_PLATFORM="" # Platform integration: "discord" or "telegram" - REQUIRED
5+
UNTHREAD_WEBHOOK_SECRET="" # Webhook secret from Unthread dashboard - REQUIRED

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ jobs:
5252
${{ env.REGISTRY_GHCR }}:dev-${{ steps.meta.outputs.short_sha }}
5353
labels: |
5454
org.opencontainers.image.title=Unthread Webhook Server
55-
org.opencontainers.image.description=Development build of Unthread Webhook Server
55+
org.opencontainers.image.description=A reliable, production-ready Node.js server for processing Unthread.io webhooks with signature verification and smart platform handling.
5656
org.opencontainers.image.version=dev-${{ steps.meta.outputs.short_sha }}
5757
org.opencontainers.image.created=${{ steps.meta.outputs.build_date }}
5858
org.opencontainers.image.revision=${{ github.sha }}

.github/workflows/release.yml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ jobs:
7676
7777
# Combine all tags
7878
ALL_TAGS="$DOCKERHUB_TAGS,$GHCR_TAGS"
79-
80-
echo "tags=$ALL_TAGS" >> $GITHUB_OUTPUT
79+
echo "tags=$ALL_TAGS" >> $GITHUB_OUTPUT
8180
8281
- name: Build and push production images
8382
uses: docker/build-push-action@v5
@@ -88,14 +87,14 @@ jobs:
8887
tags: ${{ steps.tags.outputs.tags }}
8988
labels: |
9089
org.opencontainers.image.title=Unthread Webhook Server
91-
org.opencontainers.image.description=A Node.js server application that receives webhook events from Unthread.io
90+
org.opencontainers.image.description=A reliable, production-ready Node.js server for processing Unthread.io webhooks with signature verification and smart platform handling.
9291
org.opencontainers.image.version=${{ steps.version.outputs.version }}
9392
org.opencontainers.image.created=${{ steps.version.outputs.build_date }}
9493
org.opencontainers.image.revision=${{ github.sha }}
9594
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
9695
org.opencontainers.image.url=${{ github.server_url }}/${{ github.repository }}
9796
org.opencontainers.image.licenses=GPL-3.0
98-
cache-from: type=gha
97+
cache-from: type=gha
9998
cache-to: type=gha,mode=max
10099

101100
- name: Run Trivy vulnerability scanner

CONTRIBUTING.md

Lines changed: 148 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Any contributions are welcome, encouraged, and valued. See the following informa
44

55
## 📋 Code of Conduct
66

7-
This project and everyone participating in it is governed by the project's Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to <opensource@wgtechlabs.com>.
7+
This project and everyone participating in it is governed by the project's [Code of Conduct](./CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to <opensource@wgtechlabs.com>.
88

99
## 💖 How to Contribute
1010

@@ -14,7 +14,7 @@ There are many ways to contribute to this open source project. Any contributions
1414

1515
If you can write code then create a pull request to this repo and I will review your code. Please consider submitting your pull request to the `dev` branch. I will auto reject if you submit your pull request to the `main` branch.
1616

17-
#### 🔧 Setup
17+
#### 🔧 Development Setup
1818

1919
To get started with development:
2020

@@ -44,6 +44,10 @@ To get started with development:
4444
brew services start redis # macOS
4545
sudo systemctl start redis-server # Linux
4646
docker run -d -p 6379:6379 redis:alpine # Docker
47+
48+
# OR for full Docker setup with proper naming:
49+
docker network create unthread-integration-network
50+
docker-compose up -d redis-webhook
4751
```
4852

4953
5. **Start the project in development mode**
@@ -97,11 +101,13 @@ src/
97101
#### 🎯 Development Guidelines
98102

99103
- **TypeScript First**: All code must be written in TypeScript with strict type checking
104+
- **Structured Logging**: Use `@wgtechlabs/log-engine` for all logging with built-in PII protection and security features
100105
- **Error Handling**: Implement comprehensive error handling with detailed logging
101106
- **Package Manager**: Use Yarn exclusively (enforced via preinstall script)
102107
- **Code Style**: Follow existing patterns and maintain consistency
103108
- **Environment**: Use Node.js 20+ for development
104109
- **Redis Integration**: Ensure Redis connectivity for all webhook-related features
110+
- **Webhook Integration**: Ensure compatibility with [`wgtechlabs/unthread-telegram-bot`](https://github.com/wgtechlabs/unthread-telegram-bot)
105111

106112
#### 🧪 Testing Guidelines
107113

@@ -153,11 +159,151 @@ For other bugs, please create an issue with:
153159
### 💡 Feature Requests
154160

155161
We welcome suggestions for new features! Please create an issue with:
162+
156163
- Clear description of the feature
157164
- Use case and benefits
158165
- Any implementation considerations
159166
- Examples or mockups if applicable
160167

168+
## 📊 Advanced Logging Security with Log Engine
169+
170+
This project uses [`@wgtechlabs/log-engine`](https://github.com/wgtechlabs/log-engine) for enterprise-grade logging with built-in security features and comprehensive PII protection.
171+
172+
### 🔒 **Automatic Security Features**
173+
174+
**Zero Configuration PII Protection:**
175+
176+
- **Automatic Redaction**: Passwords, tokens, emails, API keys, and 50+ sensitive patterns are automatically protected
177+
- **Deep Object Scanning**: Recursively scans nested objects and arrays for sensitive data
178+
- **Content Truncation**: Large payloads are automatically truncated to prevent log bloat
179+
- **Environment-Based Control**: Security automatically adapts based on NODE_ENV settings
180+
181+
**Built-in Patterns Protected:**
182+
183+
- **Authentication**: `password`, `token`, `apiKey`, `secret`, `jwt`, `auth`, `sessionId`
184+
- **Personal Info**: `email`, `phone`, `ssn`, `firstName`, `lastName`, `address`
185+
- **Financial**: `creditCard`, `cvv`, `bankAccount`, `routingNumber`
186+
- **System**: `clientSecret`, `privateKey`, `webhookSecret`, `unthreadSecret`
187+
188+
### 🛡️ **Advanced Security Configuration**
189+
190+
**Custom Enterprise Protection:**
191+
192+
```javascript
193+
import { LogEngine } from '@wgtechlabs/log-engine';
194+
195+
// Add custom patterns for enterprise-specific data
196+
LogEngine.addCustomRedactionPatterns([
197+
/internal.*/i, // Matches any field starting with "internal"
198+
/company.*/i, // Matches any field starting with "company"
199+
/webhook.*/i, // Matches webhook-specific fields
200+
/unthread.*/i // Matches unthread-specific fields
201+
]);
202+
203+
// Add dynamic sensitive field names
204+
LogEngine.addSensitiveFields([
205+
'webhookSecret',
206+
'unthreadWebhookSecret',
207+
'unthreadApiKey',
208+
'redisPassword'
209+
]);
210+
```
211+
212+
**Secure Logging Examples:**
213+
214+
```javascript
215+
// ✅ Automatic protection - no configuration needed
216+
LogEngine.info('Webhook authentication', {
217+
webhookId: '123456789', // ✅ Visible
218+
webhookSecret: 'secret123', // ❌ [REDACTED]
219+
targetPlatform: 'telegram', // ✅ Visible
220+
unthreadApiKey: 'key_123' // ❌ [REDACTED]
221+
});
222+
223+
// ✅ Event processing protection
224+
LogEngine.info('Event processing', {
225+
eventType: 'message_created', // ✅ Visible
226+
eventId: 'evt_001', // ✅ Visible
227+
signature: 'sha256=...', // ❌ [REDACTED]
228+
payload: { /* large data */ } // Automatically truncated
229+
});
230+
231+
// ✅ Redis queue security
232+
LogEngine.info('Queue publishing', {
233+
queueName: 'unthread-events', // ✅ Visible
234+
platform: 'unthread', // ✅ Visible
235+
redisUrl: 'redis://localhost', // ❌ [REDACTED]
236+
eventCount: 5 // ✅ Visible
237+
});
238+
```
239+
240+
### ⚙️ **Environment Configuration**
241+
242+
**Production Security (Recommended):**
243+
244+
```bash
245+
NODE_ENV=production # Full PII protection enabled
246+
LOG_REDACTION_TEXT="[SECURE]" # Custom redaction text
247+
LOG_MAX_CONTENT_LENGTH=150 # Truncate large content
248+
```
249+
250+
**Development Debugging:**
251+
252+
```bash
253+
NODE_ENV=development # Redaction disabled for debugging
254+
LOG_REDACTION_DISABLED=true # Explicit disable
255+
DEBUG_FULL_PAYLOADS=true # Show complete data
256+
```
257+
258+
**Custom Security Configuration:**
259+
260+
```bash
261+
# Custom sensitive fields (comma-separated)
262+
LOG_SENSITIVE_FIELDS="webhookSecret,unthreadSecret,redisPassword"
263+
264+
# Custom redaction patterns (JSON array)
265+
LOG_CUSTOM_PATTERNS='["/internal.*/i", "/company.*/i"]'
266+
267+
# Truncation settings
268+
LOG_MAX_CONTENT_LENGTH=200
269+
LOG_TRUNCATION_TEXT="... [CONFIDENTIAL_TRUNCATED]"
270+
```
271+
272+
### 🔧 **Development & Debugging**
273+
274+
**Raw Logging for Development:**
275+
276+
```javascript
277+
// ⚠️ Use with caution - bypasses all redaction
278+
LogEngine.debugRaw('Full webhook payload', {
279+
password: 'visible', // ⚠️ Visible (not redacted)
280+
apiKey: 'full-key-visible' // ⚠️ Visible (not redacted)
281+
});
282+
283+
// Temporary redaction bypass
284+
LogEngine.withoutRedaction().info('Debug mode', sensitiveData);
285+
286+
// Test field redaction
287+
const isRedacted = LogEngine.testFieldRedaction('webhookSecret'); // true
288+
const currentConfig = LogEngine.getRedactionConfig();
289+
```
290+
291+
### 📊 **Logging Benefits for This Webhook Server**
292+
293+
**Security Compliance:**
294+
295+
- **GDPR Ready**: Automatic PII protection for European compliance
296+
- **Data Minimization**: Only necessary data is logged
297+
- **Audit Trails**: Complete security event logging with timestamps
298+
- **Incident Response**: Quick identification of security events
299+
300+
**Operational Benefits:**
301+
302+
- **Color-Coded Output**: Easy visual identification of log levels (🔵 INFO, 🟡 WARN, 🔴 ERROR)
303+
- **Structured Logging**: Consistent format across all webhook components
304+
- **Performance Optimized**: Minimal overhead with intelligent processing
305+
- **TypeScript Support**: Full type safety and IDE integration
306+
161307
---
162308

163309
💻 with ❤️ by [Waren Gonzaga](https://warengonzaga.com), [WG Technology Labs](https://wgtechlabs.com), and [Him](https://www.youtube.com/watch?v=HHrxS4diLew&t=44s) 🙏

Dockerfile

Lines changed: 85 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,93 @@
1-
# Multi-stage build for Unthread Webhook Server
2-
3-
# Build stage
4-
FROM node:20-alpine AS builder
5-
6-
# Set working directory
7-
WORKDIR /app
8-
9-
# Copy package manager files
10-
COPY package.json yarn.lock .yarnrc ./
1+
# =============================================================================
2+
# UNTHREAD WEBHOOK SERVER - DOCKERFILE
3+
# =============================================================================
4+
# Multi-stage Docker build for the Unthread Webhook Server
5+
#
6+
# Build stages:
7+
# 1. base - Base Alpine image with Node.js and security updates
8+
# 2. deps - Install production dependencies only
9+
# 3. build - Install dev dependencies and build the application
10+
# 4. final - Create minimal runtime image with built app
11+
#
12+
# Usage:
13+
# docker build -t unthread-webhook-server .
14+
# docker run --env-file .env unthread-webhook-server
15+
#
16+
# =============================================================================
17+
18+
# syntax=docker/dockerfile:1
19+
20+
# Use Node.js 22.16 LTS Alpine with security patches
21+
ARG NODE_VERSION=22.16-alpine3.21
22+
23+
# =============================================================================
24+
# STAGE 1: Base Image
25+
# =============================================================================
26+
# Alpine Linux 3.21 base for minimal image size with latest security updates
27+
FROM node:${NODE_VERSION} AS base
28+
29+
# Install security updates for Alpine packages
30+
RUN apk update && apk upgrade && \
31+
apk add --no-cache dumb-init && \
32+
rm -rf /var/cache/apk/*
33+
34+
# Set working directory for all subsequent stages
35+
WORKDIR /usr/src/app
36+
37+
# =============================================================================
38+
# STAGE 2: Production Dependencies
39+
# =============================================================================
40+
# Install only production dependencies for runtime
41+
FROM base AS deps
42+
43+
# Use bind mounts and cache for faster builds
44+
# Downloads dependencies without copying package files into the layer
45+
RUN --mount=type=bind,source=package.json,target=package.json \
46+
--mount=type=bind,source=yarn.lock,target=yarn.lock \
47+
--mount=type=cache,target=/root/.yarn \
48+
yarn install --production --frozen-lockfile
49+
50+
# =============================================================================
51+
# STAGE 3: Build Application
52+
# =============================================================================
53+
# Install dev dependencies and build the TypeScript application
54+
FROM deps AS build
1155

1256
# Install all dependencies (including devDependencies for building)
13-
RUN yarn install --frozen-lockfile --ignore-scripts
14-
15-
# Copy source code and build configuration
16-
COPY src/ ./src/
17-
COPY tsconfig.json ./
18-
19-
# Build the TypeScript application
20-
RUN yarn build
21-
22-
# Production stage
23-
FROM node:20-alpine AS production
24-
25-
# Set working directory
26-
WORKDIR /app
27-
28-
# Copy package manager files
29-
COPY package.json yarn.lock .yarnrc ./
57+
RUN --mount=type=bind,source=package.json,target=package.json \
58+
--mount=type=bind,source=yarn.lock,target=yarn.lock \
59+
--mount=type=cache,target=/root/.yarn \
60+
yarn install --frozen-lockfile
61+
62+
# Copy source code and build the application
63+
COPY . .
64+
RUN yarn run build
65+
66+
# =============================================================================
67+
# STAGE 4: Final Runtime Image
68+
# =============================================================================
69+
# Minimal production image with only necessary files
70+
FROM base AS final
71+
72+
# Set production environment with security options
73+
ENV NODE_ENV=production \
74+
NODE_OPTIONS="--enable-source-maps --max-old-space-size=512"
75+
76+
# Create a dedicated user for the application
77+
RUN addgroup -g 1001 -S nodejs && \
78+
adduser -S nodejs -u 1001 -G nodejs
3079

31-
# Set environment to production
32-
ENV NODE_ENV=production
33-
# Install only production dependencies
34-
RUN yarn install --frozen-lockfile --production --ignore-scripts && \
35-
yarn cache clean
80+
# Copy package.json for package manager commands
81+
COPY --chown=nodejs:nodejs package.json .
3682

37-
# Copy built application from builder stage
38-
COPY --from=builder /app/dist ./dist
83+
# Copy production dependencies and built application
84+
COPY --from=deps --chown=nodejs:nodejs /usr/src/app/node_modules ./node_modules
85+
COPY --from=build --chown=nodejs:nodejs /usr/src/app/dist ./dist
3986

4087
# Copy environment example (for reference)
41-
COPY .env.example ./
42-
43-
# Create non-root user for security
44-
RUN addgroup -g 1001 -S nodejs && \
45-
adduser -S nodejs -u 1001
88+
COPY --chown=nodejs:nodejs .env.example ./
4689

47-
# Change ownership of the app directory to nodejs user
48-
RUN chown -R nodejs:nodejs /app
90+
# Switch to non-root user
4991
USER nodejs
5092

5193
# Expose the port the app runs on
@@ -55,5 +97,6 @@ EXPOSE 3000
5597
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
5698
CMD node -e "require('http').get('http://localhost:3000/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) }).on('error', () => process.exit(1))"
5799

58-
# Start the application
100+
# Use dumb-init for proper signal handling and start the application
101+
ENTRYPOINT ["dumb-init", "--"]
59102
CMD ["node", "dist/app.js"]

0 commit comments

Comments
 (0)