@launchfile/macos-dev 0.7.0 → 0.8.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/dist/provider.d.ts +42 -0
- package/dist/provider.js +113 -1
- package/package.json +2 -2
package/dist/provider.d.ts
CHANGED
|
@@ -67,6 +67,48 @@ export declare function scheduleWarning(component: string, schedule: string): st
|
|
|
67
67
|
* report success over an empty set.
|
|
68
68
|
*/
|
|
69
69
|
export declare function applyHostCapabilityRefusals(launch: NormalizedLaunch): "ok" | "none-left";
|
|
70
|
+
/**
|
|
71
|
+
* Components this provider must refuse because they require a public HTTPS
|
|
72
|
+
* origin (D-60 rule 5), mapped to the entries it cannot satisfy.
|
|
73
|
+
*
|
|
74
|
+
* This provider has no orchestrator-facing publication channel ([#294]) and no
|
|
75
|
+
* edge of its own, so it can neither provision the origin nor accept a supplied
|
|
76
|
+
* one — it refuses, which PROVIDERS.md §10 item 5 makes conformant. `supports:`
|
|
77
|
+
* entries are not refused: the component runs, degraded.
|
|
78
|
+
*/
|
|
79
|
+
export declare function refusedHttpsOrigins(launch: NormalizedLaunch): Map<string, string[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Remove every component whose required `https-origin` this provider cannot
|
|
82
|
+
* satisfy, and say so on stderr. Same shape and same reason as
|
|
83
|
+
* {@link applyHostCapabilityRefusals}: the removal IS the refusal — a component
|
|
84
|
+
* left in the map goes on to be installed, wired, registered and started, and
|
|
85
|
+
* an app that declared it needs HTTPS would run over plain HTTP behind a
|
|
86
|
+
* message nobody acted on.
|
|
87
|
+
*/
|
|
88
|
+
export declare function applyHttpsOriginRefusals(launch: NormalizedLaunch): "ok" | "none-left";
|
|
89
|
+
/**
|
|
90
|
+
* Components this provider must refuse because native TLS was selected on a
|
|
91
|
+
* listener it cannot activate (D-61 rule 5), mapped to the entries.
|
|
92
|
+
*
|
|
93
|
+
* Selection on this provider is `--with-optional`: it is the only way a
|
|
94
|
+
* `supports:` entry is ever turned on here. Without the flag a certificate
|
|
95
|
+
* binding is simply inactive and the component runs its declared HTTP
|
|
96
|
+
* baseline, which is correct (D-8) — so this returns nothing.
|
|
97
|
+
*
|
|
98
|
+
* With the flag, the operator asked for the optional capability and this
|
|
99
|
+
* provider has no way to deliver it: it has no supplied-resource channel to
|
|
100
|
+
* receive `cert_file`/`key_file` through, and no certificate of its own to
|
|
101
|
+
* offer. Refusing is what PROVIDERS.md §10 item 5 makes conformant; falling
|
|
102
|
+
* back to HTTP on a listener the operator asked to secure is the silent
|
|
103
|
+
* success the decision forbids.
|
|
104
|
+
*/
|
|
105
|
+
export declare function refusedCertificates(launch: NormalizedLaunch, withOptional: boolean): Map<string, string[]>;
|
|
106
|
+
/**
|
|
107
|
+
* Remove every component whose selected certificate binding this provider
|
|
108
|
+
* cannot activate, and say so on stderr. Same shape and same reason as
|
|
109
|
+
* {@link applyHostCapabilityRefusals}: the removal IS the refusal.
|
|
110
|
+
*/
|
|
111
|
+
export declare function applyCertificateRefusals(launch: NormalizedLaunch, withOptional: boolean): "ok" | "none-left";
|
|
70
112
|
export declare function launchUp(opts?: LaunchUpOpts): Promise<void>;
|
|
71
113
|
export declare function launchDown(opts?: {
|
|
72
114
|
destroy?: boolean;
|
package/dist/provider.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { accessSync, constants as fsConstants } from "node:fs";
|
|
8
8
|
import { readFile } from "node:fs/promises";
|
|
9
9
|
import { join, resolve as resolvePath } from "node:path";
|
|
10
|
-
import { indexOperatorStoragePaths, MissingOperatorStoragePathError, readLaunch, resolveSourcePrepareCommand, resolveSourceRunCommand, selectionClosure, UnboundOperatorStorageError, unsuppliedRequiredEnv, } from "@launchfile/sdk";
|
|
10
|
+
import { CERTIFICATE, certificateBindings, indexOperatorStoragePaths, MissingOperatorStoragePathError, readLaunch, resolveSourcePrepareCommand, resolveSourceRunCommand, selectionClosure, UnboundOperatorStorageError, unsuppliedRequiredEnv, } from "@launchfile/sdk";
|
|
11
11
|
import { checkPrereqs } from "./prereqs.js";
|
|
12
12
|
import { loadState, initState, saveState, ensureDirs } from "./state.js";
|
|
13
13
|
import { buildResolverContext, computeAppProperties, resolveComponentEnv, generateSecrets, resolveGenerators, writeEnvFile, } from "./env-writer.js";
|
|
@@ -121,6 +121,96 @@ export function applyHostCapabilityRefusals(launch) {
|
|
|
121
121
|
launch.components = Object.fromEntries(Object.entries(launch.components).filter(([n]) => !refused.has(n)));
|
|
122
122
|
return Object.keys(launch.components).length === 0 ? "none-left" : "ok";
|
|
123
123
|
}
|
|
124
|
+
/** The backing-service type that declares the app's public HTTPS origin (D-60). */
|
|
125
|
+
const HTTPS_ORIGIN = "https-origin";
|
|
126
|
+
/**
|
|
127
|
+
* Components this provider must refuse because they require a public HTTPS
|
|
128
|
+
* origin (D-60 rule 5), mapped to the entries it cannot satisfy.
|
|
129
|
+
*
|
|
130
|
+
* This provider has no orchestrator-facing publication channel ([#294]) and no
|
|
131
|
+
* edge of its own, so it can neither provision the origin nor accept a supplied
|
|
132
|
+
* one — it refuses, which PROVIDERS.md §10 item 5 makes conformant. `supports:`
|
|
133
|
+
* entries are not refused: the component runs, degraded.
|
|
134
|
+
*/
|
|
135
|
+
export function refusedHttpsOrigins(launch) {
|
|
136
|
+
const refused = new Map();
|
|
137
|
+
for (const [name, c] of Object.entries(launch.components)) {
|
|
138
|
+
const entries = (c.requires ?? [])
|
|
139
|
+
.filter((r) => r.type === HTTPS_ORIGIN)
|
|
140
|
+
.map((r) => `${r.name ?? r.type} (endpoint "${r.endpoint ?? "?"}")`);
|
|
141
|
+
if (entries.length > 0)
|
|
142
|
+
refused.set(name, entries);
|
|
143
|
+
}
|
|
144
|
+
return refused;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Remove every component whose required `https-origin` this provider cannot
|
|
148
|
+
* satisfy, and say so on stderr. Same shape and same reason as
|
|
149
|
+
* {@link applyHostCapabilityRefusals}: the removal IS the refusal — a component
|
|
150
|
+
* left in the map goes on to be installed, wired, registered and started, and
|
|
151
|
+
* an app that declared it needs HTTPS would run over plain HTTP behind a
|
|
152
|
+
* message nobody acted on.
|
|
153
|
+
*/
|
|
154
|
+
export function applyHttpsOriginRefusals(launch) {
|
|
155
|
+
const refused = refusedHttpsOrigins(launch);
|
|
156
|
+
for (const [name, entries] of refused) {
|
|
157
|
+
console.error(` Refused: ${name} requires a public HTTPS origin this provider cannot supply ` +
|
|
158
|
+
`(${entries.join("; ")}) — it has no edge and no publication channel — component not started`);
|
|
159
|
+
}
|
|
160
|
+
if (refused.size === 0)
|
|
161
|
+
return "ok";
|
|
162
|
+
launch.components = Object.fromEntries(Object.entries(launch.components).filter(([n]) => !refused.has(n)));
|
|
163
|
+
return Object.keys(launch.components).length === 0 ? "none-left" : "ok";
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Components this provider must refuse because native TLS was selected on a
|
|
167
|
+
* listener it cannot activate (D-61 rule 5), mapped to the entries.
|
|
168
|
+
*
|
|
169
|
+
* Selection on this provider is `--with-optional`: it is the only way a
|
|
170
|
+
* `supports:` entry is ever turned on here. Without the flag a certificate
|
|
171
|
+
* binding is simply inactive and the component runs its declared HTTP
|
|
172
|
+
* baseline, which is correct (D-8) — so this returns nothing.
|
|
173
|
+
*
|
|
174
|
+
* With the flag, the operator asked for the optional capability and this
|
|
175
|
+
* provider has no way to deliver it: it has no supplied-resource channel to
|
|
176
|
+
* receive `cert_file`/`key_file` through, and no certificate of its own to
|
|
177
|
+
* offer. Refusing is what PROVIDERS.md §10 item 5 makes conformant; falling
|
|
178
|
+
* back to HTTP on a listener the operator asked to secure is the silent
|
|
179
|
+
* success the decision forbids.
|
|
180
|
+
*/
|
|
181
|
+
export function refusedCertificates(launch, withOptional) {
|
|
182
|
+
const refused = new Map();
|
|
183
|
+
if (!withOptional)
|
|
184
|
+
return refused;
|
|
185
|
+
for (const [name, component] of Object.entries(launch.components)) {
|
|
186
|
+
const declared = new Set((component.supports ?? [])
|
|
187
|
+
.filter((s) => !s.host && s.type === CERTIFICATE)
|
|
188
|
+
.map((s) => s.name ?? s.type));
|
|
189
|
+
const entries = certificateBindings(component)
|
|
190
|
+
.filter(({ certificate }) => declared.has(certificate))
|
|
191
|
+
.map(({ entry, certificate }) => `${certificate} (endpoint ${entry.name === undefined ? "(unnamed)" : `"${entry.name}"`})`);
|
|
192
|
+
if (entries.length > 0)
|
|
193
|
+
refused.set(name, entries);
|
|
194
|
+
}
|
|
195
|
+
return refused;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Remove every component whose selected certificate binding this provider
|
|
199
|
+
* cannot activate, and say so on stderr. Same shape and same reason as
|
|
200
|
+
* {@link applyHostCapabilityRefusals}: the removal IS the refusal.
|
|
201
|
+
*/
|
|
202
|
+
export function applyCertificateRefusals(launch, withOptional) {
|
|
203
|
+
const refused = refusedCertificates(launch, withOptional);
|
|
204
|
+
for (const [name, entries] of refused) {
|
|
205
|
+
console.error(` Refused: ${name} selected native TLS and this provider cannot activate it ` +
|
|
206
|
+
`(${entries.join("; ")}) — it has no channel to receive cert_file/key_file — ` +
|
|
207
|
+
"component not started; it never falls back to HTTP");
|
|
208
|
+
}
|
|
209
|
+
if (refused.size === 0)
|
|
210
|
+
return "ok";
|
|
211
|
+
launch.components = Object.fromEntries(Object.entries(launch.components).filter(([n]) => !refused.has(n)));
|
|
212
|
+
return Object.keys(launch.components).length === 0 ? "none-left" : "ok";
|
|
213
|
+
}
|
|
124
214
|
export async function launchUp(opts = {}) {
|
|
125
215
|
const projectDir = opts.projectDir ?? process.cwd();
|
|
126
216
|
// 1. Check prerequisites
|
|
@@ -177,6 +267,22 @@ export async function launchUp(opts = {}) {
|
|
|
177
267
|
console.error("Every selected component requires a host capability this provider cannot grant.");
|
|
178
268
|
process.exit(1);
|
|
179
269
|
}
|
|
270
|
+
// 2a-bis. A required `https-origin` is refused for the same reason and in
|
|
271
|
+
// the same way (D-60 rule 5, PROVIDERS.md §10 item 5): this provider has
|
|
272
|
+
// no edge and no publication channel, so it cannot satisfy the entry, and
|
|
273
|
+
// starting the component anyway is the silent success the type removes.
|
|
274
|
+
if (applyHttpsOriginRefusals(launch) === "none-left") {
|
|
275
|
+
console.error("Every selected component requires a public HTTPS origin this provider cannot supply.");
|
|
276
|
+
process.exit(1);
|
|
277
|
+
}
|
|
278
|
+
// 2a-ter. A SELECTED certificate binding (`--with-optional`) is refused on
|
|
279
|
+
// the same grounds (D-61 rule 5): no channel to receive the material, so
|
|
280
|
+
// the listener the operator asked to secure would come up cleartext.
|
|
281
|
+
// Unselected, the binding is inactive and the baseline is correct (D-8).
|
|
282
|
+
if (applyCertificateRefusals(launch, opts.withOptional === true) === "none-left") {
|
|
283
|
+
console.error("Every selected component selected native TLS this provider cannot activate.");
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
180
286
|
// An optional capability is not refused — the component runs, degraded.
|
|
181
287
|
for (const [name, c] of Object.entries(launch.components)) {
|
|
182
288
|
for (const sup of c.supports ?? []) {
|
|
@@ -185,6 +291,12 @@ export async function launchUp(opts = {}) {
|
|
|
185
291
|
`${capability}=${String(value)} not granted — running degraded`);
|
|
186
292
|
}
|
|
187
293
|
}
|
|
294
|
+
for (const sup of c.supports ?? []) {
|
|
295
|
+
if (sup.type !== HTTPS_ORIGIN)
|
|
296
|
+
continue;
|
|
297
|
+
console.warn(` Warning: ${name}: optional public HTTPS origin ` +
|
|
298
|
+
`${sup.name ?? sup.type} (endpoint "${sup.endpoint ?? "?"}") not satisfied — running degraded`);
|
|
299
|
+
}
|
|
188
300
|
}
|
|
189
301
|
const componentNames = Object.keys(launch.components);
|
|
190
302
|
// 2b. Source-mode guard (D-38) — fail fast before provisioning anything.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@launchfile/macos-dev",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "macOS dev provider for Launchfile — run apps locally via brew services and native runtimes",
|
|
5
5
|
"os": [
|
|
6
6
|
"darwin"
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"directory": "providers/macos-dev"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@launchfile/sdk": "^0.
|
|
39
|
+
"@launchfile/sdk": "^0.8.0",
|
|
40
40
|
"semver": "^7.7.4"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|