feat(supabase): unify 4 runtimes into single canonical compose stack - #865
Conversation
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>
Docker Hardening ValidationHardening Validation ReportValidated: Wed Mar 11 14:28:37 UTC 2026Services CheckedPMOVES.AI Docker Hardening Validation[INFO] Checking: pmoves/docker-compose.hardened.yml [INFO] Validating: hi-rag-gateway-v2 [INFO] Validating: extract-worker [INFO] Validating: langextract [INFO] Validating: presign [INFO] Validating: render-webhook [INFO] Validating: retrieval-eval [INFO] Validating: pdf-ingest [INFO] Validating: jellyfin-bridge [INFO] Validating: invidious-companion-proxy [INFO] Validating: ffmpeg-whisper [INFO] Validating: media-video [INFO] Validating: media-audio [INFO] Validating: hi-rag-gateway-v2-gpu [INFO] Validating: hi-rag-gateway-gpu [INFO] Validating: deepresearch [INFO] Validating: supaserch [INFO] Validating: publisher-discord [INFO] Validating: mesh-agent [INFO] Validating: nats-echo-req [INFO] Validating: nats-echo-res [INFO] Validating: publisher [INFO] Validating: analysis-echo [INFO] Validating: graph-linker [INFO] Validating: comfy-watcher [INFO] Validating: grayjay-plugin-host [INFO] Validating: agent-zero [INFO] Validating: archon [INFO] Validating: channel-monitor [INFO] Validating: pmoves-yt [INFO] Validating: notebook-sync [INFO] Validating: supabase_service_role_key [INFO] Validating: supabase_jwt_secret ====================================== |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughReplaces 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
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)
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
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>
Docker Hardening ValidationHardening Validation ReportValidated: Wed Mar 11 14:35:51 UTC 2026Services CheckedPMOVES.AI Docker Hardening Validation[INFO] Checking: pmoves/docker-compose.hardened.yml [INFO] Validating: hi-rag-gateway-v2 [INFO] Validating: extract-worker [INFO] Validating: langextract [INFO] Validating: presign [INFO] Validating: render-webhook [INFO] Validating: retrieval-eval [INFO] Validating: pdf-ingest [INFO] Validating: jellyfin-bridge [INFO] Validating: invidious-companion-proxy [INFO] Validating: ffmpeg-whisper [INFO] Validating: media-video [INFO] Validating: media-audio [INFO] Validating: hi-rag-gateway-v2-gpu [INFO] Validating: hi-rag-gateway-gpu [INFO] Validating: deepresearch [INFO] Validating: supaserch [INFO] Validating: publisher-discord [INFO] Validating: mesh-agent [INFO] Validating: nats-echo-req [INFO] Validating: nats-echo-res [INFO] Validating: publisher [INFO] Validating: analysis-echo [INFO] Validating: graph-linker [INFO] Validating: comfy-watcher [INFO] Validating: grayjay-plugin-host [INFO] Validating: agent-zero [INFO] Validating: archon [INFO] Validating: channel-monitor [INFO] Validating: pmoves-yt [INFO] Validating: notebook-sync [INFO] Validating: supabase_service_role_key [INFO] Validating: supabase_jwt_secret ====================================== |
There was a problem hiding this comment.
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-fullsupabaseanddown/clean-fullsupabasenow 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 thesupabase-localcompose 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 | 🟠 MajorUse
scripts/with-env.shto load environment files inpopulate-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 usescripts/with-env.shfor 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 | 🔴 CriticalUpdate Jellyfin’s inherited Supabase keys to the new canonical source.
This block still inherits
SUPABASE_ANON_KEY/SUPABASE_SERVICE_ROLE_KEYfrompmoves/.env.local, but this file now definesANON_KEY/SERVICE_ROLE_KEYinpmoves/env.tier-supabase. As written,env.jellyfin-aican 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.yamlallowscommandactions, 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 explicitinvertflag instead of string parsing.The grep inversion logic relies on string matching ("Should NOT contain" or "No ") in the
expectfield. This is fragile—typos like "should not contain" (lowercase) would bypass inversion.Consider adding an explicit
invert: truefield 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
📒 Files selected for processing (32)
.claude/CLAUDE.md.claude/commands/tac/review.mdPMOVES-WealthPmoves-Health-wgerpmoves/Makefilepmoves/README.mdpmoves/bootstrap/registry.jsonpmoves/configs/skill-pairings.yamlpmoves/configs/submodule_skill_registry.jsonpmoves/configs/tac_schema.yamlpmoves/configs/tac_trees/firefly-iii.tac.yamlpmoves/configs/tac_trees/health-wger.tac.yamlpmoves/configs/tac_trees/n8n.tac.yamlpmoves/docker-compose.supabase.ymlpmoves/docker-compose.vps.override.ymlpmoves/docker-compose.ymlpmoves/docs/integrations/FIREFLY_WGER_INTEGRATIONS_STATUS.mdpmoves/docs/operations/SEEDED_BRANDED_DEFAULTS.mdpmoves/docs/services/supabase/MIGRATION_WORKFLOW.mdpmoves/env.tier-supabase.examplepmoves/integrations/firefly-iii/auth/bootstrap.shpmoves/integrations/firefly-iii/events/subjects.yamlpmoves/integrations/firefly-iii/n8n/flows/finance_health_crosswalk.jsonpmoves/integrations/health-wger/auth/bootstrap.shpmoves/integrations/health-wger/events/subjects.yamlpmoves/integrations/health-wger/n8n/flows/health_to_research.jsonpmoves/integrations/health-wger/n8n/flows/integration_status_reporter.jsonpmoves/integrations/health-wger/n8n/flows/voice_health_checkin.jsonpmoves/scripts/pmoves.ps1pmoves/scripts/supabase/generate-keys.shpmoves/tools/brand_defaults.pypmoves/tools/tac_runner.py
💤 Files with no reviewable changes (1)
- pmoves/docker-compose.supabase.yml
| "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 | ||
| } |
There was a problem hiding this comment.
🧩 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 -10Repository: 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 -5Repository: 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 -40Repository: 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 3Repository: 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.pyRepository: 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.pyRepository: 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 -20Repository: 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 -20Repository: 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:
- Add a JWT generator type to
bootstrap_env.pythat accepts a secret parameter and signs payloads - Remove the
"generate"field from these entries and require manual invocation ofgenerate-keys.sh - Update the help text to clarify that
random_urlsafeis 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.
| "finance": ["chit/floos", "n8n/execute", "deploy/up"], | ||
| "health": ["n8n/execute", "deploy/up"], |
There was a problem hiding this comment.
$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.
| - DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime | ||
| - DB_ENC_KEY=${SUPABASE_REALTIME_SECRET:-supabaserealtime} | ||
| # App configuration |
There was a problem hiding this comment.
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.
| - 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.
| # 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 |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
find . -name "docker-compose.yml" -path "*/pmoves/*" | head -5Repository: POWERFULMOVES/PMOVES.AI
Length of output: 210
🏁 Script executed:
wc -l ./pmoves/docker-compose.ymlRepository: POWERFULMOVES/PMOVES.AI
Length of output: 99
🏁 Script executed:
sed -n '750,850p' ./pmoves/docker-compose.yml | cat -nRepository: POWERFULMOVES/PMOVES.AI
Length of output: 4512
🏁 Script executed:
sed -n '850,950p' ./pmoves/docker-compose.yml | cat -nRepository: 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 -nRepository: 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 -nRepository: 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 -nRepository: 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 -nRepository: 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.
| { | ||
| "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" | ||
| }, |
There was a problem hiding this comment.
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).
| 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" |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, find the definition of $(DC) in the Makefile
rg "^\s*DC\s*:=" pmoves/MakefileRepository: 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 composeRepository: 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 -100Repository: 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.ymlRepository: 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}")
EOFRepository: 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 2Repository: POWERFULMOVES/PMOVES.AI
Length of output: 808
🏁 Script executed:
# Check the full STACK_FILES definition in the Makefile
grep -A 30 "STACK_FILES \?=" pmoves/MakefileRepository: 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 rundocker compose upwithout--profile(and withoutCOMPOSE_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 myprofiledserviceruns 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_ona service that’s excluded by an inactive profile, the resulting model can be invalid (i.e., you must enable whatever profiles are needed to satisfydepends_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.
| 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; \ |
There was a problem hiding this comment.
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).
| 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) |
There was a problem hiding this comment.
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.
| 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>
Docker Hardening ValidationHardening Validation ReportValidated: Wed Mar 11 14:52:40 UTC 2026Services CheckedPMOVES.AI Docker Hardening Validation[INFO] Checking: pmoves/docker-compose.hardened.yml [INFO] Validating: hi-rag-gateway-v2 [INFO] Validating: extract-worker [INFO] Validating: langextract [INFO] Validating: presign [INFO] Validating: render-webhook [INFO] Validating: retrieval-eval [INFO] Validating: pdf-ingest [INFO] Validating: jellyfin-bridge [INFO] Validating: invidious-companion-proxy [INFO] Validating: ffmpeg-whisper [INFO] Validating: media-video [INFO] Validating: media-audio [INFO] Validating: hi-rag-gateway-v2-gpu [INFO] Validating: hi-rag-gateway-gpu [INFO] Validating: deepresearch [INFO] Validating: supaserch [INFO] Validating: publisher-discord [INFO] Validating: mesh-agent [INFO] Validating: nats-echo-req [INFO] Validating: nats-echo-res [INFO] Validating: publisher [INFO] Validating: analysis-echo [INFO] Validating: graph-linker [INFO] Validating: comfy-watcher [INFO] Validating: grayjay-plugin-host [INFO] Validating: agent-zero [INFO] Validating: archon [INFO] Validating: channel-monitor [INFO] Validating: pmoves-yt [INFO] Validating: notebook-sync [INFO] Validating: supabase_service_role_key [INFO] Validating: supabase_jwt_secret ====================================== |
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>
Docker Hardening ValidationHardening Validation ReportValidated: Wed Mar 11 15:06:28 UTC 2026Services CheckedPMOVES.AI Docker Hardening Validation[INFO] Checking: pmoves/docker-compose.hardened.yml [INFO] Validating: hi-rag-gateway-v2 [INFO] Validating: extract-worker [INFO] Validating: langextract [INFO] Validating: presign [INFO] Validating: render-webhook [INFO] Validating: retrieval-eval [INFO] Validating: pdf-ingest [INFO] Validating: jellyfin-bridge [INFO] Validating: invidious-companion-proxy [INFO] Validating: ffmpeg-whisper [INFO] Validating: media-video [INFO] Validating: media-audio [INFO] Validating: hi-rag-gateway-v2-gpu [INFO] Validating: hi-rag-gateway-gpu [INFO] Validating: deepresearch [INFO] Validating: supaserch [INFO] Validating: publisher-discord [INFO] Validating: mesh-agent [INFO] Validating: nats-echo-req [INFO] Validating: nats-echo-res [INFO] Validating: publisher [INFO] Validating: analysis-echo [INFO] Validating: graph-linker [INFO] Validating: comfy-watcher [INFO] Validating: grayjay-plugin-host [INFO] Validating: agent-zero [INFO] Validating: archon [INFO] Validating: channel-monitor [INFO] Validating: pmoves-yt [INFO] Validating: notebook-sync [INFO] Validating: supabase_service_role_key [INFO] Validating: supabase_jwt_secret ====================================== |
There was a problem hiding this comment.
♻️ Duplicate comments (1)
pmoves/docker-compose.yml (1)
918-918:⚠️ Potential issue | 🟠 Major
LOGFLARE_NODE_HOST=127.0.0.1blocks inter-container traffic.Logflare binds to localhost, so
supabase-studio'sLOGFLARE_URL=http://supabase-analytics:4000(line 793) cannot connect. Per coding guidelines, containers must bind to0.0.0.0for 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
📒 Files selected for processing (4)
.github/workflows/hardening-validation.ymlPMOVES-supabasepmoves/docker-compose.ymlpmoves/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>
Docker Hardening ValidationHardening Validation ReportValidated: Wed Mar 11 15:51:03 UTC 2026Services CheckedPMOVES.AI Docker Hardening Validation[INFO] Checking: pmoves/docker-compose.hardened.yml [INFO] Validating: hi-rag-gateway-v2 [INFO] Validating: extract-worker [INFO] Validating: langextract [INFO] Validating: presign [INFO] Validating: render-webhook [INFO] Validating: retrieval-eval [INFO] Validating: pdf-ingest [INFO] Validating: jellyfin-bridge [INFO] Validating: invidious-companion-proxy [INFO] Validating: ffmpeg-whisper [INFO] Validating: media-video [INFO] Validating: media-audio [INFO] Validating: hi-rag-gateway-v2-gpu [INFO] Validating: hi-rag-gateway-gpu [INFO] Validating: deepresearch [INFO] Validating: supaserch [INFO] Validating: publisher-discord [INFO] Validating: mesh-agent [INFO] Validating: nats-echo-req [INFO] Validating: nats-echo-res [INFO] Validating: publisher [INFO] Validating: analysis-echo [INFO] Validating: graph-linker [INFO] Validating: comfy-watcher [INFO] Validating: grayjay-plugin-host [INFO] Validating: agent-zero [INFO] Validating: archon [INFO] Validating: channel-monitor [INFO] Validating: pmoves-yt [INFO] Validating: notebook-sync [INFO] Validating: supabase_service_role_key [INFO] Validating: supabase_jwt_secret ====================================== |
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>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Shaela Bello <slbello@uncg.edu> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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>
Summary
Consolidates 4 competing Supabase deployment paths into a single canonical
docker-compose.ymlstack under thesupabase-localprofile. Also enriches integration skill entries (health/wealth/n8n) and adds branded defaults.Supabase Unification (Phases 1-6 + 8)
supabase-kong:8000(canonical gateway):?for JWT_SECRET, SECRET_KEY_BASE, VAULT_ENC_KEYservice_healthydepends_on, wget for Elixir images, edge-functions + analytics checksdocker-compose.supabase.ymlsuperseded by profileJWT_SECRET/ANON_KEY/SERVICE_ROLE_KEYcanonical names, no${VAR}interpolation in env_fileopenssl base64 -A, proper HS256 JWT signing, stderr bannersIF NOT EXISTSguards)Integration Enrichment
Review Coordination
Review Focus Areas
generate-keys.sh— JWT signing correctness, cross-platform compatibilityenv.tier-supabase.example— no interpolation references, all new service secrets presentsupa-stop-all— lists all 13 servicesReview Fixes Already Applied
true:?fail-hardsupa-stop-alllists all 13 services${VAR}interpolation in aliasesopenssl base64 -ATest plan
docker compose --profile supabase-local config --serviceslists all 13 Supabase servicesmake -C pmoves supa-stop-alltargets all 13 services without errorbash pmoves/scripts/supabase/generate-keys.shproduces valid JWTs on Linux and macOShost.docker.internal:54321in compose defaultsdocker-compose.supabase.ymlin any scriptmake -C pmoves populate-tier-envscalls generate-keys.sh successfullydocker compose -f docker-compose.yml -f docker-compose.vps.override.yml configvalidates🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation