Skip to content

Commit 9596274

Browse files
authored
Merge pull request #71 from corva-ai/feat/keyfile-support
feat: proper support for `keyFile`, `replicaSet` + auth and more
2 parents 315db7f + f1fa9b8 commit 9596274

File tree

6 files changed

+168
-24
lines changed

6 files changed

+168
-24
lines changed

Dockerfile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
FROM docker:latest
22
COPY start-mongodb.sh /start-mongodb.sh
3-
RUN chmod +x /start-mongodb.sh
3+
COPY stop-mongodb.sh /stop-mongodb.sh
4+
RUN chmod +x /start-mongodb.sh /stop-mongodb.sh
45
ENTRYPOINT ["/start-mongodb.sh"]
56

action-types.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,13 @@ inputs:
1616
type: string
1717
mongodb-container-name:
1818
type: string
19+
mongodb-key:
20+
type: string
21+
mongodb-authsource:
22+
type: string
23+
mongodb-replica-set-host:
24+
type: string
25+
docker-network:
26+
type: string
27+
docker-network-alias:
28+
type: string

action.yml

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ inputs:
1212
default: 'mongo'
1313

1414
mongodb-version:
15-
description: 'MongoDB version to use (default "latest")'
15+
description: 'MongoDB version to use (default: "latest")'
1616
required: false
1717
default: 'latest'
1818

@@ -22,7 +22,7 @@ inputs:
2222
default: ''
2323

2424
mongodb-port:
25-
description: 'MongoDB port to use (default 27017)'
25+
description: 'MongoDB port to use (default: 27017)'
2626
required: false
2727
default: 27017
2828

@@ -46,6 +46,31 @@ inputs:
4646
required: false
4747
default: 'mongodb'
4848

49+
mongodb-key:
50+
description: 'MongoDB key, required if replica set and auth are setup through username and password (no key set by default)'
51+
required: false
52+
default: ''
53+
54+
mongodb-authsource:
55+
description: 'MongoDB authenticationDatabase a.k.a authSource to use (default: "admin" based on https://github.com/docker-library/mongo/blob/master/8.0/docker-entrypoint.sh#L372C4-L372C20)'
56+
required: false
57+
default: 'admin'
58+
59+
mongodb-replica-set-host:
60+
description: 'MongoDB replica set host, must be accessible from both internal container and external usage (default: "localhost")'
61+
required: false
62+
default: 'localhost'
63+
64+
docker-network:
65+
description: 'Docker network to attach the MongoDB container to. If not provided, will try to use the default GitHub Actions network if available (github_network_<rand>).'
66+
required: false
67+
default: ''
68+
69+
docker-network-alias:
70+
description: 'Network alias for the MongoDB container when attaching to a Docker network. If not provided, will use mongodb-container-name input'
71+
required: false
72+
default: ''
73+
4974
runs:
5075
using: 'docker'
5176
image: 'Dockerfile'
@@ -58,3 +83,9 @@ runs:
5883
- ${{ inputs.mongodb-username }}
5984
- ${{ inputs.mongodb-password }}
6085
- ${{ inputs.mongodb-container-name }}
86+
- ${{ inputs.mongodb-key }}
87+
- ${{ inputs.mongodb-authsource }}
88+
- ${{ inputs.mongodb-replica-set-host }}
89+
- ${{ inputs.docker-network }}
90+
- ${{ inputs.docker-network-alias }}
91+
post-entrypoint: /stop-mongodb.sh

start-mongodb.sh

100644100755
Lines changed: 89 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,33 @@ MONGODB_DB=$5
99
MONGODB_USERNAME=$6
1010
MONGODB_PASSWORD=$7
1111
MONGODB_CONTAINER_NAME=$8
12+
MONGODB_KEY=$9
13+
MONGODB_AUTHSOURCE=${10}
14+
MONGODB_REPLICA_SET_HOST=${11:-"localhost"}
15+
DOCKER_NETWORK=${12}
16+
DOCKER_NETWORK_ALIAS=${13:-$MONGODB_CONTAINER_NAME}
17+
18+
# If DOCKER_NETWORK not provided, try to detect the default GitHub Actions network
19+
if [ -z "$DOCKER_NETWORK" ]; then
20+
DOCKER_NETWORK=$(docker network ls --no-trunc --format '{{.Name}}' | grep '^github_network')
21+
fi
22+
23+
# Build network args if a network is set
24+
NETWORK_ARGS=""
25+
if [ -n "$DOCKER_NETWORK" ]; then
26+
NETWORK_ARGS="--network $DOCKER_NETWORK --network-alias $DOCKER_NETWORK_ALIAS"
27+
fi
28+
29+
# Echo selected network info for visibility
30+
echo "::group::Selecting Docker network"
31+
if [ -n "$DOCKER_NETWORK" ]; then
32+
echo " - Docker network: [$DOCKER_NETWORK]"
33+
echo " - Network alias: [$DOCKER_NETWORK_ALIAS]"
34+
else
35+
echo " - No Docker network provided; container will use default Docker network."
36+
fi
37+
echo ""
38+
echo "::endgroup::"
1239

1340
# `mongosh` is used starting from MongoDB 5.x
1441
MONGODB_CLIENT="mongosh --quiet"
@@ -47,16 +74,8 @@ wait_for_mongodb () {
4774
TIMER=0
4875

4976
MONGODB_ARGS=""
50-
51-
if [ -z "$MONGODB_REPLICA_SET" ]
52-
then
53-
if [ -z "$MONGODB_USERNAME" ]
54-
then
55-
MONGODB_ARGS=""
56-
else
57-
# no replica set, but username given: use them as args
58-
MONGODB_ARGS="--username $MONGODB_USERNAME --password $MONGODB_PASSWORD"
59-
fi
77+
if [ -n "$MONGODB_USERNAME" ]; then
78+
MONGODB_ARGS="--username $MONGODB_USERNAME --password $MONGODB_PASSWORD --authenticationDatabase $MONGODB_AUTHSOURCE"
6079
fi
6180

6281
# until ${WAIT_FOR_MONGODB_COMMAND}
@@ -66,7 +85,7 @@ wait_for_mongodb () {
6685
sleep 1
6786
TIMER=$((TIMER + 1))
6887

69-
if [[ $TIMER -eq 20 ]]; then
88+
if [ "$TIMER" -eq 20 ]; then
7089
echo "MongoDB did not initialize within 20 seconds. Exiting."
7190
exit 2
7291
fi
@@ -82,7 +101,7 @@ wait_for_mongodb () {
82101
# docker rm -f $MONGODB_CONTAINER_NAME
83102
# fi
84103

85-
104+
# If no replica set specified, run single node
86105
if [ -z "$MONGODB_REPLICA_SET" ]; then
87106
echo "::group::Starting single-node instance, no replica set"
88107
echo " - port [$MONGODB_PORT]"
@@ -92,7 +111,13 @@ if [ -z "$MONGODB_REPLICA_SET" ]; then
92111
echo " - container-name [$MONGODB_CONTAINER_NAME]"
93112
echo ""
94113

95-
docker run --name $MONGODB_CONTAINER_NAME --publish $MONGODB_PORT:$MONGODB_PORT -e MONGO_INITDB_DATABASE=$MONGODB_DB -e MONGO_INITDB_ROOT_USERNAME=$MONGODB_USERNAME -e MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD --detach $MONGODB_IMAGE:$MONGODB_VERSION --port $MONGODB_PORT
114+
docker run --name $MONGODB_CONTAINER_NAME \
115+
$NETWORK_ARGS \
116+
--publish $MONGODB_PORT:$MONGODB_PORT \
117+
-e MONGO_INITDB_DATABASE=$MONGODB_DB \
118+
-e MONGO_INITDB_ROOT_USERNAME=$MONGODB_USERNAME \
119+
-e MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD \
120+
--detach $MONGODB_IMAGE:$MONGODB_VERSION --port $MONGODB_PORT
96121

97122
if [ $? -ne 0 ]; then
98123
echo "Error starting MongoDB Docker container"
@@ -101,36 +126,81 @@ if [ -z "$MONGODB_REPLICA_SET" ]; then
101126
echo "::endgroup::"
102127

103128
wait_for_mongodb
104-
105129
exit 0
106130
fi
107131

108-
109132
echo "::group::Starting MongoDB as single-node replica set"
110133
echo " - port [$MONGODB_PORT]"
111134
echo " - version [$MONGODB_VERSION]"
112135
echo " - replica set [$MONGODB_REPLICA_SET]"
136+
if [ -n "$MONGODB_KEY" ]; then
137+
echo " - keyFile provided: yes"
138+
else
139+
echo " - keyFile provided: no (random)"
140+
fi
113141
echo ""
114142

143+
# For replica set mode:
144+
# If auth (username/password) is requested, ensure mongodb-key is provided, otherwise generate random
145+
if { [ -n "$MONGODB_USERNAME" ] || [ -n "$MONGODB_PASSWORD" ]; } && [ -z "$MONGODB_KEY" ]; then
146+
MONGODB_KEY=$(dd if=/dev/urandom bs=256 count=1 2>/dev/null | base64 | tr -d '\n')
147+
fi
148+
149+
MONGODB_CMD_ARGS="--port \"$MONGODB_PORT\""
115150

116-
docker run --name $MONGODB_CONTAINER_NAME --publish $MONGODB_PORT:$MONGODB_PORT --detach $MONGODB_IMAGE:$MONGODB_VERSION --port $MONGODB_PORT --replSet $MONGODB_REPLICA_SET
151+
if [ -n "$MONGODB_REPLICA_SET" ]; then
152+
MONGODB_CMD_ARGS="$MONGODB_CMD_ARGS --replSet \"$MONGODB_REPLICA_SET\""
153+
fi
154+
155+
if [ -n "$MONGODB_KEY" ]; then
156+
# NOTE: MONGO_KEY_FILE is interpolated internally
157+
MONGODB_CMD_ARGS="$MONGODB_CMD_ARGS --keyFile \"\$MONGO_KEY_FILE\""
158+
fi
159+
160+
161+
# Start mongod in replica set mode, with optional auth and keyFile
162+
# MONGO_INITDB_* envs will create the root user on first startup
163+
164+
docker run --name $MONGODB_CONTAINER_NAME \
165+
$NETWORK_ARGS \
166+
--publish $MONGODB_PORT:$MONGODB_PORT \
167+
-e MONGO_INITDB_DATABASE=$MONGODB_DB \
168+
-e MONGO_INITDB_ROOT_USERNAME=$MONGODB_USERNAME \
169+
-e MONGO_INITDB_ROOT_PASSWORD=$MONGODB_PASSWORD \
170+
-e MONGO_KEY=$MONGODB_KEY \
171+
-e MONGO_KEY_FILE=/tmp/mongo-keyfile \
172+
--detach \
173+
--entrypoint bash \
174+
$MONGODB_IMAGE:$MONGODB_VERSION \
175+
-c '\
176+
echo "$MONGO_KEY" > "$MONGO_KEY_FILE" && chmod 400 "$MONGO_KEY_FILE" && chown mongodb:mongodb "$MONGO_KEY_FILE" && \
177+
exec docker-entrypoint.sh mongod '"$MONGODB_CMD_ARGS"' \
178+
'
117179

118180
if [ $? -ne 0 ]; then
119181
echo "Error starting MongoDB Docker container"
120182
exit 2
121183
fi
184+
122185
echo "::endgroup::"
123186

124187
wait_for_mongodb
125188

189+
# After mongod is up, initiate the replica set
190+
# Use auth if credentials were supplied
191+
MONGODB_ARGS=""
192+
if [ -n "$MONGODB_USERNAME" ]; then
193+
MONGODB_ARGS="--username $MONGODB_USERNAME --password $MONGODB_PASSWORD"
194+
fi
195+
126196
echo "::group::Initiating replica set [$MONGODB_REPLICA_SET]"
127197

128-
docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT --eval "
198+
docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT $MONGODB_ARGS --eval "
129199
rs.initiate({
130200
\"_id\": \"$MONGODB_REPLICA_SET\",
131201
\"members\": [ {
132202
\"_id\": 0,
133-
\"host\": \"localhost:$MONGODB_PORT\"
203+
\"host\": \"$MONGODB_REPLICA_SET_HOST:$MONGODB_PORT\"
134204
} ]
135205
})
136206
"
@@ -140,5 +210,5 @@ echo "::endgroup::"
140210

141211

142212
echo "::group::Checking replica set status [$MONGODB_REPLICA_SET]"
143-
docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT --eval "rs.status()"
213+
docker exec --tty $MONGODB_CONTAINER_NAME $MONGODB_CLIENT --port $MONGODB_PORT $MONGODB_ARGS --eval "rs.status()"
144214
echo "::endgroup::"

stop-mongodb.sh

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/bin/sh
2+
3+
# Keep argument positions aligned with action.yml "args" so we can reuse them in post-args
4+
MONGODB_IMAGE=$1
5+
MONGODB_VERSION=$2
6+
MONGODB_REPLICA_SET=$3
7+
MONGODB_PORT=$4
8+
MONGODB_DB=$5
9+
MONGODB_USERNAME=$6
10+
MONGODB_PASSWORD=$7
11+
MONGODB_CONTAINER_NAME=$8
12+
MONGODB_KEY=$9
13+
MONGODB_AUTHSOURCE=${10}
14+
MONGODB_REPLICA_SET_HOST=${11:-"localhost"}
15+
DOCKER_NETWORK=${12}
16+
DOCKER_NETWORK_ALIAS=${13:-$MONGODB_CONTAINER_NAME}
17+
18+
# Best-effort cleanup, do not fail the job if cleanup fails
19+
set +e
20+
21+
echo "::group::Cleaning up MongoDB container [$MONGODB_CONTAINER_NAME]"
22+
23+
if docker ps -a --format '{{.Names}}' | grep -Eq "^${MONGODB_CONTAINER_NAME}$"; then
24+
docker rm -f "$MONGODB_CONTAINER_NAME" >/dev/null 2>&1 || true
25+
echo "Removed container $MONGODB_CONTAINER_NAME"
26+
else
27+
echo "Container $MONGODB_CONTAINER_NAME not found; nothing to clean."
28+
fi
29+
30+
echo "::endgroup::"
31+
32+
exit 0

test/single-instance/single-instance.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@ const { test } = require('uvu')
44
const { expect } = require('expect')
55
const Mongoose = require('mongoose')
66

7-
const { MONGODB_USERNAME, MONGODB_PASSWORD, MONGODB_DB } = process.env
7+
const { MONGODB_USERNAME, MONGODB_PASSWORD, MONGODB_DB, MONGODB_AUTHSOURCE } = process.env
88

99
test('connects to MongoDB', async () => {
1010
const connection = await Mongoose.createConnection('mongodb://localhost', {
1111
user: MONGODB_USERNAME,
1212
pass: MONGODB_PASSWORD,
1313
dbName: MONGODB_DB,
14-
authSource: MONGODB_USERNAME && MONGODB_PASSWORD ? 'admin' : undefined
14+
authSource: MONGODB_USERNAME && MONGODB_PASSWORD ? MONGODB_AUTHSOURCE : undefined
1515
})
1616

1717
await connection.close()

0 commit comments

Comments
 (0)