mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
test: cover subscription credential client contract
Add a UI API client contract test for company-scoped subscription credentials and document BYO subscription caveats in the Docker guide.
This commit is contained in:
1 parent
c2e3b9bf0f
commit
c83fe29ff3
2 files changed
+69
No files matched your search
@@ -156,6 +156,17 @@ Notes:
|
||||
- Without API keys, the app still runs normally.
|
||||
- Adapter environment checks in Paperclip will surface missing auth/CLI prerequisites.
|
||||
|
||||
## Bring Your Own Subscription
|
||||
|
||||
Paperclip's subscription-credential flow is per user, not a company-shared secret store. Each employee links their own official Claude or Codex subscription material from the profile/settings UI, and Paperclip stores the material encrypted at rest while only showing redacted metadata back to the board.
|
||||
|
||||
Keep these caveats in mind when you run a public deployment:
|
||||
|
||||
- Do not ask one employee to paste another employee's subscription token or `auth.json` / `.credentials.json` file.
|
||||
- Do not treat the linked credential as a shared service account.
|
||||
- Runtime refreshes are written back to the same encrypted per-user record, so the stored copy stays authoritative after a CLI session rotates material.
|
||||
- Live-provider checks still depend on the employee's local CLI login state or subscription account access; automated tests cover the storage and redaction paths, but they do not replace a real host-side login.
|
||||
|
||||
## Podman Quadlet (systemd)
|
||||
|
||||
The `docker/quadlet/` directory contains unit files to run Paperclip + PostgreSQL as systemd services via Podman Quadlet.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
const mockApi = vi.hoisted(() => ({
|
||||
get: vi.fn(),
|
||||
post: vi.fn(),
|
||||
put: vi.fn(),
|
||||
delete: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("./client", () => ({
|
||||
api: mockApi,
|
||||
}));
|
||||
|
||||
import { subscriptionCredentialsApi } from "./subscriptionCredentials";
|
||||
|
||||
describe("subscriptionCredentialsApi", () => {
|
||||
it("uses company-scoped endpoints and preserves the redacted client contract", async () => {
|
||||
mockApi.get.mockResolvedValue([]);
|
||||
mockApi.put.mockResolvedValue({
|
||||
id: "cred-1",
|
||||
provider: "claude",
|
||||
});
|
||||
mockApi.post.mockResolvedValue({
|
||||
id: "cred-1",
|
||||
provider: "claude",
|
||||
});
|
||||
mockApi.delete.mockResolvedValue(undefined);
|
||||
|
||||
await subscriptionCredentialsApi.list("company-1");
|
||||
await subscriptionCredentialsApi.get("company-1", "cred-1");
|
||||
await subscriptionCredentialsApi.upsert("company-1", {
|
||||
provider: "claude",
|
||||
credentialKind: "claude_oauth_token",
|
||||
material: "secret-token",
|
||||
status: "active",
|
||||
});
|
||||
await subscriptionCredentialsApi.recordTestResult("company-1", "cred-1", {
|
||||
testStatus: "ready",
|
||||
});
|
||||
await subscriptionCredentialsApi.remove("company-1", "cred-1");
|
||||
|
||||
expect(mockApi.get).toHaveBeenNthCalledWith(1, "/companies/company-1/subscription-credentials");
|
||||
expect(mockApi.get).toHaveBeenNthCalledWith(2, "/companies/company-1/subscription-credentials/cred-1");
|
||||
expect(mockApi.put).toHaveBeenCalledWith("/companies/company-1/subscription-credentials", {
|
||||
provider: "claude",
|
||||
credentialKind: "claude_oauth_token",
|
||||
material: "secret-token",
|
||||
status: "active",
|
||||
});
|
||||
expect(mockApi.post).toHaveBeenCalledWith(
|
||||
"/companies/company-1/subscription-credentials/cred-1/test-result",
|
||||
{
|
||||
testStatus: "ready",
|
||||
},
|
||||
);
|
||||
expect(mockApi.delete).toHaveBeenCalledWith("/companies/company-1/subscription-credentials/cred-1");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user