Skip to content

Dev#7

Open
Gujjar-Apurv-023 wants to merge 58 commits intoDevMadhup:mainfrom
Gujjar-Apurv-023:dev
Open

Dev#7
Gujjar-Apurv-023 wants to merge 58 commits intoDevMadhup:mainfrom
Gujjar-Apurv-023:dev

Conversation

@Gujjar-Apurv-023
Copy link
Copy Markdown

@Gujjar-Apurv-023 Gujjar-Apurv-023 commented Apr 28, 2026

Summary

Briefly describe the purpose of this PR.

Description

Explain in detail what this PR is all about. This should include the problem you're solving, the approach taken, and any technical details that reviewers need to know.

Images

Include any relevant images or diagrams that can help reviewers visualize the changes, if applicable

Issue(s) Addressed

Enter the issue number of the bug(s) that this PR fixes

  • Template should be strictly Closes <issue_number>
  • Example: Closes Devops #1

Prerequisites

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Docker and Docker Compose support for containerized local development and deployment.
    • Introduced Kubernetes infrastructure for production deployment with automated scaling.
    • Added CI/CD pipelines for automated testing, security scanning, and deployment.
  • Documentation

    • Added Kubernetes deployment guide and Docker setup instructions.
  • Refactor

    • Simplified frontend API endpoints to use relative paths for better portability.
    • Streamlined blog creation form with improved validation logic.
  • Chores

    • Updated TypeScript to latest version.
    • Added environment configuration files for containerized environments.

@github-actions
Copy link
Copy Markdown

Umm... did someone forget to read the style guide? Fix that PR title and let's try again! @Gujjar-Apurv-023
Don't worry, it happens to the best of us! Check out our contributor guidelines for more details.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

This PR introduces comprehensive Docker containerization and Kubernetes orchestration infrastructure for the Wanderlust application, along with CI/CD pipelines for automated testing, scanning, and deployment. Includes automation scripts for dynamic environment configuration, frontend code refactoring to support relative API paths, and complete Kubernetes manifests for production-ready deployment with persistent storage and auto-scaling.

Changes

Cohort / File(s) Summary
Automation Scripts
Automations/updateBackend.sh, Automations/updateFrontend.sh, Automations/updatebackendnew.sh, Automations/updatefrontendnew.sh
Four bash scripts that retrieve public IPv4 addresses from AWS metadata/CLI endpoints and update backend/frontend .env.docker files with dynamically constructed API/frontend URLs via sed substitution, including existence checks and early-exit logic.
CI/CD Pipeline Configuration
Jenkinsfile, GitOps/Jenkinsfile
Main Jenkins pipeline orchestrating security scanning (OWASP, Trivy, SonarQube), parallel environment updates, Docker builds, and image pushes; downstream GitOps pipeline updates Kubernetes manifests with provided Docker image tags and commits to the repository.
Docker Configuration
docker-compose.yml, backend/Dockerfile, frontend/Dockerfile, frontend/nginx.conf
Multi-service Docker Compose setup with MongoDB, Redis, backend, and frontend; two-stage Dockerfiles for optimized Node.js and nginx-based frontend builds; nginx configuration with API proxy routing and client-side routing support.
Backend Configuration
backend/.env.docker, backend/server.js, backend/.env.sample
New Docker-specific environment configuration with database connection strings and JWT settings; CORS configuration update to allow all origins; sample env file formatting fix.
Frontend Application Updates
frontend/src/pages/add-blog.tsx, frontend/src/pages/details-page.tsx, frontend/src/pages/home-page.tsx, frontend/src/components/blog-feed.tsx, frontend/package.json, frontend/.env.sample
Refactored form handling with functional state updates and dark-mode support; API endpoint changes from environment-variable-prefixed to relative paths; TypeScript version bump; env sample formatting fix.
Kubernetes Core Infrastructure
kubernetes/sc.yaml, kubernetes/mongo-pvc.yaml, kubernetes/redis-pvc.yaml
StorageClass for AWS EBS provisioning; persistent volume claims for MongoDB (5Gi) and Redis (2Gi) with gp2 storage and immediate binding.
Kubernetes Data Layer
kubernetes/mongodb.yaml, kubernetes/redis.yaml
MongoDB and Redis deployments in wanderlust namespace with persistent storage mounts, internal ClusterIP services, and resource requests/limits.
Kubernetes Application Layer
kubernetes/backend-deploy.yaml, kubernetes/backend-svc.yml, kubernetes/backend-hpa.yaml, kubernetes/frontend-deploy.yaml, kubernetes/frontend-svc.yml
Backend deployment using apurv023/backend-023:latest with HPA configured for 1–20 replicas at 90% CPU; frontend deployment using apurv023/frontend:v5; internal ClusterIP services for both components.
Kubernetes Networking & Orchestration
kubernetes/ingress.yaml, kubernetes/get_helm.sh
Nginx ingress routing /api to backend-service and / to frontend-service; comprehensive Helm installation script with architecture detection, checksum/GPG verification, and dependency validation.
Documentation
README.md, kubernetes/README.md, kubernetes/assets/README.md
Docker-based setup workflow with prerequisites and compose instructions; end-to-end Kubernetes deployment guide with namespace, CoreDNS, image build, manifest sequencing, and validation steps; empty assets directory placeholder.

Sequence Diagram

sequenceDiagram
    actor Dev as Developer
    participant Git as GitHub
    participant Jenkins as Jenkins CI
    participant Scan as Security Scanners
    participant Registry as Docker Registry
    participant GitOps as GitOps Pipeline
    participant K8s as Kubernetes Cluster

    Dev->>Git: Push code to devops branch
    Git->>Jenkins: Webhook trigger
    Jenkins->>Git: Checkout source (code_checkout)
    Jenkins->>Scan: Run OWASP dependency-check
    Scan->>Jenkins: Return report
    Jenkins->>Scan: Run Trivy filesystem scan
    Scan->>Jenkins: Return results
    Jenkins->>Scan: Run SonarQube analysis & quality gate
    Scan->>Jenkins: Evaluation complete
    Jenkins->>Jenkins: Execute backend/frontend update scripts
    Jenkins->>Jenkins: Build backend Docker image
    Jenkins->>Jenkins: Build frontend Docker image
    Jenkins->>Registry: Push backend image (test-image-donot-use)
    Jenkins->>Registry: Push frontend image (test-image-donot-use)
    Jenkins->>GitOps: Trigger Wanderlust-CD with image tags
    GitOps->>Git: Checkout devops branch
    GitOps->>GitOps: Update kubernetes/backend.yaml image reference
    GitOps->>GitOps: Update kubernetes/frontend.yaml image reference
    GitOps->>Git: Commit & push manifest updates
    GitOps->>K8s: Manifests pulled by GitOps operator
    K8s->>Registry: Pull updated backend image
    K8s->>Registry: Pull updated frontend image
    K8s->>K8s: Deploy/update pods
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰✨ A rabbit hops through Docker and Kubernetes grand,
Building containers and clusters across the land!
With Jenkins orchestrating the CI/CD delight,
And Helm scripts ensuring everything's just right,
From source to production, no stone left unturned,
DevOps wisdom thoroughly earned! 🚀

🚥 Pre-merge checks | ❌ 5

❌ Failed checks (2 warnings, 3 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description consists entirely of the unfilled template with placeholder text; no actual summary, detailed description, images, linked issues, or completion of the checklist were provided by the author. Complete the PR description with: a summary of the Docker/Kubernetes/CI-CD infrastructure additions, detailed explanation of changes (automation scripts, manifests, Dockerfiles), any relevant diagrams, the issue number in 'Closes #X' format, and confirmation of the contributing guidelines checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The PR title 'Dev' is overly vague and generic, using a non-descriptive single word that does not convey meaningful information about the substantial changeset involving Docker, Kubernetes, Jenkins CI/CD, and backend/frontend automation scripts. Replace 'Dev' with a descriptive title that captures the primary purpose, such as 'Add Docker, Kubernetes, and CI/CD pipeline automation infrastructure' or 'Setup Docker containerization and Kubernetes deployment with Jenkins CI/CD'.
Linked Issues check ❓ Inconclusive Linked issue #1 (Devops) contains only template text with no concrete objectives, acceptance criteria, or specific coding requirements, making it impossible to validate whether the changeset meets actual project requirements. Ensure the linked issue #1 includes concrete DevOps objectives such as specific Kubernetes deployment requirements, Docker image specifications, CI/CD pipeline stages, and environment configuration expectations.
Out of Scope Changes check ❓ Inconclusive The changeset encompasses extensive additions spanning Docker infrastructure, Kubernetes manifests, CI/CD automation, and environment configurations across backend and frontend components, with no linked issue objectives to determine scope. Clarify project scope in the linked issue and PR description to confirm that all Docker, Kubernetes, Jenkins pipeline, and automation script additions are within intended scope for this DevOps initiative.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch dev

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

Umm... did someone forget to read the style guide? Fix that PR title and let's try again! @coderabbitai[bot]
Don't worry, it happens to the best of us! Check out our contributor guidelines for more details.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
frontend/src/components/blog-feed.tsx (1)

23-31: ⚠️ Potential issue | 🟡 Minor

Stop loading state on request failure.

Line 22 sets loading to true, but on failure (Line 29-Line 31) it is never reset, causing an infinite skeleton state.

Proposed fix
   setLoading(true);
   axios
     .get(categoryEndpoint)
     .then((response) => {
       setPosts(response.data);
-      setLoading(false);
     })
     .catch((error) => {
       console.error(error);
-    });
+    })
+    .finally(() => {
+      setLoading(false);
+    });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/blog-feed.tsx` around lines 23 - 31, The current
axios.get call handles success by calling setPosts(response.data) and
setLoading(false) but on error the catch only logs the error and never clears
loading; update the request handling for the component (the axios.get(...)
promise) so that on failure you call setLoading(false) as well (either add
setLoading(false) inside the .catch handler or move loading cleanup into a
.finally block) and keep current setPosts, referencing the existing setPosts and
setLoading functions used in this file (the axios.get(categoryEndpoint) promise
chain).
kubernetes/backend-deploy.yaml (1)

19-35: ⚠️ Potential issue | 🟠 Major

Add readiness/liveness probes for safer rollouts and recovery.

Without probes, traffic can hit unready pods and failures may be detected late.

🩺 Suggested probe configuration
         - name: backend
           image: apurv023/backend-023:latest
+          readinessProbe:
+            tcpSocket:
+              port: 5000
+            initialDelaySeconds: 5
+            periodSeconds: 10
+          livenessProbe:
+            tcpSocket:
+              port: 5000
+            initialDelaySeconds: 20
+            periodSeconds: 20
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/backend-deploy.yaml` around lines 19 - 35, The container spec for
the "backend" container (image apurv023/backend-023:latest, containerPort 5000)
lacks readiness/liveness probes; add a readinessProbe and a livenessProbe under
that container to prevent traffic to unready pods and enable fast recovery—use
an HTTP GET (or tcpSocket) against port 5000 (e.g., path /health), set sensible
values like initialDelaySeconds, periodSeconds, timeoutSeconds, failureThreshold
(for liveness) and successThreshold (for readiness); update the container block
where PORT and containerPort are defined to include these probe definitions.
🟠 Major comments (31)
kubernetes/mongo-pvc.yaml-9-9 (1)

9-9: ⚠️ Potential issue | 🟠 Major

Avoid hard-coding an EKS-specific StorageClass in the shared PVC.

gp2 makes this manifest cluster-specific. On environments that do not expose a gp2 StorageClass, the claim will stay pending instead of provisioning. For a repo-level manifest, either parameterize the class per environment or omit storageClassName and let the cluster default apply. (kubernetes.io)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/mongo-pvc.yaml` at line 9, The manifest hard-codes
storageClassName: gp2 in the PVC which ties the shared PersistentVolumeClaim to
EKS and can leave it Pending on other clusters; remove the storageClassName
field from the PVC (or alternatively parameterize it via a Helm value /
Kustomize patch) so the cluster default StorageClass is used, and document or
expose a configurable value name (e.g., STORAGE_CLASS or helm value
storageClassName) if explicit control is required.
Automations/updatefrontendnew.sh-7-7 (1)

7-7: ⚠️ Potential issue | 🟠 Major

Validate the AWS lookup before rewriting the frontend env file.

If aws ec2 describe-instances fails or the instance has no public IP (returns None), the script will still rewrite VITE_API_PATH with an empty or invalid host, silently breaking the frontend deployment.

Add validation after line 7:

Suggested fix
 ipv4_address=$(aws ec2 describe-instances --instance-ids $INSTANCE_ID --query 'Reservations[0].Instances[0].PublicIpAddress' --output text)
+
+if [[ -z "$ipv4_address" || "$ipv4_address" == "None" ]]; then
+  echo -e "${RED}ERROR : Could not resolve a public IPv4 for ${INSTANCE_ID}.${NC}"
+  exit 1
+fi

This applies to line 7 (and line 29 where the unvalidated variable is used).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updatefrontendnew.sh` at line 7, The script sets ipv4_address
using aws ec2 describe-instances but never validates it; add a check after the
assignment of ipv4_address in updatefrontendnew.sh to ensure the variable is
non-empty and not "None" (or an invalid value) before proceeding to rewrite
VITE_API_PATH (used later around line 29); if the lookup failed, log a clear
error and exit with non-zero status (do not update the env file) so the frontend
env is not overwritten with an empty/invalid host.
Automations/updatefrontendnew.sh-11-22 (1)

11-22: ⚠️ Potential issue | 🟠 Major

Treat the no-op path as success, and only compare VITE_API_PATH.

The script reads the file at line 11 before confirming it exists, compares the entire file contents to a single expected line, and exits with -1 when it detects no change is needed. This makes the fast path brittle and turns a successful no-op update into a CI failure. Additionally, the file existence check at line 24 comes too late—after the initial read attempt at line 11 will have already failed if the file is missing.

Suggested fix
 file_to_find="../frontend/.env.docker"
-alreadyUpdate=$(cat ../frontend/.env.docker)
+if [ ! -f "$file_to_find" ]; then
+  echo -e "${RED}ERROR : File not found..${NC}"
+  exit 1
+fi
+
+current_api_path=$(grep -E '^VITE_API_PATH=' "$file_to_find" | tail -n1)

@@
-if [[ "${alreadyUpdate}" == "VITE_API_PATH=\"http://${ipv4_address}:31100\"" ]]
+if [[ "${current_api_path}" == "VITE_API_PATH=\"http://${ipv4_address}:31100\"" ]]
 then
         echo -e "${YELLOW}${file_to_find} file is already updated to the current host's Ipv4 ${NC}"
-        exit -1;
+        exit 0
 else
-        if [ -f ${file_to_find} ]
-        then
-                echo -e "${GREEN}${file_to_find}${NC} found.."
-                echo -e "${YELLOW}Configuring env variables in ${NC} ${file_to_find}"
-                sleep 7s;
-                sed -i -e "s|VITE_API_PATH.*|VITE_API_PATH=\"http://${ipv4_address}:31100\"|g" ${file_to_find}
-                echo -e "${GREEN}env variables configured..${NC}"
-        else
-                echo -e "${RED}ERROR : File not found..${NC}"
-        fi
+        echo -e "${GREEN}${file_to_find}${NC} found.."
+        echo -e "${YELLOW}Configuring env variables in ${NC} ${file_to_find}"
+        sleep 7s
+        sed -i -e "s|^VITE_API_PATH=.*|VITE_API_PATH=\"http://${ipv4_address}:31100\"|g" "$file_to_find"
+        echo -e "${GREEN}env variables configured..${NC}"
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updatefrontendnew.sh` around lines 11 - 22, Check for the file
before reading and treat the "no-op" path as success: first test that
../frontend/.env.docker exists (use a -f check on the same path referenced by
file_to_find) before assigning alreadyUpdate; extract only the VITE_API_PATH
line from the file (e.g., via grep or awk) into alreadyUpdate instead of reading
the whole file, compare that value to the expected
VITE_API_PATH="http://${ipv4_address}:31100", and when they match exit with code
0 (success) rather than -1; update any echo messages to still reference
file_to_find for clarity.
backend/.env.docker-9-9 (1)

9-9: ⚠️ Potential issue | 🟠 Major

Use production mode for Docker runtime.

Line 9 sets NODE_ENV=Development; for deployed containers this should be production to avoid non-prod behavior.

Proposed fix
-NODE_ENV=Development
+NODE_ENV=production
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/.env.docker` at line 9, The Docker environment file currently sets
NODE_ENV=Development which enables non-production behavior; update the value of
the NODE_ENV entry in backend/.env.docker from "Development" to "production"
(lowercase is conventional) so containers run in production mode, then
rebuild/redeploy the Docker image; verify there are no other env entries or code
branches that explicitly check for the string "Development" and adjust them if
necessary.
kubernetes/mongodb.yaml-17-33 (1)

17-33: ⚠️ Potential issue | 🟠 Major

Add explicit pod and container security context hardening.

The MongoDB deployment currently lacks security context configuration. Add securityContext at the pod level to enforce runAsNonRoot: true, runAsUser: 999 (or a non-root UID), and fsGroup for storage permissions. At the container level, set allowPrivilegeEscalation: false and add securityContext.capabilities.drop: ["ALL"] with only required capabilities added back if needed. Consider adding seccompProfile for additional syscall filtering.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/mongodb.yaml` around lines 17 - 33, Add hardened pod and container
security contexts to the MongoDB Pod spec: under the top-level spec add a
pod-level securityContext with runAsNonRoot: true, runAsUser: 999 (or another
non-root UID) and fsGroup set to the storage group to ensure volume
permissioning; then inside the container entry for name: mongo add a
container-level securityContext that sets allowPrivilegeEscalation: false,
capabilities.drop: ["ALL"] (and only re-add minimal capabilities if the mongo
container actually needs them), and a seccompProfile (e.g., type:
RuntimeDefault) to restrict syscalls; update the spec.containers -> - name:
mongo block and the surrounding spec.securityContext accordingly so volumes
mounted at /data/db are still accessible via fsGroup.
frontend/src/components/blog-feed.tsx-24-24 (1)

24-24: ⚠️ Potential issue | 🟠 Major

Configure Vite proxy for /api endpoints in local development.

The code relies on /api/* routes at lines 24 and 36, but frontend/vite.config.ts has no proxy configuration. Local npm run dev will fail with 404 errors unless a backend runs on the same port or the proxy is added.

Additionally, the error handler at line 30 doesn't reset the loading state, causing indefinite loading spinners if the category request fails.

Recommended fix

Add to vite.config.ts:

server: {
  proxy: {
    '/api': {
      target: 'http://localhost:5000', // adjust to your backend port
      changeOrigin: true,
    }
  }
}

And add setLoading(false) in the catch block at line 31.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/components/blog-feed.tsx` at line 24, The component uses
categoryEndpoint (via .get(categoryEndpoint)) and calls setLoading to manage
loading state; add a dev proxy in frontend/vite.config.ts mapping '/api' to your
backend (e.g., http://localhost:5000) so requests to /api/* succeed in npm run
dev, and update the BlogFeed component's catch/error handler where
categoryEndpoint is fetched to call setLoading(false) in the catch/finally path
so the loading spinner is cleared on errors.
frontend/Dockerfile-14-23 (1)

14-23: ⚠️ Potential issue | 🟠 Major

Add non-root USER to the nginx stage.

The runtime container (lines 14–23) runs as root by default since FROM nginx:alpine lacks an explicit USER directive, and the Kubernetes deployment has no securityContext to override this. Set USER nginx (or create a dedicated unprivileged user) in the Dockerfile to harden container isolation.

Example fix:
FROM nginx:alpine

COPY --from=frontend-builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf

EXPOSE 80

USER nginx

CMD ["nginx", "-g", "daemon off;"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/Dockerfile` around lines 14 - 23, The runtime Dockerfile currently
uses the nginx:alpine stage and runs as root by default; update the nginx stage
to run as a non-root user by adding a USER directive (e.g., USER nginx) after
copying assets and config, or create and switch to a dedicated unprivileged user
before CMD; ensure the chosen user has permissions to read /usr/share/nginx/html
and the nginx config so nginx (started by CMD ["nginx", "-g", "daemon off;"])
can run without root.
kubernetes/mongodb.yaml-19-37 (1)

19-37: ⚠️ Potential issue | 🟠 Major

MongoDB is deployed without authentication, exposing the database to all pods in the cluster.

Lines 19-37 define the mongo container without any authentication credentials configured (no MONGO_INITDB_ROOT_USERNAME or MONGO_INITDB_ROOT_PASSWORD). Combined with the connection string in backend/.env.docker (mongodb://mongo-service/wanderlust with no credentials), this allows any pod with network access to read and modify data.

Additionally, the deployment lacks pod/container security hardening (securityContext) which increases the attack surface.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/mongodb.yaml` around lines 19 - 37, The MongoDB container is
deployed without authentication and missing container hardening; add environment
variables MONGO_INITDB_ROOT_USERNAME and MONGO_INITDB_ROOT_PASSWORD sourced from
a Kubernetes Secret (create a Secret and reference it in the mongo container
env) and update the application connection string to include those credentials
(replace mongodb://mongo-service/wanderlust with a credentialed URI or use
separate env vars for host/db/username/password in the backend env). Also add a
securityContext at the pod and container level (e.g., runAsNonRoot/runAsUser,
allowPrivilegeEscalation: false, readOnlyRootFilesystem where possible) to the
mongo deployment spec to reduce attack surface. Ensure references: the container
named "mongo", the PVC "mongo-pvc", and the backend env vars for the connection
string are updated accordingly.
frontend/nginx.conf-10-14 (1)

10-14: ⚠️ Potential issue | 🟠 Major

Add proxy headers and configure backend to trust proxy for secure cookie handling.

Secure cookies are configured in the backend (with secure: true), but they will fail in a HTTPS-to-HTTP proxy setup without proper headers. The Nginx config must forward X-Forwarded-Proto and X-Forwarded-For headers, and the backend must be configured to trust the proxy:

Nginx changes:

  location /api/ {
    proxy_pass http://backend-service;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
+   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+   proxy_set_header X-Forwarded-Proto $scheme;
  }

Backend changes needed in backend/server.js:

const app = express();
+app.trust('proxy');

Without these, secure cookies will be rejected over HTTP, breaking authentication.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/nginx.conf` around lines 10 - 14, Update the Nginx location /api/
proxy to forward X-Forwarded-Proto and X-Forwarded-For by adding
proxy_set_header X-Forwarded-Proto $scheme and proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for so the backend sees the original protocol and client
IP; then in backend/server.js enable trusting the proxy (e.g., set Express
app.set('trust proxy', true) or equivalent) so secure cookies (secure: true) and
IP-based logic work correctly behind the proxy.
kubernetes/redis-pvc.yaml-9-9 (1)

9-9: ⚠️ Potential issue | 🟠 Major

Align PVC storage class with the StorageClass defined in this PR.

Line 9 uses gp2, while kubernetes/sc.yaml defines gp2-immediate. This mismatch can bypass the intended class and lead to inconsistent provisioning behavior.

🔧 Suggested change
-  storageClassName: gp2
+  storageClassName: gp2-immediate
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/redis-pvc.yaml` at line 9, The PersistentVolumeClaim in
kubernetes/redis-pvc.yaml is using storageClassName: gp2 which doesn't match the
StorageClass defined in this PR (gp2-immediate); update the storageClassName
value from "gp2" to "gp2-immediate" so the PVC binds to the intended
StorageClass (look for the storageClassName key in the PVC and the gp2-immediate
name in kubernetes/sc.yaml).
backend/Dockerfile-14-25 (1)

14-25: ⚠️ Potential issue | 🟠 Major

Run the runtime container as a non-root user.

No USER is set in the runtime stage, so the process runs as root by default.

🔒 Suggested change
 FROM node:21-slim

 WORKDIR /app

-COPY --from=backend-builder /app .
+COPY --from=backend-builder --chown=node:node /app .
 
-COPY .env.docker .env
+COPY --chown=node:node .env.docker .env

 EXPOSE 5000

 # 🔥 ADD THIS LINE
+USER node
 CMD ["node", "server.js"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/Dockerfile` around lines 14 - 25, The runtime Dockerfile currently
runs the container as root (no USER set) after COPY and before CMD; add a
non-root user and switch to it: create a user/group (e.g., app or node), chown
the WORKDIR (/app) and any necessary files, and add USER <username> before the
CMD so the process started by CMD ["node","server.js"] runs unprivileged; update
file ownership where COPY is used to ensure the non-root user can read/write
/app.
kubernetes/frontend-deploy.yaml-17-22 (1)

17-22: ⚠️ Potential issue | 🟠 Major

Harden pod/container security context.

The deployment currently uses the default security context, which leaves privilege escalation and root execution paths open. Add explicit pod/container hardening controls.

🔒 Suggested hardening baseline
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: frontend
           image: apurv023/frontend:v5
+          securityContext:
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+            capabilities:
+              drop: ["ALL"]
           ports:
             - containerPort: 80   # ✅ FIXED
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/frontend-deploy.yaml` around lines 17 - 22, Add explicit pod and
container securityContext entries to harden the "frontend" container: set
pod-level securityContext (e.g., runAsUser: 1000, runAsNonRoot: true, fsGroup:
1000) and container-level securityContext for the "frontend" container
(allowPrivilegeEscalation: false, privileged: false, readOnlyRootFilesystem:
true, capabilities: drop ["ALL"], seccompProfile: RuntimeDefault). Ensure these
keys are added alongside the existing spec.containers block for the container
named "frontend" so the pod and container run as a non-root, non-privileged
process with a restrictive filesystem and dropped capabilities.
kubernetes/sc.yaml-4-7 (1)

4-7: ⚠️ Potential issue | 🟠 Major

This StorageClass is currently not referenced by the PVCs.

kubernetes/redis-pvc.yaml (Line 9) and kubernetes/mongo-pvc.yaml use storageClassName: gp2, so gp2-immediate is effectively unused.

🔧 Suggested alignment
 metadata:
-  name: gp2-immediate
+  name: gp2

or update PVCs to gp2-immediate consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/sc.yaml` around lines 4 - 7, The StorageClass named gp2-immediate
is not used because PVCs in kubernetes/redis-pvc.yaml and
kubernetes/mongo-pvc.yaml reference storageClassName: gp2; fix by making names
consistent: either rename the StorageClass from gp2-immediate to gp2 (update the
name field in the StorageClass manifest) or update both PVCs to use
storageClassName: gp2-immediate so they bind to this StorageClass; ensure the
chosen name matches across the StorageClass resource (gp2 or gp2-immediate) and
the PVCs' storageClassName fields.
kubernetes/redis.yaml-17-34 (1)

17-34: ⚠️ Potential issue | 🟠 Major

Add explicit security context for Redis container.

The deployment is running with default security settings. Add pod/container hardening to reduce privilege risk.

🔒 Suggested hardening baseline
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: redis
           image: redis:7
+          securityContext:
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+            capabilities:
+              drop: ["ALL"]
           ports:
             - containerPort: 6379
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/redis.yaml` around lines 17 - 34, Add explicit pod- and
container-level securityContext entries for the Redis container to harden
privileges: under the Pod spec add pod-level securityContext (e.g., runAsUser
non-root UID, fsGroup) and for the container named "redis" add a container-level
securityContext with runAsNonRoot: true, runAsUser (non-root), runAsGroup,
readOnlyRootFilesystem: true where possible, allowPrivilegeEscalation: false,
and dropCapabilities: ["ALL"], plus a seccompProfile (RuntimeDefault) to reduce
syscall exposure; ensure the /data volumeMount still has the necessary write
permissions for the specified fsGroup/runAsUser so persistence (args:
["--appendonly","yes"] and volumeMounts: mountPath: /data) continues working.
kubernetes/redis.yaml-19-34 (1)

19-34: ⚠️ Potential issue | 🟠 Major

Add readiness/liveness probes for service reliability.

Without probes, Kubernetes can route traffic to an unready Redis pod and may not recover quickly from degraded states.

🩺 Suggested probe configuration
       containers:
         - name: redis
           image: redis:7
+          readinessProbe:
+            tcpSocket:
+              port: 6379
+            initialDelaySeconds: 5
+            periodSeconds: 10
+          livenessProbe:
+            tcpSocket:
+              port: 6379
+            initialDelaySeconds: 15
+            periodSeconds: 20
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/redis.yaml` around lines 19 - 34, Add Kubernetes readinessProbe
and livenessProbe to the Redis container spec (container name "redis") so the
kubelet can detect unready or unhealthy pods; use either an exec probe that runs
redis-cli PING against port 6379 or a tcpSocket probe on containerPort 6379, and
configure sensible timing (e.g., initialDelaySeconds, periodSeconds,
timeoutSeconds, failureThreshold) for both readinessProbe and livenessProbe to
avoid false positives; ensure probes are added alongside the existing args
["--appendonly","yes"] and volumeMounts (mountPath /data) in the same container
spec so health checks target the running Redis process.
kubernetes/backend-deploy.yaml-17-34 (1)

17-34: ⚠️ Potential issue | 🟠 Major

Add explicit security context to backend pod/container.

The deployment is using default security context, leaving unnecessary privilege surface.

🔒 Suggested hardening baseline
     spec:
+      securityContext:
+        seccompProfile:
+          type: RuntimeDefault
       containers:
         - name: backend
           image: apurv023/backend-023:latest
+          securityContext:
+            allowPrivilegeEscalation: false
+            readOnlyRootFilesystem: true
+            capabilities:
+              drop: ["ALL"]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/backend-deploy.yaml` around lines 17 - 34, Add explicit pod and
container securityContext entries to harden the backend deployment: under the
pod spec (adjacent to spec: containers) add a pod-level securityContext with
runAsNonRoot: true, runAsUser (e.g., 1000) and fsGroup (e.g., 2000); and inside
the backend container definition (the list item with name: backend) add
container-level securityContext with readOnlyRootFilesystem: true,
allowPrivilegeEscalation: false, capabilities.drop: ["ALL"], and
seccompProfile.type: "RuntimeDefault" to ensure the backend container runs
non-privileged and with minimized privileges.
kubernetes/sc.yaml-5-5 (1)

5-5: ⚠️ Potential issue | 🟠 Major

Use the AWS EBS CSI provisioner instead of the in-tree EBS provisioner.

kubernetes.io/aws-ebs is deprecated in favor of ebs.csi.aws.com, which is the recommended provisioner for current EKS clusters. The in-tree provisioner lacks ongoing maintenance and support compared to the out-of-tree CSI driver.

🔧 Suggested change
-provisioner: kubernetes.io/aws-ebs
+provisioner: ebs.csi.aws.com
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/sc.yaml` at line 5, The StorageClass uses the deprecated in-tree
provisioner value "kubernetes.io/aws-ebs"; update the provisioner field to the
CSI driver identifier "ebs.csi.aws.com" (i.e., replace the value of the
provisioner key) and ensure any associated StorageClass metadata and parameters
remain valid for the AWS EBS CSI driver (verify compatibility with the cluster's
installed CSI driver).
frontend/src/pages/details-page.tsx-23-25 (1)

23-25: ⚠️ Potential issue | 🟠 Major

Move setIsLoading(false) to a finally block to ensure loading state is cleared on both success and failure.

Currently, if the axios request fails, the catch block (lines 23-25) only logs the error without clearing the loading state. This leaves the page stuck on "Loading..." indefinitely. The finally block ensures setIsLoading(false) executes regardless of whether the request succeeds or fails.

🔧 Suggested fix
      try {
        const response = await axios.get(`/api/posts/${postId}`);
        console.log(response.data);
        setPost(response.data);
-       setIsLoading(false);
      } catch (error) {
        console.log(error);
+     } finally {
+       setIsLoading(false);
      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/details-page.tsx` around lines 23 - 25, The loading state
is not cleared on request failure; move the setIsLoading(false) call into a
finally block so it always runs after the async axios call in the function that
currently has try { ... } catch(error) { console.log(error) } — locate the axios
request and its state updater (setIsLoading) in this component (e.g., the
fetch/details loader function in details-page.tsx), add a finally {
setIsLoading(false) } and remove any duplicate setIsLoading(false) in the try or
catch so the loader is always cleared on both success and error.
backend/Dockerfile-11-11 (1)

11-11: ⚠️ Potential issue | 🟠 Major

Prevent watch mode in Docker build to ensure deterministic test execution.

RUN npm run test invokes the test script containing --watchAll, which causes Jest to run in watch mode. This hangs the Docker build indefinitely since there's no user interaction to exit. Remove the --watchAll flag by adding --watchAll=false.

Suggested fix
-RUN npm run test
+RUN npm run test -- --watchAll=false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/Dockerfile` at line 11, The Dockerfile currently runs tests with RUN
npm run test which triggers Jest's watch mode via the test script; update the
Dockerfile to run tests deterministically by invoking the test command without
watch mode (e.g., RUN npm run test -- --watchAll=false or set CI=true before
running tests) so that the npm run test invocation exits in non-interactive
Docker builds; target the RUN npm run test line in the Dockerfile to implement
this change.
frontend/src/pages/details-page.tsx-28-31 (1)

28-31: ⚠️ Potential issue | 🟠 Major

Fetch condition can serve stale data when postId changes.

The current guard only fetches when post === undefined; if navigating to a new postId while post is already set, the old post can remain rendered.

Additionally, the error handler doesn't call setIsLoading(false), leaving the component in a stuck loading state if the fetch fails.

🔧 Suggested fix
-    if (post === undefined) {
-      getPostById();
-    }
-  }, [post, postId]);
+    const currentId = String((post as any)?.id ?? (post as any)?._id ?? '');
+    if (!post || currentId !== String(postId ?? '')) {
+      setIsLoading(true);
+      getPostById();
+    }
+  }, [postId]);

Also ensure the error handler updates loading state:

      } catch (error) {
        console.log(error);
+       setIsLoading(false);
      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/details-page.tsx` around lines 28 - 31, The effect
currently only calls getPostById() when post === undefined, which allows stale
post data when postId changes; update the condition in the useEffect to call
getPostById when post is undefined OR when post.id (or postId stored on post)
does not match the current postId so the new post will be fetched; also ensure
the getPostById error handler calls setIsLoading(false) (and any other necessary
cleanup) so the component doesn't stay in a loading state on fetch failure. Use
the existing symbols getPostById, post, postId, and setIsLoading to locate and
modify the logic.
Jenkinsfile-18-22 (1)

18-22: ⚠️ Potential issue | 🟠 Major

The pipeline is checking out the wrong branch.

This PR is dev -> main, but the checkout stage is pinned to devops. That means CI can go green without ever building or scanning the code from this PR.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Jenkinsfile` around lines 18 - 22, The Git checkout stage 'Git: Code
Checkout' is hardcoded to the wrong branch via the
code_checkout("https://github.com/DevMadhup/wanderlust.git","devops") call;
update the second argument to the correct branch for this PR (e.g., "main") or,
better, use the pipeline branch variable (for example CHANGE_TARGET or
BRANCH_NAME) so code_checkout uses the PR target branch dynamically; modify the
call to code_checkout(...) accordingly inside the 'Git: Code Checkout' stage.
Jenkinsfile-91-96 (1)

91-96: ⚠️ Potential issue | 🟠 Major

Use an immutable image tag per build.

Reusing test-image-donot-use for every build means concurrent or later runs overwrite the same artifact, and the CD job cannot tell which commit it is deploying. Please derive the tag from the build number or commit SHA and pass that value through consistently.

Also applies to: 104-115

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Jenkinsfile` around lines 91 - 96, The Jenkinsfile is using a fixed tag
"test-image-donot-use" in docker_build calls which makes artifacts
non-immutable; update the docker_build invocations (e.g.,
docker_build("backend-wanderlust","test-image-donot-use","madhupdevops") and
docker_build("frontend-wanderlust","test-image-donot-use","madhupdevops")) to
compute a unique imageTag (derived from BUILD_NUMBER or GIT_COMMIT/SHA) and pass
that imageTag into the second argument for all docker_build calls (including the
other similar calls later in the file) so the tag is consistent and unique per
build and can be threaded through downstream CD jobs.
Automations/updatebackendnew.sh-10-31 (1)

10-31: ⚠️ Potential issue | 🟠 Major

This replacement logic doesn't match the current .env.docker layout.

alreadyUpdate reads Line 4 (currently ACCESS_COOKIE_MAXAGE=120000), but the condition checks for FRONTEND_URL. The file contains no FRONTEND_URL line at all. This means:

  1. The condition will always be false
  2. The script enters the else block and attempts sed -i -e "s|FRONTEND_URL.*|FRONTEND_URL=..."
  3. Since no FRONTEND_URL exists in the file, sed finds no match and the file remains unchanged
  4. The script exits normally, appearing to succeed while making no changes
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updatebackendnew.sh` around lines 10 - 31, The script currently
reads a fixed line into alreadyUpdate and compares it to FRONTEND_URL but
.env.docker doesn’t have that line, so the check always fails and sed does
nothing; update the logic in updatebackendnew.sh to (1) locate any existing
FRONTEND_URL line using grep or sed (e.g., check for a match with grep -E
'^FRONTEND_URL=') instead of reading line 4 into alreadyUpdate, (2) if a
FRONTEND_URL exists compare its value to the desired
"http://${ipv4_address}:5173" and only run sed -i
's|^FRONTEND_URL.*|FRONTEND_URL="http://${ipv4_address}:5173"|' when different,
and (3) if no FRONTEND_URL line exists append the new FRONTEND_URL line to
file_to_find; reference variables alreadyUpdate, file_to_find, ipv4_address and
the sed replacement while making sure to quote filenames/variables to avoid
globbing.
docker-compose.yml-21-27 (1)

21-27: ⚠️ Potential issue | 🟠 Major

Frontend port mapping is incorrect and service discovery will fail; /api/* requests won't reach the backend.

The frontend Dockerfile exposes port 80 (nginx listens there), but the Compose service maps 5173:5173, which will have no process listening inside the container. The mapping should be 5173:80.

Additionally, frontend/nginx.conf proxies /api/ to http://backend-service, but Compose defines a service named backend. Docker Compose resolves service names for internal DNS, so nginx will fail to reach a non-existent backend-service hostname; it should proxy to http://backend.

Fix both:

  • Change the frontend port mapping from 5173:5173 to 5173:80
  • Change the nginx.conf proxy target from http://backend-service to http://backend
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 21 - 27, Update the frontend service
definition and nginx proxy target: in the docker-compose "frontend" service
change the port mapping from "5173:5173" to "5173:80" so the host 5173 forwards
to the container's nginx port 80, and in frontend/nginx.conf replace the
proxy_pass host "http://backend-service" with "http://backend" so nginx uses the
actual Compose service name "backend" for internal DNS resolution.
Automations/updateFrontend.sh-16-19 (1)

16-19: ⚠️ Potential issue | 🟠 Major

Change exit -1 to exit 0 when file is already current.

The condition at line 19 exits with -1 when the file is already updated, which Bash normalizes to exit code 255. This causes Jenkins to fail the stage even though the file is in the desired state.

Proposed fix
 if [[ "${alreadyUpdate}" == "VITE_API_PATH=\"http://${ipv4_address}:31100\"" ]]
 then
         echo -e "${YELLOW}${file_to_find} file is already updated to the current host's Ipv4 ${NC}"
-	exit -1;
+	exit 0
 else
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updateFrontend.sh` around lines 16 - 19, The script currently
returns a non-zero exit when the file is already up-to-date: find the
conditional that checks alreadyUpdate against VITE_API_PATH using
${ipv4_address} and replace the exit -1 with exit 0 so the branch prints the
message (echo ... ${file_to_find} ...) and exits successfully; ensure no other
surrounding logic relies on a non-zero code in that branch (targets: the
conditional comparing "${alreadyUpdate}" and the exit on that branch).
Automations/updateBackend.sh-16-19 (1)

16-19: ⚠️ Potential issue | 🟠 Major

The "already updated" branch fails the pipeline.

exit -1 returns 255 in Bash, so when the file is already correctly configured, the script exits with failure status. This causes the Jenkins stage to fail even though the desired state is already achieved.

The fix is to use exit 0 instead:

Proposed fix
 if [[ "${alreadyUpdate}" == "FRONTEND_URL=\"http://${ipv4_address}:5173\"" ]]
 then
         echo -e "${YELLOW}${file_to_find} file is already updated to the current host's Ipv4 ${NC}"
-        exit -1;
+        exit 0
 else
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updateBackend.sh` around lines 16 - 19, The branch that detects
the file is already updated (check on variable alreadyUpdate and message using
file_to_find in Automations/updateBackend.sh) exits with exit -1 which yields a
non-zero failure code; change that to exit 0 so the script returns success when
no update is needed, keeping the existing echo and message intact.
Automations/updateBackend.sh-5-26 (1)

5-26: ⚠️ Potential issue | 🟠 Major

This script fails to update the backend env file due to incorrect line-based assumptions.

The script reads Line 4 (ACCESS_COOKIE_MAXAGE=120000) into alreadyUpdate, then checks if it equals a FRONTEND_URL string—a condition that can never pass. More critically, the sed command tries to replace FRONTEND_URL.*, but this key doesn't exist in the file, so the replacement silently fails. The script exits cleanly without making any changes.

To fix this, search for the key by name rather than by line number:

🐛 Proposed fix
 file_to_find="../backend/.env.docker"
-alreadyUpdate=$(sed -n "4p" ../backend/.env.docker)
+alreadyUpdate=$(grep -E '^FRONTEND_URL=' "$file_to_find" || true)
@@
-                sed -i -e "s|FRONTEND_URL.*|FRONTEND_URL=\"http://${ipv4_address}:5173\"|g" ${file_to_find}
+                if grep -q '^FRONTEND_URL=' "$file_to_find"; then
+                        sed -i -e "s|^FRONTEND_URL=.*|FRONTEND_URL=\"http://${ipv4_address}:5173\"|g" "$file_to_find"
+                else
+                        printf 'FRONTEND_URL="http://%s:5173"\n' "$ipv4_address" >> "$file_to_find"
+                fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updateBackend.sh` around lines 5 - 26, The script currently reads
a fixed line into alreadyUpdate and compares it to a FRONTEND_URL value (which
will never match) and also uses sed to replace a key that may not exist; change
the logic to target the key name instead: set/ensure file_to_find points to the
backend env file (e.g., ../backend/.env.docker), extract the current
FRONTEND_URL by grepping or using sed (e.g., current=$(grep -E '^FRONTEND_URL='
"$file_to_find" || true)), compare current to the expected value built from
ipv4_address, and then either use sed -i to replace the FRONTEND_URL line if it
exists (sed -i -e
"s|^FRONTEND_URL=.*|FRONTEND_URL=\"http://${ipv4_address}:5173\"|") or append
the FRONTEND_URL line if grep found nothing; keep the existing variables
ipv4_address, alreadyUpdate only for debugging and ensure all file paths are
quoted (use "$file_to_find") to avoid word-splitting.
GitOps/Jenkinsfile-6-7 (1)

6-7: ⚠️ Potential issue | 🟠 Major

Fail fast on blank or placeholder image tags.

This job currently only logs the tag params, then writes them into the manifests. With empty defaults here and the upstream trigger still passing test-image-donot-use from Jenkinsfile:111-118, the pipeline can commit unusable image references into GitOps state. Reject invalid tags before the sed step.

Proposed fix
     stage('Verify: Docker Image Tags') {
         steps {
             script{
+                def invalid = [
+                    params.FRONTEND_DOCKER_TAG,
+                    params.BACKEND_DOCKER_TAG,
+                ].any { !it?.trim() || it == 'test-image-donot-use' }
+
+                if (invalid) {
+                    error('FRONTEND_DOCKER_TAG and BACKEND_DOCKER_TAG must be real, non-empty image tags')
+                }
+
                 echo "FRONTEND_DOCKER_TAG: ${params.FRONTEND_DOCKER_TAG}"
                 echo "BACKEND_DOCKER_TAG: ${params.BACKEND_DOCKER_TAG}"
             }
         }
     }

Also applies to: 27-33

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GitOps/Jenkinsfile` around lines 6 - 7, Add a fail-fast validation
immediately after the parameters are read to reject empty or placeholder image
tags: check FRONTEND_DOCKER_TAG and BACKEND_DOCKER_TAG (and the other tag params
at lines 27-33) and abort the build with an error if either is blank or equals
known placeholder values like "test-image-donot-use"; do this before the
sed/manifest-write step so invalid values are never committed. Use the existing
parameter names FRONTEND_DOCKER_TAG and BACKEND_DOCKER_TAG and ensure the
validation runs early in the pipeline (prior to the sed step) so the job exits
with a clear error message when tags are invalid.
frontend/src/pages/add-blog.tsx-86-91 (1)

86-91: ⚠️ Potential issue | 🟠 Major

Keep client validation aligned with the create-post API.

backend/controllers/posts-controller.js:8-65 still rejects requests without imageLink, so this form now allows a submit path that can only fail server-side. Either restore the image requirement here or relax the backend contract in the same PR.

Proposed fix
   const validateFormData = () => {
     if (!formData.title) return toast.error('Title is required'), false;
     if (!formData.authorName) return toast.error('Author is required'), false;
+    if (!formData.imageLink) return toast.error('Select an image'), false;
     if (!formData.description) return toast.error('Description is required'), false;
     if (formData.categories.length === 0)
       return toast.error('Select at least 1 category'), false;
 
     return true;
   };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/add-blog.tsx` around lines 86 - 91, The client-side
validateFormData currently omits the image check while
backend/controllers/posts-controller.js still requires imageLink; restore parity
by adding a validation for formData.imageLink in the validateFormData function
(e.g., if (!formData.imageLink) return toast.error('Image is required'), false)
so the form will block submits that the create-post API would reject;
alternatively, if you intend to relax the API contract instead, update the
backend create-post handler (posts-controller.js) to accept missing imageLink
and handle defaults consistently.
frontend/src/pages/add-blog.tsx-173-181 (1)

173-181: ⚠️ Potential issue | 🟠 Major

Use a keyboard-accessible control for category selection.

These category pills are clickable via mouse only. Since Line 90 requires at least one category, keyboard users cannot complete the form.

Proposed fix
           <div className="flex flex-wrap gap-2">
             {categories.map((category, index) => (
-              <span key={index} onClick={() => handleCategoryClick(category)}>
+              <button
+                key={index}
+                type="button"
+                onClick={() => handleCategoryClick(category)}
+                disabled={isValidCategory(category)}
+                aria-pressed={formData.categories.includes(category)}
+              >
                 <CategoryPill
                   category={category}
                   selected={formData.categories.includes(category)}
                   disabled={isValidCategory(category)}
                 />
-              </span>
+              </button>
             ))}
           </div>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/src/pages/add-blog.tsx` around lines 173 - 181, The category pills
rendered in the categories.map block are only mouse-clickable; update the markup
around CategoryPill (the map using categories, index, handleCategoryClick,
formData.categories, and isValidCategory) to be keyboard-accessible by using a
semantic interactive element (e.g., a <button> or an element with role="button")
instead of a plain <span>, ensure it is focusable (tabIndex if needed), wire
onKeyDown to invoke handleCategoryClick on Enter/Space, and add ARIA state
attributes like aria-pressed and aria-disabled tied to selected and disabled so
keyboard and assistive technology users can toggle categories and meet the
required validation.
GitOps/Jenkinsfile-64-71 (1)

64-71: ⚠️ Potential issue | 🟠 Major

Make the git update step idempotent.

If the manifests already contain these tags, git commit exits non-zero with “nothing to commit” and the CD job fails even though the desired state is already applied. git add . is also broader than needed here.

Proposed fix
-                        git add .
-                        
-                        echo "Commiting changes: "
-                        git commit -m "Updated environment variables"
-                        
-                        echo "Pushing changes to github: "
-                        git push https://github.com/DevMadhup/wanderlust.git devops
+                        git add kubernetes/backend.yaml kubernetes/frontend.yaml
+
+                        if git diff --cached --quiet; then
+                            echo "No manifest changes to commit"
+                        else
+                            echo "Commiting changes: "
+                            git commit -m "Updated environment variables"
+
+                            echo "Pushing changes to github: "
+                            git push https://github.com/DevMadhup/wanderlust.git devops
+                        fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GitOps/Jenkinsfile` around lines 64 - 71, Replace the broad, non-idempotent
sequence (git add ., git commit -m "Updated environment variables", git push
...) with a safe flow: stage only the specific manifest files instead of git add
. (replace git add . with git add <manifest paths> or a variable like
"$MANIFEST_PATHS"), then check for staged/working-tree changes using git diff
--quiet --cached or git diff-index --quiet HEAD --; only run git commit -m
"Updated environment variables" if that check indicates changes, and only then
run git push https://github.com/DevMadhup/wanderlust.git devops; otherwise echo
"No changes to commit" and skip commit/push. This keeps the git add ., git
commit, and git push steps idempotent.
🟡 Minor comments (3)
README.md-115-115 (1)

115-115: ⚠️ Potential issue | 🟡 Minor

Avoid instructing users to edit .env.sample directly.

Line 115 should guide users to copy sample env files to runtime env files and edit those, not the template.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` at line 115, The README currently tells users to edit the template
`.env.sample` directly; change the "Update Environment Variables" instruction so
it tells users to copy `.env.sample` to a runtime file (for example `.env` or
`.env.local`) and then edit that copy with the new IP address or other runtime
values; update the sentence to show the copy step (e.g., "cp .env.sample .env")
and then "edit `.env`" rather than instructing users to modify `.env.sample`
itself.
kubernetes/README.md-9-9 (1)

9-9: ⚠️ Potential issue | 🟡 Minor

Use separators instead of empty headings.

These standalone # lines are being parsed as empty headings, which is why markdownlint is reporting duplicate-heading and heading-increment problems throughout the file. Replace them with --- or plain blank lines.

Also applies to: 17-17, 23-23, 30-30, 37-37, 44-44, 63-63, 69-69, 76-76, 83-83, 89-89, 100-100, 107-107, 114-114, 126-126, 132-132, 172-172, 191-191

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/README.md` at line 9, Replace all standalone heading markers
consisting of a single '#' character in the README with proper separators or
blank lines to avoid empty headings; search for the literal token '#' (the lone
hash lines) and change them to '---' or remove them (insert a blank line) so
markdownlint no longer treats them as empty/duplicate headings.
kubernetes/README.md-70-74 (1)

70-74: ⚠️ Potential issue | 🟡 Minor

Step 8 is outdated after the /api routing refactor.

The frontend now calls relative /api/... routes, so editing VITE_API_PATH here is no longer what determines backend reachability in Kubernetes. This step should either be removed or rewritten to describe the ingress/service routing that now carries those requests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/README.md` around lines 70 - 74, Step 8 is outdated because the
frontend now uses relative /api routes controlled by Kubernetes ingress/service
rather than VITE_API_PATH in .env.docker; update the README by removing or
replacing that instruction with a short description of how to expose the backend
via Kubernetes: explain which Kubernetes resources to configure (Ingress and
Service) and which fields to set (Ingress host/path and the Service targetPort
for the backend) so that /api/* is routed correctly, and mention verifying the
cluster's external IP or DNS for the Ingress controller rather than editing
VITE_API_PATH in .env.docker.
🧹 Nitpick comments (4)
frontend/Dockerfile (1)

7-7: Prefer npm ci for deterministic builds.

Line 7 should use npm ci in container builds for lockfile-faithful, reproducible installs.

Proposed fix
-RUN npm install
+RUN npm ci --no-audit --no-fund
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@frontend/Dockerfile` at line 7, Replace the non-deterministic install command
in the Dockerfile's RUN instruction that currently invokes "npm install" with
the lockfile-faithful command "npm ci" so container builds are reproducible;
ensure package-lock.json is copied into the image before that RUN step and keep
the same install flags/environment (e.g., NODE_ENV) as needed for production
builds.
Automations/updatebackendnew.sh (1)

3-7: Avoid hardcoding a single EC2 instance ID here.

This script only works for one specific instance/account combination. Please pass the instance ID in as an argument or environment variable, or fold this into the maintained metadata-based script so there is a single source of truth.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updatebackendnew.sh` around lines 3 - 7, The script currently
hardcodes INSTANCE_ID causing it to only work for one EC2 instance; change
updatebackendnew.sh to accept an instance ID via a positional argument or an
environment variable (e.g., check $1 then $INSTANCE_ID env) and fall back to
metadata-based discovery if neither is provided, then use that resolved
INSTANCE_ID when computing ipv4_address via the aws cli; update references to
INSTANCE_ID and the ipv4_address assignment accordingly so the script is
reusable across accounts/instances.
docker-compose.yml (1)

6-7: data is declared but never mounted.

mongodb is bind-mounting ./backend/data into /data, so the named volume on Lines 38-39 is dead config and Mongo state ends up tied to the working tree. Either remove data or mount it explicitly where Mongo stores its data.

♻️ Proposed cleanup
 services:
   mongodb:
     container_name: mongo
     image: mongo:latest
     volumes:
-      - ./backend/data:/data
+      - data:/data/db
@@
 volumes:
   data:

Also applies to: 38-39

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docker-compose.yml` around lines 6 - 7, The compose file currently
bind-mounts ./backend/data into /data (the service volume entry "-
./backend/data:/data") while also declaring a named volume "data" (dead config);
either remove the unused top-level named volume "data" or switch the service to
use that named volume and mount it at MongoDB's data path (/data/db). Update the
mongodb service's volumes to consistently use one approach: delete the "data:"
declaration if you want a bind mount, or replace "- ./backend/data:/data" with
"- data:/data/db" (and keep the "data" volume) so Mongo's state is stored in the
named volume.
Automations/updateFrontend.sh (1)

11-26: This automation is now disconnected from the frontend runtime.

The frontend code in this PR switched to relative /api/... calls, so rewriting VITE_API_PATH here no longer changes where requests go. Keeping this stage adds an EC2 metadata dependency in Jenkins without affecting app behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Automations/updateFrontend.sh` around lines 11 - 26, The script block that
fetches EC2 metadata and rewrites VITE_API_PATH (uses ipv4_address,
alreadyUpdate, file_to_find, and the sed command) should be removed or skipped
because the frontend now uses relative /api paths and this change no longer
affects runtime; update Automations/updateFrontend.sh to eliminate the metadata
curl and the conditional that tests/sets VITE_API_PATH (or replace it with a
no-op/logging path that explicitly documents it's deprecated) and ensure no
other code references ipv4_address or alreadyUpdate so the script no longer
depends on EC2 metadata during CI.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 56980968-d1f2-435b-9731-7190ee051dcc

📥 Commits

Reviewing files that changed from the base of the PR and between ddb013b and 12f0abc.

⛔ Files ignored due to path filters (20)
  • frontend/package-lock.json is excluded by !**/package-lock.json
  • kubernetes/assets/all-deps.png is excluded by !**/*.png
  • kubernetes/assets/app.png is excluded by !**/*.png
  • kubernetes/assets/backend.env.docker.png is excluded by !**/*.png
  • kubernetes/assets/backend.png is excluded by !**/*.png
  • kubernetes/assets/context wanderlust.png is excluded by !**/*.png
  • kubernetes/assets/docker backend build.png is excluded by !**/*.png
  • kubernetes/assets/docker frontend build.png is excluded by !**/*.png
  • kubernetes/assets/docker images.png is excluded by !**/*.png
  • kubernetes/assets/docker login.png is excluded by !**/*.png
  • kubernetes/assets/edit-coredns.png is excluded by !**/*.png
  • kubernetes/assets/frontend.env.docker.png is excluded by !**/*.png
  • kubernetes/assets/frontend.png is excluded by !**/*.png
  • kubernetes/assets/get-coredns.png is excluded by !**/*.png
  • kubernetes/assets/mongo.png is excluded by !**/*.png
  • kubernetes/assets/namespace create.png is excluded by !**/*.png
  • kubernetes/assets/nodes.png is excluded by !**/*.png
  • kubernetes/assets/pv.png is excluded by !**/*.png
  • kubernetes/assets/pvc.png is excluded by !**/*.png
  • kubernetes/assets/redis.png is excluded by !**/*.png
📒 Files selected for processing (35)
  • Automations/updateBackend.sh
  • Automations/updateFrontend.sh
  • Automations/updatebackendnew.sh
  • Automations/updatefrontendnew.sh
  • GitOps/Jenkinsfile
  • Jenkinsfile
  • README.md
  • backend/.env.docker
  • backend/.env.sample
  • backend/Dockerfile
  • backend/server.js
  • docker-compose.yml
  • frontend/.env.sample
  • frontend/Dockerfile
  • frontend/nginx.conf
  • frontend/package.json
  • frontend/src/components/blog-feed.tsx
  • frontend/src/pages/add-blog.tsx
  • frontend/src/pages/details-page.tsx
  • frontend/src/pages/home-page.tsx
  • frontend/src/types/post-type.ts
  • kubernetes/README.md
  • kubernetes/assets/README.md
  • kubernetes/backend-deploy.yaml
  • kubernetes/backend-hpa.yaml
  • kubernetes/backend-svc.yml
  • kubernetes/frontend-deploy.yaml
  • kubernetes/frontend-svc.yml
  • kubernetes/get_helm.sh
  • kubernetes/ingress.yaml
  • kubernetes/mongo-pvc.yaml
  • kubernetes/mongodb.yaml
  • kubernetes/redis-pvc.yaml
  • kubernetes/redis.yaml
  • kubernetes/sc.yaml

Comment thread backend/.env.docker
ACCESS_TOKEN_EXPIRES_IN='120s'
REFRESH_COOKIE_MAXAGE=120000
REFRESH_TOKEN_EXPIRES_IN='120s'
JWT_SECRET=70dd8b38486eee723ce2505f6db06f1ee503fde5eb06fc04687191a0ed665f3f98776902d2c89f6b993b1c579a87fedaf584c693a106f7cbf16e8b4e67e9d6df
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Remove committed JWT secret and inject it from secrets management.

Line 8 contains a live secret in source control. This is a blocker security issue and should be rotated immediately.

Proposed fix
-JWT_SECRET=70dd8b38486eee723ce2505f6db06f1ee503fde5eb06fc04687191a0ed665f3f98776902d2c89f6b993b1c579a87fedaf584c693a106f7cbf16e8b4e67e9d6df
+JWT_SECRET=${JWT_SECRET}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
JWT_SECRET=70dd8b38486eee723ce2505f6db06f1ee503fde5eb06fc04687191a0ed665f3f98776902d2c89f6b993b1c579a87fedaf584c693a106f7cbf16e8b4e67e9d6df
JWT_SECRET=${JWT_SECRET}
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 8-8: [UnorderedKey] The JWT_SECRET key should go before the MONGODB_URI key

(UnorderedKey)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/.env.docker` at line 8, Remove the hard-coded JWT_SECRET from
backend/.env.docker and replace it with a placeholder (e.g.
JWT_SECRET=<SECRET_FROM_SECRETS>) so no live secrets are committed; rotate the
exposed secret immediately. Update deployment/compose and CI to read the real
secret from your secrets manager or Docker secrets and inject it into the
container at runtime (ensure the secret name used matches the placeholder), and
update any startup/config code that reads JWT_SECRET to accept the injected
secret. Verify no other files commit the same value and add a short note in ops
docs describing how to provision the new secret in the secrets manager.

Comment thread backend/Dockerfile

COPY --from=backend-builder /app .

COPY .env.docker .env
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Do not bake runtime env files into the image.

Copying .env.docker into the image risks leaking sensitive runtime configuration and makes secret rotation difficult. Inject env via Kubernetes Secret/ConfigMap at deploy time instead.

🔧 Suggested change
- COPY .env.docker .env
+ # Do not bake env files into image; inject at runtime via env/envFrom
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/Dockerfile` at line 20, The Dockerfile currently bakes runtime env by
copying `.env.docker` into the image via the COPY instruction (`COPY .env.docker
.env`); remove that COPY and stop embedding runtime secrets in the image,
instead accept environment via build-time ARGs for non-secrets or document using
runtime injection (Kubernetes Secret/ConfigMap or docker run -e) for sensitive
values and ensure `.env.docker` is added to `.dockerignore` to avoid accidental
inclusion.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants