1#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2pub struct ToolchainPackageSpec {
3 pub crate_name: &'static str,
4 pub bins: &'static [&'static str],
5}
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct OciPackageSpec {
9 pub package: &'static str,
10}
11
12pub const GREENTIC_TOOLCHAIN_PACKAGES: &[ToolchainPackageSpec] = &[
13 ToolchainPackageSpec {
14 crate_name: "greentic-dev",
15 bins: &["greentic-dev"],
16 },
17 ToolchainPackageSpec {
18 crate_name: "greentic-operator",
19 bins: &["greentic-operator"],
20 },
21 ToolchainPackageSpec {
22 crate_name: "greentic-bundle",
23 bins: &["greentic-bundle"],
24 },
25 ToolchainPackageSpec {
26 crate_name: "greentic-setup",
27 bins: &["greentic-setup"],
28 },
29 ToolchainPackageSpec {
30 crate_name: "greentic-start",
31 bins: &["greentic-start"],
32 },
33 ToolchainPackageSpec {
34 crate_name: "greentic-deployer",
35 bins: &["greentic-deployer"],
36 },
37 ToolchainPackageSpec {
38 crate_name: "greentic-component",
39 bins: &["greentic-component"],
40 },
41 ToolchainPackageSpec {
42 crate_name: "greentic-flow",
43 bins: &["greentic-flow"],
44 },
45 ToolchainPackageSpec {
46 crate_name: "greentic-pack",
47 bins: &["greentic-pack"],
48 },
49 ToolchainPackageSpec {
50 crate_name: "greentic-runner",
51 bins: &["greentic-runner"],
52 },
53 ToolchainPackageSpec {
54 crate_name: "greentic-gui",
55 bins: &["greentic-gui"],
56 },
57 ToolchainPackageSpec {
58 crate_name: "greentic-secrets",
59 bins: &["greentic-secrets"],
60 },
61 ToolchainPackageSpec {
62 crate_name: "greentic-mcp",
63 bins: &["greentic-mcp"],
64 },
65];
66
67pub const GREENTIC_EXTENSION_PACK_PACKAGES: &[OciPackageSpec] = &[
68 OciPackageSpec {
69 package: "packs/demos/cards-demo",
70 },
71 OciPackageSpec {
72 package: "packs/demos/cloud-deploy-demo-app",
73 },
74 OciPackageSpec {
75 package: "packs/demos/deep-research-demo",
76 },
77 OciPackageSpec {
78 package: "packs/demos/helpdesk-itsm",
79 },
80 OciPackageSpec {
81 package: "packs/demos/hr-onboarding",
82 },
83 OciPackageSpec {
84 package: "packs/demos/incident-demo",
85 },
86 OciPackageSpec {
87 package: "packs/demos/quickstart",
88 },
89 OciPackageSpec {
90 package: "packs/demos/quickstart-event",
91 },
92 OciPackageSpec {
93 package: "packs/demos/redbutton-demo",
94 },
95 OciPackageSpec {
96 package: "packs/demos/sales-crm",
97 },
98 OciPackageSpec {
99 package: "packs/demos/supply-chain",
100 },
101 OciPackageSpec {
102 package: "packs/demos/telco-x",
103 },
104 OciPackageSpec {
105 package: "packs/demos/weather-mcp-demo",
106 },
107 OciPackageSpec {
108 package: "packs/demos/weatherapi-pack",
109 },
110 OciPackageSpec {
111 package: "packs/deployer/greentic.deploy.gcp",
112 },
113 OciPackageSpec {
114 package: "packs/deployer/greentic.deploy.azure",
115 },
116 OciPackageSpec {
117 package: "packs/deployer/greentic.deploy.aws",
118 },
119 OciPackageSpec {
120 package: "packs/deployer/greentic.deploy.helm",
121 },
122 OciPackageSpec {
123 package: "packs/deployer/greentic.deploy.juju-k8s",
124 },
125 OciPackageSpec {
126 package: "packs/deployer/greentic.deploy.juju-machine",
127 },
128 OciPackageSpec {
129 package: "packs/deployer/greentic.deploy.k8s-raw",
130 },
131 OciPackageSpec {
132 package: "packs/deployer/greentic.deploy.serverless",
133 },
134 OciPackageSpec {
135 package: "packs/deployer/greentic.deploy.snap",
136 },
137 OciPackageSpec {
138 package: "packs/deployer/greentic.deploy.terraform",
139 },
140 OciPackageSpec {
141 package: "packs/dw/context/compressor-pack",
142 },
143 OciPackageSpec {
144 package: "packs/dw/context/retrieval-pack",
145 },
146 OciPackageSpec {
147 package: "packs/dw/context/static-pack",
148 },
149 OciPackageSpec {
150 package: "packs/dw/control/basic-policy-pack",
151 },
152 OciPackageSpec {
153 package: "packs/dw/control/delegation-guard-pack",
154 },
155 OciPackageSpec {
156 package: "packs/dw/delegation/capability-match-pack",
157 },
158 OciPackageSpec {
159 package: "packs/dw/delegation/static-router-pack",
160 },
161 OciPackageSpec {
162 package: "packs/dw/engine/default-pack",
163 },
164 OciPackageSpec {
165 package: "packs/dw/engine/router-lite-pack",
166 },
167 OciPackageSpec {
168 package: "packs/dw/memory/short-term-in-memory-pack",
169 },
170 OciPackageSpec {
171 package: "packs/dw/memory/short-term-redis-pack",
172 },
173 OciPackageSpec {
174 package: "packs/dw/observer/basic-audit-pack",
175 },
176 OciPackageSpec {
177 package: "packs/dw/observer/basic-metrics-pack",
178 },
179 OciPackageSpec {
180 package: "packs/dw/planning/llm-outline-pack",
181 },
182 OciPackageSpec {
183 package: "packs/dw/planning/static-pack",
184 },
185 OciPackageSpec {
186 package: "packs/dw/reflection/llm-critic-pack",
187 },
188 OciPackageSpec {
189 package: "packs/dw/reflection/rules-pack",
190 },
191 OciPackageSpec {
192 package: "packs/dw/reflection/schema-check-pack",
193 },
194 OciPackageSpec {
195 package: "packs/dw/state/task-store-in-memory-pack",
196 },
197 OciPackageSpec {
198 package: "packs/dw/state/task-store-redis-pack",
199 },
200 OciPackageSpec {
201 package: "packs/dw/tool/component-adapter-pack",
202 },
203 OciPackageSpec {
204 package: "packs/dw/tool/mcp-adapter-pack",
205 },
206 OciPackageSpec {
207 package: "packs/dw/workspace/fs-pack",
208 },
209 OciPackageSpec {
210 package: "packs/dw/workspace/in-memory-pack",
211 },
212 OciPackageSpec {
213 package: "packs/events/events-dummy",
214 },
215 OciPackageSpec {
216 package: "packs/events/events-email",
217 },
218 OciPackageSpec {
219 package: "packs/events/events-email-sendgrid",
220 },
221 OciPackageSpec {
222 package: "packs/events/events-sms",
223 },
224 OciPackageSpec {
225 package: "packs/events/events-sms-twilio",
226 },
227 OciPackageSpec {
228 package: "packs/events/events-timer",
229 },
230 OciPackageSpec {
231 package: "packs/events/events-webhook",
232 },
233 OciPackageSpec {
234 package: "packs/messaging/messaging-dummy",
235 },
236 OciPackageSpec {
237 package: "packs/messaging/messaging-email",
238 },
239 OciPackageSpec {
240 package: "packs/messaging/messaging-slack",
241 },
242 OciPackageSpec {
243 package: "packs/messaging/messaging-teams",
244 },
245 OciPackageSpec {
246 package: "packs/messaging/messaging-telegram",
247 },
248 OciPackageSpec {
249 package: "packs/messaging/messaging-webchat",
250 },
251 OciPackageSpec {
252 package: "packs/messaging/messaging-webchat-gui",
253 },
254 OciPackageSpec {
255 package: "packs/messaging/messaging-webex",
256 },
257 OciPackageSpec {
258 package: "packs/messaging/messaging-whatsapp",
259 },
260 OciPackageSpec {
261 package: "packs/oauth/oauth-github",
262 },
263 OciPackageSpec {
264 package: "packs/oauth/oauth-google",
265 },
266 OciPackageSpec {
267 package: "packs/oauth/oauth-microsoft-graph",
268 },
269 OciPackageSpec {
270 package: "packs/oauth/oauth-oidc-generic",
271 },
272 OciPackageSpec {
273 package: "packs/oauth/oauth-slack",
274 },
275 OciPackageSpec {
276 package: "packs/secret/greentic.secrets.aws-sm.gtpack",
277 },
278 OciPackageSpec {
279 package: "packs/secret/greentic.secrets.azure-kv.gtpack",
280 },
281 OciPackageSpec {
282 package: "packs/secret/greentic.secrets.gcp-sm.gtpack",
283 },
284 OciPackageSpec {
285 package: "packs/secret/greentic.secrets.k8s.gtpack",
286 },
287 OciPackageSpec {
288 package: "packs/secret/greentic.secrets.providers.gtpack",
289 },
290 OciPackageSpec {
291 package: "packs/secret/greentic.secrets.vault-kv.gtpack",
292 },
293 OciPackageSpec {
294 package: "packs/state-memory",
295 },
296 OciPackageSpec {
297 package: "packs/state-redis",
298 },
299 OciPackageSpec {
300 package: "packs/state/state-memory",
301 },
302 OciPackageSpec {
303 package: "packs/state/state-redis",
304 },
305];
306pub const GREENTIC_COMPONENT_PACKAGES: &[OciPackageSpec] = &[
307 OciPackageSpec {
308 package: "component/component-events2msg",
309 },
310 OciPackageSpec {
311 package: "component/component-http",
312 },
313 OciPackageSpec {
314 package: "component/component-llm-openai",
315 },
316 OciPackageSpec {
317 package: "component/component-msg2events",
318 },
319 OciPackageSpec {
320 package: "component/component-pack2flow",
321 },
322 OciPackageSpec {
323 package: "component/component-sorx-business",
324 },
325 OciPackageSpec {
326 package: "components/component-adaptive-card",
327 },
328 OciPackageSpec {
329 package: "components/component-qa",
330 },
331 OciPackageSpec {
332 package: "components/secrets-provider-inmemory",
333 },
334 OciPackageSpec {
335 package: "components/templates",
336 },
337];
338
339#[cfg(test)]
340mod tests {
341 use super::{
342 GREENTIC_COMPONENT_PACKAGES, GREENTIC_EXTENSION_PACK_PACKAGES, GREENTIC_TOOLCHAIN_PACKAGES,
343 OciPackageSpec,
344 };
345 use std::collections::BTreeSet;
346
347 #[test]
348 fn catalogue_contains_expected_public_toolchain() {
349 let expected = [
350 ("greentic-dev", "greentic-dev"),
351 ("greentic-operator", "greentic-operator"),
352 ("greentic-bundle", "greentic-bundle"),
353 ("greentic-setup", "greentic-setup"),
354 ("greentic-start", "greentic-start"),
355 ("greentic-deployer", "greentic-deployer"),
356 ("greentic-component", "greentic-component"),
357 ("greentic-flow", "greentic-flow"),
358 ("greentic-pack", "greentic-pack"),
359 ("greentic-runner", "greentic-runner"),
360 ("greentic-gui", "greentic-gui"),
361 ("greentic-secrets", "greentic-secrets"),
362 ("greentic-mcp", "greentic-mcp"),
363 ];
364
365 let actual = catalogue_pairs();
366 for pair in expected {
367 assert!(actual.contains(&pair), "missing {pair:?}");
368 }
369 }
370
371 #[test]
372 fn catalogue_has_no_duplicate_crate_bin_pairs() {
373 let mut seen = BTreeSet::new();
374 for package in GREENTIC_TOOLCHAIN_PACKAGES {
375 for bin in package.bins {
376 assert!(
377 seen.insert((package.crate_name, *bin)),
378 "duplicate crate/bin pair: {}/{}",
379 package.crate_name,
380 bin
381 );
382 }
383 }
384 }
385
386 #[test]
387 fn extension_pack_catalogue_tracks_github_packages() {
388 assert_eq!(GREENTIC_EXTENSION_PACK_PACKAGES.len(), 79);
389 assert_catalogue_has_no_duplicate_packages(GREENTIC_EXTENSION_PACK_PACKAGES);
390 assert!(GREENTIC_EXTENSION_PACK_PACKAGES.iter().all(|package| {
391 package.package.starts_with("packs/") || package.package.starts_with("greentic-bundle/")
392 }));
393 assert!(
394 GREENTIC_EXTENSION_PACK_PACKAGES
395 .iter()
396 .any(|package| package.package == "packs/deployer/greentic.deploy.aws")
397 );
398 assert!(
399 GREENTIC_EXTENSION_PACK_PACKAGES
400 .iter()
401 .any(|package| package.package == "packs/deployer/greentic.deploy.helm")
402 );
403 assert!(GREENTIC_EXTENSION_PACK_PACKAGES.iter().all(|package| {
404 !package
405 .package
406 .starts_with("packs/deployer/greentic.fixture.")
407 }));
408 assert!(
409 GREENTIC_EXTENSION_PACK_PACKAGES
410 .iter()
411 .any(|package| package.package == "packs/messaging/messaging-webchat-gui")
412 );
413 assert!(
414 GREENTIC_EXTENSION_PACK_PACKAGES
415 .iter()
416 .any(|package| package.package == "packs/oauth/oauth-microsoft-graph")
417 );
418 }
419
420 #[test]
421 fn component_catalogue_tracks_github_packages() {
422 assert_eq!(GREENTIC_COMPONENT_PACKAGES.len(), 10);
423 assert_catalogue_has_no_duplicate_packages(GREENTIC_COMPONENT_PACKAGES);
424 assert!(GREENTIC_COMPONENT_PACKAGES.iter().all(|package| {
425 package.package.starts_with("component/")
426 || package.package.starts_with("components/")
427 || package.package.starts_with("validators/")
428 }));
429 assert!(
430 GREENTIC_COMPONENT_PACKAGES
431 .iter()
432 .any(|package| package.package == "component/component-llm-openai")
433 );
434 assert!(
435 GREENTIC_COMPONENT_PACKAGES
436 .iter()
437 .any(|package| package.package == "component/component-sorx-business")
438 );
439 assert!(
440 GREENTIC_COMPONENT_PACKAGES
441 .iter()
442 .any(|package| package.package == "components/component-adaptive-card")
443 );
444 }
445
446 fn catalogue_pairs() -> BTreeSet<(&'static str, &'static str)> {
447 GREENTIC_TOOLCHAIN_PACKAGES
448 .iter()
449 .flat_map(|package| {
450 package
451 .bins
452 .iter()
453 .map(move |bin| (package.crate_name, *bin))
454 })
455 .collect()
456 }
457
458 fn assert_catalogue_has_no_duplicate_packages(catalogue: &[OciPackageSpec]) {
459 let mut seen = BTreeSet::new();
460 for package in catalogue {
461 assert!(
462 seen.insert(package.package),
463 "duplicate package: {}",
464 package.package
465 );
466 }
467 }
468}