mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-02 02:07:25 +08:00
revert(apps): restore Google connector visibility (#13552)
## Thinking Path > - Paperclip helps people manage AI agents for work. > - The Connectors catalog lists services that agents can use. > - PR #13551 temporarily hid Google connectors. > - We now want to restore their catalog visibility. > - This PR reverts that change and restores the previous catalog behavior. ## Linked Issues or Issue Description Refs: #13551 Revert the temporary removal of Google connectors from the UI. ## What Changed - Restore Gmail and eight Google Workspace entries to the catalog. - Restore the matching branding flags and original catalog and service tests. - Remove the temporary-hiding documentation note. This is an exact revert of commit `cf1e873ab24277d55ffd3ab06074f77014dc4015`. ## Verification - Passed: 507 catalog, UI, and connection service tests. - Passed: `pnpm check:token-gates` and `node scripts/check-app-brand-assets.mjs`. - Passed: `pnpm --filter @paperclipai/ui... build` and `pnpm --filter @paperclipai/ui... typecheck`. - Full local build and typecheck stop at the Rust runner because `cargo` is not installed. - Full local Vitest was not repeated because the unchanged base has confirmed macOS skill-cache permission failures. The full CI suites passed. - Passed: all GitHub CI gates; Greptile 5/5 on commit `4e3dddef0ebfef1f99001e7735822ed4cba852ab`, with no review threads. - Reviewer check: open Connectors and confirm that Gmail and Google Workspace entries appear again. ## Risks Low risk. This restores the previous catalog visibility and setup entry points. Connector implementations and saved connection data are retained. ## Model Used OpenAI GPT-6 through Codex, with reasoning, tool use, and code execution. The exact deployment 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 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>
This commit is contained in:
@@ -15,10 +15,6 @@ Provider notes: [Google Workspace](./GOOGLE-WORKSPACE.md),
|
||||
[AgentMail](./AGENTMAIL.md), and [iMessage Photon](./IMESSAGE-PHOTON.md). Optional credential custody:
|
||||
[Vercel Connect](./VERCEL-CONNECT.md).
|
||||
|
||||
Gmail and Google Workspace connectors are temporarily hidden from the connector
|
||||
catalog. Their definitions and existing connections are retained. Restore their
|
||||
catalog visibility through `APP_STORE_HIDDEN_SLUGS` and the app branding manifest.
|
||||
|
||||
Post-read action: classify a new integration request, pick the right Paperclip
|
||||
layer to change, and avoid creating a parallel connection framework.
|
||||
|
||||
|
||||
@@ -663,7 +663,7 @@ describe("AppDefinition catalog", () => {
|
||||
);
|
||||
}
|
||||
});
|
||||
it("withholds hidden providers from the app store without deleting their definitions", () => {
|
||||
it("withholds unverified and reserved providers from the app store without deleting their definitions", () => {
|
||||
expect([...APP_STORE_HIDDEN_SLUGS].sort()).toEqual([
|
||||
"beehiiv",
|
||||
"bitly",
|
||||
@@ -674,15 +674,6 @@ describe("AppDefinition catalog", () => {
|
||||
"context7",
|
||||
"egnyte",
|
||||
"embat",
|
||||
"gmail",
|
||||
"google-calendar",
|
||||
"google-chat",
|
||||
"google-docs",
|
||||
"google-drive",
|
||||
"google-people",
|
||||
"google-sheets",
|
||||
"google-slides",
|
||||
"google-workspace-search",
|
||||
"kernel",
|
||||
"local-falcon",
|
||||
"make",
|
||||
@@ -696,7 +687,7 @@ describe("AppDefinition catalog", () => {
|
||||
"ticktick",
|
||||
"xero",
|
||||
]);
|
||||
expect(APP_STORE_DEFINITIONS).toHaveLength(38);
|
||||
expect(APP_STORE_DEFINITIONS).toHaveLength(47);
|
||||
const connectableSlugs = new Set(
|
||||
CONNECTABLE_APP_DEFINITIONS.map((entry) => entry.slug),
|
||||
);
|
||||
|
||||
@@ -52,15 +52,6 @@ export const APP_STORE_HIDDEN_SLUGS = new Set([
|
||||
"context7",
|
||||
"egnyte",
|
||||
"embat",
|
||||
"gmail",
|
||||
"google-calendar",
|
||||
"google-chat",
|
||||
"google-docs",
|
||||
"google-drive",
|
||||
"google-people",
|
||||
"google-sheets",
|
||||
"google-slides",
|
||||
"google-workspace-search",
|
||||
"kernel",
|
||||
"local-falcon",
|
||||
"make",
|
||||
|
||||
@@ -85,7 +85,7 @@ import { toolAccessRoutes } from "../routes/tool-access.js";
|
||||
import { errorHandler } from "../middleware/index.js";
|
||||
import type { ComposioClient } from "../services/composio.js";
|
||||
import type { VercelConnectClient } from "../services/vercel-connect.js";
|
||||
import { appWithPaperclipCloudConnectorAvailability, invalidatePaperclipCloudConnectorCapabilities, type PaperclipCloudConnector } from "../services/paperclip-cloud-connector.js";
|
||||
import { invalidatePaperclipCloudConnectorCapabilities, type PaperclipCloudConnector } from "../services/paperclip-cloud-connector.js";
|
||||
|
||||
const embeddedPostgresSupport = await getEmbeddedPostgresTestSupport();
|
||||
const describeEmbeddedPostgres = embeddedPostgresSupport.supported
|
||||
@@ -5087,12 +5087,21 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
"sentry",
|
||||
"zapier",
|
||||
"linear",
|
||||
"gmail",
|
||||
"google-drive",
|
||||
"google-docs",
|
||||
"google-sheets",
|
||||
"google-slides",
|
||||
"google-calendar",
|
||||
"google-chat",
|
||||
"google-people",
|
||||
"google-workspace-search",
|
||||
"github",
|
||||
]),
|
||||
);
|
||||
expect(res.body.apps).toHaveLength(38);
|
||||
expect(res.body.apps).toHaveLength(47);
|
||||
expect(
|
||||
appWithPaperclipCloudConnectorAvailability(getConnectableAppDefinition("gmail")!, [])
|
||||
res.body.apps.find((app: { slug: string }) => app.slug === "gmail")
|
||||
.ownershipAvailability,
|
||||
).toEqual({
|
||||
platform_shared: false,
|
||||
@@ -5128,16 +5137,17 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
expect(getConnectableAppDefinition("google-sheets")!.methods).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({ key: "local", transport: "local_stdio" }),
|
||||
expect.objectContaining({
|
||||
slug: "google-sheets",
|
||||
methods: expect.arrayContaining([
|
||||
expect.objectContaining({ key: "local", transport: "local_stdio" }),
|
||||
]),
|
||||
}),
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it("hides Google from the gallery while retaining managed methods for signed profiles", async () => {
|
||||
it("exposes managed Google methods only for profiles signed for this enrolled instance", async () => {
|
||||
const company = await createCompany(db);
|
||||
const userId = `gallery-pilot-${randomUUID()}`;
|
||||
const pilotConnector = fakeGoogleWorkspaceConnector(
|
||||
@@ -5159,11 +5169,8 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
),
|
||||
).get(`/api/companies/${company.id}/tools/gallery`);
|
||||
expect(nonPilot.status).toBe(200);
|
||||
expect(nonPilot.body.apps.find(
|
||||
const nonPilotGmail = nonPilot.body.apps.find(
|
||||
(app: { slug: string }) => app.slug === "gmail",
|
||||
)).toBeUndefined();
|
||||
const nonPilotGmail = appWithPaperclipCloudConnectorAvailability(
|
||||
getConnectableAppDefinition("gmail")!, await nonPilotConnector.getCapabilities(),
|
||||
);
|
||||
expect(nonPilotGmail.ownershipAvailability.platform_shared).toBe(false);
|
||||
expect(
|
||||
@@ -5185,11 +5192,8 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
),
|
||||
).get(`/api/companies/${company.id}/tools/gallery`);
|
||||
expect(pilot.status).toBe(200);
|
||||
expect(pilot.body.apps.find(
|
||||
const pilotGmail = pilot.body.apps.find(
|
||||
(app: { slug: string }) => app.slug === "gmail",
|
||||
)).toBeUndefined();
|
||||
const pilotGmail = appWithPaperclipCloudConnectorAvailability(
|
||||
getConnectableAppDefinition("gmail")!, await pilotConnector.getCapabilities(),
|
||||
);
|
||||
expect(pilotGmail.ownershipAvailability.platform_shared).toBe(true);
|
||||
expect(
|
||||
@@ -7040,7 +7044,7 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
["local_trusted", "private", "http://127.0.0.1:3102"] as const,
|
||||
["authenticated", "public", "https://tenant.paperclip.app"] as const,
|
||||
].map(([deploymentMode, deploymentExposure, origin]) => ({ profile, deploymentMode, deploymentExposure, origin }))))(
|
||||
"connects retained Workspace $profile without mutating definitions in $deploymentMode",
|
||||
"connects advertised Workspace $profile without mutating definitions in $deploymentMode",
|
||||
async ({ profile, deploymentMode, deploymentExposure, origin }) => {
|
||||
const slug = GOOGLE_WORKSPACE_CONNECTOR_PROFILES[profile].appSlug;
|
||||
const methodKey = getConnectableAppDefinition(slug)!.methods.find((method) => method.connectorProfile === profile)!.key;
|
||||
@@ -7054,7 +7058,7 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
undefined, { deploymentMode, deploymentExposure, paperclipCloudConnector: connector });
|
||||
const gallery = await request(app).get(`/api/companies/${company.id}/tools/gallery`);
|
||||
const workspaceApp = gallery.body.apps.find((entry: { slug: string }) => entry.slug === slug);
|
||||
expect(workspaceApp).toBeUndefined();
|
||||
expect(workspaceApp.methods.map((method: { key: string }) => method.key)).toContain(methodKey);
|
||||
const connected = await request(app).post(`/api/companies/${company.id}/tools/apps/connect`).send({
|
||||
galleryKey: slug, connectionMethodKey: methodKey, grantKind: "user", name: `Personal ${slug}`,
|
||||
});
|
||||
@@ -7077,7 +7081,7 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
expect(JSON.stringify(getConnectableAppDefinition(slug))).toBe(definitionBefore);
|
||||
});
|
||||
|
||||
it.each(GOOGLE_WORKSPACE_CONNECTOR_PROFILE_IDS)("connects retained Workspace %s with a Cloud-delivered environment identity", async (profile) => {
|
||||
it.each(GOOGLE_WORKSPACE_CONNECTOR_PROFILE_IDS)("connects advertised Workspace %s with a Cloud-delivered environment identity", async (profile) => {
|
||||
const slug = GOOGLE_WORKSPACE_CONNECTOR_PROFILES[profile].appSlug;
|
||||
const methodKey = getConnectableAppDefinition(slug)!.methods.find((method) => method.connectorProfile === profile)!.key;
|
||||
const company = await createCompany(db);
|
||||
@@ -7115,7 +7119,8 @@ describeEmbeddedPostgres("tool access service", () => {
|
||||
deploymentMode: "authenticated", deploymentExposure: "public",
|
||||
});
|
||||
const gallery = await request(app).get(`/api/companies/${company.id}/tools/gallery`);
|
||||
expect(gallery.body.apps.find((entry: { slug: string }) => entry.slug === slug)).toBeUndefined();
|
||||
expect(gallery.body.apps.find((entry: { slug: string }) => entry.slug === slug).methods
|
||||
.map((method: { key: string }) => method.key)).toContain(methodKey);
|
||||
const result = await request(app).post(`/api/companies/${company.id}/tools/apps/connect`).send({
|
||||
galleryKey: slug, connectionMethodKey: methodKey, grantKind: "user", name: `Cloud ${slug}`,
|
||||
});
|
||||
|
||||
@@ -126,37 +126,37 @@
|
||||
{
|
||||
"slug": "gmail",
|
||||
"provider": "Gmail",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/gmail.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-sheets",
|
||||
"provider": "Google Sheets",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-sheets.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-drive",
|
||||
"provider": "Google Drive",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-drive.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-docs",
|
||||
"provider": "Google Docs",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-docs.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-slides",
|
||||
"provider": "Google Slides",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-slides.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-calendar",
|
||||
"provider": "Google Calendar",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-calendar.svg",
|
||||
"aliases": [
|
||||
"gcal"
|
||||
@@ -165,13 +165,13 @@
|
||||
{
|
||||
"slug": "google-chat",
|
||||
"provider": "Google Chat",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-chat.svg"
|
||||
},
|
||||
{
|
||||
"slug": "google-people",
|
||||
"provider": "Google People",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-people.svg",
|
||||
"aliases": [
|
||||
"google contacts"
|
||||
@@ -180,7 +180,7 @@
|
||||
{
|
||||
"slug": "google-workspace-search",
|
||||
"provider": "Google Workspace Search",
|
||||
"catalogVisible": false,
|
||||
"catalogVisible": true,
|
||||
"localAsset": "/brands/apps/google-workspace-search.svg",
|
||||
"aliases": [
|
||||
"workspace search"
|
||||
|
||||
Reference in New Issue
Block a user