@synopackageland/cli 0.17.5 → 0.17.6

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.6 (2026-10-20)
4
+
5
+ - Inspect sharedFolder, Portal and install-selected Apps by reconstructing fixed lifecycle scripts from their complete inputs, including native HTTPS ingress and App hooks.
6
+
3
7
  ## 0.17.5 (2026-10-20)
4
8
 
5
9
  - Run native HTTPS preparation inside the SDK lifecycle steps before App hooks, keeping generated hook wrappers inspectable.
@@ -28,7 +28,7 @@ import { BACKGROUND_UNIT_DIR, BACKGROUND_WORKER_PAYLOAD, BRIDGE_WORKER_ARGS, bac
28
28
  import { renderStandaloneResource } from "./resource.js";
29
29
  import { recoverSharedFolder, renderSharedFolderUpgradeWizardFiles, sharedFolderInstallSteps, SHARED_FOLDER_MARKER, } from "./shared-folder.js";
30
30
  import { renderInstallWizardFiles, renderNativeInstallWizard, } from "../build-spk/install-wizard.js";
31
- import { renderDelegateScopeSteps, renderDelegateInstallDraft, } from "../build-spk/delegate-scope.js";
31
+ import { renderDelegateScopeSteps, } from "../build-spk/delegate-scope.js";
32
32
  import { renderUninstallWizardFiles } from "../build-spk/uninstall-wizard.js";
33
33
  import { renderNativePrivilege } from "../build-spk/native-lifecycle.js";
34
34
  import { renderUiConfig } from "./dsm-window.js";
@@ -162,7 +162,7 @@ export async function inspectSpk(spkPath, expectedKind) {
162
162
  : undefined;
163
163
  // Resource-worker portals use DSM-owned INFO reload, with no executor requirement.
164
164
  const portal = standalone
165
- ? await recoverPortal(dir, info, `SYNO.SDS.${info.package}.Instance`, paths, payload, findings)
165
+ ? await recoverPortal(dir, info, `SYNO.SDS.${info.package}.Instance`, paths, payload, findings, nativeGateway)
166
166
  : undefined;
167
167
  if (portal &&
168
168
  info.os_min_ver &&
@@ -269,7 +269,7 @@ export async function inspectSpk(spkPath, expectedKind) {
269
269
  ? await inspectLoginStyle(dir, info.package, Boolean(portal || executor?.policy.portal), findings)
270
270
  : undefined;
271
271
  if (standalone)
272
- checkSharedFolder(dir, findings, info.package, sharedFolder, executor?.policy.scope === "install-selected", portal, hasExecutor);
272
+ checkSharedFolder(dir, findings, info.package, sharedFolder, executor?.policy.scope === "install-selected", portal, hasExecutor, nativeGateway, info.os_min_ver);
273
273
  const icon = inspectPackageIcons(dir, findings);
274
274
  const cgiEntry = payload.find((entry) => entry.path === CGI_PAYLOAD_PATH);
275
275
  if (standalone && !cgiEntry) {
@@ -1081,7 +1081,7 @@ function checkBackground(dir, info, payload, findings, executor, daemon, bridge
1081
1081
  * declaration (without one, any present file must be the default native
1082
1082
  * install wizard), and no other install/upgrade wizard file may exist.
1083
1083
  */
1084
- function checkSharedFolder(dir, findings, pkg, folder, selected = false, portal, executor = false) {
1084
+ function checkSharedFolder(dir, findings, pkg, folder, selected = false, portal, executor = false, nativeGateway, osMinVer) {
1085
1085
  const wizardDir = join(dir, "WIZARD_UIFILES");
1086
1086
  const present = (existsSync(wizardDir) ? readdirSync(wizardDir) : [])
1087
1087
  .filter((name) => /^(install|upgrade)_uifile(_|\.|$)/.test(name))
@@ -1091,6 +1091,22 @@ function checkSharedFolder(dir, findings, pkg, folder, selected = false, portal,
1091
1091
  findings.push("the install.sharedFolder declaration in scripts/postinst is invalid");
1092
1092
  if (!pkg)
1093
1093
  return;
1094
+ // App wrappers have already been validated and unwrapped. Reconstruct the
1095
+ // remaining install-hook inputs from INFO, the payload and its build record.
1096
+ const lifecycleManifest = {
1097
+ package: pkg,
1098
+ os_min_ver: osMinVer,
1099
+ sharedFolder: folder,
1100
+ capabilities: selected
1101
+ ? { delegate: { scope: "install-selected" } }
1102
+ : executor
1103
+ ? { rootOps: true }
1104
+ : {},
1105
+ ...(nativeGateway
1106
+ ? { identityGateway: nativeGateway }
1107
+ : {}),
1108
+ ...portalManifest(portal),
1109
+ };
1094
1110
  const wizards = expectedWizardFiles(pkg, folder, selected, portal);
1095
1111
  const source = selected
1096
1112
  ? "the install-selected policy"
@@ -1110,25 +1126,17 @@ function checkSharedFolder(dir, findings, pkg, folder, selected = false, portal,
1110
1126
  findings.push(`WIZARD_UIFILES/${name} is not a wizard file produced by ${source}`);
1111
1127
  if (selected) {
1112
1128
  for (const hook of ["preinst", "postinst"]) {
1113
- if (!readOptional(join(dir, "scripts", hook))?.includes(renderDelegateInstallDraft(pkg, hook === "preinst")))
1114
- findings.push(`scripts/${hook} missing install-selected draft handling`);
1129
+ if (readOptional(join(dir, "scripts", hook)) !==
1130
+ renderStandaloneScript(hook, lifecycleManifest))
1131
+ findings.push(`scripts/${hook} does not match the fixed install-selected draft handling`);
1115
1132
  }
1116
1133
  }
1117
- if (!folder)
1134
+ if (!folder && !portal)
1118
1135
  return;
1119
1136
  for (const hook of ["postinst", "postupgrade"]) {
1120
1137
  if (readOptional(join(dir, "scripts", hook)) !==
1121
- renderStandaloneScript(hook, {
1122
- package: pkg,
1123
- sharedFolder: folder,
1124
- ...(selected
1125
- ? { capabilities: { delegate: { scope: "install-selected" } } }
1126
- : executor
1127
- ? { capabilities: { rootOps: true } }
1128
- : {}),
1129
- ...portalManifest(portal),
1130
- })) {
1131
- findings.push(`scripts/${hook} does not match the fixed script declared by install.sharedFolder`);
1138
+ renderStandaloneScript(hook, lifecycleManifest)) {
1139
+ findings.push(`scripts/${hook} does not match the fixed script declared by ${folder ? "install.sharedFolder" : "portal"}`);
1132
1140
  }
1133
1141
  }
1134
1142
  }
@@ -1160,7 +1168,7 @@ function portalManifest(portal) {
1160
1168
  * files and alias lifecycle must be exactly what the generator writes for the
1161
1169
  * package's own DSM window (native AppInstance or Compose `.url` entry); activation is never part of the package.
1162
1170
  */
1163
- async function recoverPortal(dir, info, appId, paths, payload, findings) {
1171
+ async function recoverPortal(dir, info, appId, paths, payload, findings, nativeGateway) {
1164
1172
  const files = [PORTAL_JSON_RELPATH, PORTAL_MUSTACHE_RELPATH];
1165
1173
  if (!files.some((path) => paths.has(path)))
1166
1174
  return;
@@ -1184,7 +1192,14 @@ async function recoverPortal(dir, info, appId, paths, payload, findings) {
1184
1192
  renderPortalMustache())
1185
1193
  throw new Error("content");
1186
1194
  for (const hook of ["preinst", "postinst", "postupgrade"]) {
1187
- if (!readOptional(join(dir, "scripts", hook))?.startsWith(`#!/bin/sh\n${renderPortalLifecycle(hook, portal)}`))
1195
+ const prepare = ["postinst", "postupgrade"].includes(hook)
1196
+ ? renderNativeGatewayPrepare({
1197
+ package: info.package,
1198
+ os_min_ver: info.os_min_ver,
1199
+ identityGateway: nativeGateway,
1200
+ })
1201
+ : "";
1202
+ if (!readOptional(join(dir, "scripts", hook))?.startsWith(`#!/bin/sh\n${prepare}${renderPortalLifecycle(hook, portal)}`))
1188
1203
  throw new Error(hook);
1189
1204
  }
1190
1205
  return portal;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synopackageland/cli",
3
- "version": "0.17.5",
3
+ "version": "0.17.6",
4
4
  "description": "Syno Package Land Developer Kit CLI",
5
5
  "type": "module",
6
6
  "bin": {