@treeseed/sdk 0.13.0-rc.102 → 0.13.0-rc.103
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/.treeseed-build-complete.json +1 -1
- package/dist/deployment/index.d.ts +1 -0
- package/dist/deployment/index.js +1 -0
- package/dist/deployment/postgres/contracts.js +5 -1
- package/dist/deployment/postgres/requirements.d.ts +14 -0
- package/dist/deployment/postgres/requirements.js +30 -0
- package/dist/deployment/schemas.d.ts +705 -1
- package/dist/deployment/schemas.js +17 -2
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"completedAt":"2026-09-
|
|
1
|
+
{"completedAt":"2026-09-09T06:37:08.486Z"}
|
package/dist/deployment/index.js
CHANGED
|
@@ -48,7 +48,7 @@ const postgresTopologySchema = z.object({
|
|
|
48
48
|
if (!unique(value.servers.map((server) => server.id)) || !unique(value.requirements.map((requirement) => requirement.id)) || !unique(value.allocations.map((allocation) => allocation.requirementId))) fail("Server, requirement and allocation identities must be unique.");
|
|
49
49
|
if (value.servers.filter((server) => server.mode === "shared").length > 1) fail("An environment has at most one default shared server.");
|
|
50
50
|
if (value.servers.some((server) => server.installationId !== value.installationId || server.environment !== value.environment)) fail("Servers must belong to this installation and environment.");
|
|
51
|
-
const databases = /* @__PURE__ */ new Set(), roles = /* @__PURE__ */ new Set();
|
|
51
|
+
const databases = /* @__PURE__ */ new Set(), roles = /* @__PURE__ */ new Set(), credentials = /* @__PURE__ */ new Set();
|
|
52
52
|
for (const allocation of value.allocations) {
|
|
53
53
|
const server = value.servers.find((entry) => entry.id === allocation.serverId);
|
|
54
54
|
const requirement = value.requirements.find((entry) => entry.id === allocation.requirementId);
|
|
@@ -60,6 +60,10 @@ const postgresTopologySchema = z.object({
|
|
|
60
60
|
const databaseKey = `${server.id}:${allocation.database}`;
|
|
61
61
|
if (databases.has(databaseKey)) fail("Applications must not share an allocated database.");
|
|
62
62
|
databases.add(databaseKey);
|
|
63
|
+
for (const reference of [allocation.migrationCredentialReference, allocation.runtimeCredentialReference]) {
|
|
64
|
+
if (credentials.has(reference)) fail("Applications must not share database credential references.");
|
|
65
|
+
credentials.add(reference);
|
|
66
|
+
}
|
|
63
67
|
for (const role of [allocation.ownerRole, allocation.migrationRole, allocation.runtimeRole]) {
|
|
64
68
|
const key = `${server.id}:${role}`;
|
|
65
69
|
if (roles.has(key)) fail("Applications must not share database roles.");
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Call after artifact authenticity verification, with the complete selected
|
|
2
|
+
* component inventory. Host configuration cannot weaken a package requirement.
|
|
3
|
+
*/
|
|
4
|
+
export declare function verifyHostPostgresRequirements(hostInput: unknown, releaseInputs: unknown[]): {
|
|
5
|
+
verified: true;
|
|
6
|
+
requirements: {
|
|
7
|
+
id: string;
|
|
8
|
+
componentId: string;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
supportedMajors: [number, ...number[]];
|
|
11
|
+
extensions: string[];
|
|
12
|
+
runtimeConnectionLimit: number;
|
|
13
|
+
}[];
|
|
14
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { componentReleaseSchema, hostConfigurationSchema } from "../schemas.js";
|
|
2
|
+
import { canonicalDeploymentJson, deploymentDigest } from "../canonical.js";
|
|
3
|
+
function verifyHostPostgresRequirements(hostInput, releaseInputs) {
|
|
4
|
+
const host = hostConfigurationSchema.parse(hostInput);
|
|
5
|
+
const releases = releaseInputs.map((input) => componentReleaseSchema.parse(input));
|
|
6
|
+
if (new Set(releases.map((item) => item.componentId)).size !== releases.length) throw new Error("Duplicate component release inventory");
|
|
7
|
+
if (Object.entries(host.components).some(([id, selection]) => selection.enabled && !releases.some((release) => release.componentId === id))) throw new Error("Selected component release inventory is incomplete");
|
|
8
|
+
const requirements = [];
|
|
9
|
+
for (const release of releases) {
|
|
10
|
+
const selection = host.components[release.componentId];
|
|
11
|
+
if (!selection) continue;
|
|
12
|
+
if (deploymentDigest(release.runtime) !== release.runtimeDigest) throw new Error("Component runtime digest mismatch");
|
|
13
|
+
for (const requirement of release.runtime.postgresRequirements ?? []) requirements.push({
|
|
14
|
+
...requirement,
|
|
15
|
+
componentId: release.componentId,
|
|
16
|
+
enabled: selection.enabled
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
if (new Set(requirements.map((item) => item.id)).size !== requirements.length) throw new Error("Component database requirement identities collide");
|
|
20
|
+
const normalize = (items) => items.map((item) => ({
|
|
21
|
+
...item,
|
|
22
|
+
supportedMajors: [...item.supportedMajors].sort((a, b) => a - b),
|
|
23
|
+
extensions: [...item.extensions].sort()
|
|
24
|
+
})).sort((a, b) => a.id.localeCompare(b.id));
|
|
25
|
+
if (canonicalDeploymentJson(normalize(requirements)) !== canonicalDeploymentJson(normalize(host.postgres?.requirements ?? []))) throw new Error("Host database requirements differ from selected immutable components");
|
|
26
|
+
return { verified: true, requirements };
|
|
27
|
+
}
|
|
28
|
+
export {
|
|
29
|
+
verifyHostPostgresRequirements
|
|
30
|
+
};
|
|
@@ -552,7 +552,7 @@ export declare const hostComponentSchema: z.ZodObject<{
|
|
|
552
552
|
};
|
|
553
553
|
}> | undefined;
|
|
554
554
|
}>;
|
|
555
|
-
export declare const hostConfigurationSchema: z.ZodObject<{
|
|
555
|
+
export declare const hostConfigurationSchema: z.ZodEffects<z.ZodObject<{
|
|
556
556
|
schemaVersion: z.ZodLiteral<"treeseed.host/v1">;
|
|
557
557
|
configurationId: z.ZodString;
|
|
558
558
|
generation: z.ZodNumber;
|
|
@@ -908,6 +908,278 @@ export declare const hostConfigurationSchema: z.ZodObject<{
|
|
|
908
908
|
};
|
|
909
909
|
}> | undefined;
|
|
910
910
|
}>>;
|
|
911
|
+
postgres: z.ZodOptional<z.ZodEffects<z.ZodObject<{
|
|
912
|
+
schemaVersion: z.ZodLiteral<"treeseed.postgres-topology/v1">;
|
|
913
|
+
installationId: z.ZodString;
|
|
914
|
+
environment: z.ZodEnum<["staging", "production"]>;
|
|
915
|
+
servers: z.ZodArray<z.ZodObject<{
|
|
916
|
+
id: z.ZodString;
|
|
917
|
+
installationId: z.ZodString;
|
|
918
|
+
environment: z.ZodEnum<["staging", "production"]>;
|
|
919
|
+
mode: z.ZodEnum<["shared", "dedicated", "external"]>;
|
|
920
|
+
hostname: z.ZodString;
|
|
921
|
+
port: z.ZodNumber;
|
|
922
|
+
major: z.ZodNumber;
|
|
923
|
+
extensions: z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>;
|
|
924
|
+
tls: z.ZodObject<{
|
|
925
|
+
mode: z.ZodLiteral<"verify-full">;
|
|
926
|
+
trustReference: z.ZodString;
|
|
927
|
+
}, "strict", z.ZodTypeAny, {
|
|
928
|
+
mode: "verify-full";
|
|
929
|
+
trustReference: string;
|
|
930
|
+
}, {
|
|
931
|
+
mode: "verify-full";
|
|
932
|
+
trustReference: string;
|
|
933
|
+
}>;
|
|
934
|
+
}, "strict", z.ZodTypeAny, {
|
|
935
|
+
id: string;
|
|
936
|
+
mode: "shared" | "dedicated" | "external";
|
|
937
|
+
environment: "production" | "staging";
|
|
938
|
+
port: number;
|
|
939
|
+
major: number;
|
|
940
|
+
extensions: string[];
|
|
941
|
+
installationId: string;
|
|
942
|
+
hostname: string;
|
|
943
|
+
tls: {
|
|
944
|
+
mode: "verify-full";
|
|
945
|
+
trustReference: string;
|
|
946
|
+
};
|
|
947
|
+
}, {
|
|
948
|
+
id: string;
|
|
949
|
+
mode: "shared" | "dedicated" | "external";
|
|
950
|
+
environment: "production" | "staging";
|
|
951
|
+
port: number;
|
|
952
|
+
major: number;
|
|
953
|
+
extensions: string[];
|
|
954
|
+
installationId: string;
|
|
955
|
+
hostname: string;
|
|
956
|
+
tls: {
|
|
957
|
+
mode: "verify-full";
|
|
958
|
+
trustReference: string;
|
|
959
|
+
};
|
|
960
|
+
}>, "many">;
|
|
961
|
+
requirements: z.ZodArray<z.ZodObject<{
|
|
962
|
+
id: z.ZodString;
|
|
963
|
+
componentId: z.ZodString;
|
|
964
|
+
enabled: z.ZodBoolean;
|
|
965
|
+
supportedMajors: z.ZodEffects<z.ZodArray<z.ZodNumber, "atleastone">, [number, ...number[]], [number, ...number[]]>;
|
|
966
|
+
extensions: z.ZodEffects<z.ZodArray<z.ZodEffects<z.ZodString, string, string>, "many">, string[], string[]>;
|
|
967
|
+
runtimeConnectionLimit: z.ZodNumber;
|
|
968
|
+
}, "strict", z.ZodTypeAny, {
|
|
969
|
+
id: string;
|
|
970
|
+
componentId: string;
|
|
971
|
+
enabled: boolean;
|
|
972
|
+
supportedMajors: [number, ...number[]];
|
|
973
|
+
extensions: string[];
|
|
974
|
+
runtimeConnectionLimit: number;
|
|
975
|
+
}, {
|
|
976
|
+
id: string;
|
|
977
|
+
componentId: string;
|
|
978
|
+
enabled: boolean;
|
|
979
|
+
supportedMajors: [number, ...number[]];
|
|
980
|
+
extensions: string[];
|
|
981
|
+
runtimeConnectionLimit: number;
|
|
982
|
+
}>, "many">;
|
|
983
|
+
allocations: z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
984
|
+
requirementId: z.ZodString;
|
|
985
|
+
serverId: z.ZodString;
|
|
986
|
+
database: z.ZodEffects<z.ZodString, string, string>;
|
|
987
|
+
ownerRole: z.ZodEffects<z.ZodString, string, string>;
|
|
988
|
+
migrationRole: z.ZodEffects<z.ZodString, string, string>;
|
|
989
|
+
runtimeRole: z.ZodEffects<z.ZodString, string, string>;
|
|
990
|
+
migrationCredentialReference: z.ZodString;
|
|
991
|
+
runtimeCredentialReference: z.ZodString;
|
|
992
|
+
onDisable: z.ZodLiteral<"preserve">;
|
|
993
|
+
}, "strict", z.ZodTypeAny, {
|
|
994
|
+
requirementId: string;
|
|
995
|
+
serverId: string;
|
|
996
|
+
database: string;
|
|
997
|
+
ownerRole: string;
|
|
998
|
+
migrationRole: string;
|
|
999
|
+
runtimeRole: string;
|
|
1000
|
+
migrationCredentialReference: string;
|
|
1001
|
+
runtimeCredentialReference: string;
|
|
1002
|
+
onDisable: "preserve";
|
|
1003
|
+
}, {
|
|
1004
|
+
requirementId: string;
|
|
1005
|
+
serverId: string;
|
|
1006
|
+
database: string;
|
|
1007
|
+
ownerRole: string;
|
|
1008
|
+
migrationRole: string;
|
|
1009
|
+
runtimeRole: string;
|
|
1010
|
+
migrationCredentialReference: string;
|
|
1011
|
+
runtimeCredentialReference: string;
|
|
1012
|
+
onDisable: "preserve";
|
|
1013
|
+
}>, {
|
|
1014
|
+
requirementId: string;
|
|
1015
|
+
serverId: string;
|
|
1016
|
+
database: string;
|
|
1017
|
+
ownerRole: string;
|
|
1018
|
+
migrationRole: string;
|
|
1019
|
+
runtimeRole: string;
|
|
1020
|
+
migrationCredentialReference: string;
|
|
1021
|
+
runtimeCredentialReference: string;
|
|
1022
|
+
onDisable: "preserve";
|
|
1023
|
+
}, {
|
|
1024
|
+
requirementId: string;
|
|
1025
|
+
serverId: string;
|
|
1026
|
+
database: string;
|
|
1027
|
+
ownerRole: string;
|
|
1028
|
+
migrationRole: string;
|
|
1029
|
+
runtimeRole: string;
|
|
1030
|
+
migrationCredentialReference: string;
|
|
1031
|
+
runtimeCredentialReference: string;
|
|
1032
|
+
onDisable: "preserve";
|
|
1033
|
+
}>, "many">;
|
|
1034
|
+
}, "strict", z.ZodTypeAny, {
|
|
1035
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
1036
|
+
environment: "production" | "staging";
|
|
1037
|
+
installationId: string;
|
|
1038
|
+
servers: {
|
|
1039
|
+
id: string;
|
|
1040
|
+
mode: "shared" | "dedicated" | "external";
|
|
1041
|
+
environment: "production" | "staging";
|
|
1042
|
+
port: number;
|
|
1043
|
+
major: number;
|
|
1044
|
+
extensions: string[];
|
|
1045
|
+
installationId: string;
|
|
1046
|
+
hostname: string;
|
|
1047
|
+
tls: {
|
|
1048
|
+
mode: "verify-full";
|
|
1049
|
+
trustReference: string;
|
|
1050
|
+
};
|
|
1051
|
+
}[];
|
|
1052
|
+
requirements: {
|
|
1053
|
+
id: string;
|
|
1054
|
+
componentId: string;
|
|
1055
|
+
enabled: boolean;
|
|
1056
|
+
supportedMajors: [number, ...number[]];
|
|
1057
|
+
extensions: string[];
|
|
1058
|
+
runtimeConnectionLimit: number;
|
|
1059
|
+
}[];
|
|
1060
|
+
allocations: {
|
|
1061
|
+
requirementId: string;
|
|
1062
|
+
serverId: string;
|
|
1063
|
+
database: string;
|
|
1064
|
+
ownerRole: string;
|
|
1065
|
+
migrationRole: string;
|
|
1066
|
+
runtimeRole: string;
|
|
1067
|
+
migrationCredentialReference: string;
|
|
1068
|
+
runtimeCredentialReference: string;
|
|
1069
|
+
onDisable: "preserve";
|
|
1070
|
+
}[];
|
|
1071
|
+
}, {
|
|
1072
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
1073
|
+
environment: "production" | "staging";
|
|
1074
|
+
installationId: string;
|
|
1075
|
+
servers: {
|
|
1076
|
+
id: string;
|
|
1077
|
+
mode: "shared" | "dedicated" | "external";
|
|
1078
|
+
environment: "production" | "staging";
|
|
1079
|
+
port: number;
|
|
1080
|
+
major: number;
|
|
1081
|
+
extensions: string[];
|
|
1082
|
+
installationId: string;
|
|
1083
|
+
hostname: string;
|
|
1084
|
+
tls: {
|
|
1085
|
+
mode: "verify-full";
|
|
1086
|
+
trustReference: string;
|
|
1087
|
+
};
|
|
1088
|
+
}[];
|
|
1089
|
+
requirements: {
|
|
1090
|
+
id: string;
|
|
1091
|
+
componentId: string;
|
|
1092
|
+
enabled: boolean;
|
|
1093
|
+
supportedMajors: [number, ...number[]];
|
|
1094
|
+
extensions: string[];
|
|
1095
|
+
runtimeConnectionLimit: number;
|
|
1096
|
+
}[];
|
|
1097
|
+
allocations: {
|
|
1098
|
+
requirementId: string;
|
|
1099
|
+
serverId: string;
|
|
1100
|
+
database: string;
|
|
1101
|
+
ownerRole: string;
|
|
1102
|
+
migrationRole: string;
|
|
1103
|
+
runtimeRole: string;
|
|
1104
|
+
migrationCredentialReference: string;
|
|
1105
|
+
runtimeCredentialReference: string;
|
|
1106
|
+
onDisable: "preserve";
|
|
1107
|
+
}[];
|
|
1108
|
+
}>, {
|
|
1109
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
1110
|
+
environment: "production" | "staging";
|
|
1111
|
+
installationId: string;
|
|
1112
|
+
servers: {
|
|
1113
|
+
id: string;
|
|
1114
|
+
mode: "shared" | "dedicated" | "external";
|
|
1115
|
+
environment: "production" | "staging";
|
|
1116
|
+
port: number;
|
|
1117
|
+
major: number;
|
|
1118
|
+
extensions: string[];
|
|
1119
|
+
installationId: string;
|
|
1120
|
+
hostname: string;
|
|
1121
|
+
tls: {
|
|
1122
|
+
mode: "verify-full";
|
|
1123
|
+
trustReference: string;
|
|
1124
|
+
};
|
|
1125
|
+
}[];
|
|
1126
|
+
requirements: {
|
|
1127
|
+
id: string;
|
|
1128
|
+
componentId: string;
|
|
1129
|
+
enabled: boolean;
|
|
1130
|
+
supportedMajors: [number, ...number[]];
|
|
1131
|
+
extensions: string[];
|
|
1132
|
+
runtimeConnectionLimit: number;
|
|
1133
|
+
}[];
|
|
1134
|
+
allocations: {
|
|
1135
|
+
requirementId: string;
|
|
1136
|
+
serverId: string;
|
|
1137
|
+
database: string;
|
|
1138
|
+
ownerRole: string;
|
|
1139
|
+
migrationRole: string;
|
|
1140
|
+
runtimeRole: string;
|
|
1141
|
+
migrationCredentialReference: string;
|
|
1142
|
+
runtimeCredentialReference: string;
|
|
1143
|
+
onDisable: "preserve";
|
|
1144
|
+
}[];
|
|
1145
|
+
}, {
|
|
1146
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
1147
|
+
environment: "production" | "staging";
|
|
1148
|
+
installationId: string;
|
|
1149
|
+
servers: {
|
|
1150
|
+
id: string;
|
|
1151
|
+
mode: "shared" | "dedicated" | "external";
|
|
1152
|
+
environment: "production" | "staging";
|
|
1153
|
+
port: number;
|
|
1154
|
+
major: number;
|
|
1155
|
+
extensions: string[];
|
|
1156
|
+
installationId: string;
|
|
1157
|
+
hostname: string;
|
|
1158
|
+
tls: {
|
|
1159
|
+
mode: "verify-full";
|
|
1160
|
+
trustReference: string;
|
|
1161
|
+
};
|
|
1162
|
+
}[];
|
|
1163
|
+
requirements: {
|
|
1164
|
+
id: string;
|
|
1165
|
+
componentId: string;
|
|
1166
|
+
enabled: boolean;
|
|
1167
|
+
supportedMajors: [number, ...number[]];
|
|
1168
|
+
extensions: string[];
|
|
1169
|
+
runtimeConnectionLimit: number;
|
|
1170
|
+
}[];
|
|
1171
|
+
allocations: {
|
|
1172
|
+
requirementId: string;
|
|
1173
|
+
serverId: string;
|
|
1174
|
+
database: string;
|
|
1175
|
+
ownerRole: string;
|
|
1176
|
+
migrationRole: string;
|
|
1177
|
+
runtimeRole: string;
|
|
1178
|
+
migrationCredentialReference: string;
|
|
1179
|
+
runtimeCredentialReference: string;
|
|
1180
|
+
onDisable: "preserve";
|
|
1181
|
+
}[];
|
|
1182
|
+
}>>;
|
|
911
1183
|
network: z.ZodObject<{
|
|
912
1184
|
manager: z.ZodObject<{
|
|
913
1185
|
binding: z.ZodString;
|
|
@@ -1556,6 +1828,400 @@ export declare const hostConfigurationSchema: z.ZodObject<{
|
|
|
1556
1828
|
provider: "file" | "systemd-credential";
|
|
1557
1829
|
reference: string;
|
|
1558
1830
|
}>;
|
|
1831
|
+
postgres?: {
|
|
1832
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
1833
|
+
environment: "production" | "staging";
|
|
1834
|
+
installationId: string;
|
|
1835
|
+
servers: {
|
|
1836
|
+
id: string;
|
|
1837
|
+
mode: "shared" | "dedicated" | "external";
|
|
1838
|
+
environment: "production" | "staging";
|
|
1839
|
+
port: number;
|
|
1840
|
+
major: number;
|
|
1841
|
+
extensions: string[];
|
|
1842
|
+
installationId: string;
|
|
1843
|
+
hostname: string;
|
|
1844
|
+
tls: {
|
|
1845
|
+
mode: "verify-full";
|
|
1846
|
+
trustReference: string;
|
|
1847
|
+
};
|
|
1848
|
+
}[];
|
|
1849
|
+
requirements: {
|
|
1850
|
+
id: string;
|
|
1851
|
+
componentId: string;
|
|
1852
|
+
enabled: boolean;
|
|
1853
|
+
supportedMajors: [number, ...number[]];
|
|
1854
|
+
extensions: string[];
|
|
1855
|
+
runtimeConnectionLimit: number;
|
|
1856
|
+
}[];
|
|
1857
|
+
allocations: {
|
|
1858
|
+
requirementId: string;
|
|
1859
|
+
serverId: string;
|
|
1860
|
+
database: string;
|
|
1861
|
+
ownerRole: string;
|
|
1862
|
+
migrationRole: string;
|
|
1863
|
+
runtimeRole: string;
|
|
1864
|
+
migrationCredentialReference: string;
|
|
1865
|
+
runtimeCredentialReference: string;
|
|
1866
|
+
onDisable: "preserve";
|
|
1867
|
+
}[];
|
|
1868
|
+
} | undefined;
|
|
1869
|
+
security?: {
|
|
1870
|
+
sandbox: {
|
|
1871
|
+
runtime: "kata-runtime-rs-qemu";
|
|
1872
|
+
profiles: {
|
|
1873
|
+
id: string;
|
|
1874
|
+
guestImage: string;
|
|
1875
|
+
guestImageDigest: string;
|
|
1876
|
+
}[];
|
|
1877
|
+
required: boolean;
|
|
1878
|
+
brokerSocket: string;
|
|
1879
|
+
modelGateway: {
|
|
1880
|
+
provider: "openai";
|
|
1881
|
+
upstreamBaseUrl: "https://api.openai.com";
|
|
1882
|
+
allowedModels: string[];
|
|
1883
|
+
};
|
|
1884
|
+
};
|
|
1885
|
+
providerVolume: {
|
|
1886
|
+
encryption: "luks2";
|
|
1887
|
+
backingPath: string;
|
|
1888
|
+
mountPath: string;
|
|
1889
|
+
sizeBytes: number;
|
|
1890
|
+
unlock: "systemd-credential" | "tpm2";
|
|
1891
|
+
recoveryRequired: true;
|
|
1892
|
+
};
|
|
1893
|
+
applicationEncryption: {
|
|
1894
|
+
provider: "systemd-credential";
|
|
1895
|
+
activeKeyVersion: number;
|
|
1896
|
+
diagnosticsKeyVersion: number;
|
|
1897
|
+
};
|
|
1898
|
+
} | undefined;
|
|
1899
|
+
}, {
|
|
1900
|
+
schemaVersion: "treeseed.host/v1";
|
|
1901
|
+
runtime: {
|
|
1902
|
+
management: "external" | "managed";
|
|
1903
|
+
environment?: "development" | "production" | undefined;
|
|
1904
|
+
dataRoot?: string | undefined;
|
|
1905
|
+
};
|
|
1906
|
+
components: Record<string, {
|
|
1907
|
+
enabled: boolean;
|
|
1908
|
+
track: "development" | "stable";
|
|
1909
|
+
resources?: {
|
|
1910
|
+
cpuCores?: number | undefined;
|
|
1911
|
+
memoryBytes?: number | undefined;
|
|
1912
|
+
storageBytes?: number | undefined;
|
|
1913
|
+
gpuDevices?: string[] | undefined;
|
|
1914
|
+
} | undefined;
|
|
1915
|
+
profile?: string | undefined;
|
|
1916
|
+
aliases?: Record<string, string> | undefined;
|
|
1917
|
+
configuration?: Record<string, unknown> | undefined;
|
|
1918
|
+
connections?: Record<string, {
|
|
1919
|
+
kind: "local";
|
|
1920
|
+
componentId: string;
|
|
1921
|
+
serviceId: string;
|
|
1922
|
+
endpointId: string;
|
|
1923
|
+
} | {
|
|
1924
|
+
kind: "remote";
|
|
1925
|
+
audience: string;
|
|
1926
|
+
url: string;
|
|
1927
|
+
authentication: {
|
|
1928
|
+
mode: "none" | "application" | "mtls" | "bearer";
|
|
1929
|
+
secretRef?: string | undefined;
|
|
1930
|
+
};
|
|
1931
|
+
tls: {
|
|
1932
|
+
trust: "secret" | "system" | "spki";
|
|
1933
|
+
serverName?: string | undefined;
|
|
1934
|
+
caSecretRef?: string | undefined;
|
|
1935
|
+
spkiSha256?: string | undefined;
|
|
1936
|
+
};
|
|
1937
|
+
healthGate: {
|
|
1938
|
+
timeoutSeconds: number;
|
|
1939
|
+
protocol: "http" | "tcp" | "https";
|
|
1940
|
+
path?: string | undefined;
|
|
1941
|
+
};
|
|
1942
|
+
}> | undefined;
|
|
1943
|
+
}>;
|
|
1944
|
+
network: {
|
|
1945
|
+
manager: {
|
|
1946
|
+
binding: string;
|
|
1947
|
+
aliases?: string[] | undefined;
|
|
1948
|
+
sans?: string[] | undefined;
|
|
1949
|
+
trustedLanCidrs?: string[] | undefined;
|
|
1950
|
+
};
|
|
1951
|
+
};
|
|
1952
|
+
host: {
|
|
1953
|
+
id: string;
|
|
1954
|
+
role: string;
|
|
1955
|
+
architecture: "amd64";
|
|
1956
|
+
};
|
|
1957
|
+
generation: number;
|
|
1958
|
+
configurationId: string;
|
|
1959
|
+
updates: {
|
|
1960
|
+
development: {
|
|
1961
|
+
pollSeconds: 60;
|
|
1962
|
+
};
|
|
1963
|
+
stable: {
|
|
1964
|
+
metadataPollSeconds: number;
|
|
1965
|
+
maintenanceWindow: {
|
|
1966
|
+
weekday: "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday";
|
|
1967
|
+
localTime: string;
|
|
1968
|
+
jitterMinutes: number;
|
|
1969
|
+
};
|
|
1970
|
+
};
|
|
1971
|
+
defaultTrack: "development" | "stable";
|
|
1972
|
+
};
|
|
1973
|
+
fleet: {
|
|
1974
|
+
rolloutGroup: string;
|
|
1975
|
+
receiptReporting: {
|
|
1976
|
+
enabled: boolean;
|
|
1977
|
+
intervalSeconds: number;
|
|
1978
|
+
connection?: {
|
|
1979
|
+
kind: "local";
|
|
1980
|
+
componentId: string;
|
|
1981
|
+
serviceId: string;
|
|
1982
|
+
endpointId: string;
|
|
1983
|
+
} | {
|
|
1984
|
+
kind: "remote";
|
|
1985
|
+
audience: string;
|
|
1986
|
+
url: string;
|
|
1987
|
+
authentication: {
|
|
1988
|
+
mode: "none" | "application" | "mtls" | "bearer";
|
|
1989
|
+
secretRef?: string | undefined;
|
|
1990
|
+
};
|
|
1991
|
+
tls: {
|
|
1992
|
+
trust: "secret" | "system" | "spki";
|
|
1993
|
+
serverName?: string | undefined;
|
|
1994
|
+
caSecretRef?: string | undefined;
|
|
1995
|
+
spkiSha256?: string | undefined;
|
|
1996
|
+
};
|
|
1997
|
+
healthGate: {
|
|
1998
|
+
timeoutSeconds: number;
|
|
1999
|
+
protocol: "http" | "tcp" | "https";
|
|
2000
|
+
path?: string | undefined;
|
|
2001
|
+
};
|
|
2002
|
+
} | undefined;
|
|
2003
|
+
};
|
|
2004
|
+
};
|
|
2005
|
+
secrets: Record<string, {
|
|
2006
|
+
provider: "file" | "systemd-credential";
|
|
2007
|
+
reference: string;
|
|
2008
|
+
}>;
|
|
2009
|
+
postgres?: {
|
|
2010
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
2011
|
+
environment: "production" | "staging";
|
|
2012
|
+
installationId: string;
|
|
2013
|
+
servers: {
|
|
2014
|
+
id: string;
|
|
2015
|
+
mode: "shared" | "dedicated" | "external";
|
|
2016
|
+
environment: "production" | "staging";
|
|
2017
|
+
port: number;
|
|
2018
|
+
major: number;
|
|
2019
|
+
extensions: string[];
|
|
2020
|
+
installationId: string;
|
|
2021
|
+
hostname: string;
|
|
2022
|
+
tls: {
|
|
2023
|
+
mode: "verify-full";
|
|
2024
|
+
trustReference: string;
|
|
2025
|
+
};
|
|
2026
|
+
}[];
|
|
2027
|
+
requirements: {
|
|
2028
|
+
id: string;
|
|
2029
|
+
componentId: string;
|
|
2030
|
+
enabled: boolean;
|
|
2031
|
+
supportedMajors: [number, ...number[]];
|
|
2032
|
+
extensions: string[];
|
|
2033
|
+
runtimeConnectionLimit: number;
|
|
2034
|
+
}[];
|
|
2035
|
+
allocations: {
|
|
2036
|
+
requirementId: string;
|
|
2037
|
+
serverId: string;
|
|
2038
|
+
database: string;
|
|
2039
|
+
ownerRole: string;
|
|
2040
|
+
migrationRole: string;
|
|
2041
|
+
runtimeRole: string;
|
|
2042
|
+
migrationCredentialReference: string;
|
|
2043
|
+
runtimeCredentialReference: string;
|
|
2044
|
+
onDisable: "preserve";
|
|
2045
|
+
}[];
|
|
2046
|
+
} | undefined;
|
|
2047
|
+
security?: {
|
|
2048
|
+
sandbox: {
|
|
2049
|
+
runtime: "kata-runtime-rs-qemu";
|
|
2050
|
+
profiles: {
|
|
2051
|
+
id: string;
|
|
2052
|
+
guestImage: string;
|
|
2053
|
+
guestImageDigest: string;
|
|
2054
|
+
}[];
|
|
2055
|
+
required: boolean;
|
|
2056
|
+
brokerSocket: string;
|
|
2057
|
+
modelGateway: {
|
|
2058
|
+
provider: "openai";
|
|
2059
|
+
upstreamBaseUrl: "https://api.openai.com";
|
|
2060
|
+
allowedModels: string[];
|
|
2061
|
+
};
|
|
2062
|
+
};
|
|
2063
|
+
providerVolume: {
|
|
2064
|
+
encryption: "luks2";
|
|
2065
|
+
backingPath: string;
|
|
2066
|
+
mountPath: string;
|
|
2067
|
+
sizeBytes: number;
|
|
2068
|
+
unlock: "systemd-credential" | "tpm2";
|
|
2069
|
+
recoveryRequired: true;
|
|
2070
|
+
};
|
|
2071
|
+
applicationEncryption: {
|
|
2072
|
+
provider: "systemd-credential";
|
|
2073
|
+
activeKeyVersion: number;
|
|
2074
|
+
diagnosticsKeyVersion: number;
|
|
2075
|
+
};
|
|
2076
|
+
} | undefined;
|
|
2077
|
+
}>, {
|
|
2078
|
+
schemaVersion: "treeseed.host/v1";
|
|
2079
|
+
runtime: {
|
|
2080
|
+
environment: "development" | "production";
|
|
2081
|
+
management: "external" | "managed";
|
|
2082
|
+
dataRoot?: string | undefined;
|
|
2083
|
+
};
|
|
2084
|
+
components: Record<string, {
|
|
2085
|
+
resources: {
|
|
2086
|
+
gpuDevices: string[];
|
|
2087
|
+
cpuCores?: number | undefined;
|
|
2088
|
+
memoryBytes?: number | undefined;
|
|
2089
|
+
storageBytes?: number | undefined;
|
|
2090
|
+
};
|
|
2091
|
+
enabled: boolean;
|
|
2092
|
+
track: "development" | "stable";
|
|
2093
|
+
aliases: Record<string, string>;
|
|
2094
|
+
configuration: Record<string, unknown>;
|
|
2095
|
+
connections: Record<string, {
|
|
2096
|
+
kind: "local";
|
|
2097
|
+
componentId: string;
|
|
2098
|
+
serviceId: string;
|
|
2099
|
+
endpointId: string;
|
|
2100
|
+
} | {
|
|
2101
|
+
kind: "remote";
|
|
2102
|
+
audience: string;
|
|
2103
|
+
url: string;
|
|
2104
|
+
authentication: {
|
|
2105
|
+
mode: "none" | "application" | "mtls" | "bearer";
|
|
2106
|
+
secretRef?: string | undefined;
|
|
2107
|
+
};
|
|
2108
|
+
tls: {
|
|
2109
|
+
trust: "secret" | "system" | "spki";
|
|
2110
|
+
serverName?: string | undefined;
|
|
2111
|
+
caSecretRef?: string | undefined;
|
|
2112
|
+
spkiSha256?: string | undefined;
|
|
2113
|
+
};
|
|
2114
|
+
healthGate: {
|
|
2115
|
+
timeoutSeconds: number;
|
|
2116
|
+
protocol: "http" | "tcp" | "https";
|
|
2117
|
+
path?: string | undefined;
|
|
2118
|
+
};
|
|
2119
|
+
}>;
|
|
2120
|
+
profile?: string | undefined;
|
|
2121
|
+
}>;
|
|
2122
|
+
network: {
|
|
2123
|
+
manager: {
|
|
2124
|
+
aliases: string[];
|
|
2125
|
+
binding: string;
|
|
2126
|
+
sans: string[];
|
|
2127
|
+
trustedLanCidrs: string[];
|
|
2128
|
+
};
|
|
2129
|
+
};
|
|
2130
|
+
host: {
|
|
2131
|
+
id: string;
|
|
2132
|
+
role: string;
|
|
2133
|
+
architecture: "amd64";
|
|
2134
|
+
};
|
|
2135
|
+
generation: number;
|
|
2136
|
+
configurationId: string;
|
|
2137
|
+
updates: {
|
|
2138
|
+
development: {
|
|
2139
|
+
pollSeconds: 60;
|
|
2140
|
+
};
|
|
2141
|
+
stable: {
|
|
2142
|
+
metadataPollSeconds: number;
|
|
2143
|
+
maintenanceWindow: {
|
|
2144
|
+
weekday: "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday";
|
|
2145
|
+
localTime: string;
|
|
2146
|
+
jitterMinutes: number;
|
|
2147
|
+
};
|
|
2148
|
+
};
|
|
2149
|
+
defaultTrack: "development" | "stable";
|
|
2150
|
+
};
|
|
2151
|
+
fleet: {
|
|
2152
|
+
rolloutGroup: string;
|
|
2153
|
+
receiptReporting: {
|
|
2154
|
+
enabled: boolean;
|
|
2155
|
+
intervalSeconds: number;
|
|
2156
|
+
connection?: {
|
|
2157
|
+
kind: "local";
|
|
2158
|
+
componentId: string;
|
|
2159
|
+
serviceId: string;
|
|
2160
|
+
endpointId: string;
|
|
2161
|
+
} | {
|
|
2162
|
+
kind: "remote";
|
|
2163
|
+
audience: string;
|
|
2164
|
+
url: string;
|
|
2165
|
+
authentication: {
|
|
2166
|
+
mode: "none" | "application" | "mtls" | "bearer";
|
|
2167
|
+
secretRef?: string | undefined;
|
|
2168
|
+
};
|
|
2169
|
+
tls: {
|
|
2170
|
+
trust: "secret" | "system" | "spki";
|
|
2171
|
+
serverName?: string | undefined;
|
|
2172
|
+
caSecretRef?: string | undefined;
|
|
2173
|
+
spkiSha256?: string | undefined;
|
|
2174
|
+
};
|
|
2175
|
+
healthGate: {
|
|
2176
|
+
timeoutSeconds: number;
|
|
2177
|
+
protocol: "http" | "tcp" | "https";
|
|
2178
|
+
path?: string | undefined;
|
|
2179
|
+
};
|
|
2180
|
+
} | undefined;
|
|
2181
|
+
};
|
|
2182
|
+
};
|
|
2183
|
+
secrets: Record<string, {
|
|
2184
|
+
provider: "file" | "systemd-credential";
|
|
2185
|
+
reference: string;
|
|
2186
|
+
}>;
|
|
2187
|
+
postgres?: {
|
|
2188
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
2189
|
+
environment: "production" | "staging";
|
|
2190
|
+
installationId: string;
|
|
2191
|
+
servers: {
|
|
2192
|
+
id: string;
|
|
2193
|
+
mode: "shared" | "dedicated" | "external";
|
|
2194
|
+
environment: "production" | "staging";
|
|
2195
|
+
port: number;
|
|
2196
|
+
major: number;
|
|
2197
|
+
extensions: string[];
|
|
2198
|
+
installationId: string;
|
|
2199
|
+
hostname: string;
|
|
2200
|
+
tls: {
|
|
2201
|
+
mode: "verify-full";
|
|
2202
|
+
trustReference: string;
|
|
2203
|
+
};
|
|
2204
|
+
}[];
|
|
2205
|
+
requirements: {
|
|
2206
|
+
id: string;
|
|
2207
|
+
componentId: string;
|
|
2208
|
+
enabled: boolean;
|
|
2209
|
+
supportedMajors: [number, ...number[]];
|
|
2210
|
+
extensions: string[];
|
|
2211
|
+
runtimeConnectionLimit: number;
|
|
2212
|
+
}[];
|
|
2213
|
+
allocations: {
|
|
2214
|
+
requirementId: string;
|
|
2215
|
+
serverId: string;
|
|
2216
|
+
database: string;
|
|
2217
|
+
ownerRole: string;
|
|
2218
|
+
migrationRole: string;
|
|
2219
|
+
runtimeRole: string;
|
|
2220
|
+
migrationCredentialReference: string;
|
|
2221
|
+
runtimeCredentialReference: string;
|
|
2222
|
+
onDisable: "preserve";
|
|
2223
|
+
}[];
|
|
2224
|
+
} | undefined;
|
|
1559
2225
|
security?: {
|
|
1560
2226
|
sandbox: {
|
|
1561
2227
|
runtime: "kata-runtime-rs-qemu";
|
|
@@ -1696,6 +2362,44 @@ export declare const hostConfigurationSchema: z.ZodObject<{
|
|
|
1696
2362
|
provider: "file" | "systemd-credential";
|
|
1697
2363
|
reference: string;
|
|
1698
2364
|
}>;
|
|
2365
|
+
postgres?: {
|
|
2366
|
+
schemaVersion: "treeseed.postgres-topology/v1";
|
|
2367
|
+
environment: "production" | "staging";
|
|
2368
|
+
installationId: string;
|
|
2369
|
+
servers: {
|
|
2370
|
+
id: string;
|
|
2371
|
+
mode: "shared" | "dedicated" | "external";
|
|
2372
|
+
environment: "production" | "staging";
|
|
2373
|
+
port: number;
|
|
2374
|
+
major: number;
|
|
2375
|
+
extensions: string[];
|
|
2376
|
+
installationId: string;
|
|
2377
|
+
hostname: string;
|
|
2378
|
+
tls: {
|
|
2379
|
+
mode: "verify-full";
|
|
2380
|
+
trustReference: string;
|
|
2381
|
+
};
|
|
2382
|
+
}[];
|
|
2383
|
+
requirements: {
|
|
2384
|
+
id: string;
|
|
2385
|
+
componentId: string;
|
|
2386
|
+
enabled: boolean;
|
|
2387
|
+
supportedMajors: [number, ...number[]];
|
|
2388
|
+
extensions: string[];
|
|
2389
|
+
runtimeConnectionLimit: number;
|
|
2390
|
+
}[];
|
|
2391
|
+
allocations: {
|
|
2392
|
+
requirementId: string;
|
|
2393
|
+
serverId: string;
|
|
2394
|
+
database: string;
|
|
2395
|
+
ownerRole: string;
|
|
2396
|
+
migrationRole: string;
|
|
2397
|
+
runtimeRole: string;
|
|
2398
|
+
migrationCredentialReference: string;
|
|
2399
|
+
runtimeCredentialReference: string;
|
|
2400
|
+
onDisable: "preserve";
|
|
2401
|
+
}[];
|
|
2402
|
+
} | undefined;
|
|
1699
2403
|
security?: {
|
|
1700
2404
|
sandbox: {
|
|
1701
2405
|
runtime: "kata-runtime-rs-qemu";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { AI_MODE_INTERNAL_PATH } from "./ai-mode.js";
|
|
3
|
-
import { postgresComponentRequirementSchema } from "./postgres/contracts.js";
|
|
3
|
+
import { postgresComponentRequirementSchema, postgresTopologySchema } from "./postgres/contracts.js";
|
|
4
4
|
const identifier = z.string().regex(/^[a-z][a-z0-9.-]{1,63}$/u);
|
|
5
5
|
const digest = z.string().regex(/^sha256:[a-f0-9]{64}$/u);
|
|
6
6
|
const gitCommit = z.string().regex(/^[a-f0-9]{40}$/u);
|
|
@@ -121,6 +121,7 @@ const hostConfigurationSchema = z.object({
|
|
|
121
121
|
development: z.object({ pollSeconds: z.literal(60) }).strict()
|
|
122
122
|
}).strict(),
|
|
123
123
|
components: z.record(identifier, hostComponentSchema),
|
|
124
|
+
postgres: postgresTopologySchema.optional(),
|
|
124
125
|
network: z.object({
|
|
125
126
|
manager: z.object({ binding, aliases: z.array(localAlias).default([]), sans: z.array(z.string().min(1)).default([]), trustedLanCidrs: z.array(z.string().min(1)).default([]) }).strict()
|
|
126
127
|
}).strict(),
|
|
@@ -149,7 +150,21 @@ const hostConfigurationSchema = z.object({
|
|
|
149
150
|
providerVolume: z.object({ encryption: z.literal("luks2"), backingPath: z.string().startsWith("/"), mountPath: z.string().startsWith("/"), sizeBytes: z.number().int().min(1073741824), unlock: z.enum(["tpm2", "systemd-credential"]), recoveryRequired: z.literal(true) }).strict(),
|
|
150
151
|
applicationEncryption: z.object({ provider: z.literal("systemd-credential"), activeKeyVersion: z.number().int().positive(), diagnosticsKeyVersion: z.number().int().positive() }).strict()
|
|
151
152
|
}).strict().optional()
|
|
152
|
-
}).strict()
|
|
153
|
+
}).strict().superRefine((host, context) => {
|
|
154
|
+
if (!host.postgres) return;
|
|
155
|
+
const fail = (message) => context.addIssue({ code: z.ZodIssueCode.custom, path: ["postgres"], message });
|
|
156
|
+
for (const requirement of host.postgres.requirements) {
|
|
157
|
+
if (!host.components[requirement.componentId] || host.components[requirement.componentId].enabled !== requirement.enabled) fail("Database requirements must match configured component activation.");
|
|
158
|
+
}
|
|
159
|
+
for (const allocation of host.postgres.allocations) {
|
|
160
|
+
if (!host.postgres.requirements.find((item) => item.id === allocation.requirementId)?.enabled) continue;
|
|
161
|
+
for (const reference of [allocation.migrationCredentialReference, allocation.runtimeCredentialReference]) {
|
|
162
|
+
if (host.secrets[reference]?.provider !== "systemd-credential" || host.secrets[reference]?.reference !== `/etc/treeseed/credentials/${reference}.cred`) fail("Database credentials require explicit fixed OS custody bindings.");
|
|
163
|
+
}
|
|
164
|
+
const server = host.postgres.servers.find((item) => item.id === allocation.serverId);
|
|
165
|
+
if (server.mode !== "external" && !host.components.postgres?.enabled) fail("Managed database allocations require the PostgreSQL component.");
|
|
166
|
+
}
|
|
167
|
+
});
|
|
153
168
|
const packageEndpointSchema = z.object({
|
|
154
169
|
id: identifier,
|
|
155
170
|
protocol: z.enum(["http", "https", "tcp"]),
|