@hanamesh/dsh-app-host 0.2.0-rc.2 → 0.6.12

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 (120) hide show
  1. package/LICENSE +4 -7
  2. package/README.md +136 -13
  3. package/consistency.json +41 -6
  4. package/dist/catalog/fixtures/consumer.json +35 -0
  5. package/dist/catalog/fixtures/provider.json +107 -0
  6. package/dist/catalog/suite.d.ts +4 -0
  7. package/dist/catalog/suite.js +50 -0
  8. package/dist/client-ui.d.ts +21 -3
  9. package/dist/client-ui.js +961 -94
  10. package/dist/client.js +2 -2
  11. package/dist/control-origin.js +9 -0
  12. package/dist/descriptor.js +6 -0
  13. package/dist/dsh-compat.js +6 -0
  14. package/dist/dsh.d.ts +21 -4
  15. package/dist/dsh.js +149 -58
  16. package/dist/gateway.js +140 -11
  17. package/dist/git-process.js +64 -0
  18. package/dist/git-worker.js +50 -0
  19. package/dist/index.d.ts +9 -7
  20. package/dist/install-target/fixtures/catalog.json +58 -0
  21. package/dist/install-target/fixtures/consumer-cases.json +148 -0
  22. package/dist/install-target/fixtures/install-failure-cases.json +58 -0
  23. package/dist/install-target/fixtures/provider-cases.json +618 -0
  24. package/dist/install-target/fixtures/reference-consumer.js +37 -0
  25. package/dist/install-target/fixtures/source-profile.js +123 -0
  26. package/dist/install-target/harness.js +43 -0
  27. package/dist/install-target/run.js +28 -0
  28. package/dist/install-target/suite.d.ts +19 -0
  29. package/dist/install-target/suite.js +328 -0
  30. package/dist/installation-status.d.ts +21 -0
  31. package/dist/installation-status.js +2 -0
  32. package/dist/library/catalog.js +134 -19
  33. package/dist/library/client-identity.js +31 -0
  34. package/dist/library/desktop-cli.js +7 -0
  35. package/dist/library/domain.js +3 -1
  36. package/dist/library/handoff.js +246 -0
  37. package/dist/library/install.js +138 -32
  38. package/dist/library/installation-cli.js +48 -0
  39. package/dist/library/installation-command-worker.js +27 -0
  40. package/dist/library/installation-status-http.js +26 -0
  41. package/dist/library/installation-status.js +91 -0
  42. package/dist/library/installation-worker.js +44 -0
  43. package/dist/library/locate.js +70 -9
  44. package/dist/library/node-binding.js +11 -0
  45. package/dist/library/recovery.js +66 -0
  46. package/dist/library/routes.js +90 -14
  47. package/dist/library/service.js +123 -27
  48. package/dist/library/suite.js +130 -0
  49. package/dist/manager.js +24 -8
  50. package/dist/node-runtime/domain.js +6 -0
  51. package/dist/node-runtime/releases.json +59 -0
  52. package/dist/node-runtime/service.js +101 -0
  53. package/dist/owned-probe-diagnostic.js +53 -0
  54. package/dist/router/receipts.js +8 -11
  55. package/dist/router/routes.js +7 -7
  56. package/dist/routes.js +9 -8
  57. package/dist/runtime.js +11 -1
  58. package/dist/usage-evidence.js +18 -86
  59. package/dist/workspace-origin.js +17 -0
  60. package/docs/APP_PACKAGE.md +4 -0
  61. package/docs/CONTRACT.md +68 -10
  62. package/docs/DSH_COMPATIBILITY.md +94 -0
  63. package/docs/DSH_INTEGRATION.md +41 -0
  64. package/docs/INSTALLATION_STATUS.md +96 -0
  65. package/docs/INSTALL_TARGET.md +130 -0
  66. package/docs/LIBRARY.md +44 -3
  67. package/docs/LICENSES.json +189 -61
  68. package/docs/PROVENANCE.json +53 -12
  69. package/docs/SECURITY.md +31 -0
  70. package/node_modules/@hanamesh/lib-provision/LICENSE +15 -0
  71. package/node_modules/@hanamesh/lib-provision/README.md +134 -0
  72. package/node_modules/@hanamesh/lib-provision/THIRD_PARTY_NOTICES.md +17 -0
  73. package/node_modules/@hanamesh/lib-provision/bin/hanamesh-provision.js +13 -0
  74. package/node_modules/@hanamesh/lib-provision/consistency.json +20 -0
  75. package/node_modules/@hanamesh/lib-provision/contract/CHANGELOG.md +5 -0
  76. package/node_modules/@hanamesh/lib-provision/contract/conformance.mjs +80 -0
  77. package/node_modules/@hanamesh/lib-provision/contract/fixtures/consumer.json +9 -0
  78. package/node_modules/@hanamesh/lib-provision/contract/fixtures/provider.json +11 -0
  79. package/node_modules/@hanamesh/lib-provision/contract/lib-provision.schema.json +47 -0
  80. package/node_modules/@hanamesh/lib-provision/package.json +50 -0
  81. package/package.json +81 -33
  82. package/schemas/catalog-provider-page.schema.json +4 -2
  83. package/schemas/catalog-source.schema.json +9 -7
  84. package/schemas/install-target.schema.json +298 -0
  85. package/dist/provision/LICENSE +0 -6
  86. package/dist/provision/THIRD_PARTY_NOTICES.md +0 -13
  87. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/archive.d.ts +0 -0
  88. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/archive.js +0 -0
  89. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/check.d.ts +0 -0
  90. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/check.js +0 -0
  91. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/checkpoints.d.ts +0 -0
  92. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/checkpoints.js +0 -0
  93. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/cli.d.ts +0 -0
  94. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/cli.js +0 -0
  95. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/download.d.ts +0 -0
  96. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/download.js +0 -0
  97. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/errors.d.ts +0 -0
  98. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/errors.js +0 -0
  99. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/extract.d.ts +0 -0
  100. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/extract.js +0 -0
  101. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/fsutil.d.ts +0 -0
  102. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/fsutil.js +0 -0
  103. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/index.d.ts +0 -0
  104. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/index.js +0 -0
  105. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/ledger.d.ts +0 -0
  106. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/ledger.js +0 -0
  107. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/manifest.d.ts +0 -0
  108. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/manifest.js +0 -0
  109. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/paths.d.ts +0 -0
  110. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/paths.js +0 -0
  111. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/platform.d.ts +0 -0
  112. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/platform.js +0 -0
  113. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/provision.d.ts +0 -0
  114. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/provision.js +0 -0
  115. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/tar.d.ts +0 -0
  116. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/tar.js +0 -0
  117. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/types.d.ts +0 -0
  118. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/types.js +0 -0
  119. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/zip.d.ts +0 -0
  120. /package/{dist/provision → node_modules/@hanamesh/lib-provision/lib}/zip.js +0 -0
@@ -0,0 +1,58 @@
1
+ {
2
+ "contract": "hanamesh.install-target",
3
+ "contractVersion": "1",
4
+ "since": "0.2.0-rc.10",
5
+ "evidence": "SOURCE",
6
+ "label": "SOURCE fixture: the official dsh plugin command and lib-provision are stand-ins on a temporary profile; these results never stand for a real installation or a REAL_UI product gate.",
7
+ "application": {
8
+ "itemId": "fixture.install-target.app",
9
+ "packageName": "@hanamesh-fixture/install-target-app",
10
+ "appId": "fixture-app",
11
+ "previous": "0.3.0",
12
+ "latest": "0.4.0"
13
+ },
14
+ "plugin": {
15
+ "itemId": "fixture.install-target.plugin",
16
+ "packageName": "@hanamesh-fixture/install-target-plugin",
17
+ "latest": "1.2.3"
18
+ },
19
+ "cases": [
20
+ { "id": "RB01", "mode": "new-install", "stage": "before-add", "note": "registry lookup fails before the profile is touched", "registryMissing": true,
21
+ "expect": { "code": "REGISTRY_LOOKUP_FAILED", "status": "not-needed", "actions": [] } },
22
+ { "id": "RB02", "mode": "new-install", "stage": "add", "note": "official CLI fails before writing", "inject": [["add", "before"]],
23
+ "expect": { "code": "DSH_PLUGIN_FAILED", "status": "not-needed", "actions": [] } },
24
+ { "id": "RB03", "mode": "new-install", "stage": "add", "note": "official CLI fails after writing package/lock/module", "inject": [["add", "after"]],
25
+ "expect": { "code": "DSH_PLUGIN_FAILED", "status": "restored", "actions": ["dsh plugin remove $package"] } },
26
+ { "id": "RB04", "mode": "new-install", "stage": "definition", "note": "add succeeded, application definition is invalid", "invalidDefinition": true,
27
+ "expect": { "code": "INVALID_DEFINITION", "status": "restored", "actions": ["dsh plugin remove $package"] } },
28
+ { "id": "RB05", "mode": "new-install", "stage": "provision", "note": "provision fails before promote (runtime untouched)", "inject": [["provision", "before"]],
29
+ "expect": { "code": "E_DOWNLOAD", "status": "restored", "actions": ["dsh plugin remove $package"] } },
30
+ { "id": "RB06", "mode": "new-install", "stage": "provision", "note": "provision fails after promoting a newly claimed runtime item", "inject": [["provision", "after"]],
31
+ "expect": { "code": "E_VERIFY", "status": "restored", "actions": ["dsh plugin remove $package", "provision remove runtime"] } },
32
+ { "id": "RB07", "mode": "upgrade", "stage": "before-add", "note": "upgrade: registry lookup fails before the profile is touched", "registryMissing": true,
33
+ "expect": { "code": "REGISTRY_LOOKUP_FAILED", "status": "not-needed", "actions": [] } },
34
+ { "id": "RB08", "mode": "upgrade", "stage": "add", "note": "upgrade: official CLI fails after writing the new version", "inject": [["add", "after"]],
35
+ "expect": { "code": "DSH_PLUGIN_FAILED", "status": "restored", "actions": ["dsh plugin add --save-exact $package@$previous"] } },
36
+ { "id": "RB09", "mode": "upgrade", "stage": "definition", "note": "upgrade: new definition is invalid; original exact version comes back", "invalidDefinition": true,
37
+ "expect": { "code": "INVALID_DEFINITION", "status": "restored", "actions": ["dsh plugin add --save-exact $package@$previous"] } },
38
+ { "id": "RB10", "mode": "upgrade", "stage": "provision", "note": "upgrade: new runtime promoted then failed; original runtime is provisioned again from the restored definition", "inject": [["provision", "after"]],
39
+ "expect": { "code": "E_VERIFY", "status": "restored", "actions": ["dsh plugin add --save-exact $package@$previous", "provision runtime"] } },
40
+ { "id": "RB11", "mode": "new-install", "stage": "definition", "note": "compensation itself fails: the original error is kept and the residue is reported", "invalidDefinition": true, "inject": [["remove", "before"]],
41
+ "expect": { "code": "INVALID_DEFINITION", "status": "failed", "recoveryError": "DSH_PLUGIN_FAILED", "actions": ["dsh plugin remove $package"], "residue": ["dependency", "module", "lockfile"] } },
42
+ { "id": "RB12", "mode": "upgrade", "stage": "provision", "note": "upgrade compensation fails: original version cannot be added back", "inject": [["provision", "after"], ["add", "before", 1]],
43
+ "expect": { "code": "E_VERIFY", "status": "failed", "recoveryError": "DSH_PLUGIN_FAILED", "actions": ["dsh plugin add --save-exact $package@$previous"], "residue": ["dependency", "module", "lockfile", "runtime:runtime"] } },
44
+ { "id": "RB13", "mode": "new-install", "stage": "definition", "note": "a concurrent profile writer is never undone; the lockfile cannot be proven restored", "invalidDefinition": true, "concurrent": true,
45
+ "expect": { "code": "INVALID_DEFINITION", "status": "failed", "actions": ["dsh plugin remove $package"], "residue": ["lockfile"] } },
46
+ { "id": "RB14", "mode": "new-install", "stage": "provision", "note": "unowned files in a newly claimed runtime are kept and reported, not deleted", "inject": [["provision", "unowned"], ["provision", "after"]],
47
+ "expect": { "code": "E_VERIFY", "status": "failed", "actions": ["dsh plugin remove $package", "provision remove runtime"], "residue": ["runtime:runtime"] } },
48
+ { "id": "RB15", "mode": "new-install", "stage": "add", "kind": "plugin", "note": "plugin bundle: CLI fails after selecting the bundle; selection and lock come back", "inject": [["add", "after"]],
49
+ "expect": { "code": "DSH_PLUGIN_FAILED", "status": "restored", "actions": ["dsh plugin remove $package"] } }
50
+ ],
51
+ "presentation": [
52
+ { "id": "RP01", "note": "restored new install is a failure that left nothing behind", "recovery": { "status": "restored", "mode": "new-install", "stage": "definition", "previousVersion": null, "actions": ["dsh plugin remove @hanamesh-fixture/install-target-app"], "checks": [], "residue": [] }, "expect": { "installed": false, "restored": true } },
53
+ { "id": "RP02", "note": "restored upgrade names the original version", "recovery": { "status": "restored", "mode": "upgrade", "stage": "provision", "previousVersion": "0.3.0", "actions": [], "checks": [], "residue": [] }, "expect": { "installed": false, "restored": true, "version": "0.3.0" } },
54
+ { "id": "RP03", "note": "nothing was changed before the failure", "recovery": { "status": "not-needed", "mode": "new-install", "stage": "before-add", "previousVersion": null, "actions": [], "checks": [], "residue": [] }, "expect": { "installed": false, "restored": true } },
55
+ { "id": "RP04", "note": "compensation failed: never shown as success or as rolled back", "recovery": { "status": "failed", "mode": "upgrade", "stage": "provision", "previousVersion": "0.3.0", "actions": [], "checks": [], "residue": [{ "item": "module", "reason": "NOT_RESTORED" }], "error": { "code": "DSH_PLUGIN_FAILED" }, "originals": { "dir": "/data/library-recovery/op", "files": ["package.json"] } }, "expect": { "installed": false, "restored": false, "residue": ["module"] } },
56
+ { "id": "RP05", "note": "an rc.9 provider sends no recovery: unknown, not restored", "recovery": null, "expect": { "installed": false, "restored": false } }
57
+ ]
58
+ }
@@ -0,0 +1,618 @@
1
+ {
2
+ "contract": "hanamesh.install-target",
3
+ "contractVersion": "1",
4
+ "catalog": "./catalog.json",
5
+ "targets": [
6
+ {
7
+ "id": "PV01",
8
+ "semantic": "public",
9
+ "note": "package name resolves through the market's own catalog",
10
+ "input": {
11
+ "packageName": "@hanamesh-fixture/install-target-plugin"
12
+ },
13
+ "expect": {
14
+ "status": "confirmation-required",
15
+ "itemId": "fixture.install-target.plugin",
16
+ "packageName": "@hanamesh-fixture/install-target-plugin"
17
+ }
18
+ },
19
+ {
20
+ "id": "PV02",
21
+ "semantic": "public",
22
+ "note": "catalog item id resolves",
23
+ "input": {
24
+ "itemId": "fixture.install-target.plugin"
25
+ },
26
+ "expect": {
27
+ "status": "confirmation-required",
28
+ "itemId": "fixture.install-target.plugin",
29
+ "packageName": "@hanamesh-fixture/install-target-plugin"
30
+ }
31
+ },
32
+ {
33
+ "id": "PV03",
34
+ "semantic": "public",
35
+ "note": "matching pair resolves",
36
+ "input": {
37
+ "itemId": "fixture.install-target.app",
38
+ "packageName": "@hanamesh-fixture/install-target-app"
39
+ },
40
+ "expect": {
41
+ "status": "confirmation-required",
42
+ "itemId": "fixture.install-target.app",
43
+ "packageName": "@hanamesh-fixture/install-target-app"
44
+ }
45
+ },
46
+ {
47
+ "id": "PV04",
48
+ "semantic": "version-match",
49
+ "note": "declared contract version 1 is accepted and changes nothing else",
50
+ "input": {
51
+ "packageName": "@hanamesh-fixture/install-target-plugin",
52
+ "contractVersion": "1"
53
+ },
54
+ "expect": {
55
+ "status": "confirmation-required",
56
+ "itemId": "fixture.install-target.plugin",
57
+ "packageName": "@hanamesh-fixture/install-target-plugin"
58
+ }
59
+ },
60
+ {
61
+ "id": "PV05",
62
+ "semantic": "version-mismatch",
63
+ "note": "unsupported declaration is refused explicitly",
64
+ "input": {
65
+ "packageName": "@hanamesh-fixture/install-target-plugin",
66
+ "contractVersion": "2"
67
+ },
68
+ "expect": {
69
+ "error": "CONTRACT_VERSION_UNSUPPORTED",
70
+ "http": 400
71
+ }
72
+ },
73
+ {
74
+ "id": "PV06",
75
+ "semantic": "version-mismatch",
76
+ "note": "a newer caller's extra fields are refused as a version mismatch, not silently accepted",
77
+ "input": {
78
+ "packageName": "@hanamesh-fixture/install-target-plugin",
79
+ "contractVersion": "2",
80
+ "channel": "beta"
81
+ },
82
+ "expect": {
83
+ "error": "CONTRACT_VERSION_UNSUPPORTED",
84
+ "http": 400
85
+ }
86
+ },
87
+ {
88
+ "id": "PV07",
89
+ "semantic": "version-mismatch",
90
+ "note": "empty declaration is not treated as absent",
91
+ "input": {
92
+ "packageName": "@hanamesh-fixture/install-target-plugin",
93
+ "contractVersion": ""
94
+ },
95
+ "expect": {
96
+ "error": "CONTRACT_VERSION_UNSUPPORTED",
97
+ "http": 400
98
+ }
99
+ },
100
+ {
101
+ "id": "PV08",
102
+ "semantic": "invalid",
103
+ "note": "no identifier",
104
+ "input": {},
105
+ "expect": {
106
+ "error": "INVALID_INPUT",
107
+ "http": 400
108
+ }
109
+ },
110
+ {
111
+ "id": "PV09",
112
+ "semantic": "invalid",
113
+ "note": "caller-supplied version is refused",
114
+ "input": {
115
+ "packageName": "@hanamesh-fixture/install-target-plugin",
116
+ "version": "9.0.0"
117
+ },
118
+ "expect": {
119
+ "error": "INVALID_INPUT",
120
+ "http": 400
121
+ }
122
+ },
123
+ {
124
+ "id": "PV10",
125
+ "semantic": "invalid",
126
+ "note": "caller-supplied download location is refused",
127
+ "input": {
128
+ "itemId": "fixture.install-target.plugin",
129
+ "url": "https://evil.example/pkg.tgz"
130
+ },
131
+ "expect": {
132
+ "error": "INVALID_INPUT",
133
+ "http": 400
134
+ }
135
+ },
136
+ {
137
+ "id": "PV11",
138
+ "semantic": "invalid",
139
+ "note": "package name grammar",
140
+ "input": {
141
+ "packageName": "../escape"
142
+ },
143
+ "expect": {
144
+ "error": "INVALID_INPUT",
145
+ "http": 400
146
+ }
147
+ },
148
+ {
149
+ "id": "PV12",
150
+ "semantic": "invalid",
151
+ "note": "item id longer than 160",
152
+ "input": {
153
+ "itemId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
154
+ },
155
+ "expect": {
156
+ "error": "INVALID_INPUT",
157
+ "http": 400
158
+ }
159
+ },
160
+ {
161
+ "id": "PV13",
162
+ "semantic": "invalid",
163
+ "note": "control character in item id",
164
+ "input": {
165
+ "itemId": "fixture\u0007id"
166
+ },
167
+ "expect": {
168
+ "error": "INVALID_INPUT",
169
+ "http": 400
170
+ }
171
+ },
172
+ {
173
+ "id": "PV14",
174
+ "semantic": "missing-catalog",
175
+ "note": "identifier absent from the catalog",
176
+ "input": {
177
+ "packageName": "@hanamesh-fixture/not-in-catalog"
178
+ },
179
+ "expect": {
180
+ "error": "CATALOG_ITEM_MISSING",
181
+ "http": 404
182
+ }
183
+ },
184
+ {
185
+ "id": "PV15",
186
+ "semantic": "missing-catalog",
187
+ "note": "identifiers naming two different items",
188
+ "input": {
189
+ "itemId": "fixture.install-target.plugin",
190
+ "packageName": "@hanamesh-fixture/install-target-app"
191
+ },
192
+ "expect": {
193
+ "error": "CATALOG_ITEM_MISSING",
194
+ "http": 404
195
+ }
196
+ },
197
+ {
198
+ "id": "PV16",
199
+ "semantic": "invalid",
200
+ "note": "catalog entry that is not an npm package",
201
+ "input": {
202
+ "itemId": "fixture.install-target.repository-only"
203
+ },
204
+ "expect": {
205
+ "error": "NOT_INSTALLABLE",
206
+ "http": 400
207
+ }
208
+ }
209
+ ],
210
+ "fragments": [
211
+ {
212
+ "id": "PF01",
213
+ "semantic": "public",
214
+ "note": "legacy fragment without declaration",
215
+ "fragment": "#hanamesh-install?packageName=%40hanamesh-fixture%2Finstall-target-plugin",
216
+ "expect": {
217
+ "status": "confirmation-required",
218
+ "itemId": "fixture.install-target.plugin"
219
+ }
220
+ },
221
+ {
222
+ "id": "PF02",
223
+ "semantic": "version-match",
224
+ "note": "declared v1 fragment",
225
+ "fragment": "#hanamesh-install?itemId=fixture.install-target.plugin&packageName=%40hanamesh-fixture%2Finstall-target-plugin&contractVersion=1",
226
+ "expect": {
227
+ "status": "confirmation-required",
228
+ "itemId": "fixture.install-target.plugin"
229
+ }
230
+ },
231
+ {
232
+ "id": "PF03",
233
+ "semantic": "version-mismatch",
234
+ "note": "unsupported declaration",
235
+ "fragment": "#hanamesh-install?packageName=%40hanamesh-fixture%2Finstall-target-plugin&contractVersion=2",
236
+ "expect": {
237
+ "status": "failed",
238
+ "error": "CONTRACT_VERSION_UNSUPPORTED"
239
+ }
240
+ },
241
+ {
242
+ "id": "PF04",
243
+ "semantic": "invalid",
244
+ "note": "duplicate field",
245
+ "fragment": "#hanamesh-install?packageName=%40hanamesh-fixture%2Finstall-target-plugin&packageName=evil",
246
+ "expect": {
247
+ "status": "failed",
248
+ "error": "INVALID_INPUT"
249
+ }
250
+ },
251
+ {
252
+ "id": "PF05",
253
+ "semantic": "invalid",
254
+ "note": "extra download location",
255
+ "fragment": "#hanamesh-install?packageName=%40hanamesh-fixture%2Finstall-target-plugin&url=https%3A%2F%2Fevil.example",
256
+ "expect": {
257
+ "status": "failed",
258
+ "error": "INVALID_INPUT"
259
+ }
260
+ },
261
+ {
262
+ "id": "PF06",
263
+ "semantic": "missing-catalog",
264
+ "note": "identifier absent from the catalog",
265
+ "fragment": "#hanamesh-install?packageName=%40hanamesh-fixture%2Fnot-in-catalog",
266
+ "expect": {
267
+ "status": "failed",
268
+ "error": "CATALOG_ITEM_MISSING"
269
+ }
270
+ }
271
+ ],
272
+ "loopback": {
273
+ "aliases": [
274
+ "127.0.0.1",
275
+ "localhost"
276
+ ],
277
+ "cases": [
278
+ {
279
+ "id": "LB01",
280
+ "method": "GET",
281
+ "headers": {},
282
+ "input": {
283
+ "packageName": "@hanamesh-fixture/install-target-plugin",
284
+ "contractVersion": "1"
285
+ },
286
+ "expect": {
287
+ "http": 200
288
+ },
289
+ "note": "authenticated resolution without Origin"
290
+ },
291
+ {
292
+ "id": "LB02",
293
+ "method": "GET",
294
+ "headers": {
295
+ "origin": "$origin"
296
+ },
297
+ "input": {
298
+ "packageName": "@hanamesh-fixture/install-target-plugin",
299
+ "contractVersion": "1"
300
+ },
301
+ "expect": {
302
+ "http": 200
303
+ },
304
+ "note": "authenticated same-origin resolution"
305
+ },
306
+ {
307
+ "id": "LB03",
308
+ "method": "GET",
309
+ "headers": {
310
+ "host": "unknown.example:$port"
311
+ },
312
+ "input": {
313
+ "packageName": "@hanamesh-fixture/install-target-plugin",
314
+ "contractVersion": "1"
315
+ },
316
+ "expect": {
317
+ "http": 403,
318
+ "error": "HOST_DENIED"
319
+ },
320
+ "note": "unknown Host"
321
+ },
322
+ {
323
+ "id": "LB04",
324
+ "method": "GET",
325
+ "headers": {
326
+ "host": "$hostname:$otherPort"
327
+ },
328
+ "input": {
329
+ "packageName": "@hanamesh-fixture/install-target-plugin",
330
+ "contractVersion": "1"
331
+ },
332
+ "expect": {
333
+ "http": 403,
334
+ "error": "HOST_DENIED"
335
+ },
336
+ "note": "different Host port"
337
+ },
338
+ {
339
+ "id": "LB05",
340
+ "method": "GET",
341
+ "headers": {
342
+ "origin": "$otherOrigin"
343
+ },
344
+ "input": {
345
+ "packageName": "@hanamesh-fixture/install-target-plugin",
346
+ "contractVersion": "1"
347
+ },
348
+ "expect": {
349
+ "http": 403,
350
+ "error": "ORIGIN_DENIED"
351
+ },
352
+ "note": "the other alias remains a different browser origin"
353
+ },
354
+ {
355
+ "id": "LB06",
356
+ "method": "GET",
357
+ "headers": {
358
+ "origin": "http://$hostname:$otherPort"
359
+ },
360
+ "input": {
361
+ "packageName": "@hanamesh-fixture/install-target-plugin",
362
+ "contractVersion": "1"
363
+ },
364
+ "expect": {
365
+ "http": 403,
366
+ "error": "ORIGIN_DENIED"
367
+ },
368
+ "note": "different Origin port"
369
+ },
370
+ {
371
+ "id": "LB07",
372
+ "method": "GET",
373
+ "headers": {
374
+ "origin": "https://foreign.example"
375
+ },
376
+ "input": {
377
+ "packageName": "@hanamesh-fixture/install-target-plugin",
378
+ "contractVersion": "1"
379
+ },
380
+ "expect": {
381
+ "http": 403,
382
+ "error": "ORIGIN_DENIED"
383
+ },
384
+ "note": "foreign Origin"
385
+ },
386
+ {
387
+ "id": "LB08",
388
+ "method": "GET",
389
+ "headers": {
390
+ "sec-fetch-dest": "iframe"
391
+ },
392
+ "input": {
393
+ "packageName": "@hanamesh-fixture/install-target-plugin",
394
+ "contractVersion": "1"
395
+ },
396
+ "expect": {
397
+ "http": 403,
398
+ "error": "FRAME_CONTROL_DENIED"
399
+ },
400
+ "note": "iframe"
401
+ },
402
+ {
403
+ "id": "LB09",
404
+ "method": "GET",
405
+ "headers": {
406
+ "x-install-target-suite": "wrong"
407
+ },
408
+ "input": {
409
+ "packageName": "@hanamesh-fixture/install-target-plugin",
410
+ "contractVersion": "1"
411
+ },
412
+ "expect": {
413
+ "http": 401,
414
+ "error": "UNAUTHENTICATED"
415
+ },
416
+ "note": "missing authentication"
417
+ },
418
+ {
419
+ "id": "LB10",
420
+ "method": "POST",
421
+ "headers": {
422
+ "origin": "$origin"
423
+ },
424
+ "input": {
425
+ "packageName": "@hanamesh-fixture/install-target-plugin",
426
+ "contractVersion": "1"
427
+ },
428
+ "expect": {
429
+ "http": 403,
430
+ "error": "CSRF_DENIED"
431
+ },
432
+ "note": "missing explicit client header"
433
+ },
434
+ {
435
+ "id": "LB11",
436
+ "method": "POST",
437
+ "headers": {
438
+ "x-hanamesh-client": "workspace-v1"
439
+ },
440
+ "input": {
441
+ "packageName": "@hanamesh-fixture/install-target-plugin",
442
+ "contractVersion": "1"
443
+ },
444
+ "expect": {
445
+ "http": 403,
446
+ "error": "CSRF_DENIED"
447
+ },
448
+ "note": "missing Origin"
449
+ },
450
+ {
451
+ "id": "LB12",
452
+ "method": "POST",
453
+ "headers": {
454
+ "origin": "$otherOrigin",
455
+ "x-hanamesh-client": "workspace-v1"
456
+ },
457
+ "input": {
458
+ "packageName": "@hanamesh-fixture/install-target-plugin",
459
+ "contractVersion": "1"
460
+ },
461
+ "expect": {
462
+ "http": 403,
463
+ "error": "ORIGIN_DENIED"
464
+ },
465
+ "note": "cross-alias install"
466
+ },
467
+ {
468
+ "id": "LB13",
469
+ "method": "POST",
470
+ "headers": {
471
+ "origin": "$origin",
472
+ "x-hanamesh-client": "workspace-v1",
473
+ "sec-fetch-dest": "iframe"
474
+ },
475
+ "input": {
476
+ "packageName": "@hanamesh-fixture/install-target-plugin",
477
+ "contractVersion": "1"
478
+ },
479
+ "expect": {
480
+ "http": 403,
481
+ "error": "FRAME_CONTROL_DENIED"
482
+ },
483
+ "note": "iframe install"
484
+ },
485
+ {
486
+ "id": "LB14",
487
+ "method": "POST",
488
+ "headers": {
489
+ "origin": "$origin",
490
+ "x-hanamesh-client": "workspace-v1",
491
+ "x-install-target-suite": "wrong"
492
+ },
493
+ "input": {
494
+ "packageName": "@hanamesh-fixture/install-target-plugin",
495
+ "contractVersion": "1"
496
+ },
497
+ "expect": {
498
+ "http": 401,
499
+ "error": "UNAUTHENTICATED"
500
+ },
501
+ "note": "unauthenticated install"
502
+ },
503
+ {
504
+ "id": "LB15",
505
+ "method": "POST",
506
+ "headers": {
507
+ "origin": "$origin",
508
+ "x-hanamesh-client": "workspace-v1"
509
+ },
510
+ "input": {
511
+ "packageName": "@hanamesh-fixture/install-target-plugin",
512
+ "contractVersion": "2"
513
+ },
514
+ "expect": {
515
+ "http": 400,
516
+ "error": "CONTRACT_VERSION_UNSUPPORTED"
517
+ },
518
+ "note": "unsupported install version"
519
+ },
520
+ {
521
+ "id": "LB16",
522
+ "method": "GET",
523
+ "headers": {
524
+ "origin": "null"
525
+ },
526
+ "input": {
527
+ "packageName": "@hanamesh-fixture/install-target-plugin",
528
+ "contractVersion": "1"
529
+ },
530
+ "expect": {
531
+ "http": 403,
532
+ "error": "ORIGIN_DENIED"
533
+ },
534
+ "note": "opaque Origin"
535
+ },
536
+ {
537
+ "id": "LB17",
538
+ "method": "GET",
539
+ "headers": {
540
+ "host": "localhost.:$port"
541
+ },
542
+ "input": {
543
+ "packageName": "@hanamesh-fixture/install-target-plugin",
544
+ "contractVersion": "1"
545
+ },
546
+ "expect": {
547
+ "http": 403,
548
+ "error": "HOST_DENIED"
549
+ },
550
+ "note": "unlisted localhost spelling"
551
+ },
552
+ {
553
+ "id": "LB18",
554
+ "method": "GET",
555
+ "headers": {
556
+ "host": "[::1]:$port"
557
+ },
558
+ "input": {
559
+ "packageName": "@hanamesh-fixture/install-target-plugin",
560
+ "contractVersion": "1"
561
+ },
562
+ "expect": {
563
+ "http": 403,
564
+ "error": "HOST_DENIED"
565
+ },
566
+ "note": "unlisted IPv6 Host"
567
+ },
568
+ {
569
+ "id": "LB19",
570
+ "method": "POST",
571
+ "headers": {
572
+ "origin": "https://$hostname:$port",
573
+ "x-hanamesh-client": "workspace-v1"
574
+ },
575
+ "input": {
576
+ "packageName": "@hanamesh-fixture/install-target-plugin",
577
+ "contractVersion": "1"
578
+ },
579
+ "expect": {
580
+ "http": 403,
581
+ "error": "ORIGIN_DENIED"
582
+ },
583
+ "note": "different Origin scheme"
584
+ },
585
+ {
586
+ "id": "LB20",
587
+ "method": "GET",
588
+ "headers": {},
589
+ "input": {
590
+ "packageName": "@hanamesh-fixture/install-target-plugin",
591
+ "contractVersion": "2"
592
+ },
593
+ "expect": {
594
+ "http": 400,
595
+ "error": "CONTRACT_VERSION_UNSUPPORTED"
596
+ },
597
+ "note": "unsupported resolve version"
598
+ },
599
+ {
600
+ "id": "LB21",
601
+ "method": "POST",
602
+ "headers": {
603
+ "origin": "$origin",
604
+ "x-hanamesh-client": "workspace-v1"
605
+ },
606
+ "input": {
607
+ "packageName": "@hanamesh-fixture/forbidden",
608
+ "contractVersion": "1"
609
+ },
610
+ "expect": {
611
+ "http": 403,
612
+ "error": "FORBIDDEN"
613
+ },
614
+ "note": "unauthorized installation"
615
+ }
616
+ ]
617
+ }
618
+ }