feat(auth): replace cookie/api-key auth with JWT Bearer tokens, separate UI from API
Publish Metadata Agent Image / build-and-push-image (push) Successful in 6m3s
Publish Node Player Image / build-and-push-image (push) Failing after 58s
Publish Web Player Image / build-and-push-image (push) Has been cancelled

- Add JWT Bearer token validation to Rust API via OIDC provider JWKS
  with automatic key rotation and 1-hour cache
- Remove x-api-key auth support and built-in web UI from furumi-web-player,
  leaving it as a pure API server
- Add /auth/token endpoint to Node player server to expose OIDC access
  tokens to the frontend
- Move Node player auth endpoints from /api/* to /auth/* to avoid
  path conflicts with Rust API
- Add static file serving to Node Express server for production
  single-container deployment
- Fix SameSite=Strict cookie issue breaking OIDC redirect flow (use Lax)
- Add Dockerfile.node-player with multi-stage Node.js build
- Add CI workflows for node-player Docker image (dev + release)
- Optimize Rust Dockerfiles with dependency caching layer
- Update docker-compose with OIDC env vars and OLLAMA_MODEL support
- Cherry-pick agent LLM client fixes from DEV branch

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ultradesu
2026-04-08 14:51:52 +01:00
parent 94d14e8fc8
commit e99cacae8b
20 changed files with 515 additions and 161 deletions
+27
View File
@@ -8,8 +8,35 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app
# 1. Copy workspace manifests and lock file (changes rarely → cached layer)
COPY Cargo.toml Cargo.lock ./
COPY furumi-common/Cargo.toml furumi-common/Cargo.toml
COPY furumi-server/Cargo.toml furumi-server/Cargo.toml
COPY furumi-client-core/Cargo.toml furumi-client-core/Cargo.toml
COPY furumi-mount-linux/Cargo.toml furumi-mount-linux/Cargo.toml
COPY furumi-mount-macos/Cargo.toml furumi-mount-macos/Cargo.toml
COPY furumi-agent/Cargo.toml furumi-agent/Cargo.toml
COPY furumi-web-player/Cargo.toml furumi-web-player/Cargo.toml
# 2. Create dummy sources so cargo can resolve and build dependencies
RUN mkdir -p furumi-common/src && echo "pub fn _dummy(){}" > furumi-common/src/lib.rs \
&& mkdir -p furumi-server/src && echo "fn main(){}" > furumi-server/src/main.rs \
&& mkdir -p furumi-client-core/src && echo "pub fn _dummy(){}" > furumi-client-core/src/lib.rs \
&& mkdir -p furumi-mount-linux/src && echo "fn main(){}" > furumi-mount-linux/src/main.rs \
&& mkdir -p furumi-mount-macos/src && echo "fn main(){}" > furumi-mount-macos/src/main.rs \
&& mkdir -p furumi-agent/src && echo "fn main(){}" > furumi-agent/src/main.rs \
&& mkdir -p furumi-web-player/src && echo "fn main(){}" > furumi-web-player/src/main.rs
# 3. Build dependencies only (this layer is cached until Cargo.toml/lock change)
RUN cargo build --release --bin furumi-agent 2>/dev/null || true
# 4. Copy real source code
COPY . .
# 5. Touch sources to invalidate cargo's fingerprint for our crates (not deps)
RUN touch furumi-common/src/lib.rs furumi-agent/src/main.rs
ARG FURUMI_VERSION=dev
RUN FURUMI_VERSION=${FURUMI_VERSION} cargo build --release --bin furumi-agent
+38
View File
@@ -0,0 +1,38 @@
FROM node:22-alpine AS build
WORKDIR /app
# 1. Install server dependencies (cached layer)
COPY furumi-node-player/server/package.json furumi-node-player/server/package-lock.json ./server/
RUN cd server && npm ci
# 2. Install client dependencies (cached layer)
COPY furumi-node-player/client/package.json furumi-node-player/client/package-lock.json ./client/
RUN cd client && npm ci
# 3. Build server
COPY furumi-node-player/server/ ./server/
RUN cd server && npm run build
# 4. Build client (VITE_FURUMI_API_URL empty = relative /api on same origin)
COPY furumi-node-player/client/ ./client/
RUN cd client && npm run build
FROM node:22-alpine
WORKDIR /app
# Server runtime
COPY --from=build /app/server/dist ./server/dist
COPY --from=build /app/server/node_modules ./server/node_modules
COPY --from=build /app/server/package.json ./server/
# Client static files
COPY --from=build /app/client/dist ./client/dist
ENV NODE_ENV=production
ENV PORT=3001
EXPOSE 3001
CMD ["node", "server/dist/index.js"]
+27
View File
@@ -8,8 +8,35 @@ RUN apt-get update && apt-get install -y \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/src/app
# 1. Copy workspace manifests and lock file (changes rarely → cached layer)
COPY Cargo.toml Cargo.lock ./
COPY furumi-common/Cargo.toml furumi-common/Cargo.toml
COPY furumi-server/Cargo.toml furumi-server/Cargo.toml
COPY furumi-client-core/Cargo.toml furumi-client-core/Cargo.toml
COPY furumi-mount-linux/Cargo.toml furumi-mount-linux/Cargo.toml
COPY furumi-mount-macos/Cargo.toml furumi-mount-macos/Cargo.toml
COPY furumi-agent/Cargo.toml furumi-agent/Cargo.toml
COPY furumi-web-player/Cargo.toml furumi-web-player/Cargo.toml
# 2. Create dummy sources so cargo can resolve and build dependencies
RUN mkdir -p furumi-common/src && echo "pub fn _dummy(){}" > furumi-common/src/lib.rs \
&& mkdir -p furumi-server/src && echo "fn main(){}" > furumi-server/src/main.rs \
&& mkdir -p furumi-client-core/src && echo "pub fn _dummy(){}" > furumi-client-core/src/lib.rs \
&& mkdir -p furumi-mount-linux/src && echo "fn main(){}" > furumi-mount-linux/src/main.rs \
&& mkdir -p furumi-mount-macos/src && echo "fn main(){}" > furumi-mount-macos/src/main.rs \
&& mkdir -p furumi-agent/src && echo "fn main(){}" > furumi-agent/src/main.rs \
&& mkdir -p furumi-web-player/src && echo "fn main(){}" > furumi-web-player/src/main.rs
# 3. Build dependencies only (this layer is cached until Cargo.toml/lock change)
RUN cargo build --release --bin furumi-web-player 2>/dev/null || true
# 4. Copy real source code
COPY . .
# 5. Touch sources to invalidate cargo's fingerprint for our crates (not deps)
RUN touch furumi-common/src/lib.rs furumi-web-player/src/main.rs
ARG FURUMI_VERSION=dev
RUN FURUMI_VERSION=${FURUMI_VERSION} cargo build --release --bin furumi-web-player
+11 -5
View File
@@ -16,8 +16,8 @@ services:
agent:
build:
context: .
dockerfile: Dockerfile.agent
context: ..
dockerfile: docker/Dockerfile.agent
container_name: furumi-agent
depends_on:
db:
@@ -25,10 +25,12 @@ services:
ports:
- "8090:8090"
environment:
RUST_LOG: info
FURUMI_AGENT_DATABASE_URL: "postgres://${POSTGRES_USER:-furumi}:${POSTGRES_PASSWORD:-furumi}@db:5432/${POSTGRES_DB:-furumi}"
FURUMI_AGENT_INBOX_DIR: "/inbox"
FURUMI_AGENT_STORAGE_DIR: "/storage"
FURUMI_AGENT_OLLAMA_URL: "${OLLAMA_URL:-http://host.docker.internal:11434}"
FURUMI_AGENT_OLLAMA_MODEL: "${OLLAMA_MODEL:-qwen3:14b}"
FURUMI_AGENT_OLLAMA_AUTH: "${OLLAMA_AUTH:-CHANGE-ME}"
FURUMI_PLAYER_BIND: "0.0.0.0:8090"
FURUMI_AGENT_POLL_INTERVAL_SECS: 5
@@ -41,8 +43,8 @@ services:
web-player:
build:
context: .
dockerfile: Dockerfile.web-player
context: ..
dockerfile: docker/Dockerfile.web-player
container_name: furumi-web-player
depends_on:
db:
@@ -53,7 +55,11 @@ services:
FURUMI_PLAYER_DATABASE_URL: "postgres://${POSTGRES_USER:-furumi}:${POSTGRES_PASSWORD:-furumi}@db:5432/${POSTGRES_DB:-furumi}"
FURUMI_PLAYER_STORAGE_DIR: "/storage"
FURUMI_PLAYER_BIND: "0.0.0.0:8085"
FURUMI_PLAYER_API_KEY: "node-player-api-key"
FURUMI_PLAYER_OIDC_ISSUER_URL: "${OIDC_ISSUER_URL}"
FURUMI_PLAYER_OIDC_CLIENT_ID: "${OIDC_CLIENT_ID}"
FURUMI_PLAYER_OIDC_CLIENT_SECRET: "${OIDC_CLIENT_SECRET}"
FURUMI_PLAYER_OIDC_REDIRECT_URL: "${OIDC_REDIRECT_URL}"
FURUMI_PLAYER_OIDC_SESSION_SECRET: "${OIDC_SESSION_SECRET}"
volumes:
- ./storage:/storage
restart: always