fix(server): resolve duplicate scrubGitCredentialText declaration on master (#10722)

## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - #10719 and #10720 both hardened credential scrubbing for server-side
git operations
> - #10719 defined `scrubGitCredentialText` locally in `heartbeat.ts`;
#10720 imported the identical function from the new `git-credentials.ts`
> - The two merged cleanly textually, but together they leave
`heartbeat.ts` with an import that conflicts with a local declaration
(TS2440)
> - This pull request keeps the `git-credentials.ts` copy as canonical,
drops the heartbeat-local duplicate, and re-exports the import so
existing importers are unchanged
> - The benefit is that master typechecks, builds, and produces Docker
images again

## Linked Issues or Issue Description

**What happened?**

After #10719 and #10720 merged, master fails typecheck, the server
build, and both Docker image builds with
`src/services/heartbeat.ts(76,3): error TS2440: Import declaration
conflicts with local declaration of 'scrubGitCredentialText'`. The
canary release run for e0c2448267 failed for the same reason, so no
`@paperclipai/db` canary carrying migrations 0201/0202 can publish.

**Expected behavior**

Master typechecks and builds; one canonical `scrubGitCredentialText`
lives in `git-credentials.ts`.

**Steps to reproduce**

`pnpm --filter @paperclipai/server typecheck` on e0c2448267.

**Paperclip version or commit**

`master` (e0c2448267).

## What Changed

- Removed the heartbeat-local `scrubGitCredentialText` definition
(byte-identical to the `git-credentials.ts` copy).
- Re-exported the imported function from `heartbeat.ts` so existing
importers, including `heartbeat-workspace-session.test.ts`, keep
working.

## Verification

- `pnpm --filter @paperclipai/server typecheck` — clean.
- `cd server && npx vitest run
src/__tests__/heartbeat-workspace-session.test.ts
src/__tests__/git-credentials.test.ts
src/__tests__/heartbeat-managed-clone-credentials.test.ts` — 167 tests
pass.

## Risks

Low risk — deletes one of two identical implementations and preserves
the public import surface via a re-export.

## Model Used

Claude Fable 5 (`claude-fable-5`, extended thinking, agentic tool use
via Claude Code CLI).

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [ ] All Paperclip CI gates are green
- [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge
This commit is contained in:
Devin Foley 2026-08-02 21:06:53 -07:00 committed by GitHub
parent e0c2448267
commit 75f6256b76
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 3 additions and 14 deletions

View File

@ -76,6 +76,9 @@ import {
scrubGitCredentialText,
type GitRemoteAuthProvider,
} from "./git-credentials.js";
// Re-exported because heartbeat's workspace surface exposed the scrubber before the
// git-credentials module became its canonical home; existing importers keep working.
export { scrubGitCredentialText };
import { publishLiveEvent } from "./live-events.js";
import { normalizeResponsibleUserDenialCode } from "./responsible-user-denial-run-outcomes.js";
import { getRunLogStore, type RunLogHandle } from "./run-log-store.js";
@ -2476,20 +2479,6 @@ export type WorkspaceMaterializationFailure = {
error: string;
};
/**
* Mask credential material embedded in URLs so it never reaches warnings, run errors, or
* persisted payloads: userinfo on any scheme (`https://user:token@host`,
* `ssh://user:pass@host`) and the entire query string of any URL (`?access_token=…` and
* every other parameter masked wholesale rather than by an inevitably incomplete
* parameter-name list). Scp-style remotes (`git@host:path`) carry no password and are left
* alone.
*/
export function scrubGitCredentialText(text: string): string {
return text
.replace(/([a-z][a-z0-9+.-]*:\/\/)[^/@\s]+@/gi, "$1***@")
.replace(/([a-z][a-z0-9+.-]*:\/\/[^\s"'?]*)\?[^\s"']*/gi, "$1?***");
}
export type ResolvedWorkspaceForRun = {
cwd: string;
source: "project_primary" | "task_session" | "agent_home";