@veltrixsecops/app-sdk 3.2.0 → 3.5.1
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/README.md +68 -1
- package/dist/byol/index.cjs +3802 -0
- package/dist/byol/index.cjs.map +1 -0
- package/dist/byol/index.d.cts +578 -0
- package/dist/byol/index.d.ts +578 -0
- package/dist/byol/index.js +2587 -0
- package/dist/byol/index.js.map +1 -0
- package/dist/chunk-3WK4EVQ3.js +842 -0
- package/dist/chunk-3WK4EVQ3.js.map +1 -0
- package/dist/{chunk-EOOEHZGC.js → chunk-HIL6RIDG.js} +107 -3
- package/dist/chunk-HIL6RIDG.js.map +1 -0
- package/dist/{chunk-VWFTOFTI.js → chunk-Y6XBNZGR.js} +8 -2
- package/dist/chunk-Y6XBNZGR.js.map +1 -0
- package/dist/client/index.cjs +112 -2
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +118 -6
- package/dist/client/index.d.ts +118 -6
- package/dist/client/index.js +13 -1
- package/dist/connections/index.cjs +1787 -0
- package/dist/connections/index.cjs.map +1 -0
- package/dist/connections/index.d.cts +78 -0
- package/dist/connections/index.d.ts +78 -0
- package/dist/connections/index.js +754 -0
- package/dist/connections/index.js.map +1 -0
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +2 -2
- package/dist/hooks/index.d.ts +2 -2
- package/dist/hooks/index.js +1 -1
- package/dist/index.cjs +7 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/opentofu/index.cjs +138 -0
- package/dist/opentofu/index.cjs.map +1 -0
- package/dist/opentofu/index.d.cts +131 -0
- package/dist/opentofu/index.d.ts +131 -0
- package/dist/opentofu/index.js +109 -0
- package/dist/opentofu/index.js.map +1 -0
- package/dist/pipeline/index.cjs +7 -0
- package/dist/pipeline/index.cjs.map +1 -1
- package/dist/pipeline/index.d.cts +9 -2
- package/dist/pipeline/index.d.ts +9 -2
- package/dist/pipeline/index.js +3 -1
- package/dist/pipeline-beeT8dje.d.cts +408 -0
- package/dist/pipeline-beeT8dje.d.ts +408 -0
- package/dist/ui/index.cjs +136 -0
- package/dist/ui/index.cjs.map +1 -1
- package/dist/ui/index.d.cts +109 -1
- package/dist/ui/index.d.ts +109 -1
- package/dist/ui/index.js +35 -677
- package/dist/ui/index.js.map +1 -1
- package/dist/{use-app-context-OQlcmq7t.d.cts → use-app-context-Byv_fam0.d.cts} +206 -4
- package/dist/{use-app-context-OQlcmq7t.d.ts → use-app-context-Byv_fam0.d.ts} +206 -4
- package/opentofu/README.md +114 -0
- package/opentofu/modules/aws/main.tf +1008 -0
- package/opentofu/modules/aws/outputs.tf +90 -0
- package/opentofu/modules/aws/variables.tf +437 -0
- package/opentofu/modules/aws/versions.tf +23 -0
- package/opentofu/modules/azure/main.tf +920 -0
- package/opentofu/modules/azure/outputs.tf +72 -0
- package/opentofu/modules/azure/variables.tf +498 -0
- package/opentofu/modules/azure/versions.tf +27 -0
- package/opentofu/modules/gcp/main.tf +645 -0
- package/opentofu/modules/gcp/outputs.tf +73 -0
- package/opentofu/modules/gcp/variables.tf +428 -0
- package/opentofu/modules/gcp/versions.tf +27 -0
- package/opentofu/modules/hetzner/main.tf +432 -0
- package/opentofu/modules/hetzner/outputs.tf +72 -0
- package/opentofu/modules/hetzner/variables.tf +423 -0
- package/opentofu/modules/hetzner/versions.tf +26 -0
- package/package.json +33 -1
- package/dist/chunk-EOOEHZGC.js.map +0 -1
- package/dist/chunk-VWFTOFTI.js.map +0 -1
- package/dist/pipeline-A-gSsPRR.d.cts +0 -189
- package/dist/pipeline-A-gSsPRR.d.ts +0 -189
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/opentofu/index.ts
|
|
21
|
+
var opentofu_exports = {};
|
|
22
|
+
__export(opentofu_exports, {
|
|
23
|
+
FOUNDATION_KINDS: () => FOUNDATION_KINDS,
|
|
24
|
+
renderInfraVars: () => renderInfraVars,
|
|
25
|
+
validateInfraSpec: () => validateInfraSpec
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(opentofu_exports);
|
|
28
|
+
|
|
29
|
+
// src/opentofu/spec.ts
|
|
30
|
+
var FOUNDATION_KINDS = [
|
|
31
|
+
"network",
|
|
32
|
+
"storage",
|
|
33
|
+
"secrets",
|
|
34
|
+
"tls",
|
|
35
|
+
"load-balancer",
|
|
36
|
+
"dns",
|
|
37
|
+
"license-file",
|
|
38
|
+
"hec"
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// src/opentofu/render.ts
|
|
42
|
+
function renderInfraVars(spec) {
|
|
43
|
+
const security_rules = (spec.securityRules ?? []).map((r) => ({
|
|
44
|
+
port: r.port,
|
|
45
|
+
protocol: r.protocol ?? "tcp",
|
|
46
|
+
sources: [...r.sources],
|
|
47
|
+
description: r.description ?? ""
|
|
48
|
+
}));
|
|
49
|
+
const load_balancer = spec.loadBalancer ? {
|
|
50
|
+
target_port: spec.loadBalancer.targetPort,
|
|
51
|
+
target_protocol: spec.loadBalancer.targetProtocol ?? "HTTP",
|
|
52
|
+
health_check_path: spec.loadBalancer.healthCheckPath,
|
|
53
|
+
health_check_matcher: spec.loadBalancer.healthCheckMatcher ?? "200-399",
|
|
54
|
+
health_check_protocol: spec.loadBalancer.healthCheckProtocol ?? "",
|
|
55
|
+
target_kinds: [...spec.loadBalancer.targetKinds],
|
|
56
|
+
listener_port: spec.loadBalancer.listenerPort ?? 443
|
|
57
|
+
} : null;
|
|
58
|
+
const waf_enabled = spec.waf ?? Boolean(spec.loadBalancer);
|
|
59
|
+
const alb_auth = {
|
|
60
|
+
enabled: spec.albAuth?.enabled ?? false,
|
|
61
|
+
user_pool_arn: spec.albAuth?.userPoolArn ?? "",
|
|
62
|
+
user_pool_client_id: spec.albAuth?.userPoolClientId ?? "",
|
|
63
|
+
user_pool_domain: spec.albAuth?.userPoolDomain ?? ""
|
|
64
|
+
};
|
|
65
|
+
return {
|
|
66
|
+
compute_kinds: spec.computeKinds ? [...spec.computeKinds] : [],
|
|
67
|
+
security_rules,
|
|
68
|
+
load_balancer,
|
|
69
|
+
dns_prefixes: { ...spec.dnsPrefixes },
|
|
70
|
+
waf_enabled,
|
|
71
|
+
alb_auth
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// src/opentofu/validate.ts
|
|
76
|
+
function validateInfraSpec(spec) {
|
|
77
|
+
const errors = [];
|
|
78
|
+
if (!Array.isArray(spec.securityRules) || spec.securityRules.length === 0) {
|
|
79
|
+
errors.push("securityRules must contain at least one rule.");
|
|
80
|
+
}
|
|
81
|
+
const validSources = /* @__PURE__ */ new Set(["self", "alb", "admin"]);
|
|
82
|
+
const usesAlbSource = (spec.securityRules ?? []).some(
|
|
83
|
+
(r) => (r.sources ?? []).includes("alb")
|
|
84
|
+
);
|
|
85
|
+
for (const r of spec.securityRules ?? []) {
|
|
86
|
+
if (typeof r.port !== "number" || r.port < 1 || r.port > 65535) {
|
|
87
|
+
errors.push(`securityRules: invalid port ${JSON.stringify(r.port)}.`);
|
|
88
|
+
}
|
|
89
|
+
if (!Array.isArray(r.sources) || r.sources.length === 0) {
|
|
90
|
+
errors.push(`securityRules[port ${r.port}]: sources must be non-empty.`);
|
|
91
|
+
}
|
|
92
|
+
for (const s of r.sources ?? []) {
|
|
93
|
+
if (!validSources.has(s)) {
|
|
94
|
+
errors.push(`securityRules[port ${r.port}]: unknown source "${s}" (expected self|alb|admin).`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (usesAlbSource && !spec.loadBalancer) {
|
|
99
|
+
errors.push('a securityRules entry uses source "alb" but no loadBalancer is declared.');
|
|
100
|
+
}
|
|
101
|
+
if (spec.loadBalancer) {
|
|
102
|
+
const lb = spec.loadBalancer;
|
|
103
|
+
if (typeof lb.targetPort !== "number") {
|
|
104
|
+
errors.push("loadBalancer.targetPort is required.");
|
|
105
|
+
}
|
|
106
|
+
if (!lb.healthCheckPath || !lb.healthCheckPath.startsWith("/")) {
|
|
107
|
+
errors.push('loadBalancer.healthCheckPath must be an absolute path (start with "/").');
|
|
108
|
+
}
|
|
109
|
+
if (!Array.isArray(lb.targetKinds) || lb.targetKinds.length === 0) {
|
|
110
|
+
errors.push("loadBalancer.targetKinds must name at least one compute kind.");
|
|
111
|
+
}
|
|
112
|
+
const targetPortOpen = (spec.securityRules ?? []).some(
|
|
113
|
+
(r) => r.port === lb.targetPort && (r.sources ?? []).includes("alb")
|
|
114
|
+
);
|
|
115
|
+
if (!targetPortOpen) {
|
|
116
|
+
errors.push(
|
|
117
|
+
`loadBalancer.targetPort ${lb.targetPort} is not opened to source "alb" in securityRules \u2014 the ALB can't reach the web tier.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (spec.albAuth?.enabled) {
|
|
122
|
+
const a = spec.albAuth;
|
|
123
|
+
if (!a.userPoolArn || !a.userPoolClientId || !a.userPoolDomain) {
|
|
124
|
+
errors.push("albAuth.enabled requires userPoolArn, userPoolClientId and userPoolDomain.");
|
|
125
|
+
}
|
|
126
|
+
if (!spec.loadBalancer) {
|
|
127
|
+
errors.push("albAuth is set but there is no loadBalancer to attach it to.");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return errors;
|
|
131
|
+
}
|
|
132
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
133
|
+
0 && (module.exports = {
|
|
134
|
+
FOUNDATION_KINDS,
|
|
135
|
+
renderInfraVars,
|
|
136
|
+
validateInfraSpec
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/opentofu/index.ts","../../src/opentofu/spec.ts","../../src/opentofu/render.ts","../../src/opentofu/validate.ts"],"sourcesContent":["// =============================================================================\n// @veltrixsecops/app-sdk/opentofu\n//\n// Declarative, tool-agnostic infrastructure for BYOI apps. An app ships an\n// InfraSpec (apps/<app>/infra/spec.ts); the SDK renders it into the generic\n// OpenTofu module's tfvars (sdk/opentofu/modules/<cloud>); the platform worker\n// applies it and runs the app's bring-up. No per-tool HCL, ever.\n// =============================================================================\n\nexport type {\n InfraSpec,\n SecurityRule,\n SecuritySource,\n LoadBalancerSpec,\n StorageSpec,\n AlbAuthSpec,\n FoundationKind,\n} from './spec';\nexport { FOUNDATION_KINDS } from './spec';\n\nexport type {\n AwsInfraVars,\n AwsLoadBalancerVars,\n AwsSecurityRuleVars,\n AwsAlbAuthVars,\n} from './render';\nexport { renderInfraVars } from './render';\n\nexport { validateInfraSpec } from './validate';\n","// =============================================================================\n// InfraSpec — the declarative, tool-agnostic infrastructure contract.\n//\n// An app ships one of these in `apps/<app>/infra/spec.ts`. The SDK renders it\n// into the generic OpenTofu module's tfvars (see ./render). NOTHING in the\n// module is tool-specific: an app supplies all of its shape (roles, ports,\n// front-door, DNS, bring-up) as DATA here, so the same modules provision Splunk,\n// Security Onion, or any other BYOI tool without a line of per-tool HCL.\n//\n// Pairs with sdk/opentofu/modules/<cloud> (the generic HCL) and the platform\n// render+apply worker, which invokes the app's `bringup` entrypoint after apply.\n// =============================================================================\n\n/** Where a security-group ingress rule may allow traffic from. */\nexport type SecuritySource =\n | 'self' // peer nodes in this stack (the node SG referencing itself)\n | 'alb' // the public ALB security group (only valid when loadBalancer is set)\n | 'admin'; // the Veltrix control-plane / admin CIDR (var.admin_cidr)\n\n/** One security-group ingress rule: a port and who may reach it. */\nexport interface SecurityRule {\n /** Destination port to open on the compute nodes. */\n port: number;\n /** IP protocol. Default 'tcp'. */\n protocol?: 'tcp' | 'udp';\n /** Origins allowed to reach `port`. At least one. */\n sources: SecuritySource[];\n /** Human-readable description (surfaced on the rule). */\n description?: string;\n}\n\n/** Front-door ALB spec. Omit entirely for forwarder-only / headless tools. */\nexport interface LoadBalancerSpec {\n /** Port the tool's web UI listens on behind the ALB (e.g. Splunk Web 8000). */\n targetPort: number;\n /** ALB→instance protocol. Default 'HTTP' (TLS terminates at the ALB). */\n targetProtocol?: 'HTTP' | 'HTTPS';\n /** Health-check path on the target (e.g. '/en-US/account/login'). */\n healthCheckPath: string;\n /** Health-check success matcher. Default '200-399'. */\n healthCheckMatcher?: string;\n /** Health-check protocol. Default = targetProtocol. */\n healthCheckProtocol?: 'HTTP' | 'HTTPS';\n /** Compute kinds that sit behind the ALB (e.g. ['search-head','standalone']). */\n targetKinds: string[];\n /** Public HTTPS listener port. Default 443. */\n listenerPort?: number;\n}\n\n/** An object-storage bucket the tool needs (e.g. Splunk SmartStore, frozen). */\nexport interface StorageSpec {\n /** Logical suffix for the bucket name (e.g. 'smartstore'). */\n name: string;\n}\n\n/** Optional Cognito/OIDC MFA enforced at the ALB, in front of the tool's UI. */\nexport interface AlbAuthSpec {\n enabled: boolean;\n userPoolArn?: string;\n userPoolClientId?: string;\n userPoolDomain?: string;\n}\n\n/**\n * The complete declarative infra spec for one app. Everything tool-shaped is a\n * value here; the generic module reads these via tfvars.\n */\nexport interface InfraSpec {\n /**\n * Explicit compute kinds. When omitted, ANY plan item whose `kind` is not a\n * generic FOUNDATION kind (see FOUNDATION_KINDS) is treated as compute — so an\n * app's roles become compute automatically without listing them here.\n */\n computeKinds?: string[];\n\n /** SG ingress rules: the tool's ports and who may reach each. */\n securityRules: SecurityRule[];\n\n /** ALB front-door. Omit for tools with no web UI. */\n loadBalancer?: LoadBalancerSpec;\n\n /**\n * kind → DNS label prefix for per-node function FQDNs\n * (e.g. { indexer: 'idx', 'search-head': 'sh', 'cluster-manager': 'mgmt' }).\n * A kind absent from the map falls back to the kind string itself.\n */\n dnsPrefixes: Record<string, string>;\n\n /** Object-storage buckets to create. Omit if the tool needs none. */\n storage?: StorageSpec[];\n\n /**\n * Attach a WAFv2 web ACL (AWS-managed rule sets + IP rate limit) to the ALB.\n * Defaults to true when `loadBalancer` is set; ignored otherwise.\n */\n waf?: boolean;\n\n /** Optional ALB Cognito MFA. */\n albAuth?: AlbAuthSpec;\n\n /**\n * Path, relative to the app's `infra/` dir, to the bring-up entrypoint the\n * generic worker runs after `tofu apply` succeeds (config management +\n * readiness gate). ALL tool-specific configuration lives behind this — e.g.\n * './bringup/ansible/site.yml' for Splunk. Omit for tools that are ready at\n * boot (no post-provision configuration).\n */\n bringup?: string;\n}\n\n/**\n * Generic foundation kinds the module realizes as shared infra (not compute).\n * Any plan `kind` NOT in this set is compute. Kept in sync with the module's\n * `var.foundation_kinds` default.\n */\nexport const FOUNDATION_KINDS = [\n 'network',\n 'storage',\n 'secrets',\n 'tls',\n 'load-balancer',\n 'dns',\n 'license-file',\n 'hec',\n] as const;\n\nexport type FoundationKind = (typeof FOUNDATION_KINDS)[number];\n","// =============================================================================\n// render — turn an app's declarative InfraSpec into the generic OpenTofu\n// module's variable values (tfvars).\n//\n// The platform render+apply worker builds the BASE vars (app_id, customer_id,\n// plan, subnet_cidr, tags, region, ...) from the DeployRequest, and merges these\n// SPEC-derived vars on top. Field names are snake_case to match the HCL module\n// variables 1:1. Defaults mirror the module's `optional(...)` defaults, applied\n// here so the emitted tfvars are explicit and self-describing.\n// =============================================================================\n\nimport type { InfraSpec } from './spec';\n\n/** ALB spec as the module expects it (snake_case). */\nexport interface AwsLoadBalancerVars {\n target_port: number;\n target_protocol: 'HTTP' | 'HTTPS';\n health_check_path: string;\n health_check_matcher: string;\n health_check_protocol: string; // \"\" => module falls back to target_protocol\n target_kinds: string[];\n listener_port: number;\n}\n\n/** One rendered SG ingress rule (snake_case). */\nexport interface AwsSecurityRuleVars {\n port: number;\n protocol: 'tcp' | 'udp';\n sources: string[];\n description: string;\n}\n\n/** Cognito MFA vars (snake_case), always present so `var.alb_auth.enabled` resolves. */\nexport interface AwsAlbAuthVars {\n enabled: boolean;\n user_pool_arn: string;\n user_pool_client_id: string;\n user_pool_domain: string;\n}\n\n/** The spec-derived subset of the generic AWS module's variables. */\nexport interface AwsInfraVars {\n compute_kinds: string[];\n security_rules: AwsSecurityRuleVars[];\n load_balancer: AwsLoadBalancerVars | null;\n dns_prefixes: Record<string, string>;\n waf_enabled: boolean;\n alb_auth: AwsAlbAuthVars;\n}\n\n/**\n * Render the spec-derived tfvars for the generic AWS module. Pure and\n * deterministic — no I/O, no clock, no randomness.\n */\nexport function renderInfraVars(spec: InfraSpec): AwsInfraVars {\n const security_rules: AwsSecurityRuleVars[] = (spec.securityRules ?? []).map((r) => ({\n port: r.port,\n protocol: r.protocol ?? 'tcp',\n sources: [...r.sources],\n description: r.description ?? '',\n }));\n\n const load_balancer: AwsLoadBalancerVars | null = spec.loadBalancer\n ? {\n target_port: spec.loadBalancer.targetPort,\n target_protocol: spec.loadBalancer.targetProtocol ?? 'HTTP',\n health_check_path: spec.loadBalancer.healthCheckPath,\n health_check_matcher: spec.loadBalancer.healthCheckMatcher ?? '200-399',\n health_check_protocol: spec.loadBalancer.healthCheckProtocol ?? '',\n target_kinds: [...spec.loadBalancer.targetKinds],\n listener_port: spec.loadBalancer.listenerPort ?? 443,\n }\n : null;\n\n // WAF defaults ON when there is a load balancer, OFF otherwise (the module\n // ignores it without an ALB, but keep the emitted value honest).\n const waf_enabled = spec.waf ?? Boolean(spec.loadBalancer);\n\n const alb_auth: AwsAlbAuthVars = {\n enabled: spec.albAuth?.enabled ?? false,\n user_pool_arn: spec.albAuth?.userPoolArn ?? '',\n user_pool_client_id: spec.albAuth?.userPoolClientId ?? '',\n user_pool_domain: spec.albAuth?.userPoolDomain ?? '',\n };\n\n return {\n compute_kinds: spec.computeKinds ? [...spec.computeKinds] : [],\n security_rules,\n load_balancer,\n dns_prefixes: { ...spec.dnsPrefixes },\n waf_enabled,\n alb_auth,\n };\n}\n","// =============================================================================\n// validateInfraSpec — cheap, dependency-free checks that catch the InfraSpec\n// mistakes the OpenTofu module can't (or would only surface at apply time).\n// Returns a list of human-readable errors; empty === valid.\n// =============================================================================\n\nimport type { InfraSpec } from './spec';\n\nexport function validateInfraSpec(spec: InfraSpec): string[] {\n const errors: string[] = [];\n\n if (!Array.isArray(spec.securityRules) || spec.securityRules.length === 0) {\n errors.push('securityRules must contain at least one rule.');\n }\n\n const validSources = new Set(['self', 'alb', 'admin']);\n const usesAlbSource = (spec.securityRules ?? []).some((r) =>\n (r.sources ?? []).includes('alb'),\n );\n\n for (const r of spec.securityRules ?? []) {\n if (typeof r.port !== 'number' || r.port < 1 || r.port > 65535) {\n errors.push(`securityRules: invalid port ${JSON.stringify(r.port)}.`);\n }\n if (!Array.isArray(r.sources) || r.sources.length === 0) {\n errors.push(`securityRules[port ${r.port}]: sources must be non-empty.`);\n }\n for (const s of r.sources ?? []) {\n if (!validSources.has(s)) {\n errors.push(`securityRules[port ${r.port}]: unknown source \"${s}\" (expected self|alb|admin).`);\n }\n }\n }\n\n // \"alb\" sources are meaningless without a load balancer.\n if (usesAlbSource && !spec.loadBalancer) {\n errors.push('a securityRules entry uses source \"alb\" but no loadBalancer is declared.');\n }\n\n if (spec.loadBalancer) {\n const lb = spec.loadBalancer;\n if (typeof lb.targetPort !== 'number') {\n errors.push('loadBalancer.targetPort is required.');\n }\n if (!lb.healthCheckPath || !lb.healthCheckPath.startsWith('/')) {\n errors.push('loadBalancer.healthCheckPath must be an absolute path (start with \"/\").');\n }\n if (!Array.isArray(lb.targetKinds) || lb.targetKinds.length === 0) {\n errors.push('loadBalancer.targetKinds must name at least one compute kind.');\n }\n // The web tier must be reachable from the ALB.\n const targetPortOpen = (spec.securityRules ?? []).some(\n (r) => r.port === lb.targetPort && (r.sources ?? []).includes('alb'),\n );\n if (!targetPortOpen) {\n errors.push(\n `loadBalancer.targetPort ${lb.targetPort} is not opened to source \"alb\" in securityRules — the ALB can't reach the web tier.`,\n );\n }\n }\n\n if (spec.albAuth?.enabled) {\n const a = spec.albAuth;\n if (!a.userPoolArn || !a.userPoolClientId || !a.userPoolDomain) {\n errors.push('albAuth.enabled requires userPoolArn, userPoolClientId and userPoolDomain.');\n }\n if (!spec.loadBalancer) {\n errors.push('albAuth is set but there is no loadBalancer to attach it to.');\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** Where a security-group ingress rule may allow traffic from. */
|
|
2
|
+
type SecuritySource = 'self' | 'alb' | 'admin';
|
|
3
|
+
/** One security-group ingress rule: a port and who may reach it. */
|
|
4
|
+
interface SecurityRule {
|
|
5
|
+
/** Destination port to open on the compute nodes. */
|
|
6
|
+
port: number;
|
|
7
|
+
/** IP protocol. Default 'tcp'. */
|
|
8
|
+
protocol?: 'tcp' | 'udp';
|
|
9
|
+
/** Origins allowed to reach `port`. At least one. */
|
|
10
|
+
sources: SecuritySource[];
|
|
11
|
+
/** Human-readable description (surfaced on the rule). */
|
|
12
|
+
description?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Front-door ALB spec. Omit entirely for forwarder-only / headless tools. */
|
|
15
|
+
interface LoadBalancerSpec {
|
|
16
|
+
/** Port the tool's web UI listens on behind the ALB (e.g. Splunk Web 8000). */
|
|
17
|
+
targetPort: number;
|
|
18
|
+
/** ALB→instance protocol. Default 'HTTP' (TLS terminates at the ALB). */
|
|
19
|
+
targetProtocol?: 'HTTP' | 'HTTPS';
|
|
20
|
+
/** Health-check path on the target (e.g. '/en-US/account/login'). */
|
|
21
|
+
healthCheckPath: string;
|
|
22
|
+
/** Health-check success matcher. Default '200-399'. */
|
|
23
|
+
healthCheckMatcher?: string;
|
|
24
|
+
/** Health-check protocol. Default = targetProtocol. */
|
|
25
|
+
healthCheckProtocol?: 'HTTP' | 'HTTPS';
|
|
26
|
+
/** Compute kinds that sit behind the ALB (e.g. ['search-head','standalone']). */
|
|
27
|
+
targetKinds: string[];
|
|
28
|
+
/** Public HTTPS listener port. Default 443. */
|
|
29
|
+
listenerPort?: number;
|
|
30
|
+
}
|
|
31
|
+
/** An object-storage bucket the tool needs (e.g. Splunk SmartStore, frozen). */
|
|
32
|
+
interface StorageSpec {
|
|
33
|
+
/** Logical suffix for the bucket name (e.g. 'smartstore'). */
|
|
34
|
+
name: string;
|
|
35
|
+
}
|
|
36
|
+
/** Optional Cognito/OIDC MFA enforced at the ALB, in front of the tool's UI. */
|
|
37
|
+
interface AlbAuthSpec {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
userPoolArn?: string;
|
|
40
|
+
userPoolClientId?: string;
|
|
41
|
+
userPoolDomain?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The complete declarative infra spec for one app. Everything tool-shaped is a
|
|
45
|
+
* value here; the generic module reads these via tfvars.
|
|
46
|
+
*/
|
|
47
|
+
interface InfraSpec {
|
|
48
|
+
/**
|
|
49
|
+
* Explicit compute kinds. When omitted, ANY plan item whose `kind` is not a
|
|
50
|
+
* generic FOUNDATION kind (see FOUNDATION_KINDS) is treated as compute — so an
|
|
51
|
+
* app's roles become compute automatically without listing them here.
|
|
52
|
+
*/
|
|
53
|
+
computeKinds?: string[];
|
|
54
|
+
/** SG ingress rules: the tool's ports and who may reach each. */
|
|
55
|
+
securityRules: SecurityRule[];
|
|
56
|
+
/** ALB front-door. Omit for tools with no web UI. */
|
|
57
|
+
loadBalancer?: LoadBalancerSpec;
|
|
58
|
+
/**
|
|
59
|
+
* kind → DNS label prefix for per-node function FQDNs
|
|
60
|
+
* (e.g. { indexer: 'idx', 'search-head': 'sh', 'cluster-manager': 'mgmt' }).
|
|
61
|
+
* A kind absent from the map falls back to the kind string itself.
|
|
62
|
+
*/
|
|
63
|
+
dnsPrefixes: Record<string, string>;
|
|
64
|
+
/** Object-storage buckets to create. Omit if the tool needs none. */
|
|
65
|
+
storage?: StorageSpec[];
|
|
66
|
+
/**
|
|
67
|
+
* Attach a WAFv2 web ACL (AWS-managed rule sets + IP rate limit) to the ALB.
|
|
68
|
+
* Defaults to true when `loadBalancer` is set; ignored otherwise.
|
|
69
|
+
*/
|
|
70
|
+
waf?: boolean;
|
|
71
|
+
/** Optional ALB Cognito MFA. */
|
|
72
|
+
albAuth?: AlbAuthSpec;
|
|
73
|
+
/**
|
|
74
|
+
* Path, relative to the app's `infra/` dir, to the bring-up entrypoint the
|
|
75
|
+
* generic worker runs after `tofu apply` succeeds (config management +
|
|
76
|
+
* readiness gate). ALL tool-specific configuration lives behind this — e.g.
|
|
77
|
+
* './bringup/ansible/site.yml' for Splunk. Omit for tools that are ready at
|
|
78
|
+
* boot (no post-provision configuration).
|
|
79
|
+
*/
|
|
80
|
+
bringup?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generic foundation kinds the module realizes as shared infra (not compute).
|
|
84
|
+
* Any plan `kind` NOT in this set is compute. Kept in sync with the module's
|
|
85
|
+
* `var.foundation_kinds` default.
|
|
86
|
+
*/
|
|
87
|
+
declare const FOUNDATION_KINDS: readonly ["network", "storage", "secrets", "tls", "load-balancer", "dns", "license-file", "hec"];
|
|
88
|
+
type FoundationKind = (typeof FOUNDATION_KINDS)[number];
|
|
89
|
+
|
|
90
|
+
/** ALB spec as the module expects it (snake_case). */
|
|
91
|
+
interface AwsLoadBalancerVars {
|
|
92
|
+
target_port: number;
|
|
93
|
+
target_protocol: 'HTTP' | 'HTTPS';
|
|
94
|
+
health_check_path: string;
|
|
95
|
+
health_check_matcher: string;
|
|
96
|
+
health_check_protocol: string;
|
|
97
|
+
target_kinds: string[];
|
|
98
|
+
listener_port: number;
|
|
99
|
+
}
|
|
100
|
+
/** One rendered SG ingress rule (snake_case). */
|
|
101
|
+
interface AwsSecurityRuleVars {
|
|
102
|
+
port: number;
|
|
103
|
+
protocol: 'tcp' | 'udp';
|
|
104
|
+
sources: string[];
|
|
105
|
+
description: string;
|
|
106
|
+
}
|
|
107
|
+
/** Cognito MFA vars (snake_case), always present so `var.alb_auth.enabled` resolves. */
|
|
108
|
+
interface AwsAlbAuthVars {
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
user_pool_arn: string;
|
|
111
|
+
user_pool_client_id: string;
|
|
112
|
+
user_pool_domain: string;
|
|
113
|
+
}
|
|
114
|
+
/** The spec-derived subset of the generic AWS module's variables. */
|
|
115
|
+
interface AwsInfraVars {
|
|
116
|
+
compute_kinds: string[];
|
|
117
|
+
security_rules: AwsSecurityRuleVars[];
|
|
118
|
+
load_balancer: AwsLoadBalancerVars | null;
|
|
119
|
+
dns_prefixes: Record<string, string>;
|
|
120
|
+
waf_enabled: boolean;
|
|
121
|
+
alb_auth: AwsAlbAuthVars;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Render the spec-derived tfvars for the generic AWS module. Pure and
|
|
125
|
+
* deterministic — no I/O, no clock, no randomness.
|
|
126
|
+
*/
|
|
127
|
+
declare function renderInfraVars(spec: InfraSpec): AwsInfraVars;
|
|
128
|
+
|
|
129
|
+
declare function validateInfraSpec(spec: InfraSpec): string[];
|
|
130
|
+
|
|
131
|
+
export { type AlbAuthSpec, type AwsAlbAuthVars, type AwsInfraVars, type AwsLoadBalancerVars, type AwsSecurityRuleVars, FOUNDATION_KINDS, type FoundationKind, type InfraSpec, type LoadBalancerSpec, type SecurityRule, type SecuritySource, type StorageSpec, renderInfraVars, validateInfraSpec };
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/** Where a security-group ingress rule may allow traffic from. */
|
|
2
|
+
type SecuritySource = 'self' | 'alb' | 'admin';
|
|
3
|
+
/** One security-group ingress rule: a port and who may reach it. */
|
|
4
|
+
interface SecurityRule {
|
|
5
|
+
/** Destination port to open on the compute nodes. */
|
|
6
|
+
port: number;
|
|
7
|
+
/** IP protocol. Default 'tcp'. */
|
|
8
|
+
protocol?: 'tcp' | 'udp';
|
|
9
|
+
/** Origins allowed to reach `port`. At least one. */
|
|
10
|
+
sources: SecuritySource[];
|
|
11
|
+
/** Human-readable description (surfaced on the rule). */
|
|
12
|
+
description?: string;
|
|
13
|
+
}
|
|
14
|
+
/** Front-door ALB spec. Omit entirely for forwarder-only / headless tools. */
|
|
15
|
+
interface LoadBalancerSpec {
|
|
16
|
+
/** Port the tool's web UI listens on behind the ALB (e.g. Splunk Web 8000). */
|
|
17
|
+
targetPort: number;
|
|
18
|
+
/** ALB→instance protocol. Default 'HTTP' (TLS terminates at the ALB). */
|
|
19
|
+
targetProtocol?: 'HTTP' | 'HTTPS';
|
|
20
|
+
/** Health-check path on the target (e.g. '/en-US/account/login'). */
|
|
21
|
+
healthCheckPath: string;
|
|
22
|
+
/** Health-check success matcher. Default '200-399'. */
|
|
23
|
+
healthCheckMatcher?: string;
|
|
24
|
+
/** Health-check protocol. Default = targetProtocol. */
|
|
25
|
+
healthCheckProtocol?: 'HTTP' | 'HTTPS';
|
|
26
|
+
/** Compute kinds that sit behind the ALB (e.g. ['search-head','standalone']). */
|
|
27
|
+
targetKinds: string[];
|
|
28
|
+
/** Public HTTPS listener port. Default 443. */
|
|
29
|
+
listenerPort?: number;
|
|
30
|
+
}
|
|
31
|
+
/** An object-storage bucket the tool needs (e.g. Splunk SmartStore, frozen). */
|
|
32
|
+
interface StorageSpec {
|
|
33
|
+
/** Logical suffix for the bucket name (e.g. 'smartstore'). */
|
|
34
|
+
name: string;
|
|
35
|
+
}
|
|
36
|
+
/** Optional Cognito/OIDC MFA enforced at the ALB, in front of the tool's UI. */
|
|
37
|
+
interface AlbAuthSpec {
|
|
38
|
+
enabled: boolean;
|
|
39
|
+
userPoolArn?: string;
|
|
40
|
+
userPoolClientId?: string;
|
|
41
|
+
userPoolDomain?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* The complete declarative infra spec for one app. Everything tool-shaped is a
|
|
45
|
+
* value here; the generic module reads these via tfvars.
|
|
46
|
+
*/
|
|
47
|
+
interface InfraSpec {
|
|
48
|
+
/**
|
|
49
|
+
* Explicit compute kinds. When omitted, ANY plan item whose `kind` is not a
|
|
50
|
+
* generic FOUNDATION kind (see FOUNDATION_KINDS) is treated as compute — so an
|
|
51
|
+
* app's roles become compute automatically without listing them here.
|
|
52
|
+
*/
|
|
53
|
+
computeKinds?: string[];
|
|
54
|
+
/** SG ingress rules: the tool's ports and who may reach each. */
|
|
55
|
+
securityRules: SecurityRule[];
|
|
56
|
+
/** ALB front-door. Omit for tools with no web UI. */
|
|
57
|
+
loadBalancer?: LoadBalancerSpec;
|
|
58
|
+
/**
|
|
59
|
+
* kind → DNS label prefix for per-node function FQDNs
|
|
60
|
+
* (e.g. { indexer: 'idx', 'search-head': 'sh', 'cluster-manager': 'mgmt' }).
|
|
61
|
+
* A kind absent from the map falls back to the kind string itself.
|
|
62
|
+
*/
|
|
63
|
+
dnsPrefixes: Record<string, string>;
|
|
64
|
+
/** Object-storage buckets to create. Omit if the tool needs none. */
|
|
65
|
+
storage?: StorageSpec[];
|
|
66
|
+
/**
|
|
67
|
+
* Attach a WAFv2 web ACL (AWS-managed rule sets + IP rate limit) to the ALB.
|
|
68
|
+
* Defaults to true when `loadBalancer` is set; ignored otherwise.
|
|
69
|
+
*/
|
|
70
|
+
waf?: boolean;
|
|
71
|
+
/** Optional ALB Cognito MFA. */
|
|
72
|
+
albAuth?: AlbAuthSpec;
|
|
73
|
+
/**
|
|
74
|
+
* Path, relative to the app's `infra/` dir, to the bring-up entrypoint the
|
|
75
|
+
* generic worker runs after `tofu apply` succeeds (config management +
|
|
76
|
+
* readiness gate). ALL tool-specific configuration lives behind this — e.g.
|
|
77
|
+
* './bringup/ansible/site.yml' for Splunk. Omit for tools that are ready at
|
|
78
|
+
* boot (no post-provision configuration).
|
|
79
|
+
*/
|
|
80
|
+
bringup?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Generic foundation kinds the module realizes as shared infra (not compute).
|
|
84
|
+
* Any plan `kind` NOT in this set is compute. Kept in sync with the module's
|
|
85
|
+
* `var.foundation_kinds` default.
|
|
86
|
+
*/
|
|
87
|
+
declare const FOUNDATION_KINDS: readonly ["network", "storage", "secrets", "tls", "load-balancer", "dns", "license-file", "hec"];
|
|
88
|
+
type FoundationKind = (typeof FOUNDATION_KINDS)[number];
|
|
89
|
+
|
|
90
|
+
/** ALB spec as the module expects it (snake_case). */
|
|
91
|
+
interface AwsLoadBalancerVars {
|
|
92
|
+
target_port: number;
|
|
93
|
+
target_protocol: 'HTTP' | 'HTTPS';
|
|
94
|
+
health_check_path: string;
|
|
95
|
+
health_check_matcher: string;
|
|
96
|
+
health_check_protocol: string;
|
|
97
|
+
target_kinds: string[];
|
|
98
|
+
listener_port: number;
|
|
99
|
+
}
|
|
100
|
+
/** One rendered SG ingress rule (snake_case). */
|
|
101
|
+
interface AwsSecurityRuleVars {
|
|
102
|
+
port: number;
|
|
103
|
+
protocol: 'tcp' | 'udp';
|
|
104
|
+
sources: string[];
|
|
105
|
+
description: string;
|
|
106
|
+
}
|
|
107
|
+
/** Cognito MFA vars (snake_case), always present so `var.alb_auth.enabled` resolves. */
|
|
108
|
+
interface AwsAlbAuthVars {
|
|
109
|
+
enabled: boolean;
|
|
110
|
+
user_pool_arn: string;
|
|
111
|
+
user_pool_client_id: string;
|
|
112
|
+
user_pool_domain: string;
|
|
113
|
+
}
|
|
114
|
+
/** The spec-derived subset of the generic AWS module's variables. */
|
|
115
|
+
interface AwsInfraVars {
|
|
116
|
+
compute_kinds: string[];
|
|
117
|
+
security_rules: AwsSecurityRuleVars[];
|
|
118
|
+
load_balancer: AwsLoadBalancerVars | null;
|
|
119
|
+
dns_prefixes: Record<string, string>;
|
|
120
|
+
waf_enabled: boolean;
|
|
121
|
+
alb_auth: AwsAlbAuthVars;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Render the spec-derived tfvars for the generic AWS module. Pure and
|
|
125
|
+
* deterministic — no I/O, no clock, no randomness.
|
|
126
|
+
*/
|
|
127
|
+
declare function renderInfraVars(spec: InfraSpec): AwsInfraVars;
|
|
128
|
+
|
|
129
|
+
declare function validateInfraSpec(spec: InfraSpec): string[];
|
|
130
|
+
|
|
131
|
+
export { type AlbAuthSpec, type AwsAlbAuthVars, type AwsInfraVars, type AwsLoadBalancerVars, type AwsSecurityRuleVars, FOUNDATION_KINDS, type FoundationKind, type InfraSpec, type LoadBalancerSpec, type SecurityRule, type SecuritySource, type StorageSpec, renderInfraVars, validateInfraSpec };
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// src/opentofu/spec.ts
|
|
2
|
+
var FOUNDATION_KINDS = [
|
|
3
|
+
"network",
|
|
4
|
+
"storage",
|
|
5
|
+
"secrets",
|
|
6
|
+
"tls",
|
|
7
|
+
"load-balancer",
|
|
8
|
+
"dns",
|
|
9
|
+
"license-file",
|
|
10
|
+
"hec"
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
// src/opentofu/render.ts
|
|
14
|
+
function renderInfraVars(spec) {
|
|
15
|
+
const security_rules = (spec.securityRules ?? []).map((r) => ({
|
|
16
|
+
port: r.port,
|
|
17
|
+
protocol: r.protocol ?? "tcp",
|
|
18
|
+
sources: [...r.sources],
|
|
19
|
+
description: r.description ?? ""
|
|
20
|
+
}));
|
|
21
|
+
const load_balancer = spec.loadBalancer ? {
|
|
22
|
+
target_port: spec.loadBalancer.targetPort,
|
|
23
|
+
target_protocol: spec.loadBalancer.targetProtocol ?? "HTTP",
|
|
24
|
+
health_check_path: spec.loadBalancer.healthCheckPath,
|
|
25
|
+
health_check_matcher: spec.loadBalancer.healthCheckMatcher ?? "200-399",
|
|
26
|
+
health_check_protocol: spec.loadBalancer.healthCheckProtocol ?? "",
|
|
27
|
+
target_kinds: [...spec.loadBalancer.targetKinds],
|
|
28
|
+
listener_port: spec.loadBalancer.listenerPort ?? 443
|
|
29
|
+
} : null;
|
|
30
|
+
const waf_enabled = spec.waf ?? Boolean(spec.loadBalancer);
|
|
31
|
+
const alb_auth = {
|
|
32
|
+
enabled: spec.albAuth?.enabled ?? false,
|
|
33
|
+
user_pool_arn: spec.albAuth?.userPoolArn ?? "",
|
|
34
|
+
user_pool_client_id: spec.albAuth?.userPoolClientId ?? "",
|
|
35
|
+
user_pool_domain: spec.albAuth?.userPoolDomain ?? ""
|
|
36
|
+
};
|
|
37
|
+
return {
|
|
38
|
+
compute_kinds: spec.computeKinds ? [...spec.computeKinds] : [],
|
|
39
|
+
security_rules,
|
|
40
|
+
load_balancer,
|
|
41
|
+
dns_prefixes: { ...spec.dnsPrefixes },
|
|
42
|
+
waf_enabled,
|
|
43
|
+
alb_auth
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/opentofu/validate.ts
|
|
48
|
+
function validateInfraSpec(spec) {
|
|
49
|
+
const errors = [];
|
|
50
|
+
if (!Array.isArray(spec.securityRules) || spec.securityRules.length === 0) {
|
|
51
|
+
errors.push("securityRules must contain at least one rule.");
|
|
52
|
+
}
|
|
53
|
+
const validSources = /* @__PURE__ */ new Set(["self", "alb", "admin"]);
|
|
54
|
+
const usesAlbSource = (spec.securityRules ?? []).some(
|
|
55
|
+
(r) => (r.sources ?? []).includes("alb")
|
|
56
|
+
);
|
|
57
|
+
for (const r of spec.securityRules ?? []) {
|
|
58
|
+
if (typeof r.port !== "number" || r.port < 1 || r.port > 65535) {
|
|
59
|
+
errors.push(`securityRules: invalid port ${JSON.stringify(r.port)}.`);
|
|
60
|
+
}
|
|
61
|
+
if (!Array.isArray(r.sources) || r.sources.length === 0) {
|
|
62
|
+
errors.push(`securityRules[port ${r.port}]: sources must be non-empty.`);
|
|
63
|
+
}
|
|
64
|
+
for (const s of r.sources ?? []) {
|
|
65
|
+
if (!validSources.has(s)) {
|
|
66
|
+
errors.push(`securityRules[port ${r.port}]: unknown source "${s}" (expected self|alb|admin).`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (usesAlbSource && !spec.loadBalancer) {
|
|
71
|
+
errors.push('a securityRules entry uses source "alb" but no loadBalancer is declared.');
|
|
72
|
+
}
|
|
73
|
+
if (spec.loadBalancer) {
|
|
74
|
+
const lb = spec.loadBalancer;
|
|
75
|
+
if (typeof lb.targetPort !== "number") {
|
|
76
|
+
errors.push("loadBalancer.targetPort is required.");
|
|
77
|
+
}
|
|
78
|
+
if (!lb.healthCheckPath || !lb.healthCheckPath.startsWith("/")) {
|
|
79
|
+
errors.push('loadBalancer.healthCheckPath must be an absolute path (start with "/").');
|
|
80
|
+
}
|
|
81
|
+
if (!Array.isArray(lb.targetKinds) || lb.targetKinds.length === 0) {
|
|
82
|
+
errors.push("loadBalancer.targetKinds must name at least one compute kind.");
|
|
83
|
+
}
|
|
84
|
+
const targetPortOpen = (spec.securityRules ?? []).some(
|
|
85
|
+
(r) => r.port === lb.targetPort && (r.sources ?? []).includes("alb")
|
|
86
|
+
);
|
|
87
|
+
if (!targetPortOpen) {
|
|
88
|
+
errors.push(
|
|
89
|
+
`loadBalancer.targetPort ${lb.targetPort} is not opened to source "alb" in securityRules \u2014 the ALB can't reach the web tier.`
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (spec.albAuth?.enabled) {
|
|
94
|
+
const a = spec.albAuth;
|
|
95
|
+
if (!a.userPoolArn || !a.userPoolClientId || !a.userPoolDomain) {
|
|
96
|
+
errors.push("albAuth.enabled requires userPoolArn, userPoolClientId and userPoolDomain.");
|
|
97
|
+
}
|
|
98
|
+
if (!spec.loadBalancer) {
|
|
99
|
+
errors.push("albAuth is set but there is no loadBalancer to attach it to.");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return errors;
|
|
103
|
+
}
|
|
104
|
+
export {
|
|
105
|
+
FOUNDATION_KINDS,
|
|
106
|
+
renderInfraVars,
|
|
107
|
+
validateInfraSpec
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/opentofu/spec.ts","../../src/opentofu/render.ts","../../src/opentofu/validate.ts"],"sourcesContent":["// =============================================================================\n// InfraSpec — the declarative, tool-agnostic infrastructure contract.\n//\n// An app ships one of these in `apps/<app>/infra/spec.ts`. The SDK renders it\n// into the generic OpenTofu module's tfvars (see ./render). NOTHING in the\n// module is tool-specific: an app supplies all of its shape (roles, ports,\n// front-door, DNS, bring-up) as DATA here, so the same modules provision Splunk,\n// Security Onion, or any other BYOI tool without a line of per-tool HCL.\n//\n// Pairs with sdk/opentofu/modules/<cloud> (the generic HCL) and the platform\n// render+apply worker, which invokes the app's `bringup` entrypoint after apply.\n// =============================================================================\n\n/** Where a security-group ingress rule may allow traffic from. */\nexport type SecuritySource =\n | 'self' // peer nodes in this stack (the node SG referencing itself)\n | 'alb' // the public ALB security group (only valid when loadBalancer is set)\n | 'admin'; // the Veltrix control-plane / admin CIDR (var.admin_cidr)\n\n/** One security-group ingress rule: a port and who may reach it. */\nexport interface SecurityRule {\n /** Destination port to open on the compute nodes. */\n port: number;\n /** IP protocol. Default 'tcp'. */\n protocol?: 'tcp' | 'udp';\n /** Origins allowed to reach `port`. At least one. */\n sources: SecuritySource[];\n /** Human-readable description (surfaced on the rule). */\n description?: string;\n}\n\n/** Front-door ALB spec. Omit entirely for forwarder-only / headless tools. */\nexport interface LoadBalancerSpec {\n /** Port the tool's web UI listens on behind the ALB (e.g. Splunk Web 8000). */\n targetPort: number;\n /** ALB→instance protocol. Default 'HTTP' (TLS terminates at the ALB). */\n targetProtocol?: 'HTTP' | 'HTTPS';\n /** Health-check path on the target (e.g. '/en-US/account/login'). */\n healthCheckPath: string;\n /** Health-check success matcher. Default '200-399'. */\n healthCheckMatcher?: string;\n /** Health-check protocol. Default = targetProtocol. */\n healthCheckProtocol?: 'HTTP' | 'HTTPS';\n /** Compute kinds that sit behind the ALB (e.g. ['search-head','standalone']). */\n targetKinds: string[];\n /** Public HTTPS listener port. Default 443. */\n listenerPort?: number;\n}\n\n/** An object-storage bucket the tool needs (e.g. Splunk SmartStore, frozen). */\nexport interface StorageSpec {\n /** Logical suffix for the bucket name (e.g. 'smartstore'). */\n name: string;\n}\n\n/** Optional Cognito/OIDC MFA enforced at the ALB, in front of the tool's UI. */\nexport interface AlbAuthSpec {\n enabled: boolean;\n userPoolArn?: string;\n userPoolClientId?: string;\n userPoolDomain?: string;\n}\n\n/**\n * The complete declarative infra spec for one app. Everything tool-shaped is a\n * value here; the generic module reads these via tfvars.\n */\nexport interface InfraSpec {\n /**\n * Explicit compute kinds. When omitted, ANY plan item whose `kind` is not a\n * generic FOUNDATION kind (see FOUNDATION_KINDS) is treated as compute — so an\n * app's roles become compute automatically without listing them here.\n */\n computeKinds?: string[];\n\n /** SG ingress rules: the tool's ports and who may reach each. */\n securityRules: SecurityRule[];\n\n /** ALB front-door. Omit for tools with no web UI. */\n loadBalancer?: LoadBalancerSpec;\n\n /**\n * kind → DNS label prefix for per-node function FQDNs\n * (e.g. { indexer: 'idx', 'search-head': 'sh', 'cluster-manager': 'mgmt' }).\n * A kind absent from the map falls back to the kind string itself.\n */\n dnsPrefixes: Record<string, string>;\n\n /** Object-storage buckets to create. Omit if the tool needs none. */\n storage?: StorageSpec[];\n\n /**\n * Attach a WAFv2 web ACL (AWS-managed rule sets + IP rate limit) to the ALB.\n * Defaults to true when `loadBalancer` is set; ignored otherwise.\n */\n waf?: boolean;\n\n /** Optional ALB Cognito MFA. */\n albAuth?: AlbAuthSpec;\n\n /**\n * Path, relative to the app's `infra/` dir, to the bring-up entrypoint the\n * generic worker runs after `tofu apply` succeeds (config management +\n * readiness gate). ALL tool-specific configuration lives behind this — e.g.\n * './bringup/ansible/site.yml' for Splunk. Omit for tools that are ready at\n * boot (no post-provision configuration).\n */\n bringup?: string;\n}\n\n/**\n * Generic foundation kinds the module realizes as shared infra (not compute).\n * Any plan `kind` NOT in this set is compute. Kept in sync with the module's\n * `var.foundation_kinds` default.\n */\nexport const FOUNDATION_KINDS = [\n 'network',\n 'storage',\n 'secrets',\n 'tls',\n 'load-balancer',\n 'dns',\n 'license-file',\n 'hec',\n] as const;\n\nexport type FoundationKind = (typeof FOUNDATION_KINDS)[number];\n","// =============================================================================\n// render — turn an app's declarative InfraSpec into the generic OpenTofu\n// module's variable values (tfvars).\n//\n// The platform render+apply worker builds the BASE vars (app_id, customer_id,\n// plan, subnet_cidr, tags, region, ...) from the DeployRequest, and merges these\n// SPEC-derived vars on top. Field names are snake_case to match the HCL module\n// variables 1:1. Defaults mirror the module's `optional(...)` defaults, applied\n// here so the emitted tfvars are explicit and self-describing.\n// =============================================================================\n\nimport type { InfraSpec } from './spec';\n\n/** ALB spec as the module expects it (snake_case). */\nexport interface AwsLoadBalancerVars {\n target_port: number;\n target_protocol: 'HTTP' | 'HTTPS';\n health_check_path: string;\n health_check_matcher: string;\n health_check_protocol: string; // \"\" => module falls back to target_protocol\n target_kinds: string[];\n listener_port: number;\n}\n\n/** One rendered SG ingress rule (snake_case). */\nexport interface AwsSecurityRuleVars {\n port: number;\n protocol: 'tcp' | 'udp';\n sources: string[];\n description: string;\n}\n\n/** Cognito MFA vars (snake_case), always present so `var.alb_auth.enabled` resolves. */\nexport interface AwsAlbAuthVars {\n enabled: boolean;\n user_pool_arn: string;\n user_pool_client_id: string;\n user_pool_domain: string;\n}\n\n/** The spec-derived subset of the generic AWS module's variables. */\nexport interface AwsInfraVars {\n compute_kinds: string[];\n security_rules: AwsSecurityRuleVars[];\n load_balancer: AwsLoadBalancerVars | null;\n dns_prefixes: Record<string, string>;\n waf_enabled: boolean;\n alb_auth: AwsAlbAuthVars;\n}\n\n/**\n * Render the spec-derived tfvars for the generic AWS module. Pure and\n * deterministic — no I/O, no clock, no randomness.\n */\nexport function renderInfraVars(spec: InfraSpec): AwsInfraVars {\n const security_rules: AwsSecurityRuleVars[] = (spec.securityRules ?? []).map((r) => ({\n port: r.port,\n protocol: r.protocol ?? 'tcp',\n sources: [...r.sources],\n description: r.description ?? '',\n }));\n\n const load_balancer: AwsLoadBalancerVars | null = spec.loadBalancer\n ? {\n target_port: spec.loadBalancer.targetPort,\n target_protocol: spec.loadBalancer.targetProtocol ?? 'HTTP',\n health_check_path: spec.loadBalancer.healthCheckPath,\n health_check_matcher: spec.loadBalancer.healthCheckMatcher ?? '200-399',\n health_check_protocol: spec.loadBalancer.healthCheckProtocol ?? '',\n target_kinds: [...spec.loadBalancer.targetKinds],\n listener_port: spec.loadBalancer.listenerPort ?? 443,\n }\n : null;\n\n // WAF defaults ON when there is a load balancer, OFF otherwise (the module\n // ignores it without an ALB, but keep the emitted value honest).\n const waf_enabled = spec.waf ?? Boolean(spec.loadBalancer);\n\n const alb_auth: AwsAlbAuthVars = {\n enabled: spec.albAuth?.enabled ?? false,\n user_pool_arn: spec.albAuth?.userPoolArn ?? '',\n user_pool_client_id: spec.albAuth?.userPoolClientId ?? '',\n user_pool_domain: spec.albAuth?.userPoolDomain ?? '',\n };\n\n return {\n compute_kinds: spec.computeKinds ? [...spec.computeKinds] : [],\n security_rules,\n load_balancer,\n dns_prefixes: { ...spec.dnsPrefixes },\n waf_enabled,\n alb_auth,\n };\n}\n","// =============================================================================\n// validateInfraSpec — cheap, dependency-free checks that catch the InfraSpec\n// mistakes the OpenTofu module can't (or would only surface at apply time).\n// Returns a list of human-readable errors; empty === valid.\n// =============================================================================\n\nimport type { InfraSpec } from './spec';\n\nexport function validateInfraSpec(spec: InfraSpec): string[] {\n const errors: string[] = [];\n\n if (!Array.isArray(spec.securityRules) || spec.securityRules.length === 0) {\n errors.push('securityRules must contain at least one rule.');\n }\n\n const validSources = new Set(['self', 'alb', 'admin']);\n const usesAlbSource = (spec.securityRules ?? []).some((r) =>\n (r.sources ?? []).includes('alb'),\n );\n\n for (const r of spec.securityRules ?? []) {\n if (typeof r.port !== 'number' || r.port < 1 || r.port > 65535) {\n errors.push(`securityRules: invalid port ${JSON.stringify(r.port)}.`);\n }\n if (!Array.isArray(r.sources) || r.sources.length === 0) {\n errors.push(`securityRules[port ${r.port}]: sources must be non-empty.`);\n }\n for (const s of r.sources ?? []) {\n if (!validSources.has(s)) {\n errors.push(`securityRules[port ${r.port}]: unknown source \"${s}\" (expected self|alb|admin).`);\n }\n }\n }\n\n // \"alb\" sources are meaningless without a load balancer.\n if (usesAlbSource && !spec.loadBalancer) {\n errors.push('a securityRules entry uses source \"alb\" but no loadBalancer is declared.');\n }\n\n if (spec.loadBalancer) {\n const lb = spec.loadBalancer;\n if (typeof lb.targetPort !== 'number') {\n errors.push('loadBalancer.targetPort is required.');\n }\n if (!lb.healthCheckPath || !lb.healthCheckPath.startsWith('/')) {\n errors.push('loadBalancer.healthCheckPath must be an absolute path (start with \"/\").');\n }\n if (!Array.isArray(lb.targetKinds) || lb.targetKinds.length === 0) {\n errors.push('loadBalancer.targetKinds must name at least one compute kind.');\n }\n // The web tier must be reachable from the ALB.\n const targetPortOpen = (spec.securityRules ?? []).some(\n (r) => r.port === lb.targetPort && (r.sources ?? []).includes('alb'),\n );\n if (!targetPortOpen) {\n errors.push(\n `loadBalancer.targetPort ${lb.targetPort} is not opened to source \"alb\" in securityRules — the ALB can't reach the web tier.`,\n );\n }\n }\n\n if (spec.albAuth?.enabled) {\n const a = spec.albAuth;\n if (!a.userPoolArn || !a.userPoolClientId || !a.userPoolDomain) {\n errors.push('albAuth.enabled requires userPoolArn, userPoolClientId and userPoolDomain.');\n }\n if (!spec.loadBalancer) {\n errors.push('albAuth is set but there is no loadBalancer to attach it to.');\n }\n }\n\n return errors;\n}\n"],"mappings":"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","names":[]}
|
package/dist/pipeline/index.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/pipeline/index.ts
|
|
21
21
|
var pipeline_exports = {};
|
|
22
22
|
__export(pipeline_exports, {
|
|
23
|
+
defineConnectionTester: () => defineConnectionTester,
|
|
23
24
|
defineDeployer: () => defineDeployer,
|
|
24
25
|
defineDriftDetector: () => defineDriftDetector,
|
|
25
26
|
defineHealthChecker: () => defineHealthChecker,
|
|
@@ -52,8 +53,14 @@ function defineHealthChecker(handler) {
|
|
|
52
53
|
function defineDriftDetector(handler) {
|
|
53
54
|
return handler;
|
|
54
55
|
}
|
|
56
|
+
|
|
57
|
+
// src/pipeline/define-connection-tester.ts
|
|
58
|
+
function defineConnectionTester(handler) {
|
|
59
|
+
return handler;
|
|
60
|
+
}
|
|
55
61
|
// Annotate the CommonJS export names for ESM import in node:
|
|
56
62
|
0 && (module.exports = {
|
|
63
|
+
defineConnectionTester,
|
|
57
64
|
defineDeployer,
|
|
58
65
|
defineDriftDetector,
|
|
59
66
|
defineHealthChecker,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/pipeline/index.ts","../../src/pipeline/define-validator.ts","../../src/pipeline/define-deployer.ts","../../src/pipeline/define-rollback-handler.ts","../../src/pipeline/define-health-checker.ts","../../src/pipeline/define-drift-detector.ts"],"sourcesContent":["export { defineValidator } from './define-validator'\nexport { defineDeployer } from './define-deployer'\nexport { defineRollbackHandler } from './define-rollback-handler'\nexport { defineHealthChecker } from './define-health-checker'\nexport { defineDriftDetector } from './define-drift-detector'\n","import type { PipelineContext, ValidationResult } from '../types/pipeline'\n\n/**\n * Define a validation handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineValidator } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineValidator(async (ctx) => {\n * const errors = []\n * const name = ctx.canvas.sections[0]?.fields['name']\n * if (!name) {\n * errors.push({ field: 'name', message: 'Name is required', code: 'REQUIRED' })\n * }\n * return { valid: errors.length === 0, errors, warnings: [] }\n * })\n * ```\n */\nexport function defineValidator(\n handler: (ctx: PipelineContext) => Promise<ValidationResult>,\n): (ctx: PipelineContext) => Promise<ValidationResult> {\n return handler\n}\n","import type { DeployContext, DeployResult } from '../types/pipeline'\n\n/**\n * Define a deploy handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineDeployer(async (ctx) => {\n * const { component, credential, connectivity, canvas } = ctx\n * // Push configuration to the tool\n * return { success: true, message: 'Deployed', rollbackData: previousState }\n * })\n * ```\n */\nexport function defineDeployer(\n handler: (ctx: DeployContext) => Promise<DeployResult>,\n): (ctx: DeployContext) => Promise<DeployResult> {\n return handler\n}\n","import type { RollbackContext, RollbackResult } from '../types/pipeline'\n\n/**\n * Define a rollback handler for a configuration type.\n */\nexport function defineRollbackHandler(\n handler: (ctx: RollbackContext) => Promise<RollbackResult>,\n): (ctx: RollbackContext) => Promise<RollbackResult> {\n return handler\n}\n","import type { HealthCheckContext, HealthCheckResult } from '../types/pipeline'\n\n/**\n * Define a health check handler for a configuration type.\n */\nexport function defineHealthChecker(\n handler: (ctx: HealthCheckContext) => Promise<HealthCheckResult>,\n): (ctx: HealthCheckContext) => Promise<HealthCheckResult> {\n return handler\n}\n","import type { DriftContext, DriftResult } from '../types/pipeline'\n\n/**\n * Define a drift detection handler for a configuration type.\n */\nexport function defineDriftDetector(\n handler: (ctx: DriftContext) => Promise<DriftResult>,\n): (ctx: DriftContext) => Promise<DriftResult> {\n return handler\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,SAAS,gBACd,SACqD;AACrD,SAAO;AACT;;;ACPO,SAAS,eACd,SAC+C;AAC/C,SAAO;AACT;;;ACfO,SAAS,sBACd,SACmD;AACnD,SAAO;AACT;;;ACJO,SAAS,oBACd,SACyD;AACzD,SAAO;AACT;;;ACJO,SAAS,oBACd,SAC6C;AAC7C,SAAO;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/pipeline/index.ts","../../src/pipeline/define-validator.ts","../../src/pipeline/define-deployer.ts","../../src/pipeline/define-rollback-handler.ts","../../src/pipeline/define-health-checker.ts","../../src/pipeline/define-drift-detector.ts","../../src/pipeline/define-connection-tester.ts"],"sourcesContent":["export { defineValidator } from './define-validator'\nexport { defineDeployer } from './define-deployer'\nexport { defineRollbackHandler } from './define-rollback-handler'\nexport { defineHealthChecker } from './define-health-checker'\nexport { defineDriftDetector } from './define-drift-detector'\nexport { defineConnectionTester } from './define-connection-tester'\n","import type { PipelineContext, ValidationResult } from '../types/pipeline'\n\n/**\n * Define a validation handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineValidator } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineValidator(async (ctx) => {\n * const errors = []\n * const name = ctx.canvas.sections[0]?.fields['name']\n * if (!name) {\n * errors.push({ field: 'name', message: 'Name is required', code: 'REQUIRED' })\n * }\n * return { valid: errors.length === 0, errors, warnings: [] }\n * })\n * ```\n */\nexport function defineValidator(\n handler: (ctx: PipelineContext) => Promise<ValidationResult>,\n): (ctx: PipelineContext) => Promise<ValidationResult> {\n return handler\n}\n","import type { DeployContext, DeployResult } from '../types/pipeline'\n\n/**\n * Define a deploy handler for a configuration type.\n *\n * @example\n * ```ts\n * import { defineDeployer } from '@veltrixsecops/app-sdk/pipeline'\n *\n * export default defineDeployer(async (ctx) => {\n * const { component, credential, connectivity, canvas } = ctx\n * // Push configuration to the tool\n * return { success: true, message: 'Deployed', rollbackData: previousState }\n * })\n * ```\n */\nexport function defineDeployer(\n handler: (ctx: DeployContext) => Promise<DeployResult>,\n): (ctx: DeployContext) => Promise<DeployResult> {\n return handler\n}\n","import type { RollbackContext, RollbackResult } from '../types/pipeline'\n\n/**\n * Define a rollback handler for a configuration type.\n */\nexport function defineRollbackHandler(\n handler: (ctx: RollbackContext) => Promise<RollbackResult>,\n): (ctx: RollbackContext) => Promise<RollbackResult> {\n return handler\n}\n","import type { HealthCheckContext, HealthCheckResult } from '../types/pipeline'\n\n/**\n * Define a health check handler for a configuration type.\n */\nexport function defineHealthChecker(\n handler: (ctx: HealthCheckContext) => Promise<HealthCheckResult>,\n): (ctx: HealthCheckContext) => Promise<HealthCheckResult> {\n return handler\n}\n","import type { DriftContext, DriftResult } from '../types/pipeline'\n\n/**\n * Define a drift detection handler for a configuration type.\n */\nexport function defineDriftDetector(\n handler: (ctx: DriftContext) => Promise<DriftResult>,\n): (ctx: DriftContext) => Promise<DriftResult> {\n return handler\n}\n","import type { TestConnectionContext, TestConnectionResult } from '../types/pipeline'\n\n/**\n * Define a connection-test handler for an app. The platform runs it in-process\n * with the decrypted credential to verify a Connection's endpoint + credentials\n * before they're relied on for deployments.\n */\nexport function defineConnectionTester(\n handler: (ctx: TestConnectionContext) => Promise<TestConnectionResult>,\n): (ctx: TestConnectionContext) => Promise<TestConnectionResult> {\n return handler\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACmBO,SAAS,gBACd,SACqD;AACrD,SAAO;AACT;;;ACPO,SAAS,eACd,SAC+C;AAC/C,SAAO;AACT;;;ACfO,SAAS,sBACd,SACmD;AACnD,SAAO;AACT;;;ACJO,SAAS,oBACd,SACyD;AACzD,SAAO;AACT;;;ACJO,SAAS,oBACd,SAC6C;AAC7C,SAAO;AACT;;;ACFO,SAAS,uBACd,SAC+D;AAC/D,SAAO;AACT;","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PipelineContext,
|
|
1
|
+
import { P as PipelineContext, I as ValidationResult, D as DeployContext, i as DeployResult, x as RollbackContext, z as RollbackResult, p as HealthCheckContext, r as HealthCheckResult, l as DriftContext, o as DriftResult, T as TestConnectionContext, B as TestConnectionResult } from '../pipeline-beeT8dje.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Define a validation handler for a configuration type.
|
|
@@ -50,4 +50,11 @@ declare function defineHealthChecker(handler: (ctx: HealthCheckContext) => Promi
|
|
|
50
50
|
*/
|
|
51
51
|
declare function defineDriftDetector(handler: (ctx: DriftContext) => Promise<DriftResult>): (ctx: DriftContext) => Promise<DriftResult>;
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Define a connection-test handler for an app. The platform runs it in-process
|
|
55
|
+
* with the decrypted credential to verify a Connection's endpoint + credentials
|
|
56
|
+
* before they're relied on for deployments.
|
|
57
|
+
*/
|
|
58
|
+
declare function defineConnectionTester(handler: (ctx: TestConnectionContext) => Promise<TestConnectionResult>): (ctx: TestConnectionContext) => Promise<TestConnectionResult>;
|
|
59
|
+
|
|
60
|
+
export { defineConnectionTester, defineDeployer, defineDriftDetector, defineHealthChecker, defineRollbackHandler, defineValidator };
|