@truefoundry/tfy-infra-engine 0.1.3 → 0.1.4-canary.2e1dcd4
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 +18 -12
- package/dist/index.d.mts +29 -31
- package/dist/index.d.ts +29 -31
- package/dist/index.js +38 -48
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/schema/validator.ts","../src/schema/template-json-schema.ts","../src/schema/input-validator.ts","../src/render/renderer.ts","../src/helpers/hcl.ts","../src/helpers/logic.ts","../src/helpers/types.ts","../src/helpers/index.ts","../src/render/formatter.ts","../src/integrity/hasher.ts","../src/integrity/canonical-hash.ts","../src/integrity/header.ts","../src/integrity/zones.ts","../src/render/manifest.ts","../src/integrity/drift.ts","../src/schema/envelope.ts","../src/engine.ts"],"sourcesContent":["/**\n * @truefoundry/tfy-infra-engine\n *\n * Config-driven HCL templating engine for infrastructure generation\n * with integrity verification, zone-based file ownership, and\n * deterministic hashing.\n *\n */\n\n// Error types\nexport { EngineError, EngineErrorCode } from './errors.js';\n\n// Schema types\nexport type {\n Envelope,\n Template,\n VersionInfo,\n JSONSchema7,\n FileEntry,\n FileMap,\n Manifest,\n DriftType,\n DriftReport,\n InstallResult,\n UpgradeResult,\n VerifyResult,\n HashOnlyResult,\n ResolverOptions,\n Resolver,\n} from './schema/types.js';\n\n// Schema validation\nexport { validateTemplateJson } from './schema/validator.js';\nexport { validateJsonSchemaStructure } from './schema/input-validator.js';\nexport { templateJsonSchema } from './schema/template-json-schema.js';\n\n// Rendering\nexport { isTofuAvailable } from './render/index.js';\n\n// Integrity\nexport { classifyFile, parseHeader, DEFAULT_PREFIX } from './integrity/index.js';\nexport { canonicalHash, getCanonicalHashScriptPath } from './integrity/canonical-hash.js';\n\n// Engine\nexport { createEngine } from './engine.js';\n","/**\n * Engine error codes for programmatic error handling.\n */\nexport enum EngineErrorCode {\n // Resolver errors\n TEMPLATE_NOT_FOUND = 'TEMPLATE_NOT_FOUND',\n NETWORK_ERROR = 'NETWORK_ERROR',\n GITHUB_NOT_FOUND = 'GITHUB_NOT_FOUND',\n GITHUB_RATE_LIMITED = 'GITHUB_RATE_LIMITED',\n FILE_NOT_FOUND = 'FILE_NOT_FOUND',\n HTTPS_AUTH_FAILED = 'HTTPS_AUTH_FAILED',\n\n // Validation errors\n SCHEMA_INVALID = 'SCHEMA_INVALID',\n INPUT_VALIDATION_FAILED = 'INPUT_VALIDATION_FAILED',\n TEMPLATE_JSON_NOT_FOUND = 'TEMPLATE_JSON_NOT_FOUND',\n TEMPLATE_JSON_INVALID = 'TEMPLATE_JSON_INVALID',\n\n // Rendering errors\n TEMPLATE_SYNTAX_ERROR = 'TEMPLATE_SYNTAX_ERROR',\n\n // Formatting errors\n TOFU_NOT_FOUND = 'TOFU_NOT_FOUND',\n TOFU_FMT_FAILED = 'TOFU_FMT_FAILED',\n\n // Cache errors\n CACHE_ERROR = 'CACHE_ERROR',\n\n // Integrity errors\n ENVELOPE_VALIDATION_FAILED = 'ENVELOPE_VALIDATION_FAILED',\n MANIFEST_PARSE_ERROR = 'MANIFEST_PARSE_ERROR',\n}\n\n/**\n * Custom error class for engine errors.\n * Provides structured error information including error code, cause, and details.\n */\nexport class EngineError extends Error {\n public readonly code: EngineErrorCode;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: EngineErrorCode,\n cause?: Error,\n details?: Record<string, unknown>\n ) {\n super(message, { cause });\n this.name = 'EngineError';\n this.code = code;\n this.details = details;\n\n // Maintain proper stack trace for where our error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EngineError);\n }\n }\n\n /**\n * Create a string representation including error code.\n */\n override toString(): string {\n return `[${this.code}] ${this.message}`;\n }\n\n /**\n * Convert error to JSON-serializable object.\n */\n toJSON(): Record<string, unknown> {\n const causeError = this.cause as Error | undefined;\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n details: this.details,\n cause: causeError?.message,\n };\n }\n}\n","/**\n * Template JSON structure validation using AJV.\n *\n * Validates the top-level structure of template.json against the\n * templateJsonSchema (JSON Schema Draft-07) defined in template-json-schema.ts.\n *\n * Reference: R-006, data-model.md validator.ts\n */\n\nimport Ajv, { type ErrorObject } from 'ajv';\nimport type { TemplateMetadata } from './types.js';\nimport type { JSONSchema7 } from './json-schema.js';\nimport { templateJsonSchema } from './template-json-schema.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\n/**\n * Result of validating a template.json file.\n */\nexport interface TemplateJsonResult {\n metadata: TemplateMetadata;\n jsonSchema: JSONSchema7;\n}\n\n/**\n * AJV instance for template.json validation.\n * Configured with allErrors for complete diagnostics.\n */\nconst ajv = new Ajv({\n allErrors: true,\n strict: false,\n validateSchema: false,\n});\n\nconst validate = ajv.compile(templateJsonSchema);\n\n/**\n * Validate the structure of a parsed template.json file.\n *\n * Checks:\n * - Data is an object with \"template\" and \"schema\" keys\n * - template.name is a non-empty string\n * - template.version is a semver string (x.y.z)\n * - template.description is an optional string\n * - schema is a non-null object with type: \"object\" and properties\n *\n * @param data - Parsed JSON content from template.json\n * @returns Validated metadata and JSON Schema\n * @throws EngineError with TEMPLATE_JSON_INVALID on failure\n */\nexport function validateTemplateJson(data: unknown): TemplateJsonResult {\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new EngineError(\n 'template.json must be a JSON object',\n EngineErrorCode.TEMPLATE_JSON_INVALID\n );\n }\n\n const valid = validate(data);\n\n if (!valid) {\n const message = formatAjvErrors(validate.errors ?? []);\n throw new EngineError(message, EngineErrorCode.TEMPLATE_JSON_INVALID);\n }\n\n const record = data as Record<string, unknown>;\n const templateBlock = record['template'] as Record<string, unknown>;\n\n const metadata: TemplateMetadata = {\n name: templateBlock['name'] as string,\n version: templateBlock['version'] as string,\n ...(templateBlock['description'] !== undefined\n ? { description: templateBlock['description'] as string }\n : {}),\n };\n\n const jsonSchema = record['schema'] as JSONSchema7;\n\n return { metadata, jsonSchema };\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Format AJV errors into a human-readable message for EngineError.\n *\n * Produces messages that are descriptive and contain relevant keywords\n * (e.g., \"template\", \"schema\", \"semver\") for diagnostic clarity.\n */\nfunction formatAjvErrors(errors: ErrorObject[]): string {\n const first = errors[0];\n if (!first) {\n return 'template.json validation failed';\n }\n const path = first.instancePath || '';\n\n if (first.keyword === 'required') {\n const prop = (first.params as Record<string, unknown>)['missingProperty'] as string;\n return `template.json must have a \"${prop}\" key`;\n }\n\n if (first.keyword === 'type') {\n const expected = (first.params as Record<string, unknown>)['type'] as string;\n return `template.json${path ? ` \"${dotPath(path)}\"` : ''} must be ${expected}`;\n }\n\n if (first.keyword === 'pattern' && path === '/template/version') {\n return `template.json \"template.version\" must be semver format (x.y.z)`;\n }\n\n if (first.keyword === 'minLength' && path === '/template/name') {\n return `template.json \"template.name\" must be a non-empty string`;\n }\n\n if (first.keyword === 'const') {\n const expected = (first.params as Record<string, unknown>)['allowedValue'];\n return `template.json \"${dotPath(path)}\" must be ${JSON.stringify(expected)}`;\n }\n\n return `template.json validation failed at ${path || '/'}: ${first.message ?? 'unknown error'}`;\n}\n\n/**\n * Convert JSON Pointer path (e.g., \"/template/version\") to dot notation (\"template.version\").\n */\nfunction dotPath(jsonPointer: string): string {\n return jsonPointer.replace(/^\\//, '').replace(/\\//g, '.');\n}\n","/**\n * JSON Schema (Draft-07) for template.json files.\n *\n * This is the source of truth for template.json validation.\n * Used by validator.ts via AJV for runtime validation.\n *\n * Validates:\n * - \"template\" key: name (required, non-empty), version (semver, required), description (optional string)\n * - \"schema\" key: must be a JSON Schema object with type: \"object\" and a properties key\n *\n * Note: No additionalProperties: false at root level — extra top-level keys are allowed\n * for forward compatibility.\n */\n\nimport type { JSONSchema7 } from './json-schema.js';\n\nexport const templateJsonSchema: JSONSchema7 = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n type: 'object',\n properties: {\n template: {\n type: 'object',\n properties: {\n name: { type: 'string', minLength: 1 },\n description: { type: 'string' },\n version: { type: 'string', pattern: '^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$' },\n },\n required: ['name', 'version'],\n additionalProperties: false,\n },\n schema: {\n type: 'object',\n description: 'JSON Schema Draft-07 defining template inputs',\n properties: {\n type: { type: 'string', const: 'object' },\n properties: { type: 'object' },\n required: { type: 'array', items: { type: 'string' } },\n },\n required: ['type', 'properties'],\n },\n },\n required: ['template', 'schema'],\n};\n","/**\n * AJV-based JSON Schema input validation.\n *\n * Provides:\n * - createInputValidator(): Compiles a JSON Schema into an AJV validator\n * - validateAndApplyDefaults(): Validates inputs + applies defaults in one pass\n * - validateJsonSchemaStructure(): Asserts root type: \"object\" + properties key\n *\n * Local $ref pointers (e.g., \"#/components/schemas/...\") are supported natively\n * by AJV and resolved automatically during schema compilation.\n *\n * CHANGE (008): New module replacing hand-rolled validateInputs() and applyDefaults().\n *\n * Reference: R-001, R-007, R-010\n */\n\nimport Ajv, { type ValidateFunction, type ErrorObject } from 'ajv';\nimport type { JSONSchema7 } from './json-schema.js';\nimport type { ValidationResult, ValidationError } from './types.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\n/**\n * Shared AJV instance configured per R-001.\n *\n * - useDefaults: true — applies schema-defined defaults during validation (FR-006)\n * - allErrors: true — collects all validation errors in a single pass (FR-008)\n * - discriminator: true — supports oneOf with discriminator property\n * - strict: false — allows unknown keywords (UI metadata like +label, +usage)\n * - validateSchema: false — we validate schema structure ourselves\n */\nconst ajv = new Ajv({\n useDefaults: true,\n allErrors: true,\n discriminator: true,\n strict: false,\n validateSchema: false,\n});\n\n/**\n * Compile a JSON Schema Draft-07 into an AJV validator function.\n *\n * @param jsonSchema - JSON Schema to compile\n * @returns Compiled AJV validate function\n * @throws EngineError if schema cannot be compiled\n */\nexport function createInputValidator(jsonSchema: JSONSchema7): ValidateFunction {\n try {\n return ajv.compile(jsonSchema);\n } catch (error) {\n throw new EngineError(\n `Failed to compile JSON Schema: ${(error as Error).message}`,\n EngineErrorCode.SCHEMA_INVALID,\n error as Error\n );\n }\n}\n\n/**\n * Validate inputs against a compiled schema and apply defaults in one pass.\n *\n * AJV's `useDefaults: true` mutates the input data in-place, inserting\n * default values for missing properties. Validation and defaults happen\n * simultaneously — no separate applyDefaults() call needed.\n *\n * @param validator - Compiled AJV validate function from createInputValidator()\n * @param inputs - Input data to validate (mutated in-place with defaults)\n * @returns ValidationResult with errors if invalid\n */\nexport function validateAndApplyDefaults(\n validator: ValidateFunction,\n inputs: Record<string, unknown>\n): ValidationResult {\n const valid = validator(inputs);\n\n if (valid) {\n return { valid: true };\n }\n\n const errors: ValidationError[] = (validator.errors ?? []).map(ajvErrorToValidationError);\n\n return {\n valid: false,\n errors,\n };\n}\n\n/**\n * Validate that a JSON Schema has the required structure for template inputs.\n * Must be an object with type: \"object\" and a properties key.\n *\n * @param schema - Schema to validate\n * @throws EngineError if structure is invalid\n */\nexport function validateJsonSchemaStructure(schema: JSONSchema7): void {\n if (!schema || typeof schema !== 'object') {\n throw new EngineError(\n 'Schema must be a non-null object',\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { received: typeof schema }\n );\n }\n\n if (schema.type !== 'object') {\n throw new EngineError(\n `Schema root must have \"type\": \"object\", got \"${schema.type ?? 'undefined'}\"`,\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { received: schema.type }\n );\n }\n\n if (!schema.properties || typeof schema.properties !== 'object') {\n throw new EngineError(\n 'Schema root must have a \"properties\" key',\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { hasProperties: !!schema.properties }\n );\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Map an AJV ErrorObject to our ValidationError interface.\n * Uses JSON Pointer format for paths (R-007).\n */\nfunction ajvErrorToValidationError(error: ErrorObject): ValidationError {\n return {\n path: error.instancePath || '/',\n message: error.message ?? 'Validation failed',\n expected: formatExpected(error),\n received: undefined,\n };\n}\n\n/**\n * Extract expected value description from AJV error params.\n */\nfunction formatExpected(error: ErrorObject): string | undefined {\n const params = error.params as Record<string, unknown>;\n if (!params) return undefined;\n\n if (error.keyword === 'type') {\n return String(params['type']);\n }\n if (error.keyword === 'required') {\n return `required property '${String(params['missingProperty'])}'`;\n }\n if (error.keyword === 'pattern') {\n return `match pattern ${String(params['pattern'])}`;\n }\n if (error.keyword === 'enum') {\n return `one of ${JSON.stringify(params['allowedValues'])}`;\n }\n if (error.keyword === 'const') {\n return `value ${JSON.stringify(params['allowedValue'])}`;\n }\n\n return undefined;\n}\n","/**\n * Template renderer using Handlebars.\n */\n\nimport Handlebars from 'handlebars';\nimport type { Template } from '../schema/types.js';\nimport { registerAllHelpers } from '../helpers/index.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nconst HBS_COMPILE_OPTIONS: CompileOptions = {\n noEscape: true,\n strict: false,\n};\n\n/**\n * Create a Handlebars environment with all custom helpers registered.\n */\nfunction createConfiguredHandlebars(): typeof Handlebars {\n const hbs = Handlebars.create();\n registerAllHelpers(hbs);\n return hbs;\n}\n\n/**\n * Context passed to templates during rendering.\n */\nexport interface RenderContext {\n /** User-provided inputs */\n [key: string]: unknown;\n /** Template metadata (injected by engine) */\n _template: {\n name: string;\n version: string;\n source: string;\n };\n}\n\n/**\n * Create a render context from inputs and template metadata.\n *\n * CHANGE (008): Access template.metadata instead of template.schema.template.\n *\n * @param inputs - User-provided inputs\n * @param template - Template with metadata\n * @returns Render context for Handlebars\n */\nexport function createRenderContext(\n inputs: Record<string, unknown>,\n template: Template\n): RenderContext {\n return {\n ...inputs,\n _template: {\n name: template.metadata.name,\n version: template.metadata.version,\n source: template.source,\n },\n };\n}\n\n/**\n * Render all template files with the given context.\n *\n * @param template - Template to render\n * @param inputs - User-provided inputs\n * @returns Map of file paths to rendered content\n */\nexport function renderTemplate(\n template: Template,\n inputs: Record<string, unknown>\n): Map<string, string> {\n const hbs = createConfiguredHandlebars();\n const context = createRenderContext(inputs, template);\n const results = new Map<string, string>();\n\n for (const [outputPath, hbsContent] of template.files) {\n try {\n const compiled = hbs.compile(hbsContent, HBS_COMPILE_OPTIONS);\n const rendered = compiled(context);\n results.set(outputPath, rendered);\n } catch (error) {\n throw new EngineError(\n `Failed to render ${outputPath}: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error,\n { file: outputPath, template: template.source }\n );\n }\n }\n\n return results;\n}\n\n/**\n * Compile a single template string.\n * Useful for testing or one-off rendering.\n *\n * @param templateString - Handlebars template string\n * @param context - Context object\n * @returns Rendered string\n */\nexport function renderString(templateString: string, context: Record<string, unknown>): string {\n const hbs = createConfiguredHandlebars();\n\n try {\n const compiled = hbs.compile(templateString, HBS_COMPILE_OPTIONS);\n return compiled(context);\n } catch (error) {\n throw new EngineError(\n `Failed to render template string: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error\n );\n }\n}\n\n/**\n * Validate template syntax without rendering.\n *\n * @param hbsContent - Handlebars template content\n * @returns true if valid, throws on error\n */\nexport function validateTemplateSyntax(hbsContent: string): boolean {\n try {\n Handlebars.precompile(hbsContent);\n return true;\n } catch (error) {\n throw new EngineError(\n `Invalid template syntax: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error\n );\n }\n}\n","/**\n * HCL formatting helpers for Handlebars templates.\n * These helpers format JavaScript values as valid HCL syntax.\n */\n\nimport Handlebars from 'handlebars';\n\n/**\n * Register HCL formatting helpers with Handlebars.\n */\nexport function registerHclHelpers(handlebars: typeof Handlebars): void {\n /**\n * Convert any JavaScript value to valid HCL/Terraform syntax.\n * Handles strings, numbers, booleans, arrays, and objects.\n *\n * @example\n * {{toTerraformValue name}} → \"my-cluster\"\n * {{toTerraformValue count}} → 3\n * {{toTerraformValue enabled}} → true\n * {{toTerraformValue tags}} → { \"key\" = \"value\" }\n */\n handlebars.registerHelper('toTerraformValue', function (value: unknown): Handlebars.SafeString {\n return new Handlebars.SafeString(formatValue(value));\n });\n}\n\n/**\n * Format a JavaScript value as HCL syntax.\n */\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return 'null';\n }\n\n if (typeof value === 'string') {\n // Escape backslashes and quotes\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n');\n return `\"${escaped}\"`;\n }\n\n if (typeof value === 'boolean' || typeof value === 'number') {\n return String(value);\n }\n\n if (Array.isArray(value)) {\n const elements = value.map((item) => formatValue(item));\n if (elements.length === 0) {\n return '[]';\n }\n // Use multi-line format for non-empty arrays\n if (elements.some((e) => e.includes('\\n') || e.length > 40)) {\n return `[\\n ${elements.join(',\\n ')}\\n]`;\n }\n return `[${elements.join(', ')}]`;\n }\n\n if (typeof value === 'object') {\n return formatObject(value as Record<string, unknown>);\n }\n\n return JSON.stringify(value);\n}\n\n/**\n * Format an object as HCL map syntax.\n */\nfunction formatObject(obj: Record<string, unknown>): string {\n const entries = Object.entries(obj);\n if (entries.length === 0) {\n return '{}';\n }\n\n const formatted = entries.map(([key, val]) => {\n // Quote keys that contain special characters\n const quotedKey = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key) ? key : `\"${key}\"`;\n return `${quotedKey} = ${formatValue(val)}`;\n });\n\n return `{\\n ${formatted.join('\\n ')}\\n}`;\n}\n","/**\n * Logic helpers for Handlebars templates.\n * These helpers provide boolean logic and comparison operations.\n */\n\nimport type Handlebars from 'handlebars';\n\n/**\n * Register logic helpers with Handlebars.\n */\nexport function registerLogicHelpers(handlebars: typeof Handlebars): void {\n /**\n * Strict equality comparison.\n *\n * @example\n * {{#if (eq env \"prod\")}}production{{/if}}\n */\n handlebars.registerHelper('eq', (a: unknown, b: unknown): boolean => a === b);\n\n /**\n * Logical AND (all arguments must be truthy).\n *\n * @example\n * {{#if (and enabled ready)}}go{{/if}}\n */\n handlebars.registerHelper('and', function (...args: unknown[]): boolean {\n // Last argument is Handlebars options object\n const values = args.slice(0, -1);\n return values.every(Boolean);\n });\n\n /**\n * Logical OR (any argument must be truthy).\n *\n * @example\n * {{#if (or flagA flagB)}}at least one{{/if}}\n */\n handlebars.registerHelper('or', function (...args: unknown[]): boolean {\n // Last argument is Handlebars options object\n const values = args.slice(0, -1);\n return values.some(Boolean);\n });\n}\n","/**\n * Type checking helpers for Handlebars templates.\n */\n\nimport type Handlebars from 'handlebars';\n\n/**\n * Register type checking helpers with Handlebars.\n */\nexport function registerTypeHelpers(handlebars: typeof Handlebars): void {\n /**\n * Check if value is a string.\n *\n * @example\n * {{#if (isString value)}}string value{{/if}}\n */\n handlebars.registerHelper('isString', (value: unknown): boolean => {\n return typeof value === 'string';\n });\n\n /**\n * Check if value is defined (not undefined and not null).\n *\n * @example\n * {{#if (isDefined optional)}}value exists{{/if}}\n */\n handlebars.registerHelper('isDefined', (value: unknown): boolean => {\n return value !== undefined && value !== null;\n });\n\n /**\n * Check if value is not empty (inverse of isEmpty).\n *\n * @example\n * {{#if (isNotEmpty items)}}has items{{/if}}\n */\n handlebars.registerHelper('isNotEmpty', (value: unknown): boolean => {\n if (value === null || value === undefined) return false;\n if (typeof value === 'string') return value.length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n });\n}\n","/**\n * Handlebars helpers registration.\n * Registers all helpers with a Handlebars instance.\n */\n\nimport type Handlebars from 'handlebars';\nimport { registerHclHelpers } from './hcl.js';\nimport { registerLogicHelpers } from './logic.js';\nimport { registerTypeHelpers } from './types.js';\n\n/**\n * Register all engine helpers with a Handlebars instance.\n *\n * @param handlebars - Handlebars instance to register helpers with\n */\nexport function registerAllHelpers(handlebars: typeof Handlebars): void {\n registerHclHelpers(handlebars);\n registerLogicHelpers(handlebars);\n registerTypeHelpers(handlebars);\n}\n\n// Re-export individual registration functions for selective use\nexport { registerHclHelpers } from './hcl.js';\nexport { registerLogicHelpers } from './logic.js';\nexport { registerTypeHelpers } from './types.js';\n","/**\n * HCL formatter using tofu fmt.\n */\n\nimport { spawn, execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Options for formatting.\n */\nexport interface FormatOptions {\n /** Skip formatting entirely */\n skip?: boolean;\n /** Timeout in milliseconds (default: 10000) */\n timeout?: number;\n}\n\n/**\n * Default format options.\n */\nconst DEFAULT_FORMAT_OPTIONS: Required<FormatOptions> = {\n skip: false,\n timeout: 10000,\n};\n\n/**\n * Normalize multiple blank lines to a single blank line.\n * This improves readability of generated HCL by collapsing\n * excess whitespace that can occur with Handlebars conditionals.\n *\n * @param content - Content to normalize\n * @returns Content with normalized blank lines\n */\nexport function normalizeBlankLines(content: string): string {\n let result = content\n .replace(/\\n{3,}/g, '\\n\\n') // 3+ newlines → 2 (one blank line)\n .replace(/^\\n+/, ''); // Remove leading blank lines\n\n // Ensure single trailing newline\n result = result.replace(/\\n*$/, '\\n');\n\n return result;\n}\n\nconst HCL_FORMATTABLE_SUFFIXES = ['.tf', '.tfvars', '.tftest.hcl'];\n\nfunction isHclFormattable(filePath: string): boolean {\n return HCL_FORMATTABLE_SUFFIXES.some((suffix) => filePath.endsWith(suffix));\n}\n\n/**\n * Format HCL content using tofu fmt.\n *\n * @param content - HCL content to format\n * @param options - Format options\n * @returns Formatted content\n */\nexport async function formatHCL(content: string, options?: FormatOptions): Promise<string> {\n const opts = { ...DEFAULT_FORMAT_OPTIONS, ...options };\n\n if (opts.skip) {\n return normalizeBlankLines(content);\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn('tofu', ['fmt', '-'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n child.kill();\n }, opts.timeout);\n\n child.stdout.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('error', (error: NodeJS.ErrnoException) => {\n clearTimeout(timer);\n if (error.code === 'ENOENT') {\n reject(\n new EngineError(\n 'tofu binary not found. Please install OpenTofu or use --skip-format option.',\n EngineErrorCode.TOFU_NOT_FOUND,\n error,\n { suggestion: 'Install OpenTofu from https://opentofu.org/' }\n )\n );\n } else {\n reject(\n new EngineError(\n `tofu fmt failed: ${error.message}`,\n EngineErrorCode.TOFU_FMT_FAILED,\n error,\n { stderr }\n )\n );\n }\n });\n\n child.on('close', (code) => {\n clearTimeout(timer);\n\n if (timedOut) {\n reject(\n new EngineError(\n `tofu fmt timed out after ${opts.timeout}ms`,\n EngineErrorCode.TOFU_FMT_FAILED,\n undefined,\n { timeout: opts.timeout }\n )\n );\n return;\n }\n\n if (code !== 0) {\n reject(\n new EngineError(\n `tofu fmt failed: ${stderr || 'Unknown error'}`,\n EngineErrorCode.TOFU_FMT_FAILED,\n undefined,\n { stderr, exitCode: code }\n )\n );\n return;\n }\n\n resolve(normalizeBlankLines(stdout));\n });\n\n // Write content to stdin\n child.stdin.write(content);\n child.stdin.end();\n });\n}\n\n/**\n * Format multiple HCL files.\n *\n * @param files - Map of file paths to content\n * @param options - Format options\n * @returns Map of file paths to formatted content\n */\nexport async function formatFiles(\n files: Map<string, string>,\n options?: FormatOptions\n): Promise<Map<string, string>> {\n const opts = { ...DEFAULT_FORMAT_OPTIONS, ...options };\n\n if (opts.skip) {\n return files;\n }\n\n const results = new Map<string, string>();\n\n // Format files sequentially to avoid overwhelming the system\n for (const [path, content] of files) {\n if (isHclFormattable(path)) {\n try {\n const formatted = await formatHCL(content, options);\n results.set(path, formatted);\n } catch (error) {\n // Add file context to error\n if (error instanceof EngineError) {\n throw new EngineError(error.message, error.code, error.cause as Error, {\n ...error.details,\n file: path,\n });\n }\n throw error;\n }\n } else {\n // Pass through non-tf files with normalized blank lines\n results.set(path, normalizeBlankLines(content));\n }\n }\n\n return results;\n}\n\n/**\n * Check if tofu is available in the system.\n *\n * @returns true if tofu is available\n */\nexport async function isTofuAvailable(): Promise<boolean> {\n try {\n await execFileAsync('tofu', ['version'], {\n timeout: 5000,\n encoding: 'utf-8',\n });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get tofu version.\n *\n * @returns Version string or null if not available\n */\nexport async function getTofuVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('tofu', ['version'], {\n timeout: 5000,\n encoding: 'utf-8',\n });\n // Parse version from output like \"OpenTofu v1.6.0\"\n const match = stdout.match(/v[\\d.]+/);\n return match ? match[0] : null;\n } catch {\n return null;\n }\n}\n","/**\n * Header-agnostic file hashing and aggregate Platform Hash computation.\n *\n * The hashing pipeline for each file delegates to canonical_hash.sh which\n * strips headers, canonicalizes HCL, and computes SHA-256. The aggregate hash\n * combines all platform-zone file hashes sorted by path.\n *\n * Reference: R-004, R-010, FR-004, FR-005, FR-026, FR-034\n */\n\nimport { createHash } from 'node:crypto';\nimport { canonicalHash } from './canonical-hash.js';\nimport type { FileMap } from '../schema/types.js';\nimport { MANIFEST_FILENAME } from './zones.js';\n\n/**\n * Compute a SHA-256 hash of arbitrary content.\n *\n * @param content - Content to hash\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function sha256(content: string): string {\n const hex = createHash('sha256').update(content, 'utf-8').digest('hex');\n return `sha256:${hex}`;\n}\n\n/**\n * Compute format-independent content hash for a single file.\n *\n * Delegates to the canonical hash pipeline: strip @tfy-status header →\n * canonicalize HCL (strip comments, whitespace, normalize trailing commas) →\n * SHA-256.\n *\n * @param content - Full file content (may include @tfy-status header)\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashFileContent(content: string): string {\n return canonicalHash(content);\n}\n\n/**\n * Compute the aggregate Platform Hash from a file map.\n *\n * Only platform-zone files are included. Files are sorted lexicographically\n * by path. The hash is computed from a concatenation of \"path:hash\\n\" lines.\n *\n * Algorithm (R-004):\n * 1. Collect all Platform Zone file entries: [(path, hash), ...]\n * 2. Sort by path (lexicographic, case-sensitive)\n * 3. Join as: \"path1:hash1\\npath2:hash2\\n...\"\n * 4. SHA-256 the joined string\n * 5. Return \"sha256:<hex>\"\n *\n * @param files - Zone-tagged file map\n * @returns Aggregate hash prefixed with \"sha256:\"\n */\nexport function computeAggregateHash(files: FileMap): string {\n // Step 1: Collect platform-zone files (excluding manifest.json to avoid\n // circular dependency — the manifest contains the aggregate hash)\n const entries: Array<{ path: string; hash: string }> = [];\n\n for (const [path, entry] of files) {\n if (entry.zone === 'platform' && path !== MANIFEST_FILENAME) {\n entries.push({\n path,\n hash: hashFileContent(entry.content),\n });\n }\n }\n\n // Step 2: Sort by path (lexicographic, case-sensitive)\n entries.sort((a, b) => a.path.localeCompare(b.path));\n\n // Step 3: Join as \"path:hash\\n\"\n const concatenated = entries.map((e) => `${e.path}:${e.hash}`).join('\\n');\n\n // Step 4–5: SHA-256 with prefix\n return sha256(concatenated);\n}\n","/**\n * Format-independent canonical hashing via external shell script.\n *\n * Delegates to `scripts/canonical_hash.sh` which canonicalizes HCL content\n * (stripping headers, comments, whitespace, and normalizing trailing commas)\n * then computes a SHA-256 hash. Uses spawnSync to keep the entire call graph\n * synchronous.\n *\n * Reference: R-003, R-010\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { stripHeader } from './header.js';\n\nconst HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;\nconst DEFAULT_TIMEOUT_MS = 3_000;\n\nlet _cachedScriptPath: string | undefined;\n\n/**\n * Walk up from a starting directory to find the nearest directory\n * containing package.json (the package root).\n */\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n for (;;) {\n if (existsSync(join(dir, 'package.json'))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error(`Cannot find package root (no package.json found above ${startDir})`);\n}\n\n/**\n * Get the absolute path to the canonical_hash.sh script.\n *\n * Resolves by walking up from the current module's directory to find the\n * package root, then appending `scripts/canonical_hash.sh`. The result is\n * cached after first resolution.\n *\n * Works in all environments:\n * - Dev/test: __dirname = src/integrity -> walk up 2 levels\n * - tsup CJS: __dirname = dist -> walk up 1 level\n * - tsup ESM: __dirname shimmed by esbuild -> walk up 1 level\n */\nexport function getCanonicalHashScriptPath(): string {\n if (_cachedScriptPath !== undefined) return _cachedScriptPath;\n\n const pkgRoot = findPackageRoot(__dirname);\n _cachedScriptPath = join(pkgRoot, 'scripts', 'canonical_hash.sh');\n return _cachedScriptPath;\n}\n\n/**\n * Compute a format-independent canonical hash of HCL content.\n *\n * The shell script handles the full pipeline: strip @tfy-status header,\n * strip carriage returns, canonicalize via AWK 4-state machine, then SHA-256.\n *\n * If the script fails for any reason (not found, timeout, bad exit code,\n * malformed output), falls back to a raw SHA-256 of the header-stripped\n * content and logs a warning.\n *\n * @param content - Raw file content (may include @tfy-status header)\n * @param options - Optional timeout in milliseconds (default: 10000)\n * @returns Hash string in format \"sha256:<64-hex-chars>\"\n */\nexport function canonicalHash(content: string, options?: { timeout?: number }): string {\n const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS;\n\n try {\n const scriptPath = getCanonicalHashScriptPath();\n const result = spawnSync('sh', [scriptPath], {\n input: content,\n encoding: 'utf-8',\n timeout,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n if (result.error) {\n throw result.error;\n }\n\n if (result.status !== 0) {\n throw new Error(`canonical_hash.sh exited with code ${result.status}: ${result.stderr}`);\n }\n\n const hash = result.stdout.trim();\n if (!HASH_PATTERN.test(hash)) {\n throw new Error(`canonical_hash.sh returned malformed output: ${hash}`);\n }\n\n return hash;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(\n `[tfy-infra-engine] canonical hash failed, using raw hash fallback: ${message}\\n`\n );\n const stripped = stripHeader(content);\n const hex = createHash('sha256').update(stripped, 'utf-8').digest('hex');\n return `sha256:${hex}`;\n }\n}\n","/**\n * @tfy-status header processing: parse, strip, inject.\n *\n * The header is a structured metadata block embedded as Terraform comment lines\n * at the top of every Platform Zone file.\n *\n * Format (R-001):\n * ```hcl\n * # @tfy-status:begin\n * # {\"managed\":true,\"source\":\"...\",\"version\":\"...\",\"intent_id\":\"...\",\"content_hash\":\"sha256:...\"}\n * # @tfy-status:end\n * ```\n *\n * Reference: R-001, R-002, R-010, FR-044 through FR-046\n */\n\nimport type { TfyStatusHeader } from '../schema/types.js';\n\n/** Begin sentinel for header detection */\nconst HEADER_BEGIN = '# @tfy-status:begin';\n\n/** End sentinel for header detection */\nconst HEADER_END = '# @tfy-status:end';\n\n/**\n * Parse a @tfy-status header from file content.\n * Returns undefined if no valid header is found.\n * (FR-044)\n *\n * @param content - File content possibly containing a header\n * @returns Parsed header or undefined\n */\nexport function parseHeader(content: string): TfyStatusHeader | undefined {\n const lines = content.split('\\n');\n\n // Header must start at line 0\n if (lines[0] !== HEADER_BEGIN) {\n return undefined;\n }\n\n // End sentinel must be at line 2\n if (lines[2] !== HEADER_END) {\n return undefined;\n }\n\n // Line 1 must be a comment with JSON payload\n const jsonLine = lines[1];\n if (!jsonLine || !jsonLine.startsWith('# ')) {\n return undefined;\n }\n\n const jsonStr = jsonLine.substring(2); // Remove \"# \" prefix\n\n try {\n const parsed = JSON.parse(jsonStr) as Record<string, unknown>;\n\n // Map snake_case JSON fields to camelCase TypeScript interface\n return {\n managed: parsed['managed'] as boolean,\n source: parsed['source'] as string,\n version: parsed['version'] as string,\n intentId: parsed['intent_id'] as string,\n contentHash: parsed['content_hash'] as string,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Strip the @tfy-status header from file content, returning only functional HCL.\n * If no header is found, returns content unchanged.\n * (FR-045)\n *\n * Algorithm (R-010):\n * 1. Check if content starts with \"# @tfy-status:begin\\n\"\n * 2. If yes, find the line \"# @tfy-status:end\\n\"\n * 3. Remove everything from start through (and including) the end sentinel line\n * 4. If leading newline remains after stripping, remove it\n *\n * @param content - File content possibly containing a header\n * @returns Content without the header\n */\nexport function stripHeader(content: string): string {\n if (!content.startsWith(HEADER_BEGIN + '\\n')) {\n return content;\n }\n\n const endMarker = HEADER_END + '\\n';\n const endIndex = content.indexOf(endMarker);\n\n if (endIndex === -1) {\n return content;\n }\n\n // Remove everything up to and including the end sentinel line\n let stripped = content.substring(endIndex + endMarker.length);\n\n // Remove the blank line separator after the header (if present)\n if (stripped.startsWith('\\n')) {\n stripped = stripped.substring(1);\n }\n\n return stripped;\n}\n\n/**\n * Inject a @tfy-status header into file content, prepending it as comment lines.\n * (FR-046)\n *\n * The header is always injected AFTER formatting (R-002) to ensure:\n * - tofu fmt never alters the header\n * - The content_hash matches the hash of content without the header\n *\n * @param content - File content to prepend header to\n * @param header - Header metadata to inject\n * @returns Content with header prepended\n */\nexport function injectHeader(content: string, header: TfyStatusHeader): string {\n // Map camelCase TypeScript fields to snake_case JSON (HCL convention)\n const jsonPayload = JSON.stringify({\n managed: header.managed,\n source: header.source,\n version: header.version,\n intent_id: header.intentId,\n content_hash: header.contentHash,\n });\n\n return `${HEADER_BEGIN}\\n# ${jsonPayload}\\n${HEADER_END}\\n\\n${content}`;\n}\n","/**\n * Zone classification for file ownership.\n *\n * Classifies files as Platform Zone or User Zone based on filename prefix.\n * Reference: R-007, FR-001, FR-002\n */\n\nimport { basename } from 'node:path';\nimport type { Zone, FileMap } from '../schema/types.js';\n\n/**\n * Default platform filename prefix.\n */\nexport const DEFAULT_PREFIX = 'tfy_';\n\n/**\n * The manifest filename is always classified as platform zone.\n */\nexport const MANIFEST_FILENAME = 'manifest.json';\n\n/**\n * Classify a file as Platform Zone or User Zone based on its filename.\n *\n * Rules (R-007):\n * 1. Only the basename matters (not the directory path).\n * 2. The prefix check is case-sensitive.\n * 3. The Manifest file itself (manifest.json) is classified as Platform Zone.\n * 4. Files without .tf extension that have the prefix are still Platform Zone.\n * 5. The prefix is configurable per envelope/configuration.\n *\n * @param filePath - Relative or absolute file path\n * @param prefix - Platform Zone filename prefix (default: \"tfy_\")\n * @returns Zone classification (\"platform\" or \"user\")\n */\nexport function classifyFile(filePath: string, prefix: string = DEFAULT_PREFIX): Zone {\n // Normalize path separators and get basename\n const name = basename(filePath.replace(/\\\\/g, '/'));\n\n // Rule 3: manifest.json is always platform\n if (name === MANIFEST_FILENAME) {\n return 'platform';\n }\n\n // Rules 1, 2, 4, 5: check if basename starts with the prefix (case-sensitive)\n if (name.startsWith(prefix)) {\n return 'platform';\n }\n\n return 'user';\n}\n\n/**\n * Count files classified as platform zone in a file map.\n */\nexport function countPlatformFiles(files: FileMap): number {\n let count = 0;\n for (const [, entry] of files) {\n if (entry.zone === 'platform') count++;\n }\n return count;\n}\n","/**\n * Manifest generation for rendered output — JSON v1.0.\n *\n * The Manifest is the \"State Passport\" recording cluster identity,\n * aggregate Platform Hash, per-file hashes, and engine metadata.\n *\n * Reference: R-005, FR-007, FR-033 through FR-036\n */\n\nimport type { Manifest, ManifestFileEntry, Template, FileMap } from '../schema/types.js';\nimport { sha256, hashFileContent, computeAggregateHash } from '../integrity/hasher.js';\nimport { MANIFEST_FILENAME } from '../integrity/zones.js';\n\ndeclare const __ENGINE_VERSION__: string;\nconst ENGINE_VERSION = __ENGINE_VERSION__;\n\nexport interface GenerateManifestOptions {\n files: FileMap;\n template: Template;\n inputs: Record<string, unknown>;\n formatted: boolean;\n intentId: string;\n platformPrefix?: string;\n}\n\n/**\n * Generate a Manifest for a zone-tagged file map.\n * (FR-007, FR-033, FR-034, FR-036)\n */\nexport function generateManifest(opts: GenerateManifestOptions): Manifest {\n const { files, template, inputs, formatted, intentId, platformPrefix = 'tfy_' } = opts;\n const manifestFiles: ManifestFileEntry[] = [];\n\n for (const [path, entry] of files) {\n // Skip the manifest itself if it's in the map\n if (path === MANIFEST_FILENAME) continue;\n\n manifestFiles.push({\n path,\n hash: hashFileContent(entry.content),\n size: Buffer.byteLength(entry.content, 'utf-8'),\n source: template.source,\n version: template.metadata.version,\n zone: entry.zone,\n });\n }\n\n // Sort files by path for deterministic output (FR-035)\n manifestFiles.sort((a, b) => a.path.localeCompare(b.path));\n\n // Compute aggregate hash from platform files only (FR-034)\n const aggregateHash = computeAggregateHash(files);\n\n return {\n manifestVersion: '1.0',\n intentId,\n generatedAt: new Date().toISOString(),\n templateSource: template.source,\n templateVersion: template.metadata.version,\n aggregateHash,\n engine: {\n version: ENGINE_VERSION,\n formatted,\n },\n inputs,\n platformPrefix,\n files: manifestFiles,\n };\n}\n\n/**\n * Serialize a Manifest to a JSON string.\n *\n * Uses 2-space indentation and deterministic key ordering (R-005).\n *\n * @param manifest - Manifest to serialize\n * @returns JSON string\n */\nexport function serializeManifest(manifest: Manifest): string {\n // Deterministic key ordering via explicit construction\n const ordered = {\n manifestVersion: manifest.manifestVersion,\n intentId: manifest.intentId,\n generatedAt: manifest.generatedAt,\n templateSource: manifest.templateSource,\n templateVersion: manifest.templateVersion,\n aggregateHash: manifest.aggregateHash,\n engine: manifest.engine,\n inputs: manifest.inputs,\n platformPrefix: manifest.platformPrefix,\n files: manifest.files,\n };\n\n return JSON.stringify(ordered, null, 2) + '\\n';\n}\n\n/**\n * Hash content using SHA-256.\n * Delegates to the shared sha256() utility.\n *\n * @param content - Content to hash\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashContent(content: string): string {\n return sha256(content);\n}\n\n/**\n * Hash inputs for determinism verification.\n * Normalizes inputs before hashing to ensure deterministic results.\n *\n * @param inputs - Input values\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashInputs(inputs: Record<string, unknown>): string {\n const normalized = JSON.stringify(sortObjectKeys(inputs));\n return hashContent(normalized);\n}\n\n/**\n * Recursively sort object keys for deterministic serialization.\n */\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n","/**\n * Drift detection and Chain of Command verification.\n *\n * Compares current on-disk file state against a Manifest to produce\n * a structured drift report with per-file entries.\n *\n * Reference: R-009, FR-015, FR-028, FR-041 through FR-043, FR-047\n */\n\nimport type { FileMap, Manifest, DriftReport, DriftEntry, DriftSummary } from '../schema/types.js';\nimport { parseHeader } from './header.js';\nimport { hashFileContent, computeAggregateHash } from './hasher.js';\nimport { classifyFile, DEFAULT_PREFIX, MANIFEST_FILENAME } from './zones.js';\n\n/**\n * Build a drift report comparing current files against a manifest.\n *\n * Checks performed per file:\n * - Content hash match (header-agnostic) → content_drift\n * - Chain of Command: header fields vs manifest entry → metadata_inconsistency\n * - Missing files (in manifest, not in file map) → missing_file\n * - Unexpected files (platform-prefixed, not in manifest) → unexpected_file\n * - Source mismatch (incoming source vs file headers) → source_mismatch\n *\n * @param currentFiles - Current file map (from disk)\n * @param manifest - Previous Manifest to verify against\n * @param prefix - Platform Zone prefix (default: \"tfy_\")\n * @param incomingSource - If provided, check for source mismatch (FR-028)\n * @returns Structured drift report\n */\nexport function buildDriftReport(\n currentFiles: FileMap,\n manifest: Manifest,\n prefix: string = DEFAULT_PREFIX,\n incomingSource?: string\n): DriftReport {\n const entries: DriftEntry[] = [];\n const manifestPathSet = new Set(manifest.files.map((f) => f.path));\n const checkedPaths = new Set<string>();\n\n // Check each file in the manifest against the current file map\n for (const manifestEntry of manifest.files) {\n // Only check platform zone files for integrity\n if (manifestEntry.zone !== 'platform') continue;\n\n checkedPaths.add(manifestEntry.path);\n const currentEntry = currentFiles.get(manifestEntry.path);\n\n if (!currentEntry) {\n entries.push({\n path: manifestEntry.path,\n type: 'missing_file',\n details: 'File listed in Manifest but not found in current file map',\n });\n continue;\n }\n\n // Content hash check (header-agnostic)\n const actualHash = hashFileContent(currentEntry.content);\n if (actualHash !== manifestEntry.hash) {\n entries.push({\n path: manifestEntry.path,\n type: 'content_drift',\n details: `Content hash mismatch: expected ${manifestEntry.hash}, actual ${actualHash}`,\n });\n }\n\n // Chain of Command: compare file header fields against manifest entry (FR-047)\n const header = currentEntry.header ?? parseHeader(currentEntry.content);\n if (header) {\n if (header.source !== manifestEntry.source) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header source '${header.source}' does not match Manifest source '${manifestEntry.source}'`,\n });\n }\n if (header.version !== manifestEntry.version) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header version '${header.version}' does not match Manifest version '${manifestEntry.version}'`,\n });\n }\n if (header.contentHash !== manifestEntry.hash) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header content_hash '${header.contentHash}' does not match Manifest hash '${manifestEntry.hash}'`,\n });\n }\n }\n }\n\n // Check for unexpected platform-prefixed files not in manifest\n for (const [path, entry] of currentFiles) {\n if (entry.zone === 'platform' || classifyFile(path, prefix) === 'platform') {\n if (!manifestPathSet.has(path) && path !== MANIFEST_FILENAME) {\n entries.push({\n path,\n type: 'unexpected_file',\n details: 'Platform-prefixed file found in current file map but not listed in Manifest',\n });\n }\n }\n }\n\n // Source mismatch check (FR-028)\n if (incomingSource) {\n for (const [path, entry] of currentFiles) {\n if (entry.zone !== 'platform') continue;\n const header = entry.header ?? parseHeader(entry.content);\n if (header && header.source !== incomingSource) {\n entries.push({\n path,\n type: 'source_mismatch',\n details: `File source '${header.source}' does not match incoming source '${incomingSource}'`,\n });\n }\n }\n }\n\n // Compute aggregate hash comparison\n const actualAggregateHash = computeAggregateHash(currentFiles);\n const expectedAggregateHash = manifest.aggregateHash;\n\n // Build summary\n const summary = buildSummary(entries, manifest);\n\n return {\n valid: entries.length === 0,\n aggregateHash: {\n expected: expectedAggregateHash,\n actual: actualAggregateHash,\n },\n entries,\n summary,\n };\n}\n\n/**\n * Build summary counts from drift entries.\n */\nfunction buildSummary(entries: DriftEntry[], manifest: Manifest): DriftSummary {\n const driftedPaths = new Set<string>();\n const inconsistentPaths = new Set<string>();\n let missingFiles = 0;\n let unexpectedFiles = 0;\n let sourceMismatches = 0;\n\n for (const entry of entries) {\n switch (entry.type) {\n case 'content_drift':\n driftedPaths.add(entry.path);\n break;\n case 'metadata_inconsistency':\n inconsistentPaths.add(entry.path);\n break;\n case 'missing_file':\n missingFiles++;\n break;\n case 'unexpected_file':\n unexpectedFiles++;\n break;\n case 'source_mismatch':\n sourceMismatches++;\n break;\n }\n }\n\n return {\n totalFiles: manifest.files.filter((f) => f.zone === 'platform').length,\n driftedFiles: driftedPaths.size,\n inconsistentFiles: inconsistentPaths.size,\n missingFiles,\n unexpectedFiles,\n sourceMismatches,\n };\n}\n","/**\n * Envelope validation and utilities.\n * The envelope is the configuration wrapper for template rendering\n * with integrity engine support.\n *\n * CHANGE (008): Zod removed entirely. Validation uses plain TypeScript\n * runtime checks. Template field validates new shape (metadata + jsonSchema).\n *\n * Reference: R-006, R-008, FR-031, FR-032\n */\n\nimport type { Envelope, RenderOptions, Template } from './types.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nfunction fail(message: string): never {\n throw new EngineError(message, EngineErrorCode.ENVELOPE_VALIDATION_FAILED);\n}\n\n/**\n * Validate an envelope configuration using plain TypeScript runtime checks.\n *\n * Checks:\n * - template: must be a valid Template object (metadata, jsonSchema, files Map with size > 0, source, version)\n * - intentId: required non-empty string\n * - inputs: defaults to {}\n * - platformPrefix: defaults to \"tfy_\"\n * - options: optional, validates skipFormat if present\n * - rejects unknown top-level fields\n *\n * @param data - Raw envelope data to validate\n * @returns Validated envelope\n * @throws EngineError if validation fails\n */\nexport function validateEnvelope(data: unknown): Envelope {\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n fail('Envelope must be a non-null object');\n }\n\n const record = data as Record<string, unknown>;\n\n const knownFields = new Set(['template', 'inputs', 'options', 'intentId', 'platformPrefix']);\n for (const key of Object.keys(record)) {\n if (!knownFields.has(key)) {\n fail(`Unknown field \"${key}\" in envelope. Allowed: ${[...knownFields].join(', ')}`);\n }\n }\n\n validateTemplateObject(record['template']);\n\n if (typeof record['intentId'] !== 'string' || record['intentId'].length === 0) {\n fail('intentId is required and must be non-empty');\n }\n\n const inputs = record['inputs'] !== undefined ? record['inputs'] : {};\n if (typeof inputs !== 'object' || inputs === null || Array.isArray(inputs)) {\n fail('inputs must be an object');\n }\n\n const platformPrefix = record['platformPrefix'] !== undefined ? record['platformPrefix'] : 'tfy_';\n if (typeof platformPrefix !== 'string') {\n fail('platformPrefix must be a string');\n }\n\n let options: RenderOptions | undefined;\n if (record['options'] !== undefined) {\n options = validateRenderOptions(record['options']);\n }\n\n return {\n template: record['template'] as Template,\n inputs: inputs as Record<string, unknown>,\n options,\n intentId: record['intentId'],\n platformPrefix: platformPrefix,\n };\n}\n\n/**\n * Parse render options with defaults applied.\n *\n * @param options - Optional render options\n * @returns Options with defaults applied\n */\nexport function parseRenderOptions(options?: RenderOptions): Required<RenderOptions> {\n return {\n skipFormat: options?.skipFormat ?? false,\n };\n}\n\n// ============================================================================\n// Internal validators\n// ============================================================================\n\nfunction validateTemplateObject(value: unknown): void {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n fail('template must be a non-null object');\n }\n\n const template = value as Record<string, unknown>;\n\n if (!template['metadata'] || typeof template['metadata'] !== 'object') {\n fail('template.metadata must be an object');\n }\n\n const metadata = template['metadata'] as Record<string, unknown>;\n if (typeof metadata['name'] !== 'string' || metadata['name'].length === 0) {\n fail('template.metadata.name must be a non-empty string');\n }\n if (typeof metadata['version'] !== 'string' || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata['version'])) {\n fail('template.metadata.version must be semver format (x.y.z)');\n }\n\n if (!template['jsonSchema'] || typeof template['jsonSchema'] !== 'object') {\n fail('template.jsonSchema must be an object');\n }\n\n const hasFiles =\n (template['files'] instanceof Map && template['files'].size > 0) ||\n (template['staticFiles'] instanceof Map && template['staticFiles'].size > 0);\n if (!hasFiles) {\n fail('Template must have at least one file (in files or staticFiles)');\n }\n if (template['files'] !== undefined && !(template['files'] instanceof Map)) {\n fail('template.files must be a Map');\n }\n if (template['staticFiles'] !== undefined && !(template['staticFiles'] instanceof Map)) {\n fail('template.staticFiles must be a Map');\n }\n\n if (typeof template['source'] !== 'string' || template['source'].length === 0) {\n fail('Template source URI is required');\n }\n\n if (!template['version'] || typeof template['version'] !== 'object') {\n fail('Template version info is required');\n }\n\n const version = template['version'] as Record<string, unknown>;\n if (typeof version['semver'] !== 'string' || !/^\\d+\\.\\d+\\.\\d+$/.test(version['semver'])) {\n fail('template.version.semver must be semver format (x.y.z)');\n }\n if (version['apiVersion'] !== undefined && typeof version['apiVersion'] !== 'string') {\n fail('template.version.apiVersion must be a string if provided');\n }\n}\n\nfunction validateRenderOptions(value: unknown): RenderOptions {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n fail('options must be an object');\n }\n\n const opts = value as Record<string, unknown>;\n\n const knownOptionFields = new Set(['skipFormat']);\n for (const key of Object.keys(opts)) {\n if (!knownOptionFields.has(key)) {\n fail(`Unknown option field \"${key}\". Allowed: ${[...knownOptionFields].join(', ')}`);\n }\n }\n\n if (opts['skipFormat'] !== undefined && typeof opts['skipFormat'] !== 'boolean') {\n fail('options.skipFormat must be a boolean');\n }\n\n return {\n skipFormat: opts['skipFormat'],\n };\n}\n","/**\n * HCL Engine implementation — four-operation integrity API.\n *\n * Operations:\n * - install(envelope): Generate all files for a new cluster\n * - upgrade(envelope, currentFiles, previousManifest): Update to new templates\n * - verify(currentFiles, previousManifest): Check integrity\n * - hashOnly(envelope): Calculate expected aggregate hash\n *\n * Reference: R-006, FR-037, FR-038, plan.md Operation Pipelines\n */\n\nimport type {\n Envelope,\n RenderOptions,\n HclEngine,\n InstallResult,\n UpgradeResult,\n VerifyResult,\n HashOnlyResult,\n FileMap,\n Manifest,\n Template,\n TfyStatusHeader,\n} from './schema/types.js';\nimport { validateEnvelope, parseRenderOptions } from './schema/envelope.js';\nimport {\n createInputValidator,\n validateAndApplyDefaults,\n validateJsonSchemaStructure,\n} from './schema/input-validator.js';\nimport { renderTemplate } from './render/renderer.js';\nimport { formatFiles } from './render/formatter.js';\nimport { generateManifest, serializeManifest } from './render/manifest.js';\nimport { EngineError, EngineErrorCode } from './errors.js';\nimport {\n classifyFile,\n DEFAULT_PREFIX,\n MANIFEST_FILENAME,\n countPlatformFiles,\n} from './integrity/zones.js';\nimport { hashFileContent } from './integrity/hasher.js';\nimport { injectHeader } from './integrity/header.js';\nimport { buildDriftReport } from './integrity/drift.js';\n\n/**\n * HCL Engine implementation.\n */\nclass HclEngineImpl implements HclEngine {\n /**\n * Install: Generate all files for a new cluster.\n *\n * Pipeline: validate envelope → validate inputs (AJV) → render templates →\n * format .tf files → classify by zone → hash + inject headers → generate manifest.\n */\n async install(envelope: Envelope): Promise<InstallResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return { files: fileMap, manifest };\n }\n\n /**\n * Upgrade: Update an existing cluster to new templates.\n *\n * Pipeline: validate envelope → drift detection (FR-028) → if source mismatch,\n * short-circuit → validate inputs → render → format → hash + manifest.\n */\n async upgrade(\n envelope: Envelope,\n currentFiles: FileMap,\n previousManifest: Manifest\n ): Promise<UpgradeResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const incomingSource = validatedEnvelope.template.source;\n const driftReport = buildDriftReport(currentFiles, previousManifest, prefix, incomingSource);\n const sourceBlocked = driftReport.summary.sourceMismatches > 0;\n\n if (sourceBlocked) {\n return {\n files: currentFiles,\n manifest: previousManifest,\n driftReport,\n sourceBlocked: true,\n };\n }\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return { files: fileMap, manifest, driftReport, sourceBlocked: false };\n }\n\n /**\n * Verify: Check integrity of existing files against a Manifest.\n */\n verify(currentFiles: FileMap, previousManifest: Manifest): Promise<VerifyResult> {\n if (\n !previousManifest ||\n !previousManifest.manifestVersion ||\n !previousManifest.files ||\n !previousManifest.aggregateHash\n ) {\n throw new EngineError(\n 'Invalid manifest: missing required fields (manifestVersion, files, aggregateHash)',\n EngineErrorCode.MANIFEST_PARSE_ERROR\n );\n }\n\n const driftReport = buildDriftReport(currentFiles, previousManifest);\n return Promise.resolve({ driftReport });\n }\n\n /**\n * Hash-Only: Calculate expected aggregate hash without full file generation.\n */\n async hashOnly(envelope: Envelope): Promise<HashOnlyResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return {\n aggregateHash: manifest.aggregateHash,\n templateSource: template.source,\n templateVersion: template.metadata.version,\n fileCount: countPlatformFiles(fileMap),\n };\n }\n\n // =========================================================================\n // Private helpers\n // =========================================================================\n\n /**\n * Validate envelope or throw ENVELOPE_VALIDATION_FAILED.\n */\n private validateEnvelopeOrThrow(envelope: Envelope): Envelope {\n try {\n return validateEnvelope(envelope);\n } catch (error) {\n throw new EngineError(\n `Envelope validation failed: ${(error as Error).message}`,\n EngineErrorCode.ENVELOPE_VALIDATION_FAILED,\n error as Error\n );\n }\n }\n\n /**\n * Shared render pipeline: validate schema → validate inputs → render → format.\n */\n private async renderPipeline(validatedEnvelope: Envelope, options: Required<RenderOptions>) {\n const template = validatedEnvelope.template;\n\n // JSON Schema validation pipeline (R-001, R-010)\n validateJsonSchemaStructure(template.jsonSchema);\n const validator = createInputValidator(template.jsonSchema);\n\n const inputsWithDefaults = structuredClone(validatedEnvelope.inputs);\n const validation = validateAndApplyDefaults(validator, inputsWithDefaults);\n\n if (!validation.valid) {\n throw new EngineError(\n `Input validation failed: ${validation.errors?.map((e) => `${e.path}: ${e.message}`).join(', ')}`,\n EngineErrorCode.INPUT_VALIDATION_FAILED,\n undefined,\n { errors: validation.errors }\n );\n }\n\n let renderedFiles = renderTemplate(template, inputsWithDefaults);\n\n // Merge static files (verbatim, no Handlebars processing)\n if (template.staticFiles) {\n for (const [path, content] of template.staticFiles) {\n renderedFiles.set(path, content);\n }\n }\n\n const formatted = !options.skipFormat;\n if (formatted) {\n renderedFiles = await formatFiles(renderedFiles, {\n skip: false,\n timeout: 10000,\n });\n }\n\n for (const [path, content] of renderedFiles) {\n if (content.trim() === '') {\n renderedFiles.delete(path);\n }\n }\n\n return { renderedFiles, template, formatted, inputsWithDefaults };\n }\n\n /**\n * Build a zone-tagged FileEntry map from raw rendered files.\n */\n private buildFileMap(\n renderedFiles: Map<string, string>,\n prefix: string,\n meta: { source: string; version: string; intentId: string }\n ): FileMap {\n const fileMap: FileMap = new Map();\n\n for (const [path, content] of renderedFiles) {\n const zone = classifyFile(path, prefix);\n\n if (zone === 'platform') {\n const contentHash = hashFileContent(content);\n\n const header: TfyStatusHeader = {\n managed: true,\n source: meta.source,\n version: meta.version,\n intentId: meta.intentId,\n contentHash,\n };\n\n const contentWithHeader = injectHeader(content, header);\n\n fileMap.set(path, {\n content: contentWithHeader,\n zone: 'platform',\n header,\n });\n } else {\n fileMap.set(path, {\n content,\n zone: 'user',\n });\n }\n }\n\n return fileMap;\n }\n\n /**\n * Build zone-tagged file map, generate manifest, and insert it into the map.\n * Shared by install, upgrade, and hashOnly.\n */\n private buildFilesAndManifest(\n renderedFiles: Map<string, string>,\n validatedEnvelope: Envelope,\n template: Template,\n inputsWithDefaults: Record<string, unknown>,\n formatted: boolean,\n prefix: string\n ): { fileMap: FileMap; manifest: Manifest } {\n const fileMap = this.buildFileMap(renderedFiles, prefix, {\n source: template.source,\n version: template.metadata.version,\n intentId: validatedEnvelope.intentId,\n });\n\n const manifest = generateManifest({\n files: fileMap,\n template,\n inputs: inputsWithDefaults,\n formatted,\n intentId: validatedEnvelope.intentId,\n platformPrefix: prefix,\n });\n\n fileMap.set(MANIFEST_FILENAME, {\n content: serializeManifest(manifest),\n zone: 'platform',\n });\n\n return { fileMap, manifest };\n }\n}\n\n/**\n * Create a new HCL engine instance.\n *\n * @returns Engine instance\n *\n * @example\n * ```typescript\n * import { createEngine } from '@truefoundry/tfy-infra-engine';\n *\n * const engine = createEngine();\n * const result = await engine.install({\n * template, // pre-resolved Template object\n * inputs: { cluster_name: 'prod' },\n * intentId: 'cluster-prod-001',\n * });\n * ```\n */\nexport function createEngine(): HclEngine {\n return new HclEngineImpl();\n}\n"],"mappings":"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","names":["EngineErrorCode","Ajv","import_ajv","ajv","Ajv","import_handlebars","Handlebars","Handlebars","import_node_crypto","import_node_child_process","import_node_path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/schema/validator.ts","../src/schema/bundle-schema.ts","../src/schema/input-validator.ts","../src/render/renderer.ts","../src/helpers/hcl.ts","../src/helpers/logic.ts","../src/helpers/types.ts","../src/helpers/index.ts","../src/render/formatter.ts","../src/integrity/hasher.ts","../src/integrity/canonical-hash.ts","../src/integrity/header.ts","../src/integrity/zones.ts","../src/render/manifest.ts","../src/integrity/drift.ts","../src/schema/envelope.ts","../src/engine.ts"],"sourcesContent":["/**\n * @truefoundry/tfy-infra-engine\n *\n * Config-driven HCL templating engine for infrastructure generation\n * with integrity verification, zone-based file ownership, and\n * deterministic hashing.\n *\n */\n\n// Error types\nexport { EngineError, EngineErrorCode } from './errors.js';\n\n// Schema types\nexport type {\n Envelope,\n Template,\n TemplateMetadata,\n VersionInfo,\n JSONSchema7,\n FileEntry,\n FileMap,\n Manifest,\n DriftType,\n DriftReport,\n InstallResult,\n UpgradeResult,\n VerifyResult,\n HashOnlyResult,\n ResolverOptions,\n Resolver,\n} from './schema/types.js';\n\n// Schema validation\nexport { validateBundle } from './schema/validator.js';\nexport type { BundleValidationResult } from './schema/validator.js';\nexport { validateJsonSchemaStructure } from './schema/input-validator.js';\nexport { bundleSchema } from './schema/bundle-schema.js';\n\n// Rendering\nexport { isTofuAvailable } from './render/index.js';\n\n// Integrity\nexport { classifyFile, parseHeader, DEFAULT_PREFIX } from './integrity/index.js';\nexport { canonicalHash, getCanonicalHashScriptPath } from './integrity/canonical-hash.js';\n\n// Engine\nexport { createEngine } from './engine.js';\n","/**\n * Engine error codes for programmatic error handling.\n */\nexport enum EngineErrorCode {\n // Resolver errors\n TEMPLATE_NOT_FOUND = 'TEMPLATE_NOT_FOUND',\n NETWORK_ERROR = 'NETWORK_ERROR',\n FILE_NOT_FOUND = 'FILE_NOT_FOUND',\n HTTPS_AUTH_FAILED = 'HTTPS_AUTH_FAILED',\n\n // Validation errors\n SCHEMA_INVALID = 'SCHEMA_INVALID',\n INPUT_VALIDATION_FAILED = 'INPUT_VALIDATION_FAILED',\n BUNDLE_NOT_FOUND = 'BUNDLE_NOT_FOUND',\n BUNDLE_INVALID = 'BUNDLE_INVALID',\n\n // Rendering errors\n TEMPLATE_SYNTAX_ERROR = 'TEMPLATE_SYNTAX_ERROR',\n\n // Formatting errors\n TOFU_NOT_FOUND = 'TOFU_NOT_FOUND',\n TOFU_FMT_FAILED = 'TOFU_FMT_FAILED',\n\n // Cache errors\n CACHE_ERROR = 'CACHE_ERROR',\n\n // Integrity errors\n ENVELOPE_VALIDATION_FAILED = 'ENVELOPE_VALIDATION_FAILED',\n MANIFEST_PARSE_ERROR = 'MANIFEST_PARSE_ERROR',\n}\n\n/**\n * Custom error class for engine errors.\n * Provides structured error information including error code, cause, and details.\n */\nexport class EngineError extends Error {\n public readonly code: EngineErrorCode;\n public readonly details?: Record<string, unknown>;\n\n constructor(\n message: string,\n code: EngineErrorCode,\n cause?: Error,\n details?: Record<string, unknown>\n ) {\n super(message, { cause });\n this.name = 'EngineError';\n this.code = code;\n this.details = details;\n\n // Maintain proper stack trace for where our error was thrown (V8 engines)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, EngineError);\n }\n }\n\n /**\n * Create a string representation including error code.\n */\n override toString(): string {\n return `[${this.code}] ${this.message}`;\n }\n\n /**\n * Convert error to JSON-serializable object.\n */\n toJSON(): Record<string, unknown> {\n const causeError = this.cause as Error | undefined;\n return {\n name: this.name,\n code: this.code,\n message: this.message,\n details: this.details,\n cause: causeError?.message,\n };\n }\n}\n","/**\n * Bundle structure validation using AJV.\n *\n * Validates the top-level structure of a bundle against the\n * bundleSchema (JSON Schema Draft-07) defined in bundle-schema.ts.\n *\n * Reference: R-006, data-model.md validator.ts\n */\n\nimport Ajv, { type ErrorObject } from 'ajv';\nimport type { TemplateMetadata } from './types.js';\nimport type { JSONSchema7 } from './json-schema.js';\nimport { bundleSchema } from './bundle-schema.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\n/**\n * Result of validating a bundle.\n */\nexport interface BundleValidationResult {\n metadata: TemplateMetadata;\n jsonSchema: JSONSchema7;\n}\n\n/**\n * AJV instance for bundle validation.\n * Configured with allErrors for complete diagnostics.\n */\nconst ajv = new Ajv({\n allErrors: true,\n strict: false,\n validateSchema: false,\n});\n\nconst validate = ajv.compile(bundleSchema);\n\n/**\n * Validate the structure of a parsed bundle.\n *\n * Checks:\n * - Data is an object with \"metadata\" and \"jsonSchema\" keys\n * - metadata.name is a non-empty string\n * - metadata.version is a semver string (x.y.z)\n * - metadata.description is an optional string\n * - jsonSchema is a non-null object with type: \"object\" and properties\n *\n * @param data - Parsed JSON content from a bundle\n * @returns Validated metadata and JSON Schema\n * @throws EngineError with BUNDLE_INVALID on failure\n */\nexport function validateBundle(data: unknown): BundleValidationResult {\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n throw new EngineError('bundle must be a JSON object', EngineErrorCode.BUNDLE_INVALID);\n }\n\n const valid = validate(data);\n\n if (!valid) {\n const message = formatAjvErrors(validate.errors ?? []);\n throw new EngineError(message, EngineErrorCode.BUNDLE_INVALID);\n }\n\n const record = data as Record<string, unknown>;\n const metadataBlock = record['metadata'] as Record<string, unknown>;\n\n const metadata: TemplateMetadata = {\n name: metadataBlock['name'] as string,\n version: metadataBlock['version'] as string,\n ...(metadataBlock['description'] !== undefined\n ? { description: metadataBlock['description'] as string }\n : {}),\n };\n\n const jsonSchema = record['jsonSchema'] as JSONSchema7;\n\n return { metadata, jsonSchema };\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Format AJV errors into a human-readable message for EngineError.\n */\nfunction formatAjvErrors(errors: ErrorObject[]): string {\n const first = errors[0];\n if (!first) {\n return 'bundle validation failed';\n }\n const path = first.instancePath || '';\n\n if (first.keyword === 'required') {\n const prop = (first.params as Record<string, unknown>)['missingProperty'] as string;\n return `bundle must have a \"${prop}\" key`;\n }\n\n if (first.keyword === 'type') {\n const expected = (first.params as Record<string, unknown>)['type'] as string;\n return `bundle${path ? ` \"${dotPath(path)}\"` : ''} must be ${expected}`;\n }\n\n if (first.keyword === 'pattern' && path === '/metadata/version') {\n return `bundle \"metadata.version\" must be semver format (x.y.z)`;\n }\n\n if (first.keyword === 'minLength' && path === '/metadata/name') {\n return `bundle \"metadata.name\" must be a non-empty string`;\n }\n\n if (first.keyword === 'const') {\n const expected = (first.params as Record<string, unknown>)['allowedValue'];\n return `bundle \"${dotPath(path)}\" must be ${JSON.stringify(expected)}`;\n }\n\n return `bundle validation failed at ${path || '/'}: ${first.message ?? 'unknown error'}`;\n}\n\n/**\n * Convert JSON Pointer path (e.g., \"/metadata/version\") to dot notation (\"metadata.version\").\n */\nfunction dotPath(jsonPointer: string): string {\n return jsonPointer.replace(/^\\//, '').replace(/\\//g, '.');\n}\n","/**\n * JSON Schema (Draft-07) for bundle.json files.\n *\n * This is the source of truth for bundle structure validation.\n * Used by validator.ts via AJV for runtime validation.\n *\n * Validates:\n * - \"metadata\" key: name (required, non-empty), version (semver, required), description (optional string)\n * - \"jsonSchema\" key: must be a JSON Schema object with type: \"object\" and a properties key\n *\n * Note: No additionalProperties: false at root level -- extra top-level keys are allowed\n * for forward compatibility (e.g., uiSchema, files, staticFiles, version).\n */\n\nimport type { JSONSchema7 } from './json-schema.js';\n\nexport const bundleSchema: JSONSchema7 = {\n $schema: 'http://json-schema.org/draft-07/schema#',\n type: 'object',\n properties: {\n metadata: {\n type: 'object',\n properties: {\n name: { type: 'string', minLength: 1 },\n description: { type: 'string' },\n version: { type: 'string', pattern: '^\\\\d+\\\\.\\\\d+\\\\.\\\\d+$' },\n },\n required: ['name', 'version'],\n additionalProperties: false,\n },\n jsonSchema: {\n type: 'object',\n description: 'JSON Schema Draft-07 defining template inputs',\n properties: {\n type: { type: 'string', const: 'object' },\n properties: { type: 'object' },\n required: { type: 'array', items: { type: 'string' } },\n },\n required: ['type', 'properties'],\n },\n },\n required: ['metadata', 'jsonSchema'],\n};\n","/**\n * AJV-based JSON Schema input validation.\n *\n * Provides:\n * - createInputValidator(): Compiles a JSON Schema into an AJV validator\n * - validateAndApplyDefaults(): Validates inputs + applies defaults in one pass\n * - validateJsonSchemaStructure(): Asserts root type: \"object\" + properties key\n *\n * Local $ref pointers (e.g., \"#/components/schemas/...\") are supported natively\n * by AJV and resolved automatically during schema compilation.\n *\n * CHANGE (008): New module replacing hand-rolled validateInputs() and applyDefaults().\n *\n * Reference: R-001, R-007, R-010\n */\n\nimport Ajv, { type ValidateFunction, type ErrorObject } from 'ajv';\nimport type { JSONSchema7 } from './json-schema.js';\nimport type { ValidationResult, ValidationError } from './types.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\n/**\n * Shared AJV instance configured per R-001.\n *\n * - useDefaults: true — applies schema-defined defaults during validation (FR-006)\n * - allErrors: true — collects all validation errors in a single pass (FR-008)\n * - discriminator: true — supports oneOf with discriminator property\n * - strict: false — allows unknown keywords (UI metadata like +label, +usage)\n * - validateSchema: false — we validate schema structure ourselves\n */\nconst ajv = new Ajv({\n useDefaults: true,\n allErrors: true,\n discriminator: true,\n strict: false,\n validateSchema: false,\n});\n\n/**\n * Compile a JSON Schema Draft-07 into an AJV validator function.\n *\n * @param jsonSchema - JSON Schema to compile\n * @returns Compiled AJV validate function\n * @throws EngineError if schema cannot be compiled\n */\nexport function createInputValidator(jsonSchema: JSONSchema7): ValidateFunction {\n try {\n return ajv.compile(jsonSchema);\n } catch (error) {\n throw new EngineError(\n `Failed to compile JSON Schema: ${(error as Error).message}`,\n EngineErrorCode.SCHEMA_INVALID,\n error as Error\n );\n }\n}\n\n/**\n * Validate inputs against a compiled schema and apply defaults in one pass.\n *\n * AJV's `useDefaults: true` mutates the input data in-place, inserting\n * default values for missing properties. Validation and defaults happen\n * simultaneously — no separate applyDefaults() call needed.\n *\n * @param validator - Compiled AJV validate function from createInputValidator()\n * @param inputs - Input data to validate (mutated in-place with defaults)\n * @returns ValidationResult with errors if invalid\n */\nexport function validateAndApplyDefaults(\n validator: ValidateFunction,\n inputs: Record<string, unknown>\n): ValidationResult {\n const valid = validator(inputs);\n\n if (valid) {\n return { valid: true };\n }\n\n const errors: ValidationError[] = (validator.errors ?? []).map(ajvErrorToValidationError);\n\n return {\n valid: false,\n errors,\n };\n}\n\n/**\n * Validate that a JSON Schema has the required structure for template inputs.\n * Must be an object with type: \"object\" and a properties key.\n *\n * @param schema - Schema to validate\n * @throws EngineError if structure is invalid\n */\nexport function validateJsonSchemaStructure(schema: JSONSchema7): void {\n if (!schema || typeof schema !== 'object') {\n throw new EngineError(\n 'Schema must be a non-null object',\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { received: typeof schema }\n );\n }\n\n if (schema.type !== 'object') {\n throw new EngineError(\n `Schema root must have \"type\": \"object\", got \"${schema.type ?? 'undefined'}\"`,\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { received: schema.type }\n );\n }\n\n if (!schema.properties || typeof schema.properties !== 'object') {\n throw new EngineError(\n 'Schema root must have a \"properties\" key',\n EngineErrorCode.SCHEMA_INVALID,\n undefined,\n { hasProperties: !!schema.properties }\n );\n }\n}\n\n// ============================================================================\n// Internal helpers\n// ============================================================================\n\n/**\n * Map an AJV ErrorObject to our ValidationError interface.\n * Uses JSON Pointer format for paths (R-007).\n */\nfunction ajvErrorToValidationError(error: ErrorObject): ValidationError {\n return {\n path: error.instancePath || '/',\n message: error.message ?? 'Validation failed',\n expected: formatExpected(error),\n received: undefined,\n };\n}\n\n/**\n * Extract expected value description from AJV error params.\n */\nfunction formatExpected(error: ErrorObject): string | undefined {\n const params = error.params as Record<string, unknown>;\n if (!params) return undefined;\n\n if (error.keyword === 'type') {\n return String(params['type']);\n }\n if (error.keyword === 'required') {\n return `required property '${String(params['missingProperty'])}'`;\n }\n if (error.keyword === 'pattern') {\n return `match pattern ${String(params['pattern'])}`;\n }\n if (error.keyword === 'enum') {\n return `one of ${JSON.stringify(params['allowedValues'])}`;\n }\n if (error.keyword === 'const') {\n return `value ${JSON.stringify(params['allowedValue'])}`;\n }\n\n return undefined;\n}\n","/**\n * Template renderer using Handlebars.\n */\n\nimport Handlebars from 'handlebars';\nimport type { Template } from '../schema/types.js';\nimport { registerAllHelpers } from '../helpers/index.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nconst HBS_COMPILE_OPTIONS: CompileOptions = {\n noEscape: true,\n strict: false,\n};\n\n/**\n * Create a Handlebars environment with all custom helpers registered.\n */\nfunction createConfiguredHandlebars(): typeof Handlebars {\n const hbs = Handlebars.create();\n registerAllHelpers(hbs);\n return hbs;\n}\n\n/**\n * Context passed to templates during rendering.\n */\nexport interface RenderContext {\n /** User-provided inputs */\n [key: string]: unknown;\n /** Template metadata (injected by engine) */\n _template: {\n name: string;\n version: string;\n source: string;\n };\n}\n\n/**\n * Create a render context from inputs and template metadata.\n *\n * CHANGE (008): Access template.metadata instead of template.schema.template.\n *\n * @param inputs - User-provided inputs\n * @param template - Template with metadata\n * @returns Render context for Handlebars\n */\nexport function createRenderContext(\n inputs: Record<string, unknown>,\n template: Template\n): RenderContext {\n return {\n ...inputs,\n _template: {\n name: template.metadata.name,\n version: template.metadata.version,\n source: template.source,\n },\n };\n}\n\n/**\n * Render all template files with the given context.\n *\n * @param template - Template to render\n * @param inputs - User-provided inputs\n * @returns Map of file paths to rendered content\n */\nexport function renderTemplate(\n template: Template,\n inputs: Record<string, unknown>\n): Map<string, string> {\n const hbs = createConfiguredHandlebars();\n const context = createRenderContext(inputs, template);\n const results = new Map<string, string>();\n\n for (const [outputPath, hbsContent] of template.files) {\n try {\n const compiled = hbs.compile(hbsContent, HBS_COMPILE_OPTIONS);\n const rendered = compiled(context);\n results.set(outputPath, rendered);\n } catch (error) {\n throw new EngineError(\n `Failed to render ${outputPath}: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error,\n { file: outputPath, template: template.source }\n );\n }\n }\n\n return results;\n}\n\n/**\n * Compile a single template string.\n * Useful for testing or one-off rendering.\n *\n * @param templateString - Handlebars template string\n * @param context - Context object\n * @returns Rendered string\n */\nexport function renderString(templateString: string, context: Record<string, unknown>): string {\n const hbs = createConfiguredHandlebars();\n\n try {\n const compiled = hbs.compile(templateString, HBS_COMPILE_OPTIONS);\n return compiled(context);\n } catch (error) {\n throw new EngineError(\n `Failed to render template string: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error\n );\n }\n}\n\n/**\n * Validate template syntax without rendering.\n *\n * @param hbsContent - Handlebars template content\n * @returns true if valid, throws on error\n */\nexport function validateTemplateSyntax(hbsContent: string): boolean {\n try {\n Handlebars.precompile(hbsContent);\n return true;\n } catch (error) {\n throw new EngineError(\n `Invalid template syntax: ${(error as Error).message}`,\n EngineErrorCode.TEMPLATE_SYNTAX_ERROR,\n error as Error\n );\n }\n}\n","/**\n * HCL formatting helpers for Handlebars templates.\n * These helpers format JavaScript values as valid HCL syntax.\n */\n\nimport Handlebars from 'handlebars';\n\n/**\n * Register HCL formatting helpers with Handlebars.\n */\nexport function registerHclHelpers(handlebars: typeof Handlebars): void {\n /**\n * Convert any JavaScript value to valid HCL/Terraform syntax.\n * Handles strings, numbers, booleans, arrays, and objects.\n *\n * @example\n * {{toTerraformValue name}} → \"my-cluster\"\n * {{toTerraformValue count}} → 3\n * {{toTerraformValue enabled}} → true\n * {{toTerraformValue tags}} → { \"key\" = \"value\" }\n */\n handlebars.registerHelper('toTerraformValue', function (value: unknown): Handlebars.SafeString {\n return new Handlebars.SafeString(formatValue(value));\n });\n}\n\n/**\n * Format a JavaScript value as HCL syntax.\n */\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return 'null';\n }\n\n if (typeof value === 'string') {\n // Escape backslashes and quotes\n const escaped = value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"').replace(/\\n/g, '\\\\n');\n return `\"${escaped}\"`;\n }\n\n if (typeof value === 'boolean' || typeof value === 'number') {\n return String(value);\n }\n\n if (Array.isArray(value)) {\n const elements = value.map((item) => formatValue(item));\n if (elements.length === 0) {\n return '[]';\n }\n // Use multi-line format for non-empty arrays\n if (elements.some((e) => e.includes('\\n') || e.length > 40)) {\n return `[\\n ${elements.join(',\\n ')}\\n]`;\n }\n return `[${elements.join(', ')}]`;\n }\n\n if (typeof value === 'object') {\n return formatObject(value as Record<string, unknown>);\n }\n\n return JSON.stringify(value);\n}\n\n/**\n * Format an object as HCL map syntax.\n */\nfunction formatObject(obj: Record<string, unknown>): string {\n const entries = Object.entries(obj);\n if (entries.length === 0) {\n return '{}';\n }\n\n const formatted = entries.map(([key, val]) => {\n // Quote keys that contain special characters\n const quotedKey = /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key) ? key : `\"${key}\"`;\n return `${quotedKey} = ${formatValue(val)}`;\n });\n\n return `{\\n ${formatted.join('\\n ')}\\n}`;\n}\n","/**\n * Logic helpers for Handlebars templates.\n * These helpers provide boolean logic and comparison operations.\n */\n\nimport type Handlebars from 'handlebars';\n\n/**\n * Register logic helpers with Handlebars.\n */\nexport function registerLogicHelpers(handlebars: typeof Handlebars): void {\n /**\n * Strict equality comparison.\n *\n * @example\n * {{#if (eq env \"prod\")}}production{{/if}}\n */\n handlebars.registerHelper('eq', (a: unknown, b: unknown): boolean => a === b);\n\n /**\n * Logical AND (all arguments must be truthy).\n *\n * @example\n * {{#if (and enabled ready)}}go{{/if}}\n */\n handlebars.registerHelper('and', function (...args: unknown[]): boolean {\n // Last argument is Handlebars options object\n const values = args.slice(0, -1);\n return values.every(Boolean);\n });\n\n /**\n * Logical OR (any argument must be truthy).\n *\n * @example\n * {{#if (or flagA flagB)}}at least one{{/if}}\n */\n handlebars.registerHelper('or', function (...args: unknown[]): boolean {\n // Last argument is Handlebars options object\n const values = args.slice(0, -1);\n return values.some(Boolean);\n });\n}\n","/**\n * Type checking helpers for Handlebars templates.\n */\n\nimport type Handlebars from 'handlebars';\n\n/**\n * Register type checking helpers with Handlebars.\n */\nexport function registerTypeHelpers(handlebars: typeof Handlebars): void {\n /**\n * Check if value is a string.\n *\n * @example\n * {{#if (isString value)}}string value{{/if}}\n */\n handlebars.registerHelper('isString', (value: unknown): boolean => {\n return typeof value === 'string';\n });\n\n /**\n * Check if value is defined (not undefined and not null).\n *\n * @example\n * {{#if (isDefined optional)}}value exists{{/if}}\n */\n handlebars.registerHelper('isDefined', (value: unknown): boolean => {\n return value !== undefined && value !== null;\n });\n\n /**\n * Check if value is not empty (inverse of isEmpty).\n *\n * @example\n * {{#if (isNotEmpty items)}}has items{{/if}}\n */\n handlebars.registerHelper('isNotEmpty', (value: unknown): boolean => {\n if (value === null || value === undefined) return false;\n if (typeof value === 'string') return value.length > 0;\n if (Array.isArray(value)) return value.length > 0;\n if (typeof value === 'object') return Object.keys(value).length > 0;\n return true;\n });\n}\n","/**\n * Handlebars helpers registration.\n * Registers all helpers with a Handlebars instance.\n */\n\nimport type Handlebars from 'handlebars';\nimport { registerHclHelpers } from './hcl.js';\nimport { registerLogicHelpers } from './logic.js';\nimport { registerTypeHelpers } from './types.js';\n\n/**\n * Register all engine helpers with a Handlebars instance.\n *\n * @param handlebars - Handlebars instance to register helpers with\n */\nexport function registerAllHelpers(handlebars: typeof Handlebars): void {\n registerHclHelpers(handlebars);\n registerLogicHelpers(handlebars);\n registerTypeHelpers(handlebars);\n}\n\n// Re-export individual registration functions for selective use\nexport { registerHclHelpers } from './hcl.js';\nexport { registerLogicHelpers } from './logic.js';\nexport { registerTypeHelpers } from './types.js';\n","/**\n * HCL formatter using tofu fmt.\n */\n\nimport { spawn, execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Options for formatting.\n */\nexport interface FormatOptions {\n /** Skip formatting entirely */\n skip?: boolean;\n /** Timeout in milliseconds (default: 10000) */\n timeout?: number;\n}\n\n/**\n * Default format options.\n */\nconst DEFAULT_FORMAT_OPTIONS: Required<FormatOptions> = {\n skip: false,\n timeout: 10000,\n};\n\n/**\n * Normalize multiple blank lines to a single blank line.\n * This improves readability of generated HCL by collapsing\n * excess whitespace that can occur with Handlebars conditionals.\n *\n * @param content - Content to normalize\n * @returns Content with normalized blank lines\n */\nexport function normalizeBlankLines(content: string): string {\n let result = content\n .replace(/\\n{3,}/g, '\\n\\n') // 3+ newlines → 2 (one blank line)\n .replace(/^\\n+/, ''); // Remove leading blank lines\n\n // Ensure single trailing newline\n result = result.replace(/\\n*$/, '\\n');\n\n return result;\n}\n\nconst HCL_FORMATTABLE_SUFFIXES = ['.tf', '.tfvars', '.tftest.hcl'];\n\nfunction isHclFormattable(filePath: string): boolean {\n return HCL_FORMATTABLE_SUFFIXES.some((suffix) => filePath.endsWith(suffix));\n}\n\n/**\n * Format HCL content using tofu fmt.\n *\n * @param content - HCL content to format\n * @param options - Format options\n * @returns Formatted content\n */\nexport async function formatHCL(content: string, options?: FormatOptions): Promise<string> {\n const opts = { ...DEFAULT_FORMAT_OPTIONS, ...options };\n\n if (opts.skip) {\n return normalizeBlankLines(content);\n }\n\n return new Promise((resolve, reject) => {\n const child = spawn('tofu', ['fmt', '-'], {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n let stdout = '';\n let stderr = '';\n let timedOut = false;\n\n const timer = setTimeout(() => {\n timedOut = true;\n child.kill();\n }, opts.timeout);\n\n child.stdout.on('data', (data: Buffer) => {\n stdout += data.toString();\n });\n\n child.stderr.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('error', (error: NodeJS.ErrnoException) => {\n clearTimeout(timer);\n if (error.code === 'ENOENT') {\n reject(\n new EngineError(\n 'tofu binary not found. Please install OpenTofu or use --skip-format option.',\n EngineErrorCode.TOFU_NOT_FOUND,\n error,\n { suggestion: 'Install OpenTofu from https://opentofu.org/' }\n )\n );\n } else {\n reject(\n new EngineError(\n `tofu fmt failed: ${error.message}`,\n EngineErrorCode.TOFU_FMT_FAILED,\n error,\n { stderr }\n )\n );\n }\n });\n\n child.on('close', (code) => {\n clearTimeout(timer);\n\n if (timedOut) {\n reject(\n new EngineError(\n `tofu fmt timed out after ${opts.timeout}ms`,\n EngineErrorCode.TOFU_FMT_FAILED,\n undefined,\n { timeout: opts.timeout }\n )\n );\n return;\n }\n\n if (code !== 0) {\n reject(\n new EngineError(\n `tofu fmt failed: ${stderr || 'Unknown error'}`,\n EngineErrorCode.TOFU_FMT_FAILED,\n undefined,\n { stderr, exitCode: code }\n )\n );\n return;\n }\n\n resolve(normalizeBlankLines(stdout));\n });\n\n // Write content to stdin\n child.stdin.write(content);\n child.stdin.end();\n });\n}\n\n/**\n * Format multiple HCL files.\n *\n * @param files - Map of file paths to content\n * @param options - Format options\n * @returns Map of file paths to formatted content\n */\nexport async function formatFiles(\n files: Map<string, string>,\n options?: FormatOptions\n): Promise<Map<string, string>> {\n const opts = { ...DEFAULT_FORMAT_OPTIONS, ...options };\n\n if (opts.skip) {\n return files;\n }\n\n const results = new Map<string, string>();\n\n // Format files sequentially to avoid overwhelming the system\n for (const [path, content] of files) {\n if (isHclFormattable(path)) {\n try {\n const formatted = await formatHCL(content, options);\n results.set(path, formatted);\n } catch (error) {\n // Add file context to error\n if (error instanceof EngineError) {\n throw new EngineError(error.message, error.code, error.cause as Error, {\n ...error.details,\n file: path,\n });\n }\n throw error;\n }\n } else {\n // Pass through non-tf files with normalized blank lines\n results.set(path, normalizeBlankLines(content));\n }\n }\n\n return results;\n}\n\n/**\n * Check if tofu is available in the system.\n *\n * @returns true if tofu is available\n */\nexport async function isTofuAvailable(): Promise<boolean> {\n try {\n await execFileAsync('tofu', ['version'], {\n timeout: 5000,\n encoding: 'utf-8',\n });\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Get tofu version.\n *\n * @returns Version string or null if not available\n */\nexport async function getTofuVersion(): Promise<string | null> {\n try {\n const { stdout } = await execFileAsync('tofu', ['version'], {\n timeout: 5000,\n encoding: 'utf-8',\n });\n // Parse version from output like \"OpenTofu v1.6.0\"\n const match = stdout.match(/v[\\d.]+/);\n return match ? match[0] : null;\n } catch {\n return null;\n }\n}\n","/**\n * Header-agnostic file hashing and aggregate Platform Hash computation.\n *\n * The hashing pipeline for each file delegates to canonical_hash.sh which\n * strips headers, canonicalizes HCL, and computes SHA-256. The aggregate hash\n * combines all platform-zone file hashes sorted by path.\n *\n * Reference: R-004, R-010, FR-004, FR-005, FR-026, FR-034\n */\n\nimport { createHash } from 'node:crypto';\nimport { canonicalHash } from './canonical-hash.js';\nimport type { FileMap } from '../schema/types.js';\nimport { MANIFEST_FILENAME } from './zones.js';\n\n/**\n * Compute a SHA-256 hash of arbitrary content.\n *\n * @param content - Content to hash\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function sha256(content: string): string {\n const hex = createHash('sha256').update(content, 'utf-8').digest('hex');\n return `sha256:${hex}`;\n}\n\n/**\n * Compute format-independent content hash for a single file.\n *\n * Delegates to the canonical hash pipeline: strip @tfy-status header →\n * canonicalize HCL (strip comments, whitespace, normalize trailing commas) →\n * SHA-256.\n *\n * @param content - Full file content (may include @tfy-status header)\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashFileContent(content: string): string {\n return canonicalHash(content);\n}\n\n/**\n * Compute the aggregate Platform Hash from a file map.\n *\n * Only platform-zone files are included. Files are sorted lexicographically\n * by path. The hash is computed from a concatenation of \"path:hash\\n\" lines.\n *\n * Algorithm (R-004):\n * 1. Collect all Platform Zone file entries: [(path, hash), ...]\n * 2. Sort by path (lexicographic, case-sensitive)\n * 3. Join as: \"path1:hash1\\npath2:hash2\\n...\"\n * 4. SHA-256 the joined string\n * 5. Return \"sha256:<hex>\"\n *\n * @param files - Zone-tagged file map\n * @returns Aggregate hash prefixed with \"sha256:\"\n */\nexport function computeAggregateHash(files: FileMap): string {\n // Step 1: Collect platform-zone files (excluding manifest.json to avoid\n // circular dependency — the manifest contains the aggregate hash)\n const entries: Array<{ path: string; hash: string }> = [];\n\n for (const [path, entry] of files) {\n if (entry.zone === 'platform' && path !== MANIFEST_FILENAME) {\n entries.push({\n path,\n hash: hashFileContent(entry.content),\n });\n }\n }\n\n // Step 2: Sort by path (lexicographic, case-sensitive)\n entries.sort((a, b) => a.path.localeCompare(b.path));\n\n // Step 3: Join as \"path:hash\\n\"\n const concatenated = entries.map((e) => `${e.path}:${e.hash}`).join('\\n');\n\n // Step 4–5: SHA-256 with prefix\n return sha256(concatenated);\n}\n","/**\n * Format-independent canonical hashing via external shell script.\n *\n * Delegates to `scripts/canonical_hash.sh` which canonicalizes HCL content\n * (stripping headers, comments, whitespace, and normalizing trailing commas)\n * then computes a SHA-256 hash. Uses spawnSync to keep the entire call graph\n * synchronous.\n *\n * Reference: R-003, R-010\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { createHash } from 'node:crypto';\nimport { stripHeader } from './header.js';\n\nconst HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;\nconst DEFAULT_TIMEOUT_MS = 3_000;\n\nlet _cachedScriptPath: string | undefined;\n\n/**\n * Walk up from a starting directory to find the nearest directory\n * containing package.json (the package root).\n */\nfunction findPackageRoot(startDir: string): string {\n let dir = startDir;\n for (;;) {\n if (existsSync(join(dir, 'package.json'))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n throw new Error(`Cannot find package root (no package.json found above ${startDir})`);\n}\n\n/**\n * Get the absolute path to the canonical_hash.sh script.\n *\n * Resolves by walking up from the current module's directory to find the\n * package root, then appending `scripts/canonical_hash.sh`. The result is\n * cached after first resolution.\n *\n * Works in all environments:\n * - Dev/test: __dirname = src/integrity -> walk up 2 levels\n * - tsup CJS: __dirname = dist -> walk up 1 level\n * - tsup ESM: __dirname shimmed by esbuild -> walk up 1 level\n */\nexport function getCanonicalHashScriptPath(): string {\n if (_cachedScriptPath !== undefined) return _cachedScriptPath;\n\n const pkgRoot = findPackageRoot(__dirname);\n _cachedScriptPath = join(pkgRoot, 'scripts', 'canonical_hash.sh');\n return _cachedScriptPath;\n}\n\n/**\n * Compute a format-independent canonical hash of HCL content.\n *\n * The shell script handles the full pipeline: strip @tfy-status header,\n * strip carriage returns, canonicalize via AWK 4-state machine, then SHA-256.\n *\n * If the script fails for any reason (not found, timeout, bad exit code,\n * malformed output), falls back to a raw SHA-256 of the header-stripped\n * content and logs a warning.\n *\n * @param content - Raw file content (may include @tfy-status header)\n * @param options - Optional timeout in milliseconds (default: 10000)\n * @returns Hash string in format \"sha256:<64-hex-chars>\"\n */\nexport function canonicalHash(content: string, options?: { timeout?: number }): string {\n const timeout = options?.timeout ?? DEFAULT_TIMEOUT_MS;\n\n try {\n const scriptPath = getCanonicalHashScriptPath();\n const result = spawnSync('sh', [scriptPath], {\n input: content,\n encoding: 'utf-8',\n timeout,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n if (result.error) {\n throw result.error;\n }\n\n if (result.status !== 0) {\n throw new Error(`canonical_hash.sh exited with code ${result.status}: ${result.stderr}`);\n }\n\n const hash = result.stdout.trim();\n if (!HASH_PATTERN.test(hash)) {\n throw new Error(`canonical_hash.sh returned malformed output: ${hash}`);\n }\n\n return hash;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n process.stderr.write(\n `[tfy-infra-engine] canonical hash failed, using raw hash fallback: ${message}\\n`\n );\n const stripped = stripHeader(content);\n const hex = createHash('sha256').update(stripped, 'utf-8').digest('hex');\n return `sha256:${hex}`;\n }\n}\n","/**\n * @tfy-status header processing: parse, strip, inject.\n *\n * The header is a structured metadata block embedded as Terraform comment lines\n * at the top of every Platform Zone file.\n *\n * Format (R-001):\n * ```hcl\n * # @tfy-status:begin\n * # {\"managed\":true,\"source\":\"...\",\"version\":\"...\",\"intent_id\":\"...\",\"content_hash\":\"sha256:...\"}\n * # @tfy-status:end\n * ```\n *\n * Reference: R-001, R-002, R-010, FR-044 through FR-046\n */\n\nimport type { TfyStatusHeader } from '../schema/types.js';\n\n/** Begin sentinel for header detection */\nconst HEADER_BEGIN = '# @tfy-status:begin';\n\n/** End sentinel for header detection */\nconst HEADER_END = '# @tfy-status:end';\n\n/**\n * Parse a @tfy-status header from file content.\n * Returns undefined if no valid header is found.\n * (FR-044)\n *\n * @param content - File content possibly containing a header\n * @returns Parsed header or undefined\n */\nexport function parseHeader(content: string): TfyStatusHeader | undefined {\n const lines = content.split('\\n');\n\n // Header must start at line 0\n if (lines[0] !== HEADER_BEGIN) {\n return undefined;\n }\n\n // End sentinel must be at line 2\n if (lines[2] !== HEADER_END) {\n return undefined;\n }\n\n // Line 1 must be a comment with JSON payload\n const jsonLine = lines[1];\n if (!jsonLine || !jsonLine.startsWith('# ')) {\n return undefined;\n }\n\n const jsonStr = jsonLine.substring(2); // Remove \"# \" prefix\n\n try {\n const parsed = JSON.parse(jsonStr) as Record<string, unknown>;\n\n // Map snake_case JSON fields to camelCase TypeScript interface\n return {\n managed: parsed['managed'] as boolean,\n source: parsed['source'] as string,\n version: parsed['version'] as string,\n intentId: parsed['intent_id'] as string,\n contentHash: parsed['content_hash'] as string,\n };\n } catch {\n return undefined;\n }\n}\n\n/**\n * Strip the @tfy-status header from file content, returning only functional HCL.\n * If no header is found, returns content unchanged.\n * (FR-045)\n *\n * Algorithm (R-010):\n * 1. Check if content starts with \"# @tfy-status:begin\\n\"\n * 2. If yes, find the line \"# @tfy-status:end\\n\"\n * 3. Remove everything from start through (and including) the end sentinel line\n * 4. If leading newline remains after stripping, remove it\n *\n * @param content - File content possibly containing a header\n * @returns Content without the header\n */\nexport function stripHeader(content: string): string {\n if (!content.startsWith(HEADER_BEGIN + '\\n')) {\n return content;\n }\n\n const endMarker = HEADER_END + '\\n';\n const endIndex = content.indexOf(endMarker);\n\n if (endIndex === -1) {\n return content;\n }\n\n // Remove everything up to and including the end sentinel line\n let stripped = content.substring(endIndex + endMarker.length);\n\n // Remove the blank line separator after the header (if present)\n if (stripped.startsWith('\\n')) {\n stripped = stripped.substring(1);\n }\n\n return stripped;\n}\n\n/**\n * Inject a @tfy-status header into file content, prepending it as comment lines.\n * (FR-046)\n *\n * The header is always injected AFTER formatting (R-002) to ensure:\n * - tofu fmt never alters the header\n * - The content_hash matches the hash of content without the header\n *\n * @param content - File content to prepend header to\n * @param header - Header metadata to inject\n * @returns Content with header prepended\n */\nexport function injectHeader(content: string, header: TfyStatusHeader): string {\n // Map camelCase TypeScript fields to snake_case JSON (HCL convention)\n const jsonPayload = JSON.stringify({\n managed: header.managed,\n source: header.source,\n version: header.version,\n intent_id: header.intentId,\n content_hash: header.contentHash,\n });\n\n return `${HEADER_BEGIN}\\n# ${jsonPayload}\\n${HEADER_END}\\n\\n${content}`;\n}\n","/**\n * Zone classification for file ownership.\n *\n * Classifies files as Platform Zone or User Zone based on filename prefix.\n * Reference: R-007, FR-001, FR-002\n */\n\nimport { basename } from 'node:path';\nimport type { Zone, FileMap } from '../schema/types.js';\n\n/**\n * Default platform filename prefix.\n */\nexport const DEFAULT_PREFIX = 'tfy_';\n\n/**\n * The manifest filename is always classified as platform zone.\n */\nexport const MANIFEST_FILENAME = 'manifest.json';\n\n/**\n * Classify a file as Platform Zone or User Zone based on its filename.\n *\n * Rules (R-007):\n * 1. Only the basename matters (not the directory path).\n * 2. The prefix check is case-sensitive.\n * 3. The Manifest file itself (manifest.json) is classified as Platform Zone.\n * 4. Files without .tf extension that have the prefix are still Platform Zone.\n * 5. The prefix is configurable per envelope/configuration.\n *\n * @param filePath - Relative or absolute file path\n * @param prefix - Platform Zone filename prefix (default: \"tfy_\")\n * @returns Zone classification (\"platform\" or \"user\")\n */\nexport function classifyFile(filePath: string, prefix: string = DEFAULT_PREFIX): Zone {\n // Normalize path separators and get basename\n const name = basename(filePath.replace(/\\\\/g, '/'));\n\n // Rule 3: manifest.json is always platform\n if (name === MANIFEST_FILENAME) {\n return 'platform';\n }\n\n // Rules 1, 2, 4, 5: check if basename starts with the prefix (case-sensitive)\n if (name.startsWith(prefix)) {\n return 'platform';\n }\n\n return 'user';\n}\n\n/**\n * Count files classified as platform zone in a file map.\n */\nexport function countPlatformFiles(files: FileMap): number {\n let count = 0;\n for (const [, entry] of files) {\n if (entry.zone === 'platform') count++;\n }\n return count;\n}\n","/**\n * Manifest generation for rendered output — JSON v1.0.\n *\n * The Manifest is the \"State Passport\" recording cluster identity,\n * aggregate Platform Hash, per-file hashes, and engine metadata.\n *\n * Reference: R-005, FR-007, FR-033 through FR-036\n */\n\nimport type { Manifest, ManifestFileEntry, Template, FileMap } from '../schema/types.js';\nimport { sha256, hashFileContent, computeAggregateHash } from '../integrity/hasher.js';\nimport { MANIFEST_FILENAME } from '../integrity/zones.js';\n\ndeclare const __ENGINE_VERSION__: string;\nconst ENGINE_VERSION = __ENGINE_VERSION__;\n\nexport interface GenerateManifestOptions {\n files: FileMap;\n template: Template;\n inputs: Record<string, unknown>;\n formatted: boolean;\n intentId: string;\n platformPrefix?: string;\n}\n\n/**\n * Generate a Manifest for a zone-tagged file map.\n * (FR-007, FR-033, FR-034, FR-036)\n */\nexport function generateManifest(opts: GenerateManifestOptions): Manifest {\n const { files, template, inputs, formatted, intentId, platformPrefix = 'tfy_' } = opts;\n const manifestFiles: ManifestFileEntry[] = [];\n\n for (const [path, entry] of files) {\n // Skip the manifest itself if it's in the map\n if (path === MANIFEST_FILENAME) continue;\n\n manifestFiles.push({\n path,\n hash: hashFileContent(entry.content),\n size: Buffer.byteLength(entry.content, 'utf-8'),\n source: template.source,\n version: template.metadata.version,\n zone: entry.zone,\n });\n }\n\n // Sort files by path for deterministic output (FR-035)\n manifestFiles.sort((a, b) => a.path.localeCompare(b.path));\n\n // Compute aggregate hash from platform files only (FR-034)\n const aggregateHash = computeAggregateHash(files);\n\n return {\n manifestVersion: '1.0',\n intentId,\n generatedAt: new Date().toISOString(),\n templateSource: template.source,\n templateVersion: template.metadata.version,\n aggregateHash,\n engine: {\n version: ENGINE_VERSION,\n formatted,\n },\n inputs,\n platformPrefix,\n files: manifestFiles,\n };\n}\n\n/**\n * Serialize a Manifest to a JSON string.\n *\n * Uses 2-space indentation and deterministic key ordering (R-005).\n *\n * @param manifest - Manifest to serialize\n * @returns JSON string\n */\nexport function serializeManifest(manifest: Manifest): string {\n // Deterministic key ordering via explicit construction\n const ordered = {\n manifestVersion: manifest.manifestVersion,\n intentId: manifest.intentId,\n generatedAt: manifest.generatedAt,\n templateSource: manifest.templateSource,\n templateVersion: manifest.templateVersion,\n aggregateHash: manifest.aggregateHash,\n engine: manifest.engine,\n inputs: manifest.inputs,\n platformPrefix: manifest.platformPrefix,\n files: manifest.files,\n };\n\n return JSON.stringify(ordered, null, 2) + '\\n';\n}\n\n/**\n * Hash content using SHA-256.\n * Delegates to the shared sha256() utility.\n *\n * @param content - Content to hash\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashContent(content: string): string {\n return sha256(content);\n}\n\n/**\n * Hash inputs for determinism verification.\n * Normalizes inputs before hashing to ensure deterministic results.\n *\n * @param inputs - Input values\n * @returns Hash string prefixed with \"sha256:\"\n */\nexport function hashInputs(inputs: Record<string, unknown>): string {\n const normalized = JSON.stringify(sortObjectKeys(inputs));\n return hashContent(normalized);\n}\n\n/**\n * Recursively sort object keys for deterministic serialization.\n */\nfunction sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(sortObjectKeys);\n }\n\n const sorted: Record<string, unknown> = {};\n const keys = Object.keys(obj as Record<string, unknown>).sort();\n\n for (const key of keys) {\n sorted[key] = sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n\n return sorted;\n}\n","/**\n * Drift detection and Chain of Command verification.\n *\n * Compares current on-disk file state against a Manifest to produce\n * a structured drift report with per-file entries.\n *\n * Reference: R-009, FR-015, FR-028, FR-041 through FR-043, FR-047\n */\n\nimport type { FileMap, Manifest, DriftReport, DriftEntry, DriftSummary } from '../schema/types.js';\nimport { parseHeader } from './header.js';\nimport { hashFileContent, computeAggregateHash } from './hasher.js';\nimport { classifyFile, DEFAULT_PREFIX, MANIFEST_FILENAME } from './zones.js';\n\n/**\n * Build a drift report comparing current files against a manifest.\n *\n * Checks performed per file:\n * - Content hash match (header-agnostic) → content_drift\n * - Chain of Command: header fields vs manifest entry → metadata_inconsistency\n * - Missing files (in manifest, not in file map) → missing_file\n * - Unexpected files (platform-prefixed, not in manifest) → unexpected_file\n * - Source mismatch (incoming source vs file headers) → source_mismatch\n *\n * @param currentFiles - Current file map (from disk)\n * @param manifest - Previous Manifest to verify against\n * @param prefix - Platform Zone prefix (default: \"tfy_\")\n * @param incomingSource - If provided, check for source mismatch (FR-028)\n * @returns Structured drift report\n */\nexport function buildDriftReport(\n currentFiles: FileMap,\n manifest: Manifest,\n prefix: string = DEFAULT_PREFIX,\n incomingSource?: string\n): DriftReport {\n const entries: DriftEntry[] = [];\n const manifestPathSet = new Set(manifest.files.map((f) => f.path));\n const checkedPaths = new Set<string>();\n\n // Check each file in the manifest against the current file map\n for (const manifestEntry of manifest.files) {\n // Only check platform zone files for integrity\n if (manifestEntry.zone !== 'platform') continue;\n\n checkedPaths.add(manifestEntry.path);\n const currentEntry = currentFiles.get(manifestEntry.path);\n\n if (!currentEntry) {\n entries.push({\n path: manifestEntry.path,\n type: 'missing_file',\n details: 'File listed in Manifest but not found in current file map',\n });\n continue;\n }\n\n // Content hash check (header-agnostic)\n const actualHash = hashFileContent(currentEntry.content);\n if (actualHash !== manifestEntry.hash) {\n entries.push({\n path: manifestEntry.path,\n type: 'content_drift',\n details: `Content hash mismatch: expected ${manifestEntry.hash}, actual ${actualHash}`,\n });\n }\n\n // Chain of Command: compare file header fields against manifest entry (FR-047)\n const header = currentEntry.header ?? parseHeader(currentEntry.content);\n if (header) {\n if (header.source !== manifestEntry.source) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header source '${header.source}' does not match Manifest source '${manifestEntry.source}'`,\n });\n }\n if (header.version !== manifestEntry.version) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header version '${header.version}' does not match Manifest version '${manifestEntry.version}'`,\n });\n }\n if (header.contentHash !== manifestEntry.hash) {\n entries.push({\n path: manifestEntry.path,\n type: 'metadata_inconsistency',\n details: `Header content_hash '${header.contentHash}' does not match Manifest hash '${manifestEntry.hash}'`,\n });\n }\n }\n }\n\n // Check for unexpected platform-prefixed files not in manifest\n for (const [path, entry] of currentFiles) {\n if (entry.zone === 'platform' || classifyFile(path, prefix) === 'platform') {\n if (!manifestPathSet.has(path) && path !== MANIFEST_FILENAME) {\n entries.push({\n path,\n type: 'unexpected_file',\n details: 'Platform-prefixed file found in current file map but not listed in Manifest',\n });\n }\n }\n }\n\n // Source mismatch check (FR-028)\n if (incomingSource) {\n for (const [path, entry] of currentFiles) {\n if (entry.zone !== 'platform') continue;\n const header = entry.header ?? parseHeader(entry.content);\n if (header && header.source !== incomingSource) {\n entries.push({\n path,\n type: 'source_mismatch',\n details: `File source '${header.source}' does not match incoming source '${incomingSource}'`,\n });\n }\n }\n }\n\n // Compute aggregate hash comparison\n const actualAggregateHash = computeAggregateHash(currentFiles);\n const expectedAggregateHash = manifest.aggregateHash;\n\n // Build summary\n const summary = buildSummary(entries, manifest);\n\n return {\n valid: entries.length === 0,\n aggregateHash: {\n expected: expectedAggregateHash,\n actual: actualAggregateHash,\n },\n entries,\n summary,\n };\n}\n\n/**\n * Build summary counts from drift entries.\n */\nfunction buildSummary(entries: DriftEntry[], manifest: Manifest): DriftSummary {\n const driftedPaths = new Set<string>();\n const inconsistentPaths = new Set<string>();\n let missingFiles = 0;\n let unexpectedFiles = 0;\n let sourceMismatches = 0;\n\n for (const entry of entries) {\n switch (entry.type) {\n case 'content_drift':\n driftedPaths.add(entry.path);\n break;\n case 'metadata_inconsistency':\n inconsistentPaths.add(entry.path);\n break;\n case 'missing_file':\n missingFiles++;\n break;\n case 'unexpected_file':\n unexpectedFiles++;\n break;\n case 'source_mismatch':\n sourceMismatches++;\n break;\n }\n }\n\n return {\n totalFiles: manifest.files.filter((f) => f.zone === 'platform').length,\n driftedFiles: driftedPaths.size,\n inconsistentFiles: inconsistentPaths.size,\n missingFiles,\n unexpectedFiles,\n sourceMismatches,\n };\n}\n","/**\n * Envelope validation and utilities.\n * The envelope is the configuration wrapper for template rendering\n * with integrity engine support.\n *\n * CHANGE (008): Zod removed entirely. Validation uses plain TypeScript\n * runtime checks. Template field validates new shape (metadata + jsonSchema).\n *\n * Reference: R-006, R-008, FR-031, FR-032\n */\n\nimport type { Envelope, RenderOptions, Template } from './types.js';\nimport { EngineError, EngineErrorCode } from '../errors.js';\n\nfunction fail(message: string): never {\n throw new EngineError(message, EngineErrorCode.ENVELOPE_VALIDATION_FAILED);\n}\n\n/**\n * Validate an envelope configuration using plain TypeScript runtime checks.\n *\n * Checks:\n * - template: must be a valid Template object (metadata, jsonSchema, files Map with size > 0, source, version)\n * - intentId: required non-empty string\n * - inputs: defaults to {}\n * - platformPrefix: defaults to \"tfy_\"\n * - options: optional, validates skipFormat if present\n * - rejects unknown top-level fields\n *\n * @param data - Raw envelope data to validate\n * @returns Validated envelope\n * @throws EngineError if validation fails\n */\nexport function validateEnvelope(data: unknown): Envelope {\n if (!data || typeof data !== 'object' || Array.isArray(data)) {\n fail('Envelope must be a non-null object');\n }\n\n const record = data as Record<string, unknown>;\n\n const knownFields = new Set(['template', 'inputs', 'options', 'intentId', 'platformPrefix']);\n for (const key of Object.keys(record)) {\n if (!knownFields.has(key)) {\n fail(`Unknown field \"${key}\" in envelope. Allowed: ${[...knownFields].join(', ')}`);\n }\n }\n\n validateTemplateObject(record['template']);\n\n if (typeof record['intentId'] !== 'string' || record['intentId'].length === 0) {\n fail('intentId is required and must be non-empty');\n }\n\n const inputs = record['inputs'] !== undefined ? record['inputs'] : {};\n if (typeof inputs !== 'object' || inputs === null || Array.isArray(inputs)) {\n fail('inputs must be an object');\n }\n\n const platformPrefix = record['platformPrefix'] !== undefined ? record['platformPrefix'] : 'tfy_';\n if (typeof platformPrefix !== 'string') {\n fail('platformPrefix must be a string');\n }\n\n let options: RenderOptions | undefined;\n if (record['options'] !== undefined) {\n options = validateRenderOptions(record['options']);\n }\n\n return {\n template: record['template'] as Template,\n inputs: inputs as Record<string, unknown>,\n options,\n intentId: record['intentId'],\n platformPrefix: platformPrefix,\n };\n}\n\n/**\n * Parse render options with defaults applied.\n *\n * @param options - Optional render options\n * @returns Options with defaults applied\n */\nexport function parseRenderOptions(options?: RenderOptions): Required<RenderOptions> {\n return {\n skipFormat: options?.skipFormat ?? false,\n };\n}\n\n// ============================================================================\n// Internal validators\n// ============================================================================\n\nfunction validateTemplateObject(value: unknown): void {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n fail('template must be a non-null object');\n }\n\n const template = value as Record<string, unknown>;\n\n if (!template['metadata'] || typeof template['metadata'] !== 'object') {\n fail('template.metadata must be an object');\n }\n\n const metadata = template['metadata'] as Record<string, unknown>;\n if (typeof metadata['name'] !== 'string' || metadata['name'].length === 0) {\n fail('template.metadata.name must be a non-empty string');\n }\n if (typeof metadata['version'] !== 'string' || !/^\\d+\\.\\d+\\.\\d+$/.test(metadata['version'])) {\n fail('template.metadata.version must be semver format (x.y.z)');\n }\n\n if (!template['jsonSchema'] || typeof template['jsonSchema'] !== 'object') {\n fail('template.jsonSchema must be an object');\n }\n\n const hasFiles =\n (template['files'] instanceof Map && template['files'].size > 0) ||\n (template['staticFiles'] instanceof Map && template['staticFiles'].size > 0);\n if (!hasFiles) {\n fail('Template must have at least one file (in files or staticFiles)');\n }\n if (template['files'] !== undefined && !(template['files'] instanceof Map)) {\n fail('template.files must be a Map');\n }\n if (template['staticFiles'] !== undefined && !(template['staticFiles'] instanceof Map)) {\n fail('template.staticFiles must be a Map');\n }\n\n if (typeof template['source'] !== 'string' || template['source'].length === 0) {\n fail('Template source URI is required');\n }\n\n if (!template['version'] || typeof template['version'] !== 'object') {\n fail('Template version info is required');\n }\n\n const version = template['version'] as Record<string, unknown>;\n if (typeof version['semver'] !== 'string' || !/^\\d+\\.\\d+\\.\\d+$/.test(version['semver'])) {\n fail('template.version.semver must be semver format (x.y.z)');\n }\n if (version['apiVersion'] !== undefined && typeof version['apiVersion'] !== 'string') {\n fail('template.version.apiVersion must be a string if provided');\n }\n}\n\nfunction validateRenderOptions(value: unknown): RenderOptions {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n fail('options must be an object');\n }\n\n const opts = value as Record<string, unknown>;\n\n const knownOptionFields = new Set(['skipFormat']);\n for (const key of Object.keys(opts)) {\n if (!knownOptionFields.has(key)) {\n fail(`Unknown option field \"${key}\". Allowed: ${[...knownOptionFields].join(', ')}`);\n }\n }\n\n if (opts['skipFormat'] !== undefined && typeof opts['skipFormat'] !== 'boolean') {\n fail('options.skipFormat must be a boolean');\n }\n\n return {\n skipFormat: opts['skipFormat'],\n };\n}\n","/**\n * HCL Engine implementation — four-operation integrity API.\n *\n * Operations:\n * - install(envelope): Generate all files for a new cluster\n * - upgrade(envelope, currentFiles, previousManifest): Update to new templates\n * - verify(currentFiles, previousManifest): Check integrity\n * - hashOnly(envelope): Calculate expected aggregate hash\n *\n * Reference: R-006, FR-037, FR-038, plan.md Operation Pipelines\n */\n\nimport type {\n Envelope,\n RenderOptions,\n HclEngine,\n InstallResult,\n UpgradeResult,\n VerifyResult,\n HashOnlyResult,\n FileMap,\n Manifest,\n Template,\n TfyStatusHeader,\n} from './schema/types.js';\nimport { validateEnvelope, parseRenderOptions } from './schema/envelope.js';\nimport {\n createInputValidator,\n validateAndApplyDefaults,\n validateJsonSchemaStructure,\n} from './schema/input-validator.js';\nimport { renderTemplate } from './render/renderer.js';\nimport { formatFiles } from './render/formatter.js';\nimport { generateManifest, serializeManifest } from './render/manifest.js';\nimport { EngineError, EngineErrorCode } from './errors.js';\nimport {\n classifyFile,\n DEFAULT_PREFIX,\n MANIFEST_FILENAME,\n countPlatformFiles,\n} from './integrity/zones.js';\nimport { hashFileContent } from './integrity/hasher.js';\nimport { injectHeader } from './integrity/header.js';\nimport { buildDriftReport } from './integrity/drift.js';\n\n/**\n * HCL Engine implementation.\n */\nclass HclEngineImpl implements HclEngine {\n /**\n * Install: Generate all files for a new cluster.\n *\n * Pipeline: validate envelope → validate inputs (AJV) → render templates →\n * format .tf files → classify by zone → hash + inject headers → generate manifest.\n */\n async install(envelope: Envelope): Promise<InstallResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return { files: fileMap, manifest };\n }\n\n /**\n * Upgrade: Update an existing cluster to new templates.\n *\n * Pipeline: validate envelope → drift detection (FR-028) → validate inputs →\n * render → format → hash + manifest.\n *\n * The engine always renders new files regardless of source mismatch.\n * Callers (CLI/Server) enforce blocking policy via `sourceBlocked` flag (FR-029).\n */\n async upgrade(\n envelope: Envelope,\n currentFiles: FileMap,\n previousManifest: Manifest\n ): Promise<UpgradeResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const incomingSource = validatedEnvelope.template.source;\n const driftReport = buildDriftReport(currentFiles, previousManifest, prefix, incomingSource);\n const sourceBlocked = driftReport.summary.sourceMismatches > 0;\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return { files: fileMap, manifest, driftReport, sourceBlocked };\n }\n\n /**\n * Verify: Check integrity of existing files against a Manifest.\n */\n verify(currentFiles: FileMap, previousManifest: Manifest): Promise<VerifyResult> {\n if (\n !previousManifest ||\n !previousManifest.manifestVersion ||\n !previousManifest.files ||\n !previousManifest.aggregateHash\n ) {\n throw new EngineError(\n 'Invalid manifest: missing required fields (manifestVersion, files, aggregateHash)',\n EngineErrorCode.MANIFEST_PARSE_ERROR\n );\n }\n\n const driftReport = buildDriftReport(currentFiles, previousManifest);\n return Promise.resolve({ driftReport });\n }\n\n /**\n * Hash-Only: Calculate expected aggregate hash without full file generation.\n */\n async hashOnly(envelope: Envelope): Promise<HashOnlyResult> {\n const validatedEnvelope = this.validateEnvelopeOrThrow(envelope);\n const options = parseRenderOptions(validatedEnvelope.options);\n const prefix = validatedEnvelope.platformPrefix ?? DEFAULT_PREFIX;\n\n const { renderedFiles, template, formatted, inputsWithDefaults } = await this.renderPipeline(\n validatedEnvelope,\n options\n );\n\n const { fileMap, manifest } = this.buildFilesAndManifest(\n renderedFiles,\n validatedEnvelope,\n template,\n inputsWithDefaults,\n formatted,\n prefix\n );\n\n return {\n aggregateHash: manifest.aggregateHash,\n templateSource: template.source,\n templateVersion: template.metadata.version,\n fileCount: countPlatformFiles(fileMap),\n };\n }\n\n // =========================================================================\n // Private helpers\n // =========================================================================\n\n /**\n * Validate envelope or throw ENVELOPE_VALIDATION_FAILED.\n */\n private validateEnvelopeOrThrow(envelope: Envelope): Envelope {\n try {\n return validateEnvelope(envelope);\n } catch (error) {\n throw new EngineError(\n `Envelope validation failed: ${(error as Error).message}`,\n EngineErrorCode.ENVELOPE_VALIDATION_FAILED,\n error as Error\n );\n }\n }\n\n /**\n * Shared render pipeline: validate schema → validate inputs → render → format.\n */\n private async renderPipeline(validatedEnvelope: Envelope, options: Required<RenderOptions>) {\n const template = validatedEnvelope.template;\n\n // JSON Schema validation pipeline (R-001, R-010)\n validateJsonSchemaStructure(template.jsonSchema);\n const validator = createInputValidator(template.jsonSchema);\n\n const inputsWithDefaults = structuredClone(validatedEnvelope.inputs);\n const validation = validateAndApplyDefaults(validator, inputsWithDefaults);\n\n if (!validation.valid) {\n throw new EngineError(\n `Input validation failed: ${validation.errors?.map((e) => `${e.path}: ${e.message}`).join(', ')}`,\n EngineErrorCode.INPUT_VALIDATION_FAILED,\n undefined,\n { errors: validation.errors }\n );\n }\n\n let renderedFiles = renderTemplate(template, inputsWithDefaults);\n\n // Merge static files (verbatim, no Handlebars processing)\n if (template.staticFiles) {\n for (const [path, content] of template.staticFiles) {\n renderedFiles.set(path, content);\n }\n }\n\n const formatted = !options.skipFormat;\n if (formatted) {\n renderedFiles = await formatFiles(renderedFiles, {\n skip: false,\n timeout: 10000,\n });\n }\n\n for (const [path, content] of renderedFiles) {\n if (content.trim() === '') {\n renderedFiles.delete(path);\n }\n }\n\n return { renderedFiles, template, formatted, inputsWithDefaults };\n }\n\n /**\n * Build a zone-tagged FileEntry map from raw rendered files.\n */\n private buildFileMap(\n renderedFiles: Map<string, string>,\n prefix: string,\n meta: { source: string; version: string; intentId: string }\n ): FileMap {\n const fileMap: FileMap = new Map();\n\n for (const [path, content] of renderedFiles) {\n const zone = classifyFile(path, prefix);\n\n if (zone === 'platform') {\n const contentHash = hashFileContent(content);\n\n const header: TfyStatusHeader = {\n managed: true,\n source: meta.source,\n version: meta.version,\n intentId: meta.intentId,\n contentHash,\n };\n\n const contentWithHeader = injectHeader(content, header);\n\n fileMap.set(path, {\n content: contentWithHeader,\n zone: 'platform',\n header,\n });\n } else {\n fileMap.set(path, {\n content,\n zone: 'user',\n });\n }\n }\n\n return fileMap;\n }\n\n /**\n * Build zone-tagged file map, generate manifest, and insert it into the map.\n * Shared by install, upgrade, and hashOnly.\n */\n private buildFilesAndManifest(\n renderedFiles: Map<string, string>,\n validatedEnvelope: Envelope,\n template: Template,\n inputsWithDefaults: Record<string, unknown>,\n formatted: boolean,\n prefix: string\n ): { fileMap: FileMap; manifest: Manifest } {\n const fileMap = this.buildFileMap(renderedFiles, prefix, {\n source: template.source,\n version: template.metadata.version,\n intentId: validatedEnvelope.intentId,\n });\n\n const manifest = generateManifest({\n files: fileMap,\n template,\n inputs: inputsWithDefaults,\n formatted,\n intentId: validatedEnvelope.intentId,\n platformPrefix: prefix,\n });\n\n fileMap.set(MANIFEST_FILENAME, {\n content: serializeManifest(manifest),\n zone: 'platform',\n });\n\n return { fileMap, manifest };\n }\n}\n\n/**\n * Create a new HCL engine instance.\n *\n * @returns Engine instance\n *\n * @example\n * ```typescript\n * import { createEngine } from '@truefoundry/tfy-infra-engine';\n *\n * const engine = createEngine();\n * const result = await engine.install({\n * template, // pre-resolved Template object\n * inputs: { cluster_name: 'prod' },\n * intentId: 'cluster-prod-001',\n * });\n * ```\n */\nexport function createEngine(): HclEngine {\n return new HclEngineImpl();\n}\n"],"mappings":"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","names":["EngineErrorCode","Ajv","import_ajv","ajv","Ajv","import_handlebars","Handlebars","Handlebars","import_node_crypto","import_node_child_process","import_node_path"]}
|