@celilo/cli 1.2.0 → 1.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.
- package/CELILO_CORE_MODULES.md +2 -2
- package/CELILO_SUBSYSTEMS.md +4 -1
- package/package.json +4 -4
- package/src/cli/commands/ipam.ts +93 -0
- package/src/cli/commands/machine-add.ts +22 -0
- package/src/cli/commands/system-doctor.ts +118 -4
- package/src/cli/completion.ts +38 -5
- package/src/cli/index.ts +10 -1
- package/src/hooks/types.ts +20 -74
- package/src/ipam/allocator.test.ts +38 -0
- package/src/ipam/allocator.ts +63 -1
- package/src/ipam/auto-allocator.ts +7 -0
- package/src/manifest/contracts/v1.ts +35 -0
- package/src/manifest/schema.ts +2 -0
- package/src/policy/module-business-baseline.ts +51 -35
- package/src/services/aspect-reconcile.test.ts +460 -0
- package/src/services/aspect-runner.test.ts +1 -0
- package/src/services/aspect-runner.ts +408 -37
- package/src/services/deploy-ansible-recap.test.ts +76 -0
- package/src/services/deploy-ansible.ts +56 -1
- package/src/services/module-deploy.ts +66 -12
- package/src/templates/ingress-ip.test.ts +108 -0
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
reserveVMID,
|
|
26
26
|
unreserveIP,
|
|
27
27
|
unreserveVMID,
|
|
28
|
+
updateReservationReason,
|
|
28
29
|
} from './allocator';
|
|
29
30
|
|
|
30
31
|
describe('IPAM Allocator', () => {
|
|
@@ -295,6 +296,43 @@ describe('IPAM Allocator', () => {
|
|
|
295
296
|
const reservations = await listReservations(db);
|
|
296
297
|
expect(reservations).toHaveLength(2);
|
|
297
298
|
});
|
|
299
|
+
|
|
300
|
+
// Editing in place, rather than include-then-exclude: that dance drops the
|
|
301
|
+
// row for a moment and can race an allocation into the held address.
|
|
302
|
+
test('should edit a reservation reason in place', async () => {
|
|
303
|
+
await reserveIP('10.0.10.50', 'dmz', 'LB', null, db);
|
|
304
|
+
|
|
305
|
+
const updated = await updateReservationReason('10.0.10.50', 'dmz', 'Retired LB', db);
|
|
306
|
+
|
|
307
|
+
expect(updated).toBe(true);
|
|
308
|
+
const reservations = await db.select().from(ipReservations).all();
|
|
309
|
+
expect(reservations).toHaveLength(1);
|
|
310
|
+
expect(reservations[0].reason).toBe('Retired LB');
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
test('should leave the address held while editing', async () => {
|
|
314
|
+
await reserveIP('10.0.10.50', 'dmz', 'LB', null, db);
|
|
315
|
+
|
|
316
|
+
await updateReservationReason('10.0.10.50', 'dmz', 'Retired LB', db);
|
|
317
|
+
|
|
318
|
+
expect(await isIPAvailable('10.0.10.50', 'dmz', db)).toBe(false);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
test('should edit only the addressed row', async () => {
|
|
322
|
+
await reserveIP('10.0.10.50', 'dmz', 'LB', null, db);
|
|
323
|
+
await reserveIP('10.0.10.51', 'dmz', 'LB', null, db);
|
|
324
|
+
|
|
325
|
+
await updateReservationReason('10.0.10.50', 'dmz', 'Retired LB', db);
|
|
326
|
+
|
|
327
|
+
const reasons = (await listReservations(db)).map((r) => r.reason);
|
|
328
|
+
expect(reasons.sort()).toEqual(['LB', 'Retired LB']);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
test('should report when no reservation exists to edit', async () => {
|
|
332
|
+
const updated = await updateReservationReason('10.0.10.99', 'dmz', 'Nothing there', db);
|
|
333
|
+
|
|
334
|
+
expect(updated).toBe(false);
|
|
335
|
+
});
|
|
298
336
|
});
|
|
299
337
|
|
|
300
338
|
describe('getAllocatedIPsInSubnet', () => {
|
package/src/ipam/allocator.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Prevents conflicts and tracks allocations
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { and, eq } from 'drizzle-orm';
|
|
7
|
+
import { and, eq, like, or } from 'drizzle-orm';
|
|
8
8
|
import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite';
|
|
9
9
|
import type { DbClient } from '../db/client';
|
|
10
10
|
import { ipAllocations, ipReservations, systemConfig, vmidReservations } from '../db/schema';
|
|
@@ -246,6 +246,68 @@ export async function unreserveIP(
|
|
|
246
246
|
.where(and(eq(ipReservations.ipStart, ip), eq(ipReservations.zone, zone)));
|
|
247
247
|
}
|
|
248
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Release every ingress-IP reservation a module holds (celilo#892).
|
|
251
|
+
*
|
|
252
|
+
* `ensureIngressIps` reserves an `internal`-subnet address at generate time and
|
|
253
|
+
* nothing released it at removal, so each install/remove cycle permanently
|
|
254
|
+
* burned one address from the static range — with no error and no way to tell
|
|
255
|
+
* the dead row from the live one, since both carry the same reason string.
|
|
256
|
+
*
|
|
257
|
+
* TWO reason formats exist in live databases and both must go: the current
|
|
258
|
+
* `ingress:<module>:<variable>` (since celilo#879) and the pre-879
|
|
259
|
+
* `dns-ingress:<module>`, which celilo-mgr still holds. Matching only the
|
|
260
|
+
* current one would leave the installed base leaking.
|
|
261
|
+
*
|
|
262
|
+
* Deletion is by REASON, not by the stored config value: a module can hold an
|
|
263
|
+
* ingress reservation with no `ip_allocations` row (it deploys onto a machine
|
|
264
|
+
* rather than a container), and the config rows are about to be cascade-deleted
|
|
265
|
+
* anyway. The reason string is the only thing that names the owner.
|
|
266
|
+
*
|
|
267
|
+
* @returns The addresses released, for reporting.
|
|
268
|
+
*/
|
|
269
|
+
export async function releaseIngressReservations(
|
|
270
|
+
moduleId: string,
|
|
271
|
+
db: DbOrTransaction,
|
|
272
|
+
): Promise<string[]> {
|
|
273
|
+
// Module IDs are validated kebab-case, so they carry no LIKE wildcards.
|
|
274
|
+
const ownedByModule = or(
|
|
275
|
+
like(ipReservations.reason, `ingress:${moduleId}:%`),
|
|
276
|
+
eq(ipReservations.reason, `dns-ingress:${moduleId}`),
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
const held = await db.select().from(ipReservations).where(ownedByModule).all();
|
|
280
|
+
if (held.length === 0) return [];
|
|
281
|
+
|
|
282
|
+
await db.delete(ipReservations).where(ownedByModule);
|
|
283
|
+
|
|
284
|
+
return held.map((r: typeof ipReservations.$inferSelect) => r.ipStart);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Change an existing reservation's reason in place.
|
|
289
|
+
*
|
|
290
|
+
* The alternative — include then re-exclude — drops the row for a moment and
|
|
291
|
+
* can race an allocation into the address it was holding.
|
|
292
|
+
*
|
|
293
|
+
* @returns False when no reservation exists for that IP in that zone.
|
|
294
|
+
*/
|
|
295
|
+
export async function updateReservationReason(
|
|
296
|
+
ipStart: string,
|
|
297
|
+
zone: IpamZone,
|
|
298
|
+
reason: string,
|
|
299
|
+
db: DbOrTransaction,
|
|
300
|
+
): Promise<boolean> {
|
|
301
|
+
const ip = stripCIDR(ipStart);
|
|
302
|
+
const match = and(eq(ipReservations.ipStart, ip), eq(ipReservations.zone, zone));
|
|
303
|
+
|
|
304
|
+
const existing = await db.select().from(ipReservations).where(match).all();
|
|
305
|
+
if (existing.length === 0) return false;
|
|
306
|
+
|
|
307
|
+
await db.update(ipReservations).set({ reason }).where(match);
|
|
308
|
+
return true;
|
|
309
|
+
}
|
|
310
|
+
|
|
249
311
|
/**
|
|
250
312
|
* List all IP reservations
|
|
251
313
|
*/
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { eq } from 'drizzle-orm';
|
|
11
11
|
import type { DbClient } from '../db/client';
|
|
12
12
|
import { ipAllocations } from '../db/schema';
|
|
13
|
+
import { releaseIngressReservations } from './allocator';
|
|
13
14
|
|
|
14
15
|
export interface IpamAllocation {
|
|
15
16
|
moduleId: string;
|
|
@@ -258,6 +259,12 @@ export async function allocateForModule(
|
|
|
258
259
|
* @returns True if allocation was removed, false if none existed
|
|
259
260
|
*/
|
|
260
261
|
export async function deallocateForModule(moduleId: string, db: DbClient): Promise<boolean> {
|
|
262
|
+
// Ingress reservations are released FIRST and unconditionally (celilo#892).
|
|
263
|
+
// A module can hold one with no `ip_allocations` row at all — it deploys onto
|
|
264
|
+
// a machine rather than a celilo-provisioned container — so releasing it
|
|
265
|
+
// after the early return below would skip exactly the modules that leak.
|
|
266
|
+
await releaseIngressReservations(moduleId, db);
|
|
267
|
+
|
|
261
268
|
// Check if allocation exists before deleting
|
|
262
269
|
const existing = getAllocation(moduleId, db);
|
|
263
270
|
if (!existing) {
|
|
@@ -261,6 +261,41 @@ export const V1_HOOKS: ContractHooks = {
|
|
|
261
261
|
inputs: {},
|
|
262
262
|
outputs: {},
|
|
263
263
|
},
|
|
264
|
+
/**
|
|
265
|
+
* Report what a tunnel/interface is ACTUALLY carrying, diffed against what
|
|
266
|
+
* celilo's config says it should carry.
|
|
267
|
+
*
|
|
268
|
+
* Deliberately a read of the live thing rather than of celilo's own record.
|
|
269
|
+
* celilo#928 was exactly a divergence between the two — a device present in
|
|
270
|
+
* config, rendered as active by a UI, and absent from the interface — and
|
|
271
|
+
* diagnosing it needed a screenshot and a root SSH because nothing celilo
|
|
272
|
+
* offered could tell the two apart. A hook that reported the record would
|
|
273
|
+
* have reproduced the misleading signal rather than exposing it.
|
|
274
|
+
*
|
|
275
|
+
* No structured outputs: it reports through the logger, so an operator and an
|
|
276
|
+
* agent read the same thing.
|
|
277
|
+
*/
|
|
278
|
+
list_peers: {
|
|
279
|
+
inputs: {},
|
|
280
|
+
outputs: {},
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Re-assert a module's desired peer set onto the thing carrying it, on a
|
|
284
|
+
* timer, without an operator.
|
|
285
|
+
*
|
|
286
|
+
* The counterpart to applying on change: apply-on-change bounds latency, this
|
|
287
|
+
* bounds how long ANY divergence can persist — including drift nobody
|
|
288
|
+
* predicted (a hand-edit on the box, an apply that failed, a record written
|
|
289
|
+
* before the applying code existed). celilo#934, where the module could
|
|
290
|
+
* already SEE the drift in `health_check` and had nowhere to act on it.
|
|
291
|
+
*
|
|
292
|
+
* A converge that changes nothing must be silent, so the log stays a record
|
|
293
|
+
* of things happening.
|
|
294
|
+
*/
|
|
295
|
+
reconcile_peers: {
|
|
296
|
+
inputs: {},
|
|
297
|
+
outputs: {},
|
|
298
|
+
},
|
|
264
299
|
/**
|
|
265
300
|
* Build-bus upstream publish hook. The executor passes the
|
|
266
301
|
* PublishEvent fields as env vars (CELILO_EVENT_PAYLOAD,
|
package/src/manifest/schema.ts
CHANGED
|
@@ -364,6 +364,8 @@ const LIFECYCLE_HOOK_SCHEMAS = {
|
|
|
364
364
|
refresh_registrations: LifecycleHookSchema.optional(),
|
|
365
365
|
reassert_dhcp_dns: LifecycleHookSchema.optional(),
|
|
366
366
|
reconcile_clients: LifecycleHookSchema.optional(),
|
|
367
|
+
list_peers: LifecycleHookSchema.optional(),
|
|
368
|
+
reconcile_peers: LifecycleHookSchema.optional(),
|
|
367
369
|
} satisfies Record<HookName, z.ZodTypeAny>;
|
|
368
370
|
|
|
369
371
|
/**
|
|
@@ -11,6 +11,19 @@
|
|
|
11
11
|
* refer to that document's sections 1-4 — read the row before changing a line
|
|
12
12
|
* here.
|
|
13
13
|
*
|
|
14
|
+
* **Every debt entry names the issue tracking its removal.** The audit is a
|
|
15
|
+
* ruling; the issues are the work. If you are here because the gate went red,
|
|
16
|
+
* the issue in the entry's `why` is where the fix belongs:
|
|
17
|
+
*
|
|
18
|
+
* #937 the hardcoded well-known registry + its duplicate zone table
|
|
19
|
+
* #938 the loader's capName branches, CAPABILITY_MODULE_MAP, isFirewallModule
|
|
20
|
+
* #939 the four provider-domain tables
|
|
21
|
+
* #940 the Caddyfile generator + interface classification in the shared package
|
|
22
|
+
* #941 core shelling iptables-save
|
|
23
|
+
* #943 the three capability-named CLI verbs
|
|
24
|
+
* #944 core shelling wg pubkey
|
|
25
|
+
* #945 three core primitives gated on one capability (generalise, don't move)
|
|
26
|
+
*
|
|
14
27
|
* Two kinds of entry live here and they must not be confused:
|
|
15
28
|
*
|
|
16
29
|
* - **Debt** — the default. It is here because it is wrong and not yet fixed.
|
|
@@ -25,6 +38,9 @@
|
|
|
25
38
|
* each belongs to. Scan A asserts the tagged set EQUALS this map — not that it
|
|
26
39
|
* is empty. These four exist today (audit T1, T2, T3, T6) and Phase 1 migrates
|
|
27
40
|
* nothing; an assertion that core holds none would be red the day it landed.
|
|
41
|
+
*
|
|
42
|
+
* Tracked by #939. Migrating them keeps the ownership CLAIM in core — dropping
|
|
43
|
+
* it is the mistake that made `dns_registration_consumers` necessary (#626).
|
|
28
44
|
*/
|
|
29
45
|
export const CAPABILITY_OWNED_TABLES: Readonly<Record<string, string>> = {
|
|
30
46
|
web_routes: 'public_web',
|
|
@@ -68,25 +84,25 @@ export const CAPABILITY_NAME_BASELINE: readonly CapabilityNameRow[] = [
|
|
|
68
84
|
file: 'apps/celilo/src/capabilities/well-known.ts',
|
|
69
85
|
capability: 'dhcp_server',
|
|
70
86
|
count: 1,
|
|
71
|
-
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2',
|
|
87
|
+
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2 (#937)',
|
|
72
88
|
},
|
|
73
89
|
{
|
|
74
90
|
file: 'apps/celilo/src/capabilities/well-known.ts',
|
|
75
91
|
capability: 'dns_internal',
|
|
76
92
|
count: 1,
|
|
77
|
-
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2',
|
|
93
|
+
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2 (#937)',
|
|
78
94
|
},
|
|
79
95
|
{
|
|
80
96
|
file: 'apps/celilo/src/capabilities/well-known.ts',
|
|
81
97
|
capability: 'dns_registrar',
|
|
82
98
|
count: 1,
|
|
83
|
-
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2',
|
|
99
|
+
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2 (#937)',
|
|
84
100
|
},
|
|
85
101
|
{
|
|
86
102
|
file: 'apps/celilo/src/capabilities/well-known.ts',
|
|
87
103
|
capability: 'public_web',
|
|
88
104
|
count: 1,
|
|
89
|
-
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2',
|
|
105
|
+
why: 'X1 — hardcoded canonical hostnames, required zones and literal ports; Phase 2 (#937)',
|
|
90
106
|
},
|
|
91
107
|
{
|
|
92
108
|
file: 'apps/celilo/src/cli/commands/notify-config.ts',
|
|
@@ -98,91 +114,91 @@ export const CAPABILITY_NAME_BASELINE: readonly CapabilityNameRow[] = [
|
|
|
98
114
|
file: 'apps/celilo/src/cli/commands/token.ts',
|
|
99
115
|
capability: 'idp',
|
|
100
116
|
count: 1,
|
|
101
|
-
why: 'X7 — a top-level CLI verb backed by the idp capability; Phase 5',
|
|
117
|
+
why: 'X7 — a top-level CLI verb backed by the idp capability; Phase 5 (#943)',
|
|
102
118
|
},
|
|
103
119
|
{
|
|
104
120
|
file: 'apps/celilo/src/cli/completion.ts',
|
|
105
121
|
capability: 'firewall',
|
|
106
122
|
count: 3,
|
|
107
|
-
why: 'X6 — tab completion for the capability-named CLI verbs; falls out with X6',
|
|
123
|
+
why: 'X6 — tab completion for the capability-named CLI verbs; falls out with X6 (#943)',
|
|
108
124
|
},
|
|
109
125
|
{
|
|
110
126
|
file: 'apps/celilo/src/cli/index.ts',
|
|
111
127
|
capability: 'firewall',
|
|
112
128
|
count: 2,
|
|
113
|
-
why: 'X5/X6/X7 — the command tree wiring the capability-named CLI verbs; Phase 5',
|
|
129
|
+
why: 'X5/X6/X7 — the command tree wiring the capability-named CLI verbs; Phase 5 (#943)',
|
|
114
130
|
},
|
|
115
131
|
{
|
|
116
132
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
117
133
|
capability: 'control_plane_vpn',
|
|
118
134
|
count: 1,
|
|
119
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
135
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
120
136
|
},
|
|
121
137
|
{
|
|
122
138
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
123
139
|
capability: 'dhcp_server',
|
|
124
140
|
count: 1,
|
|
125
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
141
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
126
142
|
},
|
|
127
143
|
{
|
|
128
144
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
129
145
|
capability: 'dns_internal',
|
|
130
146
|
count: 3,
|
|
131
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
147
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
132
148
|
},
|
|
133
149
|
{
|
|
134
150
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
135
151
|
capability: 'dns_registrar',
|
|
136
152
|
count: 4,
|
|
137
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
153
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
138
154
|
},
|
|
139
155
|
{
|
|
140
156
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
141
157
|
capability: 'external_web',
|
|
142
158
|
count: 1,
|
|
143
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
159
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
144
160
|
},
|
|
145
161
|
{
|
|
146
162
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
147
163
|
capability: 'firewall',
|
|
148
164
|
count: 12,
|
|
149
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
165
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
150
166
|
},
|
|
151
167
|
{
|
|
152
168
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
153
169
|
capability: 'idp',
|
|
154
170
|
count: 1,
|
|
155
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
171
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
156
172
|
},
|
|
157
173
|
{
|
|
158
174
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
159
175
|
capability: 'notification',
|
|
160
176
|
count: 1,
|
|
161
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
177
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
162
178
|
},
|
|
163
179
|
{
|
|
164
180
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
165
181
|
capability: 'private_web',
|
|
166
182
|
count: 1,
|
|
167
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
183
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
168
184
|
},
|
|
169
185
|
{
|
|
170
186
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
171
187
|
capability: 'public_web',
|
|
172
188
|
count: 8,
|
|
173
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
189
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
174
190
|
},
|
|
175
191
|
{
|
|
176
192
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
177
193
|
capability: 'registry_publish',
|
|
178
194
|
count: 1,
|
|
179
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
195
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
180
196
|
},
|
|
181
197
|
{
|
|
182
198
|
file: 'apps/celilo/src/hooks/capability-loader.ts',
|
|
183
199
|
capability: 'source_forge',
|
|
184
200
|
count: 1,
|
|
185
|
-
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3',
|
|
201
|
+
why: 'L1-L12 — core branches on the capability NAME; becomes a provider declaration in Phase 3 (#938)',
|
|
186
202
|
},
|
|
187
203
|
{
|
|
188
204
|
file: 'apps/celilo/src/manifest/validate.ts',
|
|
@@ -212,49 +228,49 @@ export const CAPABILITY_NAME_BASELINE: readonly CapabilityNameRow[] = [
|
|
|
212
228
|
file: 'apps/celilo/src/services/dns-provider-backfill.ts',
|
|
213
229
|
capability: 'dns_internal',
|
|
214
230
|
count: 2,
|
|
215
|
-
why: 'S3 — the generic event-replay half is core; the dns_internal gate is not',
|
|
231
|
+
why: 'S3 — the generic event-replay half is core; the dns_internal gate is not (#945)',
|
|
216
232
|
},
|
|
217
233
|
{
|
|
218
234
|
file: 'apps/celilo/src/services/firewall-reach.ts',
|
|
219
235
|
capability: 'firewall',
|
|
220
236
|
count: 1,
|
|
221
|
-
why: 'S8 — core shells iptables-save at a remote box and parses the output',
|
|
237
|
+
why: 'S8 — core shells iptables-save at a remote box and parses the output (#941)',
|
|
222
238
|
},
|
|
223
239
|
{
|
|
224
240
|
file: 'apps/celilo/src/services/infrastructure-selector.ts',
|
|
225
241
|
capability: 'firewall',
|
|
226
242
|
count: 1,
|
|
227
|
-
why: 'S15 — isFirewallModule hardcodes a placement rule the manifest should declare',
|
|
243
|
+
why: 'S15 — isFirewallModule hardcodes a placement rule the manifest should declare (#938)',
|
|
228
244
|
},
|
|
229
245
|
{
|
|
230
246
|
file: 'apps/celilo/src/services/module-deploy.ts',
|
|
231
247
|
capability: 'firewall',
|
|
232
248
|
count: 2,
|
|
233
|
-
why: "S16 — two more copies of S15's decision; fixing S15 removes all three",
|
|
249
|
+
why: "S16 — two more copies of S15's decision; fixing S15 removes all three (#938)",
|
|
234
250
|
},
|
|
235
251
|
{
|
|
236
252
|
file: 'apps/celilo/src/services/public-web-republish.ts',
|
|
237
253
|
capability: 'public_web',
|
|
238
254
|
count: 1,
|
|
239
|
-
why: "S2 — encodes caddy's redeploy behaviour; generalise to a provider-declared re-assert signal",
|
|
255
|
+
why: "S2 — encodes caddy's redeploy behaviour; generalise to a provider-declared re-assert signal (#945)",
|
|
240
256
|
},
|
|
241
257
|
{
|
|
242
258
|
file: 'apps/celilo/src/services/zone-policy.ts',
|
|
243
259
|
capability: 'public_web',
|
|
244
260
|
count: 1,
|
|
245
|
-
why: 'S13 — ZONE_REQUIREMENTS, a second hand-maintained copy of well-known.ts; Phase 2',
|
|
261
|
+
why: 'S13 — ZONE_REQUIREMENTS, a second hand-maintained copy of well-known.ts; Phase 2 (#937)',
|
|
246
262
|
},
|
|
247
263
|
{
|
|
248
264
|
file: 'apps/celilo/src/templates/generator.ts',
|
|
249
265
|
capability: 'dns_internal',
|
|
250
266
|
count: 1,
|
|
251
|
-
why: 'X4 — declaration-driven and the model for the rest; only the error string names the capability',
|
|
267
|
+
why: 'X4 — declaration-driven and the model for the rest; only the error string names the capability (#945)',
|
|
252
268
|
},
|
|
253
269
|
{
|
|
254
270
|
file: 'apps/celilo/src/variables/context.ts',
|
|
255
271
|
capability: 'dns_internal',
|
|
256
272
|
count: 1,
|
|
257
|
-
why: 'X3 — reaches capabilitiesMap.dns_internal by name; should read a declared field (X4 is the model)',
|
|
273
|
+
why: 'X3 — reaches capabilitiesMap.dns_internal by name; should read a declared field (X4 is the model) (#945)',
|
|
258
274
|
},
|
|
259
275
|
{
|
|
260
276
|
file: 'packages/capabilities/src/capability-contract.ts',
|
|
@@ -344,13 +360,13 @@ export const CAPABILITY_NAME_BASELINE: readonly CapabilityNameRow[] = [
|
|
|
344
360
|
file: 'packages/capabilities/src/public-web.ts',
|
|
345
361
|
capability: 'public_web',
|
|
346
362
|
count: 1,
|
|
347
|
-
why: "X8 — generateCaddyfile renders caddy's complete config from the shared package; Phase 5",
|
|
363
|
+
why: "X8 — generateCaddyfile renders caddy's complete config from the shared package; Phase 5 (#940)",
|
|
348
364
|
},
|
|
349
365
|
{
|
|
350
366
|
file: 'packages/capabilities/src/utils.ts',
|
|
351
367
|
capability: 'public_web',
|
|
352
368
|
count: 3,
|
|
353
|
-
why: 'X8 — shared helpers that name the capability they serve; moves with X8 in Phase 5',
|
|
369
|
+
why: 'X8 — shared helpers that name the capability they serve; moves with X8 in Phase 5 (#940)',
|
|
354
370
|
},
|
|
355
371
|
];
|
|
356
372
|
|
|
@@ -368,17 +384,17 @@ export const SERVICE_FILENAME_BASELINE: readonly ServiceFilenameRow[] = [
|
|
|
368
384
|
{
|
|
369
385
|
file: 'apps/celilo/src/services/dns-internal-records.ts',
|
|
370
386
|
capability: 'dns_internal',
|
|
371
|
-
why: 'S5 — the store for T6; moves with the table in Phase 4',
|
|
387
|
+
why: 'S5 — the store for T6; moves with the table in Phase 4 (#939)',
|
|
372
388
|
},
|
|
373
389
|
{
|
|
374
390
|
file: 'apps/celilo/src/services/firewall-reach.ts',
|
|
375
391
|
capability: 'firewall',
|
|
376
|
-
why: 'S8 — core reaching into one provider implementation',
|
|
392
|
+
why: 'S8 — core reaching into one provider implementation (#941)',
|
|
377
393
|
},
|
|
378
394
|
{
|
|
379
395
|
file: 'apps/celilo/src/services/public-web-republish.ts',
|
|
380
396
|
capability: 'public_web',
|
|
381
|
-
why: "S2 — named for one provider's redeploy behaviour",
|
|
397
|
+
why: "S2 — named for one provider's redeploy behaviour (#945)",
|
|
382
398
|
},
|
|
383
399
|
];
|
|
384
400
|
|
|
@@ -387,18 +403,18 @@ export const PROVIDER_LITERAL_BASELINE: readonly ProviderLiteralRow[] = [
|
|
|
387
403
|
file: 'apps/celilo/src/secrets/generators.ts',
|
|
388
404
|
literal: 'wg pubkey',
|
|
389
405
|
count: 1,
|
|
390
|
-
why: 'X11 — core shells `wg pubkey` to derive a key, and tells the operator to brew install wireguard-tools',
|
|
406
|
+
why: 'X11 — core shells `wg pubkey` to derive a key, and tells the operator to brew install wireguard-tools (#944)',
|
|
391
407
|
},
|
|
392
408
|
{
|
|
393
409
|
file: 'apps/celilo/src/services/firewall-reach.ts',
|
|
394
410
|
literal: 'iptables-save',
|
|
395
411
|
count: 1,
|
|
396
|
-
why: "S8 — core parses a firewall's live ruleset; implementation-specific, not merely capability-specific",
|
|
412
|
+
why: "S8 — core parses a firewall's live ruleset; implementation-specific, not merely capability-specific (#941)",
|
|
397
413
|
},
|
|
398
414
|
{
|
|
399
415
|
file: 'packages/capabilities/src/public-web.ts',
|
|
400
416
|
literal: '/srv/www',
|
|
401
417
|
count: 4,
|
|
402
|
-
why: "X8 — the Caddyfile generator knows caddy's on-disk asset layout",
|
|
418
|
+
why: "X8 — the Caddyfile generator knows caddy's on-disk asset layout (#940)",
|
|
403
419
|
},
|
|
404
420
|
];
|