Skip to content
Merged
11 changes: 11 additions & 0 deletions .github/workflows/publish-docker-image.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ jobs:
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# `latest` replaces the `main` tag this action emits by default. With
# releases cut on demand, the image can sit several commits behind the
# branch, so naming it after the branch misleads. The
# `is_default_branch` guard stops a dispatch from a side branch from
# moving the tag for everyone.
tags: |
type=raw,value=latest,enable={{is_default_branch}}
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4
- name: Build and push Docker Image
Expand All @@ -37,3 +44,7 @@ jobs:
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: linux/amd64,linux/arm64
# BuildKit pushes these attestations with the registry credentials
# already in use, so no extra job permissions are needed.
provenance: mode=max
sbom: true
33 changes: 33 additions & 0 deletions .github/workflows/scan-docker-image.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Scan Docker Image

# Deliberately not tied to pull requests. The image inherits its base OS
# packages from `node:lts-slim`, so findings arrive when upstream publishes an
# advisory rather than when someone changes the app, and gating pull requests on
# them would only produce a red check nobody can act on.
on:
schedule:
- cron: "0 6 * * 1"
workflow_dispatch:

jobs:
scan-published-image:
name: Scan Published Image for Vulnerabilities
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- name: Run Trivy on the published image
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
with:
image-ref: ghcr.io/${{ github.repository }}:latest
format: sarif
output: trivy-results.sarif
severity: HIGH,CRITICAL
# Without this, the report fills with advisories that have no patched
# version, drowning out the findings that can actually be fixed.
ignore-unfixed: true
- name: Upload results to code scanning
uses: github/codeql-action/upload-sarif@v4
with:
sarif_file: trivy-results.sarif
10 changes: 9 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:lts
FROM node:lts-slim

ARG SEARXNG_COMMIT_SHA="6da6eee265daeb4a62ab638d6921522bf405de69"

Expand All @@ -9,8 +9,16 @@ ARG USERNAME=node
ARG HOME_DIR=/home/${USERNAME}
ARG APP_DIR=${HOME_DIR}/app

# The slim base omits tools the full `node` image ships implicitly: `git` for
# the SearXNG checkout and the build's commit hash, `curl` for the HEALTHCHECK
# below, `openssl` for the SearXNG secret key, and `ca-certificates` for both
# the clone and pip.
RUN apt-get update && \
apt-get install -y --no-install-recommends \
ca-certificates \
curl \
git \
openssl \
python3 \
python3-venv && \
apt-get clean && \
Expand Down
24 changes: 22 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,31 @@ The AI can run entirely inside your browser tab, on GPU or CPU, so a working set
Run the published image:

```bash
docker run -p 7860:7860 ghcr.io/felladrin/minisearch:main
docker run -p 7860:7860 ghcr.io/felladrin/minisearch
```

Then open <http://localhost:7860> and start searching.

<details>
<summary>Pin to a specific build</summary>

`latest` moves on every release, so it changes under you. To stay on a known-good build, pin the digest, which always identifies the same image:

```bash
docker inspect --format '{{index .RepoDigests 0}}' ghcr.io/felladrin/minisearch:latest
docker run -p 7860:7860 ghcr.io/felladrin/minisearch@sha256:1a2b3c...
```

The version the running instance reports (in the menu, and under `build` on `/status`) tells you which commit it was built from.

Images carry provenance and SBOM attestations, which you can inspect with:

```bash
docker buildx imagetools inspect ghcr.io/felladrin/minisearch:latest
```

</details>

<details>
<summary>Use Docker Compose</summary>

Expand All @@ -48,7 +68,7 @@ Add the service to your `docker-compose.yml`:
```yaml
services:
minisearch:
image: ghcr.io/felladrin/minisearch:main
image: ghcr.io/felladrin/minisearch:latest
ports:
- "7860:7860"
```
Expand Down
3 changes: 2 additions & 1 deletion docs/development-commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ The repository uses six GitHub Actions workflows for continuous integration, dep
| `on-push-to-main.yml` | Push to `main` | Delegates to `reusable-check-docker.yml` |
| `on-pull-request-to-main.yml` | PR opened/synced/reopened to `main` | Delegates to `reusable-check-docker.yml`; skippable via `skip-check-docker` label |
| `publish-docker-image.yml` | Manual (`workflow_dispatch`) | Builds multi-platform Docker image (linux/amd64, linux/arm64) and pushes to `ghcr.io` |
| `scan-docker-image.yml` | Weekly (Monday 06:00 UTC) or manual | Trivy scan of the published image, reporting fixable HIGH/CRITICAL findings to code scanning |
| `deploy-to-hugging-face.yml` | Manual (`workflow_dispatch`) | Syncs repository to Hugging Face Spaces using `JacobLinCool/huggingface-sync` |
| `reusable-check-docker.yml` | Called by other workflows | Docker compose production build + health check via `curl localhost:7860` (lint/format/test are covered by `ci.yml`) |

Expand All @@ -72,7 +73,7 @@ Used by both `on-push-to-main` and `on-pull-request-to-main` to run the producti
The Docker image uses a multi-stage build:
The image installs Python/SearXNG, builds the Vite frontend, and runs SearXNG and Node.js in a single container via shell process composition. No compilation step is required: the reranker's ONNX Runtime binaries ship prebuilt with the npm dependency.

The production image is published to `ghcr.io` with multi-platform support (linux/amd64, linux/arm64). Tags and labels are auto-generated from Git metadata via `docker/metadata-action`.
The production image is published to `ghcr.io` with multi-platform support (linux/amd64, linux/arm64). Labels are auto-generated from Git metadata via `docker/metadata-action`, and each release is published as `latest`; to pin a build, users reference the image digest. Weekly, `scan-docker-image.yml` runs Trivy against the published `latest` and reports fixable HIGH/CRITICAL findings to code scanning.

### Manual Deployments

Expand Down
Loading