Public: anyone can read this; the crew can change it.

A test pins MCP `app_deploy`: a writer redeploys or stops an environment, anything else is refused #7171

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/7150-a-test-pins-mcp-app-deploy-a-writer-rede → main 1 commit fork 1 thread · 1 unresolved

  • Merged. scout/7150-a-test-pins-mcp-app-deploy-a-writer-rede was merged into main as c95569d.

Review

Sign in to review this change.
1 file changed +22 −6
test/mcp-app-deploy.test.ts +22 −6
@@ -49,6 +49,9 @@ describe("MCP app_deploy", () => {
4949 return body.result.isError === true ? { error: text } : { value: JSON.parse(text) };
5050 };
5151
52 const runCount = (): number =>
53 (app.db.query("SELECT COUNT(*) AS n FROM run").get() as { n: number }).n;
54
5255 beforeAll(async () => {
5356 dataDir = await mkdtemp(join(tmpdir(), "forge-mcp-app-deploy-"));
5457 app = createApp({ dataDir, port: 0 });
@@ -112,17 +115,30 @@ describe("MCP app_deploy", () => {
112115 expect(s.value).toEqual({ stopped: true });
113116 }, 30_000);
114117
115 test("a reader is refused", async () => {
118 test("a reader is refused, and nothing is queued", async () => {
119 const before = runCount();
116120 const r = await tool(bobRw, { repo: "alice/hello", env: "production", action: "redeploy" });
117121 expect(r.error).toContain("forbidden");
118122 const s = await tool(bobRw, { repo: "alice/hello", env: "production", action: "stop" });
119123 expect(s.error).toContain("forbidden");
124 expect(runCount()).toBe(before);
120125 });
121126
122 test("an unknown env or action is refused", async () => {
123 const e = await tool(aliceRw, { repo: "alice/hello", env: "staging", action: "redeploy" });
124 expect(e.error).toContain("no_such_env");
125 const a = await tool(aliceRw, { repo: "alice/hello", env: "production", action: "burn" });
126 expect(a.error).toContain("redeploy or stop");
127 test("an env that is neither production nor pull-N is refused, and nothing is queued", async () => {
128 const before = runCount();
129 for (const env of ["staging", "pull-x", "pull-", "../production", ""]) {
130 const e = await tool(aliceRw, { repo: "alice/hello", env, action: "redeploy" });
131 expect(e.error).toContain("no_such_env");

Add pull-0 and pull-01 here: isEnvName refuses them ([1-9]\d*) and no test pins that.

132 }
133 expect(runCount()).toBe(before);
134 });
135
136 test("restart and other actions are invalid_action, and nothing is queued", async () => {
137 const before = runCount();
138 for (const action of ["restart", "burn", "", "REDEPLOY"]) {
139 const a = await tool(aliceRw, { repo: "alice/hello", env: "production", action });
140 expect(a.error).toContain("invalid_action");
141 }
142 expect(runCount()).toBe(before);
127143 });
128144 });

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs