Files
paperclip/packages/db/src/migrations/meta/_journal.json
T
Devin Foley fc95699fde fix(server): enforce agent secret binding sync across lifecycle flows (#8307)
## Thinking Path

> - Paperclip is the control plane people use to create, configure, and
run AI agents for work.
> - This change sits in the server-side agent lifecycle and
secret-binding subsystem, where adapter config `env` entries can
reference company secrets.
> - An incident (while trying to configure a Novita sandbox) showed that
an agent can reach a broken runtime state if `adapterConfig.env`
contains `secret_ref` entries but the matching `company_secret_bindings`
rows are missing.
> - The immediate run-path guard and error-surfacing work made the
failure diagnosable, but they did not fully prevent new broken agents
from being created.
> - The risk came from create and approval flows being responsible for
remembering to sync bindings at each call site, which is easy to miss as
new flows are added.
> - This pull request moves the invariant into `agentService`
create/update/activate paths, keeps the existing hire-flow fix, and adds
regression coverage for create, update, and legacy pending-approval
recovery.
> - The benefit is that agent secret binding integrity is enforced
closer to the data mutation point, so future callers inherit the
protection automatically.

## Linked Issues or Issue Description

Refs #8309

### What happened?
A Paperclip agent could persist `adapterConfig.env` `secret_ref` entries
without matching agent-scoped `company_secret_bindings` rows. When that
happened, the config UI could still look configured, but the real run
path failed pre-dispatch because the secret was not actually bound to
that agent.

### Expected behavior
Every normal agent create, config-update, and pending-approval
activation flow should leave the agent with secret bindings that match
its persisted secret-ref env config.

### Steps to reproduce
1. Create or activate an agent through a flow that persists
`adapterConfig.env` secret refs without synchronizing
`company_secret_bindings`.
2. Observe that the config state can still appear populated.
3. Start a run for that agent.
4. Observe that pre-dispatch binding validation fails because the secret
reference exists but the agent binding does not.

### Deployment mode
Local dev (`pnpm dev`)

### Installation method
Built from source (`pnpm dev` / `pnpm build`)

### Agent adapter(s) involved
- Claude Code
- Not adapter-specific (core bug)

### Database mode
Embedded PGlite / embedded local dev database flow

### Access context
Board (human operator) created or approved the agent; agent runtime
later consumed the config.

### Additional context
This PR focuses on preventing new broken states from normal service
flows and on backfilling the covered legacy pending-approval activation
path.

## What Changed

- Kept the existing branch-local hire-flow fix that synchronized
bindings for route and approval paths.
- Moved the binding integrity invariant into `agentService.create()`,
`agentService.update()` when `adapterConfig` changes, and
`agentService.activatePendingApproval()`.
- Added `server/src/__tests__/agents-service-secret-bindings.test.ts`
covering create-time sync, update-time resync, and backfill for legacy
pending-approval agents.
- Removed now-redundant route-layer and approval-layer binding sync
calls once the service layer became authoritative.
- Simplified the affected unit tests so route/approval tests no longer
assert service-owned binding writes directly.

## Verification

- `pnpm --filter @paperclipai/server typecheck`
- `pnpm exec vitest run
server/src/__tests__/agents-service-secret-bindings.test.ts
server/src/__tests__/approvals-service.test.ts
server/src/__tests__/agent-skills-routes.test.ts`

## Risks

- Low to medium risk.
- This changes where secret-binding synchronization is enforced, so any
unexpected caller that relied on upper-layer manual sync behavior could
behave differently.
- Agent create/update/activation flows now perform binding
synchronization consistently, which adds binding-table writes at those
mutation points.
- This PR does not retroactively scan and heal every already-broken
historical agent row; it prevents and backfills through the covered
service flows.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex / GPT-5 Codex class model via `codex_local`
- Session model family: GPT-5 Codex
- Tool-assisted coding with shell, git, HTTP, and local test execution
- Reasoning mode: medium interactive tool-use workflow

## 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 run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [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-06-18 21:26:36 -07:00

734 lines
15 KiB
JSON

{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1771300567463,
"tag": "0000_mature_masked_marvel",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1771349039633,
"tag": "0001_fast_northstar",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1771349403162,
"tag": "0002_big_zaladane",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1771456737635,
"tag": "0003_shallow_quentin_quire",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1771545600000,
"tag": "0004_issue_identifiers",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1771545601000,
"tag": "0005_chief_luke_cage",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1771545602000,
"tag": "0006_overjoyed_mister_sinister",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1771545603000,
"tag": "0007_new_quentin_quire",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1771534160426,
"tag": "0008_amused_zzzax",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1771534211029,
"tag": "0009_fast_jackal",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1771605173513,
"tag": "0010_stale_justin_hammer",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1771616419708,
"tag": "0011_windy_corsair",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1771619674673,
"tag": "0012_perpetual_ser_duncan",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1771623691139,
"tag": "0013_dashing_wasp",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1771691806349,
"tag": "0014_many_mikhail_rasputin",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1771865100000,
"tag": "0015_project_color_archived",
"breakpoints": true
},
{
"idx": 16,
"version": "7",
"when": 1771955900000,
"tag": "0016_agent_icon",
"breakpoints": true
},
{
"idx": 17,
"version": "7",
"when": 1771883888199,
"tag": "0017_tiresome_gabe_jones",
"breakpoints": true
},
{
"idx": 18,
"version": "7",
"when": 1771897769629,
"tag": "0018_flat_sleepwalker",
"breakpoints": true
},
{
"idx": 19,
"version": "7",
"when": 1772029333401,
"tag": "0019_public_victor_mancha",
"breakpoints": true
},
{
"idx": 20,
"version": "7",
"when": 1772032176413,
"tag": "0020_white_anita_blake",
"breakpoints": true
},
{
"idx": 21,
"version": "7",
"when": 1772122471656,
"tag": "0021_chief_vindicator",
"breakpoints": true
},
{
"idx": 22,
"version": "7",
"when": 1772186400000,
"tag": "0022_company_brand_color",
"breakpoints": true
},
{
"idx": 23,
"version": "7",
"when": 1772139727599,
"tag": "0023_fair_lethal_legion",
"breakpoints": true
},
{
"idx": 24,
"version": "7",
"when": 1772806603601,
"tag": "0024_far_beast",
"breakpoints": true
},
{
"idx": 25,
"version": "7",
"when": 1772807461603,
"tag": "0025_nasty_salo",
"breakpoints": true
},
{
"idx": 26,
"version": "7",
"when": 1773089625430,
"tag": "0026_lying_pete_wisdom",
"breakpoints": true
},
{
"idx": 27,
"version": "7",
"when": 1773150731736,
"tag": "0027_tranquil_tenebrous",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1773432085646,
"tag": "0028_harsh_goliath",
"breakpoints": true
},
{
"idx": 29,
"version": "7",
"when": 1773417600000,
"tag": "0029_plugin_tables",
"breakpoints": true
},
{
"idx": 30,
"version": "7",
"when": 1773670925214,
"tag": "0030_rich_magneto",
"breakpoints": true
},
{
"idx": 31,
"version": "7",
"when": 1773511922713,
"tag": "0031_zippy_magma",
"breakpoints": true
},
{
"idx": 32,
"version": "7",
"when": 1773542934499,
"tag": "0032_pretty_doctor_octopus",
"breakpoints": true
},
{
"idx": 33,
"version": "7",
"when": 1773664961967,
"tag": "0033_shiny_black_tarantula",
"breakpoints": true
},
{
"idx": 34,
"version": "7",
"when": 1773697572188,
"tag": "0034_fat_dormammu",
"breakpoints": true
},
{
"idx": 35,
"version": "7",
"when": 1773698696169,
"tag": "0035_marvelous_satana",
"breakpoints": true
},
{
"idx": 36,
"version": "7",
"when": 1773756213455,
"tag": "0036_cheerful_nitro",
"breakpoints": true
},
{
"idx": 37,
"version": "7",
"when": 1773756922363,
"tag": "0037_friendly_eddie_brock",
"breakpoints": true
},
{
"idx": 38,
"version": "7",
"when": 1773931592563,
"tag": "0038_careless_iron_monger",
"breakpoints": true
},
{
"idx": 39,
"version": "7",
"when": 1773926116580,
"tag": "0039_fat_magneto",
"breakpoints": true
},
{
"idx": 40,
"version": "7",
"when": 1773927102783,
"tag": "0040_eager_shotgun",
"breakpoints": true
},
{
"idx": 41,
"version": "7",
"when": 1774011294562,
"tag": "0041_curly_maria_hill",
"breakpoints": true
},
{
"idx": 42,
"version": "7",
"when": 1774031825634,
"tag": "0042_spotty_the_renegades",
"breakpoints": true
},
{
"idx": 43,
"version": "7",
"when": 1774008910991,
"tag": "0043_reflective_captain_universe",
"breakpoints": true
},
{
"idx": 44,
"version": "7",
"when": 1774269579794,
"tag": "0044_illegal_toad",
"breakpoints": true
},
{
"idx": 45,
"version": "7",
"when": 1774530504348,
"tag": "0045_workable_shockwave",
"breakpoints": true
},
{
"idx": 46,
"version": "7",
"when": 1774960197878,
"tag": "0046_smooth_sentinels",
"breakpoints": true
},
{
"idx": 47,
"version": "7",
"when": 1775137972687,
"tag": "0047_overjoyed_groot",
"breakpoints": true
},
{
"idx": 48,
"version": "7",
"when": 1775145655557,
"tag": "0048_flashy_marrow",
"breakpoints": true
},
{
"idx": 49,
"version": "7",
"when": 1775349863293,
"tag": "0049_flawless_abomination",
"breakpoints": true
},
{
"idx": 50,
"version": "7",
"when": 1775487782768,
"tag": "0050_stiff_luckman",
"breakpoints": true
},
{
"idx": 51,
"version": "7",
"when": 1775524651831,
"tag": "0051_young_korg",
"breakpoints": true
},
{
"idx": 52,
"version": "7",
"when": 1775571715162,
"tag": "0052_mushy_trauma",
"breakpoints": true
},
{
"idx": 53,
"version": "7",
"when": 1775604018515,
"tag": "0053_sharp_wild_child",
"breakpoints": true
},
{
"idx": 54,
"version": "7",
"when": 1775750400000,
"tag": "0054_draft_routines",
"breakpoints": true
},
{
"idx": 55,
"version": "7",
"when": 1775825256196,
"tag": "0055_kind_weapon_omega",
"breakpoints": true
},
{
"idx": 56,
"version": "7",
"when": 1776084034244,
"tag": "0056_spooky_ultragirl",
"breakpoints": true
},
{
"idx": 57,
"version": "7",
"when": 1776309613598,
"tag": "0057_tidy_join_requests",
"breakpoints": true
},
{
"idx": 58,
"version": "7",
"when": 1776542245004,
"tag": "0058_wealthy_starbolt",
"breakpoints": true
},
{
"idx": 59,
"version": "7",
"when": 1776542246000,
"tag": "0059_plugin_database_namespaces",
"breakpoints": true
},
{
"idx": 60,
"version": "7",
"when": 1776717606743,
"tag": "0060_orange_annihilus",
"breakpoints": true
},
{
"idx": 61,
"version": "7",
"when": 1776785165389,
"tag": "0061_lively_thor_girl",
"breakpoints": true
},
{
"idx": 62,
"version": "7",
"when": 1776780000000,
"tag": "0062_routine_run_dispatch_fingerprint",
"breakpoints": true
},
{
"idx": 63,
"version": "7",
"when": 1776780001000,
"tag": "0063_issue_thread_interactions",
"breakpoints": true
},
{
"idx": 64,
"version": "7",
"when": 1776780002000,
"tag": "0064_issue_thread_interaction_idempotency",
"breakpoints": true
},
{
"idx": 65,
"version": "7",
"when": 1776903900000,
"tag": "0065_environments",
"breakpoints": true
},
{
"idx": 66,
"version": "7",
"when": 1776903901000,
"tag": "0066_issue_tree_holds",
"breakpoints": true
},
{
"idx": 67,
"version": "7",
"when": 1776904200000,
"tag": "0067_agent_default_environment",
"breakpoints": true
},
{
"idx": 68,
"version": "7",
"when": 1776959400000,
"tag": "0068_environment_local_driver_unique",
"breakpoints": true
},
{
"idx": 69,
"version": "7",
"when": 1776780003000,
"tag": "0069_liveness_recovery_dedupe",
"breakpoints": true
},
{
"idx": 70,
"version": "7",
"when": 1776780004000,
"tag": "0070_active_run_output_watchdog",
"breakpoints": true
},
{
"idx": 71,
"version": "7",
"when": 1777131234000,
"tag": "0071_default_hire_approval_off",
"breakpoints": true
},
{
"idx": 72,
"version": "7",
"when": 1777305216238,
"tag": "0072_large_sandman",
"breakpoints": true
},
{
"idx": 73,
"version": "7",
"when": 1777382021347,
"tag": "0073_shiny_salo",
"breakpoints": true
},
{
"idx": 74,
"version": "7",
"when": 1777384535070,
"tag": "0074_striped_genesis",
"breakpoints": true
},
{
"idx": 75,
"version": "7",
"when": 1777572332006,
"tag": "0075_cultured_sebastian_shaw",
"breakpoints": true
},
{
"idx": 76,
"version": "7",
"when": 1777675301279,
"tag": "0076_useful_elektra",
"breakpoints": true
},
{
"idx": 77,
"version": "7",
"when": 1777933347806,
"tag": "0077_unusual_karnak",
"breakpoints": true
},
{
"idx": 78,
"version": "7",
"when": 1778004024976,
"tag": "0078_white_darwin",
"breakpoints": true
},
{
"idx": 79,
"version": "7",
"when": 1777821410992,
"tag": "0079_company_search_document_indexes",
"breakpoints": true
},
{
"idx": 80,
"version": "7",
"when": 1777849000000,
"tag": "0080_company_search_fuzzystrmatch",
"breakpoints": true
},
{
"idx": 81,
"version": "7",
"when": 1778067785040,
"tag": "0081_optimal_dormammu",
"breakpoints": true
},
{
"idx": 82,
"version": "7",
"when": 1778067785041,
"tag": "0082_dry_vision",
"breakpoints": true
},
{
"idx": 83,
"version": "7",
"when": 1778074536410,
"tag": "0083_company_secret_provider_configs",
"breakpoints": true
},
{
"idx": 84,
"version": "7",
"when": 1778355326070,
"tag": "0084_issue_recovery_actions",
"breakpoints": true
},
{
"idx": 85,
"version": "7",
"when": 1778787362162,
"tag": "0085_tranquil_the_executioner",
"breakpoints": true
},
{
"idx": 86,
"version": "7",
"when": 1778976000000,
"tag": "0086_routine_env_runtime_contract",
"breakpoints": true
},
{
"idx": 87,
"version": "7",
"when": 1779360000000,
"tag": "0087_backfill_environment_manage_human_defaults",
"breakpoints": true
},
{
"idx": 88,
"version": "7",
"when": 1779446400000,
"tag": "0088_backfill_principal_access_compatibility",
"breakpoints": true
},
{
"idx": 89,
"version": "7",
"when": 1779129600000,
"tag": "0089_cloud_upstreams",
"breakpoints": true
},
{
"idx": 90,
"version": "7",
"when": 1779573019125,
"tag": "0090_resource_memberships",
"breakpoints": true
},
{
"idx": 91,
"version": "7",
"when": 1778810394522,
"tag": "0091_old_swarm",
"breakpoints": true
},
{
"idx": 92,
"version": "7",
"when": 1779999768200,
"tag": "0092_mighty_puma",
"breakpoints": true
},
{
"idx": 93,
"version": "7",
"when": 1780040470886,
"tag": "0093_giant_green_goblin",
"breakpoints": true
},
{
"idx": 94,
"version": "7",
"when": 1780533900000,
"tag": "0094_backfill_archived_company_agent_pauses",
"breakpoints": true
},
{
"idx": 95,
"version": "7",
"when": 1780507597454,
"tag": "0095_issue_comment_tombstones",
"breakpoints": true
},
{
"idx": 96,
"version": "7",
"when": 1780507597455,
"tag": "0096_document_annotation_issue_comment_links",
"breakpoints": true
},
{
"idx": 97,
"version": "7",
"when": 1780534000000,
"tag": "0097_low_trust_source_trust",
"breakpoints": true
},
{
"idx": 98,
"version": "7",
"when": 1780534200000,
"tag": "0098_project_icon",
"breakpoints": true
},
{
"idx": 99,
"version": "7",
"when": 1781130000000,
"tag": "0099_skills_store_foundation",
"breakpoints": true
},
{
"idx": 100,
"version": "7",
"when": 1781480000000,
"tag": "0100_skill_install_count_backfill",
"breakpoints": true
},
{
"idx": 101,
"version": "7",
"when": 1781490000000,
"tag": "0101_plugin_company_id_tenant_isolation",
"breakpoints": true
},
{
"idx": 102,
"version": "7",
"when": 1781490100000,
"tag": "0102_managed_sandbox_dedup_index",
"breakpoints": true
},
{
"idx": 103,
"version": "7",
"when": 1781490200000,
"tag": "0103_agent_error_reason",
"breakpoints": true
}
]
}