Skip to content

fix: resolve UUID secret refs with host contract - #192

Open
steingran wants to merge 2 commits into
alvarosanchez:mainfrom
steingran:fix/structured-secret-ref-host-compat
Open

fix: resolve UUID secret refs with host contract#192
steingran wants to merge 2 commits into
alvarosanchez:mainfrom
steingran:fix/structured-secret-ref-host-compat

Conversation

@steingran

Copy link
Copy Markdown
Contributor

What changed

  • Convert UUID-backed saved secret references to the structured { type: "secret_ref", secretId } form required by newer Paperclip hosts.
  • Preserve legacy non-UUID references unchanged.
  • Permit the existing company-scoped token fallback only for documented host-unavailable/invalid-secret-reference errors; unrelated secret-provider failures still fail closed.
  • Add focused regression coverage for structured refs, scoped fallback behavior, and fail-closed provider errors.

Root cause

The published worker normalizes saved secret refs to UUID strings and passes those strings directly to ctx.secrets.resolve. Newer Paperclip hosts require UUID-backed refs as structured secret_ref objects, so configured GitHub operations fail before the already provisioned company-scoped fallback can be considered.

Impact

This restores compatibility with the current host secret-reference contract without rotating, reconnecting, or logging credentials. It does not widen fallback behavior for permission failures or arbitrary resolver errors.

Validation

The originating implementation run passed:

  • pnpm typecheck
  • focused structured-ref/fallback tests (3/3)
  • full pnpm test
  • pnpm build
  • git diff --check

Publication recovery verified this branch is exactly one commit ahead of upstream main and changes only src/worker.ts and tests/plugin.spec.ts (104 insertions, 9 deletions).

@steingran
steingran marked this pull request as ready for review July 24, 2026 02:04
Copilot AI review requested due to automatic review settings July 24, 2026 02:04

Copy link
Copy Markdown
Contributor Author

Ready for review at b1a747ca4089c2362c9970d80761ba6ba00ed8d6 (one commit ahead of main; only src/worker.ts and tests/plugin.spec.ts). CI run 552 passed. The change keeps non-UUID refs unchanged and limits fallback to documented host-unavailable/invalid-ref cases; unrelated secret-provider errors remain fail-closed. No credentials were changed, logged, rotated, or reconnected.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the plugin worker to be compatible with newer Paperclip hosts that require UUID-backed secret references to be passed as structured { type: "secret_ref", secretId } objects (rather than raw UUID strings), while keeping legacy non-UUID references unchanged. It also tightens fallback behavior so the company-scoped token fallback is only used for specific “secret ref unavailable/invalid ref” host errors, and adds targeted regression tests.

Changes:

  • Add a wrapper (resolvePluginSecret) that converts UUID-shaped secret refs into structured secret_ref objects before calling ctx.secrets.resolve.
  • Refine the “secret refs unavailable” error classification to include the documented invalid-secret-reference host error.
  • Add regression tests for structured secret refs, scoped fallback behavior, and fail-closed resolver/provider errors.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
src/worker.ts Adds UUID→structured secret ref conversion and narrows fallback eligibility to specific host error cases.
tests/plugin.spec.ts Adds regression tests covering structured secret refs, fallback gating, and fail-closed resolver errors.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/worker.ts Outdated
Comment thread src/worker.ts Outdated
@steingran

Copy link
Copy Markdown
Contributor Author

@alvarosanchez Please review the updated head 4f8a497 after CI completes. It resolves both secret-reference threads (UUIDv6/v7/v8 structured refs and resolver method binding); focused regression, typecheck, full test suite, and build passed.

@alvarosanchez alvarosanchez 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.

Requesting changes because the patch does not work against either side of the repository's stated host-compatibility range.

  1. Blocking — the newer host contract requires an explicit company scope, but every new call omits it (src/worker.ts:2929-2936). Since Paperclip v2026.720.0, PluginSecretsClient.resolve forwards options.companyId/configPath, and the host rejects a call without companyId before resolution. resolvePluginSecret widens only the first argument and invokes secrets.resolve(...) with one argument, so all four changed paths still fail with companyId is required for this operation. The new unit tests replace harness.ctx.secrets.resolve with a permissive one-argument stub, so they cannot detect this production RPC failure.

  2. Blocking — the plugin still stores refs as UUID strings, so newer hosts do not create the binding that structured resolution requires (src/manifest.ts:57-69, src/ui/plugin-config.ts:1-6, and the config writes around src/ui/index.tsx:12025-12028 / 12132-12135). Current Paperclip extracts/binds object-shaped { type: "secret_ref", secretId, version? } values from company-scoped plugin config and deliberately ignores UUID strings outside schema-declared secret fields. This manifest declares these map values as plain strings, and the UI normalizers discard object values. Converting the UUID only at src/worker.ts:2923-2926 is therefore too late: after adding companyId, the host still returns binding_missing because no plugin binding was registered.

  3. Blocking — unconditional UUID conversion breaks the repository's enforced Paperclip 2026.626.0 baseline (src/worker.ts:2923-2926; baseline asserted in tests/build-script.spec.mjs:10,54-58). That host accepts only a UUID string. Passing the new object produces Invalid secret reference: [object Object], which the broadened fallback classifier does not recognize because the message contains neither secret_ref nor the old disabled-host wording. GitHub and board secret resolution therefore regress on the supported baseline.

The full local pnpm typecheck, pnpm test (335/335), and pnpm build pass at head 4f8a497e1851a28b774d05144bac246f85173f19, but those tests exercise mocked resolver shapes rather than either real host bridge. Please either implement and test an explicit dual-host path, or intentionally raise/synchronize the minimum host+SDK boundary; for the newer path, persist structured refs in trusted company-scoped config and call resolve(ref, { companyId, configPath }) through an SDK version that forwards those options.


✨ This message was AI-generated using gpt-5.6-sol

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.

3 participants