Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ export const assistantKnowledgeTopics = {
sha256:
"27b7edb026926aef1b6efb4f8e2c131d43a37afb2abaa78f0d600006a5f4a492",
},
{
path: "landing-zone-configurator/app/apps/api/src/assistant/knowledge.ts",
sha256:
"c358064444175a090d7dfb66072938a08056e301b54ba7e88d6f4d0e585e9732",
},
{
path: "src/modules/landing-zone/3-network.tf",
sha256:
"0f37a5a088f8555a2c3019d63c2a1b4087aab032bd2fb455d391726deb953471",
},
{
path: "landing-zone-configurator/app/apps/api/src/assistant/editor.ts",
sha256:
Expand Down Expand Up @@ -1575,7 +1585,7 @@ export const assistantKnowledgeTopics = {
{
path: "landing-zone-configurator/app/apps/api/src/assistant/knowledge.ts",
sha256:
"ccd2476d56f940f345fadffcb3c3010c7a9c1befa134f8ffef1426e596c452f3",
"c358064444175a090d7dfb66072938a08056e301b54ba7e88d6f4d0e585e9732",
},
{
path: "landing-zone-configurator/docs/application-execution-lifecycle.md",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ export const assistantApplicationUpgradeAdvice = {
} as const;

const fieldOverviewNotes: Record<string, string> = {
"stackit-network-components":
"STACKIT Network Area (SNA) verbindet Projekte zentral; kein AWS VPC, Shared VPC oder Direct Connect. Native Formen sind connectivity.network_area für eine einzelne Area, connectivity.network_areas als Map mit stabilen Schlüsseln und connectivity_regions für regionale Konfigurationen. Formen nicht mischen; bestehende referenzierte Area-Schlüssel erhalten. Corporate-Projekte wählen über network_area_key eine Area derselben Region. Eine SNA aktiviert weder Firewall noch VPN automatisch; OPNsense-Firewall, Routing/Policy und VPN bleiben getrennt. Für reine SNA-interne Kommunikation ist kein VPN nötig.\n\nFelder: ranges ist eine Liste von IPv4-CIDRs; transfer_network ein IPv4-CIDR für das Transfernetz. Die Map kann zusätzlich name enthalten. min_prefix_length, default_prefix_length und max_prefix_length sind ganzzahlige Präfixlängen von 0 bis 32 mit min_prefix_length <= default_prefix_length <= max_prefix_length. Native Defaults: min_prefix_length=24, default_prefix_length=28, max_prefix_length=28; kleinere Präfixzahl bedeutet größeres Netz. default_nameservers überschreibt die Resolver explizit; bei null/fehlendem Wert gelten die regional bekannten STACKIT-Resolver. Für eine unbekannte Region müssen Resolver explizit angegeben werden. Resolver sind keine autoritative DNS-Zone.\n\nCorporate network_prefix_length=null (Automatisch) liest beim Plan den tatsächlichen default_prefix_length der angebundenen regionalen SNA und gibt einen numerischen Präfix an den Provider weiter; vorhandene DNS-Einstellungen bleiben erhalten. Ein expliziter Projektpräfix geht vor. Schema-Default /28 beweist keinen aktuellen Cloud-Wert und erzwingt keine Projektgröße.\n\nKapazität ist zunächst Rechenmodell: Ein /16 enthält 2^(24-16)=256 /24-Netze beziehungsweise 512 /25-Netze, vor Reservierungen. Ein /25 enthält 128 IPv4-Adressen, nicht 128 Projekt-Subnetze. Transfer-, Plattform- und Firewall-Netze sowie bestehende Belegung reduzieren nutzbare Kapazität. Automatisch garantiert weder freie Adressen noch Quoten, Überlappungsfreiheit oder Erreichbarkeit. Freie Pools, Reservierungen, tatsächliche Nutzung und Berechtigungen separat prüfen. Nur Übersicht: keine Änderungen, noch nichts gespeichert oder ausgeführt. Keine Zugangsdaten oder IDs erforderlich; Plan und ausdrücklich freigegebener Apply bleiben separat.",
"firewall-access-bootstrap":
"Native Referenzfelder sind firewall_admin_username, firewall_admin_password, firewall_api_credentials mit api_key/api_secret, firewall_bootstrap und firewall_api_secret_version. Infrastruktur, API-Bootstrap und Policy bleiben getrennte Phasen. Adminlogin leitet nativ einen API-Key ab; API-Key/API-Secret sind eigene API-Zugänge. Im Chat nur den Betriebsbedarf klären; keine Passwörter, API-Schlüssel, Secret-Version-IDs oder Credential-Dateien anfordern, lesen oder ausgeben. Das geschützte Configurator-Zugangsprofil bindet vorhandene OPNsense-Administrationsdaten für autorisierte HA-Jobs. Es aktiviert weder API-Bootstrap noch Firewall-Policy; Zugänge werden separat gebunden, nicht durch Entwurfsübernahme freigegeben. HA benötigt passenden Zugang zu Primary und Backup; Erreichbarkeit und Failover bleiben separat zu prüfen. Nativer API-Bootstrap ist eine eigene Operator-Phase für die einzelne connectivity.firewall, keine generische Map-/Regional-/Multi-Appliance-Unterstützung. firewall_bootstrap ist ein boolescher Phasenschalter. Native API-Zugänge haben die Reihenfolge externe firewall_api_credentials, lokaler Bootstrap-Cache, Management-Secrets-Manager/Vault. Ein lokaler Credential-Cache ist ein sensibler Ausführungseffekt, kein Chat- oder Vorlagenvorgang. Auf einer bestehenden Installation kann erneuter Bootstrap ohne Cache die Löschung von Policy und gespeichertem Schlüssel planen; nicht blind erneut aktivieren. firewall_api_secret_version steuert die native Write-Version, kein vom Assistant zu erratender Secret-Verweis. firewall_config und seine tatsächlichen Bootstrap-/Secret-Prädikate bestimmen die separate Policy-Aktivierung; firewall_bootstrap=false allein beweist keine vollständigen Voraussetzungen. Nativer Bootstrap verwendet --insecure, der Provider kann TLS-Prüfung überspringen. Das bestätigt kein vertrauenswürdiges TLS-Zertifikat und keine sichere Produktionsvorgabe; TLS-Vertrauen, Provider-/Appliance-Zugang und Management-Secrets gesondert prüfen. Chat und Entwurfsübernahme rotieren keine Credentials und gewähren keine Ausführungszusage. Nur Übersicht: nichts geändert; noch nichts gespeichert oder ausgeführt. Plan und ausdrücklich freigegebener Apply bleiben separat.",
"platform-kubernetes":
Expand Down
15 changes: 15 additions & 0 deletions landing-zone-configurator/app/scripts/assistant-scenarios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@ const questions: Record<string, string> = {
};

const overviewFields: Record<string, readonly string[]> = {
"stackit-network-components": [
"connectivity.network_area",
"connectivity.network_areas",
"connectivity_regions",
"ranges",
"transfer_network",
"min_prefix_length",
"default_prefix_length",
"max_prefix_length",
"default_nameservers",
"region",
"ipv4",
],
"platform-kubernetes": [
"platform_kubernetes",
"region",
Expand Down Expand Up @@ -1987,6 +2000,8 @@ export function validateAssistantScenario(
)
)
failures.push("incomplete_native_field_overview");
if (scenario.requiredOverviewFields && dialogue.questions.length)
failures.push("native_field_overview_asked_setup_questions");
if (
scenario.id === "platform-kubernetes-advice" &&
(!/kubeconfig|kube_config/i.test(dialogue.explanation) ||
Expand Down
28 changes: 28 additions & 0 deletions landing-zone-configurator/app/tests/assistant-scenarios.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1043,3 +1043,31 @@ it.each([
);
},
);

it("rejects setup questions even when the SNA native overview is factually complete", () => {
const scenario = assistantScenarios.find(
(entry) => entry.id === "stackit-network-components-advice",
);
const explanation = buildAssistantKnowledge().topics.find(
(topic) => topic.id === "stackit-network-components",
)?.fieldOverview;
if (!scenario || !explanation) throw new Error("missing_sna_overview");
const input = {
explanation,
questions: [],
changes: [],
references: ["stackit-network-components"],
};
expect(validateAssistantScenario(scenario, input).failures).toEqual([]);
expect(
validateAssistantScenario(scenario, {
...input,
questions: [
{
path: "connectivity.network_areas",
text: "Welchen freien Adresspool möchtest du verwenden?",
},
],
}).failures,
).toEqual(["native_field_overview_asked_setup_questions"]);
});
83 changes: 80 additions & 3 deletions landing-zone-configurator/app/tests/assistant.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2582,6 +2582,7 @@ it.each([
"dns-zones",
"platform-kubernetes",
"firewall-access-bootstrap",
"stackit-network-components",
])(
"answers %s field overviews from reviewed native metadata, not incomplete model prose",
async (topic) => {
Expand Down Expand Up @@ -2626,11 +2627,45 @@ it.each([
);
expect(result.explanation.length).toBeLessThanOrEqual(3000);
if (
["vpn", "devops-git", "dns-zones", "firewall-access-bootstrap"].includes(
topic,
)
[
"vpn",
"devops-git",
"dns-zones",
"firewall-access-bootstrap",
"stackit-network-components",
].includes(topic)
)
expect(result.explanation.length).toBeLessThanOrEqual(2400);
if (topic === "stackit-network-components") {
for (const fact of [
"connectivity.network_area",
"connectivity.network_areas",
"connectivity_regions",
"network_area_key",
"ranges",
"transfer_network",
"min_prefix_length=24",
"default_prefix_length=28",
"max_prefix_length=28",
"0 bis 32",
"min_prefix_length <= default_prefix_length <= max_prefix_length",
"default_nameservers",
"derselben Region",
"numerischen Präfix",
"DNS-Einstellungen bleiben erhalten",
"256 /24",
"512 /25",
"128 IPv4-Adressen",
"weder Firewall noch VPN automatisch",
"garantiert weder freie Adressen",
"Plattform- und Firewall-Netze",
"noch nichts gespeichert oder ausgeführt",
])
expect(result.explanation).toContain(fact);
expect(result.explanation).not.toMatch(
/PIM|Secret-Version|Wie viele|Welches Netz|AWS VPC wird erstellt/i,
);
}
if (topic === "vpn") {
for (const field of [
"routing_type=ROUTE_BASED",
Expand Down Expand Up @@ -3496,3 +3531,45 @@ it.each([
}
},
);

it.each([
{
topic: "stackit-network-components",
mode: "draft",
adviceTask: "field-overview",
},
{ topic: "stackit-network-components", mode: "advice", adviceTask: "other" },
{ topic: "identity-foundations", mode: "advice", adviceTask: "other" },
])(
"does not let historical SNA field advice intercept a current $mode/$topic/$adviceTask request",
async (intent) => {
const request = vi.fn<typeof fetch>(async (_url, init) => {
const body = JSON.parse(String(init?.body));
return body.response_format.json_schema.name === "conversation_intent"
? answer({ ...intent, adviceTaskSource: "current", requirements: [] })
: answer({
explanation: "Current scoped answer; no changes or execution.",
questions: [],
changes: [],
references: [intent.topic],
});
});
const result = await new AssistantModelServing(
configuration,
request,
).converse(
selection(),
{},
[
{ role: "user", content: "Welche SNA-Felder und Defaults gibt es?" },
{ role: "assistant", content: "Vorherige SNA-Feldübersicht." },
],
"Bitte beantworte jetzt mein anderes Anliegen.",
);
expect(result.explanation).toBe(
"Current scoped answer; no changes or execution.",
);
expect(result.explanation).not.toContain("min_prefix_length=24");
expect(request).toHaveBeenCalledTimes(2);
},
);
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,5 @@ Vorschlagsvalidierung und ausdrückliche Übernahme werden weiterhin geprüft.
Firewall-Zugangs-/Bootstrap-Übersichten nutzen nach semantischer Absichtserkennung ebenfalls geprüfte native Feldmetadaten und begrenzte Zugangs-/Phasenfakten. Dadurch entfällt für diese feste Übersicht ein zweiter generativer Aufruf. Admin-Anmeldung, API-Zugangsdaten und geschützte Operator-Bindungen bleiben getrennt; die Übersicht aktiviert keinen Bootstrap, liest keine Secrets und startet keine Ausführung. Andere Beratung bleibt im bisherigen themengebundenen Generierungspfad.

Beratung zu Template-Version, Plattformvertrag und Ausführungsquelle verwendet drei abgeschlossene semantische Aufgaben. Nur aktuelle Informationsfragen im Thema configuration-lifecycle wählen die geprüften, begrenzten Ablaufbeschreibungen; historische Absichten, Vorschlagsaufträge und andere Themen tun dies nicht. Diese Antworten erklären erhaltene Identitäten, ausdrückliche Bindung, frischen Plan und separaten Apply sowie die unterschiedlichen Grenzen gemeinsamer Plattform und Recovery ohne zweiten generativen Aufruf. Sie lesen oder verändern keine Bestellung. Andere Beratung behält die themengebundene Antwortgenerierung.

SNA-Feld-/Default-Beratung verwendet denselben geprüften Übersichtspfad: native Einzel-/Map-/Regionalformen, IPv4-Pools und Transfernetze, geordnete Subnetzpräfixe, Resolver-Defaults und regionale Corporate-Bezüge. Die Antwort enthält weder Einrichtungsfragebogen noch Entwurfsänderungen oder Kapazitäts-/Verfügbarkeitszusagen. SNA-Einrichtung und kombinierte Firewall-Aufträge behalten ihre bestehenden Vorschlags- und Umfangsprüfungen. Der echte Modellfall verlangt die nativen Felder und weist Einrichtungsrückfragen ab; eine Diagnoseantwort ist kein Qualifikationsnachweis.
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ contract. Transport tests check this instruction's delivery; real-model factual
criteria still decide whether the resulting answers qualify.
Firewall access/bootstrap workflow overviews also use reviewed native-field metadata and bounded access/phase facts after semantic intent classification. This avoids a second generative request for a static overview. Admin login, API credentials and secure operator bindings remain separate; the overview never activates bootstrap, reads secrets or starts execution. Other advice retains the normal scoped generation path.

SNA field/default advice uses the same reviewed overview path: native single/map/regional forms, IPv4 pools and transfer networks, ordered subnet prefixes, resolver defaults and same-region Corporate references. It returns no setup questionnaire, draft changes or capacity/availability promise. Actual SNA setup and combined firewall requests keep their existing proposal and scope guards. The real-model case requires the native fields and rejects follow-up setup questions; a diagnostic response is never qualification evidence.

Template-version, platform-contract and execution-source upgrade advice use three closed semantic tasks. Only current-turn configuration-lifecycle advice selects their reviewed, bounded workflow descriptions; historical intent, proposals and other topics do not. These responses explain retained identity, explicit binding, fresh Plan and separate Apply, plus the distinct shared-platform and recovery boundaries, without a second generative call. They never inspect or change an order. Other advice keeps scoped answer generation.

For native field overviews, semantic intent classification selects the existing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@
"src/modules/connectivity/variables.tf",
"src/modules/connectivity/1-network-area.tf",
"src/variables.tf",
"landing-zone-configurator/app/packages/domain/src/common-validation.ts"
"landing-zone-configurator/app/packages/domain/src/common-validation.ts",
"landing-zone-configurator/app/apps/api/src/assistant/knowledge.ts",
"src/modules/landing-zone/3-network.tf"
],
"externalSources": [
"https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/resources/network_area"
Expand Down
20 changes: 17 additions & 3 deletions landing-zone-configurator/docs/assistant-test-catalogue.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
"schemaVersion": 1,
"status": "field-inventory-and-smoke-corpus-not-ai-qualification",
"engineRevision": "a256f6896d11134fdc351786f1be5eba4e56b2e2",
"knowledgeSha256": "e914925b7e86158823c1560e813e5513429309e73eab7647d00f1dddd283f478",
"knowledgeSha256": "596f3e7562a51e62f09715c18a54bfb6cf66e553bd02f70e3b7bf03911ec03b3",
"sourceDigests": {
"scripts/assistant-scenarios.ts": "b5b8c87dd35f29d323823e0c4e837d01dd922da97f93c364bafd557d6e86721b",
"scripts/assistant-scenarios.ts": "8e6c928779971e649fcc225bb0b9983158d97233b83511fc549e4663c5f9f9f4",
"scripts/assistant-tests.ts": "5e19b1c74da1ffa996f2d76876cc8dc639da698d0b6f9b7e1fc6637863833a8d"
},
"suiteSha256": "f634d2c1bff93be543c831225a6335245fe0588e2a8634b3505efa5eaf52cc5a",
"suiteSha256": "0d8147826afcd7992e3b132ce26a833be2449668fbca0d77ef2813bbd87d58c5",
"topics": [
{
"id": "credential-foundations",
Expand Down Expand Up @@ -442,9 +442,23 @@
"topic": "stackit-network-components",
"message": "Welche Angaben benoetigst du fuer einen zentralen STACKIT Network Area mit Adresspool, Transfernetz, Projekt-Praefixen und Nameservern? Nur beraten, nichts aendern.",
"fixture": "baseline",
"requiredOverviewFields": [
"connectivity.network_area",
"connectivity.network_areas",
"connectivity_regions",
"ranges",
"transfer_network",
"min_prefix_length",
"default_prefix_length",
"max_prefix_length",
"default_nameservers",
"region",
"ipv4"
],
"assertions": [
"valid_dialogue",
"reviewed_topic_reference",
"complete_native_field_overview",
"no_changes"
]
},
Expand Down
Loading