@celilo/cli 0.13.0 → 0.13.2
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/package.json
CHANGED
|
@@ -74,6 +74,22 @@
|
|
|
74
74
|
"maximum": 4094,
|
|
75
75
|
"description": "VLAN tag for internal zone (not defaulted; internal is untagged)"
|
|
76
76
|
},
|
|
77
|
+
"network.secure-mgmt.subnet": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"pattern": "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}/\\d{1,2}$",
|
|
80
|
+
"description": "Control-plane subnet CIDR — the network celilo-mgr itself occupies when it does not sit on the internal LAN (not defaulted — discovered at celilo-mgmt install, or recorded by firewall onboarding). Derives the firewall's trusted sources and the internal resolver's split-horizon view for celilo's own traffic."
|
|
81
|
+
},
|
|
82
|
+
"network.secure-mgmt.gateway": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"pattern": "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$",
|
|
85
|
+
"description": "Control-plane gateway IP address (not defaulted — discovered from the default route)"
|
|
86
|
+
},
|
|
87
|
+
"network.secure-mgmt.vlan": {
|
|
88
|
+
"type": "integer",
|
|
89
|
+
"minimum": 1,
|
|
90
|
+
"maximum": 4094,
|
|
91
|
+
"description": "VLAN tag for the control-plane zone (not defaulted)"
|
|
92
|
+
},
|
|
77
93
|
"dns.primary": {
|
|
78
94
|
"type": "string",
|
|
79
95
|
"pattern": "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$",
|
|
@@ -152,4 +152,49 @@ describe('bumpUpdatesFor', () => {
|
|
|
152
152
|
'@celilo/event-bus',
|
|
153
153
|
]);
|
|
154
154
|
});
|
|
155
|
+
|
|
156
|
+
// #399: pins are now written during the version phase from WORKSPACE versions,
|
|
157
|
+
// which run ahead of npm until the publish lands. The publish-phase pass still
|
|
158
|
+
// reads npm-latest, so without a guard it would walk those pins BACKWARDS and
|
|
159
|
+
// ship modules bundling the previous capability code — the exact bundle/repo
|
|
160
|
+
// drift ISS-0104 exists to prevent.
|
|
161
|
+
describe('never downgrades a pin', () => {
|
|
162
|
+
test('an older npm-latest leaves a newer workspace pin alone', () => {
|
|
163
|
+
const pkg: PackageJson = { dependencies: { '@celilo/capabilities': '^0.7.1' } };
|
|
164
|
+
expect(bumpUpdatesFor(pkg, latest({ '@celilo/capabilities': '0.7.0' }))).toEqual([]);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
test('across a minor and a major', () => {
|
|
168
|
+
expect(
|
|
169
|
+
bumpUpdatesFor(
|
|
170
|
+
{ dependencies: { '@celilo/cli': '^0.13.0' } },
|
|
171
|
+
latest({ '@celilo/cli': '0.12.1' }),
|
|
172
|
+
),
|
|
173
|
+
).toEqual([]);
|
|
174
|
+
expect(
|
|
175
|
+
bumpUpdatesFor(
|
|
176
|
+
{ dependencies: { '@celilo/cli': '^1.0.0' } },
|
|
177
|
+
latest({ '@celilo/cli': '0.99.9' }),
|
|
178
|
+
),
|
|
179
|
+
).toEqual([]);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test('still bumps forward', () => {
|
|
183
|
+
const updates = bumpUpdatesFor(
|
|
184
|
+
{ dependencies: { '@celilo/capabilities': '^0.7.0' } },
|
|
185
|
+
latest({ '@celilo/capabilities': '0.7.1' }),
|
|
186
|
+
);
|
|
187
|
+
expect(updates).toHaveLength(1);
|
|
188
|
+
expect(updates[0].newSpec).toBe('^0.7.1');
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
test('a prerelease suffix does not confuse the comparison', () => {
|
|
192
|
+
expect(
|
|
193
|
+
bumpUpdatesFor(
|
|
194
|
+
{ dependencies: { '@celilo/cli': '^0.13.0' } },
|
|
195
|
+
latest({ '@celilo/cli': '0.12.1-alpha.3' }),
|
|
196
|
+
),
|
|
197
|
+
).toEqual([]);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
155
200
|
});
|
|
@@ -32,8 +32,8 @@ import type { ConsumerPinItem, PackageJson } from './types';
|
|
|
32
32
|
* to current npm-latest. Returns the file paths + per-bucket update
|
|
33
33
|
* lists; doesn't write anything.
|
|
34
34
|
*/
|
|
35
|
-
export function planConsumerPins(): ConsumerPinItem[] {
|
|
36
|
-
const latestMap = fetchLatestVersions();
|
|
35
|
+
export function planConsumerPins(versions?: Map<string, string>): ConsumerPinItem[] {
|
|
36
|
+
const latestMap = versions ?? fetchLatestVersions();
|
|
37
37
|
if (latestMap.size === 0) return [];
|
|
38
38
|
|
|
39
39
|
const externalPaths = readExternalProjectPaths();
|
|
@@ -68,6 +68,23 @@ export function planConsumerPins(): ConsumerPinItem[] {
|
|
|
68
68
|
* - deps already at the target bare version (operator-class match,
|
|
69
69
|
* `^1.0.0` and `1.0.0` both count as "at version 1.0.0").
|
|
70
70
|
*/
|
|
71
|
+
/**
|
|
72
|
+
* Compare `major.minor.patch`, ignoring any prerelease suffix. Returns
|
|
73
|
+
* -1 / 0 / 1. Deliberately tiny: pins only ever move between released
|
|
74
|
+
* `@celilo/*` versions, so full semver precedence is not needed.
|
|
75
|
+
*/
|
|
76
|
+
function compareVersions(a: string, b: string): number {
|
|
77
|
+
const parse = (v: string) => (v.split('-')[0] ?? '').split('.').map(Number);
|
|
78
|
+
const pa = parse(a);
|
|
79
|
+
const pb = parse(b);
|
|
80
|
+
for (let i = 0; i < 3; i++) {
|
|
81
|
+
const x = pa[i] ?? 0;
|
|
82
|
+
const y = pb[i] ?? 0;
|
|
83
|
+
if (x !== y) return x < y ? -1 : 1;
|
|
84
|
+
}
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
71
88
|
export function bumpUpdatesFor(
|
|
72
89
|
pkg: PackageJson,
|
|
73
90
|
published: Map<string, string>,
|
|
@@ -89,6 +106,12 @@ export function bumpUpdatesFor(
|
|
|
89
106
|
if (oldSpec.startsWith('workspace:')) continue;
|
|
90
107
|
if (/^[a-z]+:/.test(oldSpec) && !oldSpec.startsWith('npm:')) continue;
|
|
91
108
|
if (bareVersion(oldSpec) === newVersion) continue;
|
|
109
|
+
// Never walk a pin backwards. Pins are now written during the version
|
|
110
|
+
// phase from WORKSPACE versions, which are ahead of npm until the publish
|
|
111
|
+
// lands. Without this, the publish-phase pass — which still reads
|
|
112
|
+
// npm-latest — would "helpfully" downgrade every pin the version PR just
|
|
113
|
+
// set, and ship modules bundling the previous capability code.
|
|
114
|
+
if (compareVersions(newVersion, bareVersion(oldSpec)) < 0) continue;
|
|
92
115
|
const newSpec = withOperator(oldSpec, newVersion);
|
|
93
116
|
if (newSpec === oldSpec) continue;
|
|
94
117
|
updates.push({ bucket, depName: name, oldSpec, newSpec });
|
|
@@ -355,6 +355,8 @@ _celilo_system_config_keys() {
|
|
|
355
355
|
'network.secure.gateway:Secure gateway IP'
|
|
356
356
|
'network.internal.subnet:Internal subnet'
|
|
357
357
|
'network.internal.gateway:Internal gateway IP'
|
|
358
|
+
'network.secure-mgmt.subnet:Control-plane subnet (celilo-mgr own network)'
|
|
359
|
+
'network.secure-mgmt.gateway:Control-plane gateway IP'
|
|
358
360
|
'dns.primary:Primary DNS server'
|
|
359
361
|
'dns.fallback:Fallback DNS servers'
|
|
360
362
|
'routing.internal_gateway:Internal gateway IP'
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
2
4
|
import type { SystemConfigProperty, SystemConfigSchema } from './system-config-schema-types';
|
|
3
5
|
import { validateKey, validateValue } from './system-config-validator';
|
|
4
6
|
|
|
@@ -158,3 +160,26 @@ describe('validateKey', () => {
|
|
|
158
160
|
expect(result.error).toContain('network.bridge');
|
|
159
161
|
});
|
|
160
162
|
});
|
|
163
|
+
|
|
164
|
+
// The shipped schema is what `celilo system config set` validates against, and it
|
|
165
|
+
// is a hand-maintained enumeration of zones. `secure-mgmt` was added to
|
|
166
|
+
// NETWORK_ZONES, IPAM, zone detection and the manifest schema but NOT here, so the
|
|
167
|
+
// zone existed everywhere except the one place its subnet could be RECORDED — and
|
|
168
|
+
// recording it is what derives firewall trust and the resolver's split-horizon
|
|
169
|
+
// view. It failed only on the live box, at `system config set`.
|
|
170
|
+
describe('shipped system_config.json covers every placement zone', () => {
|
|
171
|
+
const shipped = JSON.parse(
|
|
172
|
+
readFileSync(join(import.meta.dir, '../../schemas/system_config.json'), 'utf-8'),
|
|
173
|
+
) as SystemConfigSchema;
|
|
174
|
+
|
|
175
|
+
// `external` is deliberately absent: cloud/VPS systems carry their own
|
|
176
|
+
// addressing and celilo allocates nothing for them.
|
|
177
|
+
const ADDRESSABLE_ZONES = ['internal', 'dmz', 'app', 'secure', 'secure-mgmt'] as const;
|
|
178
|
+
|
|
179
|
+
for (const zone of ADDRESSABLE_ZONES) {
|
|
180
|
+
it(`accepts network.${zone}.subnet and .gateway`, () => {
|
|
181
|
+
expect(validateKey(`network.${zone}.subnet`, shipped).valid).toBe(true);
|
|
182
|
+
expect(validateKey(`network.${zone}.gateway`, shipped).valid).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
});
|