Compare commits
5 Commits
c2fd0e2f98
...
72345a5129
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72345a5129 | ||
|
|
7745d205cb | ||
|
|
877895f43e | ||
|
|
f29b39b40c | ||
|
|
f99772d8c0 |
@ -1,5 +1,5 @@
|
|||||||
PORT=3002
|
PORT=3002
|
||||||
BASE_URL=https://ghl.cast.ph
|
BASE_URL=https://hl.cast.ph
|
||||||
|
|
||||||
# GHL OAuth
|
# GHL OAuth
|
||||||
GHL_CLIENT_ID=
|
GHL_CLIENT_ID=
|
||||||
|
|||||||
106
.woodpecker.yml
106
.woodpecker.yml
@ -1,34 +1,64 @@
|
|||||||
steps:
|
steps:
|
||||||
- name: build
|
- name: lint
|
||||||
image: golang:1.22-alpine
|
image: golangci/golangci-lint:latest
|
||||||
commands:
|
commands:
|
||||||
- go build ./cmd/server/
|
- golangci-lint run ./...
|
||||||
|
|
||||||
- name: vet
|
|
||||||
image: golang:1.22-alpine
|
|
||||||
commands:
|
|
||||||
- go vet ./...
|
|
||||||
|
|
||||||
- name: test
|
- name: test
|
||||||
image: golang:1.22-alpine
|
image: golang:1.26-alpine
|
||||||
commands:
|
commands:
|
||||||
- go test ./...
|
- go test ./...
|
||||||
|
|
||||||
- name: docker-build
|
- name: semgrep
|
||||||
image: plugins/docker
|
image: semgrep/semgrep:latest
|
||||||
settings:
|
commands:
|
||||||
repo: registry.sds.dev/cast/cast-ghl-provider
|
- >
|
||||||
registry: registry.sds.dev
|
semgrep scan --config auto --error
|
||||||
tags:
|
--exclude-rule go.lang.security.audit.net.cookie-missing-secure.cookie-missing-secure
|
||||||
- latest
|
--exclude-rule go.lang.security.audit.net.unescaped-data-in-url.unescaped-data-in-url
|
||||||
- "${CI_COMMIT_TAG}"
|
--exclude-rule go.lang.security.audit.xss.template-html-does-not-escape.unsafe-template-type
|
||||||
username:
|
--exclude-rule html.security.audit.missing-integrity.missing-integrity
|
||||||
from_secret: docker_username
|
.
|
||||||
password:
|
|
||||||
from_secret: docker_password
|
|
||||||
when:
|
when:
|
||||||
event: tag
|
- event: [push, pull_request]
|
||||||
ref: refs/tags/v*
|
|
||||||
|
- name: gosec
|
||||||
|
image: golang:1.26-bookworm
|
||||||
|
commands:
|
||||||
|
- go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||||
|
- gosec -exclude=G120,G706,G101,G115,G203,G124 ./...
|
||||||
|
when:
|
||||||
|
- event: [push, pull_request]
|
||||||
|
|
||||||
|
- name: trivy-fs
|
||||||
|
image: aquasec/trivy:latest
|
||||||
|
commands:
|
||||||
|
- trivy fs --severity HIGH,CRITICAL --exit-code 1 .
|
||||||
|
when:
|
||||||
|
- event: [push, pull_request]
|
||||||
|
|
||||||
|
- name: trivy-secrets
|
||||||
|
image: aquasec/trivy:latest
|
||||||
|
commands:
|
||||||
|
- trivy fs --scanners secret --exit-code 1 .
|
||||||
|
when:
|
||||||
|
- event: [push, pull_request]
|
||||||
|
|
||||||
|
- name: build-and-push
|
||||||
|
image: woodpeckerci/plugin-docker-buildx
|
||||||
|
settings:
|
||||||
|
repo: git.sds.dev/cast/cast-ghl-provider
|
||||||
|
registry: git.sds.dev
|
||||||
|
tag:
|
||||||
|
- ${CI_COMMIT_SHA:0:8}
|
||||||
|
- latest
|
||||||
|
username:
|
||||||
|
from_secret: registry_user
|
||||||
|
password:
|
||||||
|
from_secret: registry_password
|
||||||
|
when:
|
||||||
|
- branch: main
|
||||||
|
event: push
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
image: appleboy/drone-ssh
|
image: appleboy/drone-ssh
|
||||||
@ -38,11 +68,29 @@ steps:
|
|||||||
username:
|
username:
|
||||||
from_secret: deploy_user
|
from_secret: deploy_user
|
||||||
key:
|
key:
|
||||||
from_secret: deploy_key
|
from_secret: deploy_ssh_key
|
||||||
script:
|
script:
|
||||||
- cd /opt/cast-ghl-provider
|
- bash /opt/cast-ghl-provider/deploy/deploy.sh
|
||||||
- docker compose pull
|
|
||||||
- docker compose up -d --remove-orphans
|
|
||||||
when:
|
when:
|
||||||
event: tag
|
- branch: main
|
||||||
ref: refs/tags/v*
|
event: push
|
||||||
|
|
||||||
|
- name: notify-telegram
|
||||||
|
image: appleboy/drone-telegram
|
||||||
|
settings:
|
||||||
|
token:
|
||||||
|
from_secret: telegram_bot_token
|
||||||
|
to:
|
||||||
|
from_secret: telegram_chat_id
|
||||||
|
message: >
|
||||||
|
{{#success build.status}}✅{{else}}❌{{/success}} **{{repo.name}}**
|
||||||
|
|
||||||
|
Branch: `{{commit.branch}}`
|
||||||
|
|
||||||
|
Status: **{{build.status}}**
|
||||||
|
|
||||||
|
Commit: `{{commit.message}}`
|
||||||
|
|
||||||
|
{{build.link}}
|
||||||
|
when:
|
||||||
|
- status: [success, failure]
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
## Stack
|
## Stack
|
||||||
|
|
||||||
- **Language:** Go 1.22+
|
- **Language:** Go 1.26+
|
||||||
- **HTTP:** `net/http` (stdlib) + `chi` router (lightweight)
|
- **HTTP:** `net/http` (stdlib) + `chi` router (lightweight)
|
||||||
- **Database:** MongoDB (OAuth token storage)
|
- **Database:** MongoDB (OAuth token storage)
|
||||||
- **Mongo driver:** `go.mongodb.org/mongo-driver/v2`
|
- **Mongo driver:** `go.mongodb.org/mongo-driver/v2`
|
||||||
@ -116,7 +116,7 @@ cast-ghl-provider/
|
|||||||
| Variable | Required | Default | Description |
|
| Variable | Required | Default | Description |
|
||||||
|----------|----------|---------|-------------|
|
|----------|----------|---------|-------------|
|
||||||
| `PORT` | No | `3002` | Server listen port |
|
| `PORT` | No | `3002` | Server listen port |
|
||||||
| `BASE_URL` | Yes | — | Public URL (e.g. `https://ghl.cast.ph`) |
|
| `BASE_URL` | Yes | — | Public URL (e.g. `https://hl.cast.ph`) |
|
||||||
| `GHL_CLIENT_ID` | Yes | — | GHL Marketplace app client ID |
|
| `GHL_CLIENT_ID` | Yes | — | GHL Marketplace app client ID |
|
||||||
| `GHL_CLIENT_SECRET` | Yes | — | GHL Marketplace app client secret |
|
| `GHL_CLIENT_SECRET` | Yes | — | GHL Marketplace app client secret |
|
||||||
| `GHL_WEBHOOK_PUBLIC_KEY` | Yes | — | PEM-encoded ECDSA public key for webhook sig |
|
| `GHL_WEBHOOK_PUBLIC_KEY` | Yes | — | PEM-encoded ECDSA public key for webhook sig |
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
FROM golang:1.22-alpine AS builder
|
FROM golang:1.26-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY go.mod go.sum ./
|
COPY go.mod go.sum ./
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|||||||
@ -243,7 +243,7 @@ Version: 2021-04-15
|
|||||||
|
|
||||||
1. Type: **SMS**
|
1. Type: **SMS**
|
||||||
2. Name: **Cast SMS**
|
2. Name: **Cast SMS**
|
||||||
3. Delivery URL: `https://ghl.cast.ph/api/ghl/v1/webhook/messages`
|
3. Delivery URL: `https://hl.cast.ph/api/ghl/v1/webhook/messages`
|
||||||
4. Do NOT check "Is this a Custom Conversation Provider"
|
4. Do NOT check "Is this a Custom Conversation Provider"
|
||||||
|
|
||||||
### Enabling the Provider (per sub-account)
|
### Enabling the Provider (per sub-account)
|
||||||
|
|||||||
@ -199,7 +199,7 @@ cast-ghl-provider/
|
|||||||
```env
|
```env
|
||||||
# Server
|
# Server
|
||||||
PORT=3002
|
PORT=3002
|
||||||
BASE_URL=https://ghl.cast.ph # Public URL for OAuth redirects + webhooks
|
BASE_URL=https://hl.cast.ph # Public URL for OAuth redirects + webhooks
|
||||||
|
|
||||||
# GHL OAuth
|
# GHL OAuth
|
||||||
GHL_CLIENT_ID=xxx
|
GHL_CLIENT_ID=xxx
|
||||||
@ -250,7 +250,7 @@ volumes:
|
|||||||
|
|
||||||
- **Host:** Vultr (existing Cast infrastructure)
|
- **Host:** Vultr (existing Cast infrastructure)
|
||||||
- **Reverse proxy:** Nginx or Caddy with HTTPS
|
- **Reverse proxy:** Nginx or Caddy with HTTPS
|
||||||
- **Domain:** `ghl.cast.ph` (or similar)
|
- **Domain:** `hl.cast.ph`
|
||||||
- **CI/CD:** Woodpecker CI at `git.sds.dev`
|
- **CI/CD:** Woodpecker CI at `git.sds.dev`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
22
deploy/deploy.sh
Normal file
22
deploy/deploy.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# deploy.sh — Called by Woodpecker CI on every push to main.
|
||||||
|
# Can also be run manually for emergency redeployments.
|
||||||
|
# Pulls the latest image from the registry and restarts the stack.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
||||||
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
echo "==> Pulling latest image from registry"
|
||||||
|
docker compose pull bridge
|
||||||
|
|
||||||
|
echo "==> Restarting services"
|
||||||
|
docker compose up -d --remove-orphans
|
||||||
|
|
||||||
|
echo "==> Status"
|
||||||
|
sleep 3
|
||||||
|
docker compose ps bridge
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "=== Deploy complete — https://hl.cast.ph/health ==="
|
||||||
@ -1,12 +1,21 @@
|
|||||||
services:
|
services:
|
||||||
bridge:
|
bridge:
|
||||||
build: .
|
image: git.sds.dev/cast/cast-ghl-provider:latest
|
||||||
ports:
|
build: . # used only for local dev (docker compose up --build); production uses the registry image
|
||||||
- "${PORT:-3002}:${PORT:-3002}"
|
# No port binding — nginx-proxy routes traffic via the shared proxy network
|
||||||
env_file: .env
|
env_file: .env
|
||||||
|
environment:
|
||||||
|
# nginx-proxy / acme-companion auto-routing
|
||||||
|
- VIRTUAL_HOST=${VIRTUAL_HOST:-hl.cast.ph}
|
||||||
|
- VIRTUAL_PORT=${PORT:-3002}
|
||||||
|
- LETSENCRYPT_HOST=${VIRTUAL_HOST:-hl.cast.ph}
|
||||||
|
- LETSENCRYPT_EMAIL=${LETSENCRYPT_EMAIL:-ops@cast.ph}
|
||||||
depends_on:
|
depends_on:
|
||||||
mongo:
|
mongo:
|
||||||
condition: service_started
|
condition: service_healthy
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
|
- proxy # shared nginx-proxy network — must match the nginx-proxy container's network
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
logging:
|
logging:
|
||||||
driver: json-file
|
driver: json-file
|
||||||
@ -16,9 +25,26 @@ services:
|
|||||||
|
|
||||||
mongo:
|
mongo:
|
||||||
image: mongo:7
|
image: mongo:7
|
||||||
|
# No ports exposed — only reachable by bridge on the internal network
|
||||||
volumes:
|
volumes:
|
||||||
- mongo-data:/data/db
|
- mongo-data:/data/db
|
||||||
|
networks:
|
||||||
|
- internal
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
|
||||||
|
networks:
|
||||||
|
internal:
|
||||||
|
# Private network for bridge ↔ mongo
|
||||||
|
proxy:
|
||||||
|
external: true
|
||||||
|
# Must match the name of the existing nginx-proxy Docker network on the server.
|
||||||
|
# Check with: docker network ls | grep proxy
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
mongo-data:
|
mongo-data:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user