@desplega.ai/agent-swarm 2.5.2 → 2.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{acp-adapter-csh0zz3b.js → acp-adapter-gr2fcyyj.js} +3 -3
- package/dist/{actions-6xx079d1.js → actions-wv766ghf.js} +18 -18
- package/dist/{amp-adapter-8n6f0hz8.js → amp-adapter-speb906t.js} +3 -3
- package/dist/{app-ft6r6v23.js → app-ag29n14f.js} +3 -3
- package/dist/{assistant-vt2cyfzd.js → assistant-3x8bz3eg.js} +19 -19
- package/dist/{boot-reembed-r3e808ky.js → boot-reembed-5b3d2eea.js} +1 -1
- package/dist/{boot-reembed-tgrfy27t.js → boot-reembed-jsmfrpzf.js} +1 -1
- package/dist/{boot-scrub-sweep-masdwxkm.js → boot-scrub-sweep-s73gerxy.js} +2 -2
- package/dist/{boot-seeds-0n82qc7q.js → boot-seeds-5zmax2wr.js} +4 -4
- package/dist/{claude-adapter-s7j47k06.js → claude-adapter-hswdnm3t.js} +3 -3
- package/dist/{claude-managed-adapter-gt6pa35d.js → claude-managed-adapter-cvbzj1h6.js} +2 -2
- package/dist/{claude-managed-setup-3hzrgrnk.js → claude-managed-setup-3k8m3hhc.js} +2 -2
- package/dist/{claude-sdk-session-0zrdzyx2.js → claude-sdk-session-fkbyk66x.js} +2 -2
- package/dist/{cli-d172svcw.js → cli-1fc85mvt.js} +4 -4
- package/dist/{cli-3e9vs93g.js → cli-210xd1f4.js} +4 -4
- package/dist/{cli-vaxw3bg0.js → cli-25j01dpj.js} +3 -3
- package/dist/{cli-n6kmqngw.js → cli-35gtk1p6.js} +1 -1
- package/dist/{cli-fgn7yg5r.js → cli-3ngdk5te.js} +1 -1
- package/dist/{cli-7ccf7akh.js → cli-40jsnrjm.js} +2 -2
- package/dist/{cli-b1tv22wr.js → cli-502eqv93.js} +1 -1
- package/dist/{cli-ydg6ep51.js → cli-6n8axjv1.js} +1 -1
- package/dist/{cli-f55b6ky0.js → cli-8s5wx3nz.js} +2 -2
- package/dist/{cli-86zpfje5.js → cli-99xgw26r.js} +1 -1
- package/dist/{cli-xw9q173h.js → cli-9s05422w.js} +1 -1
- package/dist/{cli-h5d22pfs.js → cli-aecdcr77.js} +119 -282
- package/dist/{cli-w9etnnxk.js → cli-bf8ma3f1.js} +120 -50
- package/dist/{cli-15xd0j7w.js → cli-ce0ak9ms.js} +11 -11
- package/dist/{cli-y3dzwyy3.js → cli-e2ar4bp1.js} +71 -20
- package/dist/{cli-b6tnjdvx.js → cli-e8jyq7d8.js} +1 -1
- package/dist/{cli-6y43v79h.js → cli-egjggehm.js} +1 -1
- package/dist/{cli-cf63dnxj.js → cli-ewm3pwbq.js} +2 -2
- package/dist/{cli-bpbcpd8b.js → cli-fsdprwrg.js} +1 -1
- package/dist/{cli-qrjv7t18.js → cli-fzcn3d87.js} +1 -1
- package/dist/{cli-14v1sxxy.js → cli-gpsz7g88.js} +6 -6
- package/dist/{cli-wadzapwb.js → cli-hcpj2xqz.js} +1 -1
- package/dist/{cli-jmcjbjkt.js → cli-hhxjnjzs.js} +1 -1
- package/dist/{cli-j3dwd4kz.js → cli-jjznk3f7.js} +718 -108
- package/dist/{cli-csh8fnbg.js → cli-kxawjrxg.js} +147 -28
- package/dist/{cli-mntxtkhn.js → cli-mz9afxxf.js} +2 -1
- package/dist/{cli-0vgy5wfw.js → cli-n45mr7zh.js} +2 -2
- package/dist/{cli-aaqnqpyw.js → cli-p0rzjkya.js} +2 -2
- package/dist/{cli-3qv8naq8.js → cli-p6zs9h4y.js} +827 -107
- package/dist/{cli-e91vshb1.js → cli-p9rafdrb.js} +4 -4
- package/dist/{cli-edtm741g.js → cli-qgf8emrn.js} +5 -5
- package/dist/{cli-ha22h0eg.js → cli-qzme5949.js} +26 -26
- package/dist/{cli-xzge46sj.js → cli-s49hpn37.js} +2 -2
- package/dist/{cli-b63d08rs.js → cli-s53vp709.js} +1 -1
- package/dist/{cli-cyfgxnvb.js → cli-svrj71pg.js} +18 -16
- package/dist/{cli-4qkg9968.js → cli-vwn81jbs.js} +3 -3
- package/dist/{cli-f3pfn4x3.js → cli-w1zwctj2.js} +1 -1
- package/dist/{cli-kcnwn85g.js → cli-y561h5a9.js} +4 -4
- package/dist/{cli-n2918sed.js → cli-z21whrrg.js} +15 -15
- package/dist/cli.js +16 -16
- package/dist/{codex-adapter-brh2tcxr.js → codex-adapter-n8ka66vf.js} +2 -2
- package/dist/{codex-session-runner-0dnj21qs.js → codex-session-runner-fsebts37.js} +1 -1
- package/dist/{commands-1cnvseqx.js → commands-t04rt2pc.js} +2 -2
- package/dist/{controller-kc7s9xhn.js → controller-rgna04r2.js} +2 -2
- package/dist/{controllers-connect-jzx7t4bn.js → controllers-connect-bqm1rtft.js} +20 -20
- package/dist/{cursor-adapter-qpwp5sfg.js → cursor-adapter-swr2k95y.js} +1 -1
- package/dist/{db-v5ytg5pw.js → db-24ck09xy.js} +1 -1
- package/dist/{db-4vq88jkc.js → db-a4m7haw0.js} +3 -3
- package/dist/{dispatcher-trtcrqae.js → dispatcher-nwf9ss0q.js} +17 -17
- package/dist/{dsh-adapter-f20xwn1z.js → dsh-adapter-kpdnhjst.js} +2 -2
- package/dist/{external-channel-n9bymc2n.js → external-channel-j1e2p34p.js} +2 -2
- package/dist/{grok-adapter-4kpmmnr6.js → grok-adapter-qtjz0whk.js} +4 -4
- package/dist/{handlers-ptsraqa8.js → handlers-19xr6dnz.js} +20 -20
- package/dist/{heartbeat-60qtxtjf.js → heartbeat-vtesda5d.js} +20 -20
- package/dist/{hook-rbktcstg.js → hook-8wqaszda.js} +1 -1
- package/dist/{hook-ngtvh729.js → hook-b2hhj6rd.js} +1 -1
- package/dist/{http-z8xy72gp.js → http-mxcqhhcs.js} +2757 -2448
- package/dist/{index-a9nsavhx.js → index-1r8wfpzs.js} +1 -1
- package/dist/{index-cbxkmfc5.js → index-9pn1pfkf.js} +1 -1
- package/dist/{index-s193j5fh.js → index-kw2mmat7.js} +20 -20
- package/dist/{index-06qkmcx6.js → index-n1vbvta9.js} +17 -9
- package/dist/{index-6srwvd5b.js → index-p4xfz37z.js} +1 -1
- package/dist/{index-1cscynkb.js → index-spwxjgay.js} +17 -17
- package/dist/{index-r70q0xjx.js → index-srg522m6.js} +17 -17
- package/dist/{keepalive-a9srcphj.js → keepalive-dsd8rtgx.js} +3 -3
- package/dist/{lead-3devneqy.js → lead-zyerk1x2.js} +30 -30
- package/dist/{maintenance-0er16h2y.js → maintenance-jqmqwnet.js} +1 -1
- package/dist/{oauth-refresh-sweep-b65jcyw2.js → oauth-refresh-sweep-q2c3bnvm.js} +2 -2
- package/dist/{onboard-wqywz5py.js → onboard-w4yd7s8t.js} +2 -2
- package/dist/{opencode-adapter-e56086m1.js → opencode-adapter-9tppvxar.js} +2 -2
- package/dist/{otel-impl-vk32s884.js → otel-impl-f36byzbd.js} +1 -1
- package/dist/{pricing-refresh-t27anv4z.js → pricing-refresh-xvak5p4v.js} +3 -3
- package/dist/{rbac-roles-bmcgsxjn.js → rbac-roles-682k2mt5.js} +1 -1
- package/dist/{rbac-roles-452665y0.js → rbac-roles-gfn30fb8.js} +2 -2
- package/dist/{render-v2-0ttsk2j4.js → render-v2-hgytz8nn.js} +3 -3
- package/dist/{resume-a26kvr41.js → resume-2dvq348g.js} +7 -5
- package/dist/{session-access-dgh9nkwk.js → session-access-7f21ekq9.js} +4 -4
- package/dist/{setup-9vc9qahm.js → setup-epffxtbk.js} +1 -1
- package/dist/{work-objects-vn8nkxwn.js → work-objects-xz1a5rqk.js} +20 -20
- package/dist/{worker-1x1h8vnm.js → worker-42t8emjt.js} +30 -30
- package/openapi.json +3045 -2456
- package/package.json +4 -4
- package/src/be/approval-config-question.ts +389 -0
- package/src/be/automation-preflight.ts +37 -3
- package/src/be/db/session-tree.ts +73 -15
- package/src/be/db/skill-search.ts +87 -0
- package/src/be/db/tasks/read.ts +29 -2
- package/src/be/db/workflow-runs.ts +54 -7
- package/src/be/db.ts +25 -5
- package/src/be/migrations/239_skills_fts.sql +40 -0
- package/src/be/migrations/240_workflow_run_parent_step_attempt.sql +37 -0
- package/src/be/migrations/241_skills_meta_fts.sql +39 -0
- package/src/be/swarm-config-guard.ts +23 -0
- package/src/extensions/catalog.generated.json +4 -4
- package/src/http/approval-requests.ts +209 -38
- package/src/http/config.ts +22 -37
- package/src/http/sessions.ts +27 -2
- package/src/integrations/chat-sdk/inbound.ts +5 -4
- package/src/providers/amp-adapter.ts +1 -1
- package/src/providers/dsh-adapter.ts +1 -1
- package/src/tests/approval-config-question.test.ts +702 -0
- package/src/tests/chat-sdk-inbound.test.ts +20 -0
- package/src/tests/dsh-adapter.test.ts +1 -1
- package/src/tests/entrypoint-gitlab-credential-helper.test.ts +273 -0
- package/src/tests/extensions-example-comms-adherence-gate.test.ts +321 -12
- package/src/tests/list-endpoint-slimming.test.ts +33 -0
- package/src/tests/migration-240-workflow-run-parent-step-attempt.test.ts +55 -0
- package/src/tests/script-connections.test.ts +6 -0
- package/src/tests/sessions-tree.test.ts +168 -1
- package/src/tests/skill-search-long-content.test.ts +193 -0
- package/src/tests/skill-search.test.ts +173 -22
- package/src/tests/workflow-sub-workflow.test.ts +538 -1
- package/src/tools/request-human-input.ts +27 -5
- package/src/types.ts +7 -0
- package/src/workflows/approval-notifications.ts +10 -3
- package/src/workflows/checkpoint.ts +69 -35
- package/src/workflows/engine.ts +234 -87
- package/src/workflows/executors/base.ts +6 -0
- package/src/workflows/executors/human-in-the-loop.ts +25 -1
- package/src/workflows/executors/sub-workflow.ts +45 -16
- package/src/workflows/recovery.ts +63 -1
- package/src/workflows/resume.ts +60 -21
- package/src/workflows/retry-poller.ts +25 -4
- package/templates/extensions/comms-adherence-gate/README.md +38 -13
- package/templates/extensions/comms-adherence-gate/hooks.ts +272 -69
- package/templates/extensions/comms-adherence-gate/manifest.json +2 -2
- package/templates/skills/turso-interaction/content.md +1 -1
- package/templates/skills/workflow-iterate/content.md +8 -1
- /package/dist/{cli-stxdrqs2.js → cli-avdvgcay.js} +0 -0
- /package/dist/{pi-mono-adapter-tzps8f38.js → pi-mono-adapter-tqsge1ay.js} +0 -0
|
@@ -332,6 +332,26 @@ describe("Chat SDK inbound pipeline", () => {
|
|
|
332
332
|
}
|
|
333
333
|
});
|
|
334
334
|
|
|
335
|
+
test("a mention in a subscribed group gets 👀 before the flush, and the flush does not react again", async () => {
|
|
336
|
+
await postTelegramUpdate(telegramUpdate(group(-2991), "@swarm_test_bot first ask"));
|
|
337
|
+
await flushChatBuffers();
|
|
338
|
+
const ask = telegramUpdate(group(-2991), "@swarm_test_bot second ask");
|
|
339
|
+
await postTelegramUpdate(ask);
|
|
340
|
+
expect(reactionsOn(-2991, ask)).toEqual(["👀"]);
|
|
341
|
+
await flushChatBuffers();
|
|
342
|
+
expect(await chatTasks(-2991)).toHaveLength(2);
|
|
343
|
+
expect(reactionsOn(-2991, ask)).toEqual(["👀"]);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("a !now mention in a subscribed group gets ⚡, not 👀", async () => {
|
|
347
|
+
await postTelegramUpdate(telegramUpdate(group(-2992), "@swarm_test_bot first ask"));
|
|
348
|
+
await flushChatBuffers();
|
|
349
|
+
const ask = telegramUpdate(group(-2992), "@swarm_test_bot !now second ask");
|
|
350
|
+
await postTelegramUpdate(ask);
|
|
351
|
+
expect(await chatTasks(-2992)).toHaveLength(2);
|
|
352
|
+
expect(reactionsOn(-2992, ask)).toEqual(["⚡"]);
|
|
353
|
+
});
|
|
354
|
+
|
|
335
355
|
test("two asks back to back each anchor to their own message, not the parent's", async () => {
|
|
336
356
|
const firstAsk = telegramUpdate(group(-2010), "@swarm_test_bot !now summarize the PR");
|
|
337
357
|
await postTelegramUpdate(firstAsk);
|
|
@@ -376,7 +376,7 @@ describe("dsh harness", () => {
|
|
|
376
376
|
await rename(join(config.cwd, "dsh"), join(config.cwd, "npx"));
|
|
377
377
|
config.env = { ...config.env, DSH_BINARY: "", PATH: config.cwd };
|
|
378
378
|
await expect(new DshAdapter().createSession(config)).rejects.toThrow(
|
|
379
|
-
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-rc.
|
|
379
|
+
"dsh CLI not found. Install @deepseek-ai/dsh@0.2.1-rc.3",
|
|
380
380
|
);
|
|
381
381
|
expect(await Bun.file(join(config.cwd, "invocation.json")).exists()).toBe(false);
|
|
382
382
|
});
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { CHILD_PROCESS_TEST_BUDGET_MS, expectChildOk, runChild } from "./test-proc";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Regression test for the GitLab git credential helper setup in
|
|
9
|
+
* docker-entrypoint.sh.
|
|
10
|
+
*
|
|
11
|
+
* The GITLAB_HOST assignment and the `git config --global ... helper` command
|
|
12
|
+
* are extracted verbatim from docker-entrypoint.sh and run under bash against
|
|
13
|
+
* real `git`, so this tracks the deployed snippet instead of a copy of it.
|
|
14
|
+
*
|
|
15
|
+
* Regression: the helper was set with a plain `git config --global KEY VALUE`.
|
|
16
|
+
* When the origin already had several helper values (a startup hook's
|
|
17
|
+
* `helper = ""` reset plus its own helper, or a second boot on a persisted
|
|
18
|
+
* HOME), git refused with "cannot overwrite multiple values with a single
|
|
19
|
+
* value" and `set -e` killed the entrypoint. `--replace-all` makes the step
|
|
20
|
+
* idempotent for that one origin.
|
|
21
|
+
*
|
|
22
|
+
* Every git call runs with an isolated HOME / global config, no system config,
|
|
23
|
+
* terminal prompts off, and synthetic hosts and tokens. Nothing hits the network.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
const entrypointPath = `${import.meta.dir}/../../docker-entrypoint.sh`;
|
|
27
|
+
|
|
28
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: a literal shell expansion in the entrypoint
|
|
29
|
+
const HELPER_KEY_EXPR = '"credential.${GITLAB_HOST%/}.helper"';
|
|
30
|
+
const SYNTHETIC_TOKEN = "glpat-synthetic-test-token"; // gitleaks:allow (synthetic test fixture)
|
|
31
|
+
const HOOK_HELPER = "!synthetic-hook-helper";
|
|
32
|
+
|
|
33
|
+
function extractGitlabHelperSnippet(): string {
|
|
34
|
+
const script = readFileSync(entrypointPath, "utf8");
|
|
35
|
+
|
|
36
|
+
const hostLineStart = script.indexOf('GITLAB_HOST="${GITLAB_URL:-');
|
|
37
|
+
if (hostLineStart === -1) {
|
|
38
|
+
throw new Error("Could not locate the GITLAB_HOST assignment in docker-entrypoint.sh.");
|
|
39
|
+
}
|
|
40
|
+
const hostLine = script.slice(hostLineStart, script.indexOf("\n", hostLineStart));
|
|
41
|
+
|
|
42
|
+
const keyIndex = script.indexOf(HELPER_KEY_EXPR, hostLineStart);
|
|
43
|
+
if (keyIndex === -1) {
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Could not locate ${HELPER_KEY_EXPR} in the GitLab block of docker-entrypoint.sh.`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
const commandStart = script.lastIndexOf("git config --global", keyIndex);
|
|
49
|
+
const closingMarker = "; f'";
|
|
50
|
+
const closingIndex = script.indexOf(closingMarker, keyIndex);
|
|
51
|
+
if (commandStart === -1 || closingIndex === -1) {
|
|
52
|
+
throw new Error("Could not locate the bounds of the GitLab helper `git config` command.");
|
|
53
|
+
}
|
|
54
|
+
const command = script.slice(commandStart, closingIndex + closingMarker.length);
|
|
55
|
+
|
|
56
|
+
return `set -e\n${hostLine}\n${command}\n`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const snippet = extractGitlabHelperSnippet();
|
|
60
|
+
const tempDirs: string[] = [];
|
|
61
|
+
|
|
62
|
+
afterEach(() => {
|
|
63
|
+
for (const dir of tempDirs.splice(0)) rmSync(dir, { recursive: true, force: true });
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
function makeHome(): string {
|
|
67
|
+
const home = mkdtempSync(join(tmpdir(), "gitlab-helper-"));
|
|
68
|
+
tempDirs.push(home);
|
|
69
|
+
return home;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function isolatedEnv(home: string, extra: Record<string, string> = {}): Record<string, string> {
|
|
73
|
+
return {
|
|
74
|
+
PATH: process.env.PATH ?? "/usr/bin:/bin",
|
|
75
|
+
HOME: home,
|
|
76
|
+
XDG_CONFIG_HOME: join(home, ".config"),
|
|
77
|
+
GIT_CONFIG_GLOBAL: join(home, ".gitconfig"),
|
|
78
|
+
GIT_CONFIG_NOSYSTEM: "1",
|
|
79
|
+
GIT_TERMINAL_PROMPT: "0",
|
|
80
|
+
LANG: "C",
|
|
81
|
+
LC_ALL: "C",
|
|
82
|
+
...extra,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function git(home: string, args: string[], stdin?: string, extra?: Record<string, string>) {
|
|
87
|
+
return runChild(["git", ...args], { env: isolatedEnv(home, extra), stdin });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async function addHelper(home: string, origin: string, value: string) {
|
|
91
|
+
expectChildOk(
|
|
92
|
+
await git(home, ["config", "--global", "--add", `credential.${origin}.helper`, value]),
|
|
93
|
+
"git config --add",
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** The startup-hook pattern: reset inherited helpers, then add its own. */
|
|
98
|
+
async function addHookPair(home: string, origin: string) {
|
|
99
|
+
await addHelper(home, origin, "");
|
|
100
|
+
await addHelper(home, origin, HOOK_HELPER);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function getHelpers(home: string, origin: string): Promise<string[]> {
|
|
104
|
+
const result = await git(home, [
|
|
105
|
+
"config",
|
|
106
|
+
"--global",
|
|
107
|
+
"--get-all",
|
|
108
|
+
`credential.${origin}.helper`,
|
|
109
|
+
]);
|
|
110
|
+
if (result.exitCode === 1) return [];
|
|
111
|
+
expectChildOk(result, "git config --get-all");
|
|
112
|
+
return result.stdout.replace(/\n$/, "").split("\n");
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function runSnippet(home: string, gitlabUrl?: string) {
|
|
116
|
+
const extra: Record<string, string> = { GITLAB_TOKEN: SYNTHETIC_TOKEN };
|
|
117
|
+
if (gitlabUrl !== undefined) extra.GITLAB_URL = gitlabUrl;
|
|
118
|
+
return runChild(["bash", "-c", snippet], { env: isolatedEnv(home, extra) });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function expectOnlyEntrypointHelper(helpers: string[]) {
|
|
122
|
+
expect(helpers).toHaveLength(1);
|
|
123
|
+
expect(helpers[0]).toStartWith("!f() {");
|
|
124
|
+
expect(helpers[0]).toContain("username=oauth2");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const ORIGIN = "https://gitlab.example.test";
|
|
128
|
+
|
|
129
|
+
describe("docker-entrypoint.sh: GitLab git credential helper", () => {
|
|
130
|
+
test(
|
|
131
|
+
"sets the helper when none exists (default gitlab.com origin)",
|
|
132
|
+
async () => {
|
|
133
|
+
const home = makeHome();
|
|
134
|
+
expectChildOk(await runSnippet(home), "snippet");
|
|
135
|
+
expectOnlyEntrypointHelper(await getHelpers(home, "https://gitlab.com"));
|
|
136
|
+
},
|
|
137
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
test(
|
|
141
|
+
"replaces a single existing value",
|
|
142
|
+
async () => {
|
|
143
|
+
const home = makeHome();
|
|
144
|
+
await addHelper(home, ORIGIN, "!old-helper");
|
|
145
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
146
|
+
expectOnlyEntrypointHelper(await getHelpers(home, ORIGIN));
|
|
147
|
+
},
|
|
148
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
test(
|
|
152
|
+
"succeeds over an empty reset value plus a custom helper",
|
|
153
|
+
async () => {
|
|
154
|
+
const home = makeHome();
|
|
155
|
+
await addHookPair(home, ORIGIN);
|
|
156
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
157
|
+
expectOnlyEntrypointHelper(await getHelpers(home, ORIGIN));
|
|
158
|
+
},
|
|
159
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
test(
|
|
163
|
+
"succeeds over several non-empty values",
|
|
164
|
+
async () => {
|
|
165
|
+
const home = makeHome();
|
|
166
|
+
await addHelper(home, ORIGIN, "!helper-one");
|
|
167
|
+
await addHelper(home, ORIGIN, "!helper-two");
|
|
168
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
169
|
+
expectOnlyEntrypointHelper(await getHelpers(home, ORIGIN));
|
|
170
|
+
},
|
|
171
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
test(
|
|
175
|
+
"repeated runs do not accumulate values",
|
|
176
|
+
async () => {
|
|
177
|
+
const home = makeHome();
|
|
178
|
+
for (let i = 0; i < 3; i++) expectChildOk(await runSnippet(home, ORIGIN), `snippet run ${i}`);
|
|
179
|
+
expectOnlyEntrypointHelper(await getHelpers(home, ORIGIN));
|
|
180
|
+
},
|
|
181
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
test(
|
|
185
|
+
"leaves another origin's helpers untouched",
|
|
186
|
+
async () => {
|
|
187
|
+
const home = makeHome();
|
|
188
|
+
const other = "https://other.example.test";
|
|
189
|
+
await addHookPair(home, other);
|
|
190
|
+
await addHookPair(home, ORIGIN);
|
|
191
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
192
|
+
expect(await getHelpers(home, other)).toEqual(["", HOOK_HELPER]);
|
|
193
|
+
expectOnlyEntrypointHelper(await getHelpers(home, ORIGIN));
|
|
194
|
+
},
|
|
195
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
test(
|
|
199
|
+
"keeps the port and strips one trailing slash from GITLAB_URL",
|
|
200
|
+
async () => {
|
|
201
|
+
const home = makeHome();
|
|
202
|
+
const origin = "https://gitlab.example.test:8443";
|
|
203
|
+
await addHookPair(home, origin);
|
|
204
|
+
expectChildOk(await runSnippet(home, `${origin}/`), "snippet");
|
|
205
|
+
expectOnlyEntrypointHelper(await getHelpers(home, origin));
|
|
206
|
+
expect(await getHelpers(home, `${origin}/`)).toEqual([]);
|
|
207
|
+
},
|
|
208
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
209
|
+
);
|
|
210
|
+
|
|
211
|
+
test(
|
|
212
|
+
"stores a reference to GITLAB_TOKEN, never the token value",
|
|
213
|
+
async () => {
|
|
214
|
+
const home = makeHome();
|
|
215
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
216
|
+
const gitconfig = readFileSync(join(home, ".gitconfig"), "utf8");
|
|
217
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: the helper must keep the shell reference
|
|
218
|
+
expect(gitconfig).toContain("${GITLAB_TOKEN}");
|
|
219
|
+
expect(gitconfig).not.toContain(SYNTHETIC_TOKEN);
|
|
220
|
+
},
|
|
221
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
test(
|
|
225
|
+
"answers get from the environment and ignores store / erase",
|
|
226
|
+
async () => {
|
|
227
|
+
const home = makeHome();
|
|
228
|
+
expectChildOk(await runSnippet(home, ORIGIN), "snippet");
|
|
229
|
+
const tokenEnv = { GITLAB_TOKEN: SYNTHETIC_TOKEN };
|
|
230
|
+
|
|
231
|
+
const fill = expectChildOk(
|
|
232
|
+
await git(
|
|
233
|
+
home,
|
|
234
|
+
["credential", "fill"],
|
|
235
|
+
"protocol=https\nhost=gitlab.example.test\n\n",
|
|
236
|
+
tokenEnv,
|
|
237
|
+
),
|
|
238
|
+
"git credential fill",
|
|
239
|
+
);
|
|
240
|
+
expect(fill.stdout).toContain("username=oauth2\n");
|
|
241
|
+
expect(fill.stdout).toContain(`password=${SYNTHETIC_TOKEN}\n`);
|
|
242
|
+
|
|
243
|
+
const cred = `protocol=https\nhost=gitlab.example.test\nusername=oauth2\npassword=${SYNTHETIC_TOKEN}\n\n`;
|
|
244
|
+
for (const action of ["approve", "reject"]) {
|
|
245
|
+
const result = expectChildOk(
|
|
246
|
+
await git(home, ["credential", action], cred, tokenEnv),
|
|
247
|
+
`git credential ${action}`,
|
|
248
|
+
);
|
|
249
|
+
expect(result.stdout).toBe("");
|
|
250
|
+
}
|
|
251
|
+
expect(readFileSync(join(home, ".gitconfig"), "utf8")).not.toContain(SYNTHETIC_TOKEN);
|
|
252
|
+
},
|
|
253
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
test(
|
|
257
|
+
"a startup hook can re-add its reset + helper pair across restarts",
|
|
258
|
+
async () => {
|
|
259
|
+
const home = makeHome();
|
|
260
|
+
for (let boot = 0; boot < 2; boot++) {
|
|
261
|
+
expectChildOk(await runSnippet(home, ORIGIN), `snippet boot ${boot}`);
|
|
262
|
+
await addHookPair(home, ORIGIN);
|
|
263
|
+
// The hook's "" resets the entrypoint helper before it in the chain,
|
|
264
|
+
// and the next boot's --replace-all collapses all three again.
|
|
265
|
+
const helpers = await getHelpers(home, ORIGIN);
|
|
266
|
+
expect(helpers).toHaveLength(3);
|
|
267
|
+
expectOnlyEntrypointHelper(helpers.slice(0, 1));
|
|
268
|
+
expect(helpers.slice(1)).toEqual(["", HOOK_HELPER]);
|
|
269
|
+
}
|
|
270
|
+
},
|
|
271
|
+
CHILD_PROCESS_TEST_BUDGET_MS,
|
|
272
|
+
);
|
|
273
|
+
});
|