Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

fix: run_local_safe.sh leaves the Deep Research service reachable

Open Beginner friendly
#696 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
85/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
bash, python

Research direction

Edit dashboard/scripts/run_local_safe.sh to add RESEARCH_SHELL_SERVICE_URL= RESEARCH_DD_SERVICE_URL= RESEARCH_SERVICE_TOKEN= to the env list (line ~37-51). Update docs/local-run.md section 8 and script header line 4, and add the URLs to docs/architecture/configuration.md. Done when the script blanks those vars and docs reflect that no external research call can leave a safe local instance.

Written by the indexing model from the issue text.

Description

Checked at origin/main 7f9ce0f3 by reading only. Nothing was run, so every behavioural claim below is from source.

Summary

dashboard/scripts/run_local_safe.sh says it blanks "every broker/LLM key, so nothing can trade or bill" (header, line 4), and docs/local-run.md section 8 says "no LLM call can be billed". That holds for every LLM key the backend reads. It does not hold for the research-agent path: a dashboard/.env configured like prod can still submit a Deep Research run to a real external service from a "safe" local instance. That is the exact case the script's own header (lines 5-8) says it defends against.

One path can spend. The other two vars named in the report cannot.

How the script blanks (this part works)

  • run_local_safe.sh:37-51 is exec env VAR= ... python -m uvicorn. That sets each variable to the empty string; it does not unset it.
  • app.py:70-74 then calls load_dotenv(dashboard/.env) with the default override=False. python-dotenv 1.2.2 (pinned, requirements.txt:175) skips any key already in os.environ (dotenv/main.py:105, if k in os.environ and not self.override: continue), and an empty string counts as present. So .env cannot refill a blanked key. domain/chat/service.py:24 (load_dotenv()) behaves the same.
  • Blanked: ALPACA_API_KEY, ALPACA_SECRET_KEY, ANTHROPIC_API_KEY, OPENAI_API_KEY, DEEPSEEK_API_KEY, COMMONSTACK_API_KEY, OPENROUTER_API_KEY, the three *_DATABASE_URL, BREVO_API_KEY, ATL_STRIPE_TEST_BILLING_ENABLED, STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, IFIND_REFRESH_TOKEN, IFIND_ACCESS_TOKEN. Forced: ROBINHOOD_EXECUTE=false, ATL_BAR_CACHE_WARM=0, LEADERBOARD_DAILY_AUTO_DEPLOY=0, DATABASE_PATH, ATL_BAR_CACHE_DIR.
  • Every LLM client site gates on a non-empty key before building a client (providers/anthropic_native.py:30, domain/chat/service.py:79-88, algo_service.py:149), so the SDKs' own env fallbacks are never reached with the key blanked.

What the script does not blank

Var Read at Reachable locally? Class
RESEARCH_SERVICE_TOKEN (+ RESEARCH_SHELL_SERVICE_URL, RESEARCH_DD_SERVICE_URL) api/routers/research.py:92; URLs domain/agents/marketplace.py:57-59 Yes, if .env carries a real URL Can spend: submits an LLM research job on an external service
FINGPT_API_KEY integrations/news_sentiment.py:71 Yes External, free
FINANCIAL_DATASETS_API_KEY infrastructure/ai_hedge_fund/adapter.py:75 No Unreachable in practice
DISCORD_CLIENT_SECRET, DISCORD_BOT_API_SECRET, DISCORD_OAUTH_STATE_SECRET api/discord_oauth.py:28,44,56 Yes, interactive OAuth only External, free
ROBINHOOD_MCP_URL, ROBINHOOD_OAUTH_STATE_SECRET infrastructure/brokers/robinhood_oauth.py:21,52 No Unreachable in practice
SESSION_HASH_SECRET, ADMIN_BOOTSTRAP_SECRET, LEADERBOARD_DAILY_REFRESH_SECRET, LLM_EXECUTION_HANDOFF_SECRET, ANALYTICS_PSEUDONYMIZATION_KEY, BROKER_TOKEN_ENCRYPTION_KEY various n/a Inbound or local crypto; no outbound spend
1. Research service: can spend (conditional)
  • The router is always mounted (api/router.py:24,36) and its sweeper always started (app.py:369-376).
  • POST /api/v1/research/agents/{id}/runs (research.py:262-355) needs a signed-in user, reserves $1 of local Credits (research.py:303), then httpx.post(f"{base}/runs", headers={"X-Service-Token": ...}) at research.py:322-327. The agent service runs the Deep Research job, an LLM run on that service's keys (docs/integrations/research-agents.md). The reservation only bills the local SQLite copy.
  • A fresh local signup gets the welcome Credits grant (api/auth.py:610, credits_service.grant_default_signup_credits; 8 Credits per CLAUDE.md), enough for the $1 reservation. I did not run the grant.
  • Blanking RESEARCH_SERVICE_TOKEN is not the lever. _service_token() (research.py:82-98) refuses only when RENDER/ATL_ENV=production. Locally an empty token becomes the literal dev-token and the call still goes out. Whether a real service rejects dev-token depends on that service; I did not check it.
  • The URL is the lever. marketplace.json:429,456 names RESEARCH_SHELL_SERVICE_URL / RESEARCH_DD_SERVICE_URL, defaulting to http://127.0.0.1:9100. Blank them and (base or default) falls back to the local default, so nothing leaves the machine.
  • Precondition: the URL vars are not in .env.example and not in docs/architecture/configuration.md, so only a prod-derived dashboard/.env sets them. That is the scenario the script exists for.
  • Even viewing the workbench calls GET {base}/manifest with the token (research.py:209-214).
2. FINGPT_API_KEY: external, free
  • news_sentiment._headers() (:70-72) adds a Bearer token to GETs against agenticfinsearch.org (:22-23). These read precomputed artifacts. No LLM is called per request, and the FinSearch timers are paused (CLAUDE.md).
  • /api/news/signals is frozen by default (news.py:44-52,112, unset means frozen), so the panel makes no call unless .env sets NEWS_FEED_FROZEN=0.
  • The live caller is every /api/v2 run step: execution/backtest_backend.py:194 -> get_news_sentiment -> fetch_signals, regardless of the freeze flag. Without the key the same GET goes out anonymously (_headers returns {}), so blanking the key changes only whether the prod bearer leaves the machine, not whether the call happens.
3. FINANCIAL_DATASETS_API_KEY: unreachable
  • backtests.py:2066 pops it from the child env for the hosted runtime and substitutes the agent owner's own stored credential. The route also 503s when OPENROUTER_API_KEY is empty (backtests.py:3953), and the script blanks that. HourlyBacktester is built with a hosted runtime only in the scrubbed child (dashboard/scripts/backtest_hourly_agent.py:538; engine.py:353). The adapter's allowlist entry at adapter.py:75 never sees an ambient value.

The wrong claims

  • docs/local-run.md section 8, line 213-214: "Covered by this setup: no broker order can be placed, no LLM call can be billed, and no persistent data outside ~/.cache/atl-local is written."
  • dashboard/scripts/run_local_safe.sh:4: "blanks every broker/LLM key, so nothing can trade or bill".
  • Not wrong as written: README.md:72 says "blanks broker, LLM, DB, mail, Stripe and iFinD keys", which matches the script.
  • Imprecise: docs/local-run.md:223-225 says "the news panel may call the FinSearch endpoint". The panel is frozen by default; the call that happens is the per-step /api/v2 one.

Suggested fix

  1. run_local_safe.sh: add to the env list
    RESEARCH_SHELL_SERVICE_URL= RESEARCH_DD_SERVICE_URL= RESEARCH_SERVICE_TOKEN=
    (the two URLs do the work; the token stops a prod token being sent to 127.0.0.1:9100). Optionally FINGPT_API_KEY= so a prod bearer is not sent off-machine. FINANCIAL_DATASETS_API_KEY= is a no-op, so skip it.
  2. docs/local-run.md: add a bullet to the "The script:" list (line 78-86) for the research URLs and token. Reword the section 8 sentence to: "no broker order can be placed, and no LLM call can be billed to a key from the environment (a provider key you add yourself under BYOK is your own)". Change the news bullet to say the panel is frozen by default and the live FinSearch call comes from /api/v2 run steps.
  3. Script header line 4: say "blanks the broker, LLM, research-service, ..." rather than "every".
  4. Add RESEARCH_SHELL_SERVICE_URL / RESEARCH_DD_SERVICE_URL to docs/architecture/configuration.md (only RESEARCH_SERVICE_TOKEN is listed, at line 297).

Not verified

Nothing was executed. Not checked: that a real research service rejects dev-token; that the welcome grant lands on a fresh local SQLite copy; who pays for the external service's LLM calls (docs/integrations/research-agents.md says the agent author, docs/architecture/backend-internals.md:37 says the run bills the user's Credits).

Found while fact-checking #695.

Dominant language
Python
Stars
767
Forks
156
Avg merge
1d 19h
Merged PRs (30d)
71

Getting set up

  • Ships a Dockerfile or Docker Compose file
  • No pull request template
  • No contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from Open-Finance-Lab/AgenticTrading

All issues in Open-Finance-Lab/AgenticTrading

Similar issues

More Python issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.