Skip to content

Commit 9960075

Browse files
committed
Enhance development environment and database setup
- Updated Dockerfile to include pgTAP and sqlfluff installation, along with necessary build tools. - Modified devcontainer.json to configure run arguments and post-create commands for database initialization. - Expanded .dockerignore and .gitignore to exclude unnecessary files and directories. - Added SQL connection settings in VS Code settings. - Introduced new tasks in tasks.json for database management and SQL linting. - Updated README.md with production deployment instructions and security guidelines. - Created flatten-sql.sh and rebuild-db.sh scripts for SQL file management and database rebuilding. - Added initial SQL setup script for creating products table and enabling UUID extension.
1 parent a9626e8 commit 9960075

12 files changed

Lines changed: 485 additions & 27 deletions

File tree

.devcontainer/Dockerfile

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,44 @@
1-
FROM alpine:latest
1+
FROM postgres:16.11-alpine3.23
22

3-
# Install common tools
4-
RUN apk add --no-cache bash git
3+
# Install common tools and build tools for pgTAP
4+
RUN apk add --no-cache bash git su-exec tini \
5+
make gcc musl-dev postgresql-dev perl patch \
6+
build-base perl-dev openssl-dev python3 py3-pip sudo \
7+
&& cpan TAP::Parser::SourceHandler::pgTAP
8+
9+
# Clone pgTAP
10+
RUN git clone --depth 1 https://github.com/theory/pgtap
11+
12+
# Build and install pgTAP
13+
WORKDIR /pgtap
14+
RUN make && make install
15+
16+
# Cleanup
17+
WORKDIR /
18+
RUN rm -rf /pgtap
19+
20+
# Install sqlfluff for SQL linting
21+
RUN ["/bin/bash", "-c", "pip3 --disable-pip-version-check --no-cache-dir install sqlfluff --break-system-packages"]
522

623
# Setup default user
724
ARG USERNAME=vscode
825
ARG USER_UID=1000
926
ARG USER_GID=$USER_UID
1027

28+
# Create vscode user and add to postgres group for database access
1129
RUN addgroup -g $USER_GID -S $USERNAME && \
12-
adduser -u $USER_UID -S -G $USERNAME -s /bin/bash $USERNAME
30+
adduser -u $USER_UID -S -G $USERNAME -s /bin/bash $USERNAME && \
31+
adduser $USERNAME postgres && \
32+
echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME && \
33+
chmod 0440 /etc/sudoers.d/$USERNAME && \
34+
mkdir -p /var/lib/postgresql/data /run/postgresql && \
35+
chown -R postgres:postgres /var/lib/postgresql /run/postgresql && \
36+
chmod 755 /run/postgresql
37+
38+
# Set environment variables for PostgreSQL
39+
ENV PGDATA=/var/lib/postgresql/data
40+
41+
WORKDIR /workspace
1342

1443
# Switch to the default user
1544
USER $USERNAME

.devcontainer/devcontainer.json

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,30 @@
11
{
2-
"name": "Template Development Container",
3-
"dockerFile": "Dockerfile",
2+
"name": "ChocoMax Database",
3+
"image": "ghcr.io/themaximousse/database-devcontainer:latest",
4+
"runArgs": [
5+
"--cap-add=CHOWN",
6+
"--cap-add=SETGID",
7+
"--cap-add=SETUID",
8+
"--cap-drop=ALL",
9+
"--security-opt=no-new-privileges:true"
10+
],
411
"customizations": {
512
"settings": {
613
"terminal.integrated.shell.linux": "/bin/bash"
714
},
815
"vscode": {
9-
"extensions": ["esbenp.prettier-vscode"]
16+
"extensions": [
17+
"gruntfuggly.triggertaskonsave",
18+
"mtxr.sqltools",
19+
"mtxr.sqltools-driver-pg"
20+
]
1021
}
1122
},
23+
"otherPortsAttributes": {
24+
"onAutoForward": "ignore"
25+
},
26+
"postCreateCommand": "initdb -D $PGDATA && pg_ctl -D $PGDATA -o '-k /run/postgresql' -l /tmp/pg.log start && createdb chocomax && pg_ctl -D $PGDATA stop",
27+
"postStartCommand": "pg_ctl -D $PGDATA -o '-k /run/postgresql' -l /tmp/pg.log start",
28+
"postAttachCommand": "sqlfluff fix database/ -v",
1229
"remoteUser": "vscode"
1330
}

.dockerignore

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,14 @@ LICENSE
1010
# Version control
1111
.git
1212
.gitignore
13+
.github/
14+
.gitattributes
15+
16+
# Development container
17+
.devcontainer/
18+
19+
# Test files
20+
database/tests/
21+
22+
# Scripts not needed in production
23+
scripts/

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# Database session files
2+
*.session.sql
3+
14
# Environments
25
.env
36

.sqlfluff

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[sqlfluff]
2+
dialect = postgres
3+
max_line_length = 200
4+
5+
[sqlfluff:layout:type:comment]
6+
spacing_before = single
7+
spacing_after = single

.vscode/settings.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,23 @@
77
"files.trimTrailingWhitespace": true,
88
"[yaml]": {
99
"editor.tabSize": 2
10+
},
11+
"sqltools.connections": [
12+
{
13+
"name": "ChocoMax",
14+
"server": "localhost",
15+
"driver": "PostgreSQL",
16+
"port": 5432,
17+
"database": "chocomax",
18+
"username": "vscode",
19+
"askForPassword": false,
20+
"password": "postgres"
21+
}
22+
],
23+
"sqltools.useNodeRuntime": false,
24+
"triggerTaskOnSave.tasks": {
25+
"Lint SQL File": [
26+
"database/**/*.sql"
27+
]
1028
}
1129
}

.vscode/tasks.json

Lines changed: 182 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,187 @@
1717
"runOptions": {
1818
"runOn": "folderOpen"
1919
}
20+
},
21+
{
22+
"label": "Start Database",
23+
"type": "shell",
24+
"command": "[ -S /run/postgresql/.s.PGSQL.5432 ] || pg_ctl -D $PGDATA -o '-k /run/postgresql' -l /tmp/pg.log start",
25+
"problemMatcher": [],
26+
"isBackground": false,
27+
"presentation": {
28+
"echo": true,
29+
"reveal": "always",
30+
"focus": false,
31+
"panel": "shared"
32+
}
33+
},
34+
{
35+
"label": "Flatten SQL Files",
36+
"type": "shell",
37+
"command": "./scripts/flatten-sql.sh",
38+
"dependsOn": [
39+
"Start Database"
40+
],
41+
"options": {
42+
"cwd": "${workspaceFolder}"
43+
},
44+
"problemMatcher": []
45+
},
46+
{
47+
"label": "Rebuild Database",
48+
"type": "shell",
49+
"command": "./scripts/rebuild-db.sh",
50+
"args": [
51+
"${input:db_username}",
52+
"${input:db_name}"
53+
],
54+
"dependsOn": [
55+
"Flatten SQL Files"
56+
],
57+
"options": {
58+
"cwd": "${workspaceFolder}"
59+
},
60+
"problemMatcher": [],
61+
"group": {
62+
"kind": "build",
63+
"isDefault": false
64+
}
65+
},
66+
{
67+
"label": "Stop Database",
68+
"type": "shell",
69+
"command": "pg_ctl -D $PGDATA stop || true",
70+
"problemMatcher": []
71+
},
72+
{
73+
"label": "Connect to Database",
74+
"type": "shell",
75+
"command": "psql -h /run/postgresql -U ${input:db_username} -d ${input:db_name}",
76+
"problemMatcher": [],
77+
"presentation": {
78+
"close": true
79+
}
80+
},
81+
{
82+
"label": "Full Database Rebuild",
83+
"dependsOn": [
84+
"Start Database",
85+
"Flatten SQL Files",
86+
"Rebuild Database"
87+
],
88+
"dependsOrder": "sequence",
89+
"problemMatcher": [],
90+
"group": {
91+
"kind": "build",
92+
"isDefault": true
93+
}
94+
},
95+
{
96+
"label": "Run Unit Tests",
97+
"type": "shell",
98+
"command": "pg_prove -Q -d ${input:db_name} -U ${input:db_username} database/tests/*.test.sql",
99+
"dependsOn": [
100+
"Full Database Rebuild"
101+
],
102+
"problemMatcher": [],
103+
"group": {
104+
"kind": "test",
105+
"isDefault": true
106+
}
107+
},
108+
{
109+
"label": "Lint SQL File",
110+
"type": "shell",
111+
"command": "sqlfluff fix '${file}' -v",
112+
"problemMatcher": [],
113+
"group": {
114+
"kind": "none",
115+
"isDefault": true
116+
},
117+
"presentation": {
118+
"close": true
119+
}
120+
},
121+
{
122+
"label": "Build Docker Image",
123+
"type": "shell",
124+
"command": "docker build -t ${input:docker_image_name} .",
125+
"group": {
126+
"kind": "build",
127+
"isDefault": false
128+
},
129+
"presentation": {
130+
"panel": "shared",
131+
"close": true
132+
},
133+
"problemMatcher": []
134+
},
135+
{
136+
"label": "Run Docker Container",
137+
"type": "shell",
138+
"command": "docker run -d -p 5432:5432 --name ${input:docker_container_name} --env-file .env --security-opt no-new-privileges:true --cap-drop=ALL --cap-add=NET_BIND_SERVICE ${input:docker_image_name}",
139+
"presentation": {
140+
"panel": "shared",
141+
"close": true
142+
},
143+
"problemMatcher": []
144+
},
145+
{
146+
"label": "Remove Docker Container",
147+
"type": "shell",
148+
"command": "docker stop ${input:docker_container_name} ; docker rm ${input:docker_container_name}",
149+
"presentation": {
150+
"panel": "shared",
151+
"close": true
152+
},
153+
"problemMatcher": []
154+
},
155+
{
156+
"label": "Reset Docker Container",
157+
"type": "shell",
158+
"dependsOn": [
159+
"Remove Docker Container",
160+
"Build Docker Image",
161+
"Run Docker Container"
162+
],
163+
"presentation": {
164+
"panel": "shared",
165+
"close": true
166+
},
167+
"dependsOrder": "sequence",
168+
"problemMatcher": []
169+
}
170+
],
171+
"inputs": [
172+
{
173+
"id": "db_username",
174+
"type": "promptString",
175+
"description": "Enter the database username",
176+
"default": "vscode"
177+
},
178+
{
179+
"id": "db_name",
180+
"type": "promptString",
181+
"description": "Enter the database name",
182+
"default": "chocomax"
183+
},
184+
{
185+
"id": "docker_image_name",
186+
"type": "promptString",
187+
"description": "Enter the Docker image name",
188+
"default": "chocomax-database-image"
189+
},
190+
{
191+
"id": "docker_container_name",
192+
"type": "promptString",
193+
"description": "Enter the Docker container name",
194+
"default": "chocomax-database-container"
20195
}
21-
]
196+
],
197+
"options": {
198+
"env": {
199+
"FLATTEN_SQL_DIR": "${workspaceFolder}/.tmp/flattened-sql"
200+
},
201+
"cwd": "${workspaceFolder}"
202+
}
22203
}

Dockerfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
FROM postgres:16.11-alpine3.23
2+
3+
# Remove unnecessary packages and clean up to minimize attack surface
4+
RUN rm -rf /var/cache/apk/*
5+
6+
# Create necessary directories with proper permissions
7+
RUN mkdir -p /var/lib/postgresql/data /run/postgresql \
8+
&& chown -R postgres:postgres /var/lib/postgresql /run/postgresql \
9+
&& chmod 700 /var/lib/postgresql/data \
10+
&& chmod 755 /run/postgresql
11+
12+
# Copy database files
13+
COPY --chown=postgres:postgres database/ /docker-entrypoint-initdb.d/
14+
15+
# Set environment variables
16+
ENV PGDATA=/var/lib/postgresql/data
17+
18+
# Security hardening
19+
# Drop all capabilities and add only what's needed
20+
# Run as non-root postgres user
21+
# Disable privilege escalation
22+
USER postgres
23+
24+
# Health check
25+
HEALTHCHECK --interval=30s --timeout=5s --start-period=30s --retries=3 \
26+
CMD pg_isready -U postgres || exit 1
27+
28+
# Expose PostgreSQL port
29+
EXPOSE 5432
30+
31+
# Use default postgres entrypoint (handles signals properly)
32+
CMD ["postgres"]

0 commit comments

Comments
 (0)