Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e38a88f4c7 | ||
|
|
eecc3ad9e2 | ||
|
|
e07af65f67 | ||
|
|
101cbf86d9 | ||
|
|
a4357c95cd | ||
|
|
c2abaaa2c1 | ||
| 627d04f6d4 | |||
| 8eab022a91 | |||
| 8292dcb756 | |||
| 22e842bf87 | |||
| cd3b5d242d | |||
| ecb4417f2f | |||
| eb85e581f3 | |||
| 266b9b59c2 | |||
| e934074647 | |||
| 74f4364fd4 | |||
| ee03ef39ca |
148
Jenkinsfile
vendored
148
Jenkinsfile
vendored
@@ -1,26 +1,30 @@
|
||||
pipeline {
|
||||
// 1. Run on your specific agent
|
||||
// 1. Run all heavy lifting (builds) on the dedicated Agent
|
||||
agent { label 'jenkins-agent' }
|
||||
|
||||
environment {
|
||||
REGISTRY_URL = 'registry.digitalocean.com/kongseng'
|
||||
// --- REGISTRY & REPOSITORY FIXES ---
|
||||
REGISTRY_URL = 'registry.digitalocean.com/devsecops-lab'
|
||||
REPO_NAME = 'core' // Single repository for Free Tier
|
||||
|
||||
// 2. Dynamic Naming: Image tag includes Branch Name to prevent conflicts
|
||||
// Example: registry.../backend:Dev-42 or registry.../backend:main-42
|
||||
BACKEND_IMAGE = "${REGISTRY_URL}/devsecops-backend:${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
|
||||
FRONTEND_IMAGE = "${REGISTRY_URL}/devsecops-frontend:${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
|
||||
// --- TAGS ---
|
||||
BACKEND_TAG = "backend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
|
||||
FRONTEND_TAG = "frontend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
|
||||
|
||||
// --- DEPLOYMENT TARGET ---
|
||||
DEPLOY_HOST = 'gitea.kongseng.in'
|
||||
DEPLOY_USER = 'root'
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
}
|
||||
steps { checkout scm }
|
||||
}
|
||||
|
||||
stage('Install Dependencies') {
|
||||
steps {
|
||||
echo "Installing dependencies for ${env.BRANCH_NAME} branch..."
|
||||
// Assuming Node is installed on the agent
|
||||
dir('backend') { sh 'npm install' }
|
||||
dir('frontend') { sh 'npm install' }
|
||||
}
|
||||
@@ -29,71 +33,99 @@ pipeline {
|
||||
stage('Build Docker Images') {
|
||||
steps {
|
||||
script {
|
||||
echo "Building Images for branch: ${env.BRANCH_NAME}..."
|
||||
sh "docker build -t ${BACKEND_IMAGE} ./backend"
|
||||
sh "docker build -t ${FRONTEND_IMAGE} ./frontend"
|
||||
echo "Building Backend & Frontend Images..."
|
||||
sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG} ./backend"
|
||||
sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG} ./frontend"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push to Registry') {
|
||||
steps {
|
||||
script {
|
||||
echo "Pushing images to DigitalOcean..."
|
||||
sh "docker push ${BACKEND_IMAGE}"
|
||||
sh "docker push ${FRONTEND_IMAGE}"
|
||||
withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) {
|
||||
script {
|
||||
echo "Logging into DigitalOcean Registry..."
|
||||
|
||||
// Clean login for robustness
|
||||
sh 'rm -f ~/.docker/config.json'
|
||||
sh 'echo $DO_TOKEN | docker login registry.digitalocean.com -u token --password-stdin'
|
||||
|
||||
echo "Pushing images..."
|
||||
sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}"
|
||||
sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG}"
|
||||
|
||||
sh 'docker logout registry.digitalocean.com'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- DYNAMIC DEPLOYMENT ---
|
||||
stage('Deploy') {
|
||||
stage('Remote Deploy') {
|
||||
steps {
|
||||
script {
|
||||
// Define ports and names based on the branch
|
||||
def appPort = "3000" // Fallback
|
||||
def containerName = "backend-app"
|
||||
echo "--- REMOTE DEPLOYMENT STARTED ---"
|
||||
|
||||
if (env.BRANCH_NAME == 'Dev') {
|
||||
appPort = "3001"
|
||||
containerName = "backend-dev"
|
||||
echo "Deploying to DEV Environment (Port 3001)"
|
||||
}
|
||||
else if (env.BRANCH_NAME == 'Release') {
|
||||
appPort = "3002"
|
||||
containerName = "backend-release"
|
||||
echo "Deploying to STAGING Environment (Port 3002)"
|
||||
}
|
||||
else if (env.BRANCH_NAME == 'main') {
|
||||
appPort = "3003"
|
||||
containerName = "backend-prod"
|
||||
echo "Deploying to PRODUCTION Environment (Port 3003)"
|
||||
}
|
||||
else {
|
||||
// Logic for any future feature branches
|
||||
appPort = "3004"
|
||||
containerName = "backend-feature-${env.BRANCH_NAME}"
|
||||
echo "Deploying Feature Branch"
|
||||
}
|
||||
// 1. Define Dynamic Ports and Names
|
||||
def backPort = "3000"
|
||||
def frontPort = "4000"
|
||||
|
||||
if (env.BRANCH_NAME == 'Dev') { backPort = "3001"; frontPort = "4001"; }
|
||||
else if (env.BRANCH_NAME == 'Release') { backPort = "3002"; frontPort = "4002"; }
|
||||
else if (env.BRANCH_NAME == 'main') { backPort = "3003"; frontPort = "4003"; }
|
||||
|
||||
// 1. Clean up old container
|
||||
try {
|
||||
sh "docker stop ${containerName} || true"
|
||||
sh "docker rm ${containerName} || true"
|
||||
} catch (Exception e) {
|
||||
echo "No container to stop"
|
||||
}
|
||||
def backName = "backend-${env.BRANCH_NAME}"
|
||||
def frontName = "frontend-${env.BRANCH_NAME}"
|
||||
|
||||
// 2. Run new container on the assigned port
|
||||
sh """
|
||||
docker run -d \
|
||||
--name ${containerName} \
|
||||
--restart always \
|
||||
-p ${appPort}:3000 \
|
||||
${BACKEND_IMAGE}
|
||||
"""
|
||||
// 2. Define SSH Command using the specific deploy key
|
||||
def remote = "ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa_deploy ${DEPLOY_USER}@${DEPLOY_HOST}"
|
||||
|
||||
// 3. Authenticate and Deploy BOTH Containers
|
||||
withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) {
|
||||
|
||||
// Remote Login (Gitea Server needs to pull)
|
||||
sh "${remote} 'echo ${DO_TOKEN} | docker login registry.digitalocean.com -u token --password-stdin'"
|
||||
|
||||
// --- BACKEND DEPLOYMENT (Primary Service) ---
|
||||
echo "Deploying Backend to Port ${backPort}..."
|
||||
sh "${remote} 'docker pull ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}'"
|
||||
sh "${remote} 'docker stop ${backName} || true'"
|
||||
sh "${remote} 'docker rm ${backName} || true'"
|
||||
sh """
|
||||
${remote} 'docker run -d \
|
||||
--name ${backName} \
|
||||
--restart always \
|
||||
-p ${backPort}:3001 \
|
||||
${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}'
|
||||
"""
|
||||
|
||||
// --- FRONTEND DEPLOYMENT (Secondary Service) ---
|
||||
echo "Deploying Frontend to Port ${frontPort}..."
|
||||
sh "${remote} 'docker pull ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG}'"
|
||||
sh "${remote} 'docker stop ${frontName} || true'"
|
||||
sh "${remote} 'docker rm ${frontName} || true'"
|
||||
sh """
|
||||
${remote} 'docker run -d \
|
||||
--name ${frontName} \
|
||||
--restart always \
|
||||
-p ${frontPort}:80 \
|
||||
${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG}'
|
||||
"""
|
||||
|
||||
sh 'docker logout registry.digitalocean.com'
|
||||
|
||||
echo "Deployment Complete! Backend: http://${DEPLOY_HOST}:${backPort}, Frontend: http://${DEPLOY_HOST}:${frontPort}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// Cleanup: Delete source code and clean Docker cache on the Agent
|
||||
echo 'Cleaning Agent workspace...'
|
||||
deleteDir()
|
||||
sh 'docker system prune -f'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,8 @@ COPY package*.json ./
|
||||
# Install dependencies
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
# Copy application files
|
||||
COPY server.js ./
|
||||
# Copy all application files
|
||||
COPY . ./
|
||||
|
||||
# Create logs directory and set permissions
|
||||
RUN mkdir -p logs && chown -R nodeapp:nodejs /app
|
||||
@@ -27,7 +27,7 @@ USER nodeapp
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
|
||||
|
||||
# Expose port
|
||||
# Expose port 3001 for backend
|
||||
EXPOSE 3001
|
||||
|
||||
# Start the application
|
||||
|
||||
@@ -2,21 +2,20 @@ const express = require('express');
|
||||
const cors = require('cors');
|
||||
require('dotenv').config();
|
||||
|
||||
// TESTING: Dummy secrets for TruffleHog detection - SHOULD TRIGGER SECURITY SCAN!
|
||||
const AWS_ACCESS_KEY_ID = 'AKIAIOSFODNN7EXAMPLE';
|
||||
const AWS_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY';
|
||||
const GITHUB_TOKEN = 'ghp_1234567890abcdef1234567890abcdef12345678';
|
||||
// Load secrets from environment variables (never hardcode secrets!)
|
||||
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
|
||||
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
|
||||
const DATABASE_PASSWORD = process.env.DATABASE_PASSWORD;
|
||||
const JWT_SECRET = process.env.JWT_SECRET;
|
||||
const STRIPE_SECRET_KEY = process.env.STRIPE_SECRET_KEY;
|
||||
const SENDGRID_API_KEY = process.env.SENDGRID_API_KEY;
|
||||
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
|
||||
const MONGODB_CONNECTION = process.env.MONGODB_CONNECTION;
|
||||
const TWITTER_API_KEY = process.env.TWITTER_API_KEY;
|
||||
|
||||
// Additional test secrets for comprehensive detection
|
||||
const DATABASE_PASSWORD = 'super_secret_db_password_123!';
|
||||
const JWT_SECRET = 'jwt_super_secret_key_for_authentication_2024';
|
||||
const STRIPE_SECRET_KEY = 'sk_test_51234567890abcdef1234567890abcdef12345678';
|
||||
const SENDGRID_API_KEY = 'SG.1234567890abcdef.1234567890abcdef1234567890abcdef1234567890abcdef';
|
||||
const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX';
|
||||
const MONGODB_CONNECTION = 'mongodb://admin:supersecret123@localhost:27017/devdb';
|
||||
|
||||
// FINAL TEST: Additional secret to verify TruffleHog with fixed Jenkinsfile
|
||||
const TWITTER_API_KEY = 'twitter_api_key_1234567890abcdef1234567890abcdef1234567890';
|
||||
// No-op variable used only to trigger CI/CD pipelines on small pushes
|
||||
const TRIGGER_PIPELINE_VAR = 'trigger-20251130';
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3001;
|
||||
@@ -184,7 +183,7 @@ app.use((err, req, res, next) => {
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(PORT, () => {
|
||||
app.listen(PORT, '0.0.0.0', () => {
|
||||
console.log(`🚀 Backend server running on port ${PORT}`);
|
||||
console.log(`📊 Health check: http://localhost:${PORT}/health`);
|
||||
console.log(`📝 API endpoints: http://localhost:${PORT}/api/todos`);
|
||||
@@ -192,4 +191,3 @@ app.listen(PORT, () => {
|
||||
});
|
||||
|
||||
module.exports = app;
|
||||
const API_KEY = 'sk-1234567890abcdef1234567890abcdef12345678';
|
||||
|
||||
@@ -59,7 +59,9 @@ http {
|
||||
|
||||
# Proxy API calls to backend
|
||||
location /api {
|
||||
proxy_pass http://backend:3001;
|
||||
# Use Docker bridge gateway so container can reach host's backend
|
||||
# 172.17.0.1 is the common Docker bridge gateway; adjust if different
|
||||
proxy_pass http://172.17.0.1:3001;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection 'upgrade';
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"proxy": "http://localhost:3001"
|
||||
"proxy": "http://backend:3001"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user