Skip to content

fix(tracker-github): reconcile tracker secret declarations - #877

Merged
moncher-dev merged 3 commits into
mainfrom
symphony/hojinzs-github-symphony-869
Sep 5, 2026
Merged

fix(tracker-github): reconcile tracker secret declarations#877
moncher-dev merged 3 commits into
mainfrom
symphony/hojinzs-github-symphony-869

Conversation

@moncher-dev

@moncher-dev moncher-dev commented Sep 5, 2026

Copy link
Copy Markdown
Collaborator

Issues

Summary

  • Adds regression coverage proving GitHub and Linear tracker declarations include every credential key their adapters inject.
  • Verifies both Codex and Claude strip synthetic tracker credentials supplied exclusively through adapter declarations.
  • Strengthens adapter coverage so it fails if credential resolution unexpectedly returns nothing.

Change-point diagram

  • tracker-github / tracker-linear resolver outputs → pinned non-empty credential maps → declared secret-name superset assertions
  • tracker adapter declarations → SYMPHONY_TRACKER_SECRET_ENVIRONMENT_NAMES → Codex and Claude child-environment stripping tests

Start here

  • packages/tracker-github/src/tracker-github.test.ts:1262 — GitHub injection/declaration contract and resolver-branch fixtures
  • packages/tracker-linear/src/tracker-linear.test.ts:1490 — Linear injection/declaration contract
  • packages/runtime-codex/src/runtime.test.ts — Codex declaration-driven stripping
  • packages/runtime-claude/src/adapter.test.ts — Claude declaration-driven stripping

User-Visible Behavior / Operational Impact

  • None. The source corrections are already present on the base branch; this PR adds durable regression coverage.

Validation

  • pnpm exec prettier --check packages/tracker-github/src/tracker-github.test.ts packages/tracker-linear/src/tracker-linear.test.ts — pass
  • pnpm exec vitest run packages/tracker-github/src/tracker-github.test.ts packages/tracker-linear/src/tracker-linear.test.ts — pass (163 tests)
  • pnpm lint — pass
  • pnpm test — pass
  • pnpm typecheck — pass
  • pnpm build — pass
  • Docker E2E — not applicable: the diff is deterministic unit-test coverage only and changes no integration behavior

Changeset

  • Not needed because the PR changes tests only and has no shipped behavior.

Risks & rollback

  • Low risk: four test files only, with no production code changes.
  • Reviewer focus: credential fixtures must enumerate every resolver return branch and remain non-empty.
  • Rollback by reverting commits 6102416 and a7cbe93.

Changed files

  • packages/tracker-github/src/tracker-github.test.ts — asserts declared GitHub secrets cover pinned direct and broker injection results
  • packages/tracker-linear/src/tracker-linear.test.ts — asserts declared Linear secrets cover pinned injection results
  • packages/runtime-codex/src/runtime.test.ts — asserts Codex strips adapter-declared tracker credentials only
  • packages/runtime-claude/src/adapter.test.ts — asserts Claude strips adapter-declared tracker credentials only

Post-merge / human validation

  • None

Security

  • No real tokens, private keys, .env files, or generated installation tokens are committed

@github-actions

github-actions Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 40.95% 44982 / 109830
🔵 Statements 40.95% 44982 / 109830
🔵 Functions 72.67% 2223 / 3059
🔵 Branches 78.83% 10357 / 13137
File CoverageNo changed files found.
Generated in workflow #1386 for commit caf2133 by the Vitest Coverage Report Action

@moncher-dev
moncher-dev marked this pull request as ready for review September 5, 2026 05:31
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 5, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-05T05:33:37.797118Z 6102416 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@moncher-dev

Copy link
Copy Markdown
Collaborator Author

Board review — PR #877 (issue #869)

Smoke-tested in a scratch worktree at head 6102416 against main = 519b1cfc.

Gate results

  • pnpm install --frozen-lockfile / pnpm build / pnpm test / pnpm typecheck / pnpm lint — all pass. Full suite: every package's test files pass, 0 failed.
  • CI: Test pass, Container Smoke pass. MERGEABLE / CLEAN.

Source-level acceptance criteria of #869 verified on main, not just asserted

The PR is test-only, and its claim is that #827 + #868 already landed the source fix. I checked that on main rather than taking the claim:

  • packages/tracker-github/src/orchestrator-adapter.tssecretEnvironmentNames() now includes GITHUB_TOKEN_BROKER_URL, GITHUB_TOKEN_BROKER_SECRET, GITHUB_TOKEN_CACHE_PATH, i.e. every key resolveWorkerCredentials() can return on both the direct-token and broker branches.
  • packages/runtime-claude/src/adapter.ts:702 — the hardcoded GH_TOKEN / GITHUB_* / LINEAR_* tracker list named in the issue is gone; the strip set is now declaredNames (from SYMPHONY_TRACKER_SECRET_ENVIRONMENT_NAMES) ∪ MCP-sourced names ∪ the shared CUSTOM_RUNTIME_RESERVED_AUTH_ENVIRONMENT_NAMES from @gh-symphony/core (split 1, refactor(core): share credential strip contract #873). That shared constant is the contract, not a per-runtime copy, so "no hardcoded copies remain in either runtime" holds.
  • packages/runtime-codex/src/runtime.ts:662 — same shape.

The tests are load-bearing (mutation-tested, not just read)

I reintroduced each regression #869 describes and confirmed the new test fails, then reverted:

  1. Dropped GITHUB_TOKEN_CACHE_PATH from the GitHub declaration → declares every GitHub credential environment name it can inject fails with the exact missing name. This is the original fix(tracker-github): reconcile tracker secret declarations with what the adapters inject #869 defect.
  2. Dropped LINEAR_AUTHORIZATION from the Linear declaration → Linear declaration test fails.
  3. Forced declaredNames = [] in the Claude adapter (a regression back to a hardcoded list) → strips tracker credentials from the adapter declaration fails, expected 'secret' to be undefined.
  4. Removed ...secretEnvironmentNames from the Codex strip set → the Codex counterpart fails identically.

All four also confirm the negative half: UNDECLARED_TRACKER_VALUE survives, so the strip is declaration-driven and not a blanket wipe.

Non-blocking observation (not for this PR)

packages/runtime-codex/src/runtime.ts:665 still strips the literal "LINEAR_GRAPHQL_URL" inline, and the Claude runtime does not — a tracker-specific literal living in a runtime, asymmetric between the two. It is a non-secret URL, absent from the Linear declaration, and predates this PR, so it is out of scope here; noting it in case it belongs to a later split of #844.

Local run-standalone-project-e2e.sh was not run: Docker is intentionally absent on this host and CI's container-smoke is the authoritative container check — it passed.

Recommend merge. @hojinzs added as reviewer.

@moncher-dev
moncher-dev requested a review from hojinzs September 5, 2026 05:55

@hojinzs hojinzs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review round 1/6 — verified independently at 6102416

I re-ran the verification from source rather than relying on the board-review comment, and reproduced its main claims. Two P2 test-strength defects block; everything else is non-blocking.

Requirement coverage vs #869

Acceptance criterion Status
Each adapter's declaration covers every name it injects, asserted by test ✅ Met — mutation-verified
Tracker secret names come from the adapter declaration only; no hardcoded copies remain in either runtime ⚠️ Met at the runtime-file level; see below

I confirmed on main that the three source fixes #869 asked for did land ahead of this PR, so a test-only PR here is the right shape:

  • packages/tracker-github/src/orchestrator-adapter.ts:44-54 — declaration now carries GITHUB_TOKEN_BROKER_URL / GITHUB_TOKEN_BROKER_SECRET / GITHUB_TOKEN_CACHE_PATH, matching every key resolveWorkerCredentials can return on either branch.
  • packages/runtime-claude/src/adapter.ts:702-713 — the per-runtime hardcoded GH_TOKEN / GITHUB_* / LINEAR_* list named in the issue is gone.
  • packages/runtime-codex/src/runtime.ts:611-619, 662-666 — same shape.

On the second criterion. The list wasn't deleted so much as relocated: CUSTOM_RUNTIME_RESERVED_AUTH_ENVIRONMENT_NAMES (packages/core/src/runtime/custom-child-env.ts:74-87) still hardcodes GH_TOKEN, GH_ENTERPRISE_TOKEN, GITHUB_TOKEN, GITHUB_GRAPHQL_TOKEN, GITHUB_TOKEN_BROKER_SECRET, LINEAR_API_KEY, LINEAR_AUTHORIZATION — the exact set #869 quoted — and both runtimes union it into the strip set. So "declaration only" is not literally true, and tracker-specific names now sit in packages/core, which cuts against CLAUDE.md's "Keep tracker-specific behavior out of core layers."

I am not asking for a change here: it arrived via #873, it is a strict superset of the declarations (fail-safe, no leak), and widening this PR to chase it would be scope creep. But it does mean the declaration is not the sole source of truth, and no test in this PR can detect that — the new Claude/Codex cases use a synthetic TRACKER_ADAPTER_SECRET precisely because a real tracker name would be stripped by the core constant regardless. Worth a follow-up issue under #844 rather than a silent close of #869.

Smoke test

Built and ran the suite locally on this head (pnpm install --frozen-lockfilepnpm build → targeted vitest):

✓ packages/tracker-github/src/tracker-github.test.ts  (115 tests) 149ms
✓ packages/runtime-claude/src/adapter.test.ts          (38 tests) 165ms
✓ packages/runtime-codex/src/runtime.test.ts
✓ packages/tracker-linear/src/tracker-linear.test.ts   (48 tests)  53ms
  Test Files  4 passed (4)   Tests  245 passed (245)

CI on 6102416: Test ✅, Container Smoke ✅. mergeable_state: clean. No API or UI surface changes, so container smoke is the right ceiling here — agreed that the Docker E2E script isn't applicable to a test-only diff.

Mutation testing

The point of this PR is assertion strength, so I mutated the source instead of reading the tests:

  1. Dropped "GITHUB_TOKEN_CACHE_PATH" from the GitHub declaration → test fails naming exactly that key. This is the original #869 defect, and it is caught.
  2. Gutted resolveWorkerCredentials (early return undefined;) → the same test passes. ❌ See the P2 below.

Blocking (P2)

Both are one- to two-line fixes in the tests only; no source change.

  • tracker-github.test.ts:1285-1292expect.arrayContaining([]) is a tautology, and injectedNames is ?? {}-guarded on both sides, so the guard evaporates without signal if the credential path ever returns nothing.
  • tracker-linear.test.ts:1502-1504 — identical shape.

A contract test whose whole job is "the declaration covers everything injected" shouldn't be able to go green with nothing injected. Pin the resolved credentials with toEqual and the arrayContaining check keeps working as intended.

Non-blocking

  • P3 — the GitHub test's fixtures map 1:1 onto the resolver's return branches with nothing linking them; a future third branch slips past silently. A one-line comment suffices.
  • nitcollectMcpSecretEnvironmentNames reads ~/.gh-symphony/mcp.json via homedir() with no override, so the Claude tests aren't fully hermetic. Pre-existing.
  • Agreed the inline "LINEAR_GRAPHQL_URL" literal at runtime.ts:665 (Codex-only, absent from Claude) is out of scope here.

Scope discipline

No over-engineering and no unrequested decisions: 98 added lines, four test files, zero source changes, no speculative abstraction. Omitting the changeset is correct per CLAUDE.md — no shipped behavior changes.

Push the two P2 fixes and I'll approve on the next round.


Generated by Claude Code

Comment thread packages/tracker-github/src/tracker-github.test.ts
Comment thread packages/tracker-linear/src/tracker-linear.test.ts
Comment thread packages/tracker-github/src/tracker-github.test.ts
Comment thread packages/runtime-claude/src/adapter.test.ts
@moncher-dev
moncher-dev requested a review from hojinzs September 5, 2026 06:25

@hojinzs hojinzs left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Review round 2/6 — Approve, verified at a7cbe93

Both round-1 P2s are fixed, and I confirmed that by re-running the exact mutation that defeated them rather than reading the diff or trusting the thread replies.

Round-1 findings — all closed

# Finding Status
P2 tracker-github.test.ts — vacuous arrayContaining([]) pass ✅ Fixed, mutation-verified
P2 tracker-linear.test.ts — same shape ✅ Fixed, mutation-verified
P3 GitHub fixtures ↔ resolver branches unlinked ✅ Comment added
nit collectMcpSecretEnvironmentNames non-hermetic homedir() ✅ Correctly declined as pre-existing

The P2 fix is load-bearing, not cosmetic. In round 1, adding an early return undefined; to resolveWorkerCredentials let the declaration-coverage test pass with the credential path gutted. Re-run on this head:

× declares every GitHub credential environment name it can inject
  → expected undefined to deeply equal { Object (GITHUB_GRAPHQL_TOKEN) }
× declares every Linear credential environment name it can inject
  → expected undefined to deeply equal { …(2) }

Both now fail. The floor is real. And the test still catches the defect it was written for — dropping "GITHUB_TOKEN_CACHE_PATH" from secretEnvironmentNames() fails naming exactly that key, which is the original #869 regression.

Scope discipline on the round-2 delta

6102416..a7cbe93 is 15 added lines across two test files: two toEqual pins and one comment. Exactly what was asked, nothing adjacent picked up along the way. No over-engineering, no unrequested decisions, no speculative abstraction.

Requirement coverage vs #869

Acceptance criterion Status
Each adapter's declaration covers every name it injects, asserted by test ✅ Met, mutation-verified in both directions
Tracker secret names come from the adapter declaration only; no hardcoded copies remain in either runtime ✅ Met at the runtime level

Re-confirmed on this head that no tracker-name literals survive in either runtime source — grep for "GH_TOKEN" / "GH_ENTERPRISE_TOKEN" / "LINEAR_API_KEY" / "LINEAR_AUTHORIZATION" across runtime-claude/src and runtime-codex/src (excluding tests) returns nothing. stripTrackerSecrets is now declaredNames ∪ MCP-sourced names ∪ the shared core constant.

Smoke test

No API or UI surface is touched, so the local suite plus CI container smoke is the right ceiling here; there is no preview environment to exercise.

  • pnpm build ✅ · pnpm lint ✅ · pnpm typecheck
  • pnpm test ✅ — 2,026 tests, 14 packages, 0 failed
  • Four touched files: 245 passed (245)
  • CI on a7cbe93: Test ✅, Container Smoke
  • pnpm format reports 72 files, but the identical 72 fail on main — pre-existing, and none of this PR's four files are among them. Not this PR's.
  • Base is behind main by one docs-only commit (#875), so no conflict risk.

Omitting the changeset remains correct per CLAUDE.md: tests only, no shipped behavior.

Carried forward, not blocking

The round-1 observation stands unchanged and I am explicitly not gating on it: CUSTOM_RUNTIME_RESERVED_AUTH_ENVIRONMENT_NAMES (packages/core/src/runtime/custom-child-env.ts) still hardcodes the exact tracker-name set #869 quoted, so "declaration only" is true per-runtime but not end-to-end, and tracker-specific names sit in packages/core against CLAUDE.md's "keep tracker-specific behavior out of core layers." It arrived via #873, it is a fail-safe superset, and chasing it here would be scope creep. Suggest tracking it as a follow-up under #844 rather than closing #869 silently — your call, I have not filed one.

The "LINEAR_GRAPHQL_URL" literal at runtime-codex/src/runtime.ts:665 (Codex-only, asymmetric with Claude) belongs to that same follow-up.

Approving. Two rounds, both P2s closed with minimal diffs — no reason to hold this further.


Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(tracker-github): reconcile tracker secret declarations with what the adapters inject

2 participants