-
-
Notifications
You must be signed in to change notification settings - Fork 0
fix(cli): respect remote caplet shadowing policy #146
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| --- | ||
| "@caplets/core": patch | ||
| "caplets": patch | ||
| --- | ||
|
|
||
| Respect remote Caplet shadowing policy when merging local overlays into remote CLI list output. |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -4068,6 +4068,12 @@ function mergeRemoteAndLocalRows( | |||||||||||||||||||||||||||||
| if (row.disabled) { | ||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
| if (remote.shadowing !== "allow") { | ||||||||||||||||||||||||||||||
| options.writeErr( | ||||||||||||||||||||||||||||||
| `Local Caplet '${row.server}' is suppressed because the remote Caplet forbids shadowing that Caplet ID.\n`, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||
|
Comment on lines
+4071
to
+4075
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||
|
Comment on lines
+4071
to
+4076
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||||||
| options.writeErr( | ||||||||||||||||||||||||||||||
| `Warning: ${formatOverlaySource(row.source)} Caplet ${row.server} shadows remote Caplet\n`, | ||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -493,7 +493,10 @@ describe("remote CLI routing", () => { | |
| const err: string[] = []; | ||
| writeCliCapletConfig(context.configPath, "shared", "Disabled Shared", { disabled: true }); | ||
| const fetch = vi.fn(async () => | ||
| Response.json({ ok: true, result: [remoteListRow("shared", "Remote Shared")] }), | ||
| Response.json({ | ||
| ok: true, | ||
| result: [{ ...remoteListRow("shared", "Remote Shared"), shadowing: "allow" }], | ||
| }), | ||
| ); | ||
|
|
||
| await runCli(["list", "--json"], { | ||
|
|
@@ -509,13 +512,44 @@ describe("remote CLI routing", () => { | |
| expect(err.join("")).not.toContain("shadows remote Caplet"); | ||
| }); | ||
|
|
||
| it("keeps remote list rows when the remote Caplet forbids local shadowing", async () => { | ||
| const context = testContext("caplets-cli-remote-list-forbid-shadow-"); | ||
| const out: string[] = []; | ||
| const err: string[] = []; | ||
| writeCliCapletConfig(context.configPath, "shared", "Local Shared"); | ||
| const fetch = vi.fn(async () => | ||
| Response.json({ | ||
| ok: true, | ||
| result: [{ ...remoteListRow("shared", "Remote Shared"), shadowing: "forbid" }], | ||
| }), | ||
| ); | ||
|
|
||
| await runCli(["list", "--json"], { | ||
| env: remoteEnv(context), | ||
| fetch, | ||
| writeOut: (value) => out.push(value), | ||
| writeErr: (value) => err.push(value), | ||
| }); | ||
|
|
||
| expect(JSON.parse(out.join(""))).toEqual([ | ||
| expect.objectContaining({ server: "shared", name: "Remote Shared", source: "remote" }), | ||
| ]); | ||
| expect(err.join("")).toContain( | ||
| "Local Caplet 'shared' is suppressed because the remote Caplet forbids shadowing that Caplet ID.", | ||
| ); | ||
| expect(err.join("")).not.toContain("global Caplet shared shadows remote Caplet"); | ||
| }); | ||
|
Comment on lines
+515
to
+541
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||
|
|
||
| it("lets project list rows shadow remote rows and warns on stderr", async () => { | ||
| const context = testContext("caplets-cli-remote-list-project-shadow-"); | ||
| const out: string[] = []; | ||
| const err: string[] = []; | ||
| writeProjectMcpCaplet(context.projectCapletsRoot, "shared", "Project Shared"); | ||
| const fetch = vi.fn(async () => | ||
| Response.json({ ok: true, result: [remoteListRow("shared", "Remote Shared")] }), | ||
| Response.json({ | ||
| ok: true, | ||
| result: [{ ...remoteListRow("shared", "Remote Shared"), shadowing: "allow" }], | ||
| }), | ||
| ); | ||
|
|
||
| await runCli(["list", "--json"], { | ||
|
|
@@ -537,7 +571,10 @@ describe("remote CLI routing", () => { | |
| const err: string[] = []; | ||
| writeCliCapletConfig(context.configPath, "shared", "Global Shared"); | ||
| const fetch = vi.fn(async () => | ||
| Response.json({ ok: true, result: [remoteListRow("shared", "Remote Shared")] }), | ||
| Response.json({ | ||
| ok: true, | ||
| result: [{ ...remoteListRow("shared", "Remote Shared"), shadowing: "allow" }], | ||
| }), | ||
| ); | ||
|
|
||
| await runCli(["list", "--json"], { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a remote Caplet returns
shadowing: "forbid"and a same-ID enabled local overlay exists, this branch hides the local row and tells the user it was suppressed, but remote-mode commands still callexecuteLocalOperationwheneverhasEnabledCaplet(localOverlay.config, caplet)is true inexecuteOperation. Aftercaplets listshows the remote Caplet, commands likecaplets get-tool shared...orcaplets call-tool shared...will still execute the local overlay, so the list output is inconsistent and the remote policy is not actually enforced.Useful? React with 👍 / 👎.