17 Commits
main ... Dev

Author SHA1 Message Date
test
e38a88f4c7 chore(ci): add no-op var to trigger pipeline
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 19:36:34 +05:30
test
eecc3ad9e2 Fix: Proxy to Docker bridge gateway (172.17.0.1) so frontend can reach backend 2025-11-30 19:25:16 +05:30
test
e07af65f67 Fix: Use 127.0.0.1 for nginx proxy to fix 502 error
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 19:15:58 +05:30
test
101cbf86d9 Fix: Change nginx backend proxy from hostname to localhost
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 19:07:52 +05:30
test
a4357c95cd Fix: Remove hardcoded secrets, fix port mappings, and update frontend proxy
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 19:00:41 +05:30
test
c2abaaa2c1 Update Jenkinsfile: separate backend and frontend deployment with dynamic ports
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 18:54:21 +05:30
627d04f6d4 fix: Jenkinsfile syntax and structure for dual backend/frontend deployment 2025-11-30 18:49:08 +05:30
8eab022a91 feat: deploy both backend (3001) and frontend (3002) on shared Docker network for Dev; backend listens on 3001; robust for gitea server
Some checks failed
DevSecOps-Multibranch/pipeline/head There was a failure building this commit
2025-11-30 18:45:15 +05:30
8292dcb756 fix: backend Dockerfile copies all files, server.js uses port 3000 for container consistency
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 18:35:11 +05:30
22e842bf87 updated dockerFile
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 12:52:29 +00:00
cd3b5d242d updated host port
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 12:43:39 +00:00
ecb4417f2f Updated jenkinsFile
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 12:30:43 +00:00
eb85e581f3 Dev: Update Jenkinsfile — use core repo in registry, secure login/logout, cleanup in post
All checks were successful
DevSecOps-Multibranch/pipeline/head This commit looks good
2025-11-30 16:01:58 +05:30
266b9b59c2 Update Push to Registry stage with secure credentials handling for DigitalOcean
Some checks failed
DevSecOps-Multibranch/pipeline/head There was a failure building this commit
2025-11-30 15:47:18 +05:30
e934074647 Update Jenkinsfile with optimized pipeline using shared repository and distinct image tags
Some checks failed
DevSecOps-Multibranch/pipeline/head There was a failure building this commit
2025-11-30 15:37:41 +05:30
74f4364fd4 Push main branch code to Dev branch
Some checks failed
DevSecOps-Multibranch/pipeline/head There was a failure building this commit
2025-11-30 15:28:57 +05:30
ee03ef39ca Clear all files from Dev branch 2025-11-30 15:28:37 +05:30
5 changed files with 73 additions and 62 deletions

93
Jenkinsfile vendored
View File

@@ -1,19 +1,17 @@
pipeline { pipeline {
// 1. Run heavy lifting (Build/Push) on the Agent // 1. Run all heavy lifting (builds) on the dedicated Agent
agent { label 'jenkins-agent' } agent { label 'jenkins-agent' }
environment { environment {
// CRITICAL FIX: Use the Registry Name we verified via 'doctl' // --- REGISTRY & REPOSITORY FIXES ---
REGISTRY_URL = 'registry.digitalocean.com/devsecops-lab' REGISTRY_URL = 'registry.digitalocean.com/devsecops-lab'
REPO_NAME = 'core' // Single repository for Free Tier
// CRITICAL FIX: Use 'core' to stay within 1-repo limit // --- TAGS ---
REPO_NAME = 'core'
// Dynamic Tags
BACKEND_TAG = "backend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}" BACKEND_TAG = "backend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
FRONTEND_TAG = "frontend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}" FRONTEND_TAG = "frontend-${env.BRANCH_NAME}-${env.BUILD_NUMBER}"
// Deployment Target (The Gitea Server) // --- DEPLOYMENT TARGET ---
DEPLOY_HOST = 'gitea.kongseng.in' DEPLOY_HOST = 'gitea.kongseng.in'
DEPLOY_USER = 'root' DEPLOY_USER = 'root'
} }
@@ -25,9 +23,8 @@ pipeline {
stage('Install Dependencies') { stage('Install Dependencies') {
steps { steps {
echo "Installing dependencies for ${env.BRANCH_NAME}..." echo "Installing dependencies for ${env.BRANCH_NAME} branch..."
// Ensure folders exist to avoid errors // Assuming Node is installed on the agent
sh 'ls -la'
dir('backend') { sh 'npm install' } dir('backend') { sh 'npm install' }
dir('frontend') { sh 'npm install' } dir('frontend') { sh 'npm install' }
} }
@@ -36,7 +33,7 @@ pipeline {
stage('Build Docker Images') { stage('Build Docker Images') {
steps { steps {
script { script {
echo "Building Images..." echo "Building Backend & Frontend Images..."
sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG} ./backend" sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG} ./backend"
sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG} ./frontend" sh "docker build -t ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG} ./frontend"
} }
@@ -45,66 +42,78 @@ pipeline {
stage('Push to Registry') { stage('Push to Registry') {
steps { steps {
// We MUST inject the token here, or the push will fail with "Unauthorized"
withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) { withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) {
script { script {
echo "Logging into Registry..." echo "Logging into DigitalOcean Registry..."
// 1. Clean previous state
sh 'rm -f ~/.docker/config.json'
// 2. Login using Token as Password // Clean login for robustness
sh 'rm -f ~/.docker/config.json'
sh 'echo $DO_TOKEN | docker login registry.digitalocean.com -u token --password-stdin' sh 'echo $DO_TOKEN | docker login registry.digitalocean.com -u token --password-stdin'
echo "Pushing images..." echo "Pushing images..."
sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}" sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}"
sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG}" sh "docker push ${REGISTRY_URL}/${REPO_NAME}:${FRONTEND_TAG}"
// 3. Logout
sh 'docker logout registry.digitalocean.com' sh 'docker logout registry.digitalocean.com'
} }
} }
} }
} }
// --- REMOTE DEPLOYMENT (AGENT -> GITEA SERVER) --- stage('Remote Deploy') {
stage('Deploy') {
steps { steps {
script { script {
// Define Ports based on Branch echo "--- REMOTE DEPLOYMENT STARTED ---"
def appPort = "3000"
if (env.BRANCH_NAME == 'Dev') { appPort = "3001" } // 1. Define Dynamic Ports and Names
else if (env.BRANCH_NAME == 'Release') { appPort = "3002" } def backPort = "3000"
else if (env.BRANCH_NAME == 'main') { appPort = "3003" } 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"; }
def containerName = "backend-${env.BRANCH_NAME}" def backName = "backend-${env.BRANCH_NAME}"
def frontName = "frontend-${env.BRANCH_NAME}"
// Define SSH Command using the specific deploy key we created // 2. Define SSH Command using the specific deploy key
def remote = "ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa_deploy ${DEPLOY_USER}@${DEPLOY_HOST}" def remote = "ssh -o StrictHostKeyChecking=no -i ~/.ssh/id_rsa_deploy ${DEPLOY_USER}@${DEPLOY_HOST}"
echo "Deploying to ${DEPLOY_HOST} on Port ${appPort}..." // 3. Authenticate and Deploy BOTH Containers
// We need the token again to PULL the image on the remote server
withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) { withCredentials([string(credentialsId: 'do-registry-token', variable: 'DO_TOKEN')]) {
// 1. Remote Login // Remote Login (Gitea Server needs to pull)
sh "${remote} 'echo ${DO_TOKEN} | docker login registry.digitalocean.com -u token --password-stdin'" sh "${remote} 'echo ${DO_TOKEN} | docker login registry.digitalocean.com -u token --password-stdin'"
// 2. Remote Pull // --- BACKEND DEPLOYMENT (Primary Service) ---
echo "Deploying Backend to Port ${backPort}..."
sh "${remote} 'docker pull ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}'" sh "${remote} 'docker pull ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}'"
sh "${remote} 'docker stop ${backName} || true'"
// 3. Remote Restart (Stop -> Remove -> Run) sh "${remote} 'docker rm ${backName} || true'"
sh "${remote} 'docker stop ${containerName} || true'"
sh "${remote} 'docker rm ${containerName} || true'"
sh """ sh """
${remote} 'docker run -d \ ${remote} 'docker run -d \
--name ${containerName} \ --name ${backName} \
--restart always \ --restart always \
-p ${appPort}:3000 \ -p ${backPort}:3001 \
${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}' ${REGISTRY_URL}/${REPO_NAME}:${BACKEND_TAG}'
""" """
echo "SUCCESS: App is live at http://${DEPLOY_HOST}:${appPort}" // --- 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}"
} }
} }
} }
@@ -113,7 +122,9 @@ pipeline {
post { post {
always { always {
// Save disk space on the Agent // Cleanup: Delete source code and clean Docker cache on the Agent
echo 'Cleaning Agent workspace...'
deleteDir()
sh 'docker system prune -f' sh 'docker system prune -f'
} }
} }

View File

@@ -14,8 +14,8 @@ COPY package*.json ./
# Install dependencies # Install dependencies
RUN npm ci --only=production && npm cache clean --force RUN npm ci --only=production && npm cache clean --force
# Copy application files # Copy all application files
COPY server.js ./ COPY . ./
# Create logs directory and set permissions # Create logs directory and set permissions
RUN mkdir -p logs && chown -R nodeapp:nodejs /app 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 \ HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1 CMD wget --no-verbose --tries=1 --spider http://localhost:3001/health || exit 1
# Expose port # Expose port 3001 for backend
EXPOSE 3001 EXPOSE 3001
# Start the application # Start the application

View File

@@ -2,21 +2,20 @@ const express = require('express');
const cors = require('cors'); const cors = require('cors');
require('dotenv').config(); require('dotenv').config();
// TESTING: Dummy secrets for TruffleHog detection - SHOULD TRIGGER SECURITY SCAN! // Load secrets from environment variables (never hardcode secrets!)
const AWS_ACCESS_KEY_ID = 'AKIAIOSFODNN7EXAMPLE'; const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET_ACCESS_KEY = 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'; const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
const GITHUB_TOKEN = 'ghp_1234567890abcdef1234567890abcdef12345678'; 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 // No-op variable used only to trigger CI/CD pipelines on small pushes
const DATABASE_PASSWORD = 'super_secret_db_password_123!'; const TRIGGER_PIPELINE_VAR = 'trigger-20251130';
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';
const app = express(); const app = express();
const PORT = process.env.PORT || 3001; const PORT = process.env.PORT || 3001;
@@ -184,7 +183,7 @@ app.use((err, req, res, next) => {
}); });
// Start server // Start server
app.listen(PORT, () => { app.listen(PORT, '0.0.0.0', () => {
console.log(`🚀 Backend server running on port ${PORT}`); console.log(`🚀 Backend server running on port ${PORT}`);
console.log(`📊 Health check: http://localhost:${PORT}/health`); console.log(`📊 Health check: http://localhost:${PORT}/health`);
console.log(`📝 API endpoints: http://localhost:${PORT}/api/todos`); console.log(`📝 API endpoints: http://localhost:${PORT}/api/todos`);
@@ -192,4 +191,3 @@ app.listen(PORT, () => {
}); });
module.exports = app; module.exports = app;
const API_KEY = 'sk-1234567890abcdef1234567890abcdef12345678';

View File

@@ -59,7 +59,9 @@ http {
# Proxy API calls to backend # Proxy API calls to backend
location /api { 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_http_version 1.1;
proxy_set_header Upgrade $http_upgrade; proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade'; proxy_set_header Connection 'upgrade';

View File

@@ -46,5 +46,5 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"proxy": "http://localhost:3001" "proxy": "http://backend:3001"
} }