@celilo/cli 2.1.0 → 2.2.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/drizzle/0031_module_config_source.sql +20 -0
- package/drizzle/meta/_journal.json +8 -1
- package/package.json +2 -2
- package/schemas/system_config.json +2 -1
- package/src/capabilities/public-web-publish.test.ts +61 -0
- package/src/cli/commands/firewall-interface-list.test.ts +156 -7
- package/src/cli/commands/firewall-interface-list.ts +73 -7
- package/src/cli/commands/machine-add.ts +12 -55
- package/src/cli/commands/module-config.test.ts +20 -1
- package/src/cli/commands/module-import.ts +1 -1
- package/src/cli/commands/module-update.test.ts +82 -0
- package/src/cli/commands/module-update.ts +14 -4
- package/src/cli/commands/monitor.ts +2 -10
- package/src/cli/commands/restore.ts +16 -6
- package/src/cli/generate-zsh-completion.ts +1 -1
- package/src/cli/index.ts +4 -3
- package/src/cli/restore-migration-failure.test.ts +159 -0
- package/src/db/client.ts +5 -0
- package/src/db/migrate.test.ts +61 -135
- package/src/db/migrate.ts +7 -2
- package/src/db/schema.ts +10 -0
- package/src/hooks/broker.test.ts +106 -2
- package/src/hooks/broker.ts +91 -1
- package/src/hooks/capability-loader-firewall.test.ts +37 -0
- package/src/hooks/capability-loader.ts +15 -1
- package/src/hooks/define-hook.test.ts +4 -3
- package/src/hooks/executor.test.ts +19 -18
- package/src/hooks/executor.ts +82 -11
- package/src/hooks/hook-jail-toolchain-reach.test.ts +3 -2
- package/src/hooks/hook-jail-unreachability.test.ts +4 -3
- package/src/hooks/hook-protocol.ts +46 -1
- package/src/hooks/hook-runner.ts +36 -0
- package/src/hooks/hook-store-proxy.test.ts +109 -0
- package/src/hooks/hook-store-proxy.ts +85 -0
- package/src/hooks/hook-store.test.ts +162 -0
- package/src/hooks/hook-store.ts +290 -0
- package/src/hooks/hook-timeout.test.ts +3 -2
- package/src/hooks/hook-trespass.test.ts +29 -5
- package/src/hooks/jail.test.ts +1 -1
- package/src/hooks/jail.ts +14 -7
- package/src/hooks/mount-set.test.ts +208 -0
- package/src/hooks/mount-set.ts +62 -14
- package/src/hooks/run-named-hook.ts +2 -0
- package/src/hooks/test-fixtures/jail-probe-hook.ts +1 -1
- package/src/hooks/test-fixtures/on-restore-staging-hook.ts +26 -0
- package/src/hooks/test-fixtures/store-backed.ts +47 -0
- package/src/hooks/test-fixtures/store-writing-hook.ts +63 -0
- package/src/hooks/unjailed-lint.test.ts +22 -6
- package/src/manifest/schema.ts +1 -0
- package/src/module/packaging/build.ts +70 -2
- package/src/module/web-root.ts +17 -1
- package/src/policy/fixture-capability-coverage.test.ts +322 -0
- package/src/policy/module-script-scan.test.ts +42 -1
- package/src/policy/module-script-scan.ts +275 -5
- package/src/policy/no-hand-built-ssh.test.ts +34 -1
- package/src/policy/no-swallowed-refusal.test.ts +265 -0
- package/src/policy/no-tar-shell-out-in-services.test.ts +43 -0
- package/src/registry/client.test.ts +149 -0
- package/src/registry/client.ts +203 -11
- package/src/services/alerting/format.test.ts +57 -0
- package/src/services/alerting/format.ts +24 -0
- package/src/services/alerting/run-monitor.ts +2 -2
- package/src/services/backup-create.ts +7 -7
- package/src/services/backup-envelope-roundtrip.test.ts +45 -2
- package/src/services/backup-restore.ts +8 -4
- package/src/services/bus-interview.ts +37 -14
- package/src/services/config-provenance.ts +4 -0
- package/src/services/control-plane-bootstrap.test.ts +121 -1
- package/src/services/control-plane-bootstrap.ts +51 -4
- package/src/services/deploy-preflight.ts +8 -2
- package/src/services/deploy-validation.test.ts +22 -0
- package/src/services/deploy-validation.ts +8 -0
- package/src/services/dns-discovery.test.ts +54 -0
- package/src/services/dns-discovery.ts +47 -5
- package/src/services/fleet-key.test.ts +66 -2
- package/src/services/fleet-key.ts +54 -0
- package/src/services/health-runner.ts +2 -0
- package/src/services/module-config.ts +20 -2
- package/src/services/module-deploy.dns-repoint.test.ts +187 -0
- package/src/services/module-deploy.ts +163 -1
- package/src/services/module-validator/git-hygiene.test.ts +122 -3
- package/src/services/module-validator/git-hygiene.ts +83 -14
- package/src/services/restore-from-file.test.ts +20 -0
- package/src/services/restore-from-file.ts +21 -6
- package/src/services/static-content-converge.test.ts +140 -2
- package/src/services/static-content-converge.ts +55 -8
- package/src/services/system-config-schema-types.ts +1 -1
- package/src/services/system-config-validator.test.ts +36 -0
- package/src/services/system-config-validator.ts +11 -0
- package/src/services/trusted-sources.test.ts +30 -0
- package/src/services/trusted-sources.ts +47 -10
- package/src/templates/generator.ts +9 -2
- package/src/variables/context.ts +16 -5
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
TrustedSource,
|
|
15
15
|
TrustedSourceStore,
|
|
16
16
|
} from '@celilo/capabilities';
|
|
17
|
+
import { isCidr } from '@celilo/capabilities';
|
|
17
18
|
import { and, eq } from 'drizzle-orm';
|
|
18
19
|
import type { DbClient } from '../db/client';
|
|
19
20
|
import { trustedSources } from '../db/schema';
|
|
@@ -80,20 +81,56 @@ export interface TrustedSubnetEntry {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
/**
|
|
83
|
-
* The operator's explicit trusted sources,
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* The operator's explicit trusted sources, in system config. Accepts the two
|
|
85
|
+
* forms a config value takes in this area: a comma-separated CIDR list and a
|
|
86
|
+
* JSON array of CIDRs (the form every sibling key uses, e.g. ddns_passwords).
|
|
87
|
+
*
|
|
88
|
+
* Every token must be a CIDR. The parser is the single choke point between the
|
|
89
|
+
* operator's value and the ruleset renderer, which emits each subnet verbatim
|
|
90
|
+
* into rules.v4 — a token that is not a CIDR used to ride through as a literal
|
|
91
|
+
* subnet name and iptables-restore failed the whole converge with
|
|
92
|
+
* "Bad argument `]'". Failing here names the token instead.
|
|
93
|
+
*
|
|
94
|
+
* ADDITIVE rather than replacing the derived control-plane subnet: dropping
|
|
95
|
+
* control-plane trust would block the SSH celilo uses to run every hook and
|
|
96
|
+
* converge, so an operator cannot strand celilo's own management by naming a
|
|
97
|
+
* subnet here.
|
|
88
98
|
*/
|
|
89
99
|
export const TRUSTED_SUBNETS_CONFIG_KEY = 'firewall.trusted_subnets';
|
|
90
100
|
|
|
91
101
|
export function parseOperatorTrustedSubnets(raw: string | undefined): string[] {
|
|
92
|
-
if (!raw) return [];
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
if (!raw || raw.trim().length === 0) return [];
|
|
103
|
+
|
|
104
|
+
let tokens: string[];
|
|
105
|
+
const trimmed = raw.trim();
|
|
106
|
+
if (trimmed.startsWith('[') || trimmed.startsWith('{')) {
|
|
107
|
+
let parsed: unknown;
|
|
108
|
+
try {
|
|
109
|
+
parsed = JSON.parse(trimmed);
|
|
110
|
+
} catch {
|
|
111
|
+
throw new Error(
|
|
112
|
+
`${TRUSTED_SUBNETS_CONFIG_KEY} looks like JSON but does not parse: ${raw}. Expected a JSON array of CIDRs, e.g. ["10.0.0.0/24"], or a comma-separated CIDR list.`,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
if (!Array.isArray(parsed) || parsed.some((t) => typeof t !== 'string')) {
|
|
116
|
+
throw new Error(
|
|
117
|
+
`${TRUSTED_SUBNETS_CONFIG_KEY} must be a JSON array of CIDR strings, e.g. ["10.0.0.0/24"], or a comma-separated CIDR list.`,
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
tokens = parsed;
|
|
121
|
+
} else {
|
|
122
|
+
tokens = trimmed.split(',');
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const subnets = tokens.map((s) => s.trim()).filter((s) => s.length > 0);
|
|
126
|
+
for (const subnet of subnets) {
|
|
127
|
+
if (!isCidr(subnet)) {
|
|
128
|
+
throw new Error(
|
|
129
|
+
`${TRUSTED_SUBNETS_CONFIG_KEY} contains "${subnet}", which is not an IPv4 CIDR. Expected e.g. 10.0.0.0/24 (comma-separated) or ["10.0.0.0/24"] (JSON array).`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return subnets;
|
|
97
134
|
}
|
|
98
135
|
|
|
99
136
|
/**
|
|
@@ -817,9 +817,16 @@ export async function generateTemplates(options: GenerateOptions): Promise<Gener
|
|
|
817
817
|
const configMap = new Map(configs.map((c) => [c.key, c.value || c.valueJson]));
|
|
818
818
|
|
|
819
819
|
// Check for missing required variables
|
|
820
|
-
// Skip infrastructure and terraform variables - they're auto-populated during/after generation
|
|
820
|
+
// Skip infrastructure and terraform variables - they're auto-populated during/after generation.
|
|
821
|
+
// Skip hook-owned variables too: they are discovered by the module's own
|
|
822
|
+
// hooks at runtime (hook-owned-state D2), so a hook that has not run yet
|
|
823
|
+
// is not a configuration error.
|
|
821
824
|
const missingVars = requiredVars.filter(
|
|
822
|
-
(v) =>
|
|
825
|
+
(v) =>
|
|
826
|
+
v.source !== 'infrastructure' &&
|
|
827
|
+
v.source !== 'terraform' &&
|
|
828
|
+
v.source !== 'hook' &&
|
|
829
|
+
!configMap.has(v.name),
|
|
823
830
|
);
|
|
824
831
|
|
|
825
832
|
if (missingVars.length > 0) {
|
package/src/variables/context.ts
CHANGED
|
@@ -577,19 +577,30 @@ async function assembleResolutionContext(
|
|
|
577
577
|
// LXC boots with a working resolver — before Ansible's apt update, and
|
|
578
578
|
// independent of which Proxmox node it lands on (the nodes' DNS defaults
|
|
579
579
|
// diverge): the internal dns_internal resolver first (it recurses, so it
|
|
580
|
-
// also answers external names), then the
|
|
580
|
+
// also answers external names), then the configured fleet resolvers as
|
|
581
|
+
// fallback.
|
|
581
582
|
// Bootstrap (no dns_internal provider registered yet — e.g. the DNS module's
|
|
582
583
|
// own LXC) → public only, so apt still works. Injected as
|
|
583
584
|
// $self:lxc_nameserver, mirroring how inventory.* are auto-derived; the
|
|
584
585
|
// proxmox_lxc terraform template drops it straight into `nameserver`.
|
|
585
586
|
{
|
|
586
|
-
|
|
587
|
+
// Named for what the keys hold, not for what a reader hopes they hold:
|
|
588
|
+
// `dns.primary` / `dns.fallback` mean "the resolvers systems should use",
|
|
589
|
+
// and an operator pointing the fleet at its own resolver (a deployed
|
|
590
|
+
// dns_internal provider's address) is established, deliberate practice
|
|
591
|
+
// (celilo#1239). These entries may therefore be private. The guard against
|
|
592
|
+
// a resolver celilo installed ending up here lives where the keys are
|
|
593
|
+
// WRITTEN from host state — discovery refuses a deployed provider's
|
|
594
|
+
// address (dns-discovery.ts) — not in a privateness check here, which
|
|
595
|
+
// would break that practice while fixing nothing: in an uncovered zone
|
|
596
|
+
// dropping the entries takes DNS away rather than tightening anything.
|
|
597
|
+
const configuredDns: string[] = [];
|
|
587
598
|
for (const key of ['dns.primary', 'dns.fallback']) {
|
|
588
599
|
const raw = systemConfigMap[key];
|
|
589
600
|
if (raw) {
|
|
590
601
|
for (const part of raw.split(',')) {
|
|
591
602
|
const ip = part.trim();
|
|
592
|
-
if (ip)
|
|
603
|
+
if (ip) configuredDns.push(ip);
|
|
593
604
|
}
|
|
594
605
|
}
|
|
595
606
|
}
|
|
@@ -663,8 +674,8 @@ async function assembleResolutionContext(
|
|
|
663
674
|
const nameservers = dropPublicResolvers
|
|
664
675
|
? [primaryIp, secondaryIp]
|
|
665
676
|
: primaryIp
|
|
666
|
-
? [primaryIp, ...
|
|
667
|
-
:
|
|
677
|
+
? [primaryIp, ...configuredDns]
|
|
678
|
+
: configuredDns;
|
|
668
679
|
const unique = [...new Set(nameservers)];
|
|
669
680
|
if (unique.length > 0) {
|
|
670
681
|
selfConfig.lxc_nameserver = unique.join(' ');
|