@synopackageland/cli 0.22.0 → 0.23.0
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 +5 -0
- package/dist/error-registry.js +1 -1
- package/dist/runtime/executor-digests.json +1 -1
- package/dist/runtime/sdk-source.js +1 -1
- package/dist/standalone/identity-gateway.d.ts +4 -0
- package/dist/standalone/identity-gateway.js +15 -1
- package/package.json +2 -2
- package/skills/reference/identity-gateway.md +32 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.23.0 (2026-10-21)
|
|
4
|
+
|
|
5
|
+
- Validate the explicit OIDC `browser_redirect` contract before packaging and pin templates/SDK 0.23.0.
|
|
6
|
+
- Reuse executor/v0.20.0 with unchanged executor and lifecycle payloads.
|
|
7
|
+
|
|
3
8
|
## 0.22.0 (2026-10-21)
|
|
4
9
|
|
|
5
10
|
- Support SDK/App 0.22.x and pin templates 0.22.0 with published UI 0.12.5.
|
package/dist/error-registry.js
CHANGED
|
@@ -2,7 +2,7 @@ import { COMPOSE_ERRORS } from "./standalone/compose-errors.js";
|
|
|
2
2
|
export const ERROR_REGISTRY = {
|
|
3
3
|
...COMPOSE_ERRORS,
|
|
4
4
|
INSTALL_SETTINGS_INVALID: { "code": "INSTALL_SETTINGS_INVALID", "description": "The installation setting declaration is invalid.", "suggestion": "Declare 1–32 lowercase identifier keys in install.settings, each with type https-origin, a plain label and an explicit boolean required; omit defaults and values." },
|
|
5
|
-
SDK_INSTALL_SETTINGS_UNSUPPORTED: { "code": "SDK_INSTALL_SETTINGS_UNSUPPORTED", "description": "The selected SDK does not provide native installation settings.", "suggestion": "Pin SDK 0.
|
|
5
|
+
SDK_INSTALL_SETTINGS_UNSUPPORTED: { "code": "SDK_INSTALL_SETTINGS_UNSUPPORTED", "description": "The selected SDK does not provide native installation settings.", "suggestion": "Pin SDK 0.23.0 or a matching supported release with installsettings/cmd/control, then rebuild with the matching CLI." },
|
|
6
6
|
SDK_INSTALL_SETTINGS_BUILD_FAILED: { "code": "SDK_INSTALL_SETTINGS_BUILD_FAILED", "description": "The SDK installation settings controller could not be built.", "suggestion": "Install the pinned Go toolchain, inspect the compiler diagnostics and rebuild with a complete matching SDK release." },
|
|
7
7
|
INIT_HEALTH_INVALID: { code: "INIT_HEALTH_INVALID", description: "The Compose readiness selection is invalid.", suggestion: "Supply both --health-path and --health-status with the actual endpoint and expected 2xx response; redirects are not followed." },
|
|
8
8
|
INIT_UPSTREAM_IMAGE_REQUIRED: { code: "INIT_UPSTREAM_IMAGE_REQUIRED", description: "The official upstream image repository was not selected.", suggestion: "Use init --upstream-fork --upstream-image <official-repository> for Compose." },
|
|
@@ -76,7 +76,7 @@ function goMod(backendDir) {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
/** SDK releases that reuse an immutable executor release with identical payload bytes. */
|
|
79
|
-
const EXECUTOR_RELEASES = { '0.21.0': '0.20.0', '0.21.1': '0.20.0', '0.22.0': '0.20.0' };
|
|
79
|
+
const EXECUTOR_RELEASES = { '0.21.0': '0.20.0', '0.21.1': '0.20.0', '0.22.0': '0.20.0', '0.23.0': '0.20.0' };
|
|
80
80
|
/**
|
|
81
81
|
* The module directories of one SDK version. SYNOPKGLAND_SDK_DIR names a
|
|
82
82
|
* local sdk checkout (development and gates only); otherwise modules come from
|
|
@@ -59,6 +59,10 @@ export interface IdentityGateway {
|
|
|
59
59
|
roles?: GatewayRoles;
|
|
60
60
|
headers?: Partial<Record<"user" | "email" | "name" | "groups" | "uid", string>>;
|
|
61
61
|
oidc?: {
|
|
62
|
+
browser_redirect?: {
|
|
63
|
+
html_paths?: string[];
|
|
64
|
+
same_origin_referrer?: boolean;
|
|
65
|
+
};
|
|
62
66
|
native_login?: boolean;
|
|
63
67
|
issuer_port: number;
|
|
64
68
|
browser?: GatewayBrowser;
|
|
@@ -291,7 +291,7 @@ export function readIdentityGateway(value, daemon, fail, packagedPayload = false
|
|
|
291
291
|
if (v.mode === "oidc") {
|
|
292
292
|
const o = v.oidc;
|
|
293
293
|
if (!record(o) ||
|
|
294
|
-
!only(o, ["issuer_port", "clients", "rewrite_json", "browser", "native_login"]) ||
|
|
294
|
+
!only(o, ["issuer_port", "clients", "rewrite_json", "browser", "native_login", "browser_redirect"]) ||
|
|
295
295
|
(o.native_login !== undefined && typeof o.native_login !== "boolean") ||
|
|
296
296
|
!port(o.issuer_port) ||
|
|
297
297
|
!Array.isArray(o.clients) ||
|
|
@@ -312,6 +312,14 @@ export function readIdentityGateway(value, daemon, fail, packagedPayload = false
|
|
|
312
312
|
name(r.field))) {
|
|
313
313
|
return invalid("oidc.rewrite_json entries are { method, path, field }.");
|
|
314
314
|
}
|
|
315
|
+
const br = o.browser_redirect;
|
|
316
|
+
if (br !== undefined) {
|
|
317
|
+
const path = (p) => localPath(p) && p.length <= 512 && !/[%\s]/.test(p) && !p.startsWith("/_sso");
|
|
318
|
+
if (!record(br) || !only(br, ["html_paths", "same_origin_referrer"]) ||
|
|
319
|
+
(br.same_origin_referrer !== undefined && typeof br.same_origin_referrer !== "boolean") ||
|
|
320
|
+
(br.html_paths !== undefined && (!strings(br.html_paths, path, 16) || new Set(br.html_paths).size !== br.html_paths.length)))
|
|
321
|
+
return invalid("oidc.browser_redirect accepts only optional exact html_paths outside /_sso and same_origin_referrer.");
|
|
322
|
+
}
|
|
315
323
|
const b = o.browser;
|
|
316
324
|
if (b !== undefined) {
|
|
317
325
|
const [major, minor] = v.sdk.split(".").map(Number);
|
|
@@ -334,6 +342,7 @@ export function readIdentityGateway(value, daemon, fail, packagedPayload = false
|
|
|
334
342
|
return invalid("oidc.browser needs fixed local start, login_paths and callback_paths outside /_sso.");
|
|
335
343
|
}
|
|
336
344
|
gateway.oidc = {
|
|
345
|
+
...(br !== undefined ? { browser_redirect: br } : {}),
|
|
337
346
|
...(o.native_login !== undefined ? { native_login: o.native_login } : {}),
|
|
338
347
|
issuer_port: o.issuer_port,
|
|
339
348
|
...(b !== undefined ? { browser: b } : {}),
|
|
@@ -481,6 +490,11 @@ export async function buildIdentityGateway(m, arch, work, run) {
|
|
|
481
490
|
throw new StandaloneBuildError("SDK_DOWNLOAD_FAILED", error.message.replace(/^\[[A-Z_]+\] /, ""));
|
|
482
491
|
}
|
|
483
492
|
runtimeBudgetSource(sdk.goDir, m);
|
|
493
|
+
if (m.identityGateway.oidc?.browser_redirect) {
|
|
494
|
+
const capability = join(sdk.goDir, "idgateway/browser_redirect.go");
|
|
495
|
+
if (!existsSync(capability) || !/const BrowserRedirectVersion = 2\b/.test(readFileSync(capability, "utf8")))
|
|
496
|
+
throw new StandaloneBuildError("STANDALONE_IDENTITY_GATEWAY_INVALID", "The selected SDK lacks per-request OIDC browser redirect support; use a matching SDK release or an explicit development source override.");
|
|
497
|
+
}
|
|
484
498
|
if (m.identityGateway.upstream_access === "public") {
|
|
485
499
|
const capability = join(sdk.goDir, "idgateway/provider_only.go");
|
|
486
500
|
if (!existsSync(capability) || !/const ProviderOnlyOIDCVersion = 1\b/.test(readFileSync(capability, "utf8")))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synopackageland/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.23.0",
|
|
4
4
|
"description": "Syno Package Land Developer Kit CLI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@napi-rs/keyring": "^2.1.1",
|
|
30
|
-
"@synopackageland/templates": "0.
|
|
30
|
+
"@synopackageland/templates": "0.23.0",
|
|
31
31
|
"ajv": "^8.17.1",
|
|
32
32
|
"commander": "^13.1.0",
|
|
33
33
|
"json-canonicalize": "^3.0.1",
|
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
# Wrap an OSS app with DSM accounts
|
|
2
2
|
|
|
3
|
+
## Per-request OIDC browser origins (development)
|
|
4
|
+
|
|
5
|
+
`oidc.browser_redirect: {}` opts into per-request browser origins for SDK/CLI
|
|
6
|
+
0.23. Optional `html_paths` and `same_origin_referrer` configure HTML behavior.
|
|
7
|
+
No host list is accepted or stored in the SPK: users can open the same install
|
|
8
|
+
by IP, hostname, DDNS or a new DNS alias. Each request must use a syntactically
|
|
9
|
+
valid IP/DNS authority and the declared gateway scheme/port; forwarding headers
|
|
10
|
+
cannot select the destination. DSM native ingress uses its HTTPS port.
|
|
11
|
+
Host selects only this browser response's navigation URL, never an upstream
|
|
12
|
+
dial target or an authorization decision. DSM admission, transaction origin
|
|
13
|
+
and browser binding, exact redirect registration and PKCE remain required.
|
|
14
|
+
Gateway cookies are host-only. This does not make public upstream routes a
|
|
15
|
+
network security boundary; upstream retains its authentication/CSRF duties.
|
|
16
|
+
Use trusted DNS and TLS, as a user signing in on an attacker-controlled origin
|
|
17
|
+
exposes that origin's session to its owner. Rewritten responses use no-store
|
|
18
|
+
and remove validators/digests; issuer/discovery never depend on Host.
|
|
19
|
+
|
|
20
|
+
Location and existing `rewrite_json` rules already map the loopback authorization
|
|
21
|
+
endpoint. For clients returning it in HTML, add `html_paths: ["/auth/redirect"]`:
|
|
22
|
+
only those exact GET/200 HTML responses are rewritten, up to 1 MiB using identity
|
|
23
|
+
encoding, with raw/escaped/percent-encoded URL support. Query bytes and upstream
|
|
24
|
+
CSP stay intact; inline CSP hashes over modified scripts are incompatible.
|
|
25
|
+
If an upstream native form uses `no-referrer` and browsers send `Origin: null`,
|
|
26
|
+
explicit `same_origin_referrer: true` restores same-origin metadata only on
|
|
27
|
+
the declared HTML paths. Include the form's page in that list. Referrers never
|
|
28
|
+
go to other origins; null/foreign Origin checks are not relaxed.
|
|
29
|
+
Issuer/ID token `iss`, discovery, token, userinfo and JWKS remain on loopback.
|
|
30
|
+
Redirect registration, PKCE and DSM browser binding are unchanged. This needs
|
|
31
|
+
matching SDK/CLI support; builds reject an SDK without the capability, including
|
|
32
|
+
old releases selected without a development source override.
|
|
33
|
+
|
|
3
34
|
## Provider-only OIDC
|
|
4
35
|
|
|
5
36
|
For an upstream with native authentication for browsers and native clients,
|
|
6
37
|
declare `mode: oidc`, `upstream_access: public`, and retain `access: dsm-users`,
|
|
7
38
|
`dsm-admins` or `dsm-groups` for the issuer. This capability requires
|
|
8
|
-
SDK/CLI 0.
|
|
39
|
+
SDK/CLI 0.23.0 or later. A build with an old SDK
|
|
9
40
|
without that capability fails rather than claiming support.
|
|
10
41
|
|
|
11
42
|
The gateway does not require DSM cookies or browser Origin on upstream requests.
|