Commit Graph
2 Commits
Author SHA1 Message Date
DottaandPaperclip e54354d9d3 fix(ai-connections): save quota credentials without recovery files (#18352)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work.
> - Managed AI connections keep the selected account in the secret
store.
> - Server quota refresh can receive a replacement token before its
database save commits.
> - That path currently writes an encrypted recovery file on the web
server.
> - Cloud web replacement should not need that file to use a saved
account.
> - This pull request saves the replacement directly and retries the
same value in memory.
> - The benefit is a smaller cloud storage contract with an explicit
sign-in recovery limit.

## Linked Issues or Issue Description

**What existing behavior does this improve?**

Server-owned OpenAI quota refresh and credential persistence during web
replacement.

**Current behavior**

Quota refresh checks local encrypted recovery storage before token
exchange. It writes the replacement to that storage before the secret
transaction commits. A replacement web receiver can therefore need the
old web volume.

**Proposed behavior**

Required database reads and locks must succeed before exchange. The same
logical refresh saves its returned replacement directly, with at most
three save attempts. It checks the current secret after an uncertain
commit response. A process that loses the unsaved replacement can
require sign-in again.

**Reason and benefit**

Postgres remains authoritative. This removes new quota recovery files
without adding another credential vault. Existing files remain readable
for cutover. Local-only Google retirement keeps its existing behavior.
Remote Google subscription sessions remain unsupported.

Related public work: Refs #14056 for managed Codex credential handover.
Searched open and closed credential-refresh pull requests; this change
does not duplicate their provider login work.

## What Changed

- Keep the exchanged replacement and its source generation in the
current refresh operation. Save retries do not repeat OAuth exchange.
- Reconcile a lost commit response from the saved credential. Grant
changes, secret versions, session epochs, selectors, and revocation
prevent a stale save.
- Stop creating or preparing quota recovery files. Preserve existing
record settlement and local Google compatibility.
- Document the v1 sign-in limit and existing Runner
persistence-before-completion contract.
- Add PostgreSQL and controlled-provider regressions for save rollback,
lost replies, revoked or changed authority, receiver process loss, and
pending Runner credential handover.

## Verification

- [Complete current-head
CI](https://github.com/paperclipai/paperclip/actions/runs/41099132607)
passed at `e4ed6551a707c814ddb2395a7358106b1e04857a`: 53 successful
checks and two intended skips. This includes full typecheck, tests,
build, and E2E gates.

- `pnpm -r typecheck` and `pnpm build` passed at
`1ebe75984be9bf19d518728d4ff440a2d7f3dbce`. Later branch changes only
repair tests. Rebase adds an unrelated master UI performance fix; the
credential and Runner handover source did not change.
- Focused credential tests passed: 2 files, 160 tests (145.62s).
Command: `pnpm exec vitest run
server/src/__tests__/ai-connections.test.ts
server/src/__tests__/plugin-task-credential-writeback.test.ts
--maxWorkers=1 --no-file-parallelism`.
- `pnpm test:run` was deliberately interrupted after 17m41s in its first
general-server chat integration phase, before any suite result. The
controller exited 130 and its wrapper exited 1. This is an incomplete
local run, not a full local pass or an observed test failure. The
coordinator stopped duplicate long local work; the complete current-head
CI suite subsequently passed. All owned test and PostgreSQL processes
were confirmed stopped.
- Database tests use real PostgreSQL 18.6 with POSIX semaphores through
a test-only loader. Provider requests use controlled fixtures; no
production OAuth mutation was made.
- Greptile reviewed current head
`e4ed6551a707c814ddb2395a7358106b1e04857a` at 5/5 with zero comments.
- The captured focused-test logs contain none of the replacement-token
fixture values.
- The receiver-loss test kills a separate Node process after one HTTP
token exchange while PostgreSQL blocks its secret insert. A new receiver
then uses the existing sign-in flow.
- The Runner case rejects a real deferred secret commit. Provider
completion remains uncalled until a new receiver commits the retained
credential.
- Initial setup failed because this host exhausted System V semaphore
resources. Another setup attempt lacked built SDK entries. Both were
setup failures, not passes. After setup repair, the first real run
passed 159/160 tests; the remaining test asserted the retired
directory-fsync contract. The replacement test forbids recovery writes
and requires one committed exchange without a file.

## Risks

- If all three saves fail and the producing server process exits, the
unsaved replacement is lost. The next failed use can require sign-in
again. This is the accepted v1 limit.
- Existing unresolved recovery files still require inventory and
settlement before their old volume is removed. This PR does not perform
deployment or delete those records.
- Local Google subscription retirement still needs its existing local
recovery ownership. It is outside the supported remote cloud scope.

## Model Used

OpenAI `gpt-6.1-sol`, with reasoning, repository tools, code execution,
and controlled integration tests. The context window size was not
supplied.

## 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
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-30 15:20:57 -05:00
Nicky LeachandPaperclip 33cc567f75 Add lease-scoped Runner task hooks to environment plugins (#15406)
## Thinking Path

> - Paperclip coordinates AI agents and their runs.
> - Environment plugins own remote capacity.
> - A plugin needs a typed API to start and stop its installed Runner.
> - Core must derive authority from the saved lease.
> - A lost reply or controller restart must not lose cleanup authority.
> - This PR adds the worker contract and the host task service.
> - Native execution and Runner changes are separate PRs.

## Linked Issues or Issue Description

**Subsystem affected**

Plugin SDK and environment lease services.

**Current behavior**

Environment plugins have no typed Runner task hook. Core cannot dispatch
these tasks or recover their credential handoff through a saved lease.

**Proposed behavior**

Add validated task operations, worker negotiation, company and project
checks, retained-session authorization, and durable cleanup. Keep
credentials out of lease metadata.

**Additional context**

This PR is the first part of a smaller series. Runner installed-home
support is in #16977. Native execution and setup are in #16978. Both are
stacked drafts. This PR does not enable native plugin execution, change
default environments, add a route, or add a database migration.

## What Changed

- Add `supportsTasks` and `onEnvironmentTask` with seven typed
operations.
- Validate worker requests and responses. Reject shell commands and file
transfer operations.
- Pin dispatch and cleanup to the saved company, lease, plugin, and
driver.
- Authorize projects and retained sessions. Validate the current run
separately from the retained PRP identity.
- Save dispatch before the provider call. Fence admission during
cleanup. Require observed process termination.
- Save account writeback authority on the lease. Recover Codex refreshes
through the existing account and secret services.
- Document the task API. Keep the Runner, heartbeat, setup, workspace,
and provider changes in later PRs.

## Verification

- Full `pnpm -r typecheck` and `pnpm build` passed on the separated API
scope.
- 201 focused tests passed: SDK worker dispatch, task validation,
PostgreSQL task lineage, credential recovery, and existing environment
cleanup.
- The lineage test covers a third run, repeated same-run replacements, a
stale submitting run, and exact termination receipts.
- Initial commands hit sandbox socket/IPC restrictions. The permitted
runs executed PostgreSQL and passed. A typecheck attempt lacked Cargo in
PATH; the run with the installed toolchain passed.
- The earlier combined implementation had a full local run with 22,286
passing tests, 120 skips, and eight failed assertions. Task fixture
failures were fixed before this split. Remaining host Git and
temporary-path assertions are recorded in the previous PR revision. This
split does not claim a fresh full local suite pass.
- The standard Greptile review scored this API head 5/5 with no
unresolved threads. CI is green. The single Apex review also scored this
head 5/5 with no actionable findings.
- Fresh API CI lost a self-hosted runner during server shard 9. GitHub
reported lost communication, with no failed test step. The affected jobs
passed on retry without code changes.
- CI on the prior combined head failed an unchanged workspace dev-server
readiness case. No unrelated test fix is included here. Fresh CI is
required for this smaller head.
- This scope does not run a provider or a Cloud test. The user owns
deployment and the intermediate Cloud test.

## Risks

- The API is opt-in. Native plugin execution requires the later
integrations.
- Providers must make task submission idempotent and prove descendant
termination.
- A failed status read or credential export keeps the lease available
for cleanup.
- Codex refresh writeback requires the same active grant, secret
reference, and session epoch. Revocation or account replacement discards
the old refresh.

## Model Used

OpenAI GPT-6 through Codex. Used source inspection, code execution,
tests, and GitHub tools. The exact served model ID and context-window
size are not exposed in this session.

## 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 local checks and recorded failures and their results
above
- [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
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-10-20 09:14:23 -07:00