Add env_file support for Keycloak auth in docker-compose dev #165

Merged
ldraney merged 2 commits from 164-dev-keycloak-auth into main 2026-06-07 18:45:17 +00:00
Owner

Summary

  • Enables Keycloak authentication in local dev by wiring env_file: .env into docker-compose web service
  • Developers copy .env.example to .env and fill in the client secret to enable auth
  • Without a .env file, the app continues with graceful degradation (no auth required)

Changes

  • docker-compose.yml: added env_file: .env to web service above ports/environment
  • .env.example: new file with Keycloak connection vars and documentation comments
  • .gitignore: added !/.env.example exception so the example file is tracked while real .env remains ignored

Test Plan

  • docker compose up without .env file — app starts normally, no auth required
  • Copy .env.example to .env, fill in real secret, docker compose up — app redirects to Keycloak login
  • Verify .env is not tracked by git (git status shows clean)
  • No regressions in existing dev workflow

Review Checklist

  • Passed automated review-fix loop
  • No secrets committed
  • No unnecessary file changes
  • Commit messages are descriptive
  • Feature flag needed? No — this is infrastructure wiring, not a user-visible workflow change. Auth is controlled by presence/absence of .env file.
  • ldraney/landscaping-assistant #164 — the Forgejo issue this PR implements
  • landscaping-assistant — the project this work belongs to
  • Cross-repo dependency: pal-e-services Terraform change needed separately to provision the Keycloak client/realm

Closes #164

## Summary - Enables Keycloak authentication in local dev by wiring `env_file: .env` into docker-compose web service - Developers copy `.env.example` to `.env` and fill in the client secret to enable auth - Without a `.env` file, the app continues with graceful degradation (no auth required) ## Changes - `docker-compose.yml`: added `env_file: .env` to web service above ports/environment - `.env.example`: new file with Keycloak connection vars and documentation comments - `.gitignore`: added `!/.env.example` exception so the example file is tracked while real `.env` remains ignored ## Test Plan - [ ] `docker compose up` without `.env` file — app starts normally, no auth required - [ ] Copy `.env.example` to `.env`, fill in real secret, `docker compose up` — app redirects to Keycloak login - [ ] Verify `.env` is not tracked by git (`git status` shows clean) - [ ] No regressions in existing dev workflow ## Review Checklist - [ ] Passed automated review-fix loop - [ ] No secrets committed - [ ] No unnecessary file changes - [ ] Commit messages are descriptive - [ ] Feature flag needed? No — this is infrastructure wiring, not a user-visible workflow change. Auth is controlled by presence/absence of `.env` file. ## Related Notes - `ldraney/landscaping-assistant #164` — the Forgejo issue this PR implements - `landscaping-assistant` — the project this work belongs to - Cross-repo dependency: pal-e-services Terraform change needed separately to provision the Keycloak client/realm Closes #164
Add env_file support for Keycloak auth in docker-compose dev
Some checks are pending
CI / scan_ruby (pull_request) Waiting to run
CI / scan_js (pull_request) Waiting to run
CI / lint (pull_request) Waiting to run
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
d9e596ca45
Adds env_file: .env to docker-compose web service so developers can
enable Keycloak auth locally by copying .env.example to .env and
filling in the client secret. Without .env, graceful degradation
preserves auth-free local dev.

Closes #164

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

QA Review — PR #165

Scope: 3 files changed, +10/-1. Infrastructure wiring for Keycloak env vars in docker-compose dev.

Findings

[BLOCKING] env_file: .env will error when .env does not exist

Docker Compose v2 treats a missing env_file as a fatal error by default. Since the stated goal is graceful degradation (no .env = no auth, app still runs), this will break the default dev experience for anyone who hasn't copied .env.example to .env.

Fix: use the optional file syntax:

env_file:
  - path: .env
    required: false

This tells Compose to load .env if present, skip silently if absent.

[OK] .gitignore change — Correct pattern: /.env* excludes secrets, !/.env.example allows the template to be tracked.

[OK] .env.example — No real secrets, clear documentation comments, correct variable names matching the Keycloak config.

[OK] PR body — Has all required sections, Closes #164, feature flag consideration documented.

Summary

One blocking issue: the env_file directive needs required: false to achieve the stated graceful degradation behavior. Without it, docker compose up fails for developers who haven't created .env.


VERDICT: REQUEST_CHANGES

## QA Review — PR #165 **Scope:** 3 files changed, +10/-1. Infrastructure wiring for Keycloak env vars in docker-compose dev. ### Findings **[BLOCKING] `env_file: .env` will error when `.env` does not exist** Docker Compose v2 treats a missing `env_file` as a fatal error by default. Since the stated goal is graceful degradation (no `.env` = no auth, app still runs), this will break the default dev experience for anyone who hasn't copied `.env.example` to `.env`. Fix: use the optional file syntax: ```yaml env_file: - path: .env required: false ``` This tells Compose to load `.env` if present, skip silently if absent. **[OK] `.gitignore` change** — Correct pattern: `/.env*` excludes secrets, `!/.env.example` allows the template to be tracked. **[OK] `.env.example`** — No real secrets, clear documentation comments, correct variable names matching the Keycloak config. **[OK] PR body** — Has all required sections, `Closes #164`, feature flag consideration documented. ### Summary One blocking issue: the `env_file` directive needs `required: false` to achieve the stated graceful degradation behavior. Without it, `docker compose up` fails for developers who haven't created `.env`. --- **VERDICT: REQUEST_CHANGES**
Fix env_file to use required: false for graceful degradation
Some checks failed
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
CI / scan_ruby (pull_request) Has been cancelled
CI / scan_js (pull_request) Has been cancelled
CI / lint (pull_request) Has been cancelled
e30a284ab8
Docker Compose v2 errors when env_file references a missing file.
Use the path/required syntax so .env is loaded when present and
silently skipped when absent, preserving auth-free local dev.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author
Owner

Fixed in e30a284: env_file now uses path: .env with required: false so Compose skips silently when .env is absent. Ready for re-review.

Fixed in e30a284: `env_file` now uses `path: .env` with `required: false` so Compose skips silently when `.env` is absent. Ready for re-review.
Author
Owner

PR #165 Review

DOMAIN REVIEW

Tech stack: Docker Compose, Rails OmniAuth, gitignore patterns.

env_file correctness (Compose Spec v2.20+):
The path: .env with required: false is the correct Compose Spec syntax for optional env files. When .env is absent, compose silently skips it -- no startup error. Confirmed working behavior.

OmniAuth integration completeness:
The initializer at config/initializers/omniauth.rb (lines 11-14) guards on exactly four vars:

keycloak_configured = ENV["KEYCLOAK_URL"].present? &&
                      ENV["KEYCLOAK_REALM"].present? &&
                      ENV["KEYCLOAK_CLIENT_ID"].present? &&
                      ENV["KEYCLOAK_CLIENT_SECRET"].present?

The .env.example provides all four. No missing vars.

Graceful degradation (edge cases):

  • .env absent: compose skips it, no KEYCLOAK vars set, keycloak_configured is false, app runs without auth. SAFE.
  • .env exists but empty: same result -- all .present? checks fail, no auth loaded. SAFE.
  • .env with partial vars (e.g., URL set but no secret): keycloak_configured still false due to && chain. No partial-config crash. SAFE.

Gitignore pattern:
/.env* ignores all root-level .env* files. !/.env.example negates the ignore for that specific file. Negation patterns work correctly when placed AFTER the ignore rule. Confirmed correct.

Security:

  • .env.example contains only placeholder values (<get from k8s secret or Lucas>) -- no real secrets.
  • Real .env remains gitignored by /.env* rule.
  • The Keycloak URL (keycloak.tail5b443a.ts.net) is a Tailscale internal hostname -- not publicly reachable, acceptable to commit.

BLOCKERS

None.

NITS

None. This is a clean, minimal change that does exactly what it should.

SOP COMPLIANCE

  • Branch named after issue (164-dev-keycloak-auth matches issue #164)
  • PR body follows template (Summary, Changes, Test Plan, Related all present)
  • Related references issue #164 and cross-repo dependency noted
  • No secrets committed (.env.example has placeholder only)
  • No unnecessary file changes (3 files, all directly relevant)
  • Commit messages are descriptive

PROCESS OBSERVATIONS

Small, focused infrastructure change with clear opt-in behavior. The graceful degradation pattern (presence of .env enables auth, absence disables it) is a good developer experience -- no env var juggling needed.

VERDICT: APPROVED

## PR #165 Review ### DOMAIN REVIEW **Tech stack:** Docker Compose, Rails OmniAuth, gitignore patterns. **env_file correctness (Compose Spec v2.20+):** The `path: .env` with `required: false` is the correct Compose Spec syntax for optional env files. When `.env` is absent, compose silently skips it -- no startup error. Confirmed working behavior. **OmniAuth integration completeness:** The initializer at `config/initializers/omniauth.rb` (lines 11-14) guards on exactly four vars: ```ruby keycloak_configured = ENV["KEYCLOAK_URL"].present? && ENV["KEYCLOAK_REALM"].present? && ENV["KEYCLOAK_CLIENT_ID"].present? && ENV["KEYCLOAK_CLIENT_SECRET"].present? ``` The `.env.example` provides all four. No missing vars. **Graceful degradation (edge cases):** - `.env` absent: compose skips it, no KEYCLOAK vars set, `keycloak_configured` is false, app runs without auth. SAFE. - `.env` exists but empty: same result -- all `.present?` checks fail, no auth loaded. SAFE. - `.env` with partial vars (e.g., URL set but no secret): `keycloak_configured` still false due to `&&` chain. No partial-config crash. SAFE. **Gitignore pattern:** `/.env*` ignores all root-level `.env*` files. `!/.env.example` negates the ignore for that specific file. Negation patterns work correctly when placed AFTER the ignore rule. Confirmed correct. **Security:** - `.env.example` contains only placeholder values (`<get from k8s secret or Lucas>`) -- no real secrets. - Real `.env` remains gitignored by `/.env*` rule. - The Keycloak URL (`keycloak.tail5b443a.ts.net`) is a Tailscale internal hostname -- not publicly reachable, acceptable to commit. ### BLOCKERS None. ### NITS None. This is a clean, minimal change that does exactly what it should. ### SOP COMPLIANCE - [x] Branch named after issue (`164-dev-keycloak-auth` matches issue #164) - [x] PR body follows template (Summary, Changes, Test Plan, Related all present) - [x] Related references issue #164 and cross-repo dependency noted - [x] No secrets committed (`.env.example` has placeholder only) - [x] No unnecessary file changes (3 files, all directly relevant) - [x] Commit messages are descriptive ### PROCESS OBSERVATIONS Small, focused infrastructure change with clear opt-in behavior. The graceful degradation pattern (presence of `.env` enables auth, absence disables it) is a good developer experience -- no env var juggling needed. ### VERDICT: APPROVED
ldraney deleted branch 164-dev-keycloak-auth 2026-06-07 18:45:17 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/landscaping-assistant!165
No description provided.