{"version":3,"file":"impl-B4K4ATdt2.mjs","names":["fg"],"sources":["../src/commands/policy/helpers/buildOpaBundleTarball.ts","../src/commands/policy/helpers/buildPolicyBundleFormData.ts","../src/commands/policy/helpers/defaultPolicyVersionLabel.ts","../src/commands/policy/publish/impl.ts"],"sourcesContent":["import { spawnSync } from 'node:child_process';\nimport fs from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport { gunzipSync } from 'node:zlib';\n\nimport fg from 'fast-glob';\n\nimport { MAX_BUNDLE_COMPRESSED_BYTES, MAX_BUNDLE_DECOMPRESSED_BYTES } from '../constants.js';\nimport { assertOpaInstalled } from './assertOpaInstalled.js';\nimport { runOPACapture } from './runOpa.js';\n\n/**\n * Returns whether a relative path is a publishable Rego policy file.\n *\n * OPA test files (`*_test.rego`) are excluded because they are for local\n * validation only and are not part of the upload contract.\n *\n * @param relativePath - Path relative to the bundle directory\n * @returns Whether the file should be included in the upload archive\n */\nfunction isPublishableRegoFile(relativePath: string): boolean {\n  return relativePath.endsWith('.rego') && !relativePath.endsWith('_test.rego');\n}\n\n/** Shape of the OPA bundle `manifest.json` as accepted by the Policy Engine. */\ninterface PolicyBundleManifest {\n  /** Roots of the bundle, e.g. `[\"policy_engine\"]` or `[\"policy_engine/transcend\"]` */\n  roots: string[];\n}\n\n/**\n * Reads and validates `manifest.json` from a policy bundle directory.\n *\n * The Policy Engine requires `manifest.json` to declare `roots` as an array of\n * strings. OPA's own tooling does not always enforce this against the Rego\n * packages on upload, so we validate the shape client-side to surface a clear,\n * actionable error instead of an opaque server `400` or a decide-time\n * fail-closed footgun.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns The parsed manifest\n */\nfunction readPolicyBundleManifest(dir: string): PolicyBundleManifest {\n  const manifestPath = path.join(dir, 'manifest.json');\n  if (!fs.existsSync(manifestPath)) {\n    throw new Error('Policy bundle directory must contain a manifest.json file.');\n  }\n\n  const raw = fs.readFileSync(manifestPath, 'utf8');\n  let parsed: unknown;\n  try {\n    parsed = JSON.parse(raw);\n  } catch (err) {\n    throw new Error(\n      `manifest.json is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,\n      { cause: err },\n    );\n  }\n\n  if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n    throw new Error('manifest.json must contain a JSON object.');\n  }\n\n  const roots = (parsed as { roots?: unknown }).roots;\n  if (!Array.isArray(roots) || roots.length === 0) {\n    throw new Error(\n      'manifest.json must declare \"roots\" as a non-empty array of strings (e.g. {\"roots\":[\"policy_engine\"]}).',\n    );\n  }\n\n  if (!roots.every((root) => typeof root === 'string' && root.length > 0)) {\n    throw new Error('manifest.json \"roots\" must be an array of non-empty strings.');\n  }\n\n  return { roots };\n}\n\n/** Result of collecting publishable entries from a policy bundle directory. */\ninterface PolicyBundleArchiveContents {\n  /** Relative paths to include in the upload tarball (manifest first, then rego) */\n  entries: string[];\n  /** Parsed manifest */\n  manifest: PolicyBundleManifest;\n}\n\n/**\n * Collects `manifest.json` and publishable `.rego` files from a policy directory.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @returns Archive entries and the parsed manifest\n */\nfunction collectPolicyBundleArchiveEntries(dir: string): PolicyBundleArchiveContents {\n  const manifest = readPolicyBundleManifest(dir);\n\n  const regoFiles = fg\n    .sync('**/*.rego', {\n      cwd: dir,\n      onlyFiles: true,\n      dot: false,\n    })\n    .filter(isPublishableRegoFile);\n\n  if (regoFiles.length === 0) {\n    throw new Error('Policy bundle directory must contain at least one .rego policy file.');\n  }\n\n  return { entries: ['manifest.json', ...regoFiles.sort()], manifest };\n}\n\n/** Matches a Rego `package <path>` declaration. */\nconst PACKAGE_DECLARATION_PATTERN = /^\\s*package\\s+([A-Za-z_][\\w.]*)/m;\n\n/**\n * Normalizes an OPA manifest root to a dotted package prefix.\n *\n * Roots use `/` as the path separator (e.g. `policy_engine/transcend`); Rego\n * package paths use `.` (e.g. `policy_engine.transcend`).\n *\n * @param root - A manifest root string\n * @returns The root in dotted form\n */\nfunction normalizeRootToPackagePrefix(root: string): string {\n  return root.replace(/\\//g, '.');\n}\n\n/**\n * Reads the Rego package path declared in a `.rego` file.\n *\n * @param filePath - Absolute path to the `.rego` file\n * @returns The dotted package path, or `undefined` if no `package` declaration\n */\nfunction readRegoPackagePath(filePath: string): string | undefined {\n  const contents = fs.readFileSync(filePath, 'utf8');\n  const match = PACKAGE_DECLARATION_PATTERN.exec(contents);\n  return match?.[1];\n}\n\n/**\n * Verifies that every publishable `.rego` package is covered by a manifest root.\n *\n * A bundle whose `roots` do not cover its Rego packages will upload cleanly but\n * fail-closed at decide time — the customer only discovers the mismatch via\n * denied decisions. This surfaces the mismatch at upload with a clear message.\n *\n * @param dir - Absolute path to the policy bundle directory\n * @param regoFiles - Relative paths to publishable `.rego` files\n * @param roots - Manifest roots\n */\nfunction assertRootsCoverPackages(dir: string, regoFiles: string[], roots: string[]): void {\n  const rootPrefixes = roots.map(normalizeRootToPackagePrefix);\n\n  const uncovered: string[] = [];\n  for (const relativeRego of regoFiles) {\n    const pkg = readRegoPackagePath(path.join(dir, relativeRego));\n    if (!pkg) {\n      continue;\n    }\n    const covered = rootPrefixes.some((prefix) => pkg === prefix || pkg.startsWith(`${prefix}.`));\n    if (!covered) {\n      uncovered.push(\n        `  - ${relativeRego} (package ${pkg}) is not covered by roots [${roots.join(', ')}]`,\n      );\n    }\n  }\n\n  if (uncovered.length > 0) {\n    throw new Error(\n      [\n        'manifest.json \"roots\" do not cover all Rego packages in the bundle; ' +\n          'uncovered packages will fail-closed at decide time. Either broaden \"roots\" or move the policy under a covered package:',\n        ...uncovered,\n      ].join('\\n'),\n    );\n  }\n}\n\n/**\n * Verifies that a policy directory compiles end-to-end with `opa build`.\n *\n * The compiled output is discarded — the server receives the `manifest.json` +\n * `.rego` archive produced by {@link buildOpaBundleTarball}, not the OPA bundle\n * — but a successful build guarantees the policies compile and link, surfacing\n * errors (syntax, missing imports, undefined references, etc.) before upload.\n *\n * @param dir - Absolute path to the policy bundle directory\n */\nasync function assertBundleCompiles(dir: string): Promise<void> {\n  const buildOutputPath = path.join(\n    os.tmpdir(),\n    `transcend-policy-bundle-build-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n  );\n  try {\n    // Run with `cwd` set to the bundle directory and pass `.` so `opa build`\n    // resolves the bundle root correctly. `*_test.rego` files are local-only.\n    const { code, stderr } = await runOPACapture(\n      ['build', '--v0-compatible', '--ignore', '*_test.rego', '-o', buildOutputPath, '.'],\n      { cwd: dir },\n    );\n    if (code !== 0) {\n      throw new Error(stderr.trim() || `opa build failed with exit code ${code}`);\n    }\n  } finally {\n    if (fs.existsSync(buildOutputPath)) {\n      fs.unlinkSync(buildOutputPath);\n    }\n  }\n}\n\n/**\n * Formats a byte count as a human-readable size with binary units.\n *\n * @param bytes - Number of bytes\n * @returns Human-readable size, e.g. `14 MiB` or `4 KiB`\n */\nfunction formatBytes(bytes: number): string {\n  if (bytes < 1024) {\n    return `${bytes} B`;\n  }\n  const kib = bytes / 1024;\n  if (kib < 1024) {\n    return `${kib % 1 === 0 ? kib.toFixed(0) : kib.toFixed(1)} KiB`;\n  }\n  const mib = kib / 1024;\n  return `${mib % 1 === 0 ? mib.toFixed(0) : mib.toFixed(1)} MiB`;\n}\n\n/**\n * Builds a gzip-compressed policy bundle tarball for upload to Transcend.\n *\n * The Policy Engine API expects a plain archive containing `manifest.json` and\n * one or more `.rego` files. This differs from `opa build` output, which embeds\n * `.manifest`, `data.json`, and other OPA bundle metadata that the server\n * rejects. Before packaging, the manifest is validated (shape + root coverage)\n * and the bundle is validated with `opa check` (strict Rego linting) and\n * `opa build` (full compilation) so failures surface client-side rather than\n * after upload.\n *\n * @param dir - Directory containing `manifest.json` and `.rego` policy files\n * @returns Absolute path to the generated `.tar.gz` bundle\n */\nexport async function buildOpaBundleTarball(dir: string): Promise<string> {\n  assertOpaInstalled();\n\n  const resolvedDir = path.resolve(dir);\n  if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {\n    throw new Error(`Policy directory does not exist or is not a directory: ${resolvedDir}`);\n  }\n\n  // Validate the manifest shape and that roots cover every Rego package before\n  // invoking OPA, so invalid manifests surface a clear error instead of an\n  // opaque `opa build failed with exit code 1`.\n  const { entries: archiveEntries, manifest } = collectPolicyBundleArchiveEntries(resolvedDir);\n  const regoFiles = archiveEntries.filter((entry) => entry !== 'manifest.json');\n  assertRootsCoverPackages(resolvedDir, regoFiles, manifest.roots);\n\n  // Match the Rego v1 validation the Policy Engine API runs on upload.\n  const { code: checkCode, stderr: checkStderr } = await runOPACapture([\n    'check',\n    '--strict',\n    '--v0-compatible',\n    resolvedDir,\n  ]);\n  if (checkCode !== 0) {\n    throw new Error(checkStderr.trim() || `opa check failed with exit code ${checkCode}`);\n  }\n\n  // Ensure the bundle compiles end-to-end before packaging for upload.\n  await assertBundleCompiles(resolvedDir);\n\n  const outputPath = path.join(\n    os.tmpdir(),\n    `transcend-policy-bundle-${Date.now()}-${Math.random().toString(36).slice(2)}.tar.gz`,\n  );\n\n  const tarResult = spawnSync('tar', ['-czf', outputPath, '-C', resolvedDir, ...archiveEntries], {\n    env: { ...process.env, COPYFILE_DISABLE: '1' },\n    encoding: 'utf8',\n  });\n  if (tarResult.status !== 0) {\n    throw new Error(\n      `Failed to create policy bundle archive: ${tarResult.stderr.trim() || 'tar failed'}`,\n    );\n  }\n\n  const compressedBytes = fs.readFileSync(outputPath);\n  if (compressedBytes.byteLength > MAX_BUNDLE_COMPRESSED_BYTES) {\n    fs.unlinkSync(outputPath);\n    throw new Error(\n      `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_COMPRESSED_BYTES)} compressed upload limit ` +\n        `(bundle is ${formatBytes(compressedBytes.byteLength)}). ` +\n        `The server also rejects decompressed bundles larger than ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)}.`,\n    );\n  }\n\n  const decompressedBytes = gunzipSync(compressedBytes);\n  if (decompressedBytes.byteLength > MAX_BUNDLE_DECOMPRESSED_BYTES) {\n    fs.unlinkSync(outputPath);\n    throw new Error(\n      `Policy bundle exceeds the ${formatBytes(MAX_BUNDLE_DECOMPRESSED_BYTES)} decompressed upload limit ` +\n        `(bundle is ${formatBytes(decompressedBytes.byteLength)} decompressed).`,\n    );\n  }\n\n  return outputPath;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\n/** Fields for building a policy bundle upload form. */\nexport interface BuildPolicyBundleFormDataOptions {\n  /** Absolute path to the bundle tarball */\n  bundlePath: string;\n  /** Version label */\n  version: string;\n  /** Optional description */\n  description?: string;\n  /** Bundle name (only for create) */\n  bundleName?: string;\n}\n\n/**\n * Builds multipart form data for a policy bundle upload.\n *\n * @param options - Upload fields\n * @returns FormData ready for POST\n */\nexport function buildPolicyBundleFormData(options: BuildPolicyBundleFormDataOptions): FormData {\n  const bundleBytes = fs.readFileSync(options.bundlePath);\n  const form = new FormData();\n  form.append(\n    'bundle',\n    new Blob([bundleBytes], { type: 'application/gzip' }),\n    path.basename(options.bundlePath),\n  );\n  form.append('version', options.version);\n  if (options.description) {\n    form.append('description', options.description);\n  }\n  if (options.bundleName) {\n    form.append('bundleName', options.bundleName);\n  }\n  return form;\n}\n","/**\n * Formats a date as `yyyy-mm-dd-hh-mm-ss` in UTC.\n *\n * @param date - Date to format\n * @returns Timestamp label\n */\nfunction formatPolicyVersionTimestamp(date: Date): string {\n  return date.toISOString().slice(0, 19).replace(/[T:]/g, '-');\n}\n\n/**\n * Returns a default version label from the bundle name and current UTC timestamp.\n *\n * @param bundleName - Tenant-unique policy bundle name\n * @param now - Current time (for testing)\n * @returns Version label in `{bundleName}-yyyy-mm-dd-hh-mm-ss` form\n */\nexport function defaultPolicyVersionLabel(bundleName: string, now: Date = new Date()): string {\n  return `${bundleName}-${formatPolicyVersionTimestamp(now)}`;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\n\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { buildExampleCommand } from '../../../lib/docgen/buildExamples.js';\nimport { inquirerConfirmBoolean } from '../../../lib/helpers/inquirer.js';\nimport { logger } from '../../../logger.js';\nimport type { ActivateCommandFlags } from '../activate/impl.js';\nimport {\n  buildPolicyBundleFormData,\n  buildPolicyEngineClient,\n  buildOpaBundleTarball,\n  defaultPolicyVersionLabel,\n  formatPolicyBundleVersionSummary,\n  policyEngineRequest,\n  printResult,\n  resolveBundleIdByName,\n  setPolicyEngineCliDebug,\n} from '../helpers/index.js';\nimport type { CreatePolicyBundleResponse, CreatePolicyBundleVersionResponse } from '../types.js';\n\n/** CLI flags for `transcend policy publish`. */\nexport interface PublishCommandFlags {\n  /** Directory containing Rego policy files */\n  dir: string;\n  /** Tenant-unique bundle name */\n  'bundle-name': string;\n  /** Transcend API key */\n  auth: string;\n  /** Transcend API URL */\n  'transcend-url': string;\n  /** Version label (defaults to `{bundleName}-yyyy-mm-dd-hh-mm-ss`) */\n  version?: string;\n  /** Optional version description */\n  description?: string;\n  /** Print raw JSON response */\n  json: boolean;\n  /** Skip the \"create new bundle\" confirmation */\n  yes: boolean;\n  /** Include technical error details when a command fails */\n  debug?: boolean;\n}\n\n/**\n * Build and upload a new immutable policy bundle version.\n *\n * @param this - CLI context\n * @param flags - Command flags\n */\nexport async function publish(\n  this: LocalContext,\n  {\n    dir,\n    'bundle-name': bundleName,\n    auth,\n    'transcend-url': transcendUrl,\n    version,\n    description,\n    json,\n    yes,\n    debug = false,\n  }: PublishCommandFlags,\n): Promise<void> {\n  doneInputValidation(this.process.exit);\n  setPolicyEngineCliDebug(debug);\n\n  const resolvedDir = path.resolve(dir);\n  const versionLabel = version ?? defaultPolicyVersionLabel(bundleName);\n  const client = buildPolicyEngineClient(transcendUrl, auth);\n\n  let bundlePath: string | undefined;\n  try {\n    logger.info(colors.green(`Building policy bundle from ${resolvedDir}...`));\n    bundlePath = await buildOpaBundleTarball(resolvedDir);\n\n    const existingBundleId = await resolveBundleIdByName(client, bundleName);\n\n    let responseBody: CreatePolicyBundleResponse | CreatePolicyBundleVersionResponse;\n\n    if (existingBundleId) {\n      logger.info(colors.green(`Uploading new version for bundle \"${bundleName}\"...`));\n      const form = buildPolicyBundleFormData({\n        bundlePath,\n        version: versionLabel,\n        description,\n      });\n      responseBody = await policyEngineRequest(\n        client\n          .post(`v1/policy-engine/policy-bundles/${existingBundleId}/versions`, { body: form })\n          .json<CreatePolicyBundleVersionResponse>(),\n      );\n    } else {\n      if (!this.process.stdin.isTTY && !yes) {\n        logger.error(\n          colors.red(\n            'Cannot create a new bundle in a non-interactive environment; pass --yes to confirm.',\n          ),\n        );\n        this.process.exit(1);\n        return;\n      }\n\n      if (!yes) {\n        logger.warn(\n          colors.yellow(`No policy bundle named \"${bundleName}\" exists for this organization.`),\n        );\n        const shouldCreate = await inquirerConfirmBoolean({\n          message: `No policy bundle named \"${bundleName}\" exists. Create a new bundle and upload its first version?`,\n        });\n        if (!shouldCreate) {\n          logger.info(colors.yellow('Publish cancelled.'));\n          return;\n        }\n      }\n\n      logger.info(colors.green(`Creating bundle \"${bundleName}\" and uploading first version...`));\n      const createForm = buildPolicyBundleFormData({\n        bundlePath,\n        version: versionLabel,\n        description,\n        bundleName,\n      });\n      responseBody = await policyEngineRequest(\n        client\n          .post('v1/policy-engine/policy-bundles', {\n            body: createForm,\n          })\n          .json<CreatePolicyBundleResponse>(),\n      );\n    }\n\n    printResult(this.process.stdout, {\n      json,\n      data: responseBody,\n      renderTable: () => formatPolicyBundleVersionSummary(responseBody.version),\n    });\n\n    logger.info(colors.green('Policy bundle version uploaded successfully.'));\n\n    const activateCommand = buildExampleCommand<ActivateCommandFlags>(['policy', 'activate'], {\n      version: responseBody.version.version,\n      'bundle-name': bundleName,\n    });\n    logger.info(\n      colors.yellow(\n        `Publishing a policy does not activate it. To activate this version, run:\\n  ${activateCommand}`,\n      ),\n    );\n  } finally {\n    if (bundlePath && fs.existsSync(bundlePath)) {\n      fs.unlinkSync(bundlePath);\n    }\n  }\n}\n"],"mappings":"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"}