@synopackageland/cli 0.41.8 → 0.41.9
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/CHANGELOG.md +8 -0
- package/README.md +4 -0
- package/dist/e2e/certificates.d.ts +6 -0
- package/dist/e2e/certificates.js +60 -0
- package/dist/e2e/dsm.d.ts +1 -1
- package/dist/e2e/dsm.js +5 -3
- package/dist/standalone/inspect-spk.js +7 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.41.9 (2026-10-30)
|
|
4
|
+
|
|
5
|
+
- Accept self-signed DSM and redirected gateway certificates by default in the
|
|
6
|
+
Chromium e2e target, before its first network navigation.
|
|
7
|
+
- Preserve installer-managed ports when the SPK inspector reconstructs daemon
|
|
8
|
+
and background lifecycle hooks, so native gateway Apps with `install.ports`
|
|
9
|
+
build and inspect consistently.
|
|
10
|
+
|
|
3
11
|
## 0.41.8 (2026-10-30)
|
|
4
12
|
|
|
5
13
|
- Preserve the manifest's installer ports, settings and shared-folder context
|
package/README.md
CHANGED
|
@@ -225,6 +225,10 @@ not change how the App runs or its privilege tier. See `synopkgland skill show b
|
|
|
225
225
|
suite on [`e2e`](https://www.npmjs.com/package/e2e) and `@e2e-dev/web`
|
|
226
226
|
(optional peers, with `ai` and `@ai-sdk/openai`).
|
|
227
227
|
|
|
228
|
+
`dsmTarget()` uses Chromium and accepts self-signed DSM and gateway HTTPS
|
|
229
|
+
certificates by default, including redirects from an HTTP DSM URL. It configures
|
|
230
|
+
CDP before the first network navigation; this certificate handling is Chromium-only.
|
|
231
|
+
|
|
228
232
|
```ts
|
|
229
233
|
// e2e.config.ts
|
|
230
234
|
import {dsmTarget, magpieAgent} from '@synopackageland/cli/e2e';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type EngineHandle } from "e2e/engine";
|
|
2
|
+
import type { surfaceOf } from "@e2e-dev/web";
|
|
3
|
+
type Surface = NonNullable<ReturnType<typeof surfaceOf>>;
|
|
4
|
+
/** Chromium DSM test targets accept self-signed DSM and redirected gateway certificates. */
|
|
5
|
+
export declare function withDsmCertificates(base: EngineHandle, surface: () => Surface): EngineHandle;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { defineEngine } from "e2e/engine";
|
|
2
|
+
/** Chromium DSM test targets accept self-signed DSM and redirected gateway certificates. */
|
|
3
|
+
export function withDsmCertificates(base, surface) {
|
|
4
|
+
const browsers = new WeakMap();
|
|
5
|
+
const pages = new WeakMap();
|
|
6
|
+
async function prepareBrowser() {
|
|
7
|
+
const browser = surface().context().browser();
|
|
8
|
+
if (!browser)
|
|
9
|
+
return false;
|
|
10
|
+
let pending = browsers.get(browser);
|
|
11
|
+
if (!pending) {
|
|
12
|
+
pending = (async () => {
|
|
13
|
+
const session = await browser.newBrowserCDPSession();
|
|
14
|
+
await session.send("Security.setIgnoreCertificateErrors", { ignore: true });
|
|
15
|
+
return true;
|
|
16
|
+
})().catch(() => false); // Some Chromium connections expose only page CDP.
|
|
17
|
+
browsers.set(browser, pending);
|
|
18
|
+
}
|
|
19
|
+
return pending;
|
|
20
|
+
}
|
|
21
|
+
const { capabilities: _capabilities, ...spec } = base;
|
|
22
|
+
return defineEngine({
|
|
23
|
+
...spec,
|
|
24
|
+
async startAttempt(context) {
|
|
25
|
+
await base.startAttempt?.(context);
|
|
26
|
+
await prepareBrowser();
|
|
27
|
+
},
|
|
28
|
+
session: {
|
|
29
|
+
...base.session,
|
|
30
|
+
async open(url, operation) {
|
|
31
|
+
if (!base.session?.open)
|
|
32
|
+
throw new Error("The DSM engine cannot open a page.");
|
|
33
|
+
if (!await prepareBrowser()) {
|
|
34
|
+
// The runner creates its page lazily. Open only a blank page before
|
|
35
|
+
// configuring page CDP, so the first network navigation is covered.
|
|
36
|
+
let page;
|
|
37
|
+
try {
|
|
38
|
+
page = surface().page();
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
await base.session.open("about:blank", operation);
|
|
42
|
+
page = surface().page();
|
|
43
|
+
}
|
|
44
|
+
let pending = pages.get(page);
|
|
45
|
+
if (!pending) {
|
|
46
|
+
const target = page;
|
|
47
|
+
pending = (async () => {
|
|
48
|
+
const session = await surface().context().newCDPSession(target);
|
|
49
|
+
await session.send("Security.setIgnoreCertificateErrors", { ignore: true });
|
|
50
|
+
})();
|
|
51
|
+
pages.set(page, pending);
|
|
52
|
+
pending.catch(() => pages.delete(target));
|
|
53
|
+
}
|
|
54
|
+
await pending;
|
|
55
|
+
}
|
|
56
|
+
await base.session.open(url, operation);
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
package/dist/e2e/dsm.d.ts
CHANGED
|
@@ -82,7 +82,7 @@ export declare function loadProfile(file: string, url: string): StorageState | n
|
|
|
82
82
|
* process, each write their own temporary file and rename it into place.
|
|
83
83
|
*/
|
|
84
84
|
export declare function saveProfile(file: string, url: string, state: StorageState): void;
|
|
85
|
-
/** The `targets` entry of e2e.config.ts. */
|
|
85
|
+
/** The Chromium `targets` entry of e2e.config.ts; accepts self-signed test certificates. */
|
|
86
86
|
export declare function dsmTarget(name?: string): {
|
|
87
87
|
name: string;
|
|
88
88
|
engine: import("e2e/engine").EngineHandle;
|
package/dist/e2e/dsm.js
CHANGED
|
@@ -23,6 +23,7 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|
|
23
23
|
import { readSmokeEntry } from "./app-open.js";
|
|
24
24
|
export { deriveSmokeEntry } from "./app-open.js";
|
|
25
25
|
import { surfaceOf, test, web } from "@e2e-dev/web";
|
|
26
|
+
import { withDsmCertificates } from "./certificates.js";
|
|
26
27
|
const safeName = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,63}$/;
|
|
27
28
|
const desktopSelector = "#sds-desktop";
|
|
28
29
|
const signedInSelector = "#sds-taskbar-tray-item-user";
|
|
@@ -288,15 +289,16 @@ export function saveProfile(file, url, state) {
|
|
|
288
289
|
renameSync(temporary, file);
|
|
289
290
|
}
|
|
290
291
|
// ---- Browser --------------------------------------------------------------
|
|
291
|
-
const
|
|
292
|
+
const webEngine = web({
|
|
292
293
|
viewport: { width: Number(process.env.DSM_E2E_VIEWPORT_WIDTH || 1280), height: Number(process.env.DSM_E2E_VIEWPORT_HEIGHT || 800) },
|
|
293
294
|
});
|
|
294
|
-
|
|
295
|
+
const engine = withDsmCertificates(webEngine, surface);
|
|
296
|
+
/** The Chromium `targets` entry of e2e.config.ts; accepts self-signed test certificates. */
|
|
295
297
|
export function dsmTarget(name = "dsm") {
|
|
296
298
|
return { name, engine, app: { url: dsmUrl() } };
|
|
297
299
|
}
|
|
298
300
|
function surface() {
|
|
299
|
-
const live = surfaceOf(
|
|
301
|
+
const live = surfaceOf(webEngine);
|
|
300
302
|
if (!live)
|
|
301
303
|
throw new Error("The DSM web engine is unavailable.");
|
|
302
304
|
return live;
|
|
@@ -248,10 +248,10 @@ export async function inspectSpk(spkPath, expectedKind) {
|
|
|
248
248
|
if (standalone && portal)
|
|
249
249
|
findings.push(...inspectPortalInfo(info, hasExecutor));
|
|
250
250
|
const daemon = standalone
|
|
251
|
-
? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway, uninstallHook?.uninstall, { ingress: daemonIngress, node: daemonNode, restart: daemonRestart })
|
|
251
|
+
? await checkDaemon(dir, info, paths, payload, findings, hasExecutor, background, combined, nativeGateway, uninstallHook?.uninstall, { ingress: daemonIngress, node: daemonNode, restart: daemonRestart, installPorts: Boolean(metadata.installPorts) })
|
|
252
252
|
: undefined;
|
|
253
253
|
if (background)
|
|
254
|
-
checkBackground(dir, info, payload, findings, hasExecutor, daemon, kind !== "native-go", metadata.lifecycleTimeouts, nativeGateway);
|
|
254
|
+
checkBackground(dir, info, payload, findings, hasExecutor, daemon, kind !== "native-go", metadata.lifecycleTimeouts, nativeGateway, Boolean(metadata.installPorts));
|
|
255
255
|
let executor;
|
|
256
256
|
if ((metadata.capabilities ?? []).some((name) => name === "rootOps" || name === "delegate" || name === "webapi") ||
|
|
257
257
|
paths.has("executor/executor")) {
|
|
@@ -1026,6 +1026,7 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
|
|
|
1026
1026
|
throw new Error("missing executable");
|
|
1027
1027
|
const manifest = {
|
|
1028
1028
|
package: info.package,
|
|
1029
|
+
...(extras.installPorts ? { installPorts: true } : {}),
|
|
1029
1030
|
backend: { kind: 'go', dir: dir, main: './cmd/app', timeoutSeconds: config.operation_seconds ?? 60 },
|
|
1030
1031
|
root: dir,
|
|
1031
1032
|
...(combined ? { lifecycleTimeouts: daemon.timeouts } : {}),
|
|
@@ -1057,7 +1058,7 @@ async function checkDaemon(dir, info, paths, payload, findings, executor, backgr
|
|
|
1057
1058
|
if (readFileSync(join(unpacked, "daemon/config.json"), "utf8") !== JSON.stringify(expectedConfig) + '\n')
|
|
1058
1059
|
throw new Error("non-canonical daemon config");
|
|
1059
1060
|
for (const hook of ["start-stop-status", "preupgrade", "preuninst"]) {
|
|
1060
|
-
if (!matchesStandaloneScript(hook, nativeGateway ? { ...manifest, os_min_ver: info.os_min_ver, identityGateway: nativeGateway } : manifest, readFileSync(join(dir, "scripts", hook), "utf8")))
|
|
1061
|
+
if (!matchesStandaloneScript(hook, nativeGateway ? { ...manifest, os_min_ver: info.os_min_ver, identityGateway: nativeGateway } : manifest, readFileSync(join(dir, "scripts", hook), "utf8"), Boolean(extras.installPorts)))
|
|
1061
1062
|
findings.push(`daemon scripts/${hook} does not match the fixed lifecycle`);
|
|
1062
1063
|
}
|
|
1063
1064
|
return daemon;
|
|
@@ -1379,7 +1380,7 @@ function checkConf(dir, findings, kind, background, sharedFolder, pkg, portal, c
|
|
|
1379
1380
|
}
|
|
1380
1381
|
}
|
|
1381
1382
|
/** The opt-in package user unit must be exactly what the generator writes. */
|
|
1382
|
-
function checkBackground(dir, info, payload, findings, executor, daemon, bridge = false, lifecycleTimeouts, nativeGateway) {
|
|
1383
|
+
function checkBackground(dir, info, payload, findings, executor, daemon, bridge = false, lifecycleTimeouts, nativeGateway, installPorts = false) {
|
|
1383
1384
|
const pkg = info.package;
|
|
1384
1385
|
if (!pkg)
|
|
1385
1386
|
return;
|
|
@@ -1402,6 +1403,7 @@ function checkBackground(dir, info, payload, findings, executor, daemon, bridge
|
|
|
1402
1403
|
}
|
|
1403
1404
|
if (!matchesStandaloneScript("start-stop-status", {
|
|
1404
1405
|
package: pkg,
|
|
1406
|
+
...(installPorts ? { installPorts: true } : {}),
|
|
1405
1407
|
os_min_ver: info.os_min_ver,
|
|
1406
1408
|
...(nativeGateway ? { identityGateway: nativeGateway } : {}),
|
|
1407
1409
|
lifecycleTimeouts,
|
|
@@ -1410,7 +1412,7 @@ function checkBackground(dir, info, payload, findings, executor, daemon, bridge
|
|
|
1410
1412
|
jobs: { worker: "sha256-v1" },
|
|
1411
1413
|
...(executor ? { rootOps: true } : {}),
|
|
1412
1414
|
},
|
|
1413
|
-
}, read("scripts/start-stop-status")))
|
|
1415
|
+
}, read("scripts/start-stop-status"), installPorts))
|
|
1414
1416
|
findings.push("background scripts/start-stop-status does not match the fixed synosystemctl lifecycle");
|
|
1415
1417
|
}
|
|
1416
1418
|
/**
|