This is an automated email from the ASF dual-hosted git repository.
lewismc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nutch.git
The following commit(s) were added to refs/heads/master by this push:
new 6e222aa16 NUTCH-3213 Harden Docker image: non-root USER and Dockerfile
lint (SonarCloud) (#968)
6e222aa16 is described below
commit 6e222aa1600138d1636f75a30e131abd646d0deb
Author: Lewis John McGibbney <[email protected]>
AuthorDate: Tue Sep 22 18:24:48 2026 -0700
NUTCH-3213 Harden Docker image: non-root USER and Dockerfile lint
(SonarCloud) (#968)
---
.github/workflows/docker-smoke.yml | 73 ++++++++++++++++++++++++++++++++++++++
docker/Dockerfile | 47 ++++++++++++------------
docker/README.md | 20 +++++++++--
3 files changed, 114 insertions(+), 26 deletions(-)
diff --git a/.github/workflows/docker-smoke.yml
b/.github/workflows/docker-smoke.yml
new file mode 100644
index 000000000..42f468d72
--- /dev/null
+++ b/.github/workflows/docker-smoke.yml
@@ -0,0 +1,73 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Build docker/Dockerfile and smoke-test the image (install + inject).
+# Runs only when the Dockerfile or this workflow changes.
+
+---
+name: docker image smoke
+on:
+ push:
+ branches: [master]
+ paths:
+ - 'docker/Dockerfile'
+ - '.github/workflows/docker-smoke.yml'
+ pull_request:
+ types: [opened, synchronize, reopened]
+ branches: [master]
+ paths:
+ - 'docker/Dockerfile'
+ - '.github/workflows/docker-smoke.yml'
+
+concurrency:
+ group: docker-smoke-${{ github.ref }}
+ cancel-in-progress: true
+
+permissions: {}
+
+jobs:
+ docker-smoke:
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ steps:
+ - uses: actions/checkout@v7
+ - name: Build Nutch image
+ run: docker build -t apache/nutch:ci -f docker/Dockerfile docker/
+ - name: Verify installation
+ run: |
+ set -euo pipefail
+ test "$(docker run --rm apache/nutch:ci id -un)" = nutch
+ test "$(docker run --rm apache/nutch:ci id -u)" != 0
+ test "$(docker run --rm apache/nutch:ci printenv JAVA_HOME)" \
+ = /usr/lib/jvm/java-17-openjdk
+ test "$(docker run --rm apache/nutch:ci printenv NUTCH_HOME)" \
+ = /opt/nutch/runtime/local
+ docker run --rm -i apache/nutch:ci bash -ic 'test -n "$JAVA_HOME"'
+ # nutch with no args exits 1, so only check the launchers are on PATH
+ docker run --rm apache/nutch:ci bash -c \
+ 'command -v nutch && command -v crawl'
+ - name: Inject seed URL
+ run: |
+ set -euo pipefail
+ docker run --rm apache/nutch:ci bash -c '
+ set -euo pipefail
+ cd "$NUTCH_HOME"
+ mkdir -p urls
+ printf "%s\n" "https://nutch.apache.org/" > urls/seed.txt
+ nutch inject -Dhttp.agent.name=NutchDockerSmoke crawldb urls
+ STATS=$(nutch readdb crawldb -stats 2>&1)
+ printf "%s\n" "$STATS"
+ printf "%s\n" "$STATS" | grep -E "TOTAL urls:[[:space:]]*[1-9]"
+ '
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 392dfdb86..c9c8a399c 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -28,29 +28,30 @@ LABEL org.opencontainers.image.title="Apache Nutch 1.x
Docker Image"
LABEL org.opencontainers.image.url="https://hub.docker.com/r/apache/nutch"
LABEL org.opencontainers.image.vendor="Apache Nutch https://nutch.apache.org"
-WORKDIR /root/
-
-# Install dependencies
-RUN apk update
-RUN apk --no-cache add apache-ant bash git openjdk17
-
-# Establish environment variables
-RUN echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk' >> $HOME/.bashrc
-RUN echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk' >> $HOME/.ashrc
ENV JAVA_HOME='/usr/lib/jvm/java-17-openjdk'
-ENV NUTCH_HOME='/root/nutch_source/runtime/local'
-
-# Checkout and build the Nutch master branch (1.x)
-RUN git clone https://github.com/apache/nutch.git nutch_source && \
- cd nutch_source && \
- ant runtime && \
- rm -rf build/ && \
- rm -rf /root/.ivy2/
-
-# Create symlinks for runtime/local/bin/nutch and runtime/local/bin/crawl
-RUN ln -sf $NUTCH_HOME/bin/nutch /usr/local/bin/
-RUN ln -sf $NUTCH_HOME/bin/crawl /usr/local/bin/
-
-RUN echo "Successfully built image, see https://s.apache.org/m5933 for
guidance on running a container instance."
+ENV NUTCH_HOME='/opt/nutch/runtime/local'
+
+# Install dependencies, build Nutch, and drop privileges for runtime
+RUN apk --no-cache add \
+ apache-ant=1.10.14-r0 \
+ bash=5.2.21-r0 \
+ git=2.43.7-r0 \
+ openjdk17=17.0.14_p7-r0 \
+ && addgroup -S nutch \
+ && adduser -S -D -H -G nutch -h /opt/nutch nutch \
+ && git clone https://github.com/apache/nutch.git /opt/nutch \
+ && ant -f /opt/nutch/build.xml runtime \
+ && rm -rf /opt/nutch/build/ \
+ && rm -rf /root/.ivy2/ \
+ && ln -sf "${NUTCH_HOME}/bin/nutch" /usr/local/bin/ \
+ && ln -sf "${NUTCH_HOME}/bin/crawl" /usr/local/bin/ \
+ && echo "export JAVA_HOME=${JAVA_HOME}" >> /opt/nutch/.bashrc \
+ && echo "export JAVA_HOME=${JAVA_HOME}" >> /opt/nutch/.ashrc \
+ && chown -R nutch:nutch /opt/nutch \
+ && echo "Successfully built image, see https://s.apache.org/m5933 for
guidance on running a container instance."
+
+WORKDIR /opt/nutch
+
+USER nutch
CMD ["/bin/bash"]
diff --git a/docker/README.md b/docker/README.md
index 6c6304481..1c3f57df6 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -20,7 +20,9 @@ Nutch can run on a single machine, but gains a lot of its
strength from running
Current configuration of this image consists of components:
-* Nutch 1.x (branch "master")
+* Nutch 1.x (branch "master")
+* Default runtime user `nutch` (not root)
+* `NUTCH_HOME=/opt/nutch/runtime/local` (sources under `/opt/nutch`)
## Base Image
@@ -49,9 +51,19 @@ $(boot2docker shellinit | grep export) #may not be necessary
docker build -t apache/nutch .
```
+Pull requests that change `docker/Dockerfile` (or the
+[docker image smoke](../.github/workflows/docker-smoke.yml) workflow) build
+this image and inject `https://nutch.apache.org/` into a CrawlDb. They do not
+run fetch.
+
## Security and plugin directories
-Nutch loads executable code from the directories configured as
`plugin.folders` (see `nutch-default.xml`). For production and shared images,
treat those paths as **trusted**: mount them read-only where possible, rebuild
images to change plugins, and run the crawl process under a dedicated
low-privilege user so the filesystem cannot be abused to drop unexpected JARs
or `plugin.xml` files into that tree.
+Nutch loads executable code from the directories configured as `plugin.folders`
+(see `nutch-default.xml`). For production and shared images, treat those paths
+as **trusted**: mount them read-only where possible, rebuild images to change
+plugins, and keep the crawl process on the image default user `nutch` so the
+filesystem cannot be abused to drop unexpected JARs or `plugin.xml` files into
+that tree. Use `docker run --user root ...` only for privileged debugging.
User-defined JEXL in configuration (for example `index.jexl.filter`, generator
expressions, and `hostdb.filter.expression`) is evaluated in a **sandboxed**
engine by default. The property `nutch.jexl.disable.sandbox` disables that
protection and must not be set in untrusted environments.
@@ -63,12 +75,14 @@ boot2docker up
$(boot2docker shellinit | grep export)
```
-Run a container interactively (`nutch` and `crawl` are on `PATH`; default
command is `bash`):
+Run a container interactively (`nutch` and `crawl` are on `PATH`; default
command is `bash`; process user is `nutch`):
```bash
docker run -t -i --name nutchcontainer apache/nutch
```
+The previous image layout used `/root/nutch_source`. Bind mounts that pointed
at that path must be updated to `/opt/nutch`.
+
In another terminal, attach to a running container if needed:
```bash