@synopackageland/cli 0.3.10 → 0.4.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.
Files changed (280) hide show
  1. package/README.md +20 -9
  2. package/dist/bin.js +1 -2
  3. package/dist/build-spk/generator.d.ts +0 -3
  4. package/dist/build-spk/generator.js +135 -287
  5. package/dist/build-spk/native-lifecycle.js +0 -3
  6. package/dist/build-spk/native-payload.js +0 -1
  7. package/dist/cli.js +171 -151
  8. package/dist/compose/analyze.d.ts +1 -2
  9. package/dist/compose/analyze.js +5 -48
  10. package/dist/contract/unsupported-types.d.ts +10 -0
  11. package/dist/contract/unsupported-types.js +49 -0
  12. package/dist/contract/validate.js +25 -2
  13. package/dist/contract/web-launch.js +0 -2
  14. package/dist/deploy/deploy.d.ts +1 -4
  15. package/dist/deploy/deploy.js +45 -156
  16. package/dist/deploy/homes-values.js +1 -1
  17. package/dist/deploy/plan.d.ts +18 -0
  18. package/dist/deploy/plan.js +54 -0
  19. package/dist/deploy/spk-version.d.ts +2 -14
  20. package/dist/deploy/spk-version.js +25 -111
  21. package/dist/dev.d.ts +1 -3
  22. package/dist/dev.js +14 -28
  23. package/dist/error-registry.js +810 -862
  24. package/dist/host/dsm-client.js +12 -272
  25. package/dist/host/dsm-port-profile.d.ts +0 -1
  26. package/dist/host/dsm-port-profile.js +0 -2
  27. package/dist/host/types.d.ts +1 -83
  28. package/dist/index.d.ts +0 -9
  29. package/dist/index.js +0 -6
  30. package/dist/info.d.ts +0 -1
  31. package/dist/info.js +3 -10
  32. package/dist/init.d.ts +11 -1
  33. package/dist/init.js +112 -4
  34. package/dist/log.js +2 -3
  35. package/dist/native/validate.js +0 -1
  36. package/dist/standalone/binary.d.ts +9 -0
  37. package/dist/standalone/binary.js +67 -0
  38. package/dist/standalone/build.d.ts +25 -0
  39. package/dist/standalone/build.js +108 -0
  40. package/dist/standalone/dsm-window.d.ts +26 -0
  41. package/dist/standalone/dsm-window.js +251 -0
  42. package/dist/standalone/helper.d.ts +31 -0
  43. package/dist/standalone/helper.js +104 -0
  44. package/dist/standalone/i18n.d.ts +28 -0
  45. package/dist/standalone/i18n.js +161 -0
  46. package/dist/standalone/inspect-spk.d.ts +21 -0
  47. package/dist/standalone/inspect-spk.js +160 -0
  48. package/dist/standalone/manifest.d.ts +71 -0
  49. package/dist/standalone/manifest.js +276 -0
  50. package/dist/standalone/root-messages.d.ts +7 -0
  51. package/dist/standalone/root-messages.js +250 -0
  52. package/dist/standalone/root-ops.d.ts +42 -0
  53. package/dist/standalone/root-ops.js +101 -0
  54. package/dist/standalone/root-window.d.ts +35 -0
  55. package/dist/standalone/root-window.js +290 -0
  56. package/dist/standalone/spk.d.ts +22 -0
  57. package/dist/standalone/spk.js +205 -0
  58. package/dist/templates/binary/synology-app.yaml +7 -0
  59. package/dist/templates/hello-files/compose.yaml +0 -1
  60. package/dist/templates/hello-web/compose.yaml +13 -10
  61. package/dist/templates/hello-web/html/app.js +1 -23
  62. package/dist/templates/hello-web/html/index.html +1 -3
  63. package/dist/templates/hello-web-page/compose.yaml +13 -10
  64. package/dist/templates/hello-web-page/html/app.js +1 -23
  65. package/dist/templates/hello-web-page/html/index.html +1 -3
  66. package/dist/templates/native-go/README.md +268 -0
  67. package/dist/templates/native-go/backend/cmd/app/main.go +49 -0
  68. package/dist/templates/native-go/backend/cmd/helper/main.go +38 -0
  69. package/dist/templates/native-go/backend/go.mod +3 -0
  70. package/dist/templates/native-go/backend/internal/api/errors.go +33 -0
  71. package/dist/templates/native-go/backend/internal/api/registry.go +94 -0
  72. package/dist/templates/native-go/backend/internal/api/registry_test.go +329 -0
  73. package/dist/templates/native-go/backend/internal/api/server.go +155 -0
  74. package/dist/templates/native-go/backend/internal/app/root_none.go +9 -0
  75. package/dist/templates/native-go/backend/internal/app/routes.go +127 -0
  76. package/dist/templates/native-go/backend/internal/app/routes_test.go +167 -0
  77. package/dist/templates/native-go/backend/internal/dsm/auth.go +118 -0
  78. package/dist/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  79. package/dist/templates/native-go/backend/internal/helper/control.go +219 -0
  80. package/dist/templates/native-go/backend/internal/helper/control_test.go +242 -0
  81. package/dist/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  82. package/dist/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  83. package/dist/templates/native-go/backend/internal/helper/process_linux.go +167 -0
  84. package/dist/templates/native-go/backend/internal/helper/process_other.go +5 -0
  85. package/dist/templates/native-go/backend/internal/helper/server_linux.go +83 -0
  86. package/dist/templates/native-go/backend/internal/helper/status.go +271 -0
  87. package/dist/templates/native-go/backend/internal/helper/status_test.go +205 -0
  88. package/dist/templates/native-go/backend/internal/helper/supervision.go +84 -0
  89. package/dist/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  90. package/dist/templates/native-go/backend/internal/helper/supervisor_linux.go +192 -0
  91. package/dist/templates/native-go/backend/internal/helper/supervisor_linux_test.go +302 -0
  92. package/dist/templates/native-go/dsm-package.yaml +58 -0
  93. package/dist/templates/native-go/gitignore +1 -0
  94. package/dist/templates/native-go/i18n/glossary.json +662 -0
  95. package/dist/templates/native-go/i18n/messages/de.json +28 -0
  96. package/dist/templates/native-go/i18n/messages/en.json +28 -0
  97. package/dist/templates/native-go/i18n/messages/es.json +28 -0
  98. package/dist/templates/native-go/i18n/messages/fr.json +28 -0
  99. package/dist/templates/native-go/i18n/messages/it.json +28 -0
  100. package/dist/templates/native-go/i18n/messages/ja.json +28 -0
  101. package/dist/templates/native-go/i18n/messages/ko.json +28 -0
  102. package/dist/templates/native-go/i18n/messages/zh-CN.json +28 -0
  103. package/dist/templates/native-go/i18n/messages/zh-TW.json +28 -0
  104. package/dist/templates/native-go/ui/app.css +35 -0
  105. package/dist/templates/native-go/ui/app.js +94 -0
  106. package/dist/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  107. package/dist/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  108. package/dist/templates/native-go-better-auth/node/app.mjs +72 -0
  109. package/dist/templates/native-go-better-auth/node/build.mjs +2 -0
  110. package/dist/templates/native-go-better-auth/node/package-lock.json +862 -0
  111. package/dist/templates/native-go-better-auth/node/package.json +1 -0
  112. package/dist/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  113. package/dist/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  114. package/dist/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  115. package/dist/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  116. package/dist/templates/native-go-root/backend/internal/app/root.go +107 -0
  117. package/dist/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  118. package/dist/templates/native-go-root/root/whoami.sh +6 -0
  119. package/dist/templates/native-go-vue/README.md +110 -0
  120. package/dist/templates/native-go-vue/frontend/DESIGN.md +78 -0
  121. package/dist/templates/native-go-vue/frontend/package-lock.json +2507 -0
  122. package/dist/templates/native-go-vue/frontend/package.json +6 -0
  123. package/dist/templates/native-go-vue/frontend/src/App.vue +132 -0
  124. package/dist/templates/native-go-vue/frontend/src/context.ts +17 -0
  125. package/dist/templates/native-go-vue/frontend/src/main.ts +26 -0
  126. package/dist/templates/native-go-vue/frontend/src/style.css +14 -0
  127. package/dist/templates/native-go-vue/frontend/test/apps.test.ts +148 -0
  128. package/dist/templates/native-go-vue/frontend/tsconfig.json +1 -0
  129. package/dist/templates/native-go-vue/frontend/vite.config.ts +8 -0
  130. package/dist/templates/native-go-vue/gitignore +2 -0
  131. package/dist/types.d.ts +1 -1
  132. package/dist/validate.js +11 -7
  133. package/package.json +3 -7
  134. package/schema/synology-app.schema.json +36 -37
  135. package/skills/SKILL.md +4 -48
  136. package/skills/reference/create.md +11 -83
  137. package/skills/reference/deploy.md +7 -78
  138. package/skills/reference/diagnose.md +4 -101
  139. package/skills/reference/files.md +5 -41
  140. package/skills/reference/identity.md +3 -29
  141. package/skills/reference/wrap.md +0 -2
  142. package/templates/binary/synology-app.yaml +7 -0
  143. package/templates/hello-files/compose.yaml +0 -1
  144. package/templates/hello-web/compose.yaml +13 -10
  145. package/templates/hello-web/html/app.js +1 -23
  146. package/templates/hello-web/html/index.html +1 -3
  147. package/templates/hello-web-page/compose.yaml +13 -10
  148. package/templates/hello-web-page/html/app.js +1 -23
  149. package/templates/hello-web-page/html/index.html +1 -3
  150. package/templates/native-go/README.md +268 -0
  151. package/templates/native-go/backend/cmd/app/main.go +49 -0
  152. package/templates/native-go/backend/cmd/helper/main.go +38 -0
  153. package/templates/native-go/backend/go.mod +3 -0
  154. package/templates/native-go/backend/internal/api/errors.go +33 -0
  155. package/templates/native-go/backend/internal/api/registry.go +94 -0
  156. package/templates/native-go/backend/internal/api/registry_test.go +329 -0
  157. package/templates/native-go/backend/internal/api/server.go +155 -0
  158. package/templates/native-go/backend/internal/app/root_none.go +9 -0
  159. package/templates/native-go/backend/internal/app/routes.go +127 -0
  160. package/templates/native-go/backend/internal/app/routes_test.go +167 -0
  161. package/templates/native-go/backend/internal/dsm/auth.go +118 -0
  162. package/templates/native-go/backend/internal/dsm/auth_test.go +139 -0
  163. package/templates/native-go/backend/internal/helper/control.go +219 -0
  164. package/templates/native-go/backend/internal/helper/control_test.go +242 -0
  165. package/templates/native-go/backend/internal/helper/peer_linux.go +44 -0
  166. package/templates/native-go/backend/internal/helper/peer_other.go +7 -0
  167. package/templates/native-go/backend/internal/helper/process_linux.go +167 -0
  168. package/templates/native-go/backend/internal/helper/process_other.go +5 -0
  169. package/templates/native-go/backend/internal/helper/server_linux.go +83 -0
  170. package/templates/native-go/backend/internal/helper/status.go +271 -0
  171. package/templates/native-go/backend/internal/helper/status_test.go +205 -0
  172. package/templates/native-go/backend/internal/helper/supervision.go +84 -0
  173. package/templates/native-go/backend/internal/helper/supervision_test.go +124 -0
  174. package/templates/native-go/backend/internal/helper/supervisor_linux.go +192 -0
  175. package/templates/native-go/backend/internal/helper/supervisor_linux_test.go +302 -0
  176. package/templates/native-go/dsm-package.yaml +58 -0
  177. package/templates/native-go/gitignore +1 -0
  178. package/templates/native-go/i18n/glossary.json +662 -0
  179. package/templates/native-go/i18n/messages/de.json +28 -0
  180. package/templates/native-go/i18n/messages/en.json +28 -0
  181. package/templates/native-go/i18n/messages/es.json +28 -0
  182. package/templates/native-go/i18n/messages/fr.json +28 -0
  183. package/templates/native-go/i18n/messages/it.json +28 -0
  184. package/templates/native-go/i18n/messages/ja.json +28 -0
  185. package/templates/native-go/i18n/messages/ko.json +28 -0
  186. package/templates/native-go/i18n/messages/zh-CN.json +28 -0
  187. package/templates/native-go/i18n/messages/zh-TW.json +28 -0
  188. package/templates/native-go/ui/app.css +35 -0
  189. package/templates/native-go/ui/app.js +94 -0
  190. package/templates/native-go-better-auth/backend/internal/app/identity.go +208 -0
  191. package/templates/native-go-better-auth/backend/internal/app/identity_test.go +113 -0
  192. package/templates/native-go-better-auth/node/app.mjs +72 -0
  193. package/templates/native-go-better-auth/node/build.mjs +2 -0
  194. package/templates/native-go-better-auth/node/package-lock.json +862 -0
  195. package/templates/native-go-better-auth/node/package.json +1 -0
  196. package/templates/native-go-better-auth/node/test/auth.test.mjs +31 -0
  197. package/templates/native-go-integration/backend/internal/app/identity_none.go +6 -0
  198. package/templates/native-go-integration/backend/internal/app/personal.go +203 -0
  199. package/templates/native-go-integration/backend/internal/app/personal_test.go +119 -0
  200. package/templates/native-go-root/backend/internal/app/root.go +107 -0
  201. package/templates/native-go-root/backend/internal/app/root_test.go +124 -0
  202. package/templates/native-go-root/root/whoami.sh +6 -0
  203. package/templates/native-go-vue/README.md +110 -0
  204. package/templates/native-go-vue/frontend/DESIGN.md +78 -0
  205. package/templates/native-go-vue/frontend/package-lock.json +2507 -0
  206. package/templates/native-go-vue/frontend/package.json +6 -0
  207. package/templates/native-go-vue/frontend/src/App.vue +132 -0
  208. package/templates/native-go-vue/frontend/src/context.ts +17 -0
  209. package/templates/native-go-vue/frontend/src/main.ts +26 -0
  210. package/templates/native-go-vue/frontend/src/style.css +14 -0
  211. package/templates/native-go-vue/frontend/test/apps.test.ts +148 -0
  212. package/templates/native-go-vue/frontend/tsconfig.json +1 -0
  213. package/templates/native-go-vue/frontend/vite.config.ts +8 -0
  214. package/templates/native-go-vue/gitignore +2 -0
  215. package/dist/attestation/app-package.d.ts +0 -86
  216. package/dist/attestation/app-package.js +0 -206
  217. package/dist/attestation/install-on-host.d.ts +0 -14
  218. package/dist/attestation/install-on-host.js +0 -52
  219. package/dist/attestation/keyring.d.ts +0 -21
  220. package/dist/attestation/keyring.js +0 -168
  221. package/dist/attestation/platform-service.d.ts +0 -70
  222. package/dist/attestation/platform-service.js +0 -250
  223. package/dist/build-spk/broker-glue.d.ts +0 -16
  224. package/dist/build-spk/broker-glue.js +0 -40
  225. package/dist/deploy/catalog-publish.d.ts +0 -3
  226. package/dist/deploy/catalog-publish.js +0 -7
  227. package/dist/doctor.d.ts +0 -22
  228. package/dist/doctor.js +0 -822
  229. package/dist/error-collector.d.ts +0 -2
  230. package/dist/error-collector.js +0 -46
  231. package/dist/host/broker-paths.d.ts +0 -1
  232. package/dist/host/broker-paths.js +0 -1
  233. package/dist/host/broker-upgrade-preflight.d.ts +0 -61
  234. package/dist/host/broker-upgrade-preflight.js +0 -156
  235. package/dist/host/digests.d.ts +0 -5
  236. package/dist/host/digests.js +0 -63
  237. package/dist/host/fake-nas.d.ts +0 -49
  238. package/dist/host/fake-nas.js +0 -193
  239. package/dist/mock-broker/bootstrap.d.ts +0 -2
  240. package/dist/mock-broker/bootstrap.js +0 -8
  241. package/dist/mock-broker/files.d.ts +0 -60
  242. package/dist/mock-broker/files.js +0 -408
  243. package/dist/mock-broker/oidc.d.ts +0 -31
  244. package/dist/mock-broker/oidc.js +0 -161
  245. package/dist/mock-broker/path.d.ts +0 -9
  246. package/dist/mock-broker/path.js +0 -50
  247. package/dist/mock-broker/server.d.ts +0 -19
  248. package/dist/mock-broker/server.js +0 -350
  249. package/dist/publish/build-ledger.d.ts +0 -22
  250. package/dist/publish/build-ledger.js +0 -26
  251. package/dist/publish/community-path.d.ts +0 -6
  252. package/dist/publish/community-path.js +0 -41
  253. package/dist/publish/curated-release.d.ts +0 -78
  254. package/dist/publish/curated-release.js +0 -883
  255. package/dist/publish/file-build-ledger.d.ts +0 -18
  256. package/dist/publish/file-build-ledger.js +0 -268
  257. package/dist/publish/github-pr.d.ts +0 -25
  258. package/dist/publish/github-pr.js +0 -85
  259. package/dist/publish/github-repo.d.ts +0 -8
  260. package/dist/publish/github-repo.js +0 -21
  261. package/dist/publish/platform-service-release.d.ts +0 -60
  262. package/dist/publish/platform-service-release.js +0 -333
  263. package/dist/publish/preflight.d.ts +0 -24
  264. package/dist/publish/preflight.js +0 -138
  265. package/dist/publish/publish.d.ts +0 -27
  266. package/dist/publish/publish.js +0 -136
  267. package/dist/publish/sync-definition.d.ts +0 -4
  268. package/dist/publish/sync-definition.js +0 -48
  269. package/dist/release-bin.d.ts +0 -2
  270. package/dist/release-bin.js +0 -23
  271. package/dist/templates/hello-web/html/sdk.js +0 -68
  272. package/dist/templates/hello-web-page/html/sdk.js +0 -68
  273. package/dist/templates/native/synology-app.yaml +0 -7
  274. package/dist/test-host.d.ts +0 -15
  275. package/dist/test-host.js +0 -37
  276. package/templates/hello-web/html/sdk.js +0 -68
  277. package/templates/hello-web-page/html/sdk.js +0 -68
  278. package/templates/native/synology-app.yaml +0 -7
  279. /package/dist/templates/{native → binary}/native.yaml +0 -0
  280. /package/templates/{native → binary}/native.yaml +0 -0
@@ -1,250 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { readFileSync } from "node:fs";
3
- import { SignJWT, importJWK, jwtVerify } from "jose";
4
- /**
5
- * Trust contract for releasing the platform service (the Broker SPK) itself.
6
- * This is deliberately a separate issuer, typ and keyring from the curated App
7
- * chain: the Broker carries the curated trust root as *data*, so that root can
8
- * never double as the authority that signs the Broker's own releases.
9
- */
10
- export const PLATFORM_ATTESTATION_ISSUER = "synopkgland-platform";
11
- export const PLATFORM_SERVICE_RELEASE_ATTESTATION_TYP = "platform-service-release-attestation";
12
- export const PLATFORM_SERVICE_RELEASE_ATTESTATION_VERSION = 1;
13
- export const PLATFORM_SERVICE_PACKAGE_IDENTITY = "SynoPkgLandService";
14
- export const PLATFORM_KEYRING_PURPOSE = "platform-service-release";
15
- export const PLATFORM_ATTESTATION_PRIVATE_JWK_ENV = "SYNOPKGLAND_PLATFORM_ATTESTATION_PRIVATE_JWK";
16
- export const PLATFORM_ATTESTATION_KID_ENV = "SYNOPKGLAND_PLATFORM_ATTESTATION_KID";
17
- export const PLATFORM_ATTESTATION_KEYRING_PATH_ENV = "SYNOPKGLAND_PLATFORM_ATTESTATION_KEYRING_PATH";
18
- export class PlatformServiceReleaseError extends Error {
19
- code;
20
- constructor(code, detail) {
21
- super(detail ? `${code}: ${detail}` : code);
22
- this.code = code;
23
- this.name = "PlatformServiceReleaseError";
24
- }
25
- }
26
- const PRIVATE_JWK_FIELDS = ["d", "p", "q", "dp", "dq", "qi", "oth", "k"];
27
- const KEY_STATUSES = new Set(["active", "verify-only", "revoked"]);
28
- export function parsePlatformKeyringDocument(raw) {
29
- if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
30
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", "not an object");
31
- }
32
- const document = raw;
33
- if (document.version !== 1 || !Array.isArray(document.keys)) {
34
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", "unsupported document shape");
35
- }
36
- if (document.purpose !== PLATFORM_KEYRING_PURPOSE) {
37
- // A curated keyring document has no purpose field at all; refusing here is
38
- // what keeps the Broker's bundled trust root from signing the Broker.
39
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_PURPOSE_MISMATCH");
40
- }
41
- for (const entry of document.keys) {
42
- if (!entry ||
43
- typeof entry.kid !== "string" ||
44
- entry.kid.length === 0 ||
45
- !KEY_STATUSES.has(entry.status) ||
46
- !entry.publicJwk ||
47
- typeof entry.publicJwk !== "object") {
48
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", "invalid key entry");
49
- }
50
- if (PRIVATE_JWK_FIELDS.some((field) => field in entry.publicJwk)) {
51
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_PRIVATE_MATERIAL");
52
- }
53
- if (entry.publicJwk.kty !== "RSA" || typeof entry.publicJwk.n !== "string") {
54
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", "not a public RSA key");
55
- }
56
- }
57
- if (!document.keys.some((entry) => entry.status === "active")) {
58
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_NO_ACTIVE_KEY");
59
- }
60
- return document;
61
- }
62
- export function readPlatformKeyringFile(path) {
63
- let raw;
64
- try {
65
- raw = readFileSync(path, "utf8");
66
- }
67
- catch (error) {
68
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", `unable to read keyring: ${error instanceof Error ? error.message : String(error)}`);
69
- }
70
- let parsed;
71
- try {
72
- parsed = JSON.parse(raw);
73
- }
74
- catch {
75
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", "keyring is not valid JSON");
76
- }
77
- return parsePlatformKeyringDocument(parsed);
78
- }
79
- export function canonicalPlatformServiceReleaseClaims(claims) {
80
- return JSON.stringify({
81
- arch: claims.arch,
82
- artifactDigest: claims.artifactDigest,
83
- issuedAt: claims.issuedAt,
84
- osMinVer: claims.osMinVer,
85
- packageBuild: claims.packageBuild,
86
- packageIdentity: claims.packageIdentity,
87
- packageVersion: claims.packageVersion,
88
- sourceRevision: claims.sourceRevision,
89
- sourceVersion: claims.sourceVersion,
90
- typ: claims.typ,
91
- version: claims.version,
92
- });
93
- }
94
- export function digestPlatformServiceReleaseClaims(claims) {
95
- return createHash("sha256").update(canonicalPlatformServiceReleaseClaims(claims)).digest("hex");
96
- }
97
- export async function signPlatformServiceReleaseAttestationToken(input, key) {
98
- assertPlatformInput(input);
99
- if (typeof key.kid !== "string" || key.kid.length === 0) {
100
- throw new PlatformServiceReleaseError("PLATFORM_SIGNING_MATERIAL_INVALID", "kid required");
101
- }
102
- const claims = {
103
- typ: PLATFORM_SERVICE_RELEASE_ATTESTATION_TYP,
104
- version: PLATFORM_SERVICE_RELEASE_ATTESTATION_VERSION,
105
- packageIdentity: input.packageIdentity,
106
- sourceVersion: input.sourceVersion,
107
- packageBuild: input.packageBuild,
108
- packageVersion: input.packageVersion,
109
- artifactDigest: input.artifactDigest,
110
- sourceRevision: input.sourceRevision,
111
- osMinVer: input.osMinVer,
112
- arch: input.arch,
113
- issuedAt: new Date().toISOString(),
114
- };
115
- const attestationDigest = digestPlatformServiceReleaseClaims(claims);
116
- const token = await new SignJWT({ ...claims })
117
- .setProtectedHeader({ alg: "RS256", kid: key.kid, typ: "JWT" })
118
- .setIssuer(PLATFORM_ATTESTATION_ISSUER)
119
- .setSubject(claims.packageIdentity)
120
- .setJti(attestationDigest)
121
- .sign(key.privateKey);
122
- return { token, attestationDigest, claims };
123
- }
124
- export async function verifyPlatformServiceReleaseAttestationToken(token, keyring) {
125
- parsePlatformKeyringDocument(keyring);
126
- try {
127
- const header = decodeHeader(token);
128
- const entry = keyring.keys.find((candidate) => candidate.kid === header.kid && candidate.status !== "revoked");
129
- if (!entry) {
130
- throw new Error("unknown or revoked kid");
131
- }
132
- const publicKey = (await importJWK(entry.publicJwk, "RS256"));
133
- const result = await jwtVerify(token, publicKey, {
134
- algorithms: ["RS256"],
135
- issuer: PLATFORM_ATTESTATION_ISSUER,
136
- });
137
- if (result.protectedHeader.alg !== "RS256" ||
138
- result.protectedHeader.typ !== "JWT" ||
139
- result.protectedHeader.kid !== entry.kid) {
140
- throw new Error("token header mismatch");
141
- }
142
- const payload = result.payload;
143
- if (payload.typ !== PLATFORM_SERVICE_RELEASE_ATTESTATION_TYP ||
144
- payload.version !== PLATFORM_SERVICE_RELEASE_ATTESTATION_VERSION) {
145
- throw new Error("token typ mismatch");
146
- }
147
- const claims = {
148
- typ: payload.typ,
149
- version: payload.version,
150
- packageIdentity: payload.packageIdentity,
151
- sourceVersion: payload.sourceVersion,
152
- packageBuild: payload.packageBuild,
153
- packageVersion: payload.packageVersion,
154
- artifactDigest: payload.artifactDigest,
155
- sourceRevision: payload.sourceRevision,
156
- osMinVer: payload.osMinVer,
157
- arch: payload.arch,
158
- issuedAt: payload.issuedAt,
159
- };
160
- assertPlatformInput(claims);
161
- if (typeof claims.issuedAt !== "string" || Number.isNaN(Date.parse(claims.issuedAt))) {
162
- throw new Error("issuedAt is not a timestamp");
163
- }
164
- if (result.payload.jti !== digestPlatformServiceReleaseClaims(claims)) {
165
- throw new Error("jti does not bind the claims");
166
- }
167
- return claims;
168
- }
169
- catch (error) {
170
- if (error instanceof PlatformServiceReleaseError) {
171
- throw new PlatformServiceReleaseError("PLATFORM_ATTESTATION_INVALID", error.message);
172
- }
173
- throw new PlatformServiceReleaseError("PLATFORM_ATTESTATION_INVALID", error instanceof Error ? error.message : String(error));
174
- }
175
- }
176
- export async function createPlatformAttestationSignerFromEnv(env = process.env) {
177
- const jwkRaw = env[PLATFORM_ATTESTATION_PRIVATE_JWK_ENV]?.trim();
178
- const kidFromEnv = env[PLATFORM_ATTESTATION_KID_ENV]?.trim();
179
- const keyringPath = env[PLATFORM_ATTESTATION_KEYRING_PATH_ENV]?.trim();
180
- if (!jwkRaw) {
181
- throw new PlatformServiceReleaseError("PLATFORM_SIGNING_MATERIAL_MISSING");
182
- }
183
- if (!keyringPath) {
184
- throw new PlatformServiceReleaseError("PLATFORM_KEYRING_INVALID", `${PLATFORM_ATTESTATION_KEYRING_PATH_ENV} is required`);
185
- }
186
- const keyring = readPlatformKeyringFile(keyringPath);
187
- let privateJwk;
188
- let privateKey;
189
- try {
190
- privateJwk = JSON.parse(jwkRaw);
191
- privateKey = (await importJWK(privateJwk, "RS256"));
192
- }
193
- catch {
194
- throw new PlatformServiceReleaseError("PLATFORM_SIGNING_MATERIAL_INVALID");
195
- }
196
- const kid = kidFromEnv || (typeof privateJwk.kid === "string" ? privateJwk.kid : "");
197
- if (!kid) {
198
- throw new PlatformServiceReleaseError("PLATFORM_SIGNING_MATERIAL_INVALID", "kid required");
199
- }
200
- const trustEntry = keyring.keys.find((entry) => entry.kid === kid && entry.status === "active");
201
- if (!trustEntry) {
202
- throw new PlatformServiceReleaseError("PLATFORM_SIGNING_KEY_UNKNOWN");
203
- }
204
- const signingKey = { kid, privateKey };
205
- return {
206
- sign: (input) => signPlatformServiceReleaseAttestationToken(input, signingKey),
207
- verify: (token) => verifyPlatformServiceReleaseAttestationToken(token, keyring),
208
- verificationJwk: trustEntry.publicJwk,
209
- };
210
- }
211
- function assertPlatformInput(input) {
212
- const fail = (detail) => {
213
- throw new PlatformServiceReleaseError("PLATFORM_ATTESTATION_INPUT_INVALID", detail);
214
- };
215
- if (input.packageIdentity !== PLATFORM_SERVICE_PACKAGE_IDENTITY) {
216
- fail("packageIdentity must be the platform service identity");
217
- }
218
- if (!/^\d+\.\d+\.\d+$/.test(input.sourceVersion)) {
219
- fail("sourceVersion must be plain semver without a Build suffix");
220
- }
221
- if (!Number.isSafeInteger(input.packageBuild) || input.packageBuild < 1) {
222
- fail("packageBuild must be a positive safe integer");
223
- }
224
- if (input.packageVersion !== `${input.sourceVersion}-${String(input.packageBuild).padStart(4, "0")}`) {
225
- fail("packageVersion must be sourceVersion plus the zero-padded Build");
226
- }
227
- if (!/^[a-f0-9]{64}$/.test(input.artifactDigest)) {
228
- fail("artifactDigest must be a lowercase SHA-256 digest");
229
- }
230
- if (!/^[a-f0-9]{40}$/.test(input.sourceRevision)) {
231
- fail("sourceRevision must be a full git commit SHA");
232
- }
233
- if (!/^\d+\.\d+-\d+$/.test(input.osMinVer)) {
234
- fail("osMinVer must look like 7.2-69057");
235
- }
236
- if (input.arch !== "noarch") {
237
- fail("the platform service is noarch");
238
- }
239
- }
240
- function decodeHeader(token) {
241
- const parts = token.split(".");
242
- if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
243
- throw new Error("not a compact JWT");
244
- }
245
- const header = JSON.parse(Buffer.from(parts[0], "base64url").toString("utf8"));
246
- if (!header || typeof header !== "object" || Array.isArray(header)) {
247
- throw new Error("invalid JWT header");
248
- }
249
- return header;
250
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * The Broker installer glue every Managed Profile App carries, independent of
3
- * runtime. Compose and native Apps install through the same socket, so the
4
- * Local Attestation gate and the registration-status probe live here once.
5
- */
6
- /** Shell variable preamble locating the Broker installer and its socket. */
7
- export declare const BROKER_INSTALLER_VARS = "INSTALLER=\"${BROKER_INSTALLER:-/var/packages/SynoPkgLandService/target/bin/synopkgland-installer}\"\nSOCKET=\"${BROKER_SOCKET:-/var/packages/SynoPkgLandService/var/installer.sock}\"";
8
- /**
9
- * The `status` probe: asks the Broker whether this App is still registered.
10
- * `removed` exits 150 so DSM shows the App as removed by the platform;
11
- * `unknown` exits 4. Anything else falls through to the caller, which decides
12
- * what "running" means for its runtime.
13
- */
14
- export declare function renderBrokerStatusProbe(packageIdentity: string): string;
15
- /** `preinst` / `preupgrade`: refuse to install when the Broker socket is absent. */
16
- export declare const BROKER_SOCKET_REQUIRED_SCRIPT = "#!/bin/sh\nSOCKET=\"${BROKER_SOCKET:-/var/packages/SynoPkgLandService/var/installer.sock}\"\nif [ ! -S \"$SOCKET\" ]; then\n echo \"SynoPkgLandService installer socket is not available\" >&2\n exit 1\nfi\nexit 0\n";
@@ -1,40 +0,0 @@
1
- /**
2
- * The Broker installer glue every Managed Profile App carries, independent of
3
- * runtime. Compose and native Apps install through the same socket, so the
4
- * Local Attestation gate and the registration-status probe live here once.
5
- */
6
- /** Shell variable preamble locating the Broker installer and its socket. */
7
- export const BROKER_INSTALLER_VARS = `INSTALLER="\${BROKER_INSTALLER:-/var/packages/SynoPkgLandService/target/bin/synopkgland-installer}"
8
- SOCKET="\${BROKER_SOCKET:-/var/packages/SynoPkgLandService/var/installer.sock}"`;
9
- /**
10
- * The `status` probe: asks the Broker whether this App is still registered.
11
- * `removed` exits 150 so DSM shows the App as removed by the platform;
12
- * `unknown` exits 4. Anything else falls through to the caller, which decides
13
- * what "running" means for its runtime.
14
- */
15
- export function renderBrokerStatusProbe(packageIdentity) {
16
- return ` if [ -x "$INSTALLER" ] && [ -S "$SOCKET" ]; then
17
- "$INSTALLER" --socket "$SOCKET" --phase status --attempt-id "status-$$" \\
18
- --package-identity "${packageIdentity}" --package-version "\${SYNOPKG_PKGVER}" \\
19
- --package-path "\${SYNOPKG_PKGDEST}" --bundle-path "\${SYNOPKG_PKGDEST}" \\
20
- --pkg-var "\${SYNOPKG_PKGVAR}" --pkg-home "\${SYNOPKG_PKGHOME}" >/tmp/synopkgland-status.$$ 2>/dev/null || true
21
- if grep -q '"registrationStatus":"removed"' /tmp/synopkgland-status.$$ 2>/dev/null; then
22
- rm -f /tmp/synopkgland-status.$$
23
- exit 150
24
- fi
25
- if grep -q '"registrationStatus":"unknown"' /tmp/synopkgland-status.$$ 2>/dev/null; then
26
- rm -f /tmp/synopkgland-status.$$
27
- exit 4
28
- fi
29
- rm -f /tmp/synopkgland-status.$$
30
- fi`;
31
- }
32
- /** `preinst` / `preupgrade`: refuse to install when the Broker socket is absent. */
33
- export const BROKER_SOCKET_REQUIRED_SCRIPT = `#!/bin/sh
34
- SOCKET="\${BROKER_SOCKET:-/var/packages/SynoPkgLandService/var/installer.sock}"
35
- if [ ! -S "$SOCKET" ]; then
36
- echo "SynoPkgLandService installer socket is not available" >&2
37
- exit 1
38
- fi
39
- exit 0
40
- `;
@@ -1,3 +0,0 @@
1
- import { type PublishSpkResult } from "@synopackageland/package-source/publish-spk";
2
- export declare function publishBuiltSpk(spkPath: string): Promise<PublishSpkResult>;
3
- export declare function packageSourceOrigin(): string;
@@ -1,7 +0,0 @@
1
- import { publishSpkToSource, resolvePublishTarget, } from "@synopackageland/package-source/publish-spk";
2
- export async function publishBuiltSpk(spkPath) {
3
- return publishSpkToSource(spkPath, resolvePublishTarget());
4
- }
5
- export function packageSourceOrigin() {
6
- return resolvePublishTarget().origin;
7
- }
package/dist/doctor.d.ts DELETED
@@ -1,22 +0,0 @@
1
- import type { ProjectRoot } from "./discovery.js";
2
- import type { NasHost } from "./host/types.js";
3
- export type DoctorCheckStatus = "pass" | "fail" | "skip" | "warn";
4
- export interface DoctorCheck {
5
- id: string;
6
- status: DoctorCheckStatus;
7
- code?: string;
8
- message: string;
9
- suggestion?: string;
10
- }
11
- export interface DoctorReport {
12
- ok: boolean;
13
- checks: DoctorCheck[];
14
- }
15
- export interface RunDoctorOptions {
16
- project?: ProjectRoot | null;
17
- host?: NasHost | null;
18
- packageId?: string;
19
- dev?: boolean;
20
- }
21
- export declare function runDoctor(options: RunDoctorOptions): Promise<DoctorReport>;
22
- export declare function formatDoctorReport(report: DoctorReport): string;