Skip to content

Commit 1ff2e5a

Browse files
authored
Merge pull request #2 from ExhibitFlow/dev-update
Dev update
2 parents c088d03 + 8814a51 commit 1ff2e5a

7 files changed

Lines changed: 326 additions & 151 deletions

File tree

.github/workflows/ci-cd.yml

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
name: Reservation Service CI/CD
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
env:
11+
JAVA_VERSION: '17'
12+
MAVEN_CLI_OPTS: '-B --no-transfer-progress'
13+
DOCKER_IMAGE_NAME: reservation-service
14+
REGISTRY: docker.io
15+
16+
jobs:
17+
# Job 1: Code Quality & Security
18+
code-quality:
19+
name: Code Quality & Security Checks
20+
runs-on: ubuntu-latest
21+
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
with:
26+
fetch-depth: 0 # Shallow clones should be disabled for better analysis
27+
28+
- name: Set up JDK ${{ env.JAVA_VERSION }}
29+
uses: actions/setup-java@v4
30+
with:
31+
java-version: ${{ env.JAVA_VERSION }}
32+
distribution: 'temurin'
33+
cache: 'maven'
34+
35+
- name: Cache SonarCloud packages
36+
uses: actions/cache@v3
37+
with:
38+
path: ~/.sonar/cache
39+
key: ${{ runner.os }}-sonar
40+
restore-keys: ${{ runner.os }}-sonar
41+
42+
- name: Run code style checks
43+
run: mvn ${{ env.MAVEN_CLI_OPTS }} checkstyle:check
44+
continue-on-error: true
45+
46+
- name: Run SpotBugs analysis
47+
run: mvn ${{ env.MAVEN_CLI_OPTS }} compile spotbugs:check
48+
continue-on-error: true
49+
50+
# Job 2: Build
51+
build:
52+
name: Build
53+
runs-on: ubuntu-latest
54+
needs: code-quality
55+
56+
steps:
57+
- name: Checkout code
58+
uses: actions/checkout@v4
59+
60+
- name: Set up JDK ${{ env.JAVA_VERSION }}
61+
uses: actions/setup-java@v4
62+
with:
63+
java-version: ${{ env.JAVA_VERSION }}
64+
distribution: 'temurin'
65+
cache: 'maven'
66+
67+
- name: Build with Maven
68+
run: mvn ${{ env.MAVEN_CLI_OPTS }} clean compile
69+
70+
- name: Package application
71+
run: mvn ${{ env.MAVEN_CLI_OPTS }} package -DskipTests
72+
73+
- name: Upload build artifact
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: reservation-service-jar
77+
path: target/*.jar
78+
retention-days: 5
79+
80+
# Job 3: Docker Build & Push
81+
docker-build-push:
82+
name: Build & Push Docker Image
83+
runs-on: ubuntu-latest
84+
needs: build
85+
if: github.event_name == 'push'
86+
permissions:
87+
contents: read
88+
packages: write
89+
90+
steps:
91+
- name: Checkout code
92+
uses: actions/checkout@v4
93+
94+
- name: Set up Docker Buildx
95+
uses: docker/setup-buildx-action@v3
96+
97+
- name: Log in to Docker Hub
98+
uses: docker/login-action@v3
99+
with:
100+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
101+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
102+
103+
- name: Extract metadata for Docker
104+
id: meta
105+
uses: docker/metadata-action@v5
106+
with:
107+
images: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}
108+
tags: |
109+
type=ref,event=branch
110+
type=ref,event=pr
111+
type=sha,prefix={{branch}}-
112+
type=semver,pattern={{version}}
113+
type=semver,pattern={{major}}.{{minor}}
114+
type=raw,value=latest,enable={{is_default_branch}}
115+
116+
- name: Build and push Docker image
117+
uses: docker/build-push-action@v5
118+
with:
119+
context: .
120+
file: ./Dockerfile
121+
push: true
122+
tags: ${{ steps.meta.outputs.tags }}
123+
labels: ${{ steps.meta.outputs.labels }}
124+
cache-from: type=gha
125+
cache-to: type=gha,mode=max
126+
platforms: linux/amd64,linux/arm64
127+
128+
- name: Generate SBOM
129+
uses: anchore/sbom-action@v0
130+
with:
131+
image: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ github.sha }}
132+
format: spdx-json
133+
output-file: sbom.spdx.json
134+
135+
- name: Upload SBOM
136+
uses: actions/upload-artifact@v4
137+
with:
138+
name: sbom
139+
path: sbom.spdx.json
140+
141+
# Job 4: Security Scan
142+
security-scan:
143+
name: Security Vulnerability Scan
144+
runs-on: ubuntu-latest
145+
needs: docker-build-push
146+
if: github.event_name == 'push'
147+
permissions:
148+
contents: read
149+
security-events: write
150+
151+
steps:
152+
- name: Checkout code
153+
uses: actions/checkout@v4
154+
155+
- name: Log in to Docker Hub
156+
uses: docker/login-action@v3
157+
with:
158+
username: ${{ secrets.DOCKER_HUB_USERNAME }}
159+
password: ${{ secrets.DOCKER_HUB_TOKEN }}
160+
161+
- name: Run Trivy vulnerability scanner
162+
uses: aquasecurity/trivy-action@master
163+
with:
164+
image-ref: ${{ secrets.DOCKER_HUB_USERNAME }}/${{ env.DOCKER_IMAGE_NAME }}:${{ github.sha }}
165+
format: 'sarif'
166+
output: 'trivy-results.sarif'
167+
severity: 'CRITICAL,HIGH'
168+
169+
- name: Upload Trivy results to GitHub Security
170+
uses: github/codeql-action/upload-sarif@v3
171+
if: always()
172+
with:
173+
sarif_file: 'trivy-results.sarif'
174+
175+
- name: Dependency Check
176+
uses: dependency-check/Dependency-Check_Action@main
177+
with:
178+
project: 'reservation-service'
179+
path: '.'
180+
format: 'HTML'
181+
args: >
182+
--failOnCVSS 7
183+
--enableRetired
184+
185+
- name: Upload Dependency Check report
186+
uses: actions/upload-artifact@v4
187+
if: always()
188+
with:
189+
name: dependency-check-report
190+
path: reports/
191+
192+
# Job 5: Deploy to Development
193+
deploy-dev:
194+
name: Deploy to Development
195+
runs-on: ubuntu-latest
196+
needs: [docker-build-push, security-scan]
197+
if: github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/dev-update'
198+
environment:
199+
name: development
200+
url: https://dev-reservation-service.exhibitflow.com
201+
202+
steps:
203+
- name: Checkout code
204+
uses: actions/checkout@v4
205+
206+
- name: Deploy to Development Server
207+
uses: appleboy/ssh-action@v1.0.0
208+
with:
209+
host: ${{ secrets.DEV_SERVER_HOST }}
210+
username: ${{ secrets.DEV_SERVER_USER }}
211+
key: ${{ secrets.DEV_SERVER_SSH_KEY }}
212+
port: ${{ secrets.DEV_SERVER_PORT }}
213+
script: |
214+
cd /opt/reservation-service
215+
docker compose pull
216+
docker compose up -d
217+
docker system prune -f
218+
219+
- name: Verify deployment
220+
run: |
221+
sleep 10
222+
curl -f ${{ secrets.DEV_SERVER_URL }}/actuator/health || exit 1

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ USER spring:spring
3030
COPY --from=build /app/target/reservation-service-*.jar app.jar
3131

3232
# Expose the application port
33-
EXPOSE 8080
33+
EXPOSE 8084
3434

3535
# Set JVM options for containerized environment
3636
ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0 -XX:+UseG1GC"
3737

3838
# Health check
3939
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
40-
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1
40+
CMD wget --no-verbose --tries=1 --spider http://localhost:8084/actuator/health || exit 1
4141

4242
# Run the application
4343
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]

database/setup.sql

Lines changed: 1 addition & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ CREATE TABLE reservations (
2121
stall_id BIGINT NOT NULL,
2222
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
2323
qr_code_base64 TEXT,
24-
status VARCHAR(50) NOT NULL DEFAULT 'CONFIRMED',
2524
payment_expires_at TIMESTAMP NULL,
2625
payment_completed_at TIMESTAMP NULL,
26+
status VARCHAR(50) NOT NULL DEFAULT 'PENDING_PAYMENT',
2727

2828
-- Constraint to ensure status is valid
2929
CONSTRAINT chk_status CHECK (status IN ('PENDING_PAYMENT', 'CONFIRMED', 'CANCELLED', 'EXPIRED'))
@@ -51,94 +51,3 @@ CREATE INDEX idx_status_stall ON reservations(status, stall_id);
5151

5252
-- Show initial record count
5353
SELECT COUNT(*) as total_reservations FROM reservations;
54-
-- Example: Creating a 10x10 grid of stalls
55-
-- Each stall is approximately 5m x 5m
56-
-- Coordinates are in WGS 84 (SRID 4326) - latitude/longitude format
57-
58-
-- Zone A - Ground Floor (Stalls A1-A10)
59-
INSERT INTO stalls (stall_code, size, price, is_reserved, location, boundary, zone, floor_number, description) VALUES
60-
('A1', 'Small', 500.00, FALSE,
61-
ST_SetSRID(ST_MakePoint(-0.001000, 0.000000), 4326),
62-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.001025 -0.000025, -0.000975 -0.000025, -0.000975 0.000025, -0.001025 0.000025, -0.001025 -0.000025)')), 4326),
63-
'Zone A', 1, 'Corner stall with good visibility'),
64-
('A2', 'Small', 500.00, FALSE,
65-
ST_SetSRID(ST_MakePoint(-0.000900, 0.000000), 4326),
66-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000925 -0.000025, -0.000875 -0.000025, -0.000875 0.000025, -0.000925 0.000025, -0.000925 -0.000025)')), 4326),
67-
'Zone A', 1, 'Central location'),
68-
('A3', 'Medium', 750.00, FALSE,
69-
ST_SetSRID(ST_MakePoint(-0.000800, 0.000000), 4326),
70-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000825 -0.000040, -0.000775 -0.000040, -0.000775 0.000040, -0.000825 0.000040, -0.000825 -0.000040)')), 4326),
71-
'Zone A', 1, 'Medium sized stall'),
72-
('A4', 'Small', 500.00, TRUE,
73-
ST_SetSRID(ST_MakePoint(-0.000700, 0.000000), 4326),
74-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000725 -0.000025, -0.000675 -0.000025, -0.000675 0.000025, -0.000725 0.000025, -0.000725 -0.000025)')), 4326),
75-
'Zone A', 1, 'Already reserved'),
76-
('A5', 'Large', 1000.00, FALSE,
77-
ST_SetSRID(ST_MakePoint(-0.000600, 0.000000), 4326),
78-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000625 -0.000050, -0.000575 -0.000050, -0.000575 0.000050, -0.000625 0.000050, -0.000625 -0.000050)')), 4326),
79-
'Zone A', 1, 'Large premium stall');
80-
81-
-- Zone B - Ground Floor (Stalls B1-B5)
82-
INSERT INTO stalls (stall_code, size, price, is_reserved, location, boundary, zone, floor_number, description) VALUES
83-
('B1', 'Small', 500.00, FALSE,
84-
ST_SetSRID(ST_MakePoint(-0.001000, 0.000100), 4326),
85-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.001025 0.000075, -0.000975 0.000075, -0.000975 0.000125, -0.001025 0.000125, -0.001025 0.000075)')), 4326),
86-
'Zone B', 1, 'North side location'),
87-
('B2', 'Medium', 750.00, TRUE,
88-
ST_SetSRID(ST_MakePoint(-0.000900, 0.000100), 4326),
89-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000925 0.000060, -0.000875 0.000060, -0.000875 0.000140, -0.000925 0.000140, -0.000925 0.000060)')), 4326),
90-
'Zone B', 1, 'Already reserved'),
91-
('B3', 'Small', 500.00, FALSE,
92-
ST_SetSRID(ST_MakePoint(-0.000800, 0.000100), 4326),
93-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000825 0.000075, -0.000775 0.000075, -0.000775 0.000125, -0.000825 0.000125, -0.000825 0.000075)')), 4326),
94-
'Zone B', 1, 'Available stall'),
95-
('B4', 'Large', 1000.00, FALSE,
96-
ST_SetSRID(ST_MakePoint(-0.000700, 0.000100), 4326),
97-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000725 0.000050, -0.000675 0.000050, -0.000675 0.000150, -0.000725 0.000150, -0.000725 0.000050)')), 4326),
98-
'Zone B', 1, 'Large corner stall'),
99-
('B5', 'Medium', 750.00, FALSE,
100-
ST_SetSRID(ST_MakePoint(-0.000600, 0.000100), 4326),
101-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000625 0.000060, -0.000575 0.000060, -0.000575 0.000140, -0.000625 0.000140, -0.000625 0.000060)')), 4326),
102-
'Zone B', 1, 'Good traffic flow');
103-
104-
-- Zone C - First Floor (Stalls C1-C5)
105-
INSERT INTO stalls (stall_code, size, price, is_reserved, location, boundary, zone, floor_number, description) VALUES
106-
('C1', 'Small', 450.00, FALSE,
107-
ST_SetSRID(ST_MakePoint(-0.001000, -0.000100), 4326),
108-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.001025 -0.000125, -0.000975 -0.000125, -0.000975 -0.000075, -0.001025 -0.000075, -0.001025 -0.000125)')), 4326),
109-
'Zone C', 2, 'First floor economy'),
110-
('C2', 'Small', 450.00, FALSE,
111-
ST_SetSRID(ST_MakePoint(-0.000900, -0.000100), 4326),
112-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000925 -0.000125, -0.000875 -0.000125, -0.000875 -0.000075, -0.000925 -0.000075, -0.000925 -0.000125)')), 4326),
113-
'Zone C', 2, 'Available'),
114-
('C3', 'Medium', 700.00, TRUE,
115-
ST_SetSRID(ST_MakePoint(-0.000800, -0.000100), 4326),
116-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000825 -0.000140, -0.000775 -0.000140, -0.000775 -0.000060, -0.000825 -0.000060, -0.000825 -0.000140)')), 4326),
117-
'Zone C', 2, 'Already reserved'),
118-
('C4', 'Small', 450.00, FALSE,
119-
ST_SetSRID(ST_MakePoint(-0.000700, -0.000100), 4326),
120-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000725 -0.000125, -0.000675 -0.000125, -0.000675 -0.000075, -0.000725 -0.000075, -0.000725 -0.000125)')), 4326),
121-
'Zone C', 2, 'Quiet area'),
122-
('C5', 'Large', 900.00, FALSE,
123-
ST_SetSRID(ST_MakePoint(-0.000600, -0.000100), 4326),
124-
ST_SetSRID(ST_MakePolygon(ST_GeomFromText('LINESTRING(-0.000625 -0.000150, -0.000575 -0.000150, -0.000575 -0.000050, -0.000625 -0.000050, -0.000625 -0.000150)')), 4326),
125-
'Zone C', 2, 'Premium first floor location');
126-
127-
'Zone C', 2, 'Premium first floor location');
128-
129-
-- Create a user for the application (optional - update credentials as needed)
130-
-- CREATE USER reservation_user WITH PASSWORD 'your_password';
131-
-- GRANT ALL PRIVILEGES ON DATABASE reservation_db TO reservation_user;
132-
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO reservation_user;
133-
-- GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO reservation_user;
134-
135-
-- Display table structures
136-
\d+ stalls;
137-
\d+ reservations;
138-
139-
-- Show initial record counts
140-
SELECT COUNT(*) as total_stalls FROM stalls;
141-
SELECT COUNT(*) as total_reservations FROM reservations;
142-
143-
-- Show spatial reference system info
144-
SELECT * FROM spatial_ref_sys WHERE srid = 4326;

0 commit comments

Comments
 (0)