diff --git a/agents/hermes/policy-permissive.yaml b/agents/hermes/policy-permissive.yaml index eb64ec51cb..f6bf7ed802 100644 --- a/agents/hermes/policy-permissive.yaml +++ b/agents/hermes/policy-permissive.yaml @@ -208,6 +208,7 @@ network_policies: endpoints: - host: slack.com port: 443 + path: /api/apps.connections.open protocol: rest enforcement: enforce request_body_credential_rewrite: true diff --git a/src/lib/messaging/channels/slack/policy/hermes.yaml b/src/lib/messaging/channels/slack/policy/hermes.yaml index 7f931a9d38..7ccd40934d 100644 --- a/src/lib/messaging/channels/slack/policy/hermes.yaml +++ b/src/lib/messaging/channels/slack/policy/hermes.yaml @@ -11,6 +11,7 @@ network_policies: endpoints: - host: slack.com port: 443 + path: /api/apps.connections.open protocol: rest enforcement: enforce request_body_credential_rewrite: true diff --git a/src/lib/onboard/initial-policy-real-policy.test.ts b/src/lib/onboard/initial-policy-real-policy.test.ts index 5dd7e23079..c164bd0b9a 100644 --- a/src/lib/onboard/initial-policy-real-policy.test.ts +++ b/src/lib/onboard/initial-policy-real-policy.test.ts @@ -30,6 +30,7 @@ type PolicyRule = { type PolicyEndpoint = { host?: string; port?: number; + path?: string; access?: string; protocol?: string; enforcement?: string; @@ -449,7 +450,7 @@ describe("initial sandbox policy real preset merge", () => { expect(JSON.stringify(effective)).not.toContain("{sandboxName}"); }); - it("materializes separate Hermes Slack bot and app credential bindings", () => { + it("uses a more specific route for the Hermes Slack app credential binding (#10155)", () => { const sandboxName = "hermes-slack-e2e"; const effective = readPreparedPolicy( prepareInitialSandboxCreatePolicy( @@ -465,11 +466,15 @@ describe("initial sandbox policy real preset merge", () => { ); expect(slackCom).toHaveLength(2); - expect(slackCom[0]).toMatchObject({ - credential_binding: { provider: `${sandboxName}-slack-app` }, - rules: [{ allow: { method: "POST", path: "/api/apps.connections.open" } }], - }); - expect(slackCom[1]?.credential_binding?.provider).toBe(`${sandboxName}-slack-bridge`); + expect( + slackCom.map((endpoint) => ({ + path: endpoint.path, + provider: endpoint.credential_binding?.provider, + })), + ).toEqual([ + { path: "/api/apps.connections.open", provider: `${sandboxName}-slack-app` }, + { path: undefined, provider: `${sandboxName}-slack-bridge` }, + ]); expect(websocketEndpoints.map((endpoint) => endpoint.credential_binding?.provider)).toEqual([ `${sandboxName}-slack-app`, `${sandboxName}-slack-app`, diff --git a/test/runtime/policy/permissive-runtime.test.ts b/test/runtime/policy/permissive-runtime.test.ts index 203dc876e2..8acd3df3a9 100644 --- a/test/runtime/policy/permissive-runtime.test.ts +++ b/test/runtime/policy/permissive-runtime.test.ts @@ -65,6 +65,7 @@ type SlackEndpoint = { access?: string; credential_binding?: { provider?: string }; host?: string; + path?: string; rules?: Array<{ allow?: { method?: string; path?: string } }>; }; @@ -73,6 +74,7 @@ function expectExactHermesSlackCredentialRoutes(endpoints: SlackEndpoint[]): voi endpoints.map((endpoint) => ({ access: endpoint.access, host: endpoint.host, + path: endpoint.path, provider: endpoint.credential_binding?.provider, routes: endpoint.rules?.map((rule) => `${String(rule.allow?.method)} ${String(rule.allow?.path)}`) ?? @@ -82,36 +84,42 @@ function expectExactHermesSlackCredentialRoutes(endpoints: SlackEndpoint[]): voi { access: undefined, host: "slack.com", + path: "/api/apps.connections.open", provider: "hermes-box-slack-app", routes: ["POST /api/apps.connections.open"], }, { access: "full", host: "slack.com", + path: undefined, provider: "hermes-box-slack-bridge", routes: [], }, { access: "full", host: "api.slack.com", + path: undefined, provider: "hermes-box-slack-bridge", routes: [], }, { access: "full", host: "hooks.slack.com", + path: undefined, provider: "hermes-box-slack-bridge", routes: [], }, { access: undefined, host: "wss-primary.slack.com", + path: undefined, provider: "hermes-box-slack-app", routes: ["GET /**", "WEBSOCKET_TEXT /**"], }, { access: undefined, host: "wss-backup.slack.com", + path: undefined, provider: "hermes-box-slack-app", routes: ["GET /**", "WEBSOCKET_TEXT /**"], },