fix(authz): link connection settings and stop the page search

Two journeys showed agents searching for a web page after a board denial
that named none: the general fallback told them to link the most specific
page they knew. It now says to link a page only when its route is already
known and not to search for one. Prompt injection prevention, decision
model and fast response routes now link the connection settings page that
holds those controls.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
DottaandClaude Opus 5.5 committed 2026-11-08 21:17:21 -06:00
1 parent 9af18eba9d
commit bc68e5c062
2 files changed
+4 -1

No files matched your search

@@ -35,6 +35,7 @@ describe("board-only denial", () => {
["post", `/api/companies/${COMPANY_ID}/secrets`, "[Open company secrets](/<prefix>/company/settings/secrets)"],
["post", `/api/secrets/${AGENT_ID}/rotate`, "[Open company secrets](/<prefix>/company/settings/secrets)"],
["post", `/api/companies/${COMPANY_ID}/budget-incidents/i-1/resolve?x=1`, "[Open budgets](/<prefix>/activity/budgets)"],
["put", `/api/companies/${COMPANY_ID}/prompt-injection-prevention`, "[Open connection settings](/<prefix>/company/settings/connections)"],
["patch", `/api/agents/${AGENT_ID}/permissions`, `[Open the agent's permissions](/<prefix>/agents/${AGENT_ID}/permissions)`],
["post", `/api/agents/${AGENT_ID}/keys`, `[Open the agent's API keys](/<prefix>/agents/${AGENT_ID}/api-keys)`],
["post", `/api/agents/${AGENT_ID}/pause`, `[Open the agent's profile](/<prefix>/agents/${AGENT_ID})`],
@@ -52,6 +53,7 @@ describe("board-only denial", () => {
expect(res.body.code).toBe(BOARD_ACCESS_REQUIRED_CODE);
expect(res.body.remediation).toContain("this denial is final");
expect(res.body.remediation).toContain("Paperclip web app or with their own board credentials");
expect(res.body.remediation).toContain("Link a page only if you already know its route; do not search for one");
expect(res.body.remediation).not.toContain("](/");
});
+2 -1
View File
@@ -48,6 +48,7 @@ const AGENT_PROFILE_TABS: Record<string, [string, string]> = {
const BOARD_CONTROL_PAGES: Array<[RegExp, (match: RegExpExecArray) => [string, string]]> = [
[/^\/(?:companies\/[^/]+\/)?secrets?(?:[-/]|$)/, () => ["company secrets", "/<prefix>/company/settings/secrets"]],
[/^\/companies\/[^/]+\/(?:budgets|budget-incidents|costs)(?:\/|$)/, () => ["budgets", "/<prefix>/activity/budgets"]],
[/^\/companies\/[^/]+\/(?:prompt-injection-prevention|decision-model|fast-response)(?:\/|$)/, () => ["connection settings", "/<prefix>/company/settings/connections"]],
[/^\/companies\/[^/]+\/(?:members|invites|join-requests)(?:\/|$)/, () => ["company members", "/<prefix>/company/settings/members"]],
[/^\/companies\/[^/]+\/(?:tools\/)?gateways(?:\/|$)|^\/tool-gateway\//, () => ["tool gateways", "/<prefix>/apps/gateways"]],
[/^\/approvals\/([^/]+)/, match => ["the approval", `/<prefix>/approvals/${match[1]}`]],
@@ -76,7 +77,7 @@ export function boardAccessRequired(req: Request) {
const page = boardControlPage(req);
const where = page
? `They can do it in the Paperclip web app: link [Open ${page[0]}](${page[1]}), with this conversation's company prefix as <prefix>.`
: "They can do it in the Paperclip web app or with their own board credentials; link the most specific page you know.";
: "They can do it in the Paperclip web app or with their own board credentials. Link a page only if you already know its route; do not search for one.";
return forbidden("Board access required", {
code: BOARD_ACCESS_REQUIRED_CODE,
remediation: `This action is board-only by design and this denial is final: no agent credential, tool or other API route can do it, so do not search for one. Tell the person that a board user must do it. ${where}`,