chore: release Dockerfile and GHCR publish workflow for RC1
- Replace stale Streamlit Dockerfile with self-contained release build (uvicorn/FastAPI; Streamlit removed in #104) - cf-orch BSL client installed via BuildKit secret in release CI; community builds skip it gracefully and fall back to local backends - compose.yml api build now uses single-repo context (context: .) so self-hosters can build without sibling repo setup - Add image: tags to api + web services in compose.yml and compose.demo.yml so docker compose pull works for pre-built images - Enable Docker push in release.yml: api + web to GHCR on v* tags (was disabled pending BSL registry policy — cf-agents#3 resolved) - cloud image (compose.cloud.yml / Dockerfile.cfcore) unchanged: never published, built on Heimdall with sibling repos available - .dockerignore: add plain_text_resume.yaml and adzuna.yaml
This commit is contained in:
parent
80041d1dd9
commit
7e361aa6d1
5 changed files with 117 additions and 44 deletions
|
|
@ -3,17 +3,20 @@ __pycache__
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
staging.db
|
staging.db
|
||||||
|
# gitignored secrets — belt-and-suspenders with the RUN rm -f in Dockerfile
|
||||||
config/user.yaml
|
config/user.yaml
|
||||||
|
config/plain_text_resume.yaml
|
||||||
config/notion.yaml
|
config/notion.yaml
|
||||||
config/email.yaml
|
config/email.yaml
|
||||||
config/tokens.yaml
|
config/tokens.yaml
|
||||||
config/craigslist.yaml
|
config/craigslist.yaml
|
||||||
|
config/adzuna.yaml
|
||||||
|
.env
|
||||||
.streamlit.pid
|
.streamlit.pid
|
||||||
.streamlit.log
|
.streamlit.log
|
||||||
aihawk/
|
aihawk/
|
||||||
docs/
|
docs/
|
||||||
tests/
|
tests/
|
||||||
.env
|
|
||||||
data/
|
data/
|
||||||
log/
|
log/
|
||||||
unsloth_compiled_cache/
|
unsloth_compiled_cache/
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,20 @@
|
||||||
# Tag-triggered release workflow.
|
# Tag-triggered release workflow.
|
||||||
# Generates changelog and creates Forgejo release on v* tags.
|
# Generates changelog, publishes Docker images to GHCR, and creates Forgejo release.
|
||||||
# Copied from Circuit-Forge/cf-agents workflows/release.yml
|
|
||||||
#
|
#
|
||||||
# Docker push is intentionally disabled — BSL 1.1 registry policy not yet resolved.
|
# Images published on v* tags:
|
||||||
# Tracked in Circuit-Forge/cf-agents#3. Re-enable the Docker steps when that lands.
|
# ghcr.io/circuitforgellc/peregrine:latest — FastAPI API (includes cf-orch)
|
||||||
|
# ghcr.io/circuitforgellc/peregrine:<tag>
|
||||||
|
# ghcr.io/circuitforgellc/peregrine-web:latest — Vue SPA (base path /)
|
||||||
|
# ghcr.io/circuitforgellc/peregrine-web:<tag>
|
||||||
#
|
#
|
||||||
# Required secrets: FORGEJO_RELEASE_TOKEN
|
# The cloud image (compose.cloud.yml) is never published — it is built and
|
||||||
# (GHCR_TOKEN not needed until Docker push is enabled)
|
# deployed directly on Heimdall from Dockerfile.cfcore with sibling repos.
|
||||||
|
#
|
||||||
|
# Required secrets:
|
||||||
|
# FORGEJO_RELEASE_TOKEN — Forgejo API token for creating releases
|
||||||
|
# GH_GHCR_TOKEN — GitHub PAT with packages:write for GHCR push
|
||||||
|
# FORGEJO_CF_ORCH_TOKEN — Forgejo token to install private circuitforge-orch
|
||||||
|
# during the API image build (BSL client for paid tier)
|
||||||
|
|
||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
|
|
@ -32,28 +40,56 @@ jobs:
|
||||||
env:
|
env:
|
||||||
OUTPUT: CHANGES.md
|
OUTPUT: CHANGES.md
|
||||||
|
|
||||||
# ── Docker (disabled — BSL registry policy pending cf-agents#3) ──────────
|
# ── Docker setup ─────────────────────────────────────────────────────────
|
||||||
# - name: Set up QEMU
|
- name: Set up QEMU
|
||||||
# uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
# - name: Set up Buildx
|
|
||||||
# uses: docker/setup-buildx-action@v3
|
- name: Set up Buildx
|
||||||
# - name: Log in to GHCR
|
uses: docker/setup-buildx-action@v3
|
||||||
# uses: docker/login-action@v3
|
|
||||||
# with:
|
- name: Log in to GHCR
|
||||||
# registry: ghcr.io
|
uses: docker/login-action@v3
|
||||||
# username: ${{ github.actor }}
|
with:
|
||||||
# password: ${{ secrets.GHCR_TOKEN }}
|
registry: ghcr.io
|
||||||
# - name: Build and push Docker image
|
username: ${{ github.actor }}
|
||||||
# uses: docker/build-push-action@v6
|
password: ${{ secrets.GH_GHCR_TOKEN }}
|
||||||
# with:
|
|
||||||
# context: .
|
# ── API image ─────────────────────────────────────────────────────────────
|
||||||
# push: true
|
# cf-orch (BSL, private) is installed via BuildKit secret — token never
|
||||||
# platforms: linux/amd64,linux/arm64
|
# appears in any image layer. Community builds without the secret fall back
|
||||||
# tags: |
|
# to local backends automatically.
|
||||||
# ghcr.io/circuitforgellc/peregrine:${{ github.ref_name }}
|
- name: Build and push API image
|
||||||
# ghcr.io/circuitforgellc/peregrine:latest
|
uses: docker/build-push-action@v6
|
||||||
# cache-from: type=gha
|
with:
|
||||||
# cache-to: type=gha,mode=max
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
secrets: |
|
||||||
|
forgejo_token=${{ secrets.FORGEJO_CF_ORCH_TOKEN }}
|
||||||
|
tags: |
|
||||||
|
ghcr.io/circuitforgellc/peregrine:${{ github.ref_name }}
|
||||||
|
ghcr.io/circuitforgellc/peregrine:latest
|
||||||
|
cache-from: type=gha,scope=api
|
||||||
|
cache-to: type=gha,mode=max,scope=api
|
||||||
|
|
||||||
|
# ── Web image ─────────────────────────────────────────────────────────────
|
||||||
|
# Published with VITE_BASE_PATH=/ (self-hosted default).
|
||||||
|
# Cloud and demo deployments build locally with VITE_BASE_PATH=/peregrine/.
|
||||||
|
- name: Build and push web image
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
context: .
|
||||||
|
dockerfile: docker/web/Dockerfile
|
||||||
|
push: true
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
build-args: |
|
||||||
|
VITE_BASE_PATH=/
|
||||||
|
tags: |
|
||||||
|
ghcr.io/circuitforgellc/peregrine-web:${{ github.ref_name }}
|
||||||
|
ghcr.io/circuitforgellc/peregrine-web:latest
|
||||||
|
cache-from: type=gha,scope=web
|
||||||
|
cache-to: type=gha,mode=max,scope=web
|
||||||
|
|
||||||
# ── Forgejo Release ───────────────────────────────────────────────────────
|
# ── Forgejo Release ───────────────────────────────────────────────────────
|
||||||
- name: Create Forgejo release
|
- name: Create Forgejo release
|
||||||
|
|
|
||||||
55
Dockerfile
55
Dockerfile
|
|
@ -1,30 +1,59 @@
|
||||||
# Dockerfile
|
# Dockerfile — Peregrine release build
|
||||||
|
# Self-contained single-repo context. Used for published images and community builds.
|
||||||
|
#
|
||||||
|
# cf-core: installed from public Forgejo via requirements.txt
|
||||||
|
# cf-orch: BSL-licensed cloud inference client; installed only when the
|
||||||
|
# forgejo_token BuildKit secret is present (release CI).
|
||||||
|
# Community builds skip it gracefully — local Ollama/vllm still work.
|
||||||
|
#
|
||||||
|
# Release CI (Forgejo):
|
||||||
|
# docker buildx build --secret id=forgejo_token,env=FORGEJO_TOKEN -t peregrine:latest .
|
||||||
|
#
|
||||||
|
# Community / source build:
|
||||||
|
# docker buildx build -t peregrine:latest .
|
||||||
|
#
|
||||||
|
# Previously this file ran Streamlit (app/app.py). Streamlit was removed in
|
||||||
|
# peregrine#104. The runtime is now uvicorn (FastAPI). Dockerfile.cfcore remains
|
||||||
|
# for the cloud deployment on Heimdall, where sibling repos are available.
|
||||||
|
|
||||||
FROM python:3.11-slim
|
FROM python:3.11-slim
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# System deps for companyScraper (beautifulsoup4, fake-useragent, lxml) and PDF gen
|
|
||||||
# libsqlcipher-dev: required to build pysqlcipher3 (SQLCipher AES-256 encryption for cloud mode)
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
gcc libffi-dev curl libsqlcipher-dev git \
|
gcc libffi-dev curl libsqlcipher-dev git \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
COPY requirements.txt .
|
COPY requirements.txt .
|
||||||
# Install Python dependencies
|
|
||||||
RUN pip install --no-cache-dir -r requirements.txt
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
# Install Playwright browser (cached separately from Python deps so requirements
|
# cf-orch BSL client — cloud inference routing for paid/premium tier.
|
||||||
# changes don't bust the ~600–900 MB Chromium layer and vice versa)
|
# The --mount=type=secret keeps the token out of all image layers.
|
||||||
|
# If no secret is provided the pip install is skipped; the app falls back to
|
||||||
|
# local backends (Ollama, vllm) and tier gating blocks cloud-orch features.
|
||||||
|
RUN --mount=type=secret,id=forgejo_token \
|
||||||
|
TOKEN=$(cat /run/secrets/forgejo_token 2>/dev/null || true) && \
|
||||||
|
if [ -n "$TOKEN" ]; then \
|
||||||
|
pip install --no-cache-dir \
|
||||||
|
"git+https://x-access-token:${TOKEN}@git.opensourcesolarpunk.com/Circuit-Forge/circuitforge-orch.git@main" \
|
||||||
|
&& echo "cf-orch installed"; \
|
||||||
|
else \
|
||||||
|
echo "cf-orch skipped (community build — local backends available)"; \
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Chromium for Playwright-based scrapers (companyScraper, job board scraping)
|
||||||
RUN playwright install chromium && playwright install-deps chromium
|
RUN playwright install chromium && playwright install-deps chromium
|
||||||
|
|
||||||
# Bundle companyScraper (company research web scraper)
|
|
||||||
COPY scrapers/ /app/scrapers/
|
COPY scrapers/ /app/scrapers/
|
||||||
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
EXPOSE 8501
|
# Strip gitignored secrets that may exist in a local checkout.
|
||||||
|
# Defense-in-depth: .dockerignore already excludes these, but an explicit rm
|
||||||
|
# guarantees they never appear in the image even if .dockerignore is misconfigured.
|
||||||
|
RUN rm -f config/user.yaml config/plain_text_resume.yaml config/notion.yaml \
|
||||||
|
config/email.yaml config/tokens.yaml config/craigslist.yaml \
|
||||||
|
config/adzuna.yaml .env
|
||||||
|
|
||||||
CMD ["streamlit", "run", "app/app.py", \
|
EXPOSE 8601
|
||||||
"--server.port=8501", \
|
|
||||||
"--server.headless=true", \
|
CMD ["uvicorn", "dev_api:app", "--host", "0.0.0.0", "--port", "8601"]
|
||||||
"--server.fileWatcherType=none"]
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
services:
|
services:
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
image: ghcr.io/circuitforgellc/peregrine:latest
|
||||||
build: .
|
build: .
|
||||||
command: >
|
command: >
|
||||||
bash -c "uvicorn dev_api:app --host 0.0.0.0 --port 8601"
|
bash -c "uvicorn dev_api:app --host 0.0.0.0 --port 8601"
|
||||||
|
|
@ -42,6 +43,8 @@ services:
|
||||||
# No host port — nginx proxies /api/ → api:8601 internally
|
# No host port — nginx proxies /api/ → api:8601 internally
|
||||||
|
|
||||||
web:
|
web:
|
||||||
|
# Built with VITE_BASE_PATH=/peregrine/ — not the same as the published
|
||||||
|
# peregrine-web:latest image (which uses base path /). Always build locally.
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/web/Dockerfile
|
dockerfile: docker/web/Dockerfile
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,10 @@
|
||||||
services:
|
services:
|
||||||
|
|
||||||
api:
|
api:
|
||||||
|
image: ghcr.io/circuitforgellc/peregrine:latest
|
||||||
build:
|
build:
|
||||||
context: ..
|
context: .
|
||||||
dockerfile: peregrine/Dockerfile.cfcore
|
dockerfile: Dockerfile
|
||||||
command: >
|
command: >
|
||||||
bash -c "uvicorn dev_api:app --host 0.0.0.0 --port 8601"
|
bash -c "uvicorn dev_api:app --host 0.0.0.0 --port 8601"
|
||||||
volumes:
|
volumes:
|
||||||
|
|
@ -31,6 +32,7 @@ services:
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
web:
|
web:
|
||||||
|
image: ghcr.io/circuitforgellc/peregrine-web:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/web/Dockerfile
|
dockerfile: docker/web/Dockerfile
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue