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:
pyr0ball 2026-06-14 20:03:40 -07:00
parent 80041d1dd9
commit 7e361aa6d1
5 changed files with 117 additions and 44 deletions

View file

@ -3,17 +3,20 @@ __pycache__
*.pyc
*.pyo
staging.db
# gitignored secrets — belt-and-suspenders with the RUN rm -f in Dockerfile
config/user.yaml
config/plain_text_resume.yaml
config/notion.yaml
config/email.yaml
config/tokens.yaml
config/craigslist.yaml
config/adzuna.yaml
.env
.streamlit.pid
.streamlit.log
aihawk/
docs/
tests/
.env
data/
log/
unsloth_compiled_cache/

View file

@ -1,12 +1,20 @@
# Tag-triggered release workflow.
# Generates changelog and creates Forgejo release on v* tags.
# Copied from Circuit-Forge/cf-agents workflows/release.yml
# Generates changelog, publishes Docker images to GHCR, and creates Forgejo release.
#
# Docker push is intentionally disabled — BSL 1.1 registry policy not yet resolved.
# Tracked in Circuit-Forge/cf-agents#3. Re-enable the Docker steps when that lands.
# Images published on v* tags:
# 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
# (GHCR_TOKEN not needed until Docker push is enabled)
# The cloud image (compose.cloud.yml) is never published — it is built and
# 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
@ -32,28 +40,56 @@ jobs:
env:
OUTPUT: CHANGES.md
# ── Docker (disabled — BSL registry policy pending cf-agents#3) ──────────
# - name: Set up QEMU
# uses: docker/setup-qemu-action@v3
# - name: Set up Buildx
# uses: docker/setup-buildx-action@v3
# - name: Log in to GHCR
# uses: docker/login-action@v3
# with:
# registry: ghcr.io
# username: ${{ github.actor }}
# password: ${{ secrets.GHCR_TOKEN }}
# - name: Build and push Docker image
# uses: docker/build-push-action@v6
# with:
# context: .
# push: true
# platforms: linux/amd64,linux/arm64
# tags: |
# ghcr.io/circuitforgellc/peregrine:${{ github.ref_name }}
# ghcr.io/circuitforgellc/peregrine:latest
# cache-from: type=gha
# cache-to: type=gha,mode=max
# ── Docker setup ─────────────────────────────────────────────────────────
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GH_GHCR_TOKEN }}
# ── API image ─────────────────────────────────────────────────────────────
# cf-orch (BSL, private) is installed via BuildKit secret — token never
# appears in any image layer. Community builds without the secret fall back
# to local backends automatically.
- name: Build and push API image
uses: docker/build-push-action@v6
with:
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 ───────────────────────────────────────────────────────
- name: Create Forgejo release

View file

@ -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
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 \
gcc libffi-dev curl libsqlcipher-dev git \
&& rm -rf /var/lib/apt/lists/*
COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt
# Install Playwright browser (cached separately from Python deps so requirements
# changes don't bust the ~600900 MB Chromium layer and vice versa)
# cf-orch BSL client — cloud inference routing for paid/premium tier.
# 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
# Bundle companyScraper (company research web scraper)
COPY scrapers/ /app/scrapers/
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", \
"--server.port=8501", \
"--server.headless=true", \
"--server.fileWatcherType=none"]
EXPOSE 8601
CMD ["uvicorn", "dev_api:app", "--host", "0.0.0.0", "--port", "8601"]

View file

@ -16,6 +16,7 @@
services:
api:
image: ghcr.io/circuitforgellc/peregrine:latest
build: .
command: >
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
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:
context: .
dockerfile: docker/web/Dockerfile

View file

@ -3,9 +3,10 @@
services:
api:
image: ghcr.io/circuitforgellc/peregrine:latest
build:
context: ..
dockerfile: peregrine/Dockerfile.cfcore
context: .
dockerfile: Dockerfile
command: >
bash -c "uvicorn dev_api:app --host 0.0.0.0 --port 8601"
volumes:
@ -31,6 +32,7 @@ services:
restart: unless-stopped
web:
image: ghcr.io/circuitforgellc/peregrine-web:latest
build:
context: .
dockerfile: docker/web/Dockerfile