Skip to content

feat(supabase): unify 4 runtimes into single canonical compose stack - #865

Merged
POWERFULMOVES merged 13 commits into
mainfrom
feat/supabase-unify
Mar 11, 2026
Merged

POWERFULMOVES merged 13 commits into
mainfrom
feat/supabase-unify

Conversation

@POWERFULMOVES

@POWERFULMOVES POWERFULMOVES commented Mar 11, 2026

Copy link
Copy Markdown
Owner

Summary

Consolidates 4 competing Supabase deployment paths into a single canonical docker-compose.yml stack under the supabase-local profile. Also enriches integration skill entries (health/wealth/n8n) and adds branded defaults.

Supabase Unification (Phases 1-6 + 8)

  • 6 new services: imgproxy, pg-meta, edge-functions (Deno runtime), analytics (Logflare), vector, supavisor — completing the 13-service self-hosted stack
  • Version upgrades: Postgres 17.6.1, GoTrue, PostgREST v14.3, Kong 3.7.1, Realtime v2.72.0, Storage v1.37.1, Studio
  • Consumer URL migration: All services → supabase-kong:8000 (canonical gateway)
  • Fail-hard secrets: :? for JWT_SECRET, SECRET_KEY_BASE, VAULT_ENC_KEY
  • Healthcheck hardening: service_healthy depends_on, wget for Elixir images, edge-functions + analytics checks
  • Delete stale shim: docker-compose.supabase.yml superseded by profile
  • Env standardization: JWT_SECRET / ANON_KEY / SERVICE_ROLE_KEY canonical names, no ${VAR} interpolation in env_file
  • Key generation: macOS-compatible openssl base64 -A, proper HS256 JWT signing, stderr banners
  • VPS override: edge-functions + vector entries
  • Migration docs: Canonical workflow documenting initdb/migrations overlap (Geometry Bus IF NOT EXISTS guards)

Integration Enrichment

  • Auto-generate integration credentials (Firefly-III, wger, n8n)
  • TAC tree schema, runner, and review trees for integration auditing
  • Enriched health/wealth/n8n skill entries with FlOOS hooks
  • Cross-domain n8n workflow templates (finance↔health, voice health check-in)

Review Coordination

Review Focus Areas

  • Compose service definitions — healthcheck patterns, fail-hard secrets
  • generate-keys.sh — JWT signing correctness, cross-platform compatibility
  • env.tier-supabase.example — no interpolation references, all new service secrets present
  • VPS override — all 13 services covered
  • supa-stop-all — lists all 13 services

Review Fixes Already Applied

  • C6: edge-functions healthcheck + VERIFY_JWT default true
  • C7: Supavisor warns on missing pooler.exs
  • C8: JWT_SECRET/SECRET_KEY_BASE/VAULT_ENC_KEY use :? fail-hard
  • C9: supa-stop-all lists all 13 services
  • C10: generate-keys.sh banner → stderr
  • C11: env.tier-supabase.example no ${VAR} interpolation in aliases
  • C12: supabase-vector depends_on analytics + volume
  • C13: DB_ENC_KEY parameterized via SUPABASE_REALTIME_SECRET
  • HIGH: Storage/Studio depends_on upgraded to service_healthy
  • HIGH: VPS override adds edge-functions + vector
  • HIGH: macOS-compatible openssl base64 -A
  • MEDIUM: Analytics/pooler healthchecks use wget
  • MEDIUM: populate-tier-envs calls generate-keys.sh for proper JWTs

Test plan

  • docker compose --profile supabase-local config --services lists all 13 Supabase services
  • make -C pmoves supa-stop-all targets all 13 services without error
  • bash pmoves/scripts/supabase/generate-keys.sh produces valid JWTs on Linux and macOS
  • No references to host.docker.internal:54321 in compose defaults
  • No references to stale docker-compose.supabase.yml in any script
  • make -C pmoves populate-tier-envs calls generate-keys.sh successfully
  • VPS override: docker compose -f docker-compose.yml -f docker-compose.vps.override.yml config validates

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Health and finance sync workflows (Wger & Firefly III) plus cross-domain pipelines (finance↔health).
    • New n8n flows for anomaly detection, status reporting, voice check‑ins, and a finance–health crosswalk.
    • Supabase moved to a unified 13‑service stack with a Kong gateway for consolidated routing.
  • Documentation

    • Integration status guides and Supabase migration/operation docs added.
    • TAC review schema and workflow documentation introduced.

hunnibear and others added 8 commits March 11, 2026 06:48
Add _ensure_integration_credentials() to brand_defaults.py that
auto-generates non-placeholder values for:
- FIREFLY_APP_KEY: Laravel-format base64: + 32 random bytes
- N8N_ENCRYPTION_KEY: 32-byte urlsafe token for credential encryption
- N8N_RUNNERS_AUTH_TOKEN: 24-byte urlsafe shared secret
- WGER_API_TOKEN: pm_wger_ prefixed 24-byte token

Also adds base64:CHANGE_ME to the placeholder detection set,
updates registry.json with generation hints, and documents n8n
limitations (API key requires UI creation) in branded defaults doc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add health/quick, n8n/execute skills to Wealth and Health-wger entries
- Add context_files, agents_docs, and floos_hooks (publish/subscribe)
  for both integration submodules
- Enrich PMOVES-n8n with health/finance domain tags and FlOOS hooks
- Update $domain_tag_skill_map: health and finance now route to
  n8n/execute and deploy/up skills
- Add health-sync and finance-sync pairings to skill-pairings.yaml
  with proper dependency chains through n8n → tokenism CGP encoding

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add TAC (Task-Action-Context) tree framework for structured audit
checklists:
- tac_schema.yaml: node schema (file_exists, grep, command, manual)
- tac_trees/health-wger.tac.yaml: 7-node health integration review
- tac_trees/firefly-iii.tac.yaml: 7-node wealth integration review
- tac_trees/n8n.tac.yaml: 14-node workflow inventory audit
- tac_runner.py: depth-first traversal with JSON/text output
- /tac:review slash command skill for interactive review

The runner checks file existence and grep patterns, reports pass/fail
JSON for agent consumption, and includes agent_hint fields per node.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…flows

Documentation fixes:
- Fill Pmoves-Health-wger/PMOVES.AI_INTEGRATION.md template (all $t/_TBD_)
- Fix PMOVES-Wealth port 8096->8075, add Waterfly III mobile docs
- Refresh FIREFLY_WGER_INTEGRATIONS_STATUS.md with current state

Bootstrap scripts (replace no-ops):
- health-wger: Wger health check + API token validation + admin pw warning
- firefly-iii: APP_KEY format validation + service health + token check

New cross-domain n8n workflows:
- health_to_research.json: DeepResearch on health anomaly
- finance_health_crosswalk.json: correlate purchases with workouts
- voice_health_checkin.json: daily Flute-Gateway check-in
- integration_status_reporter.json: 6h health dashboard to Discord

NATS subject updates for health/finance sync and anomaly detection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mer URLs

Add imgproxy, pg-meta, edge-functions (Deno runtime), analytics (Logflare),
vector, and supavisor to the canonical docker-compose.yml under the
supabase-local profile. Upgrade existing services to current Supabase
self-hosted versions (Postgres 17.6.1, GoTrue, PostgREST v14.3, Kong 3.7.1,
Realtime v2.72.0, Storage v1.37.1, Studio).

Key changes:
- Migrate all consumer service URLs to supabase-kong:8000 (canonical gateway)
- Upgrade depends_on from service_started to service_healthy where healthchecks exist
- Add fail-hard :? for JWT_SECRET, SECRET_KEY_BASE, VAULT_ENC_KEY
- Use wget for analytics/pooler healthchecks (Elixir images lack curl)
- Delete stale docker-compose.supabase.yml shim (superseded by profile)
- Add VERIFY_JWT=true default for edge-functions
- Add supabase-vector depends_on analytics + volume mount

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Align all Supabase credential names to the canonical JWT_SECRET / ANON_KEY /
SERVICE_ROLE_KEY convention. Remove ${VAR} interpolation from
env.tier-supabase.example (env_file values are literal, not interpolated by
Docker Compose).

Key changes:
- generate-keys.sh: proper JWT signing with HS256, macOS-compatible
  openssl base64 -A, banner output to stderr, generate all 6 new service
  secrets (IMGPROXY_KEY/SALT, LOGFLARE_API_KEY, etc.)
- registry.json: standard names as canonical, legacy SUPABASE_* as aliases
- Makefile: supa-stop-all lists all 13 services, populate-tier-envs calls
  generate-keys.sh for proper JWT generation, add shim target aliases
- env.tier-supabase.example: duplicate actual values instead of referencing
  other variables, add secrets for all 6 new services

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Complete the Supabase unification by updating all peripheral files to
reference the new canonical compose stack.

Key changes:
- VPS override: add edge-functions + vector service entries with volume
- README: update Supabase section to reference unified 13-service stack
- CLAUDE.md: update infrastructure section with accurate service list,
  version numbers, and canonical consumer URL (supabase-kong:8000)
- pmoves.ps1: replace -f docker-compose.supabase.yml with
  --profile supabase-local

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ations overlap

Add MIGRATION_WORKFLOW.md documenting the two-phase initialization strategy
(initdb for fresh databases, migrations for incremental updates), known DDL
overlaps between initdb and migrations (Geometry Bus tables), schema catalog,
file naming conventions, and Postgres 17 compatibility notes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Wed Mar 11 14:28:37 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: analysis-echo
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: graph-linker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 120 passed, 40 warnings, 0 errors

@coderabbitai

coderabbitai Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@POWERFULMOVES has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 27 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9ffe85dd-ca5a-4284-8ba3-0b1860d60d19

📥 Commits

Reviewing files that changed from the base of the PR and between caab0d8 and 071e6f1.

📒 Files selected for processing (3)
  • pmoves/integrations/firefly-iii/auth/bootstrap.sh
  • pmoves/integrations/firefly-iii/events/subjects.yaml
  • pmoves/integrations/health-wger/auth/bootstrap.sh
📝 Walkthrough

Walkthrough

Replaces the PostgREST-centric Supabase topology with a Kong‑gateway unified 13‑service stack; adds Neo4j/Meilisearch/MinIO to the knowledge layer; introduces TAC tree schema/runner and multiple n8n pipelines (health/finance); adds credential auto-generation, bootstrap validators, updated env/registry entries, Makefile/compose orchestration, and documentation updates.

Changes

Cohort / File(s) Summary
Supabase unified stack
pmoves/docker-compose.yml, pmoves/docker-compose.vps.override.yml, pmoves/docker-compose.supabase.yml
Replaces PostgREST-centric compose with a Kong gateway and 13-service Supabase stack (postgrest, kong, gotrue, realtime, storage, imgproxy, meta, analytics, edge-functions, vector, pooler, DB, etc.); updates images, ports, healthchecks, volumes and internal URLs; removes legacy supabase compose file.
Makefile & scripts orchestration
pmoves/Makefile, pmoves/scripts/pmoves.ps1, pmoves/scripts/supabase/generate-keys.sh
Expands supa-* targets to manage added sidecars; makes supabase-up an alias for unified profile; adds conditional tier secret generation using new generate-keys.sh; generate-keys.sh adds hex/base64 helpers and produces many new secrets.
Registry & env / secret schema
pmoves/bootstrap/registry.json, pmoves/env.tier-supabase.example, .github/workflows/hardening-validation.yml
Reworks registry/env keys for gateway model (JWT_SECRET/ANON/SERVICE keys, legacy aliases), adds VAULT_ENC_KEY/PG_META_CRYPTO_KEY/LOGFLARE keys and port vars; updates CI dummy envs.
TAC audit framework
pmoves/configs/tac_schema.yaml, pmoves/configs/tac_trees/*, pmoves/tools/tac_runner.py, .claude/commands/tac/review.md
Adds TAC schema, multiple TAC trees (firefly-iii, health-wger, n8n), a tac_runner.py executable to evaluate file_exists/grep/command/manual nodes and emit JSON/text results, and documentation for TAC review usage.
Credential/bootstrap tooling
pmoves/tools/brand_defaults.py, pmoves/scripts/supabase/generate-keys.sh
Adds auto-generation helper for integration credentials (FIREFLY_APP_KEY, N8N keys, WGER token) invoked during env upsert; generate-keys.sh expanded to emit new service secrets and aliases.
Integrations & n8n workflows
pmoves/integrations/health-wger/**, pmoves/integrations/firefly-iii/**, pmoves/integrations/firefly-iii/n8n/flows/*, pmoves/integrations/health-wger/n8n/flows/*
Replaces no-op bootstraps with service reachability and token validation scripts; adds event subjects for health/finance; introduces multiple n8n workflows (finance↔health crosswalk, health→DeepResearch, status reporter, voice checkin) and integration flow JSONs.
Skill registry & pipelines
pmoves/configs/skill-pairings.yaml, pmoves/configs/submodule_skill_registry.json
Adds health-sync and finance-sync pipelines, NATS subjects, extends domain tags/skills/context_files and floos_hooks across PMOVES-n8n/Wealth/Health-wger submodules.
Docs & metadata
.claude/CLAUDE.md, pmoves/README.md, pmoves/docs/**, pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md
Updates architecture docs to reflect Kong gateway, unified stack, credential generation, TAC audits, and new n8n workflow inventories; adds migration workflow doc and updates README usage.
Submodule pointers
PMOVES-Wealth, PMOVES-Health-wger, PMOVES-supabase
Bump submodule commit references to updated revisions that include the new workflow/integration content.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant tac_runner as tac_runner.py
    participant FS as Filesystem
    participant Evaluator as Node Evaluator
    participant Action as Action Handler
    participant Output as Formatter

    User->>tac_runner: run /path/to/tree.tac.yaml
    tac_runner->>FS: read YAML tree
    FS-->>tac_runner: tree contents
    tac_runner->>Evaluator: evaluate_node(root)

    loop DFS traversal
        Evaluator->>Action: dispatch action (file_exists/grep/command/manual)
        alt file_exists
            Action->>FS: stat file
            FS-->>Action: exists / missing
        else grep
            Action->>FS: search pattern in files
            FS-->>Action: match / no-match
        else command
            Action->>FS: run command (30s timeout)
            FS-->>Action: stdout/exit
        else manual
            Action-->>Action: mark pending
        end
        Action-->>Evaluator: status + detail
        Evaluator->>Evaluator: process children
    end

    Evaluator->>Output: aggregate results
    Output-->>User: print JSON or text (exit code reflects failures)
Loading
sequenceDiagram
    participant Scheduler
    participant n8n as n8n
    participant WGER as WGER API
    participant Firefly as Firefly III
    participant Supabase as Supabase (via Kong)
    participant NATS

    Scheduler->>n8n: trigger (daily)
    n8n->>WGER: GET /workouts (last N days)
    WGER-->>n8n: workout data
    n8n->>Firefly: GET /transactions (last N days)
    Firefly-->>n8n: transactions
    n8n->>Supabase: POST /rest/v1/crosswalk (via Kong)
    Supabase-->>n8n: 200/201
    n8n->>NATS: publish health.workouts.synced.v1 / finance.transactions.synced.v1
    NATS-->>n8n: ack
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • hunnibear

"🐰 In tunnels of code I hop and sing,
Kong gates open, and workflows take wing.
TAC trees I inspect with twitchy ear,
Keys are minted, bootstraps now clear.
Hooray — services dance, the pipelines cheer!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title accurately describes the main architectural change: unifying multiple Supabase deployment paths into a single canonical compose stack.
Description check ✅ Passed Description is well-structured with Summary, Testing, Review Coordination, and Test Plan sections covering the key changes, though Summary lacks the typical bullet points.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/supabase-unify

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

SECRET_KEY_BASE and VAULT_ENC_KEY use ${:?} guards in docker-compose.yml
for the new supabase-pooler and supabase-vector services. These variables
are resolved via compose interpolation (not env_file), so they must be
present in the CI shell environment during `docker compose config`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Wed Mar 11 14:35:51 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: analysis-echo
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: graph-linker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 120 passed, 40 warnings, 0 errors

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
pmoves/scripts/pmoves.ps1 (1)

20-42: ⚠️ Potential issue | 🟠 Major

up-fullsupabase and down/clean-fullsupabase now manage different runtimes.

When the Supabase CLI is present, Lines 21-33 start the CLI stack and rewrite PMOVES URLs to host.docker.internal. Lines 40-42 only tear down the supabase-local compose profile, so the CLI path stays running and bypasses the canonical compose stack.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/scripts/pmoves.ps1` around lines 20 - 42, The current commands start
the Supabase CLI when available (in the "up-fullsupabase" branch using supabase
start and mapping SUPA_REST_URL/SUPABASE_* envs) but the tear-down commands
("down-fullsupabase"/"clean-fullsupabase") only run Compose --profile
supabase-local down, leaving the CLI-managed Supabase stack running; update the
down/clean-fullsupabase logic to detect the Supabase CLI (Get-Command supabase
-ErrorAction SilentlyContinue) and when present call supabase stop (or check
supabase status and stop only if running) in addition to or instead of Compose
--profile supabase-local down, so both CLI-started and compose-started Supabase
stacks are properly stopped.
pmoves/Makefile (1)

1303-1304: ⚠️ Potential issue | 🟠 Major

Use scripts/with-env.sh to load environment files in populate-tier-envs.

The raw sourcing (. ./env.shared / . ./.env.local) bypasses the safe loader that handles multiline values, special characters, and shell metacharacters. Other Makefile targets use scripts/with-env.sh for this reason—it safely quotes values, strips whitespace, disables history expansion, and prevents parsing/injection issues.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 1303 - 1304, Replace the raw sourcing in the
populate-tier-envs Makefile recipe (currently using ". ./env.shared" and ".
./.env.local") with the safe loader script by invoking scripts/with-env.sh to
load env.shared and .env.local; update the populate-tier-envs recipe to call
scripts/with-env.sh with those filenames so multiline values, special
characters, and shell metacharacters are handled, whitespace is stripped, and
history expansion is disabled while preserving the original environment-loading
behavior.
pmoves/bootstrap/registry.json (1)

511-540: ⚠️ Potential issue | 🔴 Critical

Update Jellyfin’s inherited Supabase keys to the new canonical source.

This block still inherits SUPABASE_ANON_KEY / SUPABASE_SERVICE_ROLE_KEY from pmoves/.env.local, but this file now defines ANON_KEY / SERVICE_ROLE_KEY in pmoves/env.tier-supabase. As written, env.jellyfin-ai can no longer resolve its required Supabase credentials.

Suggested fix
         {
           "key": "SUPABASE_ANON_KEY",
           "file": "pmoves/env.jellyfin-ai",
           "prompt": "Supabase anon key (Jellyfin)",
           "help": "Same anon key used by the core stack.",
           "required": true,
           "sensitive": true,
           "inherit": {
-            "file": "pmoves/.env.local",
-            "key": "SUPABASE_ANON_KEY"
+            "file": "pmoves/env.tier-supabase",
+            "key": "ANON_KEY"
           }
         },
         {
           "key": "SUPABASE_SERVICE_ROLE_KEY",
           "file": "pmoves/env.jellyfin-ai",
           "prompt": "Supabase service role key (Jellyfin)",
           "help": "Same service role key used by the core stack.",
           "required": true,
           "sensitive": true,
           "inherit": {
-            "file": "pmoves/.env.local",
-            "key": "SUPABASE_SERVICE_ROLE_KEY"
+            "file": "pmoves/env.tier-supabase",
+            "key": "SERVICE_ROLE_KEY"
           }
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/bootstrap/registry.json` around lines 511 - 540, The SUPABASE_ANON_KEY
and SUPABASE_SERVICE_ROLE_KEY entries in env.jellyfin-ai still inherit from
pmoves/.env.local but the canonical values now live in pmoves/env.tier-supabase
under keys ANON_KEY and SERVICE_ROLE_KEY; update the inherit blocks for the
SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY entries to point to file
"pmoves/env.tier-supabase" and the corresponding keys "ANON_KEY" and
"SERVICE_ROLE_KEY" so env.jellyfin-ai can resolve the required Supabase
credentials.
🧹 Nitpick comments (7)
PMOVES-Wealth (1)

1-1: Document the submodule update rationale.

Submodule pointer updates should include documentation of what changed and why. Consider adding a note to the PR description explaining the purpose of the PMOVES-Wealth submodule update and any compatibility considerations with this PR's changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@PMOVES-Wealth` at line 1, Add a clear PR description entry documenting the
PMOVES-Wealth submodule update: state the updated submodule name
"PMOVES-Wealth", include the new commit hash or tag, summarize what changed in
that submodule (features/bugfixes/APIs), call out any compatibility or breaking
changes that affect this PR (public function/class/API surface), and list
required developer actions (build, migration, or test steps) so reviewers can
validate the update.
pmoves/integrations/firefly-iii/auth/bootstrap.sh (1)

38-54: Consider handling HTTP 403 for consistency with health-wger bootstrap.

The health-wger bootstrap script handles both 401 and 403 for invalid tokens (line 27-30 in that file), while this script only handles 401. For consistency, consider adding 403 handling.

📝 Proposed fix for consistency
   if [ "$STATUS" = "200" ]; then
     echo "[firefly-iii] OK: FIREFLY_ACCESS_TOKEN is valid"
-  elif [ "$STATUS" = "401" ]; then
+  elif [ "$STATUS" = "401" ] || [ "$STATUS" = "403" ]; then
-    echo "[firefly-iii] FAIL: FIREFLY_ACCESS_TOKEN is invalid"
+    echo "[firefly-iii] FAIL: FIREFLY_ACCESS_TOKEN is invalid (HTTP $STATUS)"
     echo "[firefly-iii] Generate a new token from Firefly III: Profile -> OAuth -> Personal Access Tokens"
     exit 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/integrations/firefly-iii/auth/bootstrap.sh` around lines 38 - 54, The
script currently checks the FIREFLY_TOKEN by storing HTTP status in STATUS and
only treats "401" as invalid; update the conditional around STATUS (the
if/elif/else block that echoes token validity) to also treat "403" as an invalid
token like "401" (either by adding an elif for "$STATUS" = "403" or by checking
both values together) so that the failure message and exit behavior for invalid
tokens matches the health-wger bootstrap handling.
pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md (2)

34-38: Add language specifier to fenced code block.

📝 Proposed fix
 ### migrations/ — Timestamped (three formats in use)
-```
+```text
 20250115000000_service_catalog.sql      ← YYYYMMDDhhmmss (Supabase CLI standard)
 20250115_persona_agent_creation.sql     ← YYYYMMDD (short form)
 2025-09-08_geometry_bus.sql             ← YYYY-MM-DD (early convention)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md` around lines 34 - 38,
Update the fenced code block containing the migration filename examples to
include a language specifier (e.g., add "text" after the opening backticks) so
syntax highlighting and renderer treat it as plain text; modify the block that
shows "20250115000000_service_catalog.sql … 2025-09-08_geometry_bus.sql" in
MIGRATION_WORKFLOW.md to start with ```text instead of ``` to apply the fix.

23-29: Add language specifier to fenced code blocks.

Per markdownlint MD040, fenced code blocks should have a language specified for proper syntax highlighting.

📝 Proposed fix
 ### initdb/ — Numbered ordering
-```
+```text
 00_pmoves_schema.sql      ← Foundation: extensions, schemas, core tables
 01_public_init.sql        ← Public schema roles/grants
 02_seed.sql               ← Initial seed data
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md` around lines 23 - 29,
The fenced code block in MIGRATION_WORKFLOW.md is missing a language specifier
(MD040); update the opening fence (the triple backticks) to include an
appropriate language token (e.g., text) so the block becomes ```text, ensuring
proper syntax highlighting for the listed filenames like 00_pmoves_schema.sql
and 17_persona_seed.sql; leave the block contents unchanged and only modify the
opening fence.
.claude/commands/tac/review.md (1)

19-27: Avoid executing the TAC tree twice.

Lines 19-27 instruct the agent to rerun the whole tree for a second output format. Because pmoves/configs/tac_schema.yaml allows command actions, this can duplicate expensive or side-effecting checks; render both views from a single execution result instead.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.claude/commands/tac/review.md around lines 19 - 27, The docs currently tell
users to run pmoves/tools/tac_runner.py twice (once with --format text and once
without) which can re-execute command actions defined by
pmoves/configs/tac_schema.yaml; change tac_runner.py so it performs a single
execution of the TAC tree and then renders both views from that single result
(e.g., capture the execution output/result object in the main run function and
call the existing text-render and json-render routines on that object rather
than re-running the tree), and update any CLI option handling to allow a
combined output mode or to always produce both formats when requested.
pmoves/tools/tac_runner.py (1)

105-114: Consider explicit invert flag instead of string parsing.

The grep inversion logic relies on string matching ("Should NOT contain" or "No ") in the expect field. This is fragile—typos like "should not contain" (lowercase) would bypass inversion.

Consider adding an explicit invert: true field to the action schema for clearer intent.

♻️ Suggested schema extension

In TAC tree YAML:

action:
  type: grep
  target: "..."
  pattern: "no-op"
  invert: true  # Explicit: finding pattern means FAIL
  expect: "Should NOT contain 'no-op'"

In runner:

-            if "Should NOT contain" in expect or "No " in expect:
+            if action.get("invert", False):
                 # Invert: finding the pattern means FAIL
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/tools/tac_runner.py` around lines 105 - 114, The grep inversion
currently infers intent by string-matching the action's "expect" text which is
fragile; update the runner to support an explicit boolean invert flag on the
action (e.g., action.get("invert", False)) and use that to decide inversion
instead of checking substrings of expect. Locate the grep handling block around
_check_grep and replace the conditional that inspects expect ("Should NOT
contain" / "No ") with logic that reads action.get("invert", False) and then set
result["status"] = "fail" if status == "pass" when invert is True (otherwise
keep status), and always copy result["detail"] from the _check_grep return.
Ensure backwards compatibility by keeping the original behavior only if you
choose to, but prefer the explicit invert flag for new checks.
pmoves/docs/integrations/FIREFLY_WGER_INTEGRATIONS_STATUS.md (1)

27-53: Add blank lines around Markdown tables for compatibility.

Per markdownlint MD058, tables should be surrounded by blank lines to ensure consistent rendering across Markdown parsers.

📝 Proposed formatting fix
 ## n8n Workflow Inventory
 
 ### Health Domain (pmoves/integrations/health-wger/n8n/flows/)
+
 | Workflow | Purpose | NATS Subject |
 |----------|---------|-------------|
 | `health_wger_sync.json` | Sync workouts from Wger to Supabase | `health.workouts.synced.v1` |
 ...
 | `integration_status_reporter.json` | Periodic integration health dashboard | — |
+
 ### Finance Domain (pmoves/integrations/firefly-iii/n8n/flows/)
+
 | Workflow | Purpose | NATS Subject |
 |----------|---------|-------------|
 ...
 | `finance_health_crosswalk.json` | Correlate purchases with workouts | — |
+
 ### Cross-Domain Workflows
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docs/integrations/FIREFLY_WGER_INTEGRATIONS_STATUS.md` around lines 27
- 53, The Markdown tables under "Health Domain
(pmoves/integrations/health-wger/n8n/flows/)" (the table listing workflows like
`health_wger_sync.json`, `wger_sync_to_supabase.json`, etc.) and "Finance Domain
(pmoves/integrations/firefly-iii/n8n/flows/)" (the table listing workflows like
`finance_firefly_sync.json`, `firefly_sync_to_supabase.json`, etc.) need blank
lines before and after each table per markdownlint MD058; update the document by
inserting a single empty line above the header row and a single empty line after
the closing table row for both tables so they are properly separated from
surrounding headings and paragraphs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pmoves/bootstrap/registry.json`:
- Around line 40-61: The registry entries for ANON_KEY and SERVICE_ROLE_KEY are
set to use "generate": {"type":"random_urlsafe"} but bootstrap_env.py's
generate_value() does not produce HS256-signed JWTs (so it will emit plain
random strings instead of the JWTs described in the help); fix by either (A)
adding a JWT generator branch in bootstrap_env.py (implement a generate type
like "jwt" that calls a signing routine similar to
scripts/supabase/generate-keys.sh's generate_jwt_token(), accepting the secret
param/JWT_SECRET and producing an HS256 token) and change the registry entries'
generate.type to "jwt" with any required params, or (B) remove the generate
block from the ANON_KEY and SERVICE_ROLE_KEY registry entries and leave help
text as-is so keys must be produced by scripts/supabase/generate-keys.sh, or (C)
keep random_urlsafe but update the help text to state that a random token (not a
signed JWT) will be generated; reference symbols: ANON_KEY, SERVICE_ROLE_KEY,
generate_value(), bootstrap_env.py, generate_jwt_token(),
scripts/supabase/generate-keys.sh.

In `@pmoves/configs/submodule_skill_registry.json`:
- Around line 18-19: The domain-tag skill map entry for "health" is missing the
new "health/quick" skill; update the JSON object key "health" (the
$domain_tag_skill_map.health array) to include "health/quick" alongside the
existing entries (e.g., ["n8n/execute", "deploy/up", "health/quick"]) so
domain-based discovery will surface the Pmoves-Health-wger advertised skill.

In `@pmoves/docker-compose.yml`:
- Around line 681-683: Replace the hardcoded fallback for DB_ENC_KEY so the
service does not boot with a known secret: remove the default value
"${SUPABASE_REALTIME_SECRET:-supabaserealtime}" and require the env var be
provided (e.g., use DB_ENC_KEY=${SUPABASE_REALTIME_SECRET}), or add a startup
validation that exits if SUPABASE_REALTIME_SECRET equals the insecure literal;
update the docker-compose environment entry for DB_ENC_KEY and any related
startup/entrypoint logic that checks DB_ENC_KEY to fail fast when the secret is
missing or still the insecure default.
- Around line 761-762: The docker-compose dependency for supabase-storage is
waiting on an unsatisfiable healthcheck from supabase-postgrest (it has no
HEALTHCHECK), so update the dependency under the supabase-storage service:
replace the dependency condition "service_healthy" referencing
supabase-postgrest with "service_started" so supabase-storage uses
service_started instead of waiting for a healthcheck; locate the block that
lists the supabase-storage dependency on supabase-postgrest and change the
condition accordingly.
- Around line 1311-1312: Services cannot resolve the hostname supabase-kong
because they are not on the same Docker network; update the docker-compose
service network membership for extract-worker, supaserch, and jellyfin-bridge to
also include the pmoves_api network (in addition to pmoves_app, pmoves_bus, and
pmoves_external for jellyfin-bridge) so they can reach
http://supabase-kong:8000, or alternatively change the SUPA_REST_URL and
SUPA_REST_INTERNAL_URL environment variables used by those services to a
host-routable endpoint; locate the env vars SUPA_REST_URL and
SUPA_REST_INTERNAL_URL and the service blocks named extract-worker, supaserch,
and jellyfin-bridge to apply the change.
- Around line 781-795: supabase-studio cannot reach supabase-meta and
supabase-analytics because they are on different Docker networks (pmoves_api vs
pmoves_data) and LOGFLARE_NODE_HOST=127.0.0.1 prevents external container
binding; update the docker-compose service definitions so supabase-studio is
attached to the same network as supabase-meta and supabase-analytics (or add the
other services to a shared network) and change the analytics binding from
LOGFLARE_NODE_HOST=127.0.0.1 to LOGFLARE_NODE_HOST=0.0.0.0; also verify
STUDIO_PG_META_URL and LOGFLARE_URL point to the service hostnames
(supabase-meta, supabase-analytics) so supabase-studio can resolve them.
- Line 891: Update the Postgres URI environment variables so the password
fallback uses the URL-encoded variant; specifically, replace uses of plain
POSTGRES_PASSWORD/ SUPABASE_DB_PASSWORD in the SUPABASE_DB_URL (and the two
other Postgres connection string variables noted) with the URL-encoded fallback
pattern (POSTGRES_PASSWORD_URLENCODED) like the other services do; ensure the
variable names referenced in the docker-compose lines (e.g., SUPABASE_DB_URL and
the two other Postgres connection string env vars) include the
POSTGRES_PASSWORD_URLENCODED fallback to avoid unescaped '/' and '+' from
generate-keys.sh breaking the URI.
- Around line 887-892: The supabase-edge-functions service only joins the
pmoves_api network but needs access to pmoves_data for name resolution to
supabase-db and supabase-analytics; update the supabase-edge-functions service
definition to include both networks (pmoves_api and pmoves_data) in its networks
list and ensure pmoves_data is declared in the compose file so the service can
resolve supabase-db and supabase-analytics at runtime.

In `@pmoves/env.tier-supabase.example`:
- Around line 55-62: The GOTRUE_API_EXTERNAL_URL legacy alias currently points
at direct GoTrue on port 9999; update it to use the canonical gateway URL (the
same host/port used by SUPABASE_PUBLIC_URL / SUPABASE_SITE_URL, e.g. port 8000)
so all public auth endpoints share the same external surface. Locate the
GOTRUE_API_EXTERNAL_URL entry and replace its value with the
SUPABASE_PUBLIC_URL/gateway value (matching SUPABASE_SITE_URL and
GOTRUE_SITE_URL) to eliminate the split external surface.

In `@pmoves/integrations/firefly-iii/n8n/flows/finance_health_crosswalk.json`:
- Around line 54-67: The request URL for the WGER workout fetch currently points
only to "/api/v2/workoutsession/" and lacks query parameters to limit results to
the last 30 days; update the "url" parameter used to call the workoutsession
endpoint so it includes start/end date query params computed at runtime (e.g.
using n8n expressions/moment) to enforce the same 30-day window described later
in the flow, ensuring the "url" string in the node's parameters contains those
date-based query parameters.
- Around line 90-92: The URL construction in the flow's parameters.url is
appending "/rest/v1" unconditionally which duplicates the path when
SUPA_REST_URL already contains "/rest/v1" (as set in pmoves.ps1); update the
parameters.url in the finance_health_crosswalk flow to avoid double "/rest/v1"
by either using SUPA_REST_URL as the full REST base (remove the appended
"/rest/v1" so the path becomes "={{ $env.SUPA_REST_URL ||
'http://supabase-postgrest:3000' }}/health_finance_crosswalk") or change
pmoves.ps1 to set SUPA_REST_URL without "/rest/v1" and keep the current
concatenation—adjust whichever side (parameters.url or pmoves.ps1) to ensure
only one "/rest/v1" is present; target the parameters.url entry in the
finance_health_crosswalk flow and the SUPA_REST_URL assignment in pmoves.ps1 to
make the change.

In `@pmoves/integrations/health-wger/n8n/flows/health_to_research.json`:
- Around line 39-48: The Trigger DeepResearch node is using {{
$json.anomaly_type }} but only receives output from Fetch Recent Workouts, so
anomaly_type from the NATS Trigger is lost; fix by carrying the NATS Trigger
payload forward (e.g., modify the Fetch Recent Workouts node to merge/append the
incoming NATS Trigger data into its output), or add a Merge node that combines
the NATS Trigger output with Fetch Recent Workouts before the Trigger
DeepResearch node, or change the Trigger DeepResearch node to explicitly
reference the NATS Trigger output; update the flow so the node names involved
are NATS Trigger, Fetch Recent Workouts, Merge (if added), and Trigger
DeepResearch and ensure anomaly_type is present in the payload passed to Trigger
DeepResearch.
- Around line 14-30: Add a queryParameters block to the HTTP request node
(alongside the existing headerParameters) that filters workouts to the past 7
days: create a query parameter (use the Wger API's date filter key, e.g.,
creation_date_after or date_after) and set its value to an n8n expression that
computes the ISO date seven days ago; keep the existing
options.queryParameterArrays setting so the parameter is sent correctly and do
not hard-code the date into parameters.url.

In `@pmoves/integrations/health-wger/n8n/flows/integration_status_reporter.json`:
- Around line 63-85: The Discord POST is using {{ $json.wger_status }}, {{
$json.firefly_status }}, and {{ $json.nats_status }}, but the merged output from
the "Merge Results" node (id "merge-1") never maps the three HTTP check results
into those named fields; add a follow-up mapping step (e.g., a Set or Function
node immediately after merge-1) that reads the merged check results and
normalizes them into explicit keys wger_status, firefly_status, and nats_status
(derive values from the merged items' response/status fields or boolean checks),
so the HTTP Request node that posts to DISCORD_WEBHOOK_URL can reference those
normalized fields instead of falling back to 'unknown'.

In `@pmoves/integrations/health-wger/n8n/flows/voice_health_checkin.json`:
- Around line 17-46: The Discord "sent" notification is unconditionally
triggered from the "Fetch Last Workout" branch even when the "Generate Voice
Prompt" (id: voice-prompt-1, name: "Generate Voice Prompt") fails; modify the
flow so the Discord Notification node only receives the success path of the
voice branch: add or update an IF/conditional node after "Generate Voice Prompt"
(or use the httpRequest's success output) to check for a successful synthesis
(e.g., HTTP 2xx or presence of audio payload) and wire only that success output
into the Discord Notification node, leaving error/failure outputs to a separate
handler or to stop propagation from "Generate Voice Prompt"; ensure the same
gating is applied wherever Discord Notification is currently connected
(including flows originating at "Fetch Last Workout" and the other referenced
ranges).

In `@pmoves/Makefile`:
- Around line 1313-1323: The current Makefile check only looks for legacy
placeholders in env.tier-supabase and will skip regeneration even when new
required secrets are missing; update the populate logic that checks
env.tier-supabase to verify presence (and non-empty values) of the new required
keys SECRET_KEY_BASE, VAULT_ENC_KEY, and PG_META_CRYPTO_KEY in addition to the
old placeholders, and if any are absent or empty invoke
scripts/supabase/generate-keys.sh to regenerate/populate env.tier-supabase
(keeping the existing messaging flow and fallback that suggests running 'make
supa-init' if generate-keys.sh is missing).
- Around line 639-641: The supabase-clean Makefile target currently uses $(DC)
--profile supabase-local down which also brings down unprofiled default
services; change it to target only Supabase by either invoking compose with a
Supabase-only file (e.g., use $(DC) -f docker-compose.supabase.yml down -v
--remove-orphans) or explicitly stop/remove only the Supabase service names (use
$(DC) stop <supabase-service-list> && $(DC) rm -f <supabase-service-list>)
instead of relying on --profile; update the supabase-clean recipe (the target
name supabase-clean and the $(DC) invocation) to use one of these approaches so
only Supabase containers/volumes are removed.

In `@pmoves/scripts/supabase/generate-keys.sh`:
- Around line 42-49: The current use of command substitutions inside local
assignments (variables header, payload, signature and the use of signing_input)
masks failures from b64_encode/openssl; change each "local var=$(...)" into a
two-step pattern: first declare the variable with local header payload signature
signing_input, then perform the command substitution on a separate line
(header=$(...)) so that any non-zero exit from b64_encode or openssl is
propagated and causes the script to fail under set -euo pipefail; ensure you
keep the same transformations (tr -d '=' and '/+' -> '_-') and validate or exit
if any of those commands fail.

In `@pmoves/tools/tac_runner.py`:
- Around line 66-82: The _check_command function currently calls subprocess.run
with shell=True (in subprocess.run), which is a command-injection risk; change
it to invoke subprocess.run with shell=False and pass a parsed argument list
using shlex.split(target) (or otherwise construct a safe list) so the call uses
subprocess.run(args, shell=False, ...). If any commands legitimately require
shell features (pipes/redirection), either explicitly detect/allow them with a
documented whitelist or require TAC trees to be trusted; update the function's
docstring/comments to note this constraint and adjust error handling for
argument parsing failures.

---

Outside diff comments:
In `@pmoves/bootstrap/registry.json`:
- Around line 511-540: The SUPABASE_ANON_KEY and SUPABASE_SERVICE_ROLE_KEY
entries in env.jellyfin-ai still inherit from pmoves/.env.local but the
canonical values now live in pmoves/env.tier-supabase under keys ANON_KEY and
SERVICE_ROLE_KEY; update the inherit blocks for the SUPABASE_ANON_KEY and
SUPABASE_SERVICE_ROLE_KEY entries to point to file "pmoves/env.tier-supabase"
and the corresponding keys "ANON_KEY" and "SERVICE_ROLE_KEY" so env.jellyfin-ai
can resolve the required Supabase credentials.

In `@pmoves/Makefile`:
- Around line 1303-1304: Replace the raw sourcing in the populate-tier-envs
Makefile recipe (currently using ". ./env.shared" and ". ./.env.local") with the
safe loader script by invoking scripts/with-env.sh to load env.shared and
.env.local; update the populate-tier-envs recipe to call scripts/with-env.sh
with those filenames so multiline values, special characters, and shell
metacharacters are handled, whitespace is stripped, and history expansion is
disabled while preserving the original environment-loading behavior.

In `@pmoves/scripts/pmoves.ps1`:
- Around line 20-42: The current commands start the Supabase CLI when available
(in the "up-fullsupabase" branch using supabase start and mapping
SUPA_REST_URL/SUPABASE_* envs) but the tear-down commands
("down-fullsupabase"/"clean-fullsupabase") only run Compose --profile
supabase-local down, leaving the CLI-managed Supabase stack running; update the
down/clean-fullsupabase logic to detect the Supabase CLI (Get-Command supabase
-ErrorAction SilentlyContinue) and when present call supabase stop (or check
supabase status and stop only if running) in addition to or instead of Compose
--profile supabase-local down, so both CLI-started and compose-started Supabase
stacks are properly stopped.

---

Nitpick comments:
In @.claude/commands/tac/review.md:
- Around line 19-27: The docs currently tell users to run
pmoves/tools/tac_runner.py twice (once with --format text and once without)
which can re-execute command actions defined by pmoves/configs/tac_schema.yaml;
change tac_runner.py so it performs a single execution of the TAC tree and then
renders both views from that single result (e.g., capture the execution
output/result object in the main run function and call the existing text-render
and json-render routines on that object rather than re-running the tree), and
update any CLI option handling to allow a combined output mode or to always
produce both formats when requested.

In `@PMOVES-Wealth`:
- Line 1: Add a clear PR description entry documenting the PMOVES-Wealth
submodule update: state the updated submodule name "PMOVES-Wealth", include the
new commit hash or tag, summarize what changed in that submodule
(features/bugfixes/APIs), call out any compatibility or breaking changes that
affect this PR (public function/class/API surface), and list required developer
actions (build, migration, or test steps) so reviewers can validate the update.

In `@pmoves/docs/integrations/FIREFLY_WGER_INTEGRATIONS_STATUS.md`:
- Around line 27-53: The Markdown tables under "Health Domain
(pmoves/integrations/health-wger/n8n/flows/)" (the table listing workflows like
`health_wger_sync.json`, `wger_sync_to_supabase.json`, etc.) and "Finance Domain
(pmoves/integrations/firefly-iii/n8n/flows/)" (the table listing workflows like
`finance_firefly_sync.json`, `firefly_sync_to_supabase.json`, etc.) need blank
lines before and after each table per markdownlint MD058; update the document by
inserting a single empty line above the header row and a single empty line after
the closing table row for both tables so they are properly separated from
surrounding headings and paragraphs.

In `@pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md`:
- Around line 34-38: Update the fenced code block containing the migration
filename examples to include a language specifier (e.g., add "text" after the
opening backticks) so syntax highlighting and renderer treat it as plain text;
modify the block that shows "20250115000000_service_catalog.sql …
2025-09-08_geometry_bus.sql" in MIGRATION_WORKFLOW.md to start with ```text
instead of ``` to apply the fix.
- Around line 23-29: The fenced code block in MIGRATION_WORKFLOW.md is missing a
language specifier (MD040); update the opening fence (the triple backticks) to
include an appropriate language token (e.g., text) so the block becomes ```text,
ensuring proper syntax highlighting for the listed filenames like
00_pmoves_schema.sql and 17_persona_seed.sql; leave the block contents unchanged
and only modify the opening fence.

In `@pmoves/integrations/firefly-iii/auth/bootstrap.sh`:
- Around line 38-54: The script currently checks the FIREFLY_TOKEN by storing
HTTP status in STATUS and only treats "401" as invalid; update the conditional
around STATUS (the if/elif/else block that echoes token validity) to also treat
"403" as an invalid token like "401" (either by adding an elif for "$STATUS" =
"403" or by checking both values together) so that the failure message and exit
behavior for invalid tokens matches the health-wger bootstrap handling.

In `@pmoves/tools/tac_runner.py`:
- Around line 105-114: The grep inversion currently infers intent by
string-matching the action's "expect" text which is fragile; update the runner
to support an explicit boolean invert flag on the action (e.g.,
action.get("invert", False)) and use that to decide inversion instead of
checking substrings of expect. Locate the grep handling block around _check_grep
and replace the conditional that inspects expect ("Should NOT contain" / "No ")
with logic that reads action.get("invert", False) and then set result["status"]
= "fail" if status == "pass" when invert is True (otherwise keep status), and
always copy result["detail"] from the _check_grep return. Ensure backwards
compatibility by keeping the original behavior only if you choose to, but prefer
the explicit invert flag for new checks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 389c8bcb-7866-45e8-8ec0-12213bb26187

📥 Commits

Reviewing files that changed from the base of the PR and between ff7e86a and d4bc8ec.

📒 Files selected for processing (32)
  • .claude/CLAUDE.md
  • .claude/commands/tac/review.md
  • PMOVES-Wealth
  • Pmoves-Health-wger
  • pmoves/Makefile
  • pmoves/README.md
  • pmoves/bootstrap/registry.json
  • pmoves/configs/skill-pairings.yaml
  • pmoves/configs/submodule_skill_registry.json
  • pmoves/configs/tac_schema.yaml
  • pmoves/configs/tac_trees/firefly-iii.tac.yaml
  • pmoves/configs/tac_trees/health-wger.tac.yaml
  • pmoves/configs/tac_trees/n8n.tac.yaml
  • pmoves/docker-compose.supabase.yml
  • pmoves/docker-compose.vps.override.yml
  • pmoves/docker-compose.yml
  • pmoves/docs/integrations/FIREFLY_WGER_INTEGRATIONS_STATUS.md
  • pmoves/docs/operations/SEEDED_BRANDED_DEFAULTS.md
  • pmoves/docs/services/supabase/MIGRATION_WORKFLOW.md
  • pmoves/env.tier-supabase.example
  • pmoves/integrations/firefly-iii/auth/bootstrap.sh
  • pmoves/integrations/firefly-iii/events/subjects.yaml
  • pmoves/integrations/firefly-iii/n8n/flows/finance_health_crosswalk.json
  • pmoves/integrations/health-wger/auth/bootstrap.sh
  • pmoves/integrations/health-wger/events/subjects.yaml
  • pmoves/integrations/health-wger/n8n/flows/health_to_research.json
  • pmoves/integrations/health-wger/n8n/flows/integration_status_reporter.json
  • pmoves/integrations/health-wger/n8n/flows/voice_health_checkin.json
  • pmoves/scripts/pmoves.ps1
  • pmoves/scripts/supabase/generate-keys.sh
  • pmoves/tools/brand_defaults.py
  • pmoves/tools/tac_runner.py
💤 Files with no reviewable changes (1)
  • pmoves/docker-compose.supabase.yml

Comment on lines +40 to +61
"key": "ANON_KEY",
"file": "pmoves/env.tier-supabase",
"prompt": "Supabase anon key (JWT token)",
"help": "JWT signed with JWT_SECRET, role=anon. Generate via scripts/supabase/generate-keys.sh",
"required": true,
"type": "url"
"sensitive": true,
"generate": {
"type": "random_urlsafe",
"length": 64
}
},
{
"key": "SUPABASE_STORAGE_URL",
"file": "pmoves/.env.local",
"prompt": "Supabase storage URL",
"default": "http://localhost:5000",
"help": "Storage service base URL exposed by Supabase CLI.",
"key": "SERVICE_ROLE_KEY",
"file": "pmoves/env.tier-supabase",
"prompt": "Supabase service role key (JWT token)",
"help": "JWT signed with JWT_SECRET, role=service_role. Generate via scripts/supabase/generate-keys.sh",
"required": true,
"type": "url"
"sensitive": true,
"generate": {
"type": "random_urlsafe",
"length": 64
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Relevant generator references ==\n'
rg -n -C3 'random_urlsafe|random_hex|laravel_app_key|ANON_KEY|SERVICE_ROLE_KEY|JWT_SECRET|generate-keys\.sh' pmoves

printf '\n== Supabase key generation script ==\n'
fd '^generate-keys\.sh$' pmoves -t f -x sed -n '1,240p' {}

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Finding generate-keys.sh ==\n'
find . -name 'generate-keys.sh' -type f

printf '\n== Finding populate-tier-envs or registry consumer ==\n'
fd -t f -e py -e sh | xargs grep -l 'populate-tier-envs\|populate_tier_envs' 2>/dev/null | head -5

printf '\n== Searching for registry consumer/bootstrap code ==\n'
fd -t f -e py -e sh | xargs grep -l '"generate".*"type"\|random_urlsafe' 2>/dev/null | head -10

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 198


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Look for Supabase key generation logic - check bootstrap/registry handling
printf '\n== Examining bootstrap/registry.json structure ==\n'
head -100 pmoves/bootstrap/registry.json

printf '\n== Looking for bootstrap/registry consumer code ==\n'
fd 'registry' -t f pmoves/bootstrap/ | grep -E '\.(py|sh|ts|js)$'

printf '\n== Search for code that processes generate directives ==\n'
rg -l 'random_urlsafe|generate.*type' --type py --type sh pmoves/bootstrap/ pmoves/tools/ 2>/dev/null | head -5

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 3562


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Reading generate-keys.sh ==\n'
wc -l pmoves/scripts/supabase/generate-keys.sh
sed -n '1,100p' pmoves/scripts/supabase/generate-keys.sh

printf '\n== Searching for bootstrap registry consumer ==\n'
find pmoves/bootstrap -type f \( -name '*.py' -o -name '*.sh' \) 2>/dev/null

printf '\n== Searching for code that processes registry.json ==\n'
rg -n 'registry\.json|"generate"|random_urlsafe' --type py --type sh pmoves/tools/ pmoves/bootstrap/ 2>/dev/null | head -40

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4352


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Search credential_setup.py for registry consumption ==\n'
rg -n 'registry|generate|random_urlsafe' pmoves/tools/credential_setup.py | head -20

printf '\n== Check if there is a bootstrap runner ==\n'
find pmoves -name '*bootstrap*' -type f | head -10

printf '\n== Look at env setup tools ==\n'
ls -la pmoves/tools/ | grep -E 'env|setup|populate'

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2096


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Examining env_setup_unified.py ==\n'
wc -l pmoves/tools/env_setup_unified.py
sed -n '1,150p' pmoves/tools/env_setup_unified.py

printf '\n== Check bootstrap_light_env.py for registry usage ==\n'
sed -n '1,150p' pmoves/tools/bootstrap_light_env.py

printf '\n== Search for where registry.json "generate" is consumed ==\n'
rg -n '"generate"' pmoves/tools/ pmoves/scripts/ -A 3 -B 3

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 11995


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Examining bootstrap_env.py generate_value function ==\n'
sed -n '1,50p' pmoves/scripts/bootstrap_env.py

printf '\n== Finding generate_value function ==\n'
rg -n 'def generate_value' pmoves/scripts/bootstrap_env.py -A 20

printf '\n== Check full context around line 366-370 ==\n'
sed -n '350,400p' pmoves/scripts/bootstrap_env.py

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4548


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Verify: does bootstrap_env.py have a JWT generator type? ==\n'
rg 'jwt|HS256|hmac|sign' pmoves/scripts/bootstrap_env.py

printf '\n== Confirm: what does the actual registry entries look like ==\n'
sed -n '40,65p' pmoves/bootstrap/registry.json

printf '\n== Verify: is there any other code that handles JWT generation for these keys? ==\n'
rg -n 'ANON_KEY|SERVICE_ROLE_KEY' pmoves/scripts/bootstrap_env.py

printf '\n== Check if generate-keys.sh is invoked anywhere in bootstrap flow ==\n'
rg -n 'generate-keys\.sh' pmoves/scripts/bootstrap_env.py pmoves/tools/env_setup_unified.py

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 130


🏁 Script executed:

#!/bin/bash
set -euoripefail

printf '\n== Registry entries for ANON_KEY and SERVICE_ROLE_KEY ==\n'
jq '.services[] | select(.id == "supabase") | .variables[] | select(.key == "ANON_KEY" or .key == "SERVICE_ROLE_KEY")' pmoves/bootstrap/registry.json

printf '\n== Confirm generate_value supports JWT generation ==\n'
sed -n '54,74p' pmoves/scripts/bootstrap_env.py

printf '\n== Check if generate-keys.sh is called anywhere ==\n'
rg -r 'generate-keys\.sh' pmoves/ --type py --type sh 2>/dev/null | head -20

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 741


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Registry entries for ANON_KEY and SERVICE_ROLE_KEY ==\n'
jq '.services[] | select(.id == "supabase") | .variables[] | select(.key == "ANON_KEY" or .key == "SERVICE_ROLE_KEY")' pmoves/bootstrap/registry.json

printf '\n== Confirm generate_value only supports these types ==\n'
sed -n '54,74p' pmoves/scripts/bootstrap_env.py

printf '\n== Check if generate-keys.sh is called anywhere in bootstrap ==\n'
rg 'generate-keys' pmoves/scripts/ pmoves/tools/ 2>/dev/null | head -20

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 1953


Fix registry entries for ANON_KEY and SERVICE_ROLE_KEY: use JWT generator or remove auto-generation.

The registry defines "generate": {"type": "random_urlsafe"} for both keys, but bootstrap_env.py's generate_value() function does not support JWT signing. This will emit plain random strings instead of HS256-signed JWTs as documented in the help text. The generate-keys.sh script has the correct JWT implementation (generate_jwt_token() with HMAC-SHA256), but bootstrap never invokes it.

Either:

  1. Add a JWT generator type to bootstrap_env.py that accepts a secret parameter and signs payloads
  2. Remove the "generate" field from these entries and require manual invocation of generate-keys.sh
  3. Update the help text to clarify that random_urlsafe is used, not JWT signing
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/bootstrap/registry.json` around lines 40 - 61, The registry entries
for ANON_KEY and SERVICE_ROLE_KEY are set to use "generate":
{"type":"random_urlsafe"} but bootstrap_env.py's generate_value() does not
produce HS256-signed JWTs (so it will emit plain random strings instead of the
JWTs described in the help); fix by either (A) adding a JWT generator branch in
bootstrap_env.py (implement a generate type like "jwt" that calls a signing
routine similar to scripts/supabase/generate-keys.sh's generate_jwt_token(),
accepting the secret param/JWT_SECRET and producing an HS256 token) and change
the registry entries' generate.type to "jwt" with any required params, or (B)
remove the generate block from the ANON_KEY and SERVICE_ROLE_KEY registry
entries and leave help text as-is so keys must be produced by
scripts/supabase/generate-keys.sh, or (C) keep random_urlsafe but update the
help text to state that a random token (not a signed JWT) will be generated;
reference symbols: ANON_KEY, SERVICE_ROLE_KEY, generate_value(),
bootstrap_env.py, generate_jwt_token(), scripts/supabase/generate-keys.sh.

Comment on lines +18 to +19
"finance": ["chit/floos", "n8n/execute", "deploy/up"],
"health": ["n8n/execute", "deploy/up"],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

$domain_tag_skill_map.health is missing the new health/quick skill.

Pmoves-Health-wger now advertises health/quick, but domain-based discovery for health will never surface it from this source-of-truth map.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/configs/submodule_skill_registry.json` around lines 18 - 19, The
domain-tag skill map entry for "health" is missing the new "health/quick" skill;
update the JSON object key "health" (the $domain_tag_skill_map.health array) to
include "health/quick" alongside the existing entries (e.g., ["n8n/execute",
"deploy/up", "health/quick"]) so domain-based discovery will surface the
Pmoves-Health-wger advertised skill.

Comment thread pmoves/docker-compose.yml
Comment on lines +681 to 683
- DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime
- DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:-supabaserealtime}
# App configuration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fail hard instead of booting Realtime with a known encryption key.

supabaserealtime is a predictable fallback for DB_ENC_KEY. That weakens tenant-data protection whenever env generation is skipped or incomplete.

Suggested fix
-    - DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:-supabaserealtime}
+    - DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:?Set SUPABASE_REALTIME_SECRET in env.tier-supabase}

As per coding guidelines, pmoves/docker-compose*.yml: Flag hardcoded credentials/default secrets in environment blocks.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime
- DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:-supabaserealtime}
# App configuration
- DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime
- DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:?Set SUPABASE_REALTIME_SECRET in env.tier-supabase}
# App configuration
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docker-compose.yml` around lines 681 - 683, Replace the hardcoded
fallback for DB_ENC_KEY so the service does not boot with a known secret: remove
the default value "${SUPABASE_REALTIME_SECRET:-supabaserealtime}" and require
the env var be provided (e.g., use DB_ENC_KEY=${SUPABASE_REALTIME_SECRET}), or
add a startup validation that exits if SUPABASE_REALTIME_SECRET equals the
insecure literal; update the docker-compose environment entry for DB_ENC_KEY and
any related startup/entrypoint logic that checks DB_ENC_KEY to fail fast when
the secret is missing or still the insecure default.

Comment thread pmoves/docker-compose.yml Outdated
Comment thread pmoves/docker-compose.yml
Comment on lines +781 to +795
# Postgres Meta connection (Studio uses pg-meta, not PostgREST directly)
- STUDIO_PG_META_URL=http://supabase-meta:8080
# Auth / Kong gateway
- SUPABASE_URL=http://supabase-kong:8000
- SUPABASE_PUBLIC_URL=${API_EXTERNAL_URL:-${SUPABASE_PUBLIC_URL:-}}
- SUPABASE_ANON_KEY=${SUPABASE_ANON_KEY:-${ANON_KEY:-${SUPABASE_PUBLISHABLE_KEY:-}}}
- SUPABASE_ANON_KEY=${ANON_KEY:-${SUPABASE_ANON_KEY:-}}
- SUPABASE_SERVICE_KEY=${SERVICE_ROLE_KEY:-${SUPABASE_SERVICE_ROLE_KEY:-}}
- AUTH_JWT_SECRET=${JWT_SECRET:-${SUPABASE_JWT_SECRET:-}}
- PG_META_CRYPTO_KEY=${PG_META_CRYPTO_KEY:-}
# Analytics (Logflare) integration
- LOGFLARE_PUBLIC_ACCESS_TOKEN=${LOGFLARE_PUBLIC_ACCESS_TOKEN:-}
- LOGFLARE_PRIVATE_ACCESS_TOKEN=${LOGFLARE_PRIVATE_ACCESS_TOKEN:-}
- LOGFLARE_URL=http://supabase-analytics:4000
- NEXT_PUBLIC_ENABLE_LOGS=true
- NEXT_ANALYTICS_BACKEND_PROVIDER=postgres

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "docker-compose.yml" -path "*/pmoves/*" | head -5

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 210


🏁 Script executed:

wc -l ./pmoves/docker-compose.yml

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 99


🏁 Script executed:

sed -n '750,850p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4512


🏁 Script executed:

sed -n '850,950p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 4775


🏁 Script executed:

# Check the "Also applies to" line ranges mentioned
echo "=== Lines 811-816 ===" && sed -n '811,816p' ./pmoves/docker-compose.yml | cat -n
echo "=== Lines 819-820 ===" && sed -n '819,820p' ./pmoves/docker-compose.yml | cat -n
echo "=== Lines 874-875 ===" && sed -n '874,875p' ./pmoves/docker-compose.yml | cat -n
echo "=== Lines 915-916 ===" && sed -n '915,916p' ./pmoves/docker-compose.yml | cat -n
echo "=== Lines 939-940 ===" && sed -n '939,940p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 596


🏁 Script executed:

# Check if supabase-analytics and supabase-meta have published ports
echo "=== supabase-analytics service (lines 900-950) ===" && sed -n '900,950p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2412


🏁 Script executed:

# Check if supabase-meta or supabase-analytics have ports sections
echo "=== supabase-meta full definition ===" && sed -n '851,876p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 1110


🏁 Script executed:

# Verify supabase-studio environment variables and network dependencies
echo "=== supabase-studio full definition (lines 774-820) ===" && sed -n '774,820p' ./pmoves/docker-compose.yml | cat -n

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2407


supabase-studio cannot reach its dependencies supabase-meta and supabase-analytics due to network isolation and binding restrictions.

supabase-studio is only on pmoves_api, while both supabase-meta and supabase-analytics are only on pmoves_data. Additionally, LOGFLARE_NODE_HOST=127.0.0.1 restricts analytics to localhost binding, preventing inter-container communication even if networks were shared.

Fix
  supabase-meta:
    networks:
+    - pmoves_api
     - pmoves_data

  supabase-analytics:
    environment:
-    - LOGFLARE_NODE_HOST=127.0.0.1
+    - LOGFLARE_NODE_HOST=0.0.0.0
    networks:
+    - pmoves_api
     - pmoves_data
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docker-compose.yml` around lines 781 - 795, supabase-studio cannot
reach supabase-meta and supabase-analytics because they are on different Docker
networks (pmoves_api vs pmoves_data) and LOGFLARE_NODE_HOST=127.0.0.1 prevents
external container binding; update the docker-compose service definitions so
supabase-studio is attached to the same network as supabase-meta and
supabase-analytics (or add the other services to a shared network) and change
the analytics binding from LOGFLARE_NODE_HOST=127.0.0.1 to
LOGFLARE_NODE_HOST=0.0.0.0; also verify STUDIO_PG_META_URL and LOGFLARE_URL
point to the service hostnames (supabase-meta, supabase-analytics) so
supabase-studio can resolve them.

Comment on lines +17 to +46
{
"parameters": {
"url": "http://flute-gateway:8055/v1/voice/synthesize/prosodic",
"method": "POST",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "text",
"value": "Good morning. How are you feeling today? Did you complete any workouts yesterday? Any pain or discomfort to report?"
},
{
"name": "voice_id",
"value": "default"
},
{
"name": "format",
"value": "wav"
}
]
},
"options": {}
},
"id": "voice-prompt-1",
"name": "Generate Voice Prompt",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [470, 300],
"notes": "Synthesize check-in prompt via Flute-Gateway prosodic API"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Gate the “sent” notification on the voice branch.

Lines 119-123 only feed “Discord Notification” from “Fetch Last Workout”. If “Generate Voice Prompt” fails, Line 92 still posts that the daily check-in was sent.

Also applies to: 83-92, 110-123

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/integrations/health-wger/n8n/flows/voice_health_checkin.json` around
lines 17 - 46, The Discord "sent" notification is unconditionally triggered from
the "Fetch Last Workout" branch even when the "Generate Voice Prompt" (id:
voice-prompt-1, name: "Generate Voice Prompt") fails; modify the flow so the
Discord Notification node only receives the success path of the voice branch:
add or update an IF/conditional node after "Generate Voice Prompt" (or use the
httpRequest's success output) to check for a successful synthesis (e.g., HTTP
2xx or presence of audio payload) and wire only that success output into the
Discord Notification node, leaving error/failure outputs to a separate handler
or to stop propagation from "Generate Voice Prompt"; ensure the same gating is
applied wherever Discord Notification is currently connected (including flows
originating at "Fetch Last Workout" and the other referenced ranges).

Comment thread pmoves/Makefile
Comment on lines +639 to +641
supabase-clean: ## Stop + remove Supabase containers and volumes
@$(DC) --profile supabase-local down -v --remove-orphans >/dev/null 2>&1 || true
@echo "✅ Supabase stack cleaned"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the definition of $(DC) in the Makefile
rg "^\s*DC\s*:=" pmoves/Makefile

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 167


🏁 Script executed:

# Look at the docker-compose configuration to understand profiles
fd "docker-compose" pmoves/

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2625


🏁 Script executed:

# Search for compose files in the repository
fd -e yml -e yaml | grep -i compose

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2938


🏁 Script executed:

# Look for services in compose files and their profile definitions
rg "services:|profile:" pmoves/docker-compose.yml -A 2 -B 2 | head -100

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 724


🏁 Script executed:

# Search for Supabase-related services and profile definitions
rg "supabase-local" pmoves/

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2546


🏁 Script executed:

# Get a general overview of the main docker-compose.yml file
wc -l pmoves/docker-compose.yml && head -50 pmoves/docker-compose.yml

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2281


🏁 Script executed:

# Extract all service definitions and check which ones have profiles
python3 << 'EOF'
import yaml
import sys

with open('pmoves/docker-compose.yml', 'r') as f:
    content = yaml.safe_load(f)

services = content.get('services', {})
unprofiled_services = []
supabase_services = []

for service_name, service_def in services.items():
    profiles = service_def.get('profiles', [])
    if not profiles:
        unprofiled_services.append(service_name)
    elif 'supabase-local' in profiles:
        supabase_services.append(service_name)

print(f"Services with NO profile attribute ({len(unprofiled_services)}):")
for svc in sorted(unprofiled_services)[:20]:
    print(f"  - {svc}")

if len(unprofiled_services) > 20:
    print(f"  ... and {len(unprofiled_services) - 20} more")

print(f"\nServices in 'supabase-local' profile ({len(supabase_services)}):")
for svc in sorted(supabase_services):
    print(f"  - {svc}")
EOF

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 740


🏁 Script executed:

# Verify Docker Compose profile behavior by checking documentation/examples
# Let's also check if there's any STACK_FILES variable that might add extra services
rg "STACK_FILES" pmoves/Makefile -B 2 -A 2

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 808


🏁 Script executed:

# Check the full STACK_FILES definition in the Makefile
grep -A 30 "STACK_FILES \?=" pmoves/Makefile

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 49


🌐 Web query:

Docker Compose profile behavior default services no profile

💡 Result:

  • Services with no profiles: key are “default” services: if you run docker compose up without --profile (and without COMPOSE_PROFILES), Compose includes all services that have no profiles and excludes services that do declare profiles. [1][2]
  • Activating profiles doesn’t disable defaults: when you run docker compose --profile <name> up, Compose starts the default (no-profile) services plus the services in the enabled profile(s). [1][2]
  • Explicitly targeting a profiled service overrides profile activation: docker compose up myprofiledservice runs that service even if you didn’t enable its profile (Compose treats the service’s profile as active for that run). [1][2]
  • Dependencies matter: if an enabled service has depends_on a service that’s excluded by an inactive profile, the resulting model can be invalid (i.e., you must enable whatever profiles are needed to satisfy depends_on, or restructure). [2]

Sources: Docker Compose profiles docs. [1][2]


🏁 Script executed:

# Verify STACK_FILES more carefully
cat pmoves/Makefile | grep -A 40 "STACK_FILES"

Repository: POWERFULMOVES/PMOVES.AI

Length of output: 2095


supabase-clean tears down the entire stack, not just Supabase.

Services with no profile (qdrant, neo4j, meilisearch, nats, minio, hi-rag-gateway, tensorzero-gateway, and others) are default services that are always included when docker compose down runs. The --profile supabase-local flag activates the Supabase profile but does not exclude default services—it activates the profile in addition to running all unprofiled services. Therefore, $(DC) --profile supabase-local down -v --remove-orphans will stop and remove both the 13 Supabase services and the 19 core infrastructure services.

Use a separate compose file or an explicit service list instead of relying on the profile to isolate the target.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 639 - 641, The supabase-clean Makefile target
currently uses $(DC) --profile supabase-local down which also brings down
unprofiled default services; change it to target only Supabase by either
invoking compose with a Supabase-only file (e.g., use $(DC) -f
docker-compose.supabase.yml down -v --remove-orphans) or explicitly stop/remove
only the Supabase service names (use $(DC) stop <supabase-service-list> && $(DC)
rm -f <supabase-service-list>) instead of relying on --profile; update the
supabase-clean recipe (the target name supabase-clean and the $(DC) invocation)
to use one of these approaches so only Supabase containers/volumes are removed.

Comment thread pmoves/Makefile
Comment on lines +1313 to +1323
if grep -q "your_jwt_secret_here\|your_anon_key_here\|your_service_role_key_here" env.tier-supabase 2>/dev/null; then \
echo "Generating Supabase secrets with proper JWT tokens..."; \
if [ -x scripts/supabase/generate-keys.sh ]; then \
scripts/supabase/generate-keys.sh > env.tier-supabase; \
echo "✓ Populated env.tier-supabase (via generate-keys.sh with valid JWTs)"; \
else \
echo "⚠ scripts/supabase/generate-keys.sh not found — run 'make supa-init' to generate proper JWT keys"; \
fi; \
else \
echo "✓ env.tier-supabase already has real values, skipping"; \
fi; \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

The Supabase placeholder probe won't repair upgraded env files.

This branch only looks for the old JWT/anon/service placeholders. An existing env.tier-supabase can pass that test while still missing new required keys like SECRET_KEY_BASE, VAULT_ENC_KEY, or PG_META_CRYPTO_KEY, so supa-start will still fail after populate-tier-envs says everything is fine.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/Makefile` around lines 1313 - 1323, The current Makefile check only
looks for legacy placeholders in env.tier-supabase and will skip regeneration
even when new required secrets are missing; update the populate logic that
checks env.tier-supabase to verify presence (and non-empty values) of the new
required keys SECRET_KEY_BASE, VAULT_ENC_KEY, and PG_META_CRYPTO_KEY in addition
to the old placeholders, and if any are absent or empty invoke
scripts/supabase/generate-keys.sh to regenerate/populate env.tier-supabase
(keeping the existing messaging flow and fallback that suggests running 'make
supa-init' if generate-keys.sh is missing).

Comment thread pmoves/scripts/supabase/generate-keys.sh Outdated
Comment on lines +66 to +82
def _check_command(target: str) -> tuple[str, str]:
try:
result = subprocess.run(
target,
shell=True,
cwd=str(REPO_ROOT),
capture_output=True,
text=True,
timeout=30,
)
if result.returncode == 0:
return "pass", result.stdout.strip()[:200]
return "fail", result.stderr.strip()[:200]
except subprocess.TimeoutExpired:
return "fail", "command timed out (30s)"
except Exception as e:
return "fail", str(e)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Security consideration: shell=True in subprocess call.

The _check_command function uses shell=True which can execute arbitrary shell commands. While TAC trees are currently repo-controlled, if untrusted YAML files are ever processed, this becomes a command injection vector.

Consider using shlex.split() with shell=False for commands that don't require shell features, or document that TAC trees must be from trusted sources.

🛡️ Safer alternative for simple commands
+import shlex
+
 def _check_command(target: str) -> tuple[str, str]:
     try:
         result = subprocess.run(
-            target,
-            shell=True,
+            shlex.split(target),
+            shell=False,
             cwd=str(REPO_ROOT),
             capture_output=True,
             text=True,
             timeout=30,
         )

Note: This would break commands requiring shell features (pipes, redirects). If shell features are needed, ensure TAC trees are only loaded from trusted paths.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _check_command(target: str) -> tuple[str, str]:
try:
result = subprocess.run(
target,
shell=True,
cwd=str(REPO_ROOT),
capture_output=True,
text=True,
timeout=30,
)
if result.returncode == 0:
return "pass", result.stdout.strip()[:200]
return "fail", result.stderr.strip()[:200]
except subprocess.TimeoutExpired:
return "fail", "command timed out (30s)"
except Exception as e:
return "fail", str(e)
def _check_command(target: str) -> tuple[str, str]:
try:
result = subprocess.run(
shlex.split(target),
shell=False,
cwd=str(REPO_ROOT),
capture_output=True,
text=True,
timeout=30,
)
if result.returncode == 0:
return "pass", result.stdout.strip()[:200]
return "fail", result.stderr.strip()[:200]
except subprocess.TimeoutExpired:
return "fail", "command timed out (30s)"
except Exception as e:
return "fail", str(e)
🧰 Tools
🪛 Ruff (0.15.5)

[error] 68-68: subprocess call with shell=True identified, security issue

(S602)


[warning] 81-81: Do not catch blind exception: Exception

(BLE001)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/tools/tac_runner.py` around lines 66 - 82, The _check_command function
currently calls subprocess.run with shell=True (in subprocess.run), which is a
command-injection risk; change it to invoke subprocess.run with shell=False and
pass a parsed argument list using shlex.split(target) (or otherwise construct a
safe list) so the call uses subprocess.run(args, shell=False, ...). If any
commands legitimately require shell features (pipes/redirection), either
explicitly detect/allow them with a documented whitelist or require TAC trees to
be trusted; update the function's docstring/comments to note this constraint and
adjust error handling for argument parsing failures.

Updates PMOVES-supabase submodule to c84e9d5b which wires real NATS
publishing in pmoves_announcer (replacing no-op stub) and adds UI tier
to pmoves_common.ServiceTier for 7-tier canonical alignment.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Wed Mar 11 14:52:40 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: analysis-echo
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: graph-linker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 120 passed, 40 warnings, 0 errors

hunnibear and others added 2 commits March 11, 2026 10:05
Fix 4 cross-network DNS resolution issues identified in PR #865:

1. supabase-storage: postgrest depends_on service_healthy → service_started
   (distroless image has no shell for healthcheck)
2. supabase-studio: add pmoves_data network (reach supabase-meta, analytics)
3. supabase-edge-functions: add pmoves_data network (reach supabase-db,
   analytics)
4. extract-worker: add pmoves_api network (reach supabase-kong for REST)

Without these fixes, services on different Docker networks cannot resolve
each other's hostnames, causing silent connection failures at runtime.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bash 'local var=$(cmd)' masks the exit code of cmd (local always returns 0).
Split into 'local var; var=$(cmd)' so set -o pipefail correctly propagates
failures from b64_encode and openssl pipelines.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Wed Mar 11 15:06:28 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: analysis-echo
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: graph-linker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 120 passed, 40 warnings, 0 errors

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
pmoves/docker-compose.yml (1)

918-918: ⚠️ Potential issue | 🟠 Major

LOGFLARE_NODE_HOST=127.0.0.1 blocks inter-container traffic.

Logflare binds to localhost, so supabase-studio's LOGFLARE_URL=http://supabase-analytics:4000 (line 793) cannot connect. Per coding guidelines, containers must bind to 0.0.0.0 for in-container accessibility.

Suggested fix
-    - LOGFLARE_NODE_HOST=127.0.0.1
+    - LOGFLARE_NODE_HOST=0.0.0.0
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pmoves/docker-compose.yml` at line 918, LOGFLARE is currently bound to
localhost via the LOGFLARE_NODE_HOST env var which prevents other containers
(e.g., supabase-studio using LOGFLARE_URL=http://supabase-analytics:4000) from
reaching it; change LOGFLARE_NODE_HOST from 127.0.0.1 to 0.0.0.0 so the Logflare
service (supabase-analytics) listens on all interfaces and becomes accessible
from other containers, then restart the compose stack to verify supabase-studio
can connect to LOGFLARE_URL.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@pmoves/docker-compose.yml`:
- Line 918: LOGFLARE is currently bound to localhost via the LOGFLARE_NODE_HOST
env var which prevents other containers (e.g., supabase-studio using
LOGFLARE_URL=http://supabase-analytics:4000) from reaching it; change
LOGFLARE_NODE_HOST from 127.0.0.1 to 0.0.0.0 so the Logflare service
(supabase-analytics) listens on all interfaces and becomes accessible from other
containers, then restart the compose stack to verify supabase-studio can connect
to LOGFLARE_URL.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 00701420-7671-4c08-b9b0-b95e20b427d2

📥 Commits

Reviewing files that changed from the base of the PR and between d4bc8ec and caab0d8.

📒 Files selected for processing (4)
  • .github/workflows/hardening-validation.yml
  • PMOVES-supabase
  • pmoves/docker-compose.yml
  • pmoves/scripts/supabase/generate-keys.sh
✅ Files skipped from review due to trivial changes (1)
  • PMOVES-supabase

Bootstrap scripts:
- Replace no-ops with real validation (APP_KEY, token, health checks)
- Add exit code contract (0=pass, 1=fail, 2=unreachable)
- Write warnings to stderr, handle 5xx/000 HTTP errors
- Firefly: add 403 handling, fail on malformed APP_KEY
- Wger: skip sentinel GENERATE_FROM_WGER_UI token

NATS subjects:
- Add health.workouts.synced.v1, health.weekly.summary.v1,
  health.anomaly.detected.v1 to health-wger
- Add finance.transactions.synced.v1, finance.monthly.summary.v1
  to firefly-iii

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Docker Hardening Validation

Hardening Validation Report

Validated: Wed Mar 11 15:51:03 UTC 2026

Services Checked

PMOVES.AI Docker Hardening Validation

[INFO] Checking: pmoves/docker-compose.hardened.yml

[INFO] Validating: hi-rag-gateway-v2
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: extract-worker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: langextract
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: presign
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: render-webhook
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: retrieval-eval
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pdf-ingest
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: jellyfin-bridge
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: invidious-companion-proxy
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: ffmpeg-whisper
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-video
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: media-audio
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-v2-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: hi-rag-gateway-gpu
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: deepresearch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supaserch
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher-discord
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: mesh-agent
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-req
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: nats-echo-res
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: publisher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: analysis-echo
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: graph-linker
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: comfy-watcher
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: grayjay-plugin-host
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: agent-zero
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: archon
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: channel-monitor
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: pmoves-yt
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: notebook-sync
[PASS] Non-root user: 65532:65532
[PASS] Read-only filesystem
[PASS] All capabilities dropped
[PASS] No-new-privileges enabled
[WARN] No resource limits

[INFO] Validating: supabase_service_role_key
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

[INFO] Validating: supabase_jwt_secret
[WARN] No user directive
[WARN] No read_only directive
[WARN] No cap_drop: ["ALL"]
[WARN] No no-new-privileges
[WARN] No resource limits

======================================
Summary: 120 passed, 40 warnings, 0 errors

@POWERFULMOVES
POWERFULMOVES merged commit 65c3efd into main Mar 11, 2026
19 checks passed
@POWERFULMOVES
POWERFULMOVES deleted the feat/supabase-unify branch March 11, 2026 15:55
POWERFULMOVES pushed a commit that referenced this pull request Mar 11, 2026
Strengthen URL sanitization in chrome-extension options.js from regex
to URL constructor with strict protocol allowlist (http:/https: only).
Update production audit dashboard with Supabase unification milestone
and CodeQL alert resolution status.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Mar 11, 2026
POWERFULMOVES pushed a commit that referenced this pull request Mar 11, 2026
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
POWERFULMOVES added a commit that referenced this pull request Mar 11, 2026
Co-authored-by: Shaela Bello <slbello@uncg.edu>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
POWERFULMOVES pushed a commit that referenced this pull request Mar 13, 2026
Post-unification (PR #865) smoke tests failed because:
- test_env_uses_selfhosted_urls only accepted supabase-postgrest, not supabase-kong
- test_supabase_pg_isready used hardcoded container name instead of resolving from docker ps
- test_supabase_url_consistency didn't accept supabase-kong URL pattern

Also: dashboard header reconciled to ade4248, CodeQL #195 closed,
SUPABASE_REALTIME_ENC_KEY added to bootstrap registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants