Skip to content

feat(miner): add GITHUB_TOKEN_FILE secret-mount indirection for fleet mode - #5560

Merged
JSONbored merged 1 commit into
JSONbored:mainfrom
galuis116:feat/miner-github-token-file
Jul 13, 2026
Merged

feat(miner): add GITHUB_TOKEN_FILE secret-mount indirection for fleet mode#5560
JSONbored merged 1 commit into
JSONbored:mainfrom
galuis116:feat/miner-github-token-file

Conversation

@galuis116

Copy link
Copy Markdown
Contributor

Summary

  • The miner is a separate deployable from ORB — its own process/container per DEPLOYMENT.md's fleet mode —
    so it never runs through ORB's own src/selfhost/load-file-secrets.ts server-startup resolver. GITHUB_TOKEN
    (and any coding-agent credential passed via env var) is only ever readable as a plain env var, meaning its
    value is visible in plaintext via docker inspect / docker compose config on any host running the miner,
    with no file-mount alternative for Docker Swarm/Kubernetes-managed secrets.
  • Added packages/gittensory-miner/lib/env-file-indirection.js (+ .d.ts): a generic <NAME>_FILE resolver
    ported from ORB's exact pattern. It's generic by design — it scans env for any <NAME>_FILE key and
    resolves it into <NAME> — so one early call at CLI startup (before any subcommand dispatches, in
    bin/gittensory-miner.js) covers GITHUB_TOKEN and any coding-agent env-var credential
    (CLAUDE_CODE_OAUTH_TOKEN, ANTHROPIC_API_KEY) with zero changes to the several individual call sites
    throughout the package that already read env.GITHUB_TOKEN directly (discover-cli.js, loop-cli.js,
    manage-poll.js, attempt-cli.js).
  • Deliberately diverges from the ORB analogue in one place, per the issue's explicit requirement: a
    missing/unreadable <NAME>_FILE throws (rather than logging and continuing), so a broken secret mount
    fails a miner container fast and loud with a clear message naming the var and path — never a silent
    empty/undefined credential that surfaces later as a confusing GitHub 401. bin/gittensory-miner.js catches
    that throw and exits 1 with the message, instead of an uncaught-exception stack trace.
  • The documented precedence rule matches the ORB analogue exactly: an explicit <NAME> value always wins over
    <NAME>_FILE.
  • Updated DEPLOYMENT.md's fleet-mode docker run example with a GITHUB_TOKEN_FILE alternative (Swarm/K8s
    secret-mount style) alongside the existing plain-env-var example, and added a commented example to the
    repo-root .gittensory-miner.env.example starter file.

Fixes #5178

Scope

  • The PR title follows type(scope): short summary Conventional Commit format, for example fix(api): restore profile access checks.
  • This PR is focused and does not mix unrelated backend, UI, MCP, docs, dependency, and deploy changes.
  • This follows CONTRIBUTING.md and does not reintroduce GitHub Pages, VitePress, site/, or CNAME.
  • I linked a currently open issue this PR resolves (e.g. Closes #123) — a linked open issue is required for every contributor PR.

Validation

  • git diff --check
  • npm run actionlint
  • npm run typecheck
  • npm run test:coverage locally — packages/gittensory-miner/lib/**/*.js is included in this repo's codecov/patch gate. Targeted coverage run (--coverage.include scoped to env-file-indirection.js): 100% statements, 100% branches, 100% functions, 100% lines. bin/gittensory-miner.js is NOT in coverage.include (only lib/** is), so its lines aren't Codecov-patch-gated; its wiring is instead proven by real end-to-end tests below rather than coverage numbers.
  • npm run test:workers
  • npm run build:mcp
  • npm run test:mcp-pack
  • npm run build:miner
  • npm run test:miner-pack
  • npm run ui:openapi:check
  • npm run ui:lint
  • npm run ui:typecheck
  • npm run ui:build
  • npm audit --audit-level=moderate
  • New or changed behavior has unit/integration tests for new branches, fallback paths, and sanitizer boundaries

Ran the full local gate: npm run test:ci (803 test files, 0 failures) and npm audit --audit-level=moderate (0 vulnerabilities), both clean on the final rebased commit.

New test/unit/miner-env-file-indirection.test.ts (13 tests): plain-var-only, _FILE-only (trimmed), both-set precedence, neither-set, missing/unreadable file (throws, with both the Error and non-Error fallback branches covered), an empty-but-readable file resolving to "" (not an error), COMPOSE_FILE/COMPOSE_ENV_FILE exclusion (mirrors the ORB analogue's own reserved-var guard), multiple independent _FILE vars resolved in one pass, an invariant asserting a thrown error message never contains the resolved secret's own value, and — beyond unit coverage — two real end-to-end tests that spawn the actual bin/gittensory-miner.js binary: one confirming GITHUB_TOKEN_FILE resolves correctly through the real CLI with the secret value never appearing in stdout/stderr, one confirming a broken _FILE path fails the real process with exit 1 and a clear stderr message.

Safety

  • No secrets, wallet details, hotkeys, coldkeys, user PATs, private keys, raw trust scores, private rankings, or private maintainer evidence are exposed.
  • Public GitHub text stays sanitized, low-noise, and does not imply compensation guarantees or optimization tactics.
  • Auth, cookie, CORS, GitHub App, Cloudflare, or session changes include negative-path tests. — N/A, no auth/session/CORS surface touched; this is credential-resolution plumbing only (per the issue's own boundary fix(docs): restore Nightward-style homepage flow #9, it never touches governor/attempt/claim control-flow).
  • API/OpenAPI/MCP behavior is updated and tested where needed. — no public API/OpenAPI/MCP surface touched.
  • UI changes use live API data or real empty/error/loading states, not production mock/demo fallbacks. — N/A, no UI surface.
  • Visible UI changes include a UI Evidence section below. — N/A, see below.
  • Public docs/changelogs are updated where needed; changelogs are only edited for release-prep PRs. — updated DEPLOYMENT.md and .gittensory-miner.env.example.

UI Evidence

N/A — this is a local CLI-only credential-resolution change with no visible UI surface. No screenshots apply.

Notes

  • The module is named env-file-indirection.js, not something with "secret" in the name — this PR's own local
    gate (npm run test:miner-packscripts/check-miner-package.mjs) caught a real, self-inflicted defect
    before ever pushing: the package's own npm-pack safety guard forbids any packed file whose path matches
    .*secret.* (case-insensitive), so the module was originally named load-file-secrets.js and had to be
    renamed. A related second hit: DEPLOYMENT.md's first draft literally wrote `-e GITHUB_TOKEN=...` in
    prose, which matched the same guard's content-side check for a TOKEN= assignment shape — reworded to drop
    the =.... Both were caught and fixed by running the exact regexes from scripts/check-miner-package.mjs/
    scripts/forbidden-content.mjs directly against every touched file before the final push, not just by
    re-running the test suite and hoping.
  • Scoped to GITHUB_TOKEN and any coding-agent credential passed via a plain env var. Explicitly not
    applied to codex-cli's credential, which is already a file path (auth.json) read directly today, not an
    env-var-provided secret value — <NAME>_FILE indirection doesn't apply to something that's already a file
    reference, so there's nothing to port there.
  • Did not touch packages/gittensory-engine/** — the coding-agent driver's own construction path continues to
    read whichever env var it already reads; this PR only ensures that var is populated correctly before
    construction happens, via the single early resolver call.

… mode

The miner is a separate deployable from ORB (its own process/container
per DEPLOYMENT.md's fleet mode), so it never ran through ORB's own
src/selfhost/load-file-secrets.ts server-startup resolver -- a plain
GITHUB_TOKEN env var is visible in plaintext via `docker inspect` on
any host running the miner, with no file-mount alternative.

Add a generic <NAME>_FILE resolver, ported from that same ORB pattern,
called once at CLI startup (before any subcommand dispatches or reads
process.env) so it covers GITHUB_TOKEN and any coding-agent env-var
credential with zero changes to the individual call sites that already
read those vars. Diverges from the ORB analogue on purpose: throws
(rather than logging and continuing) on a missing/unreadable file, so
a broken secret mount fails a container fast and loud.

Fixes JSONbored#5178
@galuis116
galuis116 requested a review from JSONbored as a code owner July 13, 2026 05:12
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.91%. Comparing base (df5336e) to head (fa599d6).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #5560   +/-   ##
=======================================
  Coverage   94.91%   94.91%           
=======================================
  Files         570      571    +1     
  Lines       45351    45360    +9     
  Branches    14675    14675           
=======================================
+ Hits        43046    43055    +9     
  Misses       1571     1571           
  Partials      734      734           
Flag Coverage Δ
shard-1 44.13% <0.00%> (-0.02%) ⬇️
shard-2 35.66% <0.00%> (-0.05%) ⬇️
shard-3 31.87% <0.00%> (-0.07%) ⬇️
shard-4 31.77% <0.00%> (-0.11%) ⬇️
shard-5 32.91% <0.00%> (-0.10%) ⬇️
shard-6 44.36% <100.00%> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...kages/gittensory-miner/lib/env-file-indirection.js 100.00% <100.00%> (ø)
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 13, 2026
@loopover-orb

loopover-orb Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ Gittensory review result - approve/merge recommended

Review updated: 2026-07-13 05:18:16 UTC

6 files · 2 AI reviewers · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR ports ORB's `<NAME>_FILE` secret-file resolution pattern into the miner package, adding a generic `loadMinerFileSecrets` scanner (excluding Compose's own reserved `_FILE` vars), wiring it as the first thing `bin/gittensory-miner.js` does at startup, and deliberately throwing (rather than logging-and-continuing) on an unreadable file so a broken secret mount fails fast. The implementation correctly matches the described precedence rule (explicit `<NAME>` wins), never logs the resolved secret value, and is covered by a thorough unit + end-to-end test suite. This closes issue #5178 and is well-targeted, narrow operator-facing plumbing with no schema/migration surface.

Nits — 5 non-blocking
  • packages/gittensory-miner/bin/gittensory-miner.js:40 uses `console.error` for the fatal secret-mount failure — verify this is the established pattern for fatal CLI errors elsewhere in this file (e.g. other early-exit paths) rather than routing through the shared logger from `../lib/logger.js` used later in the same file.
  • lib/env-file-indirection.js iterates `Object.keys(env)` on every call — for `process.env` in a long-lived process this is O(n) but only runs once at CLI startup, so no real concern, just worth a one-line note in the doc comment that it's a one-shot pass.
  • The doc comment in env-file-indirection.js is quite long (20+ lines) for a 15-line function; consider trimming to the essential precedence/throw-behavior facts and moving historical rationale to the PR/issue.
  • Consider extracting the `_FILE` suffix length (`"_FILE".length`) into a named constant if this pattern is copied elsewhere, to avoid magic-string duplication between the `endsWith` check and `slice`.
  • The end-to-end tests in miner-env-file-indirection.test.ts spawn a real `node` process per test (status --json / status) — fine for CI given they're cheap, but worth confirming timeout budget as more such spawn-based tests accumulate.
Signal Result Evidence
Code review ✅ No blockers 2 reviewers, synthesized
Linked issue ✅ Linked #5178
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 1877 registered-repo PR(s), 1237 merged, 49 issue(s).
Contributor context ✅ Confirmed Gittensor contributor galuis116; Gittensor profile; 1877 PR(s), 49 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor — Code changes are accompanied by test evidence. LLM value judgment: moderate — The diff adds a small, well-tested, correctly-scoped security hardening feature (file-mount secret indirection) that closes a real gap (issue #5178) between the miner's env handling and ORB's existing analogous resolver, without touching unrelated call sites.
Linked issue satisfaction

Addressed
The PR adds a generic env-file-indirection resolver mirroring load-file-secrets.ts's precedence and error-handling pattern, wires it in early at CLI startup so it covers GITHUB_TOKEN and coding-agent credentials like ANTHROPIC_API_KEY without touching per-callsite code, throws a clear actionable error on missing/unreadable files, never logs secret values, and updates DEPLOYMENT.md with a GITHUB_TO

Review context
  • Author: galuis116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: JavaScript, Python, Dart, TypeScript, HTML, MDX, Rust, C++
  • Official Gittensor activity: 1877 PR(s), 49 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
[BETA] Chat with Gittensory

Ask Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @gittensory ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @gittensory chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @gittensory mention with a real question is routed to the closest matching read-only command automatically -- no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.

  • Re-run Gittensory review

@loopover-orb loopover-orb Bot added the manual-review Gittensor contributor context label Jul 13, 2026
@JSONbored
JSONbored merged commit 72fb957 into JSONbored:main Jul 13, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. manual-review Gittensor contributor context

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add <NAME>_FILE secrets-file indirection for GITHUB_TOKEN and coding-agent credentials in fleet mode

2 participants