fix: remove API key from plain-text config file, add workflow permissions

- config.py: stop writing API_KEY to .immich_config.json; direct users
  to .env instead. Resolves CodeQL py/clear-text-storage-sensitive-data.
- test.yml, lint.yml: add permissions: contents: read to satisfy
  actions/missing-workflow-permissions scanner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 03:51:55 +00:00
co-authored by Claude Sonnet 4.6
parent 8f2a6d3163
commit 444932c369
3 changed files with 11 additions and 5 deletions
+2
View File
@@ -9,6 +9,8 @@ on:
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
env: env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
steps: steps:
+2
View File
@@ -9,6 +9,8 @@ on:
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
permissions:
contents: read
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
+7 -5
View File
@@ -67,12 +67,11 @@ class _Config:
self.ENABLE_CACHE = os.getenv("ENABLE_CACHE", "false").lower() in ("true", "1", "yes") self.ENABLE_CACHE = os.getenv("ENABLE_CACHE", "false").lower() in ("true", "1", "yes")
self.CACHE_DIR = os.getenv("CACHE_DIR", ".if_cache") self.CACHE_DIR = os.getenv("CACHE_DIR", ".if_cache")
# Fall back to config file for missing values # Fall back to config file for non-sensitive values (API_KEY not stored here)
if CONFIG_FILE.exists(): if CONFIG_FILE.exists():
try: try:
data = json.loads(CONFIG_FILE.read_text()) data = json.loads(CONFIG_FILE.read_text())
self.IMMICH_URL = self.IMMICH_URL or data.get("IMMICH_URL") self.IMMICH_URL = self.IMMICH_URL or data.get("IMMICH_URL")
self.API_KEY = self.API_KEY or data.get("API_KEY")
if not os.getenv("OUTPUT_DIR"): if not os.getenv("OUTPUT_DIR"):
self.OUTPUT_DIR = data.get("OUTPUT_DIR", self.OUTPUT_DIR) self.OUTPUT_DIR = data.get("OUTPUT_DIR", self.OUTPUT_DIR)
except (json.JSONDecodeError, OSError) as e: except (json.JSONDecodeError, OSError) as e:
@@ -84,13 +83,16 @@ class _Config:
cls._instance = None cls._instance = None
def save(self) -> None: def save(self) -> None:
"""Persist configuration to file.""" """Persist non-sensitive configuration to file.
API_KEY is intentionally excluded — store it in .env or as an
environment variable instead of a plain-text config file.
"""
try: try:
CONFIG_FILE.write_text( CONFIG_FILE.write_text(
json.dumps( json.dumps(
{ {
"IMMICH_URL": self.IMMICH_URL, "IMMICH_URL": self.IMMICH_URL,
"API_KEY": self.API_KEY,
"OUTPUT_DIR": self.OUTPUT_DIR, "OUTPUT_DIR": self.OUTPUT_DIR,
}, },
indent=2, indent=2,
@@ -113,8 +115,8 @@ class _Config:
if not self.API_KEY: if not self.API_KEY:
console.print("[yellow]Immich API Key not found.[/yellow]") console.print("[yellow]Immich API Key not found.[/yellow]")
console.print("[dim]Tip: set API_KEY in your .env file to avoid re-entering it.[/dim]")
self.API_KEY = Prompt.ask("Enter Immich API Key", password=True) self.API_KEY = Prompt.ask("Enter Immich API Key", password=True)
self.save()
def validate(self) -> None: def validate(self) -> None:
"""Raise ValueError if required config is missing.""" """Raise ValueError if required config is missing."""